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

Informe OOP para borrar artículos abiertos simulando la transacción FB05

By s4pcademy 


Estoy escribiendo esta publicación de blog para demostrar cómo podemos estructurar un informe ABAP de una manera OOP que nos ayude a resolver un problema de la vida real. Quiero decir en primer lugar que no creo que mi ejemplo implique todas las mejores prácticas de programación orientada a objetos, pero es un intento honesto de un ABAPer procedimental para hacer el cambio al mundo de la orientación a objetos.

La solicitud era crear un informe que ayudara a compensar las partidas abiertas de un socio comercial entre sí. El interlocutor comercial se configuró en el sistema con los roles de Cliente y Proveedor. Entonces, el propósito de nuestro programa es encontrar si para un socio comercial se han generado asientos contables tanto como cliente como proveedor y si el monto total de estos asientos es cero. Entonces, puede comprender que si encontramos tales entradas, debemos borrarlas ejecutando el código de transacción FB05.

Los asientos contables debían ser compensados ​​de acuerdo con uno de los siguientes criterios:

  • ZUONR – Asignación
  • XREF2 – Ref. Clave 2
  • XBLNR – Referencia

La siguiente imagen muestra la pantalla de selección de nuestro programa personalizado:

He organizado mi código de manera similar al patrón de objetos MCV y digo similar, porque mis tres clases no hacen exactamente lo que se supone que deben hacer si seguimos estrictamente este patrón.

Así que he creado estas tres clases para ayudar con la lógica del programa:

  1. lcl_read_data -> Lee artículos abiertos para los proveedores y clientes y guarda los datos leídos en los atributos de instancia mt_bsik (Vendedores) y mt_bsid (Clientes)
  2. lcl_process_data –> Utiliza la clase anterior como atributo de instancia para tener acceso a datos de clientes y proveedores. Luego, la clase combina los datos de estas dos fuentes e identifica qué líneas se pueden borrar entre sí. Por último, si el usuario no ha ejecutado una prueba, borra estos elementos identificados a través del código de transacción FB05. Después de todo el procesamiento, los datos se guardan en el atributo de instancia. mt_total.
  3. lcl_display_data –> Utiliza la clase lcl_process_data como atributo de instancia para tener acceso a los datos procesados ​​y mostrarlos en un ALV.

He creado el objeto principal ZFI_PAREGGIO_CLNT_FORN y algunos Incluidos para modularizar el programa. Debajo del código de este objeto:

&----------------------------------------------------------------------*
*& Report ZPAREGGIO_CLNT_FORN
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT zfi_pareggio_clnt_forn.

INCLUDE zfi_pareggio_clnt_forn_top.  "Global declarations
INCLUDE zfi_pareggio_clnt_forn_sel.  "SELECTION SCREEN definition
INCLUDE zfi_pareggio_clnt_forn_def.  "Class definition
INCLUDE zfi_pareggio_clnt_forn_imp.  "Class implementation
INCLUDE zfi_pareggio_clnt_forn_form. "Form to handle hotspot click

*----------------------------------------------------------------------*
* INITIALIZATION Event
*----------------------------------------------------------------------*
INITIALIZATION.
  DATA(gt_list) = VALUE vrm_values(
    ( key = 'ZUONR' text = TEXT-t01 )
    ( key = 'XREF2' text = TEXT-t02 )
    ( key = 'XBLNR' text = TEXT-t03 ) ).

  CALL FUNCTION 'VRM_SET_VALUES'
    EXPORTING
      id              = 'Z_PAR'
      values          = gt_list
    EXCEPTIONS
      id_illegal_name = 1
      OTHERS          = 2.

  "Object to read data from database
  go_read_data = NEW #( ).

  "Object to prepare data that with be displayed in ALV
  go_process_data = NEW #( io_read_data = go_read_data ).

  "Object to display the final output of the report
  go_disp_data = NEW #( io_process_data = go_process_data ).

*----------------------------------------------------------------------*
* START-OF-SELECTION Event
*----------------------------------------------------------------------*
START-OF-SELECTION.
  go_read_data->read_data( ).
  go_process_data->process_data( ).

*----------------------------------------------------------------------*
* END-OF-SELECTION Event
*----------------------------------------------------------------------*
END-OF-SELECTION.
  go_disp_data->display_data( ).

No entraré en muchos detalles, porque puedo decir con orgullo que habla por sí mismo (pero de todos modos, no dude en preguntar sobre este código y todo lo que seguirá).

A continuación está la declaración de las variables globales que he tratado de evitar tanto como sea posible:

&---------------------------------------------------------------------*
*& Include ZFI_PAREGGIO_CLNT_FORN_TOP
*&---------------------------------------------------------------------*
TYPES: BEGIN OF ty_bp,
         bp TYPE char10,
       END OF ty_bp.
