Friday, January 23, 2009

No more smiles

No more smiles in ATP. Why SAP why?

Labels: ,

Monday, January 12, 2009

Another spell for the hacker book


The object oriented programming in APO uses in many cases the singleton pattern. An object static method (class method in standard object oriented talk) is used to obtain the object instance. If it is the first time the object is created and stored in a static attribute (class attribute). Then further calls to the method return the instance stored in the attribute. A practical result of this coding logic is that these objects become global structures of data because as long they were initialized at a given point of time, they are can be accessed at any later time just by calling the static method. For example, the object /SAPAPO/CL_ATPFIELD_BUF can be called in ATP user-exits to get the field catalog (some user-exits don’t have the field catalog available in the input parameters).


CALL METHOD /sapapo/cl_atpfield_buf=>get_atpfield
EXPORTING
iv_ordid = lv_ordid
iv_delps = lv_delps
IMPORTING
et_atpfield = lt_atpfield.


This works because the field catalog is stored in a static attribute of the object.

For global classes (like /SAPAPO/CL_ATPFIELD_BUF) this is very simple, but ABAP also allows the definition of local classes. For example, the main objects for the ATP calculation (LCL_REQUIREMENT_ATP, etc) are classes defined inside program /SAPAPO/SAPLATPT. I always wanted to have access to these objects inside user-exits (because it means having access to all ATP information). Something like this trick for global variables but able to access the objects.

After many failed attempts, this one works fine.


DATA:
l_name(150) TYPE c,
l_tabtype(150) TYPE c,
ldr_reqref TYPE REF TO data.

FIELD-SYMBOLS:
<reqref_t> TYPE ANY TABLE.

l_name = '\PROGRAM=/SAPAPO/SAPLATPT\CLASS=LCL_REQUIREMENT_ATP'.
l_tabtype = '\PROGRAM=/SAPAPO/SAPLATPT\TYPE=TBL_REQREF'.

CREATE DATA ldr_reqref TYPE (l_tabtype).
ASSIGN ldr_reqref->* TO <reqref_t> CASTING TYPE (l_tabtype).

CALL METHOD (l_name)=>get_instances
RECEIVING rt_reqref = <reqref_t>.


Now this pointer <reqref_t> is a pointer to a list of all LCL_REQUIREMENT_ATP object instances relevant for the current ATP check.

Labels: ,

A Simple Controller

There are many ways to design a PAL model. The design that comes naturally to our minds is the one that splits the available quantity over a number of buckets (markets, plants, customers, etc).



This design is simple to understand, but from the point of view of automatic control it faces serious challenges. A control system would have to compute where to deallocate and where to allocate quantity. It becomes an optimization problem.

But let's see a different design (that was also part of this discussion). It checks first the capacity on the main buckets and then checks on a second level a capacity that is available for all orders (sequence of procedures).



Let's suppose we use monthly buckets and that at the start of the month the first procedure has 100% of total capacity and the second procedure has zero capacity. This is exactly as having just one level. Then as time passes the control system can read each bucket and compare the available capacity to some expected target value. If there is more free capacity than the target the system can reduce the bucket capacity and allocate the remaining to the second procedure.

The target open quantity can be one of many functions that return a profile of consumption over time. For example it could just be linear, linear within an internal interval or exponential as shown bellow.



This will make a control algorithm that is simple to understand and implement. And for many practical purposes it does what business expects (if a market is not consuming the quota, then it becomes available for the other markets).

Labels: , ,

Happy Lunar New Year

Happy new year everybody!

Yes I should have posted it in time, but hey, today is the lunar new year and that makes a great excuse :-)