Wednesday 12 April 2023

Where-Used List for NAST output types

If the current system already has dozens or even hundreds of NAST output types, one day must adapt all those forms if related to one group of specific criteria like sales organization, then how to identify which output type has been used by the sales organization?

SAP ABAP Career, SAP ABAP Skills, SAP ABAP Jobs, SAP ABAP Prep, SAP ABAP Preparation, SAP ABAP Tutorial and Materials, SAP ABAP Guides, SAP ABAP Learning, SAP ABAP NAST, SAP ABAP Guides

It’s well known that general NAST output determination and configuration are maintained with various key combinations and stored at multiple condition record tables just like pricing determination processing.

1. List of the basic tables for NAST output processing


TNAPR (Processing programs for output)

The easiest way to check the driver program and form name per output type.

SAP ABAP Career, SAP ABAP Skills, SAP ABAP Jobs, SAP ABAP Prep, SAP ABAP Preparation, SAP ABAP Tutorial and Materials, SAP ABAP Guides, SAP ABAP Learning, SAP ABAP NAST, SAP ABAP Guides

◉ NACH (Detailed output data)

It has a relationship of condition record number with Condition Type. And it already contains all the values of key combinations but we don’t know their meanings exactly. Actually, we can use this field VAKEY for pattern searching if that value contains the criteria you want, but be aware that could be inaccurate as company code/sales org./ purchase org./plants, etc could share the same value.

Another important field is KOTABNR which is the condition table code. It can be used to search the real condition table in Table T681 mentioned below.

SAP ABAP Career, SAP ABAP Skills, SAP ABAP Jobs, SAP ABAP Prep, SAP ABAP Preparation, SAP ABAP Tutorial and Materials, SAP ABAP Guides, SAP ABAP Learning, SAP ABAP NAST, SAP ABAP Guides

◉ T681 (Conditions: Structures)

It contains the relationship of the Condition table code with the Condition table. Take KOTABNR 902 as an example, its condition table is A902 for application ‘V’. That’s one of the tables we need to search where-used list per output type.

SAP ABAP Career, SAP ABAP Skills, SAP ABAP Jobs, SAP ABAP Prep, SAP ABAP Preparation, SAP ABAP Tutorial and Materials, SAP ABAP Guides, SAP ABAP Learning, SAP ABAP NAST, SAP ABAP Guides

◉ Condition tables like A902

There’re hundreds of Condition tables like A902 with various key combinations per output type. For this example, the key combination is Sales org./Cust.grp 1/Mat.pr.grp/ZZPRODH2. If we need where-used for sales org/ customer group/material pricing group, that’s the table we need to search.

SAP ABAP Career, SAP ABAP Skills, SAP ABAP Jobs, SAP ABAP Prep, SAP ABAP Preparation, SAP ABAP Tutorial and Materials, SAP ABAP Guides, SAP ABAP Learning, SAP ABAP NAST, SAP ABAP Guides

2. Sample program to fetch all related outputs/forms for the sales organization


1) Fetch all the form names/driver programs per output type;
2) Fetch all output condition records per application/ output type;
3) Fetch all condition tables with condition table codes fetched from step 2;
4) Create dynamic selection based on condition tables fetched in step 3;
5) Loop structure of the dynamic table, search sales organization field name VKORG;
6) Loop output type and collect sales org./form names/driver programs per output type.

*&---------------------------------------------------------------------*
*& Report  ZSD_FORMS_VKORG_LIST
*&
*-----------------------------------------------------------------------
* Program Information
*-----------------------------------------------------------------------
* Program Name: ZSD_FORMS_VKORG_LIST

REPORT zsd_forms_vkorg_list.
TABLES: nach, tnapr, t681, dd03l, zpolarisorgmap.

*-----------------------------------------------------------------------
* Types& Data Definition
*-----------------------------------------------------------------------
TYPES: BEGIN OF t_key,
        kappl TYPE kappl,
        kschl TYPE na_kschl,
        vkorg TYPE vkorg,
       END OF t_key,

      BEGIN OF t_out,
        fonam(36),
        kappl TYPE kappl,
        kschl TYPE na_kschl,
        vkorg TYPE vkorg,
        pgnam TYPE na_pgnam,
        sfp_flag(16),
       END OF t_out.

DATA: gt_tnapr TYPE TABLE OF tnapr,
      gr_table TYPE REF TO cl_salv_table,
      gs_tnapr LIKE LINE OF gt_tnapr,
      gt_out   TYPE TABLE OF t_out,
      gs_out   LIKE LINE OF gt_out,
      gt_vkorg   TYPE TABLE OF zpolarisorgmap,
      gs_vkorg   LIKE LINE OF gt_vkorg,
      gt_t681  TYPE TABLE OF t681,
      gs_t681  LIKE LINE OF gt_t681,
      gt_key   TYPE TABLE OF t_key,
      gs_key   LIKE LINE OF gt_key,
      gt_nach  TYPE TABLE OF nach,
      gs_nach  LIKE LINE OF gt_nach.

DATA:
  o_ref TYPE REF TO data.
FIELD-SYMBOLS:
  <lt_table> TYPE STANDARD TABLE,
  <fs>       TYPE any,
  <field>    TYPE any,
  <field1>   TYPE any.

*-----------------------------------------------------------------------
* Selection Parameters
*-----------------------------------------------------------------------

SELECTION-SCREEN: BEGIN OF BLOCK a2 WITH FRAME TITLE text-001.
SELECT-OPTIONS: s_kschl FOR tnapr-kschl.
SELECT-OPTIONS: s_fonam FOR tnapr-fonam.
SELECTION-SCREEN: END   OF BLOCK a2.

PARAMETERS:
  p_tab       TYPE tabname NO-DISPLAY,       " Table name
  p_field(20) TYPE c NO-DISPLAY,             " Field name
  p_polar     AS CHECKBOX DEFAULT '',        " Polaris only
  p_script    AS CHECKBOX DEFAULT '',        "script only
  p_skip      AS CHECKBOX DEFAULT ''.       " no form find


*-----------------------------------------------------------------------
* START-OF-SELECTION
*-----------------------------------------------------------------------
START-OF-SELECTION.
  PERFORM get_data.
  PERFORM data_output.

*&---------------------------------------------------------------------*
*&      Form  get_data
*&---------------------------------------------------------------------*
FORM get_data.

  REFRESH gt_vkorg.
  SELECT *
    FROM zpolarisorgmap
    INTO TABLE gt_vkorg.

  REFRESH gt_tnapr.
  SELECT *
    INTO TABLE gt_tnapr
    FROM tnapr
    WHERE kschl IN s_kschl
    AND ( fonam IN s_fonam OR fonam2 IN s_fonam OR
          fonam3 IN s_fonam OR fonam4 IN s_fonam OR
          sform IN s_fonam ).

  LOOP AT gt_tnapr INTO gs_tnapr.
    IF   gs_tnapr-fonam IN s_fonam  OR gs_tnapr-fonam2 IN s_fonam
     OR gs_tnapr-fonam3 IN s_fonam  OR gs_tnapr-fonam4 IN s_fonam
     OR  gs_tnapr-sform IN s_fonam.

    ELSE.
      DELETE TABLE gt_tnapr FROM gs_tnapr.
    ENDIF.
  ENDLOOP.

  IF gt_tnapr[] IS INITIAL.
    MESSAGE 'No Data found!' TYPE 'E' DISPLAY LIKE 'E'.
  ENDIF.

  REFRESH gt_nach.
  SELECT *
    FROM nach
    INTO TABLE gt_nach
    FOR ALL ENTRIES IN gt_tnapr
    WHERE kappl = gt_tnapr-kappl
     AND  kschl = gt_tnapr-kschl.

  IF gt_nach[] IS INITIAL.
    LOOP AT gt_tnapr INTO gs_tnapr.
      CLEAR gs_out.
      gs_out-fonam = gs_tnapr-fonam.
      gs_out-kschl = gs_tnapr-kschl.
      gs_out-pgnam = gs_tnapr-pgnam.
      gs_out-vkorg = 'N/A'.
      APPEND gs_out TO gt_out.
    ENDLOOP.
  ENDIF.

  IF gt_nach[] IS NOT INITIAL.
    REFRESH gt_t681.
    SELECT *
      FROM t681
      INTO TABLE gt_t681
      FOR ALL ENTRIES IN gt_nach
      WHERE kotabnr EQ gt_nach-kotabnr
      AND   kappl   EQ gt_nach-kappl.
  ENDIF.

  LOOP AT gt_nach INTO gs_nach WHERE kotabnr IS NOT INITIAL.
    CLEAR gs_tnapr.
    READ TABLE gt_tnapr INTO gs_tnapr
                  WITH KEY kschl = gs_nach-kschl
                           kappl = gs_nach-kappl.

