Friday 2 November 2018

Making your own planning and scheduling system

The aim of this blog is to show how you can make your own planning and scheduling system as an add-in into your SAP or at least the first step:  building order net for particular order-position-schedule combination or in other words order status report known from the transaction MD04.

Preface:


Like many other companies, our plant has been struggling with the delivery performance and other problems, which can be solved by various sorts of APS (Advance Planning and Scheduling Systems) such as APO from SAP and others add-ons.  After examining and testing various solutions, we decided to make our own as an add-in in our SAP environment.  As mentioned earlier, the first step and key for following planning and scheduling operations are building order net table.

Here is the code using function module MD_SALES_ORDER_STATUS_REPORT, following by a recursive method GET_LINE for building the desire result table.

MAN Production Planning (PP), ABAP Development, SAP ABAP Tutorial and Material, SAP ABAP Guides, SAP ABAP Study Materials

REPORT zjarda.


PARAMETERS: p_delnr TYPE mdps-del12,
            p_delps TYPE delps,
            p_delet TYPE delet.

CLASS lcl_main DEFINITION.

  PUBLIC SECTION.
  CLASS-METHODS:
  main.
         METHODS:
   constructor IMPORTING i_ioel TYPE ioel.


  PRIVATE SECTION.
          TYPES:BEGIN OF t_itab.
        TYPES: rsnum TYPE ioel-rsnum,
               rspos TYPE ioel-rspos,
               etenr TYPE ioel-etenr,
               level TYPE i,
               matnr  TYPE matnr,
               mng01 TYPE menge13,
               delnr TYPE del12, " delnr for dispositons element   / MRP element number
               nxtrs TYPE rsnum, "Number of Reservation/Dependent Requirement
               key TYPE salv_de_node_key."Number of Reservation/Dependent Requirement
        TYPES END OF t_itab.
  CLASS-DATA: lt_ioel TYPE TABLE OF ioel,
              lt_onet TYPE TABLE OF t_itab,
              ls_onet TYPE t_itab,
              lo_ioel TYPE REF TO lcl_main,
              lt_delkz TYPE TABLE OF char2,
              lv_key TYPE salv_de_node_key VALUE 1,
                 go_tree TYPE REF TO cl_salv_tree,
                 lo_nodes TYPE REF TO   cl_salv_nodes,
                 lo_node TYPE REF TO   cl_salv_node,
                 columns TYPE REF TO cl_salv_columns,
                 lt_itab TYPE TABLE OF t_itab,
                 key TYPE salv_de_node_key.
       DATA: ioel TYPE ioel.
       METHODS get_line.
    CLASS-METHODS get_ioel.
    CLASS-METHODS get_net.
    CLASS-METHODS display.
    CLASS-METHODS get_nodes.

ENDCLASS.

CLASS lcl_main IMPLEMENTATION.

  METHOD main.
   get_ioel( ).
   get_net( ).
   display( ).
  ENDMETHOD.


  METHOD get_ioel.
        CALL FUNCTION 'MD_SALES_ORDER_STATUS_REPORT'
      EXPORTING
        edelet                   = p_delet
        edelkz                   = 'VC' " 'VC' for Orders, for other value see value range on domain delkz in dictonary
        edelnr                   = p_delnr
        edelps                   = p_delps
*       EPLSCN                   = 000 " if needed you can use Planning Scenario
*       AVAILABILITY_CHECK       = ' '
*       NO_SAVETY_STOCK          = ' '
*       DATA_IN_MEMORY           = ' '
*       MEMORY_ID                = 'PLHS'
*       EMATNR                   = ' '
        ewerks                   = '013' " your plant
*       EBERID                   = ' '
*       EMDPS                    =
       nodisp                   = 'X' "otherwise it would be displayed
*       I_IGNORE_MTOLD           = ' '
*       I_PROFID                 = ' '
*       I_REP_REFRESH            = ' '
*       IS_PROFILE               =
*       IT_VBEP_KEYS             =
*       NO_COMMIT_WORK           = ' '
*     IMPORTING
*       ET_MLDELAY               =
*       ET_RTREE_SEL             =
     TABLES
       iioelx                   = lt_ioel
*     EXCEPTIONS
*       ERROR                    = 1
*       OTHERS                   = 2
              .
    IF sy-subrc <> 0.
* Implement suitable error handling here
    ENDIF.
  ENDMETHOD.


  METHOD get_net.
* the first level contains elements for satisfying primary requirements
* the conection goes like this:
*ioel-rsnum = p_delnr.
*ioel-rspos = p_delps.
*ioel-etenr = p_delet.
  LOOP AT lt_ioel ASSIGNING FIELD-SYMBOL(<fs_ioel>) WHERE rsnum = p_delnr
    AND rspos = p_delps
    AND etenr = p_delet
    AND sobes IS NOT INITIAL " we are interested only in not satisfied requirements
     AND ( delkz = 'FE' OR  delkz = 'PA' OR  delkz = 'BE' OR
    delkz = 'LE' OR  delkz = 'LA' OR  delkz = 'BA' OR  delkz = 'WB' OR  delkz = 'SA').  " check your own delkz

     MOVE-CORRESPONDING <fs_ioel> TO ls_onet.
       ls_onet-level = 0.
       ls_onet-key = lv_key.
      APPEND ls_onet TO lt_onet.

   CREATE OBJECT lo_ioel EXPORTING i_ioel = <fs_ioel>.
    lo_ioel->get_line( ). " for lower levels
   CLEAR: lo_ioel, ls_onet.
  ENDLOOP.
  ENDMETHOD.

  METHOD constructor.
   ioel = i_ioel.
  ENDMETHOD.


  METHOD get_line.
* here we are looking through lower levels, which are connecting in this way:
* ioel-nxtrs of upper element =  ioel-rsnum of lower element
  LOOP AT lt_ioel ASSIGNING FIELD-SYMBOL(<fs_ioel>) WHERE rsnum = ioel-nxtrs
     AND sobes IS NOT INITIAL " we are interested only in not satisfied requirements
         AND ( delkz = 'FE' OR  delkz = 'PA' OR  delkz = 'BE' OR
    delkz = 'LE' OR  delkz = 'LA' OR  delkz = 'BA' OR  delkz = 'WB' OR  delkz = 'SA').  " check your own delkz

    READ TABLE lt_onet ASSIGNING FIELD-SYMBOL(<fs_upper>) WITH KEY nxtrs = <fs_ioel>-rsnum.
       MOVE-CORRESPONDING <fs_ioel> TO ls_onet.
   ls_onet-level = <fs_upper>-level + 1.
   lv_key = lv_key + 1.
   ls_onet-key = lv_key.
   APPEND ls_onet TO lt_onet.

   CREATE OBJECT lo_ioel EXPORTING i_ioel = <fs_ioel>.
    lo_ioel->get_line( ). " for lower levels

   CLEAR: lo_ioel, ls_onet.
  ENDLOOP.
  ENDMETHOD.

  METHOD display.

      IF go_tree IS NOT BOUND.
      TRY.
            cl_salv_tree=>factory(
        IMPORTING
          r_salv_tree = go_tree
        CHANGING
          t_table      = lt_itab ).
    CATCH cx_salv_error.
      FREE go_tree.
       ENDTRY.
      ENDIF.
      get_nodes( ).
        columns = go_tree->get_columns( ).
        columns->set_optimize( abap_true ).

  go_tree->display( ).
  ENDMETHOD.

  METHOD get_nodes.
    lo_nodes = go_tree->get_nodes( ).

  LOOP AT lt_onet INTO ls_onet.
    READ TABLE lt_onet ASSIGNING FIELD-SYMBOL(<fs_upper>) WITH KEY nxtrs = ls_onet-rsnum.
    IF sy-subrc = 0.
     key = <fs_upper>-key.
    ENDIF.
    TRY.
      lo_node = lo_nodes->add_node( related_node = key
                            relationship = cl_gui_column_tree=>relat_first_child ).
      lo_node->set_data_row( ls_onet ).

    CATCH cx_salv_msg.
    ENDTRY.
    CLEAR ls_onet.
  ENDLOOP.
  ENDMETHOD.

ENDCLASS.


START-OF-SELECTION.
lcl_main=>main( ).

◈ The result is the internal table LT_IOEL which can be used as a data source for displaying in the tree with the class CL_SALV_TREE – see the picture

MAN Production Planning (PP), ABAP Development, SAP ABAP Tutorial and Material, SAP ABAP Guides, SAP ABAP Study Materials

MAN Production Planning (PP), ABAP Development, SAP ABAP Tutorial and Material, SAP ABAP Guides, SAP ABAP Study Materials

◈ Or it can be used as a base for building and scheduling capacity requirements in your own way. This can be followed by displaying these requirements – see pictures.

MAN Production Planning (PP), ABAP Development, SAP ABAP Tutorial and Material, SAP ABAP Guides, SAP ABAP Study Materials

MAN Production Planning (PP), ABAP Development, SAP ABAP Tutorial and Material, SAP ABAP Guides, SAP ABAP Study Materials

As you can see SAP function modules and classes can be extremely helpful to build your own APS with your own functionalities and logic.

No comments:

Post a Comment