miércoles, 24 de junio de 2015

Enviar documentos anexos como adjuntos de un email


En uno de mis últimos proyecto, el cliente , anexaba archivos PDF a las entregas de pedidos de ventas en la transacción VL03N y nos solicito un desarrollo para poder enviar al destinatario de la entrega, un email donde se adjuntasen automáticamente los anexos de la entrega

El proceso constaría de los siguientes pasos:
  1. El usuario selecciona las entregas a través de una pantalla de selección standard.
  2. Para cada entrega seleccionada:
    1. El programa busca los documentos PDF anexados a la entrega.
    2. El programa recupera el email asignado al cliente.
    3. Crear y enviar un email al cliente con los documentos PDF anexados como adjunto
diagrama de actividades
    Antes de empezar con el desarrollo, conviene repasar como y donde se almacena los anexos.
    También asegurarnos que esta correctamente configurado el SAPconnect desde la transacción SCOT.


    El primer paso, una vez tenemos el número de entrega, es recuperar los enlaces a los documentos que tiene anexados. Estos enlaces están guardados en la tabla SRGBTBREL y podemos acceder a ellos con un SELECT como el siguiente:

    SELECT instid_b INTO TABLE tl_instid_b
       FROM srgbtbrel
       WHERE reltype  EQ 'ATTA'
         AND instid_a EQ pi_vbeln  "nº de la entrega
         AND typeid_a EQ 'LIKP'.
    

    Ahora que ya tenemos los enlaces, podemos utilizar la bapi SO_DOCUMENT_READ_API1 para recuperar de cada enlace el archivo PDF . Esta bapi nos retornara el archivo en una tabla  de tipo SOLIX con una longitud de 255 para almacenar datos raw. Si concatenásemos todos los registros de la tabla SOLIX obtendríamos una cadena binaria que representaría el archivo PDF.

    Estructura SOLIX

    La configuración del email, adjuntar los archivos PDF y su envió es la parte mas fácil de todo el desarrollo. Desde la versión 6.10 se incluyen en SAP varias funciones y clases para el procesamiento del correo vía SMTP desde nuestras aplicaciones:
    • CL_BCS
    • SO_DOCUMENT_SEND_API1
    • SO_NEW_DOCUMENT_ATT_SEND_API1
    • SO_NEW_DOCUMENT_SEND_API1
    Para este desarrollo utilizamos la clase estándar CL_BCS. Esta clase sirve como interfaz para Business Communication Services (BCS) que es un componente de SAP que permite a los desarrolladores una forma sencilla de integrar el envió de la información a través de mensajes, ya sean email, fax, etc... Puede utilizarse también para muchas mas tareas como control de estados pero en este caso nos centramos en el envio de emails con documentos adjuntos.

    BCS se apoya sobre SAPconnect para enviar los emails.

    BCS se apoya en SAPconnect para enviar los objetos al exterior

    La dirección de email del cliente se encuentra en la tabla ADR6 en el campo SMTP_ADDR.
    Se puede acceder a ella a través del código del cliente KUNNR  pasando por la tabla KNA1.

    KNA1 -ADR6


    Para las pruebas, he adjuntado dos PDF a una entrega en la transacción VL03N

    Entrega 80000035 con dos archivos PDF anexados

    Una vez ejecutado el desarrollo, en la transacción SOST podemos ver el email creado listo para salir.

    Email generado en la transacción SOST

    Contenido del email generado, están adjuntos los archivos PDF de la entrega

    A continuación os dejo el código completo

    *&---------------------------------------------------------------------*
    *& Report  ZZPRUEBA_ANEXOS_EMAIL
    *& Autor   David Rueda Barrón
    *&---------------------------------------------------------------------*
    *& Envio de documentos PDF anexos a las entregas por email
    *&---------------------------------------------------------------------*
    
    REPORT zzprueba_anexos_email.
    
    
    *&---------------------------------------------------------------------*
    *& Parámetros de Selección
    *&---------------------------------------------------------------------*
    SELECTION-SCREEN BEGIN OF BLOCK block01 WITH FRAME TITLE text-001.
    PARAMETERS: p_vbeln TYPE likp-vbeln.
    SELECTION-SCREEN END OF BLOCK block01.
    
    *&---------------------------------------------------------------------*
    *& START-OF-SELECTION
    *&---------------------------------------------------------------------*
    START-OF-SELECTION.
      PERFORM f_enviar_email_adjuntos USING p_vbeln.
    
    *&------------------------------------------------------------------
    *& F_ENVIAR_EMAIL_ADJUNTOS
    *&------------------------------------------------------------------
    *  Enviar los doc. anexados de la entrega como adjuntos de email
    *&------------------------------------------------------------------
    FORM f_enviar_email_adjuntos USING pi_vbeln TYPE likp-vbeln.
    
      TYPES: BEGIN OF type_instid_b,
               instid_b TYPE srgbtbrel-instid_b,
             END OF type_instid_b.
    
      DATA: tl_instid_b TYPE STANDARD TABLE OF type_instid_b.
      DATA: wl_doc_id   TYPE sofolenti1-doc_id.
      DATA: tmp_solix   TYPE STANDARD TABLE OF solix.
      DATA: wl_file     TYPE string.
      DATA: wl_data     TYPE sofolenti1.
    
      DATA: wl_filename(20) TYPE c,
            wl_extension(3) TYPE c.
    
      DATA: lo_send_request TYPE REF TO cl_bcs,
            lo_document     TYPE REF TO cl_document_bcs,
            lo_sender       TYPE REF TO if_sender_bcs,
            lo_recipient    TYPE REF TO if_recipient_bcs.
    
      DATA wl_kunnr TYPE likp-kunnr.
      DATA wl_SMTP_ADDR TYPE ADR6-SMTP_ADDR.
    
      DATA: wl_email_line(80) TYPE c,
            lt_message_body   TYPE bcsy_text,
            wl_message_body   TYPE bcsy_text,
            w_subject(50)     TYPE c,
            l_sub             TYPE so_obj_des.
    
      DATA wl_error_ref TYPE REF TO cx_root.
      DATA wl_string    TYPE string.
    
      FIELD-SYMBOLS: <fs_instid_b> TYPE type_instid_b.
    
      CLEAR wl_SMTP_ADDR.
      REFRESH tl_instid_b.
    
      SELECT instid_b INTO TABLE tl_instid_b
       FROM srgbtbrel
       WHERE reltype  EQ 'ATTA'
         AND instid_a EQ pi_vbeln  "nº de la entrega
         AND typeid_a EQ 'LIKP'.
    
      IF tl_instid_b[] IS INITIAL.
        MESSAGE text-e01 TYPE 'I' DISPLAY LIKE 'E'.  "La entrega no tiene documentos anexados
        EXIT.
      ENDIF.
    
    * Recuperamos la direccion email del cliente de la entrega, sera el destinatario
      SELECT SINGLE kunnr into wl_kunnr
        FROM LIKP
        WHERE vbeln EQ pi_vbeln.
    
      SELECT SINGLE s~SMTP_ADDR INTO WL_SMTP_ADDR
        FROM kna1 as K
        INNER JOIN adr6 as s
           ON k~ADRNR EQ s~ADDRNUMBER
        WHERE kunnr EQ wl_kunnr.
    
      IF ( sy-subrc <> 0 ) OR ( WL_SMTP_ADDR IS INITIAL ).
    *   El cliente no tiene direción de email
        MESSAGE text-e02 TYPE 'I' DISPLAY LIKE 'E'.
        EXIT.
      ENDIF.
    
    * Inicializamos el objeto lo_send_request, utilizaremos sus metodos para enviar el email
    * Inicializamos el objeto lo_document, sera el objeto que enviaremos  por BCS<
      wl_message_body = 'Le adjuntamos los documentos PDF correspondientes  a su entrega'.
      APPEND wl_message_body TO lt_message_body.
      wl_message_body = 'Atentamente'.
      APPEND wl_message_body TO lt_message_body.
      wl_message_body = 'El supervisor'.
      APPEND wl_message_body TO lt_message_body.
    
      lo_send_request = cl_bcs=>create_persistent( ).
    
      lo_document = cl_document_bcs=>create_document(
                                    i_type = 'RAW'
                                    i_text = lt_message_body   "Mensaje del email
                                    i_subject = text-s01 && pi_vbeln ).        "Asunto del email
    
      CALL METHOD lo_send_request->set_document( lo_document ).
    
    * Añadimos el remitente del email, en este caso el usuario de sap que lo crea
      lo_sender = cl_sapuser_bcs=>create( sy-uname ).
      CALL METHOD lo_send_request->set_sender( i_sender = lo_sender ).
    
    * Añadimos la dirección email del destinatario, sera la direccion email del cliente.
    * Las direcciones de correo electronico se encuentranen al tabal ADR6
      lo_recipient = cl_cam_address_bcs=>create_internet_address( '' ).
      CALL METHOD lo_send_request->add_recipient
        EXPORTING
          i_recipient = lo_recipient
          i_express   = 'X'.
    
    * Añadimos los documentos adjuntos que hemos recuperado
    * Utilizamos la BAPI SO_DOCUMENT_READ_API1 para recuperarlos
      LOOP AT tl_instid_b ASSIGNING <fs_instid_b>.
    
        CLEAR:  wl_doc_id, wl_file, wl_extension.
        REFRESH: tmp_solix.
    
        wl_doc_id = <fs_instid_b>-instid_b.
    
        CALL FUNCTION 'SO_DOCUMENT_READ_API1'
          EXPORTING
            document_id                = wl_doc_id
    *       FILTER                     = 'X '
          IMPORTING
            document_data              = wl_data
          TABLES
    *       OBJECT_HEADER              =
    *       OBJECT_CONTENT             =
    *       OBJECT_PARA                =
    *       OBJECT_PARB                =
    *       ATTACHMENT_LIST            =
    *       RECEIVER_LIST              =
            contents_hex               = tmp_solix
          EXCEPTIONS
            document_id_not_exist      = 1
            operation_no_authorization = 2
            x_error                    = 3
            OTHERS                     = 4.
    
        CHECK tmp_solix[] IS NOT INITIAL.
    
        TRY.
    
            w_subject = wl_data-obj_descr.
            CALL METHOD lo_document->add_attachment
              EXPORTING
                i_attachment_type    = 'PDF'
                i_attachment_subject = w_subject
                i_att_content_hex    = tmp_solix[].
    
          CATCH cx_root INTO wl_error_ref.
    *      Error al adjuntar el archivo.
            wl_string = wl_error_ref->get_text( ).
            MESSAGE wl_string TYPE 'I' DISPLAY LIKE 'E'.
        ENDTRY.
    
      ENDLOOP.
    
    *  Enviamos el email, ira directamente a la SOST en cuanto hagamos el commit
      CALL METHOD lo_send_request->set_document( lo_document ).
      lo_send_request->send( i_with_error_screen = 'X' ).
    
      IF sy-subrc <> 0 .
        CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
      ELSE.
        CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
          EXPORTING
            wait = 'X'.
      ENDIF.
    
    
    ENDFORM.                    " F_ENVIAR_EMAIL_ADJUNTOS
    
    

    Referencias:
    ABAP Development - Sending Mails
    Send email from ABAP with class CL_BCS