This is the continuation of the Part-1 in the series “Practical use of BRF+ Application in SAP”
https://blogs.sap.com/2020/06/27/practical-use-of-brf-application-to-design-the-rules-in-sap/#
In this blog, we will discuss about another practical example where We integrated BRF+ and also used some more exciting features provided by BRF+ Framework. New features in the expressions that we will cover are as follow:
- Procedure Call
- Loop
Apart from the above functions, we will also cover the topics and use of other expressions :
- Decision Tables
- DB Lookup
- Formulas
Business Requirements:
On Invoice output, there is a section to display Item details with various columns. In Item description column, there are various rules which we would like to integrate into a BRF+ application.
Before starting all the items, there would be a header section under description column where header information for the invoice document can be displayed.
Rules for header Description:
Rule 1: Display Contract validity period if available in table VEDA for the contract for which current invoice is generated.
Rule 2: Display License ID/ Amendment ID/ Manuscript ID on header when It is available in Invoice Header Structure.
Rule 3: Exclude Contract Validity period on header for specific Invoice types.
Rules for Item Description:
For each Item, description lines should have rule for each line:
Rule 1.1: Line 1 should display Product description from Item structure
Rule 1.2: Line 2 should display the ISBN code from Item structure. For special direct sales materials, It should be sales product ID.
Rule 1.3: Line 3 should display preceding sales document no. and the Item no.
Rule 1.4: Line 4 should display the initial sales document No.
Rule 1.5: Line 5 should display Contract Validity period for the corresponding Item no. when the contract period ( start date & end date ) for Item is different than contract period of header.
Rule 1.6: Next lines should display License ID/ Amendment ID/ Manuscript ID for the corresponding Item no. when the License ID/ Amendment ID/ Manuscript ID for Item is different than header.
Technical Design:
From part-1 of this series, we explained all the basic implementation steps to create a BRF+ application.If you need any guidance in that, please refer the blog: https://blogs.sap.com/2020/06/27/practical-use-of-brf-application-to-design-the-rules-in-sap/#
Function:
Function for the Invoice Output BRF+ would be as follow:
There are 3 importing parameters:
This function would be called from external applications by passing Invoice header and Item data.
Now, Rule set can be created and linked to this function.
Rule Set:
Rule set would contain all the rules defined in the business requirement. Based on that, we would start implementing rules for header first and then we would implement rules for items.
Rule 1: Display Contract validity period if available in table VEDA for the contract for which current invoice is generated.
From importing parameter IS_DOC_HEADER-VBELN_VAUF, We would get the contract no.so we can get the contract start and end dates from table VEDA by using DB Lookup. However, we also want to format the dates in the customer’s country settings.
e.g. If customer belongs to Germany, Date should be in format DD.MM.YYYY
If customer belongs to US, Date should be in format MM/DD/YYYY
To handle this requirement in general, we opted to create a Procedure in BRF+ and called a function module via this procedure.This procedure would return the dates in the required date format based on country key.
Procedure:
Steps to create Procedure call in BRF+ Application:
Step 1: Create ABAP Function module ZSD_OUTPUT_FORMAT_DATE
FUNCTION zsd_output_format_date.
*"----------------------------------------------------------------------
*"*"Local Interface:
*" IMPORTING
*" REFERENCE(IV_CONTRACT_NO) TYPE VBELN_VAUF
*" REFERENCE(IV_COUNTRY_KEY) TYPE LAND1
*" REFERENCE(IV_ITEMNO) TYPE POSNR OPTIONAL
*" EXPORTING
*" REFERENCE(ES_FORMATTED_DATES) TYPE
*" ZST_SD_OUTPUT_FORMATTED_DATES
*"----------------------------------------------------------------------
*FM to format the contract validity dates
IF iv_itemno IS INITIAL.
SELECT SINGLE vbegdat, venddat FROM veda INTO @DATA(ls_veda) WHERE vbeln = @iv_contract_no
AND vposn = '000000'.
ELSE.
SELECT SINGLE vbegdat, venddat FROM veda INTO @ls_veda WHERE vbeln = @iv_contract_no
AND vposn = @iv_itemno.
ENDIF.
IF ls_veda-vbegdat IS NOT INITIAL AND ls_veda-venddat IS NOT INITIAL.
es_formatted_dates-start_date = zcl_fi_outputs_utility=>format_date( iv_land1 = iv_country_key iv_date = ls_veda-vbegdat ).
es_formatted_dates-end_date = zcl_fi_outputs_utility=>format_date( iv_land1 = iv_country_key iv_date = ls_veda-venddat ).
ENDIF.
ENDFUNCTION.
Method FORMAT_DATE would convert the dates in the required format based on country key:
METHOD format_date.
SET COUNTRY iv_land1.
rv_result = |{ iv_date DATE = ENVIRONMENT }|.
ENDMETHOD.
Step 2: Create a new function in BRF+ application
Function would be required to trigger the procedure call . Signature of function should be same as signature of ABAP Function module so we need to create different data objects in function signature as import parameters and result object.
Step 3: Link procedure call expression in the BRF+ Function
In the top expression field, create an expression of type “Procedure Call”
We can select the call type of a procedure ( Static method, Function module, DB Procedure ). In our case, we can select “Function Module” and provide the ABAP FM name created in Step 1.
This step is important to link the ABAP Function module signature with BRF+ Function which in turn calls the procedure
By following the above steps, we can create different procedure calls in the BRF+ application whenever we need to add some complex logic.
Now, back to the Rule 1 to derive the contract validity text, we have created a decision table to configure the constant text in different languages
Decision Table:
Formula:
Now, we have created a Formula to concatenate the constant text from Decision table DT_CONTRACT_VALIDITY_TEXT and validity dates from Procedure PR_GET_FORMATTED_DATE
At the end, after creating all the necessary expressions ( Decision table, Procedure call, Formula ), we are all set to create a rule
Please note that LS_RES_STR_HEAD_ITEM_TEXT is a structure/work area for the result table ET_HEAD_ITEM_DESCRIPTION from our main BRF+ function. (Please refer the Function result data object) So once we will fill the work area with contract validity period line, we will append it into result internal table.
Result Table should be looking as follow:
All the lines highlighted within red border are description text lines for Header section. Sequence no. would indicate the priority of each line to be displayed first.
Lets find out how we composed the Item lines. We need to derive the description lines for each item in the Invoice document. As an import parameter , we passed Item data as IT_DOCUMENT_ITEMS in the main BRF+ function. Now, we would need to read each Item data in a Loop within BRF+ application. For that, BRF+ provides additional expression called Loop.
Loop:
Step 1: Create a new expression type Loop
Step 2: Provide details for Loop expression
For Loop LP_PROCESS_ITEMS, we need to provide:
- Processing Mode -> Whether to return some data objects or perform a repetitive action
- Result Data Object -> In case of returning value, provide result data object
- Loop Mode -> DO..ENDO , WHILE or FOR
Step 3: Enter rules executable for each Item
Since we are preparing a result internal table with Item No., Sequence no.and Text, each rule will have 2 parts. In part 1, we will fill the work area of type result table and in part 2, we will simply append the work area in target internal table and clear the work area to be filled from scratch from subsequent rules.
Rule 1.1: Line 1 should display Product description from Item structure
Get the Product description for each line in import parameter IT_DOCUMENT_ITEMS-ARKTX
Append it into result data object ( table )
Similarly all the different lines can be appended into result table.
Step 4: Call the Loop expression in rule set
To call this Loop, we will add an additional rule in main rule set after processing all the rules for header. From this rule, we can provide the Item Data from Function import parameter and get the result data object filled from the Loop expression.
Now, after we complete this BRF+ application with all the different rules for Header and Items description, we can now integrate it as a function call in ABAP. We have our custom data provider class for Invoice Output. In the CONSTRUCTOR method, we can call the BRF+ application via its function and get the result table in a private attribute to be used across the output data class:
METHOD _get_description_from_brf.
CONSTANTS:lc_function_id TYPE if_fdt_types=>id VALUE '005056A5F0F91EEBA0DFD379B4AB5FE1'.
DATA:lv_timestamp TYPE timestamp,
lt_name_value TYPE abap_parmbind_tab,
ls_name_value TYPE abap_parmbind,
lr_data TYPE REF TO data,
lx_fdt TYPE REF TO cx_fdt,
ls_doc_header TYPE vbdkr,
lr_it_document_items TYPE REF TO data,
lr_vbkdr_line TYPE REF TO data,
lv_language TYPE if_fdt_types=>element_text.
FIELD-SYMBOLS: <ls_any> TYPE any,
<lt_document_items> TYPE STANDARD TABLE.
****************************************************************************************************
* All method calls within one processing cycle calling the same function must use the same timestamp.
* For subsequent calls of the same function, we recommend to use the same timestamp for all calls.
* This is to improve the system performance.
****************************************************************************************************
* If you are using structures or tables without DDIC binding, you have to declare the respective types
* by yourself. Insert the according data type at the respective source code line.
****************************************************************************************************
GET TIME STAMP FIELD lv_timestamp.
****************************************************************************************************
* Process a function without recording trace data, passing context data objects via a name/value table.
****************************************************************************************************
* Prepare function processing:
****************************************************************************************************
* Let BRFplus convert your data into the type BRFplus requires:
* Data object is bound to a DDIC type, so you can improve performance by passing a variable of that type.
* If you pass a variable of this type, you should indicate this by passing "abap_true" for parameter "iv_has_ddic_binding".
****************************************************************************************************
ls_name_value-name = 'IS_DOC_HEADER'.
GET REFERENCE OF ms_header_billing_print INTO lr_data.
cl_fdt_function_process=>move_data_to_data_object( EXPORTING ir_data = lr_data
iv_function_id = lc_function_id
iv_data_object = '005056A5F0F91EDBA0DFDA48F5688028' "IS_DOC_HEADER
iv_timestamp = lv_timestamp
iv_trace_generation = abap_false
iv_has_ddic_binding = abap_true
IMPORTING er_data = ls_name_value-value ).
INSERT ls_name_value INTO TABLE lt_name_value.
****************************************************************************************************
* Let BRFplus convert your data into the type BRFplus requires:
****************************************************************************************************
ls_name_value-name = 'IT_DOCUMENT_ITEMS'.
CREATE DATA lr_it_document_items TYPE vbdpr_tt.
ASSIGN lr_it_document_items->* TO <lt_document_items>.
CREATE DATA lr_vbkdr_line TYPE vbdpr.
ASSIGN lr_vbkdr_line->* TO FIELD-SYMBOL(<ls_data_line>).
LOOP AT mt_items_print ASSIGNING FIELD-SYMBOL(<ls_items>).
ASSIGN COMPONENT 'VBDPR' OF STRUCTURE <ls_items> TO FIELD-SYMBOL(<ls_vbdpr>).
IF sy-subrc = 0.
<ls_data_line> = <ls_vbdpr>.
APPEND <ls_data_line> TO <lt_document_items>.
ENDIF.
ENDLOOP.
lr_data = lr_it_document_items.
cl_fdt_function_process=>move_data_to_data_object( EXPORTING ir_data = lr_data
iv_function_id = lc_function_id
iv_data_object = '005056A5F0F91EDBA0DFE94C0CE5E031' "IT_DOCUMENT_ITEMS
iv_timestamp = lv_timestamp
iv_trace_generation = abap_false
iv_has_ddic_binding = abap_false
IMPORTING er_data = ls_name_value-value ).
INSERT ls_name_value INTO TABLE lt_name_value.
****************************************************************************************************
ls_name_value-name = 'IV_LANGUAGE'.
GET REFERENCE OF mv_spras INTO lr_data.
ls_name_value-value = lr_data.
INSERT ls_name_value INTO TABLE lt_name_value.
****************************************************************************************************
* Create the data to store the result value after processing the function
* You can skip the following call, if you already have
* a variable for the result. Please replace also the parameter
* EA_RESULT in the method call CL_FDT_FUNCTION_PROCESS=>PROCESS
* with the desired variable.
****************************************************************************************************
cl_fdt_function_process=>get_data_object_reference( EXPORTING iv_function_id = lc_function_id
iv_data_object = '_V_RESULT'
iv_timestamp = lv_timestamp
iv_trace_generation = abap_false
IMPORTING er_data = lr_data ).
ASSIGN lr_data->* TO <ls_any>.
TRY.
cl_fdt_function_process=>process( EXPORTING iv_function_id = lc_function_id
iv_timestamp = lv_timestamp
IMPORTING ea_result = rt_result"<ls_any>
CHANGING ct_name_value = lt_name_value ).
CATCH cx_fdt INTO lx_fdt.
****************************************************************************************************
* You can check CX_FDT->MT_MESSAGE for error handling.
****************************************************************************************************
ENDTRY.
ENDMETHOD.
Testing Invoice Form:
After integrating the above BRF+ application with all different rules to define each line applicable for Header and Items, We tested the output using T-Code VF03 , provided one Invoice no. and selected “Issue Output To” by selecting the print output: