• Inicio
  • Novedades
  • Academia SAP
  • FAQ
  • Blog
  • Contacto
S4PCADEMY_Logo
Twitter Linkedin Instagram
S4PCADEMY_Logo
Twitter Linkedin Instagram
FORMACIÓN SAP

Automatice la impresión de documentos PDF recibidos como archivos adjuntos de correo electrónico en SAP

By s4pcademy 


Resumen : En mi blog anterior He cubierto cómo procesar/guardar documentos pdf (puede tener varios) que se reciben por correo electrónico en SAP. En este blog, veremos cómo podemos habilitar la funcionalidad de impresión automática para documentos PDF en una impresora física dedicada o en una impresora local (LP01) en spool.

Requisito comercial adicional: todos los documentos PDF (si hay varios archivos adjuntos en el correo electrónico) deben generarse como un PDF en la cola y, en el caso de la impresión a dos caras, un documento no debe imprimirse en el reverso de otro.

Según el artículo anterior, ya hemos implementado los dos métodos de interfaz IF_INBOUND_EXIT_BCS en la salida entrante (clase Z: ZCL_BILLING_EMAIL_IN).

Método: IF_INBOUND_EXIT_BCS~CREATE_INSTANCE (Igual que el artículo anterior)

*Create instance of the object with the class itself

    DATA(lo_ref_instance) = NEW zcl_billing_email_in( ).
    IF lo_ref_instance IS BOUND.
      ro_ref = lo_ref_instance.
    ENDIF.

Método: IF_INBOUND_EXIT_BCS~PROCESS_INBOUND

Necesitamos escribir código en el segundo método de la interfaz para implementar la funcionalidad de impresión según el fragmento de código a continuación con los siguientes pasos.

  1. Obtenga los documentos PDF (formato hexadecimal) del objeto de correo electrónico
  2. Convertir formato hexadecimal a formato XSTRING
  3. Obtener el número total de páginas en cada documento PDF e identificar si el número total de páginas es impar: Método – GET_TOTAL_PAGES.
  4. Agregue una página en blanco adicional en el documento PDF si el número total de páginas es impar para evitar cualquier problema en caso de impresión a dos caras. (Requisito adicional): Método – GET_BLANK_PDF_PAGE
  5. Combinar todos los datos de XSTRING
  6. Imprimir documento PDF en la impresora: Método – PRINT_PDF_DOC
    CONSTANTS: lc_pdf TYPE char3 VALUE 'PDF'.        "Document Type PDF

    DATA: lv_printer      TYPE rspopshort,                "Spool: short name for output device
          lv_blank_page   TYPE xstring,
          lv_total_pages  TYPE i.

    CLEAR: e_retcode, es_t100msg.

lv_printer="LP01". "Or any physical printer in SAP but with short name

*Extract Attachment from e-mail
    TRY .
        IF io_sreq IS BOUND.
* Get document
          DATA(lo_ref_document) = io_sreq->get_document( ).
          IF lo_ref_document IS BOUND.

* Find all the PDF attachments and process it.
              TRY.
* Create PDF Merge Object to be printed in spool as one document
                    TRY.
                        DATA(lo_ref_pdf_merger) = NEW cl_rspo_pdf_merge( ).
                      CATCH cx_rspo_pdf_merge INTO DATA(lv_merge_ex).
                    ENDTRY.

                    DO lo_ref_document->get_body_part_count( ) TIMES.
                      TRY.
                          DATA(lv_doc_type) = lo_ref_document->get_body_part_attributes( im_part = sy-index )-doc_type.
                          TRANSLATE lv_doc_type TO UPPER CASE.

* If Document type is PDF then only proceed as program needs to look into PDF attachments only
                          IF lv_doc_type = lc_pdf.
* Get the file name of attached document
                            DATA(lv_filename) = lo_ref_document->get_body_part_attributes( im_part = sy-index  )-filename.

* Get the content of attached file in hex format.
                            DATA(ls_body_part_content) = lo_ref_document->get_body_part_content( sy-index ).

                            IF lv_filename IS NOT INITIAL AND ls_body_part_content IS NOT INITIAL.

		      TRY.
*Convert Hex data into Xstring
                        CALL METHOD cl_bcs_convert=>xtab_to_xstring
                           EXPORTING
                              it_xtab    = iv_body_part_content-cont_hex
                           RECEIVING
                              rv_xstring = DATA(lv_xstring).
                      CATCH cx_bcs .
                         continue.
                      ENDTRY.

                              IF lv_xstring IS NOT INITIAL.
                                IF lo_ref_pdf_merger IS BOUND.
                                  lo_ref_pdf_merger->add_document( lv_xstring ).
                                ENDIF.

* Get total no of pages in PDF document
                                CALL METHOD me->get_total_pages
                                  EXPORTING
                                    iv_content   = lv_xstring
                                  IMPORTING
                                    ev_pages     = DATA(lv_pages)
                                    ev_odd_pages = DATA(lv_odd_flag).

                                lv_total_pages = lv_total_pages + lv_pages.
                                IF lv_odd_flag EQ abap_true.
* If there is odd number of pages, then add one blank PDF page at the end to avoid back to back printing
                                  IF lv_blank_page IS INITIAL.
                                    CALL METHOD me->get_blank_pdf_page
                                      IMPORTING
                                        ev_blank_content = lv_blank_page.
                                  ENDIF.
                                  IF lv_blank_page IS NOT INITIAL.
* Merge all PDF documents in one PDF
                                    lv_total_pages = lv_total_pages + 1.
                                    lo_ref_pdf_merger->add_document( lv_blank_page ).
                                  ENDIF.
                                ENDIF.
                              ENDIF.
                            ENDIF.
                          ENDIF.
                        CATCH cx_document_bcs.
                          CONTINUE.
                      ENDTRY.
                      CLEAR: lv_xstring,ls_body_part_content,
                             lv_doc_type, lv_filename.
                    ENDDO.

* Merge all the PDF documents (in XSTRING format)
                      IF lo_ref_pdf_merger IS BOUND.
                        lo_ref_pdf_merger->merge_documents(
                                        IMPORTING
                                           merged_document = DATA(lv_pdf_all)
                                           rc              = DATA(lv_rc) ).
                        IF lv_rc NE 0.
                          lo_ref_pdf_merger->get_err_doc_index(
                                        IMPORTING
                                          index = DATA(lv_docindex) ).
                          MESSAGE e895(po) WITH lv_docindex INTO DATA(lv_errortext).
                        ENDIF.
                      ENDIF.

* Print the PDF document on dedicated printer 
                          CALL METHOD me->print_pdf_doc
                            EXPORTING
                              iv_content = lv_pdf_all
                              iv_dest    = lv_printer
                              iv_pages   = lv_total_pages.
                  ENDIF.
                CATCH cx_abap_error_analyze.
                  e_retcode  = if_inbound_exit_bcs=>gc_continue.
              ENDTRY.
          ENDIF.
        ENDIF.
      CATCH cx_os_object_not_found.
        e_retcode  = if_inbound_exit_bcs=>gc_continue.
    ENDTRY.

Para el punto 3: Método- GET_TOTAL_PAGESel código verificará si el número total de páginas es impar o no (usando la función MOD en el número entero ev_pages)

    DATA: lt_result TYPE match_result_tab.

* Convert XSTRING to STRING format
    CLEAR: ev_odd_pages, ev_pages.
    cl_bcs_convert=>xstring_to_string(
        EXPORTING
          iv_xstr   = iv_content
          iv_cp     =  1100                " SAP character set identification
        RECEIVING
          rv_string = DATA(lv_cont) ).

* Get total no of pages in PDF document
      FIND REGEX `/N (.{1,5})/` IN lv_cont IGNORING CASE RESULTS lt_result.
      IF sy-subrc NE 0.
        FIND ALL OCCURRENCES OF REGEX `/count (.{1,4})/` IN lv_cont IGNORING CASE RESULTS lt_result.
      ENDIF.

      DATA(lv_lines) = lines( lt_result ).
      IF lv_lines IS NOT INITIAL.
        READ TABLE lt_result ASSIGNING FIELD-SYMBOL(<fs_result>) INDEX lv_lines.
        IF sy-subrc EQ 0.
          READ TABLE <fs_result>-submatches ASSIGNING FIELD-SYMBOL(<fs_subm>) INDEX 1.
          IF sy-subrc EQ 0.
            DATA(lv_temp) = lv_cont+<fs_subm>-offset(<fs_subm>-length).
            CONDENSE lv_temp NO-GAPS.

            DATA(lv_pages) = CONV numc5( |{ lv_temp ALPHA = OUT }| ).
            ev_pages = CONV i( lv_pages ).
            IF ev_pages MOD 2 NE 0.
              ev_odd_pages = abap_true.
            ENDIF.
          ENDIF.
        ENDIF.
      ENDIF.

Para el punto 4: Método – GET_BLANK_PDF_PAGE

Si tenemos un número total de páginas impares, agregue una página PDF en blanco adicional. Podemos almacenar datos XSTRING para una página PDF en blanco en texto estándar SO10 y leerlos desde allí con el módulo de funciones READ_TEXT.

    DATA: lt_lines TYPE STANDARD TABLE OF tline,
          lv_data  TYPE string.

    CLEAR: ev_blank_content,
           lt_lines.

    CALL FUNCTION 'READ_TEXT'
      EXPORTING
        client                  = sy-mandt
        id                      = 'ST'
        language="E"
        name="ZBLANK_PDF_XSTRING"
        object="TEXT"
      TABLES
        lines                   = lt_lines
      EXCEPTIONS
        id                      = 1
        language                = 2
        name                    = 3
        not_found               = 4
        object                  = 5
        reference_check         = 6
        wrong_access_to_archive = 7
        OTHERS                  = 8.
    IF sy-subrc EQ 0.
      LOOP AT lt_lines ASSIGNING FIELD-SYMBOL(<fs_lines>).
        CONCATENATE lv_data <fs_lines>-tdline INTO lv_data.
      ENDLOOP.
      IF lv_data IS NOT INITIAL.
        ev_blank_content = CONV xstring( lv_data ).
      ENDIF.
    ENDIF.

