Applies to:
1) SAP BPC projects migrating from MS version to 7.X NW version.
2) New development on SAP BPC 7.X NW version.
Summary: The article explains few code snippets which interface with the backend SAP BI system to retrieve or write-back the required BPC data.
Prerequisites: Nascent knowledge of SAP BPC 7.X NW tool, in particular the coding conventions applicable in *.LGF file. Understanding of basic Object-oriented (OOPS) ABAP.
Introduction: A LGF level logic which is required to process large volume of application records will in most likeliness perform better when implemented in ABAP rather than employing the same logic through *.LGF file completely. The ABAP level logic is invoked by calling the BAdI. For more information on BAdI, please refer the following link: SAP Library - Enhancement Framework
To save the extra time overhead in read of application data whenever QUERY is set to ON in START_BADI... END_BADI construct, this parameter can be set to OFF and an equivalent ABAP logic can then fetch the application data. This way the code executes much faster. This kind of code snippet and few more are described below.
Code Snippet # 1
The below code reads a certain dimension's master data
DATA: lo_dim TYPE REF TO cl_uja_dim,
lr_dim_data TYPE REF TO if_uja_dim_data,
lt_attr_name TYPE uja_t_attr_name,
lt_sel TYPE uj0_t_sel,
ls_sel TYPE uj0_s_sel,
lr_data TYPE REF TO data,
ls_emp TYPE REF TO data.
FIELD-SYMBOLS: <lt_emp> TYPE STANDARD TABLE,
<ls_emp> TYPE ANY.
***Construct to generate the EMPLOYEE data from dimension library
REFRESH: lt_attr_name, lt_sel.
CLEAR: ls_sel.
TRY .
CREATE OBJECT lo_dim
EXPORTING
i_appset_id = i_appset_id
i_dimension = 'EMPLOYEE'.
CATCH cx_uja_admin_error .
ENDTRY.
lr_dim_data = lo_dim.
" Append the list of attribute(s) for which the master data is generated
APPEND: 'ID' TO lt_attr_name.
" Bind the condition data to lt_sel table, this will become selection criteria
" analogous to the WHERE clause of a DB SELECT statement
ls_sel-dimension = 'EMPLOYEE'.
ls_sel-attribute = 'CALC'.
ls_sel-sign = 'I'.
ls_sel-option = 'EQ'.
ls_sel-low = 'N'.
APPEND ls_sel TO lt_sel.
" GET DIMENSION MEMBERS
TRY.
CALL METHOD lr_dim_data->read_mbr_data
EXPORTING
it_attr_list = lt_attr_name "attribute list
it_sel = lt_sel "condition data
IMPORTING
er_data = lr_data. "reference of master data table
CATCH cx_uja_admin_error .
ENDTRY.
"Assign the referenced memory area to a field-symbol
ASSIGN lr_data->* TO <lt_emp>.
CREATE DATA ls_emp LIKE LINE OF <lt_emp>.
ASSIGN ls_emp->* TO <ls_emp>.
***End of construct
Points to note:
read_mbr_data method reads the relevant master data from dimension library. In addition to lt_attr_name and lt_sel, developer has options to give a particular hierarchy, or specify if only base members are required to be pulled.
Code Snippet # 2
The below code reads child members of a parent node from the hierarchy of dimension's master data
DATA: lo_dim TYPE REF TO cl_uja_dim,
lr_dim_data TYPE REF TO if_uja_dim_data,
lt_base_en TYPE uja_t_dim_member.
TRY.
CREATE OBJECT lo_dim
EXPORTING
i_appset_id = i_appset_id
i_dimension = 'ENTITY'.
CATCH cx_uja_admin_error.
ENDTRY.
lr_dim_data = lo_dim.
"GET THE CHILD NODES
CALL METHOD lr_dim_data->get_children_mbr
EXPORTING
i_parent_mbr = 'ENT_PAR01'
if_only_base_mbr = 'X'
IMPORTING
et_member = lt_base_en.
Points to note:
If if_only_base_mbr parameter is left blank then all the intermediate hierarchy level nodes are fetched in lt_base_en.
Code Snippet # 3
The below code reads an application’s transaction data and puts in a dynamic internal table
DATA: lt_sel TYPE uj0_t_sel,
ls_sel TYPE uj0_s_sel,
ls_cv TYPE ujk_s_cv,
lo_appl TYPE REF TO cl_uja_application,
lt_appl_dim TYPE uja_t_appl_dim,
ls_appl_dim LIKE LINE OF lt_appl_dim,
lt_dim_name TYPE ujq_t_dim,
ls_dim_name LIKE LINE OF lt_dim_name,
lo_model TYPE REF TO if_uj_model,
lo_dataref TYPE REF TO data.
FIELD-SYMBOLS: <lt_tx_data> TYPE STANDARD TABLE.
*** Get structure of application data table****
CREATE OBJECT lo_appl
EXPORTING
i_appset_id = i_appset_id "input parameter of method
i_application_id = i_appl_id. "input parameter of method
* Getting all dimensions for the given application and appset
REFRESH lt_appl_dim.
lo_appl->get_appl_dim(
EXPORTING
i_appl_id = i_appl_id
IMPORTING
et_appl_dim = lt_appl_dim ).
* populate internal table for SQE call
REFRESH lt_dim_name.
LOOP AT lt_appl_dim INTO ls_appl_dim.
ls_dim_name = ls_appl_dim-dimension.
APPEND ls_dim_name TO lt_dim_name.
ENDLOOP.
* Including MEASURES dimension in table structure
ls_dim_name = 'MEASURES'.
APPEND ls_dim_name TO lt_dim_name.
SORT lt_dim_name.
* Get the structure of the result
TRY.
lo_model = cl_uj_model=>get_model( i_appset_id ).
lo_model->create_tx_data_ref(
EXPORTING
i_appl_name = i_appl_id
i_type = 'T'
it_dim_name = lt_dim_name
if_tech_name = space
IMPORTING
er_data = lo_dataref ).
CATCH cx_uj_static_check.
ENDTRY.
* Assigning the structure to table
ASSIGN lo_dataref->* TO <lt_tx_data>.
"Generating application data with below filter set
REFRESH lt_sel.
CLEAR ls_sel.
ls_sel-dimension = 'RPTCURRENCY'.
ls_sel-low = 'LC'.
APPEND ls_sel TO lt_sel.
" Reading the time values passed from the LGF script that calls this BAdI
ls_sel-dimension = 'TIME'.
READ TABLE it_cv INTO ls_cv WITH KEY dimension = 'TIME'.
IF sy-subrc = 0.
LOOP AT ls_cv-member INTO ls_dim_member.
ls_sel-low = ls_dim_member.
APPEND ls_sel TO lt_sel.
CLEAR ls_dim_member.
ENDLOOP.
ENDIF.
REFRESH <lt_tx_data>.
TRY.
"module call to populate the data records
CALL FUNCTION 'UJQ_RUN_RSDRI_QUERY'
EXPORTING
i_appset_id = i_appset_id
i_appl_id = i_appl_id
it_dim_name = lt_dim_name
if_check_security = abap_false
it_sel = lt_sel "condition data
IMPORTING
et_data = <lt_tx_data>.
CATCH cx_ujq_exception.
ENDTRY.
Points to note:
UJQ_RUN_RSDRI_QUERY reads the application data only for the base level values of the dimensions and the function module can’t fetch the aggregated transaction data at parent level
Code Snippet # 4
The below code push (write) the data back to the application
DATA: l_count TYPE i,
l_incr TYPE i,
l_index1 TYPE p,
l_index2 TYPE p.
DATA: rf_context_ro TYPE REF TO if_uj_context,
lo_wb_main_int TYPE REF TO cl_ujr_write_back,
context_ro TYPE REF TO if_uj_context,
wa_cl_uje_user TYPE REF TO cl_uje_user,
wa_user TYPE uj0_s_user,
wa_work_status TYPE ujr_s_work_status,
gi_message TYPE uj0_t_message,
log TYPE string,
lt_dataref TYPE REF TO data,
ls_dataref TYPE REF TO data,
lo_ref TYPE REF TO cx_root.
***Logic to process the ct_data***
" The logic processes ct_data, ct_data is refreshed and the generated output is appended back to ct_data
" If write is set to OFF in the call to BAdI,
" the new ct_data will now be required to be written back explicitly through ABAP
***Logic to process the ct_data ends***
IF ct_data[] IS NOT INITIAL. " Check to make sure the buffer is not empty
* Get the current context details
CALL METHOD cl_uj_context=>get_cur_context
RECEIVING
ro_context = context_ro.
context_ro->switch_to_srvadmin( ).
* Assign the user details
wa_user = context_ro->ds_user.
TRY.
CALL METHOD cl_uj_context=>set_cur_context
EXPORTING
i_appset_id = i_appset_id
is_user = wa_user
i_appl_id = i_appl_id
i_module_name = context_ro->d_calling_module.
CATCH cx_uj_obj_not_found .
ENDTRY.
wa_work_status-module_id = cl_ujk_model=>g_module_id.
DESCRIBE TABLE ct_data LINES l_count.
l_incr = 0.
DO .
"40000 number based on PACKAGE_SIZE parameter of UJR_PARAM table
l_index1 = 40000 * l_incr + 1.
l_incr = l_incr + 1.
l_index2 = 40000 * l_incr.
IF l_count < l_index2.
" lt_tab_1 declared static internal table having identical structure as that of ct_data
REFRESH lt_tab_1.
APPEND LINES OF ct_data FROM l_index1 TO l_count TO lt_tab_1.
ELSE.
REFRESH lt_tab_1.
APPEND LINES OF ct_data FROM l_index1 TO l_index2 TO lt_tab_1.
ENDIF.
SORT lt_tab_1. " System takes less time to write to application when the data is sorted
TRY.
CREATE OBJECT lo_wb_main_int.
CALL METHOD lo_wb_main_int->write_back_int
EXPORTING
is_work_status = wa_work_status
i_default_logic = abap_false
i_bypass_badi = 'X'
i_sign_trans = abap_false
it_array = lt_tab_1
i_appl_id = i_appl_id
i_appset_id = i_appset_id
IMPORTING
et_message = gi_message
es_status_records = l_status_records.
CATCH cx_uj_static_check INTO lo_ref.
ENDTRY.
IF l_count < l_index2.
"Exit the do.. enddo, as the last package is written to the application
EXIT.
ENDIF.
ENDDO.
ENDIF.
Points to note:
Whenever the data is in process of writing back to application or commiting to DB, the system (based on the filter setting in write-back BAdI) triggers the write-back BAdI. Also the default logic is triggered after the entire process of data save is complete. If this trigger of “extra” logic is not required, then the write_back_int method has i_default_logic and i_bypass_badi as input parameters which can be used to specify to system whether the write-back or the default part should be triggered or not.
Code Snippet # 5
The logic in code snippet # 2 pulls all the base members, immaterial of the level of base members, for a specified parent. Likewise, there is often times a need to read all parents at different levels for a certain base level member. The below code reads all the ascendants for a specified base member from the hierarchy of dimension's master data.
DATA: lo_dim TYPE REF TO cl_uja_dim,
lr_dim_data TYPE REF TO if_uja_dim_data,
lr_hier_en_data TYPE REF TO if_uja_hier,
lt_mbr_name TYPE uja_t_dim_member,
lt_mbr_node TYPE uja_t_mbr_node.
***Construct to read all ascendants (parents) of a base member
TRY.
CREATE OBJECT lo_dim
EXPORTING
i_appset_id = i_appset_id
i_dimension = 'ENTITY'.
CATCH cx_uja_admin_error.
ENDTRY.
lr_dim_data = lo_dim.
"get_hier_of_mbr will generate a reference to (BI backend type information of) ENT_BAS01 base member
CALL METHOD lr_dim_data->get_hier_of_mbr
EXPORTING
i_member = 'ENT_BAS01'
RECEIVING
ro_hier = lr_hier_en_data. "BPC's interface for ENTITY hierarchy
CALL METHOD lr_hier_en_data->get_parents
EXPORTING
i_member = 'ENT_BAS01'
if_self = 'X'
if_parent_after = 'X'
IMPORTING
et_mbr_name = lt_mbr_name
et_mbr_node = lt_mbr_node.
***End of construct
Points to note:
Conclusion:
The above 4 snippets are of most utility in a typical BPC 7.X NW project. One can explore the CL_UJA_DIM, CL_UJA_APPLICATION, and CL_UJR_WRITE_BACK interfaces (SE24) and implement different methods from it to further customize the requirement in addition to the described code snippets. 2 common parameters in all 4 codes are i_appset_id & i_appl_id and they are the input parameters present in the method of invoked BAdI, specifying the appset and application which triggered the logic originally.
Note: All the ABAP mentioned in this article can be directly utilized in any BPC7.X NW project, but it will require a further change and proper testing to suit the client's requirement.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
3 | |
1 | |
1 | |
1 | |
1 | |
1 |