# Finding the Constraint

## Capacity evaluation in PP

### Introduction:

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( ).
```

### Conclusion:

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. 🙂

Regards

Jarda

Hi Jaroslav Hrbacek,

Thank you for sharing such article with code.

But it will great help from your side if you can also attach output screen after this enhancement, so it may get very picture for us.

Hi Anand Shukla,

this is great with SAP. Once you have the data (as in our case the itab lt_load), you can use them everywhere. (graphic classes- alv, hierarchical table, graph etc)

In our company, we have various ways for evaluating these data. see pictures: