Sunday, March 22, 2009

Marked Cell in Demand Planning Macros

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.

The standard macro functions PLOB_MARKED and COLUMN_MARKED work when selecting full rows and columns. Consider the following example macro:



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.



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.

It was easy to develop new functions 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.

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.



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.

Labels: ,

Wednesday, February 20, 2008

Tutorial on ABAP functions for DP macros

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.

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



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.

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.

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


FUNCTION z_macro_maxmode .
*"----------------------------------------------------------------------
*"*"Local interface:
*" TABLES
*" VALUE_TAB STRUCTURE /SAPAPO/VALUE_TAB
*" CHANGING
*" REFERENCE(F_CALC_ERROR) TYPE C
*" REFERENCE(F_ARGUMENT) TYPE /SAPAPO/MXSOP-V
*"----------------------------------------------------------------------

TYPES:
BEGIN OF t_histogram,
value TYPE i,
counter TYPE i,
END OF t_histogram.

DATA:
lv_value TYPE i,
ls_hist TYPE t_histogram,
lt_hist TYPE TABLE OF t_histogram WITH KEY value.

LOOP AT value_tab.
IF value_tab-string IS INITIAL.
CLEAR ls_hist.
* just truncated integers to make it simpler
lv_value = trunc( value_tab-value ).
READ TABLE lt_hist WITH TABLE KEY value = lv_value INTO ls_hist.
IF sy-subrc = 0.
* already in the table, increase the counter
ls_hist-counter = ls_hist-counter + 1.
MODIFY TABLE lt_hist FROM ls_hist TRANSPORTING counter.
ELSE.
* insert value for the first time in the table
ls_hist-value = lv_value.
ls_hist-counter = 1.
INSERT ls_hist INTO TABLE lt_hist.
ENDIF.
ENDIF.
ENDLOOP.

* return the integer with largest counter (if more than one return the
* largest integer)
SORT lt_hist BY counter DESCENDING value DESCENDING.
READ TABLE lt_hist INDEX 1 INTO ls_hist.

f_argument = ls_hist-value.

ENDFUNCTION.


Now this function can be added to the macro builder (/sapapo/advm). First one registers the function using the following menu option.





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.



Then the macro is created with the new function being called like the standard ones.



I've found that moving logic to ABAP functions can be a good way to simplify complex macros.

Labels: , ,

Friday, December 07, 2007

On Debugging Planning Macros

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.

In the macro builder, for a given macro just put the command ADVA in the command window.



It will jump to the ABAP source generated for the macro.



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.



Then I search the code for PERFORM RESULTS_SHOW.



That's it.

Labels: , ,