BRFplus Basics – Handling of Amounts
In several scenarios when working with business rules you have to deal with amounts. BRFplus is well prepared for this task but when starting to work with BRFplus and modeling your first rules you might stumble across some pitfalls e. g. when trying to access a the currency of the amount or when using the amount in a procedure call. In addition, there are some performance aspects that you should take into account when working with amounts.
In order to get a decent start when modeling rules with amounts, this blog shall give you some insight into the handling of amounts in BRFplus.
Before we go into detail: all the examples shown in the following sections are not real life examples. Their intention is to explain the concepts of the handling of amounts in BRFplus.
Amounts – Internal Representation
In general BRFplus has an own element of type “amount” that you can use when you have to use amounts in your rule modeling. Do not get fooled by the word “element”. The internal representation of the amount is a structure. It is typed IF_FDT_TYPES=>ELEMENT_AMOUNT which points to the structure FDT_S_AMOUNT:
As you can see the structure consists (as one would expect) of two components: one representing the value of the amount (NUMBER) and one representing the currency (CURRENCY).
Whenever you create a data object in BRFplus and bind to this built-in element you will recognize that BRFplus restricts the options concerning the length and the number of decimals with respect to the currency:
The evaluation of this attributes of the amount is done at runtime so you do not need to bother about that. BRFplus does it automatically for you. The only restriction that you can apply is if you want to allow negative amounts or not.
Comparing fields of Amounts
Let us now assume that we have a function that gets an amount handed over via the BRFplus built-in element and returns another amount:
We attach a rule set to that function and to some comparisons of the input data with some values.Let us first take a look at a simple comparison of the input within a rule:
BRFplus automatically recognizes that we are using an amount and adapts the data capturing for the comparison accordingly i. e. it offers two fields in order to enter the value of the amount as well as the currency that shall be used. The obvious question is now: what happens if the currency in the data object “Input Amount” has a currency that differs from the value we compare against. Then BRFplus has to do some work namely executing a currency conversion during runtime. Let us take a look at how this is done in the code. To do so we have to go to the PROCESS_PURE method of the generated class of the BRFplus function:
We can see that BRFplus checks if the currencies match. If this is the case it just compares the values of the amount (code marked by the red box). In the other case (code marked by the green box) it has to do a complete amount comparison i. e. executing a currency conversion. We want to take a closer look at the second option. Here the code delegates first to the CL_FDT_AMOUNT_CONV=>COMPARE_AMOUNT which does the conversion of the currencies (code marked by the red box) and then the comparison of the converted values (code marked by the green box) as shown in the following screenshot:
In order to do the conversion, the system fetches the current time stamp and converts it to UTC. The exchange rate type is set to “M” and then some internal processing is done in order to avoid rounding of the amounts when doing the conversion. At the end, the basis function module CONVERT_TO_LOCAL_CURRENCY (package SFIB) is used in order to perform the final currency conversion. This is the standard currency conversion behavior of BRFplus that has to be considered when it comes to do the base configuration of the currency exchange rates in the system. If this is not the way you want to do the conversion you have the option of an application exit to implement your own currency conversion logic. This is explained later in this document.
The same concept is used whenever you do such a comparison like within the cells of a decision table:
Taking a look behind the scenes we see the already familiar way of doing the comparison including a currency conversion:
So for simple comparisons of amounts within rules or expressions everything works as expected. Nevertheless, there are some more scenarios that are worth taking a look at.
Getting the single fields of the Amount Structure
Up to now we just compared the whole amount data object i. e. the amount structure with another amount structure. What can we do if we want to access a component of the structure e. g. just the currency within a BRFplus rule or expression? The solution for this is the usage of a formula or to be more explicit the usage of some formula functions that are delivered out-of-the-box. The functions that we are looking for are contained in the category “Miscellaneous Functions” and allow several actions that can be done with respect to amounts. The following formula functions are offered:
- GET_CURRENCY: This function returns the currency as text from an amount
- SET_CURRENCY: This function sets the currency for an amount
- TO_AMOUNT: This function combines a number and a currency into a BRFplus amount
- CONVERT_AMOUNT: This function executes a currency conversion from one amount and a target currency to a target amount
So in case we want to extract the currency of a BRFplus amount the following formula does the job:
There are also some further functionalities within the formula functions that might be worth a look when you have to handle amounts like converting an amount to a string or vice versa. So whenever you have a requirement the catalog of table functions is worth a look in order to fulfill them. Even if there is no explicit formula function a chain of several formula functions might do the job. As a last “exit”, you can always use the option to create a custom formula function, but you should do so only after a detailed check of what is already available.
These formula functions might be quite handy when you have to do e. g. a SELECT to the database where you have to specify the components of the amount explicitly.
Mapping of Amounts in a Procedure Call
One special case of expression is the procedure call. It allows you some specific kind of parameter mapping when it comes to amounts. As an example, we want to call a static class method. This static class method has as input parameters two fields. One for the value of an amount and one for the currency. It returns a structure of the type of a BRFplus amount. How can we call the class from BRFplus? Do we have to do some transformations first in order to be able to provide the input parameters? The answer is no. The expression already has some built-in mapping functionality that does the work for us:
As you can see we have three mapping options when dealing with amounts:
- We can move the value of the amount to a parameter by using the move type “Move Value” (as done for the input parameter IV_AMOUNT)
- We can move the currency of the amount to a parameter by using the move type “Move Currency/Unit” (as done for the input parameter IV_CURRENCY)
- We can enforce a move (corresponding) like behavior by using the move type “Move Corresponding Fields” (as done for the exporting parameter ES_BRFPLUS_AMOUNT)
Again taking a look behind the scene shows us what happens in the three cases:
The code looks as one would expect. The different components are moved to the input parameters (code marked by the red and green box) and the result is directly moved to the target structure (code marked by the blue box).
This move type functionality is quite convenient and reduces additional mapping effort when calling a procedure.
Calling a Function with Amounts
Last but not least we also want to call the BRFplus function from the ABAP backend: This is as easy as usual and as described in the document BRFplus Basics – How to call a function. So just use the code template and fill the parameters accordingly. As the amount is a structure you have to fill the value field as well as the currency field. But that is all the magic. The same statement holds for the handling of the result data object.
Applying the ABAP 7.40 syntax to the code template the filling of the parameters has the following structure:
First we fill the BRFplus structure representing the amount with the value and the currency (code marked by the red box using the VALUE constructor expression) and then transfer the structure as a reference to the table of type ABAP_PARMBIND_TAB. Nothing exciting here, nevertheless make sure that the two parameters of the structure are always filled.
Enhancement Option – Currency Conversion
As already stated there is a predefined exit in order to hook in your own currency conversion logic. Whenever BRFplus has to call the currency it checks, if such an exit exists and in case it does, delegates the currency conversion to this exit This happens in the class CL_FDT_AMOUNT_CONV method CONVERT_AMOUNT:
The procedure how to hook into the exit is a bit different to the “regular” application exit implementation. The starting point is an application exit class that implements the interface IF_FDT_APPLICATION_SETTINGS and that you store on application level in your BRFplus application:
Now in contrast to the usual application exit handling i. e. setting the parameter of the interface to ABAP_TRUE in the constructor of your application exit class (e. g. GV_AUTHORITY_CHECK) and implementing the corresponding interface method to hook in your code (e. g. IF_FDT_APPLICATION_SETTINGS~AUTHORITY_CHECK) you have to store the name of the class that implements your custom currency conversion in the attribute GV_UNIT_CURR_EXIT of your application exit class. The class that you store has to implement the interface IF_FDT_UNIT_CURR_EXIT:
The method CONVERT_AMOUNT is the one that has to be implemented in order to execute a custom currency conversion. When implementing the exit be aware that the typing of the IV_AMOUNT_IN parameter does not refer to the BRFplus amount structure but to the type AMOUNT_INTERNAL which is a packed number:
So in case you require a custom currency conversion this is possible in a modification-free manner. But this comes at a price that you have to be aware of. As you can see the interface contains three additional methods that allow a custom handling of unit conversions. If you use this exit and also deal with units you have to make sure that all four methods are implemented as this exit is called whenever a currency or a unit conversion is triggered within the application the exit class is assigned to. You have no option to specify that you just want to enhance the currency conversion.
Some Words on Performance
Up to now we took for granted that we can work with amounts in BRFplus and got a lot of features (automatic currency conversion, advanced mapping in procedure calls etc.) to deal with the rules using amounts without paying any price.
Taking a closer look at the code that lies behind the rules and expressions dealing with amounts you see that each and every comparison triggers a currency conversion in case that the currencies that are compared differ. This has a negative impact on the overall performance of your BRFplus function and it is something that you have to keep in mind if you want to/have to model your rules using amounts with currencies. This can be escalated by using different currencies to compare against within the rules which in addition makes the comprehensibility of the rule execution difficult (interpreting the traces at a later point in time and checking each and every currency conversion might be cumbersome).
From a performance point-of-view, the best way to get rid of that drawback is to use not to use amounts but just the values within the BRFplus function. So the pattern would be to convert all the data outside of the BRFplus function to a common currency and then hand over only the values to the BRFplus and not the currencies. This way you restrict the conversion to one before the start of the BRFplus function (and probably one after the result was returned).
In case that you really want to have the currency within your rules we recommend to restrict the currency that is allowed within the BRFplus application to a default currency. This can be done on the level of the application within the default settings:
This way you have no choice when implementing your rules and expressions to use a different currency. You can just enter the amount whereas the currency is not changeable as can be seen below:
Again we advise doing the currency conversion outside of BRFplus in order to have it at one spot instead of having it triggered at a lot of different places that you might not have under control when the number of rules grows.
Summarizing this document one can say that BRFplus is capable of dealing with amounts (i. e. with currencies) and offers a lot of functionality out-of-the.box to have a decent handling of this topic. When you have understood the basic concept of currencies and how they are processed in the ABAP code that gets generated out of your modeled rules you will certainly be able to handle rule requirements connected to currencies in a good way.
Although BRFplus offers all this convenience and additional options to influence the currency conversion it comes at a price which name is performance. This is something that you have to keep in mind when modeling rules including amounts and hopefully the hints given above can help you to identify and overcome these issues.
Excellent explanation Christian - as always!
Your blog helped me get out of the pitfall (beginner's mistake), thanks!
Does it mean that whenever we have a "amount" field in a Procedure call (in my case Sum of Customer Open Items), we must use the BRF+ structure FDT_S_AMOUNT?
I am happy that this helped you.
Yes either you already have the right structure in place in the interface of your called procedure or you have to do the mapping.
great Explanation. It helped me a lot to understand more about handling of amounts.
But currently I am facing the following issue and I haven't any clue why it doesn't work.
The requirement is to create a formula with only quantity fields.
The formula looks like this:
( STRUC-ISM01 / STRUC-VGW01 ) / STRUC-BMSCH
STRUC is importing structure of the function.
The Returning-Parameter is a quantity field which is related to a DDIC data-element (QUAN 10 with decimals 2). The result quantity should always be unit "PIECES".
I implemeted the function CONVERT_QUANTITY( , ) in different ways but I always get an exception or Syntax error.
My implementation Looks like this. What's wrong with that?
Exception after running simulation
I would be really greateful for any help.
Many thanks in advance
would you mind if you post this as a question in the Q&A area of the Community (I have to say that as a moderator ). Many thanks
P.S. I will have a look at the new Q&A questions, I promise
P.S: And when posting the question, can you please also provide Screenshots concerning the Input structure and the data types that are used there
UPDATE: The question is now available in Q&A: https://answers.sap.com/questions/351500/brf-formula-convert-quantity.html
Thanks. Could you please explain how to pass the converted amount to the field of a decision tree.
for e.g.: I have translated the foreign to local amount using a class and then pass the value to decision tree to compare against a fixed value.
1 EUR = 1.09 USD ==>Conversion
if 1.09 USD (from above) >= 2 USD return x.
I am trying to understand how to pass the value of field in decision table from the output of above conversion.
Thanks a lot.