Para imprimir el documento PDF, debemos abrir la solicitud de cola ADS y escribir allí según la lógica del código a continuación.

Método – PRINT_PDF_DOC

DATA: lv_handle    TYPE sy-tabix,
          lv_partname  TYPE adspart,
          lv_globaldir TYPE text1024,
          lv_dstfile   TYPE text1024,
          lv_filesize  TYPE i.
* Open an ADS spool request for writing the attachment file for printing
    CALL FUNCTION 'ADS_SR_OPEN'
      EXPORTING
        dest             = iv_dest
        doctype="ADSP"
        copies           = 1
        immediate_print  = abap_true
      IMPORTING
        handle           = lv_handle
        partname         = lv_partname
      EXCEPTIONS
        device_missing   = 1
        no_such_device   = 2
        operation_failed = 3
        wrong_doctype    = 4
        wrong_devicetype = 5
        OTHERS           = 6.
* If there is any error then set the variable lv_print_err_flag as X
    IF sy-subrc NE 0.
      DATA(lv_print_err_flag) = abap_true.
    ELSE.
* Provides storage location for ADS spool requests
      CALL FUNCTION 'ADS_GET_PATH'
        IMPORTING
          ads_path = lv_globaldir.
* Prepare the filepath to write the content
      CONCATENATE lv_globaldir '/' lv_partname '.pdf' INTO lv_dstfile.
* Open the filepath and transfer the PDF content in Spool
      TRY.
          OPEN DATASET lv_dstfile FOR OUTPUT IN BINARY MODE.
          IF sy-subrc NE 0.
            lv_print_err_flag = abap_true.
          ELSE.
            TRANSFER iv_content TO lv_dstfile.
            IF sy-subrc NE 0.
              lv_print_err_flag = abap_true.
            ELSE.
* Close the file when writing is completed
              CLOSE DATASET lv_dstfile.
              IF sy-subrc NE 0.
                lv_print_err_flag = abap_true.

              ELSE.

                lv_filesize = xstrlen( iv_content ).
*Writing all lines in an open ADS spool request
                CALL FUNCTION 'ADS_SR_CONFIRM'
                  EXPORTING
                    handle           = lv_handle
                    partname         = lv_partname
                    size             = lv_filesize
                    pages            = iv_pages
                  EXCEPTIONS
                    handle_not_valid = 1
                    operation_failed = 2
                    OTHERS           = 3.
                IF sy-subrc NE 0.
                  lv_print_err_flag = abap_true.
                ELSE.
*Closing an ADS spool request
                  CALL FUNCTION 'ADS_SR_CLOSE'
                    EXPORTING
                      handle           = lv_handle
                    EXCEPTIONS
                      handle_not_valid = 1
                      operation_failed = 2
                      OTHERS           = 3.
                  IF sy-subrc NE 0.
                    lv_print_err_flag = abap_true.
                  ENDIF.
                ENDIF.
              ENDIF.
            ENDIF.
          ENDIF.
        CATCH cx_sy_file_open
              cx_sy_codepage_converter_init
              cx_sy_conversion_codepage
              cx_sy_file_authority
              cx_sy_pipes_not_supported
              cx_sy_too_many_files
              cx_sy_file_close
              cx_sy_file_io
              cx_sy_file_open_mode
              cx_sy_pipe_reopen.
          lv_print_err_flag = abap_true.
      ENDTRY.
    ENDIF.

* If there is any error in printing then raise exception
    IF lv_print_err_flag = abap_true.
      RAISE EXCEPTION TYPE cx_abap_error_analyze
        EXPORTING
          message = CONV string( TEXT-001 )
          kind    = 'E'.
    ENDIF.

Ejecutemos la funcionalidad después de activar el correo electrónico que tiene tres documentos PDF separados.

Ahora ejecute el código T SP01 con el valor de pantalla de selección Creado por: MAILADM (o ID de sistema similar que procesa el correo electrónico entrante en SAP).

Nota: aquí hemos abordado la funcionalidad empresarial adicional (un documento PDF en la cola y la adición de una página PDF en blanco, si ninguna de las páginas del documento es impar). Estos no son necesarios para completar la funcionalidad de impresión automática y el código se puede suprimir en consecuencia.

Espero que hayas disfrutado este artículo. Siga leyendo y siéntase libre de proporcionar cualquier sugerencia o comentario. Gracias de nuevo por revisar este documento. ¡Aprecie su valioso tiempo!




Informe OOP para borrar artículos abiertos simulando la transacción FB05
Previo
Segmentación de demanda y suministro de SAP S/4HANA: una guía práctica para arquitectos de soluciones
Siguiente

Madrid

Calle Eloy Gonzalo, 27
Madrid, Madrid.
Código Postal 28010

México

Paseo de la Reforma 26
Colonia Juárez,  Cuauhtémoc
Ciudad de México 06600

Costa Rica

Real Cariari
Autopista General Cañas, 
San José, SJ 40104

Perú

Av. Jorge Basadre 349
San Isidro
Lima, LIM 15073

Twitter Linkedin Instagram
Copyright 2022 | All Right Reserved.