DATA wa_bp TYPE ty_bp. "Business Partner structure

DATA wa_bkpf TYPE bkpf.

CONSTANTS c_text TYPE bkpf-bktxt VALUE 'Eq. rev. charg. VAT ent.'.

CLASS: lcl_read_data    DEFINITION DEFERRED,
       lcl_process_data DEFINITION DEFERRED,
       lcl_display_data DEFINITION DEFERRED.

DATA: go_read_data    TYPE REF TO lcl_read_data,
      go_process_data TYPE REF TO lcl_process_data,
      go_disp_data    TYPE REF TO lcl_display_data.

También la declaración de la PANTALLA DE SELECCIÓN es bastante simple de seguir:

*&---------------------------------------------------------------------*
*& Include ZFI_PAREGGIO_CLNT_FORN_SEL
*&---------------------------------------------------------------------*
SELECTION-SCREEN BEGIN OF BLOCK select WITH FRAME TITLE TEXT-001.
  SELECT-OPTIONS s_bukrs FOR wa_bkpf-bukrs OBLIGATORY.
  PARAMETERS s_waers TYPE bkpf-waers DEFAULT 'EUR' OBLIGATORY.
  SELECT-OPTIONS: s_belnr FOR wa_bkpf-belnr,
                  s_gjahr FOR wa_bkpf-gjahr,
                  s_budat FOR wa_bkpf-budat,
                  s_bldat FOR wa_bkpf-bldat,
                  s_blart FOR wa_bkpf-blart,
                  s_bp    FOR wa_bp-bp.
  PARAMETERS: z_par(5) TYPE c AS LISTBOX VISIBLE LENGTH 20 OBLIGATORY,
              test  TYPE c AS CHECKBOX.
SELECTION-SCREEN END OF BLOCK select.

SELECTION-SCREEN BEGIN OF BLOCK clearing WITH FRAME TITLE TEXT-002.
  PARAMETERS: r_budat TYPE bkpf-budat OBLIGATORY DEFAULT sy-datum,
              r_bldat TYPE bkpf-bldat OBLIGATORY DEFAULT sy-datum,
              r_blart TYPE bkpf-blart OBLIGATORY DEFAULT 'AB',
              r_bktxt TYPE bkpf-bktxt DEFAULT c_text.
SELECTION-SCREEN END OF BLOCK clearing.

Ahora aquí viene la parte interesante. En primer lugar, el include con las definiciones de las clases:

*&---------------------------------------------------------------------*
*& Include ZFI_PAREGGIO_CLNT_FORN_DEF
*&---------------------------------------------------------------------*

CLASS lcl_read_data DEFINITION FINAL.
  PUBLIC SECTION.
    TYPES: BEGIN OF ty_bsik,
             bukrs TYPE bsik_view-bukrs,
             lifnr TYPE bsik_view-lifnr,
             waers TYPE bsik_view-waers,

             "One of the following next three fields will be used for clearing
             zuonr TYPE bsik_view-zuonr,
             xref2 TYPE bsik_view-xref2,
             xblnr TYPE bsik_view-xblnr,

             belnr TYPE bsik_view-belnr,
             gjahr TYPE bsik_view-gjahr,
             blart TYPE bsik_view-blart,
             bldat TYPE bsik_view-bldat,
             budat TYPE bsik_view-budat,
             wrbtr TYPE bsik_view-wrbtr,
             shkzg TYPE bsik_view-shkzg, "To check if value is multiplied by -1
           END OF ty_bsik.
    TYPES tt_bsik TYPE STANDARD TABLE OF ty_bsik.

    TYPES: BEGIN OF ty_bsid,
             bukrs TYPE bsid_view-bukrs,
             kunnr TYPE bsid_view-kunnr,
             waers TYPE bsid_view-waers,

             "One of the following next three fields will be used for clearing
             zuonr TYPE bsid_view-zuonr,
             xref2 TYPE bsid_view-xref2,
             xblnr TYPE bsid_view-xblnr,

             belnr TYPE bsid_view-belnr,
             gjahr TYPE bsid_view-gjahr,
             blart TYPE bsid_view-blart,
             bldat TYPE bsid_view-bldat,
             budat TYPE bsid_view-budat,
             wrbtr TYPE bsid_view-wrbtr,
             shkzg TYPE bsid_view-shkzg, "To check if value is multiplied by -1
           END OF ty_bsid.
    TYPES tt_bsid TYPE STANDARD TABLE OF ty_bsid.

    DATA: mt_bsik TYPE tt_bsik,
          mt_bsid TYPE tt_bsid.

    METHODS read_data.

  PRIVATE SECTION.
    METHODS: read_data_from_bsik,
             read_data_from_bsid.
ENDCLASS.

CLASS lcl_process_data DEFINITION FINAL.
  PUBLIC SECTION.
    TYPES: BEGIN OF ty_total,
             z_ind TYPE char4,
             bukrs TYPE bsik_view-bukrs,
             bp    TYPE char10,
             waers TYPE bsik_view-waers,

             "Only one of the following three fields will be used for clearing
             zuonr TYPE bsik_view-zuonr,
             xref2 TYPE bsik_view-xref2,
             xblnr TYPE bsik_view-xblnr,

             koart TYPE bseg-koart, "Account type 'K' or 'D'
             belnr TYPE bsik_view-belnr,
             gjahr TYPE bsik_view-gjahr,
             blart TYPE bsik_view-blart,
             bldat TYPE bsik_view-bldat,
             budat TYPE bsik_view-budat,
             wrbtr TYPE bsik_view-wrbtr,

             "Data for Clearing Document
             clear_belnr TYPE bsik_view-belnr,
             clear_gjahr TYPE bsik_view-belnr,
           END OF ty_total.
    TYPES tt_total TYPE STANDARD TABLE OF ty_total.

    DATA mt_total TYPE tt_total.

    METHODS:
      constructor
        IMPORTING
          io_read_data TYPE REF TO lcl_read_data,
      process_data.

  PRIVATE SECTION.
    TYPES: tt_ftclear TYPE STANDARD TABLE OF ftclear,
           tt_ftpost  TYPE STANDARD TABLE OF ftpost.

    DATA mr_read_data TYPE REF TO lcl_read_data.
    DATA mt_sort_criteria TYPE abap_sortorder_tab.
    METHODS:
      combine_data,
      sort_data,
      evaluate_data,
      build_value
        IMPORTING
          is_total        TYPE ty_total
          it_sort_crit    TYPE abap_sortorder_tab
        RETURNING
          VALUE(rv_value) TYPE string,
      modify_traffic_lights
        IMPORTING
          iv_found_diff_acc_type TYPE c
          iv_sum_rows            TYPE bsik_view-wrbtr
        EXPORTING
          ev_flag_correct        TYPE c
        CHANGING
          ct_group_calc          TYPE tt_total,
      clear_accounting_docs
        IMPORTING
          it_group_calc TYPE tt_total,
      interface_start,
      interface_clearing
        IMPORTING
          it_group_calc TYPE tt_total,
      interface_end,
      prepare_ftpost
        IMPORTING
          it_group_calc TYPE tt_total
        EXPORTING
          et_ftpost     TYPE tt_ftpost,
      prepare_ftclear
        IMPORTING
          it_group_calc TYPE tt_total
        EXPORTING
          et_ftclear    TYPE tt_ftclear,
      check_cleared_items
        CHANGING
          ct_group_calc TYPE tt_total.
ENDCLASS.

CLASS lcl_display_data DEFINITION FINAL.
  PUBLIC SECTION.
    DATA mr_process_data TYPE REF TO lcl_process_data.

    METHODS:
      constructor
        IMPORTING
          io_process_data TYPE REF TO lcl_process_data,
      display_data.

  PRIVATE SECTION.
    METHODS:
      prepare_fieldcatalog
        EXPORTING
          et_fcat TYPE slis_t_fieldcat_alv,
      prepare_layout
        EXPORTING
          es_layout  TYPE slis_layout_alv
          es_variant TYPE disvariant.
ENDCLASS.

Ahora, para la implementación de la clase, pegaré el Incluir ZFI_PAREGGIO_CLNT_FORN_IMP en partes. Primero el código de implementación de la primera clase. lcl_leer_datos:

CLASS lcl_read_data IMPLEMENTATION.

  METHOD read_data.

    read_data_from_bsik( ).
    read_data_from_bsid( ).

  ENDMETHOD.

  METHOD read_data_from_bsik.

    SELECT bukrs, lifnr, waers, zuonr, xref2,
           xblnr, belnr, gjahr, blart, bldat,
           budat, wrbtr, shkzg
      FROM bsik_view
      INTO TABLE @mt_bsik
      WHERE bukrs IN @s_bukrs AND waers = @s_waers
        AND belnr IN @s_belnr AND gjahr IN @s_gjahr
        AND budat IN @s_budat AND bldat IN @s_bldat
        AND blart IN @s_blart AND lifnr IN @s_bp.

  ENDMETHOD.

  METHOD read_data_from_bsid.

    SELECT bukrs, kunnr, waers, zuonr, xref2,
           xblnr, belnr, gjahr, blart, bldat,
           budat, wrbtr, shkzg
      FROM bsid_view
      INTO TABLE @mt_bsid
      FOR ALL ENTRIES IN @mt_bsik
      WHERE bukrs = @mt_bsik-bukrs AND waers = @mt_bsik-waers
        AND gjahr = @mt_bsik-gjahr AND kunnr = @mt_bsik-lifnr
        AND belnr IN @s_belnr AND budat IN @s_budat
        AND bldat IN @s_bldat AND blart IN @s_blart.

  ENDMETHOD.

