SAP Profitability and Cost Management (PCM) includes a number of features that let you extend the functionality of the product’s approach to Activity Based Costing (ABC). Chief amongst these is the ability to write scripts to add your own business rules to your model, such as calculated driver values. That’s one example, but a lesser known use of the SAP PCM rules engine allows the model to run custom scripts after the model calculation has finished. These scripts are called Capacity Rules.
Capacity Rules are rather misnamed, actually. They can be used to identify capacity issues in the model data, but they can also be used for other things. On a recent project, I used them to automatically detect unallocated activity and cost object costs, so that the model creates a useful warning message in the Model Alerts if any costs show up in Activity Unassigned, CO1 Unassigned or CO2 Unassigned.
This is really helpful for our users, because it highlights, and helps them to diagnose, missing driver data or incorrect assignments in the model. Previously the users had to open a grid and painstakingly drill through to find the unallocated costs, and also try to work out why they those costs hadn’t been allocated. Then they would fix those and recalculate the model, but often they hadn’t found all the problems, and had to go through the same process again, until all the issues were solved.
Now the model gives them a diagnostic report, via the Model Alerts, immediately after the model has finished calculating. They can also export the Model Alerts and drop them into the governance documentation that they produce as part of the model’s monthly run.
SAP PCM’s documentation of Capacity Rules doesn’t include all the information that I needed, and it took me a bit of effort to fully get to grips with the functionality, so I’m writing up the lessons that I learned here. Hopefully this is going to be of some use to PCM users out there. I’m sure it’s going to be useful for me to refer back to in the future.
The Capacity Rules dimension
In SAP PCM, “Capacity Rules” is one of the standard dimensions of any model. Referring to Capacity Rules as a dimension is a bit counter-intuitive, because it isn’t really a dimension as such (there’s no data that is actually dimensioned by Capacity Rules). But it’s useful to organise Capacity Rules in a hierarchy structure, like the “real” PCM dimensions.
You can have multiple Capacity Rules. After the model calculation process is finished, SAP PCM runs each Capacity Rule once, unless one of the Capacity Rules returns a non-zero value, in which case PCM doesn’t run the subsequent Capacity Rules.
If you have multiple conditions that you want to check for, it’s possible to do it all in a single Capacity Rule, but probably better to have a separate Capacity Rule for each condition that you want to check. This makes it easier to manage the Capacity Rules, for example to remove a particular condition or even to add new ones.
Each Capacity Rule gets its own node in the Capacity Rules dimension, and, as with other dimensions, you can organise the dimension members into a hierarchy, going as deep as you like. Only the leaf nodes have rules, though, so just use the parents for arranging the leaves into useful groups.
Writing a Capacity Rule
Like other rules in SAP PCM, Capacity Rules are written in VBScript, so if you’ve written PCM rules before, you’ll be quite at home with the syntax.
There are some significant differences, however, in how and when PCM runs Capacity Rules. For one thing, PCM runs the Capacity Rules only at the end of the calculation, when all of the cost allocations have been run. The benefit of this is that all the calculated results are available to the Capacity Rules, so you can safely run code that refers to the calculated Activity Costs or Cost Object Costs of the model.
You can’t, however, store the results of a Capacity Rule in the model. You can, as in other types of rule, return a value from the Capacity Rule by assigning a value to a VBScript variable CellValue, but the only purpose of that is that if the rule assigns a non-zero value to CellValue, SAP PCM writes a critical alert with the Details “Critical Capacity Detected” to the Model Alerts, and doesn’t process subsequent Capacity Rules.
(The documentation says that this happens if the rule returns a value of TRUE via CellValue. Actually, any non-zero value of CellValue will have the same effect).
Personally I haven’t found this very useful. The alert message “Critical Capacity Detected” doesn’t tell you what the problem is, or even the Capacity Rule in which the problem was detected.
I think it’s better to use the RaiseCapacityAlert function, which has parameters for specifying the message that will be displayed, so you can add some useful information that could help you to home in on the problem. RaiseCapacityAlert is documented in the PCM on-line help, in the “Capacity Planning” topic.
One big difference compared to other types of rule is that each Capacity Rule only runs once during a calculation. Other types of rule will run multiple times, depending on type of item that the rule refers to, and the dimensionality of the model. For instance, in a model with 2 leaf-level versions, 12 leaf-level periods and 50 leaf-level Responsibility Centers, each Line Item rule will run 2 * 12 * 50 = 1,200 times (assuming we don’t use Restrict statements in the rules).
For each Capacity Rule, the rule is only run once.
This means that, if you want to run for multiple dimension members, you have to build your own loop into the rule. The SAP PCM documentation has an example of this, which you will find in the on-line help if you search for the topic “Capacity Planning”. But it’s a simple example that assumes any dimension you want to loop around only goes down one level. In my situation, I had to loop through a hierarchy that had multiple levels, didn’t go to the same depth down each branch, and changed frequently. So in my Capacity Rule there’s code that finds its way around a tree of arbitrary structure, and the example shown below uses that.
Capacity Rules can check for particular conditions in the model results and in the model data. Our real-world model checked for unallocated costs in the results, and did some simple validation checks on the data. However, bear in mind that the Capacity Rules run after the model has calculated. If there are issues with the input data, it’s probably preferable to know before you start calculating the model, so that you don’t spend time calculating the model and then find out there’s a problem with the input data. A different method of checking this sort of thing might be useful, but it’s not covered in this article.
An example Capacity Rule
In our model, we expect all Activities to be allocated to particular Products. So the purpose of this Capacity Rule is to check every Activity to determine whether there are Cost Object Costs for the Activity in CO1 Unassigned. If there are, it’s a problem that’s probably caused either by a missing Cost Object Assignment or missing Activity Driver data. The Capacity Rule puts a message into the Model Alerts for every Activity that has non-zero costs for CO1 Unassigned.
The rule produces the following Model Alerts.
If you wanted to, you could make the message more specific. Perhaps you would want to tell the user which Period, Version and Responsibility Center the unallocated costs were in too. You could do that addingt nested loops, one for each dimension to the above code. Just be aware that the Capacity Rules might start to take longer to run if you do this.
On the subject of performance, it should be noted that our real-world version of the model had five Capacity Rules, each executing a loop 1,500 times, and it had no noticeable impact on the model calculation time whatsoever.
There were a few other things that caught me out, and I’ve grouped them together in this section.
If SAP PCM complains about the arrays, try changing the Model Calculation Option “Rules Engine”. The default value for this option is “Compiled with VBScript”, but I found that PCM preferred “VB Script”.
I’m not sure why this is, but I think it’s possibly to do with whether the rules engine is able to evaluate the model hierarchies at compile time. If you can shed any light on this, please add a comment below.
Another thing to watch out for is the size of the array DimensionMembersArray in the example. The rule uses this array to maintain a list of all the members of a particular dimension (the Activity dimension, in this case). Theoretically, it should be possible to write the code to increase the size of this array dynamically if the Capacity Rule reaches the last declared element of the array, using VBScript’s ReDim Preserve statement, but I couldn’t get this to work. Possibly it’s a limitation of the way the PCM rules engine has been implemented. Again, if you know why this might be, please feel free to add a comment.
In the end I just declared the array with a size that I knew was going to be big enough for my particular model. My (not real-world) model won’t ever have more than 100 Activities, so I set the upper limit of the array to 100. It doesn’t matter much if you over-estimate the size of the array. The rule only uses however many array elements it needs.
Your model may, of course, increase over time and one day the number of dimension members may overtake the size of the array. However, the rule doesn’t error in that circumstance, it just stops processing, and you won’t see any Capacity Alerts. This is not helpful, so there’s an explicit check built into the Capacity Rule that detects this condition, and raises a critical alert when the condition occurs.
The final gotcha that I want to point out is that Capacity Rules execute in the order in which their dimension members were created. Changing their order by dragging them around the dimension hierarchy won’t alter this: the rule whose member was created first executes first, and the rule whose member was created last executes last. If you want to change the order in which your Capacity Rules run – for example, if you want some capacity rules not to run if an exception is detected by an earlier capacity rule – then you need to rebuild the dimension in the order that you need.
We found Capacity Rules very useful, and they are a terrific way of cutting down the amount of time spent auditing and validating the model and chasing down omissions from the assignments and data. They are a great example of extending the functionality of SAP PCM and adding customisations for our particular requirements. There are other features of PCM – for example using the CalculateSlice function to force calculation of consolidated items and hence speed up reporting from the model – that we didn’t use, and which make use of Capacity Rules, and which you could investigate if that would help you.
If you have any observations, please do add them in the comments.