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.
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!
Calle Eloy Gonzalo, 27
Madrid, Madrid.
Código Postal 28010
Paseo de la Reforma 26
Colonia Juárez, Cuauhtémoc
Ciudad de México 06600
Real Cariari
Autopista General Cañas,
San José, SJ 40104
Av. Jorge Basadre 349
San Isidro
Lima, LIM 15073