Skip to Content
Technical Articles

Merging Multiple Adobe Forms and Downloading it as a single PDF

Hi fellow ABAPERS, sometimes we could a client requirement of merging multiple adobe forms and displaying it as one single pdf to the end-user.

However, after doing a lot of googling and reading numerous threads, I came across various solutions but some gave output as spool or some merged the forms but didn’t gave user to download the generated pdf into the system with desired location and name.

So, here I’ll provide the complete end-to-end solution with steps as well as the complete code, so that it really helps you. So let’s get started..

 

STEP 1:

Call function module FP_JOB_OPEN, with below parameters-

Data:ls_fp_outputparams TYPE sfpoutputparams.
    ls_fp_outputparams-dest     = 'LP01'"Depends on user settings
    ls_fp_outputparams-nodialog = abap_true.
    ls_fp_outputparams-preview  = abap_false.
    ls_fp_outputparams-getpdf   = 'M'."(Default value = 'X')
    ls_fp_outputparams-assemble = 'S'."bigger data
    ls_fp_outputparams-bumode   = 'M'."This is Bundle Mode
    ls_fp_outputparams-reqnew   = abap_true.

    CALL FUNCTION 'FP_JOB_OPEN'           
      CHANGING
        ie_outputparams = ls_fp_outputparams
      EXCEPTIONS
        cancel          = 1
        usage_error     = 2
        system_error    = 3
        internal_error  = 4
        OTHERS          = 5.
    IF sy-subrc <> 0.
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
              WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
      RETURN.
    ENDIF.
*Remember all the values should be passed exactly the same in order to 
achieve the functionality.

STEP 2:

Get the Adobe Form function Module using FP_FUNCTION_MODULE_NAME and call the generated unction module for your 1st Adobe Form.

Data:lv_fm_inv     TYPE rs38l_fnam,
ls_fp_docparams    TYPE sfpdocparams,
ls_pdf_file        TYPE fpformoutput.

   TRY.
        CALL FUNCTION 'FP_FUNCTION_MODULE_NAME'  
          EXPORTING
            i_name     = 'ZFORM1'
          IMPORTING
            e_funcname = lv_fm_inv.

      CATCH cx_fp_api_repository.
      CATCH cx_fp_api_usage.
      CATCH cx_fp_api_internal.
    ENDTRY.

*&--- Call the generated function module
    CALL FUNCTION lv_fm_inv     
      EXPORTING
        /1bcdwb/docparams  = ls_fp_docparams
      IMPORTING
        /1bcdwb/formoutput = ls_pdf_file
      EXCEPTIONS
        usage_error        = 1
        system_error       = 2
        internal_error     = 3.
    IF sy-subrc <> 0.
*  <error handling>
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
        WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
      RETURN.
    ENDIF.

STEP 3:

Repeat Step 2, for 2nd Adobe Form. Call ‘FP_JOB_CLOSE’  to close the spool job.

*&---- Close the spool job
    CALL FUNCTION 'FP_JOB_CLOSE'
*    IMPORTING
*     E_RESULT             =
      EXCEPTIONS
        usage_error    = 1
        system_error   = 2
        internal_error = 3
        OTHERS         = 4.
    IF sy-subrc <> 0.
*   <error handling>
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
        WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
      RETURN.
    ENDIF.

Note: You can use LOOP..ENDLOOP to call FP_FUNCTION_MODULE_NAME and it’s generated function module if you have more than two adobe forms.

TYPES: BEGIN OF lty_forms,
form TYPE fpname,
END OF lty_forms,

lty_t_forms TYPE STANDARD TABLE OF lty_forms WITH EMPTY KEY..

Data:lt_forms type lty_t_forms.

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 = ls_fp_docparams
iv_final = lwa_final
IMPORTING
/1bcdwb/formoutput =ls_pdf_file
EXCEPTIONS
usage_error = 1
system_error = 2
internal_error = 3
OTHERS = 4.

IF sy-subrc <> 0.
ENDIF.

CLEAR: lwa_forms, lv_fm_name.
ENDLOOP

STEP 4:

Call function module,’ FP_GET_PDF_TABLE’, to merge multiple generated files into a single pdf.

    DATA:lt_data            TYPE STANDARD TABLE OF tabl1024, "RAWSTRING
         lo_pdf_merger      TYPE REF TO cl_rspo_pdf_merge,
         lt_pdf_table       TYPE tfpcontent,
         lv_merged_document TYPE xstring,
         lv_len             TYPE i,
         lv_rc              TYPE i VALUE 0.

*&&-- Merging different PDF files into one
    CREATE OBJECT lo_pdf_merger.

    CALL FUNCTION 'FP_GET_PDF_TABLE'
      IMPORTING
        e_pdf_table = lt_pdf_table.

We will use standard class cl_rspo_pdf_merge methods which can be 
reffered from the program:RSPO_TEST_MERGE_PDF_FILES.The same class 
can be used to write to a SAP application server.


* Add documents to attribute table of PDF merger
    LOOP AT lt_pdf_table 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 ).
    CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'
      EXPORTING
        buffer        = lv_merged_document
      IMPORTING
        output_length = lv_len
      TABLES
        binary_tab    = lt_data.

Step 5:

We will call the method cl_gui_frontend_services=>file_save_dialog, which gives user choice to name and save the pdf at the desired location.

    DATA:lv_file            TYPE string,
         lv_path            TYPE string,
         lv_file_name       TYPE string.
   CALL METHOD cl_gui_frontend_services=>file_save_dialog
      EXPORTING
        window_title              = 'Save Form'    "You can pass any value as per your choice
        default_extension         = '.pdf'
        default_file_name         = 'Invoice.pdf'
        prompt_on_overwrite       = 'X'
      CHANGING
        filename                  = lv_file_name
        path                      = lv_path
        fullpath                  = lv_file
      EXCEPTIONS
        cntl_error                = 1
        error_no_gui              = 2
        not_supported_by_gui      = 3
        invalid_default_file_name = 4
        OTHERS                    = 5.
    IF sy-subrc <> 0.
* Implement suitable error handling here
    ENDIF

. STEP 6:

Finally,We will call the method cl_gui_frontend_services=>gui_download, for downloading the file and cl_gui_frontend_services=>execute, to automatically open the pdf, after it is downloaded.

    DATA:lt_data            TYPE STANDARD TABLE OF tabl1024,
         lv_file            TYPE string,
         lv_len             TYPE i,
         lv_rc              TYPE i VALUE 0
    CALL METHOD cl_gui_frontend_services=>gui_download
      EXPORTING
        bin_filesize            = lv_len
        filename                = lv_file
        filetype                = 'BIN'
      CHANGING
        data_tab                = lt_data
      EXCEPTIONS
        file_write_error        = 1
        no_batch                = 2
        gui_refuse_filetransfer = 3
        invalid_type            = 4
        no_authority            = 5
        unknown_error           = 6
        header_not_allowed      = 7
        separator_not_allowed   = 8
        filesize_not_allowed    = 9
        header_too_long         = 10
        dp_error_create         = 11
        dp_error_send           = 12
        dp_error_write          = 13
        unknown_dp_error        = 14
        access_denied           = 15
        dp_out_of_memory        = 16
        disk_full               = 17
        dp_timeout              = 18
        file_not_found          = 19
        dataprovider_exception  = 20
        control_flush_error     = 21
        not_supported_by_gui    = 22
        error_no_gui            = 23
        OTHERS                  = 24.
    IF sy-subrc IS NOT INITIAL.
    ENDIF.
    CALL METHOD cl_gui_frontend_services=>execute
      EXPORTING
        document               = lv_file
        synchronous            = 'X'
      EXCEPTIONS
        cntl_error             = 1
        error_no_gui           = 2
        bad_parameter          = 3
        file_not_found         = 4
        path_not_found         = 5
        file_extension_unknown = 6
        error_execute_failed   = 7
        synchronous_failed     = 8
        not_supported_by_gui   = 9
        OTHERS                 = 10.
    IF sy-subrc IS NOT INITIAL.
    ENDIF.

 

Below I’m also posting the complete code-

    DATA: lv_fm_dpr          TYPE rs38l_fnam,      " CHAR 30 0 Name of Function Module
          lv_fm_inv          TYPE rs38l_fnam,
          ls_fp_docparams    TYPE sfpdocparams,    " Structure  SFPDOCPARAMS    Short Description  Form Parameters for Form Processing
          ls_fp_outputparams TYPE sfpoutputparams, " Structure  SFPOUTPUTPARAMS Short Description  Form Processing Output Parameter
          ls_pdf_file        TYPE fpformoutput.
       
    DATA:lt_data            TYPE STANDARD TABLE OF tabl1024,
         lo_pdf_merger      TYPE REF TO cl_rspo_pdf_merge,
         lt_pdf_table       TYPE tfpcontent,
         lv_file            TYPE string,
         lv_path            TYPE string,
         lv_file_name       TYPE string,
         lv_merged_document TYPE xstring,
         lv_len             TYPE i,
         lv_rc              TYPE i VALUE 0.

    ls_fp_outputparams-dest     = 'LP01'. "Depends on user settings
    ls_fp_outputparams-nodialog = abap_true.
    ls_fp_outputparams-getpdf   = 'M'.
    ls_fp_outputparams-assemble = 'S'.
    ls_fp_outputparams-bumode   = 'M'.
    ls_fp_outputparams-reqnew   = abap_true.
   
* Sets the output parameters and opens the spool job
    CALL FUNCTION 'FP_JOB_OPEN'                   "& Form Processing: Call Form
      CHANGING
        ie_outputparams = ls_fp_outputparams
      EXCEPTIONS
        cancel          = 1
        usage_error     = 2
        system_error    = 3
        internal_error  = 4
        OTHERS          = 5.
    IF sy-subrc <> 0.
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
              WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
      RETURN.
    ENDIF.

    TRY.
        CALL FUNCTION 'FP_FUNCTION_MODULE_NAME'           "& Form Processing Generation
          EXPORTING
            i_name     = 'ZFORM1'
          IMPORTING
            e_funcname = lv_fm_inv.

      CATCH cx_fp_api_repository.
      CATCH cx_fp_api_usage.
      CATCH cx_fp_api_internal.
    ENDTRY.

**&---- Get the name of the generated function module
    TRY.
        CALL FUNCTION 'FP_FUNCTION_MODULE_NAME'           "& Form Processing Generation
          EXPORTING
            i_name     = 'ZFORM2'
          IMPORTING
            e_funcname = lv_fm_dpr.

      CATCH cx_fp_api_repository.
      CATCH cx_fp_api_usage.
      CATCH cx_fp_api_internal.
    ENDTRY.

* Language and country setting (here US as an example)
    ls_fp_docparams-langu   = 'E'.
    ls_fp_docparams-country = 'US'.


*&--- Call the generated function module
    CALL FUNCTION lv_fm_inv
      EXPORTING
        /1bcdwb/docparams  = ls_fp_docparams
      IMPORTING
        /1bcdwb/formoutput = ls_pdf_file
      EXCEPTIONS
        usage_error        = 1
        system_error       = 2
        internal_error     = 3.
    IF sy-subrc <> 0.
*  <error handling>
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
        WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
      RETURN.
    ENDIF.

*&--- Call the generated function module
    CALL FUNCTION lv_fm_dpr
      EXPORTING
        /1bcdwb/docparams  = ls_fp_docparams
      IMPORTING
        /1bcdwb/formoutput = ls_pdf_file
      EXCEPTIONS
        usage_error        = 1
        system_error       = 2
        internal_error     = 3.
    IF sy-subrc <> 0.
*  <error handling>
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
        WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
      RETURN.
    ENDIF.
*
*    ENDLOOP.
*&---- Close the spool job
    CALL FUNCTION 'FP_JOB_CLOSE'
*    IMPORTING
*     E_RESULT             =
      EXCEPTIONS
        usage_error    = 1
        system_error   = 2
        internal_error = 3
        OTHERS         = 4.
    IF sy-subrc <> 0.
*   <error handling>
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
        WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
      RETURN.
    ENDIF.
*&&-- Merging different PDF files into one
    CREATE OBJECT lo_pdf_merger.

    CALL FUNCTION 'FP_GET_PDF_TABLE'
      IMPORTING
        e_pdf_table = lt_pdf_table.

* Add documents to attribute table of PDF merger
    LOOP AT lt_pdf_table 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 ).
    CALL FUNCTION 'SCMS_XSTRING_TO_BINARY'
      EXPORTING
        buffer        = lv_merged_document
      IMPORTING
        output_length = lv_len
      TABLES
        binary_tab    = lt_data.

    CALL METHOD cl_gui_frontend_services=>file_save_dialog
      EXPORTING
        window_title              = 'Save Form'
        default_extension         = '.pdf'
        default_file_name         = 'Invoice.pdf'
        prompt_on_overwrite       = 'X'
      CHANGING
        filename                  = lv_file_name
        path                      = lv_path
        fullpath                  = lv_file
      EXCEPTIONS
        cntl_error                = 1
        error_no_gui              = 2
        not_supported_by_gui      = 3
        invalid_default_file_name = 4
        OTHERS                    = 5.
    IF sy-subrc <> 0.
* Implement suitable error handling here
    ENDIF.

    CALL METHOD cl_gui_frontend_services=>gui_download
      EXPORTING
        bin_filesize            = lv_len
        filename                = lv_file
        filetype                = 'BIN'
      CHANGING
        data_tab                = lt_data
      EXCEPTIONS
        file_write_error        = 1
        no_batch                = 2
        gui_refuse_filetransfer = 3
        invalid_type            = 4
        no_authority            = 5
        unknown_error           = 6
        header_not_allowed      = 7
        separator_not_allowed   = 8
        filesize_not_allowed    = 9
        header_too_long         = 10
        dp_error_create         = 11
        dp_error_send           = 12
        dp_error_write          = 13
        unknown_dp_error        = 14
        access_denied           = 15
        dp_out_of_memory        = 16
        disk_full               = 17
        dp_timeout              = 18
        file_not_found          = 19
        dataprovider_exception  = 20
        control_flush_error     = 21
        not_supported_by_gui    = 22
        error_no_gui            = 23
        OTHERS                  = 24.
    IF sy-subrc IS NOT INITIAL.
    ENDIF.
    CALL METHOD cl_gui_frontend_services=>execute
      EXPORTING
        document               = lv_file
        synchronous            = 'X'
      EXCEPTIONS
        cntl_error             = 1
        error_no_gui           = 2
        bad_parameter          = 3
        file_not_found         = 4
        path_not_found         = 5
        file_extension_unknown = 6
        error_execute_failed   = 7
        synchronous_failed     = 8
        not_supported_by_gui   = 9
        OTHERS                 = 10.
    IF sy-subrc IS NOT INITIAL.
    ENDIF.
    CLEAR:lv_file,lv_len,lv_path,lv_file_name,lt_data.

 

You can also check this in spool request(SP01) and download it to your system as well.I hope you all will find  it helpful.

Thanks for reading my first blog post and also please provide your feedback..!!

Regards,

Rohit

2 Comments
You must be Logged on to comment or reply to a post.
  • Thank you for sharing, we did something similar but also included download of related ZPL or PCL files using FM ADS_SR_READ_CONTENT_TAB.

    Best Regards, Daniel