ENDCLASS.

No puedo decir mucho sobre el código, excepto el hecho de que si realiza una inspección del código, le dirá que una combinación hubiera sido una mejor idea, pero así fue como me lo solicitó el cliente.

La segunda clase es la más larga y me detendré más aquí después de haberte dado el código:

CLASS lcl_process_data IMPLEMENTATION.

  METHOD constructor.

    mr_read_data = io_read_data.

  ENDMETHOD.

  METHOD combine_data.

    DATA ls_total TYPE ty_total.

    LOOP AT mr_read_data->mt_bsik ASSIGNING FIELD-SYMBOL(<fs_bsik>).
      ls_total-bukrs = <fs_bsik>-bukrs.
      ls_total-bp    = <fs_bsik>-lifnr.
      ls_total-waers = <fs_bsik>-waers.

      ls_total-zuonr = <fs_bsik>-zuonr.
      ls_total-xref2 = <fs_bsik>-xref2.
      ls_total-xblnr = <fs_bsik>-xblnr.

      ls_total-koart="K".
      ls_total-belnr = <fs_bsik>-belnr.
      ls_total-gjahr = <fs_bsik>-gjahr.
      ls_total-blart = <fs_bsik>-blart.
      ls_total-bldat = <fs_bsik>-bldat.
      ls_total-budat = <fs_bsik>-budat.

      IF <fs_bsik>-shkzg = 'H'.
        ls_total-wrbtr = -1 * <fs_bsik>-wrbtr.
      ELSE.
        ls_total-wrbtr = <fs_bsik>-wrbtr.
      ENDIF.

      APPEND ls_total TO mt_total.
    ENDLOOP.

    LOOP AT mr_read_data->mt_bsid ASSIGNING FIELD-SYMBOL(<fs_bsid>).
      ls_total-bukrs = <fs_bsid>-bukrs.
      ls_total-bp    = <fs_bsid>-kunnr.
      ls_total-waers = <fs_bsid>-waers.

      ls_total-zuonr = <fs_bsid>-zuonr.
      ls_total-xref2 = <fs_bsid>-xref2.
      ls_total-xblnr = <fs_bsid>-xblnr.

      ls_total-koart="D".
      ls_total-belnr = <fs_bsid>-belnr.
      ls_total-gjahr = <fs_bsid>-gjahr.
      ls_total-blart = <fs_bsid>-blart.
      ls_total-bldat = <fs_bsid>-bldat.
      ls_total-budat = <fs_bsid>-budat.

      IF <fs_bsid>-shkzg = 'H'.
        ls_total-wrbtr = -1 * <fs_bsid>-wrbtr.
      ELSE.
        ls_total-wrbtr = <fs_bsid>-wrbtr.
      ENDIF.

      APPEND ls_total TO mt_total.
    ENDLOOP.

  ENDMETHOD.

  METHOD sort_data.

    mt_sort_criteria =
      VALUE #( ( name="BUKRS" )
               ( name="BP"    )
               ( name="WAERS" ) ).

    CASE z_par.
      WHEN 'ZUONR'.
        mt_sort_criteria = VALUE #( BASE mt_sort_criteria
          ( name="ZUONR" ) ).
      WHEN 'XREF2'.
        mt_sort_criteria = VALUE #( BASE mt_sort_criteria
          ( name="XREF2" ) ).
      WHEN 'XBLNR'.
        mt_sort_criteria = VALUE #( BASE mt_sort_criteria
          ( name="XREF2" ) ).
    ENDCASE.

    SORT mt_total BY (mt_sort_criteria).

  ENDMETHOD.

  METHOD evaluate_data.

    "Internal tables used to calculate traffic light column
    DATA: lt_group_calc TYPE tt_total,
          lt_total_calc TYPE tt_total.

    DATA ls_total TYPE ty_total.

    "Values build upon sort criteria
    DATA: current_value    TYPE string,
          comparison_value TYPE string.

    "Account type
    DATA: comparison_acc_type TYPE bseg-koart.

    "Variables to check if records should be cleared
    DATA: found_different_acc_type TYPE c,
          sum_rows                 TYPE bsik-wrbtr,
          flag_correct             TYPE c.

    CHECK mt_total IS NOT INITIAL.

    ls_total = mt_total[ 1 ].

    comparison_value =
      build_value(
        EXPORTING
          is_total     = ls_total
          it_sort_crit = mt_sort_criteria ).

    comparison_acc_type = ls_total-koart.

    LOOP AT mt_total INTO ls_total.
      current_value =
        build_value(
          EXPORTING
            is_total     = ls_total
            it_sort_crit = mt_sort_criteria ).

      IF current_value = comparison_value.
        APPEND ls_total TO lt_group_calc.
        sum_rows = sum_rows + ls_total-wrbtr.

        IF ls_total-koart <> comparison_acc_type. "The rows correspond to different account types
          found_different_acc_type="X".
        ENDIF.
      ELSE.
        modify_traffic_lights(
          EXPORTING
            iv_found_diff_acc_type = found_different_acc_type
            iv_sum_rows            = sum_rows
          IMPORTING
            ev_flag_correct        = flag_correct
          CHANGING
            ct_group_calc          = lt_group_calc ).

        IF flag_correct="X" AND test <> 'X'.
          clear_accounting_docs( lt_group_calc ).
          check_cleared_items(
            CHANGING
              ct_group_calc = lt_group_calc ).
        ENDIF.

        APPEND LINES OF lt_group_calc TO lt_total_calc.

        "Do the neccesary calculations for the next iteration
        CLEAR lt_group_calc.
        comparison_value = current_value.
        comparison_acc_type = ls_total-koart.
        CLEAR: sum_rows, found_different_acc_type, flag_correct.

        APPEND ls_total TO lt_group_calc.
        sum_rows = sum_rows + ls_total-wrbtr.

      ENDIF.
    ENDLOOP.

    modify_traffic_lights(
      EXPORTING
        iv_found_diff_acc_type = found_different_acc_type
        iv_sum_rows            = sum_rows
      IMPORTING
        ev_flag_correct        = flag_correct
      CHANGING
        ct_group_calc          = lt_group_calc ).

    IF flag_correct="X" AND test <> 'X'.
      clear_accounting_docs( lt_group_calc ).
      check_cleared_items(
        CHANGING
          ct_group_calc = lt_group_calc ).
    ENDIF.

    APPEND LINES OF lt_group_calc TO lt_total_calc.

    "Save the changes of traffic lights to the attribute table
    mt_total = lt_total_calc.

  ENDMETHOD.

  METHOD build_value.

    FIELD-SYMBOLS <field> TYPE any.

    LOOP AT it_sort_crit INTO DATA(ls_sort_crit).
      ASSIGN COMPONENT ls_sort_crit-name OF STRUCTURE is_total
        TO <field>.
      IF <field> IS ASSIGNED.
        IF rv_value IS INITIAL.
          rv_value = |{ <field> }|.
        ELSE.
          rv_value = |{ rv_value };{ <field> }|.
        ENDIF.
      ENDIF.
    ENDLOOP.

  ENDMETHOD.

  METHOD process_data.

    combine_data( ).
    sort_data( ).
    evaluate_data( ).

  ENDMETHOD.

  METHOD modify_traffic_lights.

    FIELD-SYMBOLS <fs_grp_calc> TYPE ty_total.

    SORT ct_group_calc BY koart belnr. "First Customer and than Vendor documents

    "Modify the traffic light
    IF iv_found_diff_acc_type="X" AND iv_sum_rows IS INITIAL.
      LOOP AT ct_group_calc ASSIGNING <fs_grp_calc>.
        <fs_grp_calc>-z_ind = icon_green_light.
      ENDLOOP.
      ev_flag_correct="X".
    ELSE.
      LOOP AT ct_group_calc ASSIGNING <fs_grp_calc>.
        <fs_grp_calc>-z_ind = icon_red_light.
      ENDLOOP.
    ENDIF.

  ENDMETHOD.

  METHOD clear_accounting_docs.

    interface_start( ).
    interface_clearing( it_group_calc ).
    interface_end( ).

  ENDMETHOD.

  METHOD interface_start.

    DATA: lv_function TYPE rfipi-funct    VALUE 'C', "B = BDC, C = Call Transaction
          lv_mode     TYPE rfpdo-allgazmd VALUE 'N',
          lv_update   TYPE rfpdo-allgvbmd VALUE 'S'.

    CALL FUNCTION 'POSTING_INTERFACE_START'
      EXPORTING
        i_client           = sy-mandt
        i_function         = lv_function
        i_mode             = lv_mode
        i_update           = lv_update
        i_user             = sy-uname
      EXCEPTIONS
        client_incorrect   = 1
        function_invalid   = 2
        group_name_missing = 3
        mode_invalid       = 4
        update_invalid     = 5
        OTHERS             = 6.

    IF sy-subrc <> 0.
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
        WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    ENDIF.

  ENDMETHOD.

  METHOD interface_clearing.

    DATA: lt_blntab TYPE TABLE OF blntab,
          lt_fttax  TYPE TABLE OF fttax.

    prepare_ftpost(
      EXPORTING
        it_group_calc = it_group_calc
      IMPORTING
        et_ftpost     = DATA(lt_ftpost) ).

    prepare_ftclear(
      EXPORTING
        it_group_calc = it_group_calc
      IMPORTING
        et_ftclear    = DATA(lt_ftclear) ).

    CALL FUNCTION 'POSTING_INTERFACE_CLEARING'
      EXPORTING
        i_auglv                    = 'GUTSCHRI'
        i_tcode="FB05"
        i_sgfunct="C"
      TABLES
        t_blntab                   = lt_blntab
        t_ftclear                  = lt_ftclear
        t_ftpost                   = lt_ftpost
        t_fttax                    = lt_fttax
      EXCEPTIONS
        clearing_procedure_invalid = 1
        clearing_procedure_missing = 2
        table_t041a_empty          = 3
        transaction_code_invalid   = 4
        amount_format_error        = 5
        too_many_line_items        = 6
        company_code_invalid       = 7
        screen_not_found           = 8
        no_authorization           = 9
        OTHERS                     = 10.

    IF sy-subrc <> 0.
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
            WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    ENDIF.

  ENDMETHOD.

  METHOD interface_end.

    CALL FUNCTION 'POSTING_INTERFACE_END'
      EXPORTING
        i_bdcimmed              = 'X'
      EXCEPTIONS
        session_not_processable = 1
        OTHERS                  = 2.

    IF sy-subrc <> 0.
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
            WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
    ENDIF.

  ENDMETHOD.

  METHOD prepare_ftpost.

    DATA lv_count TYPE count_pi VALUE '001'.
    DATA(ls_group_calc) = it_group_calc[ 1 ].

    et_ftpost = VALUE #(
      ( stype="K"
        count = lv_count
        fnam  = 'BKPF-BLDAT' fval = |{ r_bldat+6(2) }.{ r_bldat+4(2) }.{ r_bldat(4) }| )
      ( stype="K"
        count = lv_count
        fnam  = 'BKPF-BLART' fval = r_blart )
      ( stype="K"
        count = lv_count
        fnam  = 'BKPF-BUKRS' fval = ls_group_calc-bukrs )
      ( stype="K"
        count = lv_count
        fnam  = 'BKPF-BUDAT' fval = |{ r_budat+6(2) }.{ r_budat+4(2) }.{ r_budat(4) }| )
      ( stype="K"
        count = lv_count
        fnam  = 'BKPF-WAERS' fval = ls_group_calc-waers )
      ( stype="K"
        count = lv_count
        fnam  = 'BKPF-BKTXT' fval = r_bktxt ) ).

  ENDMETHOD.

  METHOD prepare_ftclear.

    LOOP AT it_group_calc INTO DATA(ls_group_calc).

      et_ftclear = VALUE #( BASE et_ftclear (
        agkoa = ls_group_calc-koart  "Account Type
        agkon = ls_group_calc-bp     "BP number
        agbuk = ls_group_calc-bukrs  "Company code
        xnops="X"                  "Indicator: Select Only Open Items Which Are Not Special G/L?
        selfd = 'BELNR'              "Selection Field
        selvon = ls_group_calc-belnr "Lower limit
        selbis = ls_group_calc-belnr "Upper limit
        ) ).

    ENDLOOP.

  ENDMETHOD.

  METHOD check_cleared_items.

    "Check if the items where cleared in tables BSAD and BSAK
    LOOP AT ct_group_calc ASSIGNING FIELD-SYMBOL(<fs_group_calc>).
      CASE <fs_group_calc>-koart.
        WHEN 'D'.
          SELECT SINGLE augbl, auggj FROM bsad_view
            INTO @DATA(clearing_customer_item)
            WHERE bukrs = @<fs_group_calc>-bukrs
              AND kunnr = @<fs_group_calc>-bp
              AND belnr = @<fs_group_calc>-belnr
              AND gjahr = @<fs_group_calc>-gjahr.
          IF sy-subrc = 0.
            <fs_group_calc>-clear_belnr = clearing_customer_item-augbl.
            <fs_group_calc>-clear_gjahr = clearing_customer_item-auggj.
          ENDIF.
        WHEN 'K'.
          SELECT SINGLE augbl, auggj FROM bsak_view
            INTO @DATA(clearing_vendor_item)
            WHERE bukrs = @<fs_group_calc>-bukrs
              AND lifnr = @<fs_group_calc>-bp
              AND belnr = @<fs_group_calc>-belnr
              AND gjahr = @<fs_group_calc>-gjahr.
          IF sy-subrc = 0.
            <fs_group_calc>-clear_belnr = clearing_vendor_item-augbl.
            <fs_group_calc>-clear_gjahr = clearing_vendor_item-auggj.
          ENDIF.
      ENDCASE.
    ENDLOOP.

  ENDMETHOD.

