Saturday, 28 September 2019

How to merge multiple PDF forms into single one and write in application server

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.

SAP ABAP Tutorials and Materials, SAP ABAP Certifications, SAP ABAP Learning

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.

SAP ABAP Tutorials and Materials, SAP ABAP Certifications, SAP ABAP Learning

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.

SAP ABAP Tutorials and Materials, SAP ABAP Certifications, SAP ABAP Learning

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