SAP中的递归循环检查 Recursion with Loop Checking in SAP

2021-10-24 00:38发布


          点击此处--->   EasySAP.com 群内免费提供SAP练习系统(在群公告中)

加入QQ群:457200227(SAP S4 HANA技术交流) 群内免费提供SAP练习系统(在群公告中)

* This program can be a model for any ABAP recursion.
* This is often needed to navigate down hierarchical data.
* One example is BOM.

* Important point is to chack for stack overflow
* and give RIGHT MESSAGE so that corrective action can be taken.

*&---------------------------------------------------------------------*
* Sample Program Showing Recursion in ABAP
* Simple BOM Tree walking in ABAP
* Takes Care of Diagnostics as well - detects Loops
* Hence never experience Stack Overflow!
*&---------------------------------------------------------------------*


REPORT zjncrecursion.

INCLUDE zjncinclude. " From www.erpgreat.com

TABLES: makt.

CONSTANTS: maxlevels TYPE i VALUE 10.

TYPES: BEGIN OF ty_usage,
          parent  TYPE  makt-matnr,
          child   TYPE  makt-matnr,
          usage   TYPE  mseg-menge,
       END OF ty_usage.

DATA: wa_usage  TYPE ty_usage,
      it_usage  TYPE STANDARD TABLE OF ty_usage.    " USAGE data

TYPES: BEGIN OF ty_stack,
          level   TYPE  h_level,
          matnr   TYPE  makt-matnr,
          menge   TYPE  mseg-menge,
       END OF ty_stack.

DATA: istackpos TYPE i,
      wa_stack  TYPE ty_stack,
      it_stack  TYPE STANDARD TABLE OF ty_stack.   "BOM Stack

TYPES: BEGIN OF ty_reqd,
          matnr   TYPE  makt-matnr,
          menge   TYPE  mseg-menge,
       END OF ty_reqd.

DATA: wa_reqd   TYPE ty_reqd,
      it_reqd   TYPE STANDARD TABLE OF ty_reqd.    "NET Requirement of 
RAW Material

PARAMETERS: p_build TYPE makt-matnr,    "Target   to Build
            p_menge TYPE mseg-menge.    "Quantity to Build

INITIALIZATION.
  PERFORM f_usage_data.


START-OF-SELECTION.

  istackpos = 0.

  MOVE istackpos  TO wa_stack-level.
  MOVE p_build    TO wa_stack-matnr.
  MOVE p_menge    TO wa_stack-menge.
  APPEND wa_stack TO it_stack.                              " 1st PUSH

  PERFORM f_explode USING p_build.

  SORT it_reqd BY matnr.

  PERFORM zjnc_dump_list USING 'IT_REQD' 'WA_REQD' 'Net RAW 
Requirement'.

*&--------------------------------------------------------------------*
*&      Form  f_Explode
*&--------------------------------------------------------------------*
FORM f_explode USING p_pmatnr.
  DATA: icount   TYPE i,
        totalreq TYPE mseg-menge.

  istackpos = istackpos + 1.                          " PUSH

  IF istackpos GE maxlevels.
    PERFORM f_dumpstack.    " terminate
    LEAVE PROGRAM.
  ENDIF.

  icount = 0.

  LOOP AT it_usage INTO wa_usage WHERE parent = p_pmatnr.
    icount = icount + 1.

    MOVE istackpos      TO wa_stack-level.
    MOVE wa_usage-child TO wa_stack-matnr.
    MOVE wa_usage-usage TO wa_stack-menge.
    APPEND wa_stack     TO it_stack.                  " PUSH

    PERFORM f_explode USING wa_usage-child.

  ENDLOOP.

  IF icount = 0.                                  " then LEAF
    totalreq = '1.0'.
    LOOP AT it_stack INTO wa_stack.
      totalreq = totalreq * wa_stack-menge.
    ENDLOOP.

    MOVE p_pmatnr   TO wa_reqd-matnr.
    MOVE totalreq   TO wa_reqd-menge.
    COLLECT wa_reqd INTO it_reqd.

  ENDIF.

  DELETE it_stack INDEX istackpos.                      " POP

  istackpos = istackpos - 1.                            " POP

ENDFORM.                    "f_Explode

*&--------------------------------------------------------------------*
*&      Form  f_dumpstack
*&--------------------------------------------------------------------*
FORM f_dumpstack.

  PERFORM zjnc_dump_list USING 'IT_STACK' 'WA_STACK' 'LOOP in BOM 
STACK'.

ENDFORM.                    "f_dumpstack

