Send SAPscript form PDF from output type message to Business Network

One of the common requirements when we are implementing SAP Ariba Commerce Automation or Digital Supplier Network, is to send attachments inside the purchase order to Ariba Business Network, but this functionality is already included implementing the next Include in the User Exit EXIT_SAPLEINM_002:

INCLUDE ARBCIG_ORDER_REQUEST_002 IF FOUND.

But…what happens when you want to send the PDF of the purchase order, and this PDF is generated in a SAPScript form, that is executed inside the output type message:

Message Output

This Output type is configured in NACE transaction where you enter the form name of the SAPScript that will be triggered:

NACE Output Type

The complication of this functionality is that this printout of the purchase order, is triggered when the output message is already processed and the purchase order is already approved, but when you are sending the purchase order to Ariba Business Network, this steps are not finished yet, so you must implement a logic to print the PDF of the purchase order, executing manually the SAPScript in real time when the PO is sent to Business Network.

We can do that implementing the BADI ARBCIG_BADI_ATTACHMENT_UTIL where we process the attachments of the PO.

BADI ARBCIG_BADI_ATTACHMENT_UTIL

We only need the method PRE_ATTACHMENT_PROCESS:

METHOD PRE_ATTACHMENT_PROCESS

Inside this method, we will implement the next logic:

  1. Search in NAST table with the PO ID if exists the message you are configured in NACE transaction for the purchase order you are approving.
  2. Read the data of the PO from MF ME_READ_PO_FOR_PRINTING.
  3. Execute the MF ECP_PRINT_PO with the form ID.
  4. Read the OTF data of the form with MF READ_OTF_FROM_MEMORY.
  5. Convert OTF data to PDF with MF CONVERT_OTF.
  6. Encrypt the PDF from Hexadecimal to Base64 with MF SCMS_BASE64_ENCODE_STR.
  7. Complete the E1ARBCIG_ATTACH_HDR_DET segment with header data of attachment.
  8. Complete the E1ARBCIG_ATTACH_CONTENT_DET segment with the content of Base64 string.

All this steps are detailed in the next code:

method IF_ARBCIG_ATTACHMENT_UTIL~PRE_ATTACHMENT_PROCESS.


    DATA: gint_nast      TYPE nast,
          lv_count       TYPE i,
          lv_ebeln       TYPE ebeln,
          ent_screen     TYPE c,
          ent_retco      TYPE i,
          l_nast         TYPE nast,
          l_druvo        TYPE t166k-druvo,
          l_from_memory,
          toa_dara       TYPE toa_dara,
          arc_params     TYPE arc_params,
          aux_form       TYPE tnapr-fonam VALUE 'ZMMSS_PEDCOMPRAS',
          lv_message     TYPE tnapr-fonam VALUE 'ZPC',
          lt_docs        TYPE TABLE OF docs,
          l_doc          TYPE meein_purchase_doc_print,
          otf            TYPE TABLE OF itcoo,
          pdf_bytecount  TYPE i,
          nom_archivo    TYPE string,
          pdfout         TYPE TABLE OF tline,
          lv_debug       TYPE char1,
          pdf            TYPE XSTRING,
          ls_e1edk01     TYPE e1edk01,
          ls_hdr_det     TYPE E1ARBCIG_ATTACH_HDR_DET,
          ls_hdr_content TYPE E1ARBCIG_ATTACH_CONTENT_DET,
          idoc_data      TYPE edidd,
          lv_base64      TYPE string,
          len            TYPE i,
          lv_offset_mx   TYPE i,
          lv_offset_mn   TYPE i,
          div            TYPE i,
          temp           TYPE i.

*"---------------------------------------------------------------------
*" NOTES:
*"  1) Control display of PO in GUI window
*"       ENT_SCREEN = 'X'   => PO is displayed in GUI window
*"       ENT_SCREEN = space => Spool file of the PO is created
*"                               Spool number is returned in message
*"  2) Write PO to memory as OTF
*"       NAST-SORT1 = 'SWP' => PO is written to memory as OTF
*"                               Memory ID = PO Number - Use function
*"                               READ_OTF_FROM_MEMORY to retrieve
*"       NAST-SORT1 = space => PO is NOT written to memory
*"---------------------------------------------------------------------

*Infinite LOOP only for debug
    SELECT SINGLE low
    FROM ARBCIG_TVARV
    WHERE name = 'DEBUG_PRE_ATTACHMENT_PROCESS'
    INTO @lv_debug.

    IF lv_debug EQ 'X'.
      WHILE lv_debug IS NOT INITIAL.
      ENDWHILE.
    ENDIF.

*First we obtain the PO ID from field
*Belnr from segment e1edk01
    READ TABLE c_edidd[] INTO idoc_data INDEX 1.
    CHECK idoc_data-segnam EQ 'E1EDK01'.
    MOVE idoc_data-sdata TO ls_e1edk01.

    lv_ebeln = ls_e1edk01-belnr.

    IF lv_ebeln IS NOT INITIAL.

*Field lv_message is the output type message where the form is configured
      SELECT SINGLE *
         FROM nast INTO gint_nast WHERE objky EQ lv_ebeln
          AND kschl EQ lv_message.

