Sei sulla pagina 1di 9

Useful ABAP code in BPC 7.

X NW version
created by Pankaj Patil on Jun 4, 2012 6:51 AM, last modified by Pankaj Patil on Jul 26, 2012 4:18 PM
Version 2
inShare

TApplies 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 tolt_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 inlt_base_en. Code Snippet # 3 The below code reads an applications 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 cant 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 lo_wb_main_int context_ro wa_cl_uje_user wa_user wa_work_status gi_message log lt_dataref ls_dataref lo_ref

TYPE TYPE TYPE TYPE TYPE TYPE TYPE TYPE TYPE TYPE TYPE

REF REF REF REF

if_uj_context, cl_ujr_write_back, if_uj_context, cl_uje_user, uj0_s_user, ujr_s_work_status, uj0_t_message, string, REF TO data, REF TO data, REF TO cx_root.

TO TO TO TO

***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_intmethod 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 rea

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: lt_mbr_name reads all the hierarchy nodes in an array format. For example: if ENT_BAS01 is at level 4 of the heirarchy with root node being level 1, then lt_mbr_name will have 4 entries containing "ENT_BAS01 and the 3 upper level parents". lt_mbr_node will consist all the hierarchy like information of lt_mbr_name.lt_mbr_node contains columns as MEMBER, PARENT, TLEVEL describing the linkage of base node to its parent(s) within the hierarchy. 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.

ABAP Code (BPC 10 NW) to read an application's transaction data within the BAdI
created by Rajesh Balakrishnan on Jan 14, 2013 7:27 PM, last modified by Rajesh Balakrishnan on Jan 14, 2013 7:55 PM
Version 1
inShare

Tweet This is an updated version of Code Snippet #3 which had been posted by Pankaj Patil in his excellent post pertaining to useful ABAP Codes for BPC 7.x which can be found here : http://scn.sap.com/docs/DOC-28777 The below mentioned code will apply only to BPC 10, and for prior versions of BPC, the link posted above should be referred. As mentioned by Pankaj in his post, the gist of what the below mentioned code will achieve is as follows:

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.
To elaborate, in a START_BADIEND_BADI syntax, we generally keep QUERY=ON and WRITE = ON. eg.

*START_BADI (insert filter name here) QUERY=ON WRITE=ON *END_BADI

QUERY = ON helps to populate the CT_DATA table so that the logic can be executed on the records populated as per the scope file. However, the ABAP code below helps fetch the data records directly into ct_data [] in the BAdI itself. Since the BAdI fetches the data records, we can keep QUERY = OFF, and save the time involved in querying data from BPC. The LGF file will now look this: *START_BADI (insert filter name here) QUERY=OFF WRITE=ON *END_BADI

** 1. **--------- Data Declarations -------** DATA: lt_sel TYPE uj0_t_sel, "Selection criteria table ls_sel TYPE uj0_s_sel, ls_cv TYPE ujk_s_cv, " Logic Current View lt_dim_member TYPE UJA_T_DIM_MEMBER , ls_dim_member LIKE LINE OF lt_dim_member , 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, lo_query TYPE REF TO if_ujo_query , lt_message TYPE uj0_t_message . FIELD-SYMBOLS: <lt_tx_data> TYPE STANDARD TABLE.
*Declare the dimensions of ct_data which should have same number of dimensions as in the scope ,In this example it has 12 fields given below:

TYPES : begin of ty_ctdata, account_p type c length 32, audittrail type c length 32, * flow type c length 32, legal_entity type c length 32, measures type c length 32, plant type c length 32, product type c length 32, profit_center type c length 32, rptcurrency type c length 32, time type c length 32, version type c length 32, zones type c length 32, signeddata type /b28/oisdata ,"(11) type p decimals 7, end of ty_ctdata. DATA : it_ctd_int Initial temporary table. wa_ctd_int type standard table of ty_ctdata , " type ty_ctdata .

**---------------End of Data Declaration----------------------** *---- 2. Create an object for the input parameters such i_appset_id, CREATE OBJECT lo_appl EXPORTING i_appset_id = i_appset_id i_application_id = i_appl_id. *---- 3. Use this object to read the dimension for the i_appl_id & Append ' Measures ' to the dimension table -----* REFRESH lt_appl_dim. lo_appl->get_appl_dim( EXPORTING i_appl_id = i_appl_id IMPORTING et_appl_dim = lt_appl_dim ).Dimension table REFRESH lt_dim_name. **Populate dimension table '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. i_appl_id.-------*

CLEAR ls_dim_name. ENDLOOP. * Include ' Measures ' as dimension table * ls_dim_name = 'MEASURES'. APPEND ls_dim_name TO lt_dim_name. SORT lt_dim_name. *--4. Prepare Selection range table say for ex : 'lt_sel ' for each dimension passing values tofields Dimension
,Attribute, Option ,Sign , low ----*.

loop at lt_dim_name INTO ls_dim_name . CLEAR : ls_cv . * Read from scope for each dimension from current view table* READ TABLE it_cv INTO ls_cv WITH KEY dimension = ls_dim_name . IF sy-subrc = 0. LOOP AT ls_cv-member into ls_dim_member. ls_sel-dimension = ls_cv-dimension. ls_sel-attribute = 'ID'. ls_sel-sign = 'I'. ls_sel-option = 'EQ'. ls_sel-low = ls_dim_member. APPEND ls_sel TO lt_sel. CLEAR ls_dim_member. ENDLOOP. CLEAR lt_dim_member. ENDIF. ENDLOOP. *---5. Create a reference structure similar to ct_data using the method -----* ' create_tx_data_ref ' .
A.

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>.
**Run a query using method

' run_rsdri_query ' **

TRY. lo_query = cl_ujo_query_factory=>get_query_adapter( i_appset_id = i_appset_id i_appl_id = i_appl_id ). ** Run Query to populate ct_data based on dimensions , selection criteria **. lo_query->run_rsdri_query( EXPORTING it_dim_name = lt_dim_name " BPC: Dimension List it_range = lt_sel " BPC: Selection condition if_check_security = ABAP_FALSE " BPC: Generic indicator IMPORTING et_data et_message ). = <lt_tx_data> = lt_message

" BPC: Messages

CATCH cx_ujo_read. ENDTRY.

" Exception of common read

*Move the Queried data into initial temp table. loop at <lt_tx_data> into wa_ctd_int . append wa_ctd_int to it_ctd_int .

ENDLOOP. clear :wa_ctd_int , <lt_tx_data>. *-- 6. Copy data into ct_data ----* REFRESH CT_DATA. * !!Ensure the scope file has a 'MEASURES" dimension!!!* * for data to get correctly copied into ct_data * ct_data[] = it_ctd_int[] . CLEAR it_ctd_int[]
*---------------------------------------------------------------------------------------------------------------------------------------*

Things to Remember:
Ensure that your scope file also includes the MEASURES dimension. eg. *XDIM_MEMBERSET MEASURES = PERIODIC. Without this, the two internal tables end up being incompatible and we get a dump. The CT_DATA fails to populate for some reasion if the CURRENCY dimension is scoped as <ALL>. We were forced to individually specify every currency in our Scope file as *XDIM_MEMBERSET RPTCURRENCY = INR,USD,GBP,EUR (If any of the experts here can explain the reason for the same, it would be very helpful)

The code pasted above can be used in any BPC 10 implementation but it might need slight modifications from project to project (eg. list of dimensions etc)

We request all BPC experts to pitch in and correct us or help us improve our code, if a possibility to do so exists. Hope this is helpful to everyone.

Potrebbero piacerti anche