*&--------------------------------------------------------------------*
*&      Form  f_usage_data for Hungry Bengali ABAPer in Kolkata
*&--------------------------------------------------------------------*
FORM f_usage_data.
  MOVE 'FISHCURRY'   TO wa_usage-parent.
  MOVE 'SPICES'      TO wa_usage-child.
  MOVE 10            TO wa_usage-usage.
  APPEND wa_usage TO it_usage.

  MOVE 'FISHCURRY'   TO wa_usage-parent.
  MOVE 'MIRCHI'      TO wa_usage-child.
  MOVE 5             TO wa_usage-usage.
  APPEND wa_usage TO it_usage.

  MOVE 'FISHCURRY'   TO wa_usage-parent.
  MOVE 'ALOO'        TO wa_usage-child.
  MOVE 8             TO wa_usage-usage.
  APPEND wa_usage TO it_usage.

  MOVE 'SPICES'      TO wa_usage-parent.
  MOVE 'MIRCHI'      TO wa_usage-child.
  MOVE 2             TO wa_usage-usage.
  APPEND wa_usage TO it_usage.

  MOVE 'SPICES'      TO wa_usage-parent.
  MOVE 'JEERA'       TO wa_usage-child.
  MOVE 3             TO wa_usage-usage.
  APPEND wa_usage TO it_usage.

  MOVE 'SPICES'      TO wa_usage-parent.
  MOVE 'HALUD'       TO wa_usage-child.
  MOVE 7             TO wa_usage-usage.
  APPEND wa_usage TO it_usage.

ENDFORM.                    "f_usage_data


下边是这个 include 的代码

INCLUDE zjncinclude
*&---------------------------------------------------------------------*
*&  Include           ZJNCINCLUDE                                      
*
*&---------------------------------------------------------------------*

*&---------------------------------------------------------------------*
*&  Reincarnations of REUSE_ALV_FIELDCATALOG_MERGE
*&---------------------------------------------------------------------*

*-----------------------------------------------------------------------
* These FORMs are for people accustomed to
*   REUSE_ALV_FIELDCATALOG_MERGE (despite the 72 ch source line limit)
*   but not happy with  LVC_FIELDCATALOG_MERGE
* We do not want to crowd DDIC with too many structures!
*-----------------------------------------------------------------------

*&--------------------------------------------------------------------*
*&      Form  ZJNC_DUMP_LIST  Our Good Old ALV list -  RECOMMENDED!
*&--------------------------------------------------------------------*
FORM zjnc_dump_list  USING value(p_it_name) TYPE c
                           value(p_wa_name) TYPE c
                           value(p_heading) TYPE c.

  TYPE-POOLS: slis.

  DATA:
    stru_ref    TYPE REF TO cl_abap_structdescr,
    comp_tab    TYPE abap_compdescr_tab,
    one_comp    TYPE abap_compdescr,
    one_name    TYPE string,
    type_ref    TYPE REF TO cl_abap_typedescr,
    is_ddic     TYPE abap_bool,
    lt_ddic     TYPE dd_x031l_table,
    wa_ddic     TYPE x031l,
    lt_fcat     TYPE slis_t_fieldcat_alv,
    wa_fcat     TYPE slis_fieldcat_alv,
    ls_layo     TYPE slis_layout_alv,
    l_alv       TYPE REF TO cl_gui_alv_grid.

  FIELD-SYMBOLS: <fs_type>  TYPE ANY,
                 <fs_table> TYPE STANDARD TABLE,
                 <fs_line>  TYPE ANY.

  ASSIGN (p_it_name) TO <fs_table>.

  ASSIGN (p_wa_name) TO <fs_line>.

  ls_layo-colwidth_optimize = 'X'.
  ls_layo-zebra = 'X'.
  ls_layo-window_titlebar = p_heading.
  ls_layo-box_tabname   = p_it_name.

  stru_ref ?= cl_abap_structdescr=>describe_by_data( <fs_line> ).

  comp_tab = stru_ref->components.

  LOOP AT comp_tab INTO one_comp.
    CLEAR wa_fcat.
    wa_fcat-tabname   = p_it_name.
    wa_fcat-fieldname = one_comp-name.

    CONCATENATE p_wa_name '-' one_comp-name INTO one_name.

    ASSIGN (one_name) TO <fs_type>.

    type_ref ?= cl_abap_typedescr=>describe_by_data( <fs_type> ).

    is_ddic = type_ref->is_ddic_type( ).

    IF is_ddic = abap_true.
      lt_ddic = type_ref->get_ddic_object( ).

      LOOP AT lt_ddic INTO wa_ddic.
        CLEAR wa_ddic-tabname.
        SELECT SINGLE
               dd03l~tabname
          INTO wa_ddic-tabname
          FROM dd03l
         WHERE dd03l~fieldname = wa_ddic-fieldname
           AND dd03l~tabname NOT LIKE '/%'.          " I live in normal 
namespace


        wa_fcat-ref_tabname    = wa_ddic-tabname.
        wa_fcat-ref_fieldname = wa_ddic-fieldname.

        SELECT SINGLE
               dd04t~scrtext_s
               dd04t~scrtext_m
               dd04t~scrtext_l
          INTO (wa_fcat-seltext_s, wa_fcat-seltext_m, 
wa_fcat-seltext_l)
          FROM dd04t
         WHERE dd04t~rollname   = wa_ddic-fieldname
           AND dd04t~ddlanguage = sy-langu.

      ENDLOOP.
    ELSE.
      MOVE one_comp-name TO: wa_fcat-seltext_s, wa_fcat-seltext_m, 