* Get condition table name
    CLEAR gs_t681.
    READ TABLE gt_t681 INTO gs_t681 WITH KEY
               kotabnr = gs_nach-kotabnr
               kappl   = gs_nach-kappl.
    IF sy-subrc EQ 0.
      p_tab = gs_t681-kotab.
    ELSE.
      CONTINUE.
    ENDIF.


*---to newly created object.
    CREATE DATA o_ref TYPE TABLE OF (p_tab).
*--Asssign the reference to field-symbol
    p_field = 'VKORG'.
    ASSIGN p_field TO <field1>.
    ASSIGN o_ref->* TO <lt_table>.

    SELECT *
      INTO TABLE <lt_table>
      FROM (p_tab)
      WHERE kappl = gs_nach-kappl
      AND   kschl = gs_nach-kschl
      AND   knumh = gs_nach-knumh.

    LOOP AT <lt_table> ASSIGNING <fs>.
      CLEAR gs_out.
      ASSIGN COMPONENT <field1> OF STRUCTURE <fs>
                    TO <field>.
      IF sy-subrc = 0.
        gs_out-vkorg = <field>.

        p_field = 'KAPPL'.
        ASSIGN p_field TO <field1>.
        ASSIGN COMPONENT <field1> OF STRUCTURE <fs>
                      TO <field>.
        IF sy-subrc = 0.
          gs_out-kappl = <field>.
        ENDIF.

        p_field = 'KSCHL'.
        ASSIGN p_field TO <field1>.
        ASSIGN COMPONENT <field1> OF STRUCTURE <fs>
                      TO <field>.
        IF sy-subrc = 0.
          gs_out-kschl = <field>.
        ENDIF.

        gs_out-pgnam = gs_tnapr-pgnam.
        IF   gs_tnapr-fonam IS NOT INITIAL.
          gs_out-fonam = gs_tnapr-fonam.
        ELSEIF  gs_tnapr-fonam2 IS NOT INITIAL.
          gs_out-fonam = gs_tnapr-fonam2.
        ELSEIF  gs_tnapr-fonam3 IS NOT INITIAL.
          gs_out-fonam = gs_tnapr-fonam3.
        ELSEIF  gs_tnapr-fonam4 IS NOT INITIAL.
          gs_out-fonam = gs_tnapr-fonam4.
        ELSEIF  gs_tnapr-sform  IS NOT INITIAL.
          gs_out-fonam = gs_tnapr-sform.
          gs_out-sfp_flag = 'X'.
        ENDIF.

        IF p_script = 'X' AND gs_out-sfp_flag = 'X'.
          CONTINUE.
        ENDIF.

        IF p_skip = 'X'.
          IF gs_out-fonam IS INITIAL.
            CONTINUE.
          ENDIF.
        ENDIF.

        IF p_polar = 'X'.
          CLEAR gs_vkorg.
          READ TABLE gt_vkorg INTO gs_vkorg WITH KEY
                      pvkorg = gs_out-vkorg.
          IF sy-subrc <> 0.
            CONTINUE.
          ENDIF.
        ENDIF.

        APPEND gs_out TO gt_out.
        CLEAR gs_out.
      ELSE.
        CONTINUE.
      ENDIF.
    ENDLOOP.
  ENDLOOP.

  SORT gt_out BY fonam kappl kschl vkorg.
  DELETE ADJACENT DUPLICATES FROM gt_out.

ENDFORM.

*&---------------------------------------------------------------------*
*&      Form  DATA_OUTPUT
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
FORM data_output.
* Functions
  DATA: lr_functions    TYPE REF TO   cl_salv_functions,
        lr_columns      TYPE REF TO   cl_salv_columns_table,
        lo_column       TYPE REF TO   cl_salv_column_table,
        lr_column       TYPE REF TO   cl_salv_column,
        lr_events       TYPE REF TO   cl_salv_events_table,
        ls_color        TYPE lvc_s_colo,
        lr_sorts        TYPE REF TO   cl_salv_sorts,
        lr_layout       TYPE REF TO   cl_salv_layout,
        lr_optimize     TYPE REF TO   cl_salv_columns_table,
        lf_variant TYPE slis_vari,
