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

    martes, 14 de abril de 2015

    Un ALV popup rápido y sencillo

    Esta es una forma rápida y sencilla de  lanzar un ALV en un popup o ventana emergente utilizando la clase CL_SALV_TABLE.  Esta clase es muy útil pues permite generar listados ALV con solo llamar a dos métodos de al misma, pero lo mejor es que también tiene un método para poder lanzar el ALV como si fuese un popup o ventana emergente a través de un método llamado SET_SCREEN_POPUP.


    Como hemos dicho, es muy sencillo manejar esta clase, solo necesitamos:
    • Una tabla interna con la información del listado
    • Una variable que instancie a la clase  cl_salv_table.

    Lo mejor, es ver el código, ya veréis como con 3 métodos creamos todo :

    REPORT zzprueba_alv_popup.
    
    TYPES: BEGIN OF type_matnr,
             matnr TYPE mara-matnr,
             meins TYPE mara-meins,
             maktx TYPE makt-maktx,
           END OF type_matnr.
    
    * Tabla interna con los datos del listado ALV
    DATA tl_matnr TYPE STANDARD TABLE OF type_matnr.
    
    * Objeto de la clase CL_SALV_TABLE
    DATA obj_alv_table TYPE REF TO cl_salv_table.
    
    SELECT m~matnr m~meins t~maktx
      INTO CORRESPONDING FIELDS OF TABLE tl_matnr
      FROM mara AS m
      INNER JOIN makt AS t
              ON m~matnr EQ t~matnr
      WHERE t~spras EQ sy-langu.
    
    * Instanciamos la clase con la tabla que contiene los datos
    cl_salv_table=>factory( IMPORTING r_salv_table = obj_alv_table
                            CHANGING t_table       = tl_matnr ).
    
    * Caracteristicas del POPUP
    obj_alv_table->set_screen_popup(
      start_column = 1
      end_column   = 160
      start_line   = 1
      end_line     = 20 ).
    
    * Lanzamos el ALV
    obj_alv_table->display( ).
    


    Resultado,  un ALV en una ventana emergente o popup .

    ALV dentro de un popup

    Si comentáis el método SET_SCREEN_POPUP el ALV sera a pantalla completa.

    El mismo ALV a pantalla compelta
    Muy sencillo, ¿no?

    jueves, 22 de enero de 2015

    Manejar campos a medida en pedidos de venta

    Es muy común añadir campos a medida o "campos Z" a los pedidos de venta de SAP para poder adaptar SAP a los procesos de negocio del cliente. Si se quiere añadir campos a medida, basta con crear un append a la tabla correspondiente:

    • VBAK si son campos a medida para la cabecera del pedido de ventas.
    • VBAP  si son campos a medida para las posiciones del pedido de venta.
    1. Desde la transacción SE11, dentro de la tabla correspondiente pulsamos el botón APPEND
    2. Creamos un nuevo append y añadimos nuestros campos a medida.
    3. Guardad y activar.

    Crear un nuevo append a la tabla
    Nuevos campos a medida para la tabla VBAP
    ATENCIÓN: Si añadís campos a través de append a las tablas estándar, SAP recomienda que el nombre del campo empiece por dos ZZ o dos YY, si no, os saltara una advertencia al activar el append a la tabla como me acaba de pasar a mi al utilizar una sola Z.

    Aviso: el nombre del campo debería empezar por ZZ o YY

    El problema surge cuando queremos gestionar estos campos con alguna bapi de ventas como:

    • SD_SALESDOCUMENT_CREATE
    • BAPI_SALESORDER_CHANGE
    • BAPI_SALESORDER_CREATEFROMDAT2
    • .... y más que hay....

    ¿Donde están nuestros campos a medida? ¿ como puedo usarlos en estas bapis?
    Para estas bapis, los campos a medida se gestionan a través del parámetro EXTENSIONIN.

    Primero, añadir los nuevos campos a las siguientes tablas a través de un APPEND:

    Si son campos a medida en las posiciones del pedido de venta:
    • BAPE_VBAP
    • BAPE_VBAPX
    • VBAPKOZ
    • VBAPKOZX
    Si son campos a medida en la cabecera del pedido de venta:
    • BAPE_VBAK
    • BAPE_VBAKX
    • VBAKKOZ
    • VBAKKOZX
    NOTA  MUY IMPORTANTE
    En las estructuras BAPE_VBAK/BAPE_VBAP todos los campos deben ser de tipo CHAR sino cuando más adelante rellenéis la estructura de la bapi, los campos numéricos saldrán con caracteres extraños como &# y no coincidirán las longitudes.

    Por ejemplo:

    •  Un campo DEC 15 con 3 decimales , lo definiremos como CHAR de 15
    •  Un campo INT de longitud, lo definiremos como CHAR de 8.



    En las estructuras  BAPE_VBAPX / BAPE_VBAKX los campos deben ser CHAR1 (char de long. 1)
    En las estructuras  VBAPKOZX o VBAKKOZX los campos deben ser CHAR1 (char de long. 1)

    Centrándonos en el ejemplo, ampliamos las tablas para posiciones de pedido:
    BAPE_VBAP - todos los campos son de tipo CHAR
    BAPE_VBAPX - todos los campos son de tipo CHAR
    VBAPKOZ
    VBAPKOZX

    Con esto hemos terminado la parte de las estructuras que necesitamos.
    Ahora vamos con el código.

    EXTENSIONIN es de tipo BAPIPAREX, su estructura es la siguiente:

    Estructura BAPIPAREX
    En el primer campo indicamos que estructura vamos a pasarle BAPE_VBAP o BAPE_VBAPX
    En los siguientes campos guardamos los valores de los campos concatenados como un solo registro.
    Lo mejor es utilizar el método fill_container_c de la  cl_abap_container_utilities.

    Aquí os dejo un ejemplo para rellenar la estructura EXTENSIONIN:

    DATA: wl_vbape  TYPE  bape_vbap,
          wl_vbapex TYPE  bape_vbapx.
    
    DATA: tl_extin type STANDARD TABLE OF bapiparex.
    
    FIELD-SYMBOLS: <fs_extin> TYPE bapiparex.
    
    wl_vbape-VBELN = wg_vbeln.   "nº de documento de ventas
    wl_vbape-POSNR = wg_posnr.   "nº de posición
    
    wl_vbapex-VBELN = wg_vbeln.  "nº de documento de ventas
    wl_vbapex-POSNR = wg_posnr.  "nº de posición
    
    wl_vbape-zzcampo1 = 'prueba'.
    wl_vbape-zzcampo2 = 'de campos'.
    wl_vbape-zzcampo3 = 'a medida'.
    
    wl_vbapex-zzcampo1 = 'X'.   "o ABAP_TRUE si usais TYPE-POOLS: ABAP.
    wl_vbapex-zzcampo2 = 'X'.
    wl_vbapex-zzcampo3 = 'X'.
    
    APPEND INITIAL LINE TO it_extin ASSIGNING  <fs_extin>.
    <fs_extin>-structure = 'BAPE_VBAP'.
    
    
    *si parecen caracteres extraños, revisar que todos los campos de la estrc son CHAR
    cl_abap_container_utilities=>fill_container_c( EXPORTING im_value  = wl_vbape
                                                   IMPORTING ex_container = <fs_extin>+30 ).
    
    
    APPEND INITIAL LINE TO it_extin ASSIGNING  <fs_extin>.
    <fs_extin>-structure = 'BAPE_VBAPX'.
    
    cl_abap_container_utilities=>fill_container_c( EXPORTING im_value  = wl_vbapex
                                                   IMPORTING ex_container = <fs_extin>+30 ).
    
    * ya podemos usarlo en la bapi:
        CALL FUNCTION 'SD_SALESDOCUMENT_CREATE'
          EXPORTING
            sales_header_in      = wa_so_hearder
            sales_header_inx     = wa_so_hearderx
            testrun              = test
          IMPORTING
            salesdocument_ex     = wa_saorder
          TABLES
            return               = lt_return
            sales_items_in       = it_items
            sales_partners       = it_fi
            extensionin          = it_extin. "<Campos a medida del pedido


    Notas relacionadas:
    Note 143580 - Information on SD BAPIs and customer enhancement

    viernes, 7 de noviembre de 2014

    Abap in Eclipse (AiE) : Nuevas funcionalidades I

    Eclipse incluye una serie de nuevas herramientas para facilitarnos la creación de código ABAP.

    Auto-completar palabras claves

    Nos permite escribir mas rápido el código, sugiriendo palabras clave según escribimos el código.
    Es suficiente con escribir la primeras letras para que eclipse nos sugiera la palabra clave:
    • Con la tecla TAB aceptamos la palabra que nos sugiere y esta se completa automáticamente
    • Ctrl + Barra Espaciadora  nos mostrara todas las sugerencia disponible.
    Por ejemplo:

    Auto-completar palabra clave

    Pero si antes, mientras nos sugiere start-of-editing  le doy a Ctrl+barra espaciadora,  aparecerán todas las palabras claves posibles que coinciden con lo que llevo escrito hasta el momento y podre seleccionar una para auto-completar la palabra clave.

    Lista completa de palabras clave coincidentes

    Auto-completar código

    la combinación Ctrl + Barra espaciadora no solo sirve para mostrar todas las palabras claves posibles, también se puede utilizar para auto-completar código como llamadas a métodos de clases, atributos, eventos, bapis o clases.

    Por ejemplo, podemos ver los atributos de nuestras variables internas

    No se vosotros, pero cuando me tocaba codificar una llamada a una bapi, tenia que abrir una nueva ventana con la transacción SE37 para ver el nombre y tipo de los parámetros de una bapi. En eclipse con la combinación Ctrl + Barra espaciadora  podemos ver la información de la bapi  sin necesidad   de abrir una nueva ventana con el código de la bapi.



    Simplemente Ctrl + Barra espaciadora, selecciono la bapi Mayusculas + Intro.
    La firma de la bapi se completa automáticamente en mi código.



    Lo mismo si estamos escribiendo el nombre de una clase o sus métodos. mientras escribimos el nombre de la clase, podemos usar la combinación Ctrl + Barra espaciadora para ver todas las clases y sus métodos coincidentes.


    Si ya tenemos la clase, podemos usar la combinación Ctrl + Barra espaciadora para ver  sus métodos y atributos. Seleccionar el método o atributo que queremos auto-completar y lo ejecutamos con la combinación Mayus + Intro.





    La ayuda y documentación en linea

    Como todo entrono de programación, tenemos disponible en cualquier momento la documentación para ayudarnos en la implementación del código ABAP que desarrollemos. Al igual que en la SE38 bastara con situar el cursor sobre la palabra clave  y pulsar F1 para que aparezca la ayuda de SAP. Esta ayuda funciona exactamente igual que la ayuda que utilizamos cuando trabajamos desde la transacción SE38.

    Ayuda de SAP

    Nota: Esta ayuda no esta en Eclipse, es un servicio web que consumimos del sistema SAP al que estamos conectados, si no os funciona, revisar que estén activo  los servicios  web HTTP correspondientes para poder acceder a la ayuda.

    Error al acceder a la ayuda de SAP


    Además, la ayuda incluye ejemplos ejecutables.
    Por ejemplo en la ayuda busqueda de ADBC, Query:


    Ejemplos ejecutables en la ayuda


    Entradas anteriores:
    Abap in Eclipse (AiE)
    Abap in Eclipse (AiE): Instalación
    Abap in Eclipse (AiE) : El entorno de trabajo de Eclipse

    Entradas siguientes:
    Abap in Eclipse (Aie) : Nuevas funcionalidades II  ( en proceso )

    jueves, 6 de noviembre de 2014

    Filtrar los datos para las ayudas busquedas

    Una ayuda búsqueda para un campo de una dynpro, no tiene porque mostrar toda la información al usuario. Podemos filtrar la información que aparece en un ayuda búsqueda basándonos en los datos introducidos por el usuario en otros campos de la dynpro.

    Por ejemplo, imaginemos dos campos SOCIEDAD y CLIENTE.

    Si el usuario rellena primero el campo SOCIEDAD y después activa la ayuda búsqueda del campo PROVEEDOR, queda mucho mejor que aparezcan solamente los clientes de la sociedad que ha indicado que todos los clientes de todas las sociedades del sistema.

    Ayuda búsqueda filtrada

    Vamos con el  programa de ejemplo, seria sencillo, un modulpool con una dynpro y dos campos.



    El proceso, cuando el usuario active la ayuda búsqueda del campo Proveedores, sera :
    1. Leer los campos que necesitamos para filtrar la ayuda búsqueda
    2. Crear y lanzar la ayuda búsqueda
    3. Completar los campos con los datos seleccionados de la ayuda búsqueda por el usuario.
    PROCESS ON VALUE-REQUEST  es el proceso de la dynpro que se lanza cuando el usuario activa la ayuda búsqueda de un campo.  Si el campo , tiene asociado en esta sección un modulo, este sera lanzado cuando el usuario active la ayuda búsqueda del campo. No viene por defecto en la pestaña log. de proceso cuando creamos la dynpro, tenemos que añadirlo nosotros.


    PROCCES ON VALUE-REQUEST


    Y dentro del modulo, llamamos a nuestra subrutina.

    Modulo y subrutina para la ayuda búsqueda
    La subrutina, esta completa al final de la entrada.

    Y aquí tenéis el resultado, dos capturas de la misma ayuda búsqueda, pero en una hemos rellenado el campo SOCIEDAD y la ayuda búsqueda queda filtrada por ese campo.


    Ayuda búsqueda sin filtrar , el campo SOCIEDAD esta vació

    Ayuda búsqueda filtrada por el contenido del campo SOCIEDAD
    Hay que tener en cuenta que si el usuario , introduce la sociedad, no pulsa intro o provoca otro evento e inmediatamente activa la ayuda búsqueda, el campo SOCIEDAD nos llegara vació a a la ayuda búsqueda.

    Para evitarlo, utilizaremos la bapi  DYNP_VALUES_READ para leer el contenido ACTUAL de los campos de la dynpro.


    Y esta sera la subrutina encargada de filtrar y generar la ayuda búsqueda:

    *&---------------------------------------------------------------------*
    *&      Form  F4_LIFNR_HELP_F01
    *&---------------------------------------------------------------------*
    FORM f4_lifnr_help_f01 .
    
      TYPES: BEGIN OF type_f4_help_lifnr,
               bukrs TYPE lfb1-bukrs,
               butxt TYPE t001-butxt,
               lifnr TYPE lfa1-lifnr,
               name1 TYPE lfa1-name1,
             END OF type_f4_help_lifnr.
    
      DATA: tl_map        TYPE TABLE OF dselc.
      DATA: tl_help_lifnr TYPE TABLE OF type_f4_help_lifnr.
      DATA: tl_ddshretval TYPE TABLE OF ddshretval.
      DATA: tl_dynpread   TYPE TABLE OF dynpread.
      RANGES: r_bukrs FOR   lfb1-bukrs.
    
      FIELD-SYMBOLS: <fs_ddshretval> TYPE ddshretval,
                     <fs_dynpread>   TYPE dynpread,
                     <fs_dselc>      TYPE dselc.
    
      APPEND INITIAL LINE TO tl_dynpread ASSIGNING <fs_dynpread>.
      <fs_dynpread>-fieldname = 'WL_BUKRS'.  "Campo de la dynpro
    
      CALL FUNCTION 'DYNP_VALUES_READ'
        EXPORTING
          dyname               = sy-repid
          dynumb               = sy-dynnr
        TABLES
          dynpfields           = tl_dynpread
        EXCEPTIONS
          invalid_abapworkarea = 1
          invalid_dynprofield  = 2
          invalid_dynproname   = 3
          invalid_dynpronummer = 4
          invalid_request      = 5
          no_fielddescription  = 6
          invalid_parameter    = 7
          undefind_error       = 8
          double_conversion    = 9
          stepl_not_found      = 10
          OTHERS               = 11.
    
      CHECK sy-subrc EQ 0.
    
    *  Si todo ha ido bien, ya podemos crear el rango para el filtro
      READ TABLE tl_dynpread  INDEX 1 ASSIGNING <fs_dynpread>.
      IF <fs_dynpread>-fieldvalue IS NOT INITIAL.
        r_bukrs-sign   = 'I'.
        r_bukrs-option = 'EQ'.
        r_bukrs-low    = <fs_dynpread>-fieldvalue.
        APPEND r_bukrs.
      ENDIF.
    
      SELECT  b~bukrs t~butxt a~lifnr a~name1
       INTO CORRESPONDING FIELDS OF TABLE tl_help_lifnr
       FROM lfa1 AS a
       INNER JOIN lfb1 AS b
               ON a~lifnr EQ b~lifnr
       INNER JOIN t001 AS t
               ON b~bukrs EQ t~bukrs
       WHERE b~bukrs IN r_bukrs.
    
       CHECK ( sy-subrc EQ 0 ).
    
       SORT tl_help_lifnr ASCENDING BY BUKRS lifnr.
    
    *  Mapeamos los campos de la ayuda busqueda con los de la dynpro
       APPEND INITIAL LINE TO tl_map ASSIGNING <fs_dselc>.
       <fs_dselc>-fldname   = 'F0001'.    "1º columna de la tabla interna tl_help_lifnr
       <fs_dselc>-dyfldname = 'WL_BUKRS'. "Campo de la dynpro correspondiente
    
       APPEND INITIAL LINE TO tl_map ASSIGNING <fs_dselc>.
       <fs_dselc>-fldname   = 'F0003'.    "3º columna de la tabla interna tl_help_lifnr
       <fs_dselc>-dyfldname = 'WL_LIFNR'. "Campo de la dynpro correspondiente
    
    *  Lanzamosla ayuda busqueda
       CALL FUNCTION 'F4IF_INT_TABLE_VALUE_REQUEST'
        EXPORTING
          retfield         = 'LIFNR'
          dynprofield      = 'WL_LIFNR'
          value_org        = 'S'
          dynpprog         = sy-repid
          dynpnr           = sy-dynnr
          callback_program = sy-repid
        TABLES
          value_tab        = tl_help_lifnr
          return_tab       = tl_ddshretval
          dynpfld_mapping  = tl_map.
    
    ENDFORM.                    " F4_LIFNR_HELP_F01
    


    Entradas relacionadas:
    Recuperar varios campos con una ayuda busqueda

    miércoles, 5 de noviembre de 2014

    Abap in Eclipse (AiE) : Hello World

    Llego el momento de escribir nuestro primer programa en Abap con Eclipse: "Hello World".

    Antes de empezar, recordar que es necesario que tengamos acceso a un sistema SAP.

    Si estáis utilizando un SAP NetWeaver AS ABAP 7.03 SP04 64-bit Trial o superior, aseguraros de que el servicio esta activo en windows, en INICIO accedemos a EJECUTAR y tecleamos "services.msc".

    Buscamos el servicio SAPXXX_00 ( donde XXXX es el ID sel sistema ) con el botón derecho del ratón, nos sale el menú para activar el servicio.


    Ejecutamos el Sap Management Console para arrancar el sistema SAP.


    Arrancamos Eclipse y activamos la perspectiva ABAP.

    Desde el menú superior File -> New ->Abap Project
    También  desde el explorador de proyectos -> Menu contextual ( click botón derecho ) -> New ->Proyect
    Crear nuevo proyecto en Eclipse

    Abrimos la carpeta Abap -> Abap proyect -> Next



    Introducir los datos de conexión al sistema SAP,
    Es posible importar los datos de  conexión si tenemos instalado el  cliente de SAP SapGUI.

    Importar la conexión del SapGUI

    Crear conexión a SAP manualmente



    El siguiente paso, es autentificarse en el sistema con nuestro usuario/contraseña. Si no hay ningún error de compatibilidad ( recordar que necesitamos que le sistema Sap tenga SAP Kernerl 7.20 y el SAP BASIS 7.31 con el nivel de parche 4 ) nos conectaremos al sistema desde Eclipse y podremos empezar a trabajar.

    usuario / contraseña para acceder al sistema SAP

    Empezemos a crear nuestro programa "Hello World":

    1. Seleccionar el  proyecto ( systema SAP ).
    2. Botón derecho del ratón para desplegar el menu contextual
    3. New -> Others... -> Abap Repository Object,
    4. Seleccionar Source Library -> Abap Program




    Se puede  crear cualquier objeto del repositorio de SAP desde tablas, funciones, enhancements, BSP, paquetes, etc...
    Introducimos los datos del programa como el  nombre (que empieze por Z o Y ), descripción y paquete para transporte.
    Como yo  no voy a transportar el programa a otro sistema lo he incluido en el paquete local $TMP.

    atributos del nuevo rapport ABAP

    Siguiente .-> Finalizar y se abre el editor ABAP ( transacción SE38 en el sistema Sap ).

    Escribimos la siguiente linea:

    write "Hello World, programado en Eclipse".



    En la barra superior, tenemos los botones básicos, como verificación de sintaxis, activar , el "where used list...", etc...  todos los botones del editor Abap están en Eclipse. 


    Revisamos la sintaxis y activamos el programa:


    Os va a dar un error de verificación de sintaxis, la cadenas de texto van con comillas simples no dobles, fijaos en la ventana inferior con la pestaña Problems:
















    Cambiamos las comillas dobles por comillas dobles, verificar y activar si no hay más errores.
    Para ejecutarlo:

    Como veis, la integración de Eclipse - Abap - Sistema SAp es total, es un gran avance con respecto al editor actual de Abap. Otro ejemplo, vamos a buscar desde Eclipse todas las tablas donde se este usando el elemento de datos KUNNR ( nº de cliente ) en el sistema Sap. 





    En las siguientes entradas seguiremos probando más sobre Abap in Eclipse.

    Entradas siguientes: