Finding the Constraint
Capacity evaluation in PP
The topic of this blog post is to show you how can SAP PP help you to find the constraint on the shop floor.
If you use ToC (Theory of Constraint) in your plant or you would like to or you are at least aware of ToC and its principles then you know that its keystone is knowing your constraint. How to find a constraint in your production using SAP, that is the topic of my post.
How you can do it?
In SAP PP there are standard transactions for capacity evaluation and planning like CM01 and other CMXX transactions using actual data and CM38 for Planning Scenarios. Working with these TAs to get the overall picture about the distribution of capacity loads and overloads across the entire plant is quite challenging. That was the reason I decided to build my own tool which I could customize to my own requirements. From the beginning of my journey, I was trying to use SAP function module CY_FILL_KUBEL. Without having the right documentation, it was hard and almost impossible to get what I wanted. Eventually, I decided to take another approach.
In the coding below you can see my way through with all needed notes. The function of the code is very simple and straightforward. Through parameters you can select capacity IDs and the time area (from, to) you are focusing on. Then it provides the basic tables for each selected ID with available capacity for time period chosen above and with a time grid selected by the parameter p_peart ( Methode get_available => FM ‘CR_CAPACITY_PERIODS’ and ‘CR_CAPACITY_AVAILABLE_PERIODS’ ). You can choose whether to go on with a sum from the table (as in my case) or to use load_tab for details according to your preferences and time grid. The next method provides a sum of all capacity requirements for the capacity ID and time area (expanded by backlog, which is set by the parameter p_back) using the internal table lt_kbeds. The function module ‘CY_AMOUNT_KBED_COMPUTE’ provides the exact amount of the duration for each working step according to settings in work-centre master data. In the last step, the sum of capacity requirements and available capacity are divided to get the percentage of the capacity load.
Here is my coding….
*&---------------------------------------------------------------------* *& Report zcapaload *& *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* REPORT zcapaload. DATA: wa_kapid TYPE kapid. SELECT-OPTIONS:sl_kapid FOR wa_kapid."range for kapid PARAMETERS: p_werk TYPE werks-werks DEFAULT '013'. " your plant PARAMETERS: p_from TYPE sy-datum DEFAULT sy-datum, "parameters for time area to evaluate p_to TYPE sy-datum . PARAMETERS: p_plscn TYPE plscn, " for Planning Scenario p_peart TYPE daper DEFAULT 'C', " for Entry type "A = day; C = week; D = month p_back TYPE i DEFAULT 30. " for backlog -> how far in the history / how many days back CLASS lcl_kapid DEFINITION CREATE PRIVATE. PUBLIC SECTION. TYPES: " for main itab BEGIN OF t_loads, kapid TYPE kapid, "capacity id arbpl TYPE arbpl, "if capacity id goes with work-center, you can mine the number name TYPE kako-name, "if capacity id goes with (Pool) capacity, you can mine the name sum_load TYPE kbed-kruerest, " the sum of capacity requirements sum_avail TYPE kbed-kruerest, " the sum of capacity available load_prct TYPE p LENGTH 5 DECIMALS 2, "load in % END OF t_loads. TYPES: tt_loads TYPE STANDARD TABLE OF t_loads WITH DEFAULT KEY. TYPES BEGIN OF t_kbeds. " for capacity requirements evaluation INCLUDE TYPE kbed . TYPES: duration TYPE kbed-kruerest, "for duration of the capacity requirements in second END OF t_kbeds. CLASS-DATA: lt_loads TYPE tt_loads, lt_kbeds TYPE HASHED TABLE OF t_kbeds WITH UNIQUE KEY kapid bedid bedzl canum. CLASS-METHODS class_constructor. CLASS-METHODS get_table. METHODS constructor IMPORTING is_loads TYPE t_loads. PROTECTED SECTION. PRIVATE SECTION. CLASS-METHODS get_loads. DATA: loads TYPE t_loads. METHODS: get_data RETURNING VALUE(rs_loads) TYPE t_loads, get_available, get_requirements. ENDCLASS. CLASS lcl_kapid IMPLEMENTATION. METHOD constructor. loads = is_loads. ENDMETHOD. METHOD class_constructor. SELECT * FROM kako INTO CORRESPONDING FIELDS OF TABLE lt_loads WHERE kapid IN sl_kapid AND werks = p_werk. ENDMETHOD. METHOD get_table. get_loads( ). " at first we mine all requirements for time area and plant and for Planning Scenario if selected LOOP AT lt_loads ASSIGNING FIELD-SYMBOL(<fs_loads>). " the next step is getting capacity requirements and available for specifically capacity id DATA(lo) = NEW lcl_kapid( <fs_loads> ). <fs_loads> = lo->get_data( ). ENDLOOP. ENDMETHOD. METHOD get_loads. SELECT * FROM kbed APPENDING TABLE lt_kbeds FOR ALL ENTRIES IN lt_loads WHERE kapid = lt_loads-kapid AND sstad <= p_to AND sendd >= p_from AND plscn = p_plscn AND NOT keinh IS NULL AND ( canumf = '0000' OR canumf IS NULL ). SORT lt_kbeds BY kapid. ENDMETHOD. METHOD get_data. get_available( ). get_requirements( ). loads-load_prct = ( loads-sum_load / loads-sum_avail ) * 100. "get load in % rs_loads = loads. ENDMETHOD. METHOD get_available. DATA: load_tab TYPE TABLE OF rc65k. * Create period for each day (shifts can be different by day): CALL FUNCTION 'CR_CAPACITY_PERIODS' EXPORTING datub = p_to datuv = p_from * KAPEL = ' ' kapid = loads-kapid * MRPCAL = ' ' * PEANZ = '000' peart = p_peart "A = day; C = week; D = month * PEBEG = ' ' * PEDAU = '000' * VERSN = * ZRAST = ' ' TABLES t_per = load_tab. * Get available capacity for each day by shift: CALL FUNCTION 'CR_CAPACITY_AVAILABLE_PERIODS' EXPORTING exact_breaks = 'X' shifts = 'X' unit_si = 'X' "in seconds TABLES t_avail = load_tab EXCEPTIONS hierarchy_not_found = 1 object_not_in_hierarchy = 2 version_without_hierarchy = 3 parameter_not_with_time = 4 OTHERS = 5. **get sum LOOP AT load_tab ASSIGNING FIELD-SYMBOL(<fs_load>). loads-sum_avail = loads-sum_avail + <fs_load>-angeb. ENDLOOP. ENDMETHOD. METHOD get_requirements. DATA: ls_prevod TYPE kbedd, ls_duration TYPE cx_duration_sec, backlog TYPE sy-datum. backlog = p_from - p_back. "date for backlog withdraw LOOP AT lt_kbeds ASSIGNING FIELD-SYMBOL(<fs_kbeds>) WHERE kapid = loads-kapid. MOVE-CORRESPONDING <fs_kbeds> TO ls_prevod. CALL FUNCTION 'CY_AMOUNT_KBED_COMPUTE' EXPORTING in_kbed = ls_prevod IMPORTING ex_requirement_sec = ls_duration EXCEPTIONS duration_initial = 1 unit_conversion_error = 2 schedule_error = 3 OTHERS = 4 . IF sy-subrc <> 0. ls_duration = 1. ENDIF. loads-sum_load = loads-sum_load + ls_duration. CLEAR: ls_prevod,ls_duration. ENDLOOP. ENDMETHOD. ENDCLASS. START-OF-SELECTION. lcl_kapid=>get_table( ).
If it is run through all your capacity IDs you can get the ID with the highest load for the time interval which shall be than your constraint you are looking for. With this constraint, according to ToC, you can proceed to 5 focusing steps where SAP can help you too. But this topic is for another blog post. 🙂