ENDCLASS.

Estos son los métodos de nuestra clase en el orden en que aparecen arriba:

  • constructor – Pasamos la referencia al primer objeto ir_leer_datos al atributo de instancia mr_read_data cuando creamos el nuevo objeto ir_procesar_datos.
  • combine_data: como su nombre lo dice, combina los datos de los clientes y proveedores en el atributo de instancia mt_total.
  • sort_data: ordena la tabla interna mt_total por BUKRS: código de empresa, BP: socio comercial, WAERS: moneda y uno de los criterios de selección (ZUONR, XREF2, XBLNR).
  • evaluar_datos: hace todo el trabajo pesado y utiliza otros métodos útiles para realizar la lógica requerida
    1. build_value: ayuda a crear un valor concatenado de las columnas que se usaron para ordenar y eso ayudará a comprender cuándo estamos procesando una nueva fila de mt_total con una combinación diferente de estos cuatro campos.
    2. modificar_traffic_lights: este método se llama dentro del bucle en la tabla interna mt_total y directamente después del bucle. Dentro del ciclo, se llama al método si el valor actual devuelto por el método build_value es diferente del valor de comparación. Dentro del método modificamos los semáforos a verde o rojo y llenamos la variable bandera_correcta con el valor ‘X’ o vacío.
    3. Después de la ejecución del método anterior, si flag_correct tiene el valor ‘X’ y no estamos realizando una ejecución de prueba, ejecutamos el método clear_accounting_docs. Explicaré este método por separado ya que es importante entender cómo ejecutamos la transacción FB05.
    4. check_cleared_items se ejecuta para recuperar el valor de los documentos de compensación si todo salió bien.
  • process_data: sirve como contenedor para llamar a los tres métodos mencionados anteriormente.