*We ensure the output type exists for the PO.
      CHECK sy-subrc EQ 0.

      gint_nast-sort1 = 'SWP'.

      IF gint_nast-aende EQ space.
        l_druvo = '1'.
      ELSE.
        l_druvo = '2'.
      ENDIF.

      CLEAR ent_retco.

      CALL FUNCTION 'ME_READ_PO_FOR_PRINTING'
        EXPORTING
          IX_NAST        = gint_nast
          IX_SCREEN      = ent_screen
        IMPORTING
          EX_RETCO       = ent_retco
          DOC            = l_doc
          EX_NAST        = l_nast
        CHANGING
          CX_DRUVO       = l_druvo
          CX_FROM_MEMORY = l_from_memory.

*      CHECK ent_retco EQ 0.
      IF ent_retco EQ 3.
        "It means the PO is not released yet, but this is normal, dont panic.
        
        CLEAR ent_retco.
      ENDIF.

      CHECK ent_retco EQ 0.

*Field aux_form is the SAPScript ID form.
      CALL FUNCTION 'ECP_PRINT_PO'
        EXPORTING
          IX_NAST        = l_nast
          IX_DRUVO       = l_druvo
          DOC            = l_doc
          IX_SCREEN      = ent_screen
*         IX_XFZ         =
*         IX_MFLAG       = ' '
          IX_FROM_MEMORY = l_from_memory
          IX_TOA_DARA    = toa_dara
          IX_ARC_PARAMS  = arc_params
          IX_FONAM       = aux_form
        IMPORTING
          EX_RETCO       = ent_retco.

      CLEAR otf.

      CALL FUNCTION 'READ_OTF_FROM_MEMORY'
        EXPORTING
          MEMORY_KEY = l_nast-objky " PO Number
        TABLES
          OTF        = otf
*       EXCEPTIONS
*         MEMORY_EMPTY       = 1
*         OTHERS     = 2
        .
      IF sy-subrc <> 0.
*        RAISE otf_error.
      ENDIF.

*We transform OTF to PDF
      CALL FUNCTION 'CONVERT_OTF'
        EXPORTING
          format                = 'PDF'
        IMPORTING
          bin_filesize          = pdf_bytecount
          BIN_FILE              = PDF
        TABLES
          otf                   = otf
          lines                 = pdfout
        EXCEPTIONS
          err_max_linewidth     = 1
          err_format            = 2
          err_conv_not_possible = 3
          OTHERS                = 4.
      IF sy-subrc <> 0.
*        RAISE error.  " oops
      ENDIF.

*We transform the PDF from Hexa to Base64
      CHECK PDF IS NOT INITIAL.

      CALL FUNCTION 'SCMS_BASE64_ENCODE_STR'
        EXPORTING
          INPUT  = PDF
        IMPORTING
          OUTPUT = lv_base64.

*If all its OK, we already have the PDF in Base64
      CHECK lv_base64 IS NOT INITIAL.

      CLEAR idoc_data.
*We insert segment E1ARBCIG_ATTACH_HDR_DET.
      idoc_data-segnam = 'E1ARBCIG_ATTACH_HDR_DET'.
      CONCATENATE lv_ebeln  '.pdf' INTO ls_hdr_det-filename.
      ls_hdr_det-charset = 'UTF-8'.
      ls_hdr_det-contentid = '1'.
      ls_hdr_det-contenttype = 'application/pdf'.
      ls_hdr_det-contentlength = pdf_bytecount.
      CONDENSE ls_hdr_det-contentlength NO-GAPS.
      MOVE ls_hdr_det TO idoc_data-sdata.
      APPEND idoc_data TO c_edidd[].

*We insert segments E1ARBCIG_ATTACH_CONTENT_DET.
      CLEAR idoc_data.
      idoc_data-segnam = 'E1ARBCIG_ATTACH_CONTENT_DET'.
      len = strlen( lv_base64 ).
      lv_offset_mx = 255.
      lv_offset_mn = 0.
      div = ceil( len / 255 ).
      do div times.
        clear ls_hdr_content.
        IF lv_offset_mn GE len.
          "Last loop
          EXIT.
        ELSE.
          temp = len - lv_offset_mn.
          IF temp LT lv_offset_mx.
          "Last loop
            ls_hdr_content-content = lv_base64+lv_offset_mn(temp).
            MOVE ls_hdr_content TO idoc_data-sdata.
            APPEND idoc_data TO c_edidd[].
            EXIT.
          ENDIF.
          ls_hdr_content-content = lv_base64+lv_offset_mn(lv_offset_mx).
          MOVE ls_hdr_content TO idoc_data-sdata.
          APPEND idoc_data TO c_edidd[].
          lv_offset_mn = lv_offset_mn + lv_offset_mx.
        ENDIF.
      enddo.

    ENDIF.

  endmethod.

Summary

As a final result, the buyer will only add the message output type in the purchase order, without need of attaching anything to the purchase order, and the system automatically will print this PDF in background and will be attached this PDF to the IDOC sent to business network.

IDOC with attachments

And finally, the supplier will have the PDF inside the purchase order in business network:

Business Network with PDF