<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:georss="http://www.georss.org/georss"><id>tag:blogger.com,1999:blog-6297557</id><updated>2010-01-31T18:15:24.123Z</updated><title type="text">Apolemia</title><subtitle type="html">On SAP SCM/APO, life and tech</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/" /><link rel="hub" href="http://pubsubhubbub.appspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default?start-index=26&amp;max-results=25" /><author><name>pvl</name><email>noreply@blogger.com</email></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>132</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/apolemia" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="apolemia" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><feedburner:emailServiceId xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">apolemia</feedburner:emailServiceId><feedburner:feedburnerHostname xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0">http://feedburner.google.com</feedburner:feedburnerHostname><entry><id>tag:blogger.com,1999:blog-6297557.post-4397714850950390055</id><published>2009-10-26T21:52:00.006Z</published><updated>2009-10-26T22:06:00.274Z</updated><category scheme="http://www.blogger.com/atom/ns#" term="atp" /><category scheme="http://www.blogger.com/atom/ns#" term="badi" /><title type="text">Hidden BADIs</title><content type="html">There is a very practical BADI in R3 for developing custom ATP scenarios, named ATP_PUBLISH_RESULTS. But one strange thing is this BADI does not show up in the SE18 queries, for example when doing a query for ATP*. So until recently I did not know about this BADI at all.&lt;br /&gt;&lt;br /&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 276px;" src="http://2.bp.blogspot.com/_LUNtiAx0Y3E/SuYb0FNRJAI/AAAAAAAAARU/nCkwWdY2gWM/s400/badi1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5397031785015092226" /&gt;&lt;br /&gt;&lt;br /&gt;But it will show when inputting the full name. &lt;br /&gt;&lt;br /&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 226px;" src="http://2.bp.blogspot.com/_LUNtiAx0Y3E/SuYb_J8JbwI/AAAAAAAAARc/VMEBNxmf5J0/s400/badi2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5397031975264022274" /&gt;&lt;br /&gt;&lt;br /&gt;So why is it hidden in SE18 queries? With some debugging it is easy to see that a F4 query in SE18 will go to table SXS_ATTR with ATP* as the pattern for the EXIT_NAME field and with INTERNAL different from X. It turns out that this INTERNAL field marks the BADI as internal (only to be used by SAP) so it becomes hidden from the F4 query in SE18. &lt;br /&gt;&lt;br /&gt;So next question was: are there many internal BADIs? It turns out there are about 200 in APO and 400 in R3. So I suppose that it is well worth digging on this table if nothing can be found in the “external” BADIs and exits. Although one should avoid using the internal BADIs I suppose it makes a better option than standard code changes or some &lt;a href="http://apolemia.blogspot.com/2009/01/another-spell-for-hacker-book.html"&gt;extreme hacks&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-4397714850950390055?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/4397714850950390055/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=4397714850950390055&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/4397714850950390055" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/4397714850950390055" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2009/10/hidden-badis.html" title="Hidden BADIs" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_LUNtiAx0Y3E/SuYb0FNRJAI/AAAAAAAAARU/nCkwWdY2gWM/s72-c/badi1.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6297557.post-694598358859784089</id><published>2009-09-23T14:30:00.006+01:00</published><updated>2009-09-23T14:49:43.724+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="sap" /><title type="text">OnSAP.com - questions and answers on SAP topics</title><content type="html">&lt;center&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.onsap.com"&gt;&lt;img style="display:block; border: 0px; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 280px;" src="http://2.bp.blogspot.com/_LUNtiAx0Y3E/SrolYC4NdsI/AAAAAAAAARM/RZeGjyptOFo/s400/onsap_screen.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5384657399494571714" /&gt;&lt;/a&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;I've been working on SAP for a long time. Of course there is still a lot to learn, but on the specific topics I specialize and focus most of my work on, after some time there is no book or SAP documentation with new knowledge. The best and maybe only way to continue learning is getting new challenges and finding solutions, and learning how other people solved hard problems. &lt;br /&gt;&lt;br /&gt;Internet forums are great places to find good questions and answers. Unfortunately sometimes the forums have too much noise, bad questions and bad answers. One site that I think does the right thing is &lt;a href="http://stackoverflow.com"&gt;stackoverflow&lt;/a&gt;. Although it is a forum, it has some mechanisms to increase visibility of the best questions, give credit to the right answers and to the people that write the good questions and answers. The &lt;a href="http://www.onsap.com"&gt;OnSAP&lt;/a&gt; website tries to be the same for &lt;a href="http://www.onsap.com"&gt;SAP questions and answers&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;It is a place where I will post my questions and hopefully my answers when I find them. It starts with a small community but at least on APO and ABAP there will be enough knowledgeable people to make it a good place to discuss hard topics. I also invite all of you to post your questions there, and give some answers if you feel like helping and improving the open knowledge (both the software and the contents of the site are open licensed).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-694598358859784089?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/694598358859784089/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=694598358859784089&amp;isPopup=true" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/694598358859784089" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/694598358859784089" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2009/09/onsapcom-questions-and-answers-on-sap.html" title="OnSAP.com - questions and answers on SAP topics" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_LUNtiAx0Y3E/SrolYC4NdsI/AAAAAAAAARM/RZeGjyptOFo/s72-c/onsap_screen.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6297557.post-3122839030303519139</id><published>2009-07-16T21:27:00.005+01:00</published><updated>2009-10-26T22:07:29.245Z</updated><category scheme="http://www.blogger.com/atom/ns#" term="sap" /><category scheme="http://www.blogger.com/atom/ns#" term="life" /><title type="text">Typical projects</title><content type="html">Typical project of the 90's: FI, CO, SD, MM, PP, sales organizations, warehouses, distribution centers and maybe factories. &lt;br /&gt;&lt;br /&gt;Typical project of this decade: trade company in Luxemburg, Switzerland or other low tax country; stocks owned by the trade company but physically in a different location; outsource production but control the planning of raw materials and possibly reorder from a central location; have the outsourcing partner stocks and in-process productions in the system as if it was a standard plant.  &lt;br /&gt;&lt;br /&gt;It's amazing the base model continues to be the same. But in the past it was clean and now it looks quite twisted.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-3122839030303519139?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/3122839030303519139/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=3122839030303519139&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/3122839030303519139" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/3122839030303519139" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2009/07/typical-projects.html" title="Typical projects" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6297557.post-8139311246069499737</id><published>2009-04-25T23:04:00.003+01:00</published><updated>2009-04-25T23:12:42.141+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="sap" /><title type="text">And now? Going back to ABAP?</title><content type="html">So &lt;a href="http://www.theregister.co.uk/2009/04/21/oracle_sun_open_source/"&gt;Oracle buys Sun&lt;/a&gt; and gets Solaris, Mysql, MaxDB and Java. The first is a very important database but not very relevant to enterprise and SAP world (although it is used in SAP xMII). The second (previously named SAP DB) is the core to SAP APO LiveCache. And the last, the Java programming language, is the programming environment on which most new SAP products are developed and is also used for the cross platform GUI. And I would guess a lot of customers run on Solaris.&lt;br /&gt;&lt;br /&gt;Before this purchase Oracle already had the most used database in SAP deployments. Is it me, or this is too much Oracle on SAP's backyard? If it was in my house, I would start doing some cleaning.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-8139311246069499737?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/8139311246069499737/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=8139311246069499737&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/8139311246069499737" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/8139311246069499737" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2009/04/and-now-going-back-to-abap.html" title="And now? Going back to ABAP?" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6297557.post-4358312832714919977</id><published>2009-03-22T12:14:00.017Z</published><updated>2009-03-22T16:16:23.524Z</updated><category scheme="http://www.blogger.com/atom/ns#" term="macros" /><category scheme="http://www.blogger.com/atom/ns#" term="dp" /><title type="text">Marked Cell in Demand Planning Macros</title><content type="html">I wanted to allow the users to choose a planning book cell, then click on a macro button to open a pop-up window with additional information related to the cell. But it does not seem to be possible to get the marked cell when developing planning book macros.&lt;br /&gt;&lt;br /&gt;The standard macro functions PLOB_MARKED and COLUMN_MARKED work when selecting full rows and columns. Consider the following example macro:&lt;br /&gt;&lt;br /&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 281px; height: 153px;" src="http://1.bp.blogspot.com/_LUNtiAx0Y3E/ScYuPVp3hNI/AAAAAAAAAPg/fnrf7yJagnY/s400/macro1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5315987251203114194" /&gt;&lt;br /&gt;&lt;br /&gt;It is possible to use that macro to identify a cell if the user selects both the row and column (pressing the control key to allow that kind of selection). But that is very user-unfriendly.&lt;br /&gt;&lt;br /&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 180px;" src="http://3.bp.blogspot.com/_LUNtiAx0Y3E/ScYufLhCAxI/AAAAAAAAAPo/-QyexS0muC0/s400/macro2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5315987523359605522" /&gt;&lt;br /&gt;&lt;br /&gt;It turns out that most of the functionality for getting the marked cell in the macros is already available in the lower level macro functions. The standard function /SAPAPO/MARKED_ELEMENTS is used in the macro functions that return the marked row and column. That function also has information on the marked cell, so with some simple modifications it can be used for returning the selected cell.&lt;br /&gt;&lt;br /&gt;It was easy to &lt;a href="http://apolemia.blogspot.com/2008/02/tutorial-on-abap-functions-for-dp.html"&gt;develop new functions&lt;/a&gt; to check the row (PLOB) for the marked cell and a function to check the column for the marked cell. Both call internally the modified /SAPAPO/MARKED_ELEMENTS and are based on the standard functions.&lt;br /&gt;&lt;br /&gt;Then it is possible to develop macros that act on cells, to put the toolbar button for the macro and to open an ALV with cell detail information.&lt;br /&gt;&lt;br /&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 313px; height: 201px;" src="http://4.bp.blogspot.com/_LUNtiAx0Y3E/ScYusqjJK-I/AAAAAAAAAPw/aT5-dG6pvEo/s400/macro3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5315987755028261858" /&gt;&lt;br /&gt;&lt;br /&gt;I still find it strange that marked cell macro is not available in the standard. Perhaps it is in some recent release. IMHO is a must have for planning books.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-4358312832714919977?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/4358312832714919977/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=4358312832714919977&amp;isPopup=true" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/4358312832714919977" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/4358312832714919977" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2009/03/marked-cell-in-demand-planning-macros.html" title="Marked Cell in Demand Planning Macros" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_LUNtiAx0Y3E/ScYuPVp3hNI/AAAAAAAAAPg/fnrf7yJagnY/s72-c/macro1.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6297557.post-146257596922455139</id><published>2009-01-23T10:13:00.003Z</published><updated>2009-01-23T10:16:40.829Z</updated><category scheme="http://www.blogger.com/atom/ns#" term="fun" /><category scheme="http://www.blogger.com/atom/ns#" term="atp" /><title type="text">No more smiles</title><content type="html">No more &lt;a href="http://apolemia.blogspot.com/2006/11/atp-fun-i-always-suspected-that-apo.html"&gt;smiles in ATP&lt;/a&gt;. Why SAP why?&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_LUNtiAx0Y3E/SXmYhy0-60I/AAAAAAAAAPY/Oc09b4X9F8s/s1600-h/sd21.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 381px; height: 149px;" src="http://1.bp.blogspot.com/_LUNtiAx0Y3E/SXmYhy0-60I/AAAAAAAAAPY/Oc09b4X9F8s/s400/sd21.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5294430543297833794" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-146257596922455139?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/146257596922455139/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=146257596922455139&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/146257596922455139" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/146257596922455139" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2009/01/no-more-smiles.html" title="No more smiles" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_LUNtiAx0Y3E/SXmYhy0-60I/AAAAAAAAAPY/Oc09b4X9F8s/s72-c/sd21.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6297557.post-3204605079661289794</id><published>2009-01-12T19:01:00.007Z</published><updated>2009-10-26T22:04:56.535Z</updated><category scheme="http://www.blogger.com/atom/ns#" term="abap" /><category scheme="http://www.blogger.com/atom/ns#" term="atp" /><title type="text">Another spell for the hacker book</title><content type="html">&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_LUNtiAx0Y3E/SWuVPClpHfI/AAAAAAAAAOw/rYMC8sQPleg/s1600-h/hammer.gif"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 150px; height: 149px;" src="http://3.bp.blogspot.com/_LUNtiAx0Y3E/SWuVPClpHfI/AAAAAAAAAOw/rYMC8sQPleg/s400/hammer.gif" border="0" alt=""id="BLOGGER_PHOTO_ID_5290486272902110706" /&gt;&lt;/a&gt;&lt;br /&gt;The object oriented programming in APO uses in many cases the &lt;a href="http://en.wikipedia.org/wiki/Singleton_pattern"&gt;singleton pattern&lt;/a&gt;. 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).&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;CALL METHOD /sapapo/cl_atpfield_buf=&gt;get_atpfield&lt;br /&gt;   EXPORTING&lt;br /&gt;      iv_ordid =  lv_ordid &lt;br /&gt;      iv_delps = lv_delps&lt;br /&gt;   IMPORTING&lt;br /&gt;      et_atpfield = lt_atpfield.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This works because the field catalog is stored in a static attribute of the object. &lt;br /&gt;&lt;br /&gt;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 &lt;a href="http://apolemia.blogspot.com/2004/03/userexit-hacking-here-is-very-useful.html"&gt;this trick&lt;/a&gt; for global variables but able to access the objects.&lt;br /&gt;&lt;br /&gt;After many failed attempts, this one works fine.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;DATA:&lt;br /&gt;    l_name(150)    TYPE c,&lt;br /&gt;    l_tabtype(150) TYPE c,&lt;br /&gt;    ldr_reqref     TYPE REF TO data.&lt;br /&gt;&lt;br /&gt;  FIELD-SYMBOLS:&lt;br /&gt;    &amp;lt;reqref_t&amp;gt; TYPE ANY TABLE.&lt;br /&gt;&lt;br /&gt;  l_name = '\PROGRAM=/SAPAPO/SAPLATPT\CLASS=LCL_REQUIREMENT_ATP'.&lt;br /&gt;  l_tabtype = '\PROGRAM=/SAPAPO/SAPLATPT\TYPE=TBL_REQREF'.&lt;br /&gt;&lt;br /&gt;  CREATE DATA ldr_reqref TYPE (l_tabtype).&lt;br /&gt;  ASSIGN ldr_reqref-&amp;gt;* TO &amp;lt;reqref_t&amp;gt; CASTING TYPE (l_tabtype).&lt;br /&gt;&lt;br /&gt;  CALL METHOD (l_name)=&amp;gt;get_instances&lt;br /&gt;    RECEIVING rt_reqref = &amp;lt;reqref_t&amp;gt;.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now this pointer &amp;lt;reqref_t&amp;gt; is a pointer to a list of all LCL_REQUIREMENT_ATP object instances relevant for the current ATP check.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-3204605079661289794?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/3204605079661289794/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=3204605079661289794&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/3204605079661289794" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/3204605079661289794" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2009/01/another-spell-for-hacker-book.html" title="Another spell for the hacker book" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_LUNtiAx0Y3E/SWuVPClpHfI/AAAAAAAAAOw/rYMC8sQPleg/s72-c/hammer.gif" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6297557.post-5338834165606856421</id><published>2009-01-12T16:42:00.012Z</published><updated>2009-01-12T19:34:05.593Z</updated><category scheme="http://www.blogger.com/atom/ns#" term="pal" /><category scheme="http://www.blogger.com/atom/ns#" term="control" /><category scheme="http://www.blogger.com/atom/ns#" term="atp" /><title type="text">A Simple Controller</title><content type="html">There are many ways to &lt;a href="http://apolemia.blogspot.com/2008/09/modeling-limits-and-reservations-with.html"&gt;design a PAL model&lt;/a&gt;. 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).&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_LUNtiAx0Y3E/SLvZ4VkkKLI/AAAAAAAAAIk/DjS9hXYKOBc/s1600-h/pal1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_LUNtiAx0Y3E/SLvZ4VkkKLI/AAAAAAAAAIk/DjS9hXYKOBc/s400/pal1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5241022153262114994" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;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. &lt;br /&gt;&lt;br /&gt;But let's see a different design (that was also part of &lt;a href="http://apolemia.blogspot.com/2008/09/modeling-limits-and-reservations-with.html"&gt;this discussion&lt;/a&gt;). 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).&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_LUNtiAx0Y3E/SLvaqu-8CUI/AAAAAAAAAJE/J3v9IjrAQl0/s1600-h/pal5.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_LUNtiAx0Y3E/SLvaqu-8CUI/AAAAAAAAAJE/J3v9IjrAQl0/s400/pal5.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5241023019077077314" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_LUNtiAx0Y3E/SWuZ0_LCBpI/AAAAAAAAAPA/hV70CmWIK-g/s1600-h/profiles.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 500px; height: 99px;" src="http://3.bp.blogspot.com/_LUNtiAx0Y3E/SWuZ0_LCBpI/AAAAAAAAAPA/hV70CmWIK-g/s400/profiles.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5290491322866730642" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;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).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-5338834165606856421?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/5338834165606856421/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=5338834165606856421&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/5338834165606856421" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/5338834165606856421" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2009/01/simple-controller.html" title="A Simple Controller" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_LUNtiAx0Y3E/SLvZ4VkkKLI/AAAAAAAAAIk/DjS9hXYKOBc/s72-c/pal1.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6297557.post-1722256242524957841</id><published>2009-01-12T16:32:00.002Z</published><updated>2009-01-12T16:41:38.554Z</updated><title type="text">Happy Lunar New Year</title><content type="html">Happy new year everybody!&lt;br /&gt;&lt;br /&gt;Yes I should have posted it in time, but hey, today is the &lt;a href="http://en.wikipedia.org/wiki/Lunar_New_Year"&gt;lunar new year&lt;/a&gt; and that makes a great excuse :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-1722256242524957841?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/1722256242524957841/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=1722256242524957841&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/1722256242524957841" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/1722256242524957841" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2009/01/happy-lunar-new-year.html" title="Happy Lunar New Year" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6297557.post-5682322008236584404</id><published>2008-12-27T21:53:00.008Z</published><updated>2008-12-27T23:14:28.425Z</updated><category scheme="http://www.blogger.com/atom/ns#" term="pal" /><category scheme="http://www.blogger.com/atom/ns#" term="atp" /><title type="text">From Water Distribution to Product Allocation</title><content type="html">The &lt;a href="http://apolemia.blogspot.com/2008/12/similar-control-system.html"&gt;water distribution control system&lt;/a&gt; is quite similar to gATP product allocation. What is available in vanilla PAL is something like the open loop control system.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_LUNtiAx0Y3E/SVaj-_17_MI/AAAAAAAAAOQ/7OBj0Uk-YAY/s1600-h/diag1.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 247px;" src="http://3.bp.blogspot.com/_LUNtiAx0Y3E/SVaj-_17_MI/AAAAAAAAAOQ/7OBj0Uk-YAY/s400/diag1.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5284591515450735810" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;A common development in PAL implementations is to use sales forecast to create the allocation plan. By frequently updating the allocation plan, PAL will become a feedback controller. &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_LUNtiAx0Y3E/SValM6s6V1I/AAAAAAAAAOg/BwUr2uH14Cg/s1600-h/diag5.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 339px;" src="http://2.bp.blogspot.com/_LUNtiAx0Y3E/SValM6s6V1I/AAAAAAAAAOg/BwUr2uH14Cg/s400/diag5.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5284592854100498258" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The key piece of technology to have a good control system is the controller. In this case the controller is the logic that calculates the bucket capacities from the sales forecast and user defined constraints. It is a bit amazing that SAP APO, probably the most advanced supply chain planning system, left this key piece of technology out of the software. It is up to the people doing the implementation to build the controller. And that is something &lt;strike&gt;hard&lt;/strike&gt; interesting to do.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-5682322008236584404?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/5682322008236584404/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=5682322008236584404&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/5682322008236584404" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/5682322008236584404" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2008/12/from-water-distribution-to-product.html" title="From Water Distribution to Product Allocation" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_LUNtiAx0Y3E/SVaj-_17_MI/AAAAAAAAAOQ/7OBj0Uk-YAY/s72-c/diag1.jpg" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6297557.post-7952487178914317937</id><published>2008-12-27T21:44:00.006Z</published><updated>2008-12-27T23:04:35.811Z</updated><category scheme="http://www.blogger.com/atom/ns#" term="pal" /><category scheme="http://www.blogger.com/atom/ns#" term="atp" /><title type="text">Similar Control System</title><content type="html">I tried to find some real work control problems that are similar in objective to PAL . So far, the one I like more is the control of water allocation in regions of limited water and power supply. &lt;br /&gt;&lt;br /&gt;The water distribution is done using a network of reservoirs. In dry regions, planning and controlling the level of water in each reservoir is quite important since it may not be possible to pump more water into each tank. For each time period (day, week, etc) there is a planned level of water for each tank in the network. If everybody tries to consume more water than available then all will have shortages. In that scenario the planned tank level corresponds to the fair share of water available for each node in the network.&lt;br /&gt;&lt;br /&gt;On the other hand, if there is some tank that experiences more consumption than planned and other tanks have excess capacity, then water needs to be pumped from one place to the other. If power is limited in the region it is also important to plan the pumping of water because it may be more expensive (or not possible at all) to transfer the water only when the tank becomes empty.&lt;br /&gt;&lt;br /&gt;The water network control system will probably plan the consumption of water in each node of the network based on historic values. Then, based of the available water capacity, will define the level that will be loaded on each tank (or the quantity to be pumped).&lt;br /&gt;&lt;br /&gt;The system could just wait for the end of the period and do the same operation again for the next period. Of course this will have the risk of unexpected consumption making some tanks empty. If that happens, and if water is available, someone will have to try to pump water from some node to the empty tanks. This is not a very good system because there will be a penalty for users that run out of water, it needs manual intervention, and it may be more expensive to pump water. This is like the &lt;a href="http://apolemia.blogspot.com/2008/12/open-loop-controller-at-home.html"&gt;open loop system&lt;/a&gt; described before.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_LUNtiAx0Y3E/SVaiNSN-YGI/AAAAAAAAAOA/c4gBHdeZpZY/s1600-h/diag2.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 173px;" src="http://4.bp.blogspot.com/_LUNtiAx0Y3E/SVaiNSN-YGI/AAAAAAAAAOA/c4gBHdeZpZY/s400/diag2.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5284589561878306914" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;A more advanced system will do real-time monitoring of the water level in each tank. Using that information will recalculate the forecasted consumption. Using the new forecast it is possible to define the values for the tank levels so that quotas are enforced in case of drought but at the same time all available water will reach consumers. This is a supervisory control system with a feedback loop.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_LUNtiAx0Y3E/SVaiTurSwuI/AAAAAAAAAOI/red0M7mYChQ/s1600-h/diag3.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 244px;" src="http://1.bp.blogspot.com/_LUNtiAx0Y3E/SVaiTurSwuI/AAAAAAAAAOI/red0M7mYChQ/s400/diag3.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5284589672596685538" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-7952487178914317937?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/7952487178914317937/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=7952487178914317937&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/7952487178914317937" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/7952487178914317937" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2008/12/similar-control-system.html" title="Similar Control System" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_LUNtiAx0Y3E/SVaiNSN-YGI/AAAAAAAAAOA/c4gBHdeZpZY/s72-c/diag2.jpg" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6297557.post-7136428601682910143</id><published>2008-12-21T18:22:00.003Z</published><updated>2008-12-21T18:35:34.966Z</updated><category scheme="http://www.blogger.com/atom/ns#" term="pal" /><category scheme="http://www.blogger.com/atom/ns#" term="atp" /><title type="text">Product Allocation Controller</title><content type="html">In &lt;a href="http://apolemia.blogspot.com/2008/12/open-loop-controller-at-home.html"&gt;this last post&lt;/a&gt; I wrote that &lt;a href="http://help.sap.com/saphelp_scm50/helpdata/en/7a/f1783739e6ff5de10000009b38f8cf/frameset.htm"&gt;PAL&lt;/a&gt; is an open loop controller. That statement implies that information from the evolution of the desired objective is not used to compute the control actions. At this stage I need to try to answer the question: what is the objective function for product allocation controlling? &lt;br /&gt;&lt;br /&gt;It is easier to start by looking at what comes with vanilla PAL (what comes with standard SAP). Many designs are possible (this &lt;a href="http://apolemia.blogspot.com/2008/09/modeling-limits-and-reservations-with.html"&gt;previous post&lt;/a&gt; shows some possibilities), but in each case there is a capacity that is constrained. For each time period and allocation characteristics (market, customer, etc) there is a bucket with a defined capacity. When the capacity is reached no more orders can be confirmed on the bucket. &lt;br /&gt;&lt;br /&gt;This control system is quite similar to something I have at home - the &lt;a href="http://en.wikipedia.org/wiki/Flush_toilet"&gt;flush toilet&lt;/a&gt;. When water reaches the capacity of the tank, the valve is closed and the inflow of water stops. Same with PAL, only that the tank capacity is defined by the user. &lt;br /&gt;&lt;br /&gt;The flush toilet is an &lt;a href="http://en.wikipedia.org/wiki/Control_system#On-off_control"&gt;on-off feedback controller&lt;/a&gt; (uses the information of water level to decide on closing the valve). So PAL should also be an on-off feedback controller if the objective was to control the maximal capacity of the bucket. &lt;br /&gt;&lt;br /&gt;But this is business software, the natural objective function should somehow relate to maximizing profit. And of course, it will always be profit related and only on few exceptions profit will be equivalent to bucket capacity limitation. &lt;br /&gt;&lt;br /&gt;If the goal is to split the available capacity and it is guaranteed that there will be demand to fill each bucket, then capacity limitation and profit are equivalent. This happens because sales profit is constant (all available capacity will be sold) and the additional strategic value related to allocating the products to the desired customers is maximized. This scenario happens, for example when new and over-hyped products are launched or when short time promotions are done. &lt;br /&gt;&lt;br /&gt;But it would be surprising, even in fast growing economies, that demand is always so much large than supply that whatever buckets are defined all capacity is sold. Because when that happens prices are increased to restore balance to the market and increase the profit. So most of the times, for sales allocation purpose, demand is only slightly larger than supply and the goal of PAL controlling has to be different - it must be maximizing capacity usage (all material must be sold) while minimizing the difference between actual and planned bucket allocation.&lt;br /&gt;&lt;br /&gt;So if the control objective is not used for the control actions, it is an open loop controller. At home I have to check the temperature and manually change the controller set-point for the inflow of energy. Some PAL users have to manually change the bucket capacities (quotas) to reach the objective.&lt;br /&gt;&lt;br /&gt;From experience I know that a vanilla PAL works quite well with peak demand (promotions, etc) and it is more problematic in the most common balanced market scenario. I find it interesting that it works well when it is a feedback controller and not so well when it is an open loop controller. So making sure that PAL is always a feedback controller should be a design goal.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-7136428601682910143?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/7136428601682910143/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=7136428601682910143&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/7136428601682910143" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/7136428601682910143" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2008/12/product-allocation-controller.html" title="Product Allocation Controller" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6297557.post-5556283824796038920</id><published>2008-12-18T23:13:00.004Z</published><updated>2008-12-18T23:44:22.584Z</updated><category scheme="http://www.blogger.com/atom/ns#" term="pal" /><category scheme="http://www.blogger.com/atom/ns#" term="atp" /><title type="text">Open loop controller at home</title><content type="html">In my house the heating system is made of electrical heaters that are mainly connected during the night (electricity is cheaper at night where I live). And during the day the heat accumulated in ceramic materials is slowly released. &lt;br /&gt;&lt;br /&gt;To control when the heater should be connected I have a clock timers in the electrical plugs with the scheduled night hours.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_LUNtiAx0Y3E/SUreCHx40FI/AAAAAAAAAN4/Em4m_UDMPHo/s1600-h/timer.jpeg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 200px;" src="http://1.bp.blogspot.com/_LUNtiAx0Y3E/SUreCHx40FI/AAAAAAAAAN4/Em4m_UDMPHo/s400/timer.jpeg" border="0" alt=""id="BLOGGER_PHOTO_ID_5281277641074724946" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This clock device is an &lt;a href="http://en.wikipedia.org/wiki/Open-loop_controller"&gt;open loop controller&lt;/a&gt; (a controler that makes decisions without information of the controlled variable). It is also a good example of the disadvantages of such systems. Since there is no feedback loop, the temperature will vary depending on the external conditions, since the heat input will remain constant. Sometimes it becomes too cold in the house and I need to connect it manually some more hours. When the winter is coming to an end temperature increases, and then I know it is time to reduce the programmed number of hours. &lt;br /&gt;&lt;br /&gt;This system has some advantages but it's terrible if one wants to have good control of the temperature. And it would be expensive if I was to spend time analyzing the measured temperatures and manually trying to adjust the number of hours to adjust the system to the external conditions changes. It would be expensive because my time is limited. &lt;br /&gt;&lt;br /&gt;Looking at what comes with the SAP standard, gATP PAL is an open loop controller (to be continued).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-5556283824796038920?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/5556283824796038920/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=5556283824796038920&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/5556283824796038920" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/5556283824796038920" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2008/12/open-loop-controller-at-home.html" title="Open loop controller at home" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_LUNtiAx0Y3E/SUreCHx40FI/AAAAAAAAAN4/Em4m_UDMPHo/s72-c/timer.jpeg" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6297557.post-7690238173635302514</id><published>2008-12-18T23:11:00.003Z</published><updated>2008-12-18T23:44:10.475Z</updated><category scheme="http://www.blogger.com/atom/ns#" term="pal" /><category scheme="http://www.blogger.com/atom/ns#" term="atp" /><title type="text">Product Allocation</title><content type="html">When I think of science I always think of something exciting like invention. But truth is that many times it is not more than transfering knowledge between similar areas. Like moving furniture between rooms. It's not exciting but it is much more effective than building something new from scratch on the other room. &lt;br /&gt;&lt;br /&gt;So I've been moving some furniture between control theory and gATP product allocation. I'll try to write down my findings in a series of posts.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-7690238173635302514?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/7690238173635302514/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=7690238173635302514&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/7690238173635302514" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/7690238173635302514" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2008/12/product-allocation.html" title="Product Allocation" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6297557.post-2050466011088578770</id><published>2008-12-15T14:48:00.004Z</published><updated>2008-12-15T15:05:59.962Z</updated><title type="text">Data references</title><content type="html">The following is the data reference equivalent to the &lt;a href="http://apolemia.blogspot.com/2008/10/objects-instead-of-references.html"&gt;example code using an object&lt;/a&gt;. It's shorter but less clear (IMHO).&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;TYPES:&lt;br /&gt;  BEGIN OF t_place,&lt;br /&gt;    place TYPE char30,&lt;br /&gt;  END OF t_place,&lt;br /&gt;  t_place_tab TYPE TABLE OF t_place,&lt;br /&gt;  BEGIN OF t_city,&lt;br /&gt;    city_name TYPE char20,&lt;br /&gt;    places_ref TYPE REF TO data,&lt;br /&gt;  END OF t_city.&lt;br /&gt;&lt;br /&gt;FIELD-SYMBOLS:&lt;br /&gt;  &amp;lt;ref&amp;gt; TYPE t_place_tab.&lt;br /&gt;&lt;br /&gt;DATA:&lt;br /&gt;  gt_city TYPE HASHED TABLE OF t_city WITH UNIQUE KEY city_name,&lt;br /&gt;  gs_city TYPE t_city,&lt;br /&gt;  gs_place TYPE t_place.&lt;br /&gt;&lt;br /&gt;START-OF-SELECTION.&lt;br /&gt;  gs_city-city_name = 'Porto'.&lt;br /&gt;  CREATE DATA gs_city-places_ref TYPE t_place_tab.&lt;br /&gt;  ASSIGN gs_city-places_ref-&amp;gt;* TO &amp;lt;ref&amp;gt;.&lt;br /&gt;  gs_place-place = 'Torre dos Clerigos'.&lt;br /&gt;  APPEND gs_place TO &amp;lt;ref&amp;gt;.&lt;br /&gt;  gs_place-place = 'Casa da Musica'.&lt;br /&gt;  APPEND gs_place TO &amp;lt;ref&amp;gt;.&lt;br /&gt;  gs_place-place = 'Serralves'.&lt;br /&gt;  APPEND gs_place TO &amp;lt;ref&amp;gt;.&lt;br /&gt;&lt;br /&gt;  INSERT gs_city INTO TABLE gt_city.&lt;br /&gt;&lt;br /&gt;  gs_city-city_name = 'New York'.&lt;br /&gt;  CREATE DATA gs_city-places_ref TYPE t_place_tab.&lt;br /&gt;  ASSIGN gs_city-places_ref-&amp;gt;* TO &amp;lt;ref&amp;gt;.&lt;br /&gt;  gs_place-place = 'Empire State Building'.&lt;br /&gt;  APPEND gs_place TO &amp;lt;ref&amp;gt;.&lt;br /&gt;  gs_place-place = 'Central Park'.&lt;br /&gt;  APPEND gs_place TO &amp;lt;ref&amp;gt;.&lt;br /&gt;&lt;br /&gt;  INSERT gs_city INTO TABLE gt_city.&lt;br /&gt;&lt;br /&gt;  READ TABLE gt_city INTO gs_city WITH KEY city_name = 'Porto'.&lt;br /&gt;  IF sy-subrc = 0.&lt;br /&gt;    ASSIGN gs_city-places_ref-&amp;gt;* TO &amp;lt;ref&amp;gt;.&lt;br /&gt;    SORT &amp;lt;ref&amp;gt; BY place.&lt;br /&gt;    LOOP AT &amp;lt;ref&amp;gt; INTO gs_place.&lt;br /&gt;      WRITE: / gs_city-city_name, gs_place-place.&lt;br /&gt;    ENDLOOP.&lt;br /&gt;  ENDIF.&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-2050466011088578770?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/2050466011088578770/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=2050466011088578770&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/2050466011088578770" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/2050466011088578770" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2008/12/data-references.html" title="Data references" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6297557.post-1656519646410961009</id><published>2008-10-31T19:11:00.002Z</published><updated>2008-10-31T19:21:36.463Z</updated><title type="text">Objects instead of references</title><content type="html">The ABAP syntax for working with tables is really good. But the syntax for working with references is crap.&lt;br /&gt;&lt;br /&gt;Many times, for the sake of efficiency, I need to mix references and tables. And I never found an easy way to do that in ABAP.&lt;br /&gt;&lt;br /&gt;For example, I want to have a table with thousands of city names and for each city I want to have a table of dozens of places. Then, for a given city I want to get the list of places and do some actions on that data (sorting, removing, changing, etc). Notice that it is not a good idea to have just one table with both cities and places because each sublist operation would have a big penalty because of the big size of the full table.&lt;br /&gt;&lt;br /&gt;In python it is so easy:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;cities = {'Porto':['Casa da Musica','Serralves','Torre dos Clerigos'],&lt;br /&gt;   'New York': ['Empire State Building','Central Park'] }&lt;br /&gt;&lt;br /&gt;#print the sorted list of places in Porto&lt;br /&gt;cities['Porto'].sort()&lt;br /&gt;print cities['Porto']&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;In ABAP I find myself using objects because the resulting syntax is cleaner. It looks something like this:  &lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;TYPES:&lt;br /&gt;  BEGIN OF t_place,&lt;br /&gt;    place TYPE char30,&lt;br /&gt;  END OF t_place.&lt;br /&gt;&lt;br /&gt;TYPES:&lt;br /&gt;  t_tab_places TYPE TABLE OF t_place.&lt;br /&gt;&lt;br /&gt;CLASS place_obj DEFINITION.&lt;br /&gt;  PUBLIC SECTION.&lt;br /&gt;    DATA places_table TYPE t_tab_places.&lt;br /&gt;    METHODS add_place IMPORTING place_name TYPE char30.&lt;br /&gt;  PRIVATE SECTION.&lt;br /&gt;ENDCLASS.                    "place DEFINITION&lt;br /&gt;&lt;br /&gt;CLASS place_obj IMPLEMENTATION.&lt;br /&gt;  METHOD add_place.&lt;br /&gt;    DATA ls_place TYPE t_place.&lt;br /&gt;    ls_place-place = place_name.&lt;br /&gt;    APPEND ls_place TO places_table.&lt;br /&gt;  ENDMETHOD.                 &lt;br /&gt;ENDCLASS.                    &lt;br /&gt;&lt;br /&gt;TYPES:&lt;br /&gt;  BEGIN OF t_city,&lt;br /&gt;    city_name TYPE char20,&lt;br /&gt;    places_ref TYPE REF TO place_obj,&lt;br /&gt;  END OF t_city.&lt;br /&gt;&lt;br /&gt;DATA:&lt;br /&gt;  gt_city TYPE HASHED TABLE OF t_city WITH UNIQUE KEY city_name,&lt;br /&gt;  gs_city TYPE t_city,&lt;br /&gt;  gs_place TYPE t_place.&lt;br /&gt;&lt;br /&gt;DATA oref TYPE REF TO place_obj.&lt;br /&gt;&lt;br /&gt;START-OF-SELECTION.&lt;br /&gt;  gs_city-city_name = 'Porto'.&lt;br /&gt;  CREATE OBJECT oref.&lt;br /&gt;  gs_city-places_ref = oref.&lt;br /&gt;  CALL METHOD oref-&gt;add_place( 'Torre dos Clerigos' ).&lt;br /&gt;  CALL METHOD oref-&gt;add_place( 'Casa da Musica' ).&lt;br /&gt;  CALL METHOD oref-&gt;add_place( 'Serralves' ).&lt;br /&gt;  INSERT gs_city INTO TABLE gt_city.&lt;br /&gt;&lt;br /&gt;  gs_city-city_name = 'New York'.&lt;br /&gt;  CREATE OBJECT oref.&lt;br /&gt;  gs_city-places_ref = oref.&lt;br /&gt;  CALL METHOD oref-&gt;add_place( 'Empire State Building' ).&lt;br /&gt;  CALL METHOD oref-&gt;add_place( 'Central Park' ).&lt;br /&gt;  INSERT gs_city INTO TABLE gt_city.&lt;br /&gt;&lt;br /&gt;  READ TABLE gt_city INTO gs_city WITH KEY city_name = 'Porto'.&lt;br /&gt;  IF sy-subrc = 0.&lt;br /&gt;    oref = gs_city-places_ref.&lt;br /&gt;    SORT oref-&gt;places_table BY place.&lt;br /&gt;    LOOP AT oref-&gt;places_table INTO gs_place.&lt;br /&gt;      WRITE: / gs_city-city_name, gs_place-place.&lt;br /&gt;    ENDLOOP.&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;But it's still far from perfect. Dear lazy web, is there a better way?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-1656519646410961009?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/1656519646410961009/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=1656519646410961009&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/1656519646410961009" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/1656519646410961009" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2008/10/objects-instead-of-references.html" title="Objects instead of references" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6297557.post-1521387153482662489</id><published>2008-09-01T11:57:00.014+01:00</published><updated>2008-09-05T15:06:54.097+01:00</updated><title type="text">Modeling Limits and Reservations with gATP Product Allocation</title><content type="html">Product Allocation (PAL), is the APO tool that enables quota definition for the ATP process. With this tool it is possible, for example, to setup quotas for customers to have more control in the distribution of the stock or plant production capacity. For more on product allocation see &lt;a href="http://help.sap.com/saphelp_scm50/helpdata/en/26/c2d63b18bc7e7fe10000000a114084/frameset.htm"&gt;here&lt;/a&gt; and &lt;a href="http://help.sap.com/saphelp_scm50/helpdata/en/98/5ad83738c11613e10000009b38f8cf/frameset.htm"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Although PAL can be used to model quotas for any characteristic in the sales order, here I will use the simple scenario of modeling quotas for customers to highlight two major topics: limits and reservations.&lt;br /&gt;&lt;br /&gt;A very standard way of using the PAL tool is to set limits for the quantity a customer can buy in a given time period (for example month). Suppose we have a plant that can make 1000 M3 of material, and we have three main customers (A, B, and C) that every month need 400, 300 and 300 M3. We can define the quotas in a single procedure with a single step (the graphic represents a step and each color in the graphic a characteristic combination in the step).&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_LUNtiAx0Y3E/SLvZ4VkkKLI/AAAAAAAAAIk/DjS9hXYKOBc/s1600-h/pal1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_LUNtiAx0Y3E/SLvZ4VkkKLI/AAAAAAAAAIk/DjS9hXYKOBc/s400/pal1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5241022153262114994" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This means that customer A can take at most 400 M3, but it also means that customer A will have reserved 400 M3 of production capacity, because all others together cannot take more than 600 M3.&lt;br /&gt;&lt;br /&gt;This last model works well when there is almost fixed demand. But it does not allow any new customer to place and order and have ATP confirmation. A different scenario for a company with many customers is to model two or three important customers and have some quota for all the others (PAL has a wildcard that represents all the other elements in the set). For example:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_LUNtiAx0Y3E/SLvaEQJlgJI/AAAAAAAAAIs/rsTHNkVs8t4/s1600-h/pal2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_LUNtiAx0Y3E/SLvaEQJlgJI/AAAAAAAAAIs/rsTHNkVs8t4/s400/pal2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5241022357965209746" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Again this model is a both a limit and a reservation of the quantity the customers can get. It works well when the demand is greater than the production capacity, so the result will be equal to the quotas and the excess orders will be rejected or postponed.&lt;br /&gt;&lt;br /&gt;Still with this simple model, it is possible to have some interesting variants. Let's suppose the company is interested in putting a limit on the quantity A and B can get in a given month, but it does not want to reserve them capacity. It should be possible for the other customers to take all the capacity. In this case quotas are defined as limits, and for each element we define the limit we want to impose. And for others we give the total plant capacity (this assumes there will be limitations on the ATP product check, or in alternative a new step can be added with the plant capacity constraint). &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_LUNtiAx0Y3E/SLvaOnBQpmI/AAAAAAAAAI0/rHGvsVRQz98/s1600-h/pal3.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_LUNtiAx0Y3E/SLvaOnBQpmI/AAAAAAAAAI0/rHGvsVRQz98/s400/pal3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5241022535902996066" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;But there are other common scenarios that this simple model does not represent well. Considering again the last model, let's say customer A is a good customer that usually buys from 200 M3 to 500 M3. The plant wants to reserve 200 M3 of capacity but wants to allow him to allocate up to 600 M3. And for customer B reserve 100 M3 and allow up to 500 M3. This kind of business rule is not modeled adequately by the single step, single procedure model we have been using.&lt;br /&gt;&lt;br /&gt;Product allocation modeling is done by a combination of procedures. Each procedure is made of one or several steps and each step has one or several characteristic combinations. These are the modeling building blocks of PAL and they allow a large number of possibilities.&lt;br /&gt;&lt;br /&gt;The characteristic combinations are the customers we have been using (A, B and others, for example). The sequence of steps means the PAL check will go to each step in sequence and will use the resulting quantity and date from one step as the input of the next step. On the other hand, when using several procedures the PAL check gets a confirmed quantity from each of the procedures and uses the one that first confirms the requested quantity or the one that allows a larger confirmation.&lt;br /&gt;&lt;br /&gt;I usually like to think of the steps as mathematical sets, the characteristics combinations are elements in the set. In this analogy the sequence of steps represent set intersections and the different procedures are set unions.&lt;br /&gt;&lt;br /&gt;Getting back to the modeling scenario, if we model each customer in a step, we can set the limit (the customer quota) and also reserve quantity (the difference between the "others" quota and the plant capacity).&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_LUNtiAx0Y3E/SME82zVZCJI/AAAAAAAAAJM/oLlpVgdqcRk/s1600-h/pal4.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_LUNtiAx0Y3E/SME82zVZCJI/AAAAAAAAAJM/oLlpVgdqcRk/s400/pal4.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5242538353426499730" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;For the last example, let's suppose the company just wants to have some minimal capacity reservations (100M3 for customer A and B). The remaining capacity is to be given on first come first served basis. This is better modeled as a sequence of procedures (set union). The first procedure has the capacities for A and B. The system first checks on the first procedure, if quantity is missing it goes to the second procedure, that, in this case has the quantities available for all customers.  &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_LUNtiAx0Y3E/SLvaqu-8CUI/AAAAAAAAAJE/J3v9IjrAQl0/s1600-h/pal5.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_LUNtiAx0Y3E/SLvaqu-8CUI/AAAAAAAAAJE/J3v9IjrAQl0/s400/pal5.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5241023019077077314" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Although the documentation only highlights the standard "limits" model definition, with PAL it's possible to design many different allocation strategies.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-1521387153482662489?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/1521387153482662489/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=1521387153482662489&amp;isPopup=true" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/1521387153482662489" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/1521387153482662489" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2008/09/modeling-limits-and-reservations-with.html" title="Modeling Limits and Reservations with gATP Product Allocation" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_LUNtiAx0Y3E/SLvZ4VkkKLI/AAAAAAAAAIk/DjS9hXYKOBc/s72-c/pal1.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6297557.post-2441734541844023789</id><published>2008-04-29T20:47:00.001+01:00</published><updated>2008-04-29T21:49:23.840+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="osx mac" /><title type="text">SAP on Mac</title><content type="html">SAP with that annoying windows bug fixed.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_LUNtiAx0Y3E/SBd9lNnFSQI/AAAAAAAAAGw/ltD8GdHqXMo/s1600-h/mac1.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_LUNtiAx0Y3E/SBd9lNnFSQI/AAAAAAAAAGw/ltD8GdHqXMo/s400/mac1.jpg" alt="" id="BLOGGER_PHOTO_ID_5194758773457373442" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_LUNtiAx0Y3E/SBd9qtnFSRI/AAAAAAAAAG4/7W_LrKlMwDk/s1600-h/mac2.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_LUNtiAx0Y3E/SBd9qtnFSRI/AAAAAAAAAG4/7W_LrKlMwDk/s400/mac2.jpg" alt="" id="BLOGGER_PHOTO_ID_5194758867946653970" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;* Not really fixed, windows is running inside a virtual machine (VMWare). But since it allows to run applications outside the VM box, SAP feels like a OSX application.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-2441734541844023789?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/2441734541844023789/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=2441734541844023789&amp;isPopup=true" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/2441734541844023789" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/2441734541844023789" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2008/04/sap-on-mac.html" title="SAP on Mac" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_LUNtiAx0Y3E/SBd9lNnFSQI/AAAAAAAAAGw/ltD8GdHqXMo/s72-c/mac1.jpg" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6297557.post-8171824355947673191</id><published>2008-02-20T15:09:00.008Z</published><updated>2008-02-20T15:37:59.365Z</updated><category scheme="http://www.blogger.com/atom/ns#" term="abap" /><category scheme="http://www.blogger.com/atom/ns#" term="macros" /><category scheme="http://www.blogger.com/atom/ns#" term="dp" /><title type="text">Tutorial on ABAP functions for DP macros</title><content type="html">It seems that there is no standard function to calculate the statistical mode. So I thought it would make a good example for a short tutorial on creation of ABAP functions to be used in planning macros.&lt;br /&gt;&lt;br /&gt;The macro functions are standard functions created with SE37 that must have a specific call signature (input and output parameters and tables). The base parameters are the ones shown in the following figure (later other options are presented).&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_LUNtiAx0Y3E/R7xDNUha3WI/AAAAAAAAAF4/wWQv72NuBFA/s1600-h/macro0.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_LUNtiAx0Y3E/R7xDNUha3WI/AAAAAAAAAF4/wWQv72NuBFA/s400/macro0.png" alt="" id="BLOGGER_PHOTO_ID_5169080368440728930" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The VALUE_TAB structure has two fields, one for numbers and one for strings. All input parameters set in the macro are added to this table in the same order as defined in the macro, in the number or string field depending on the data type.&lt;br /&gt;&lt;br /&gt;For our exemple the function will receive a list of numbers. The goal is to calculate the mode of the integer part of the numbers. Since the mode can be a list of several numbers, we intend to return the largest integer number of the list.&lt;br /&gt;&lt;br /&gt;Bellow is the code for such a function. It just counts the frequency of the numbers (after convertion to integers). The final list is sorted and the mode (or maximum of modes) is returned on the output parameter field F_ARGUMENT. The other parameter F_CALC_ERROR is a flag that should be set in case of errors that cannot be handled (the equivalent of raising an exception).&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;FUNCTION z_macro_maxmode .&lt;br /&gt;*"----------------------------------------------------------------------&lt;br /&gt;*"*"Local interface:&lt;br /&gt;*"  TABLES&lt;br /&gt;*"      VALUE_TAB STRUCTURE  /SAPAPO/VALUE_TAB&lt;br /&gt;*"  CHANGING&lt;br /&gt;*"     REFERENCE(F_CALC_ERROR) TYPE  C&lt;br /&gt;*"     REFERENCE(F_ARGUMENT) TYPE  /SAPAPO/MXSOP-V&lt;br /&gt;*"----------------------------------------------------------------------&lt;br /&gt;&lt;br /&gt; TYPES:&lt;br /&gt;   BEGIN OF t_histogram,&lt;br /&gt;     value   TYPE i,&lt;br /&gt;     counter TYPE i,&lt;br /&gt;   END OF t_histogram.&lt;br /&gt;&lt;br /&gt; DATA:&lt;br /&gt;   lv_value TYPE i,&lt;br /&gt;   ls_hist  TYPE t_histogram,&lt;br /&gt;   lt_hist  TYPE TABLE OF t_histogram WITH KEY value.&lt;br /&gt;&lt;br /&gt; LOOP AT value_tab.&lt;br /&gt;   IF value_tab-string IS INITIAL.&lt;br /&gt;     CLEAR ls_hist.&lt;br /&gt;*     just truncated integers to make it simpler&lt;br /&gt;     lv_value = trunc( value_tab-value ).&lt;br /&gt;     READ TABLE lt_hist WITH TABLE KEY value = lv_value INTO ls_hist.&lt;br /&gt;     IF sy-subrc = 0.&lt;br /&gt;*     already in the table, increase the counter&lt;br /&gt;       ls_hist-counter = ls_hist-counter + 1.&lt;br /&gt;       MODIFY TABLE lt_hist FROM ls_hist TRANSPORTING counter.&lt;br /&gt;     ELSE.&lt;br /&gt;*     insert value for the first time in the table&lt;br /&gt;       ls_hist-value = lv_value.&lt;br /&gt;       ls_hist-counter = 1.&lt;br /&gt;       INSERT ls_hist INTO TABLE lt_hist.&lt;br /&gt;     ENDIF.&lt;br /&gt;   ENDIF.&lt;br /&gt; ENDLOOP.&lt;br /&gt;&lt;br /&gt;* return the integer with largest counter (if more than one return the&lt;br /&gt;* largest integer)&lt;br /&gt; SORT lt_hist BY counter DESCENDING value DESCENDING.&lt;br /&gt; READ TABLE lt_hist INDEX 1 INTO ls_hist.&lt;br /&gt;&lt;br /&gt; f_argument = ls_hist-value.&lt;br /&gt;&lt;br /&gt;ENDFUNCTION.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now this function can be added to the macro builder (/sapapo/advm). First one registers the function using the following menu option.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_LUNtiAx0Y3E/R7xD90ha3XI/AAAAAAAAAGA/AMdX6S2Lo8g/s1600-h/macro3.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_LUNtiAx0Y3E/R7xD90ha3XI/AAAAAAAAAGA/AMdX6S2Lo8g/s400/macro3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5169081201664384370" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_LUNtiAx0Y3E/R7xEWEha3YI/AAAAAAAAAGI/a979HSWJpJo/s1600-h/macro4.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_LUNtiAx0Y3E/R7xEWEha3YI/AAAAAAAAAGI/a979HSWJpJo/s400/macro4.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5169081618276212098" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;A list of parameters is shown. The previous macro only uses the base parameters so no other checkbox is flagged, but here is the place to  choose the parameter options.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_LUNtiAx0Y3E/R7xEu0ha3ZI/AAAAAAAAAGQ/iaqlhv29hUg/s1600-h/macro5.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_LUNtiAx0Y3E/R7xEu0ha3ZI/AAAAAAAAAGQ/iaqlhv29hUg/s400/macro5.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5169082043477974418" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Then the macro is created with the new function being called like the standard ones.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_LUNtiAx0Y3E/R7xFYEha3aI/AAAAAAAAAGY/xBUF89bNnoU/s1600-h/macro6.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_LUNtiAx0Y3E/R7xFYEha3aI/AAAAAAAAAGY/xBUF89bNnoU/s400/macro6.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5169082752147578274" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I've found that moving logic to ABAP functions can be a good way to simplify complex macros.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-8171824355947673191?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/8171824355947673191/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=8171824355947673191&amp;isPopup=true" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/8171824355947673191" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/8171824355947673191" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2008/02/tutorial-on-abap-functions-for-dp.html" title="Tutorial on ABAP functions for DP macros" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_LUNtiAx0Y3E/R7xDNUha3WI/AAAAAAAAAF4/wWQv72NuBFA/s72-c/macro0.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6297557.post-3257284119335702574</id><published>2007-12-15T18:57:00.000Z</published><updated>2007-12-15T19:07:23.521Z</updated><category scheme="http://www.blogger.com/atom/ns#" term="fun" /><title type="text">I'm using the wrong APO</title><content type="html">First &lt;a href="http://abaplog.wordpress.com/2007/12/09/new-frontiers-of-apo/"&gt;this post&lt;/a&gt; opened my eyes. Maybe I was using the wrong APO. Then Google sent me the answer on an adsense link (I'm both amazed and scared on how Google makes these guesses). I should be using &lt;a href="http://whc.unesco.org/en/tentativelists/5033/"&gt;APO reef&lt;/a&gt;!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_LUNtiAx0Y3E/R2QkfDTs7uI/AAAAAAAAAFw/g6djfmWtsFM/s1600-h/apo_reef.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_LUNtiAx0Y3E/R2QkfDTs7uI/AAAAAAAAAFw/g6djfmWtsFM/s400/apo_reef.jpg" alt="" id="BLOGGER_PHOTO_ID_5144276790246436578" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-3257284119335702574?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/3257284119335702574/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=3257284119335702574&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/3257284119335702574" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/3257284119335702574" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2007/12/im-using-wrong-apo.html" title="I'm using the wrong APO" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_LUNtiAx0Y3E/R2QkfDTs7uI/AAAAAAAAAFw/g6djfmWtsFM/s72-c/apo_reef.jpg" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6297557.post-8107397873258640411</id><published>2007-12-07T11:20:00.001Z</published><updated>2009-03-22T12:48:42.007Z</updated><category scheme="http://www.blogger.com/atom/ns#" term="abap" /><category scheme="http://www.blogger.com/atom/ns#" term="macros" /><category scheme="http://www.blogger.com/atom/ns#" term="dp" /><title type="text">On Debugging Planning Macros</title><content type="html">Lately I have been dealing with some planning macros. I am a newbie with these macros but I have a lot of experience with ABAP debugging. That's why I was quite happy with the following trick that allows ABAP debugging of planning macros.&lt;br /&gt;&lt;br /&gt;In the macro builder, for a given macro just put the command ADVA in the command window.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_LUNtiAx0Y3E/R1kvUYAmEFI/AAAAAAAAAEs/PoFYw2GqChc/s1600-h/adva_1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_LUNtiAx0Y3E/R1kvUYAmEFI/AAAAAAAAAEs/PoFYw2GqChc/s400/adva_1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5141192476708966482" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It will jump to the ABAP source generated for the macro.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_LUNtiAx0Y3E/R1kvj4AmEGI/AAAAAAAAAE0/WMTXWYn10XI/s1600-h/adva_2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_LUNtiAx0Y3E/R1kvj4AmEGI/AAAAAAAAAE0/WMTXWYn10XI/s400/adva_2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5141192742996938850" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It is a big source file so it may be hard to find the right section to place the breakpoint. I found it helpful to set a stop point in the macro in the step I want to debug.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_LUNtiAx0Y3E/R1kvuoAmEHI/AAAAAAAAAE8/-0_0yUkiCwM/s1600-h/adva_3.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_LUNtiAx0Y3E/R1kvuoAmEHI/AAAAAAAAAE8/-0_0yUkiCwM/s400/adva_3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5141192927680532594" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Then I search the code for PERFORM RESULTS_SHOW.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_LUNtiAx0Y3E/R1kv6YAmEII/AAAAAAAAAFE/eZKWf2gCV1c/s1600-h/adva_4.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_LUNtiAx0Y3E/R1kv6YAmEII/AAAAAAAAAFE/eZKWf2gCV1c/s400/adva_4.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5141193129543995522" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;That's it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-8107397873258640411?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/8107397873258640411/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=8107397873258640411&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/8107397873258640411" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/8107397873258640411" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2007/12/on-debugging-planning-macros.html" title="On Debugging Planning Macros" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_LUNtiAx0Y3E/R1kvUYAmEFI/AAAAAAAAAEs/PoFYw2GqChc/s72-c/adva_1.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6297557.post-4385680747639118257</id><published>2007-11-20T15:47:00.000Z</published><updated>2007-11-20T16:05:52.536Z</updated><category scheme="http://www.blogger.com/atom/ns#" term="tip" /><category scheme="http://www.blogger.com/atom/ns#" term="fun" /><title type="text">Quickies</title><content type="html">From searchSAP a very useful &lt;a href="http://go.techtarget.com/r/2570137/1689974"&gt;tip to find BADIs&lt;/a&gt; (quick instructions: break on SXV_GET_CLIF_BY_NAME, use the TA and check the name in EXIT_NAME when it stops).&lt;br /&gt;&lt;br /&gt;I have to highlight &lt;a href="http://apolemia.blogspot.com/2006/11/atp-fun-i-always-suspected-that-apo.html#comments"&gt;this comment&lt;/a&gt; posted by Zoltan with a finding in the BOP source code. I won't say more, you must check it :-)&lt;br /&gt;&lt;br /&gt;In the same spirit, this &lt;a href="http://nigeljames.wordpress.com/2007/07/18/crm-and-le-tour/"&gt;post by Nigel James&lt;/a&gt; has a funny finding on CRM source.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-4385680747639118257?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/4385680747639118257/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=4385680747639118257&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/4385680747639118257" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/4385680747639118257" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2007/11/quickies.html" title="Quickies" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6297557.post-4774241667851369315</id><published>2007-10-11T16:08:00.000+01:00</published><updated>2007-10-11T16:18:44.746+01:00</updated><title type="text">Hello World</title><content type="html">One of the joys of having a blog is being able to connect to people all over the world. Today I checked the blog statistics (more or less one year of data since I installed google analytics), and it made be very happy. No less than 98 countries, including some exotic places I would really like to visit some day: Mauritius, Trinidad and Tobago, Yemen, Namibia, Uruguay, Peru, Moldova, Panama, and many others (click to enlarge the picture). &lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_LUNtiAx0Y3E/Rw4-cA2GetI/AAAAAAAAAEM/Qu2d12Bt-QA/s1600-h/apolemia_world.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_LUNtiAx0Y3E/Rw4-cA2GetI/AAAAAAAAAEM/Qu2d12Bt-QA/s320/apolemia_world.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5120098477351008978" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The world is a great place.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-4774241667851369315?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/4774241667851369315/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=4774241667851369315&amp;isPopup=true" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/4774241667851369315" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/4774241667851369315" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2007/10/hello-world.html" title="Hello World" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_LUNtiAx0Y3E/Rw4-cA2GetI/AAAAAAAAAEM/Qu2d12Bt-QA/s72-c/apolemia_world.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6297557.post-31901936506659542</id><published>2007-09-29T19:30:00.000+01:00</published><updated>2007-10-10T12:46:25.226+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="abap" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><title type="text">How to use ABAP  HTTP_POST</title><content type="html">SAP has the function modules HTTP_GET and HTTP_POST to call remote urls. With HTTP_GET one can just had parameters in the URL to send information to the external system. For example, setting the url to&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;http://myserver.com/mypage?x=1&amp;y=10&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;sends x=1 and y=10 as parameters to mypage. The problem with HTTP GET is that there is a limit on the ammount of data that can be sent (technically it is unlimited in the new specification, but there are still servers that impose the old limit).&lt;br /&gt;&lt;br /&gt;To send large ammounts of data using HTTP one should use the POST method (ABAP function HTTP_POST). To accomplish the same call with HTTP_POST first the length of the data must be calculated&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;len("x=1&amp;y=10") = 8&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;then the function must be called with the following parameters&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;ABSOLUTE_URI                  http://myserver.com/mypage&lt;br /&gt;REQUEST_ENTITY_BODY_LENGTH    8&lt;br /&gt;REQUEST_ENTITY_BODY           x=1&amp;y=10&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The function group URL_GENERATION has some data quoting functions to help build valid URLs. Also, the introspector tool is helpful to debug the HTTP calls.&lt;br /&gt;&lt;br /&gt;PS. This post was originally in pvl.freezope.org, but that site is down most of the time so I'm moving it here.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-31901936506659542?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/31901936506659542/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=31901936506659542&amp;isPopup=true" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/31901936506659542" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/31901936506659542" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2007/09/how-to-use-abap-httppost.html" title="How to use ABAP  HTTP_POST" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6297557.post-3571389773022443305</id><published>2007-09-28T09:17:00.000+01:00</published><updated>2007-09-28T10:15:43.838+01:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="pass" /><category scheme="http://www.blogger.com/atom/ns#" term="atp" /><title type="text">Very interesting new ATP BADI</title><content type="html">The &lt;a href="http://help.sap.com/saphelp_scm50/helpdata/en/22/977941a51a1809e10000000a155106/frameset.htm"&gt;parameter dependent safety stock &lt;/a&gt; (PASS) is a very interesting functionality introduced in SCM 5. In  its standard form one can use the forecasted demand to calculate a safety stock requirement during the ATP process. But the calculation of the safety stock value can use any other logic we want if we use the extension BADI /SAPAPO/ATP_PSS.&lt;br /&gt;&lt;br /&gt;The process flow is very simple: &lt;br /&gt;&lt;br /&gt;1) In the sales order we make sure that all information need for the calculation is transfered to APO through the field catalogue. &lt;br /&gt;&lt;br /&gt;2) In the BADI we calculate the value we want for the PASS. &lt;br /&gt;&lt;br /&gt;3) The ATP introduced the PASS dummy requirement as the first requirement in the list .&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_LUNtiAx0Y3E/RvzDigbySwI/AAAAAAAAACs/ZfKXeogmgA8/s1600-h/pass0.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_LUNtiAx0Y3E/RvzDigbySwI/AAAAAAAAACs/ZfKXeogmgA8/s400/pass0.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5115178274375486210" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;4) The ATP information returned to the user shows the amount of PASS that was used (which the user should read as: there is this amount of product/capacity, but its reserved for other kind of orders)&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_LUNtiAx0Y3E/RvzDsAbySxI/AAAAAAAAAC0/nb3OL2dKS0c/s1600-h/pass1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://1.bp.blogspot.com/_LUNtiAx0Y3E/RvzDsAbySxI/AAAAAAAAAC0/nb3OL2dKS0c/s400/pass1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5115178437584243474" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;5) At the end of the ATP process the PASS requirement is removed.&lt;br /&gt;&lt;br /&gt;This functionality has many use cases. The one described in the documentation is quite typical. The company wants to keep some quantity always available for rush orders, so a PASS value is defined and the user exit changes the PASS value to zero when the order type is of type "rush order". &lt;br /&gt;&lt;br /&gt;A slightly more complex use case is to use PASS to enforce the allocation quotas at the product availability level. Product allocation is decoupled from the product availability check in ATP, so if a customer has consumed all allocation for the current period the system will shift the availability date to first day of the next period. But it will still be consuming stock/receipts from the previous period if such elements exist. For example, in the picture bellow the red customer places two orders of 100 in month 1. Since he only has 100 of allocation in each month the second order date is shifted for the first day of month 2. But it still uses the receipt from month 1.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_LUNtiAx0Y3E/RvzD4QbySyI/AAAAAAAAAC8/3AcYGLJ2yb0/s1600-h/pass2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_LUNtiAx0Y3E/RvzD4QbySyI/AAAAAAAAAC8/3AcYGLJ2yb0/s400/pass2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5115178648037640994" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;When the orange customer places an order of 200 on month 1 it fails. It is possible from the point of view of allocation, but since the red customer orders are both using the receipt of month 1 the system can only confirm the orange order in month 2.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_LUNtiAx0Y3E/RvzEAgbySzI/AAAAAAAAADE/NP6wo4siRoU/s1600-h/pass3.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_LUNtiAx0Y3E/RvzEAgbySzI/AAAAAAAAADE/NP6wo4siRoU/s400/pass3.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5115178789771561778" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This is the typical problem and with PASS this scenario can be improved. Based on the   allocation data (quota and consumption) a PASS value can be calculated to protect the allocation receipts. That way, when the latter customers place their orders the system will still have both allocation and receipts to confirm the orders in the expected periods. The picture bellow shows the same process when using PASS to protect the open allocation of the orange customer.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_LUNtiAx0Y3E/RvzEHwbyS0I/AAAAAAAAADM/u0u1Ec2dTPM/s1600-h/pass4.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_LUNtiAx0Y3E/RvzEHwbyS0I/AAAAAAAAADM/u0u1Ec2dTPM/s400/pass4.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5115178914325613378" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;A last remark on using PASS with the R3. The &lt;a href="http://help.sap.com/saphelp_scm50/helpdata/en/b2/887941a51a1809e10000000a155106/frameset.htm"&gt;documentation &lt;/a&gt;makes a reference that it is only supported by CRM and it seems to be because there is no user interface to define the PASS type parameter that APO is expecting to receive from R3. But using the BADI APO_BAPI_BUS10400 we can change the parameters coming from R3 and, in this case, we just need to put something like:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;METHOD if_ex_apo_bapi_bus10400~change_inputparamextern.&lt;br /&gt;  DATA: ls_req TYPE bapi10400req.&lt;br /&gt;  LOOP AT requirements INTO ls_req.&lt;br /&gt;    ls_req-safety_stock_parameter = 'P'.&lt;br /&gt;    MODIFY requirements INDEX sy-tabix FROM ls_req.&lt;br /&gt;  ENDLOOP.&lt;br /&gt;ENDMETHOD.&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6297557-3571389773022443305?l=apolemia.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://apolemia.blogspot.com/feeds/3571389773022443305/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=6297557&amp;postID=3571389773022443305&amp;isPopup=true" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/3571389773022443305" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6297557/posts/default/3571389773022443305" /><link rel="alternate" type="text/html" href="http://apolemia.blogspot.com/2007/09/very-interesting-new-atp-badi.html" title="Very interesting new ATP BADI" /><author><name>pvl</name><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd="http://schemas.google.com/g/2005" name="OpenSocialUserId" value="00336456900442907005" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_LUNtiAx0Y3E/RvzDigbySwI/AAAAAAAAACs/ZfKXeogmgA8/s72-c/pass0.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total></entry></feed>