A continuación me concentraré en la parte divertida, o al menos desde mi punto de vista :). El método clear_accounting_docs hace la llamada de la transacción FB05 para compensar las partidas abiertas identificadas.

Ahora nuestro método llama en sí mismo a los siguientes métodos:

  • inicio_interfaz – Inicia la interfaz a través del módulo de función POSTING_INTERFACE_START.
  • limpieza_interfaz – Llama a BAPI POSTING_INTERFACE_CLEARING para borrar los elementos, pero antes prepara los datos para el encabezado y los elementos respectivamente con los métodos preparar_ftpost y prepare_ftclear.
  • interfaz_fin – Cierra la interfaz llamando al módulo de función POSTING_INTERFACE_END.

Ahora estoy pegando debajo el código para la tercera y última clase:

CLASS lcl_display_data IMPLEMENTATION.

  METHOD constructor.

    mr_process_data = io_process_data.

  ENDMETHOD.

  METHOD prepare_fieldcatalog.

    et_fcat = VALUE #(
      ( fieldname="Z_IND"
        seltext_s = TEXT-s01
        seltext_m = TEXT-m01
        seltext_l = TEXT-l01
        col_pos   = 1
        icon      = 'X'           )
      ( fieldname="BUKRS"
        seltext_s = TEXT-s02
        seltext_m = TEXT-m02
        seltext_l = TEXT-l02
        col_pos   = 2             )
      ( fieldname="BP"
        seltext_s = TEXT-s03
        seltext_m = TEXT-m03
        seltext_l = TEXT-l03
        col_pos   = 3             )
      ( fieldname="WAERS"
        seltext_s = TEXT-s04
        seltext_m = TEXT-m04
        seltext_l = TEXT-l04
        col_pos   = 4             )
      ( fieldname="ZUONR"
        seltext_s = TEXT-s05
        seltext_m = TEXT-m05
        seltext_l = TEXT-l05
        col_pos   = 5             )
      ( fieldname="XREF2"
        seltext_s = TEXT-s06
        seltext_m = TEXT-m06
        seltext_l = TEXT-l06
        col_pos   = 6             )
      ( fieldname="XBLNR"
        seltext_s = TEXT-s07
        seltext_m = TEXT-m07
        seltext_l = TEXT-l07
        col_pos   = 7             )
      ( fieldname="KOART"
        seltext_s = TEXT-s08
        seltext_m = TEXT-m08
        seltext_l = TEXT-l08
        col_pos   = 8             )
      ( fieldname="BELNR"
        seltext_s = TEXT-s09
        seltext_m = TEXT-m09
        seltext_l = TEXT-l09
        col_pos   = 9
        hotspot="X"           )
      ( fieldname="GJAHR"
        seltext_s = TEXT-s10
        seltext_m = TEXT-m10
        seltext_l = TEXT-l10
        col_pos   = 10            )
      ( fieldname="BLART"
        seltext_s = TEXT-s11
        seltext_m = TEXT-m11
        seltext_l = TEXT-l11
        col_pos   = 11            )
      ( fieldname="BLDAT"
        seltext_s = TEXT-s12
        seltext_m = TEXT-m12
        seltext_l = TEXT-l12
        col_pos   = 12            )
      ( fieldname="BUDAT"
        seltext_s = TEXT-s13
        seltext_m = TEXT-m13
        seltext_l = TEXT-l13
        col_pos   = 13            )
      ( fieldname="WRBTR"
        seltext_s = TEXT-s14
        seltext_m = TEXT-m14
        seltext_l = TEXT-l14
        col_pos   = 14            )
      ( fieldname="CLEAR_BELNR"
        seltext_s = TEXT-s15
        seltext_m = TEXT-m15
        seltext_l = TEXT-l15
        col_pos   = 15
        hotspot="X"           )
      ( fieldname="CLEAR_GJAHR"
        seltext_s = TEXT-s16
        seltext_m = TEXT-m16
        seltext_l = TEXT-l16
        col_pos   = 16            ) ).

  ENDMETHOD.

  METHOD prepare_layout.

    es_layout = VALUE #(
      no_input="X"
      colwidth_optimize="X"
      zebra="X" ).

    es_variant = VALUE #(
      report  = sy-repid
      variant = SWITCH #( z_par
                  WHEN 'ZUONR' THEN '/LAYOUT1'
                  WHEN 'XREF2' THEN '/LAYOUT2'
                  WHEN 'XBLNR' THEN '/LAYOUT3' ) ).

  ENDMETHOD.

  METHOD display_data.

    prepare_fieldcatalog(
      IMPORTING
        et_fcat = DATA(lt_fcat) ).

    prepare_layout(
      IMPORTING
        es_layout  = DATA(ls_layout)
        es_variant = DATA(ls_variant) ).

    CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
      EXPORTING
        i_buffer_active         = space
        i_callback_program      = sy-repid
        i_callback_user_command = 'USER_COMMAND'
        is_layout               = ls_layout
        it_fieldcat             = lt_fcat
        i_save="X"
        is_variant              = ls_variant
      TABLES
        t_outtab                = mr_process_data->mt_total
      EXCEPTIONS
        program_error           = 1
        OTHERS                  = 2.

  ENDMETHOD.

