Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
former_member184611
Active Participant

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_pagecl_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