The business object layer (BOL) model is a programming concept that allows for uniform application development, decoupled from interface changes in the underlying business-object-specific application programming interfaces The BOL layer provides a consistent interface to access the business objects APIs or the underlying data fetching APIs using the GENIL framework. The BOL object uses the object oriented approach to access the model and also acts as the buffer for the UI. GENIL is the generic interaction layer which provides you access to the business logic which is present in the Business object. As compared to BOL, GENIL can also be used for scenarios other than the Web UI.
Even though BOL layer is built by SAP specifically for SAP CRM Web UI, it is widely used in HCM portal applications. Instead of going deep into the conceptual level, in this document I have tried to provide a quick code reference for developers who are dealing with the HCM portal developments. Most of the time you will be able to find BOL related examples based on the CRM only. Here we are using an HCM scenario of reading/updating the dependent data for Health plans in Benefits.
The Benefits Participation Overview application uses the Model for ESS Benefits (HRBENF) BOL model.
GENIL_MODEL_BROWSER - This transaction is used to check the BOL Objects and their underlying structures. The BOL objects are related together in order to make it easier to access the related data.
They can be categorized as one of the various kinds on Objects.
Root Objects
Access Objects
Dependent Objects
Abstract Objects
Query Objects
Query Result Objects
View Objects
Dynamic Query Objects
In our example we are using the relation HEALTH_DEP_REL, as you can see it lies in the third level. In our coding we need to drill down to that level to read/update the data existing there.
As per my requirement, I have used the below code as an enhancement in CL_HRESS_BEN_DEPENDENTS->PROCESS_EVENT. This will be triggered on clicking OK button in the plan option popup. You can add your code anywhere based on your requirement.
*----- Data declarations
DATA : lo_bol_core TYPE REF TO cl_crm_bol_core,
lo_hress TYPE REF TO cx_hress,
ls_object_spec TYPE crmt_genil_obj_instance,
lo_iterator TYPE REF TO if_bol_entity_col_iterator,
lo_entity TYPE REF TO cl_crm_bol_entity,
lo2_iterator TYPE REF TO if_bol_entity_col_iterator,
lo_entity TYPE REF TO cl_crm_bol_entity,
lv_object_id TYPE crmt_genil_object_id,
lt_object_specs TYPE crmt_genil_obj_instance_tab,
lo_collection_in TYPE REF TO if_bol_entity_col,
lo_collection_out TYPE REF TO if_bol_entity_col,
lo2_collection_out TYPE REF TO if_bol_entity_col,
lo_access TYPE REF TO if_bol_bo_property_access,
lo_bol_filter TYPE REF TO cl_crm_bol_filter,
lv_tech_exception_text TYPE string,
ls_pernr_struc TYPE hrpernr,
lv_rel_name TYPE crmt_relation_name,
lv_string TYPE string.
*----- Data declaration for objects which stores the change that has to be updated in BOL.
DATA : lt_dep_sel TYPE ztthbn_deplife_dep_sel,
lx_dep_sel TYPE zshbn_deplife_dep_sel,
lx_dep_sel_n TYPE zshbn_deplife_dep_sel.
IF io_event->mv_event_id EQ cl_fpm_event=>gc_event_close_dialog_box AND mo_collection IS BOUND.
io_event->mo_event_data->get_value( EXPORTING iv_key = if_fpm_constants=>gc_dialog_box-dialog_buton_key
IMPORTING ev_value = lv_button ).
IF lv_button = if_fpm_constants=>gc_dialog_action_id-ok.
lo_bol_core = cl_crm_bol_core=>get_instance( ).
lo_bol_core->start_up( iv_appl_name = 'EMPTY'
iv_display_mode_support = space ).
lo_bol_core->load_component( 'HRBENF' ).
*----- Get object
TRY.
ls_pernr_struc-pernr = cl_hress_employee_services=>get_instance( )->get_pernr( ).
CATCH cx_hress INTO lo_hress.
lv_tech_exception_text = cl_hress_fpm_msg_services=>return_tech_exception( lo_hress ).
cl_fpm_factory=>get_instance( )->display_error_page( cl_fpm_error_factory=>create_from_object(
io_exception_obj = lo_hress iv_technical_exception = lv_tech_exception_text iv_additional_info = 'HRESS_EXCEPTION' ) ).
RETURN.
ENDTRY.
lv_object_id = cl_crm_genil_container_tools=>build_object_id( ls_pernr_struc-pernr ).
CLEAR ls_object_spec .
ls_object_spec-object_name = 'PERNR_BEN'.
ls_object_spec-object_id = lv_object_id.
APPEND ls_object_spec TO lt_object_specs.
ls_object_spec-object_name = 'HEALTH_PLANS'.
ls_object_spec-object_id = lv_object_id.
APPEND ls_object_spec TO lt_object_specs.
ls_object_spec-object_name = 'DEPENDENTS'.
ls_object_spec-object_id = lv_object_id.
APPEND ls_object_spec TO lt_object_specs.
lo_collection_in = lo_collection_out = lo_bol_core->get_root_entities( it_instances = lt_object_specs ).
lo_iterator = lo_collection_out->get_iterator( ).
lo_entity = lo_iterator->get_first( ).
IF lo_entity IS BOUND.
lo_entity ->lock( ). "Lock the root entity
lo_entity ->reread( ). "Refresh / re-read the contents
IF lo_collection_out IS BOUND.
lo_entity = lo_collection_out->get_first( ).
IF lo_entity IS BOUND.
lo_entity ->reread( ). "* "Refresh / re-read the contents
*--Filtering the relevant Plan type and Benefit plan from the Health Plans. We are building a filter for that.
lv_rel_name = 'HEALTH_PLANS_REL'.
lo_bol_filter = cl_crm_bol_relation_filter=>get_instance( lv_rel_name ).
CALL METHOD lo_bol_filter ->if_bol_bo_property_access~set_property
EXPORTING
iv_attr_name = 'ENDDA'
iv_value = '99991231'.
CALL METHOD lo_bol_filter ->if_bol_bo_property_access~set_property
EXPORTING
iv_attr_name = 'BEGDA'
iv_value = sy-datum.
CALL METHOD lo_bol_filter ->if_bol_bo_property_access~set_property
EXPORTING
iv_attr_name = 'PLAN_TYPE'
iv_value = 'DPLF'.
CALL METHOD lo_bol_filter->if_bol_bo_property_access~set_property
EXPORTING
iv_attr_name = 'BPLAN'
iv_value = 'DPL1'.
CALL METHOD lo_bol_filter->if_bol_bo_property_access~set_property
EXPORTING
iv_attr_name = 'EVENT'
iv_value = 'ANYT'.
*--Reading the Plan Data from BOL with the filter
lo_collection_out = lo_entity ->get_related_entities_by_filter( iv_relation_name = lv_rel_name iv_filter = lo_bol_filter ).
lo_entity ->lock( ).
lo_entity ->reread( ).
IF lo_collection_out IS BOUND.
lo_iterator = lo_collection_out->get_iterator( ).
lo_entity = lo_iterator->get_first( ).
CLEAR lv_string.
WHILE lo_entity IS BOUND. "Looping of Benefit plans
CALL METHOD lo_entity->get_property_as_value
EXPORTING
iv_attr_name = 'BOPTI'
IMPORTING
ev_result = lv_string.
*--We have added a condition here, as per requirement. If only the plan option is either ‘1OPT’ or ‘2OPT’, we need to read the dependent data.
IF lv_string EQ '1OPT' OR lv_string EQ '2OPT'.
*-Reading the health plan dependents data from BOL
lv_rel_name = 'HEALTH_DEP_REL'.
lo_collection_out = lo_entity->get_related_entities(
iv_relation_name = lv_rel_name ).
lo_entity->lock( ).
lo2_iterator = lo_collection_out->get_iterator( ).
lo_entity = lo2_iterator->get_first( ).
WHILE lo_entity IS BOUND. "Looping of dependents record
*-Reading the values of attributes such as BPLAN, DEP_TYPE, etc. This is to read the relevant data from itab LT_DEP_SEL, which contains the *- data to be updated. The code for populating the itab LT_DEP_SEL is not mentioned here. You can use data based on your requirement.
CALL METHOD lo_entity->get_property_as_value
EXPORTING
iv_attr_name = 'BPLAN'
IMPORTING
ev_result = lv_string.
lx_dep_sel-bplan = lv_string.
CLEAR lv_string.
CALL METHOD lo_entity->get_property_as_value
EXPORTING
iv_attr_name = 'DEP_TYPE'
IMPORTING
ev_result = lv_string.
lx_dep_sel-dep_type = lv_string.
CLEAR lv_string.
CALL METHOD lo_entity->get_property_as_value
EXPORTING
iv_attr_name = 'DEP_ID'
IMPORTING
ev_result = lv_string.
lx_dep_sel-dep_id = lv_string.
CLEAR lv_string.
CALL METHOD lo_entity->get_property_as_value
EXPORTING
iv_attr_name = 'PERID'
IMPORTING
ev_result = lv_string.
lx_dep_sel-perid = lv_string.
CLEAR lv_string.
lo_entity ->switch_to_change_mode( ).
IF lo_entity ->is_changeable( ) = abap_true.
IF lo_entity ->alive( ) = abap_true.
lo_access = lo_entity .
*-Reading the dependent details from already populated itab
READ TABLE lt_dep_sel INTO lx_dep_sel_n WITH KEY bplan = lx_dep_sel-bplan
dep_type = lx_dep_sel-dep_type
dep_id = lx_dep_sel-dep_id
perid = lx_dep_sel-perid.
IF sy-subrc EQ 0.
lv_string = lx_dep_sel_n-selected. “This value has to set to the respective BOL attribute.
CLEAR: lx_dep_sel,
lx_dep_sel_n.
ENDIF.
TRY.
*-Updating the BOL data
lo2_access->set_property_as_string(
iv_attr_name = 'SELECTED'
iv_value = lv_string ).
lo_entity ->activate_sending( ).
CATCH cx_crm_cic_parameter_error.
ENDTRY.
ENDIF.
ENDIF.
lo_entity ?= lo2_iterator->get_next( ). "Dependent loop
ENDWHILE.
ENDIF.
lo_entity ?= lo_iterator->get_next( ). "Health Plan loop
ENDWHILE.
ENDIF.
ENDIF.
ENDIF.
ENDIF.
ENDIF.
ENDIF.
Thank you