Today I will try to explain how we can merge multiple PDF forms output into single one and write the same PDF file into application server.
Brief requirement: The real life scenario demanded to send a bundle of different SAP system generated PDF forms to a third party document repository ( has access to the SAP application server ) . The form bundle contains different forms like cover letter, loan agreement, direct debit, third party authorization, terms and condition forms etc.
In the below example we will see how the 5 different PDF forms are getting stitched into one. Here is the sample code of the driver program. Just use it to play and observe the behavior:
Code Block 1: Data Declaration. Below 5 constants are the different PDF forms created in the system.
TYPES: BEGIN OF lty_forms,
form TYPE fpname,
END OF lty_forms,
lty_t_forms TYPE STANDARD TABLE OF lty_forms WITH EMPTY KEY.
*&&-- Below are the 5 different Adobe form names created for Contract
CONSTANTS: lc_form_cover TYPE fpname VALUE 'ZFI_CP_COVER_LETTER',
lc_form_agreement TYPE fpname VALUE 'ZFI_CP_LOAN_AGREEMENT',
lc_form_debit TYPE fpname VALUE 'ZFI_CP_DIRECT_DEBIT',
lc_form_third_party TYPE fpname VALUE 'ZFI_CP_THIRD_PARTY',
lc_form_terms TYPE fpname VALUE 'ZFI_CP_TERMS_CONDITION'.
DATA: lwa_outputparams TYPE sfpoutputparams,
lv_fm_name TYPE rs38l_fnam,
lwa_docparams TYPE sfpdocparams,
lwa_formoutput TYPE fpformoutput,
lt_pdfcontent TYPE TABLE OF solix,
lt_formoutput TYPE tfpcontent,
lv_merged_document TYPE xstring,
lv_rc TYPE i,
lv_file_name TYPE string,
lwa_final TYPE zsfi_int_sub.
DATA: lo_pdf_merger TYPE REF TO cl_rspo_pdf_merge.
Code Block 2: Populate the multiple form names into internal table and pass desired values to output parameters to trigger the form.
*&&-- Populate the multiple form names into an internal table
DATA(lt_forms) = VALUE lty_t_forms( ( form = lc_form_cover )
( form = lc_form_agreement )
( form = lc_form_debit )
( form = lc_form_third_party )
( form = lc_form_terms ) ).
lwa_outputparams-nodialog = abap_true.
lwa_outputparams-dest = 'LOCL'.
lwa_outputparams-getpdf = 'M'.
lwa_outputparams-bumode = 'M'. " Bundle Mode Multiple
Code Block 3: Trigger the 5 forms one by one inside LOOP. The interface import parameters are same for 5 forms. You can mark import parameters in the interface as optional so that different parameters can be used for different forms. Creating single interface will be easier to maintain.
*&---------------------------------------------------------------------*
*& Form Processing: Call Form - Open
*&---------------------------------------------------------------------*
CALL FUNCTION 'FP_JOB_OPEN'
CHANGING
ie_outputparams = lwa_outputparams
EXCEPTIONS
cancel = 1
usage_error = 2
system_error = 3
internal_error = 4
OTHERS = 5.
IF sy-subrc <> 0.
" Suitable Error Handling
ENDIF.
LOOP AT lt_forms INTO DATA(lwa_forms).
TRY.
CALL FUNCTION 'FP_FUNCTION_MODULE_NAME'
EXPORTING
i_name = lwa_forms-form
IMPORTING
e_funcname = lv_fm_name.
CATCH cx_fp_api.
ENDTRY.
CALL FUNCTION lv_fm_name
EXPORTING
/1bcdwb/docparams = lwa_docparams
iv_final = lwa_final
IMPORTING
/1bcdwb/formoutput = lwa_formoutput
EXCEPTIONS
usage_error = 1
system_error = 2
internal_error = 3
OTHERS = 4.
IF sy-subrc <> 0.
ENDIF.
CLEAR: lwa_forms, lwa_formoutput, lv_fm_name.
ENDLOOP.
CALL FUNCTION 'FP_JOB_CLOSE'
EXCEPTIONS
usage_error = 1
system_error = 2
internal_error = 3
OTHERS = 4.
IF sy-subrc <> 0.
* Implement suitable error handling here
ENDIF.
Code Block 4: Merge form’s PDF output into one. Internal table LT_FORMOUTPUT will contain 5 rows with PDF data in XSTRING format for 5 different forms.
*&&-- Merging different PDF files into one
CREATE OBJECT lo_pdf_merger.
CALL FUNCTION 'FP_GET_PDF_TABLE'
IMPORTING
e_pdf_table = lt_formoutput.
* Add documents to attribute table of PDF merger
LOOP AT lt_formoutput INTO DATA(lwa_form).
lo_pdf_merger->add_document( lwa_form ).
ENDLOOP.
* Call kernel method to do the merge of the specified files.
lo_pdf_merger->merge_documents( IMPORTING merged_document = lv_merged_document
rc = lv_rc ).
Code Block 5: Write the PDF file to application directory. The variable LV_MERGED_DOCUMENT contains the merged XSTRING value of those 5 forms.
CONCATENATE 'Loan_Contract' sy-datum sy-uzeit INTO DATA(lv_name) SEPARATED BY '_'.
CONCATENATE lv_name '.pdf' INTO lv_name.
REFRESH: lt_formoutput.
lwa_formoutput-pdf = lv_merged_document.
CALL FUNCTION 'FILE_GET_NAME_USING_PATH'
EXPORTING
client = sy-mandt
logical_path = 'ZFI_CUSTSTMT_PATH'
file_name = lv_name
IMPORTING
file_name_with_path = lv_file_name
EXCEPTIONS
path_not_found = 1
missing_parameter = 2
operating_system_not_found = 3
file_system_not_found = 4
OTHERS = 5.
IF sy-subrc <> 0.
* Implement suitable error handling here
ENDIF.
*PDF Upload
IF lwa_formoutput-pdf IS NOT INITIAL.
lt_pdfcontent = cl_document_bcs=>xstring_to_solix( ip_xstring = lwa_formoutput-pdf ).
OPEN DATASET lv_file_name FOR OUTPUT IN BINARY MODE .
IF sy-subrc = 0.
LOOP AT lt_pdfcontent INTO DATA(lwa_pdfcontent).
TRANSFER lwa_pdfcontent-line TO lv_file_name.
ENDLOOP.
CLOSE DATASET lv_file_name.
REFRESH lt_pdfcontent.
ENDIF.
ENDIF.
OUTPUT:
File has been written in application server successfully. This file can be downloaded in PDF format using CG3Y transaction from application directory for verification. You will not be able to open this PDF file directly from AL11.
Brief requirement: The real life scenario demanded to send a bundle of different SAP system generated PDF forms to a third party document repository ( has access to the SAP application server ) . The form bundle contains different forms like cover letter, loan agreement, direct debit, third party authorization, terms and condition forms etc.
In the below example we will see how the 5 different PDF forms are getting stitched into one. Here is the sample code of the driver program. Just use it to play and observe the behavior:
Code Block 1: Data Declaration. Below 5 constants are the different PDF forms created in the system.
TYPES: BEGIN OF lty_forms,
form TYPE fpname,
END OF lty_forms,
lty_t_forms TYPE STANDARD TABLE OF lty_forms WITH EMPTY KEY.
*&&-- Below are the 5 different Adobe form names created for Contract
CONSTANTS: lc_form_cover TYPE fpname VALUE 'ZFI_CP_COVER_LETTER',
lc_form_agreement TYPE fpname VALUE 'ZFI_CP_LOAN_AGREEMENT',
lc_form_debit TYPE fpname VALUE 'ZFI_CP_DIRECT_DEBIT',
lc_form_third_party TYPE fpname VALUE 'ZFI_CP_THIRD_PARTY',
lc_form_terms TYPE fpname VALUE 'ZFI_CP_TERMS_CONDITION'.
DATA: lwa_outputparams TYPE sfpoutputparams,
lv_fm_name TYPE rs38l_fnam,
lwa_docparams TYPE sfpdocparams,
lwa_formoutput TYPE fpformoutput,
lt_pdfcontent TYPE TABLE OF solix,
lt_formoutput TYPE tfpcontent,
lv_merged_document TYPE xstring,
lv_rc TYPE i,
lv_file_name TYPE string,
lwa_final TYPE zsfi_int_sub.
DATA: lo_pdf_merger TYPE REF TO cl_rspo_pdf_merge.
Code Block 2: Populate the multiple form names into internal table and pass desired values to output parameters to trigger the form.
*&&-- Populate the multiple form names into an internal table
DATA(lt_forms) = VALUE lty_t_forms( ( form = lc_form_cover )
( form = lc_form_agreement )
( form = lc_form_debit )
( form = lc_form_third_party )
( form = lc_form_terms ) ).
lwa_outputparams-nodialog = abap_true.
lwa_outputparams-dest = 'LOCL'.
lwa_outputparams-getpdf = 'M'.
lwa_outputparams-bumode = 'M'. " Bundle Mode Multiple
Code Block 3: Trigger the 5 forms one by one inside LOOP. The interface import parameters are same for 5 forms. You can mark import parameters in the interface as optional so that different parameters can be used for different forms. Creating single interface will be easier to maintain.
*&---------------------------------------------------------------------*
*& Form Processing: Call Form - Open
*&---------------------------------------------------------------------*
CALL FUNCTION 'FP_JOB_OPEN'
CHANGING
ie_outputparams = lwa_outputparams
EXCEPTIONS
cancel = 1
usage_error = 2
system_error = 3
internal_error = 4
OTHERS = 5.
IF sy-subrc <> 0.
" Suitable Error Handling
ENDIF.
LOOP AT lt_forms INTO DATA(lwa_forms).
TRY.
CALL FUNCTION 'FP_FUNCTION_MODULE_NAME'
EXPORTING
i_name = lwa_forms-form
IMPORTING
e_funcname = lv_fm_name.
CATCH cx_fp_api.
ENDTRY.
CALL FUNCTION lv_fm_name
EXPORTING
/1bcdwb/docparams = lwa_docparams
iv_final = lwa_final
IMPORTING
/1bcdwb/formoutput = lwa_formoutput
EXCEPTIONS
usage_error = 1
system_error = 2
internal_error = 3
OTHERS = 4.
IF sy-subrc <> 0.
ENDIF.
CLEAR: lwa_forms, lwa_formoutput, lv_fm_name.
ENDLOOP.
CALL FUNCTION 'FP_JOB_CLOSE'
EXCEPTIONS
usage_error = 1
system_error = 2
internal_error = 3
OTHERS = 4.
IF sy-subrc <> 0.
* Implement suitable error handling here
ENDIF.
Code Block 4: Merge form’s PDF output into one. Internal table LT_FORMOUTPUT will contain 5 rows with PDF data in XSTRING format for 5 different forms.
*&&-- Merging different PDF files into one
CREATE OBJECT lo_pdf_merger.
CALL FUNCTION 'FP_GET_PDF_TABLE'
IMPORTING
e_pdf_table = lt_formoutput.
* Add documents to attribute table of PDF merger
LOOP AT lt_formoutput INTO DATA(lwa_form).
lo_pdf_merger->add_document( lwa_form ).
ENDLOOP.
* Call kernel method to do the merge of the specified files.
lo_pdf_merger->merge_documents( IMPORTING merged_document = lv_merged_document
rc = lv_rc ).
Code Block 5: Write the PDF file to application directory. The variable LV_MERGED_DOCUMENT contains the merged XSTRING value of those 5 forms.
CONCATENATE 'Loan_Contract' sy-datum sy-uzeit INTO DATA(lv_name) SEPARATED BY '_'.
CONCATENATE lv_name '.pdf' INTO lv_name.
REFRESH: lt_formoutput.
lwa_formoutput-pdf = lv_merged_document.
CALL FUNCTION 'FILE_GET_NAME_USING_PATH'
EXPORTING
client = sy-mandt
logical_path = 'ZFI_CUSTSTMT_PATH'
file_name = lv_name
IMPORTING
file_name_with_path = lv_file_name
EXCEPTIONS
path_not_found = 1
missing_parameter = 2
operating_system_not_found = 3
file_system_not_found = 4
OTHERS = 5.
IF sy-subrc <> 0.
* Implement suitable error handling here
ENDIF.
*PDF Upload
IF lwa_formoutput-pdf IS NOT INITIAL.
lt_pdfcontent = cl_document_bcs=>xstring_to_solix( ip_xstring = lwa_formoutput-pdf ).
OPEN DATASET lv_file_name FOR OUTPUT IN BINARY MODE .
IF sy-subrc = 0.
LOOP AT lt_pdfcontent INTO DATA(lwa_pdfcontent).
TRANSFER lwa_pdfcontent-line TO lv_file_name.
ENDLOOP.
CLOSE DATASET lv_file_name.
REFRESH lt_pdfcontent.
ENDIF.
ENDIF.
OUTPUT:
File has been written in application server successfully. This file can be downloaded in PDF format using CG3Y transaction from application directory for verification. You will not be able to open this PDF file directly from AL11.
Note: During the test, it was triggering error/merge failure message at the time of merging. You may need to implement the below OSS note to resolve the error related to class CL_RSPO_PDF_MERGE.
There is a sample program RSPO_TEST_MERGE_PDF_FILES which contains all the required codes to play around with PDF merging. Just explore this for other merging functionalities.
In the above example, we can send the output to the Spool as well. Just pass the below parameters in the code lines of code block 2 , followed by code block 3.
lwa_outputparams-nodialog = abap_true.
lwa_outputparams-device = 'PRINTER'.
lwa_outputparams-reqnew = abap_true.
lwa_outputparams-dest = 'LOCL'.
lwa_outputparams-bumode = 'M'. " Bundle Mode Multiple
Spool request with single PDF will be generated. For our example, 36 pages have been generated for 5 forms.
Once you open the PDF in spool, you can see the 5 forms. You can check one by one by clicking arrow sign or you can click “Overall View On” to get a merged view.
If you want to test the code, just create two dummy PDF forms ( Transaction SFP ) and replace those form names mentioned in the constants.
No comments:
Post a Comment