wa_fcat-seltext_l.
    ENDIF.

    APPEND wa_fcat TO lt_fcat.

  ENDLOOP.

  CALL FUNCTION 'REUSE_ALV_LIST_DISPLAY'
    EXPORTING
      is_layout   = ls_layo
      it_fieldcat = lt_fcat
    TABLES
      t_outtab    = <fs_table>.

ENDFORM.                    "ZJNC_DUMP_LIST

*&--------------------------------------------------------------------*
*&      Form  ZJNC_DUMP_GRID  Object Oriented
*&--------------------------------------------------------------------*
FORM zjnc_dump_grid  USING value(p_it_name) TYPE c
                           value(p_wa_name) TYPE c
                           value(p_screen)  TYPE n
                           value(p_heading) TYPE c.

  DATA:
    stru_ref    TYPE REF TO cl_abap_structdescr,
    comp_tab    TYPE abap_compdescr_tab,
    one_comp    TYPE abap_compdescr,
    one_name    TYPE string,
    type_ref    TYPE REF TO cl_abap_typedescr,
    is_ddic     TYPE abap_bool,
    lt_ddic     TYPE dd_x031l_table,
    wa_ddic     TYPE x031l,
    lt_fcat     TYPE lvc_t_fcat,
    wa_fcat     TYPE lvc_s_fcat,
    ls_layo     TYPE lvc_s_layo,
    l_alv       TYPE REF TO cl_gui_alv_grid.

  FIELD-SYMBOLS: <fs_type>  TYPE ANY,
                 <fs_table> TYPE ANY TABLE,
                 <fs_line>  TYPE ANY.

  ASSIGN (p_it_name) TO <fs_table>.

  ASSIGN (p_wa_name) TO <fs_line>.

  ls_layo-cwidth_opt = 'X'.
  ls_layo-zebra = 'X'.
  ls_layo-grid_title = p_heading.
  ls_layo-box_fname = p_it_name.

  stru_ref ?= cl_abap_structdescr=>describe_by_data( <fs_line> ).

  comp_tab = stru_ref->components.

  LOOP AT comp_tab INTO one_comp.
    CLEAR wa_fcat.
    wa_fcat-tabname   = p_it_name.
    wa_fcat-fieldname = one_comp-name.

    CONCATENATE p_wa_name '-' one_comp-name INTO one_name.

    ASSIGN (one_name) TO <fs_type>.

    type_ref ?= cl_abap_typedescr=>describe_by_data( <fs_type> ).

    is_ddic = type_ref->is_ddic_type( ).

    IF is_ddic = abap_true.
      lt_ddic = type_ref->get_ddic_object( ).

      LOOP AT lt_ddic INTO wa_ddic.
        CLEAR wa_ddic-tabname.
        SELECT SINGLE
               dd03l~tabname
          INTO wa_ddic-tabname
          FROM dd03l
         WHERE dd03l~fieldname = wa_ddic-fieldname
           AND dd03l~tabname NOT LIKE '/%'.          " I live in normal 
namespace


        wa_fcat-ref_table = wa_ddic-tabname.
        wa_fcat-ref_field = wa_ddic-fieldname.

        SELECT SINGLE
               dd04t~scrtext_s
               dd04t~scrtext_m
               dd04t~scrtext_l
          INTO (wa_fcat-scrtext_s, wa_fcat-scrtext_m, 
wa_fcat-scrtext_l)
          FROM dd04t
         WHERE dd04t~rollname   = wa_ddic-fieldname
           AND dd04t~ddlanguage = sy-langu.

      ENDLOOP.

    ELSE.
      MOVE one_comp-name TO: wa_fcat-scrtext_s, wa_fcat-scrtext_m, 
wa_fcat-scrtext_l.
    ENDIF.

    APPEND wa_fcat TO lt_fcat.

  ENDLOOP.

  CREATE OBJECT l_alv EXPORTING i_parent = cl_gui_container=>screen0.

  CALL METHOD l_alv->set_table_for_first_display
    EXPORTING
      is_layout       = ls_layo
    CHANGING
      it_outtab       = <fs_table>
      it_fieldcatalog = lt_fcat.

  CALL SELECTION-SCREEN p_screen.

ENDFORM.                    "ZJNC_DUMP_GRID


These FORMs are for people accustomed to
  REUSE_ALV_FIELDCATALOG_MERGE (despite the 72 ch source line limit)
  but not happy with  LVC_FIELDCATALOG_MERGE which has NO Internal 
table option
  
We do not want to crowd DDIC with too many structures!

The routines handle any internal table using field name as title 
if not a DDIC data element.

Create a Include ZJNCINCLUDE with the 2 FORMs

There are two FORMs:  ZJNC_DUMP_LIST will be very useful as it is 
simple and needs no screen and can be called any number of times.

Should be very useful also for debugging esp. where Excel is not 
available as you can dump any internal table anytime and inspect contents.

I wrote these routine mainly for debugging and the problem created by 
half-line long comments in internal tables. With RTTI there is no source 
code dependency.

ZJNC_DUMP_GRID is for OO-GRID loving people who can adapt that routine 
for one off reports. 
You can call this ONLY ONCE as it is best used using a dummy selection 
screen - tip from SDN ABAP FAQ.

As FORMs use RTTI there is no special case for Structures!


赞赏支持