ENDCLASS.

Ahora, el código de esta clase hace lo habitual para mostrar los datos en un ALV. Los datos, como adivinó, se proporcionaron de la clase anterior en el constructor. Me disculpo por usar el buen viejo REUSE_ALV_GRID_DISPLAY para mostrar el ALV y no el CL_SALV_TABLE, pero considérelo como una práctica no tan buena de mezclar las formas antiguas con las nuevas recomendadas.

La última inclusión agrega insulto a la lesión y ayuda a llamar a la transacción FB03 para mostrar los documentos contables de las columnas de puntos de acceso.

*&---------------------------------------------------------------------*
*& Include ZFI_PAREGGIO_CLNT_FORN_FORM
*&---------------------------------------------------------------------*
FORM user_command USING r_ucomm     TYPE sy-ucomm
                        rs_selfield TYPE slis_selfield.

  IF r_ucomm = '&IC1'.
    READ TABLE go_disp_data->mr_process_data->mt_total
      INDEX rs_selfield-tabindex
      INTO DATA(ls_selected_row).
    IF sy-subrc = 0.
      SET PARAMETER ID 'BUK' FIELD ls_selected_row-bukrs.

      CASE rs_selfield-fieldname.
        WHEN 'BELNR'.
          SET PARAMETER ID 'BLN' FIELD ls_selected_row-belnr.
          SET PARAMETER ID 'GJR' FIELD ls_selected_row-gjahr.
        WHEN 'CLEAR_BELNR'.
          SET PARAMETER ID 'BLN' FIELD ls_selected_row-clear_belnr.
          SET PARAMETER ID 'GJR' FIELD ls_selected_row-clear_gjahr.
      ENDCASE.

      CALL TRANSACTION 'FB03' AND SKIP FIRST SCREEN.
    ENDIF.
  ENDIF.

ENDFORM.

Lo último que me gustaría señalar es que he creado tres diseños que cambian solo por los criterios utilizados para la compensación:

/ DISEÑO1 – Diseño ZUONR
/ DISEÑO2 – Diseño XREF2
/LAYOUT3 – Diseño XBLNR

Como es costumbre después de una presentación tan larga, me gustaría agradecerles la atención y realmente espero que les haya resultado informativo o que hayan aprendido algo nuevo de ella. No dudes en darme algún comentario útil de lo que se podría haber hecho mejor o cómo hubieras resuelto un problema así de otra manera.

Me gustaría animarte a seguir la página de Desarrollo ABAP https://community.sap.com/topics/abap y su blog https://blogs.sap.com/tags/833755570260738661924709785639136. Además, no dude en hacer y responder preguntas en el área de preguntas y respuestas. https://answers.sap.com/tags/833755570260738661924709785639136. ¡Hasta la próxima!




Enviar archivo XLSX con varias pestañas en formato zip por correo electrónico
Previo
Automatice la impresión de documentos PDF recibidos como archivos adjuntos de correo electrónico en SAP
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.

x