*        ld_email TYPE adr6-smtp_addr,
        ls_key    TYPE salv_s_layout_key,
        l_msg TYPE string.

  DATA: lv_sub TYPE sood-objdes.
  CLEAR lv_sub.
  DATA: lv_xml_type TYPE salv_bs_constant,
        lv_xml TYPE xstring.

  TRY.
      CALL METHOD cl_salv_table=>factory
        EXPORTING
          list_display = if_salv_c_bool_sap=>false
*         r_container  =
*         container_name =
        IMPORTING
          r_salv_table = gr_table
        CHANGING
          t_table      = gt_out.
    CATCH cx_salv_msg.
  ENDTRY.

* Set Screen status.
  TRY.
      CALL METHOD gr_table->set_screen_status
        EXPORTING
          report        = sy-repid
          pfstatus      = 'ZSALV_STANDARD'
          set_functions = 0.
  ENDTRY.

  CALL METHOD gr_table->get_functions
    RECEIVING
      value = lr_functions.

* Activate all Standard tool bar functions.
  CALL METHOD lr_functions->set_all
    EXPORTING
      value = if_salv_c_bool_sap=>true.

  lr_layout = gr_table->get_layout( ).
  lr_layout->set_default( abap_true ).
  lr_layout->set_save_restriction( if_salv_c_layout=>restrict_none ).

* Get Output table columns.
  CALL METHOD gr_table->get_columns
    RECEIVING
      value = lr_columns.

* Set column width optimize
  lr_columns->set_optimize( abap_true ).

* Set sorts.
  TRY.
      lr_sorts = gr_table->get_sorts( ).
    CATCH cx_salv_not_found.
  ENDTRY.

  "Column
  TRY.
      lr_column = lr_columns->get_column( 'FONAM' ).
      lr_column->set_long_text( 'FORM Name' ).
      lr_column->set_medium_text( 'FORM Name' ).
      lr_column->set_output_length( '36' ).
    CATCH cx_salv_not_found .
  ENDTRY.

  TRY.
      lr_column = lr_columns->get_column( 'SFP_FLAG' ).
      lr_column->set_long_text( 'Adobe or SF?' ).
      lr_column->set_medium_text( 'Adobe or SF?' ).
      lr_column->set_output_length( '16' ).
    CATCH cx_salv_not_found .
  ENDTRY.

  TRY.
*  Apply Color
      lo_column ?= lr_columns->get_column( 'KSCHL' ).
      ls_color-col = 5.
      ls_color-int = 1.
      CALL METHOD lo_column->set_color
        EXPORTING
          value = ls_color.
    CATCH cx_salv_not_found .
  ENDTRY.

  TRY.
*  Apply Color
      lo_column ?= lr_columns->get_column( 'VKORG' ).
      ls_color-col = 5.
      ls_color-int = 1.
      CALL METHOD lo_column->set_color
        EXPORTING
          value = ls_color.
    CATCH cx_salv_not_found .
  ENDTRY.

  IF gt_out[] IS NOT INITIAL.
* Display Data.
    CALL METHOD gr_table->display.
  ELSE.
    WRITE: / 'DATA not found!'.
  ENDIF.

ENDFORM.

By looping dynamic table field lists fetched from NACH with condition table code from T681, replacing sales org. field VKORG with other key combinations, we can get all the where-used lists we are interested in. But be aware of this approach to fetch sales org. list based on NACH entry and those condition tables(with key combinations including VKORG) may not cover all scenarios cause:

◉ Some output type doesn’t have condition records (NACH entry);
◉ Some output entries at NAST may create manually without NACH entry as well;
◉ Some output may be triggered by the customized programs without NAST processing, etc.

To be more accurate maybe need a sum of the result fetched from this approach plus entries from NAST at the production system like for the last 2 years. For example, fetch sales org. from VBAK for V1 application by VBELN equal to object key get from NAST.

No comments:

Post a Comment