Olaf Pohlmann
Read all my blogsWhen working with a CRM 7.0 system, especially when enhancing it, you very soon get to know some aspects of the framework behind its WebClient. The following picture gives an overview of the different layers.
For instance, if you want to change a screen configuration you need tools that are offered by the Presentation Layer. This layer is responsible for presenting the CRM data to the user and handling user interactions. The necessary data is not directly read from tables but instead are offered in a object oriented way by the layer below, the Business Layer.
The Business Layer presents the CRM data and logic in a nice uniform way by encapsulating data in Business Objects. These objects have attributes and may have, and this is a very powerful aspect, relations with other objects. The actual data is accessed through what is called the Generic Interaction Layer, or GenIL. This, CRM specific, layer is formed by ABAP classes that access the data by calling Application Programming Interfaces and provide it to the Business Object Layer.
In this blog I want to zoom in on the Business Layer and show a little bit of how it can be accessed from ABAP code, how the GenIL is implemented for a Business Partner and then…
…switch to the other side of the Business Object Layer and, instead of being a consumer of Business Objects, show how to enhance existing objects with new additional fields and relations and how to create completely new Business Objects.
Tools within the Business Object Layer
- the Model Browser, a design environment to view the properties of the available Business Objects. It can be started with transaction GENIL_MODEL_BROWSER.
- the BOL Browser, a test environment for accessing Business Objects with real data. Transaction GENIL_BOL_BROWSER.
When starting either one of these tools you first have to select a component or a component set (which is a collection of components). Commonly used components are BP for the Business Partner objects and BT for the Business Transactions. An easy way to discover which component set is used behind a certain screen is by pressing F2 on a field on the screen to get the UI Component, then go to the UI Component Workbench by starting transaction BSP_WD_CMPWB and have a look at the models node in the Runtime Repository display. The displayed value represents the component set that is used within this UI component:
Business Object Layer APIs
The BOL comes with several APIs that you can use from ABAP code. Some examples of how to get a Business Object (also called entity) from the BOL:
“Based on the internal key
lr_entity = cl_crm_bol_core=>get_instance( )->get_root_entity(
iv_object_name = ‘BTOrder’
iv_object_guid = ‘BC305BEC6E911EE284C07BCD24DED4E3’ ).
“Utility class
lr_entity = cl_crm_uiu_bp_tools=>get_builheader_entity( ‘200362166’ ).
“Query
lr_query = cl_crm_bol_query_service=>get_instance( ‘BuilHeaderSearchNew’ ).
lr_query->set_property( iv_attr_name = ‘MC_NAME1’ iv_value = ‘media store’ ).
lr_entity = lr_query->get_query_result( )->get_first( ).
Other examples of how to perform to CRUD (Create, Read, Update and Delete) operations:
“Create a new private account
ls_param-name = ‘LASTNAME’.
ls_param-value = ‘Demo’.
append ls_param to lt_params.
“Similar for BP_CATEGORY, PARTNERLANGUAGE and CORRESPONDLANGUAGE
lr_person = cl_crm_bol_core=>get_instance( )
->get_entity_factory( ‘BuilHeader’ )->create( lt_params ).
“Create a new relation with a phone object
lr_phone = lr_person->create_related_entity( ‘BuilIndependantPhoneRel’ ).
“Read the e-mail attributes
lr_address = lr_builheader->get_related_entity( ‘BuilStandardAddressRel’ ).
if lr_address is bound.
lr_email = lr_address->get_related_entity( ‘BuilStandardAddressEmailRel’ ).
if lr_email is bound.
lv_email = lr_email->get_property_as_string( ‘E_MAIL’ ).
endif.
endif.
Method GET_PROPERTY_AS_STRING provides a formatted value:
BP number: 200362202 / Date: 09.12.2012
Method GET_PROPERTY_AS_VALUE returns the real internal type without conversion:
BP number: 0200362202 / Date: 20120912
“Attributes can also be read in a compact manner using BPath
lv_email_ref ?= lr_builheader->get_properties_by_bpath(
`BuilStandardAddressRel/BuilStandardAddressEmailRel/@E_MAIL` ).
“Update a telephone number
lr_phone->set_property(
iv_attr_name = ‘TELEPHONE’
iv_value = ‘010720527’ ).
“A modify is required to process and validate the new values
cl_crm_bol_core=>get_instance( )->modify( ).
The Generic Interaction Layer (GenIL)
- CRMV_OBJ_IBIL for Business Transacties
- CRMV_OBJ_BUIL for Business Partner
Business Engine
Customer enhancements
Examples of enhancements in the Business Layer are:
- Add additional search fields to existing queries
- Adding new relations to existing Business Objects
- Creating new Business Objects
Enhancing existing Business Objects
Let’s say you have a system in which a lot of Installed Bases (IBases) are linked to accounts and when searching for accounts you want to add the possibility to search for the external ID of an IBase as well. The first step is to find the query object that is used in the view you normally use to search for accounts. Again the F2-functionality on the screen gives you all the information to start with: the UI component, the view and the context node. Once you have found the context node in the UI Component Workbench, it will tell you the query object that it is linked to:
The next step is figuring out the implementation details of this query. The GenIL customizing for the BP-component (transaction SM30, view CRMV_OBJ_BUIL) reveals the details:
Now we can create our enhanced versions:
- Structure ZCRMT_BUPA_IL_HEADER_SEARCH in which we first include the original structure and add a field ZEXTID for the external ID as well
- Class ZCL_BUPA_IL_HEADER_SEARCH as a subclass of the original one with a redefinition of method GET_DYNAMIC_QUERY_RESULT. Place an external breakpoint in this method for testing purposes later on.
We are now ready to perform the first test of the enhanced query. Start the BOL browser for the BP-component, navigate to the BuilHeaderAdvancedQuery and double click it. In the section for Dynamic Query Parameters see if you can select field ZEXTID. Provide some values and press the Find-button. If everything goes well the system now stops at the breakpoint in our enhanced version. Parameter table IT_SELECTION_PARAMETERS contains the selection criteria. You now have a starting point for implementing additional logic. This logic could look something like this:
method if_crm_bupa_il_query~get_dynamic_query_result.
data:
lt_params type genilt_selection_parameter_tab,
ls_param type genilt_selection_parameter.
lt_params = it_selection_parameters.
“Search on IBase?
read table lt_params transporting no fields with key attr_name = ‘ZEXTID’.
if sy-subrc = 0.
“Execute an IBase query e.g. using IBIBaseToIBaseAdv in component IBASE
“…
“Retrieve the linked accounts and add the found account numbers to LT_PARAMS
ls_param-attr_name = ‘PARTNER’.
ls_param-sign = ‘I’.
ls_param-option = ‘EQ’.
ls_param-low = ‘<BP number>’.
append ls_param to lt_params.
clear ls_param.
“Remove the IBase specific search parameters
delete lt_params where attr_name = ‘ZEXTID’.
endif.
“Search using the standard advanced query
super->if_crm_bupa_il_query~get_dynamic_query_result(
iv_query_name = iv_query_name
is_query_parameters = is_query_parameters
it_selection_parameters = lt_params
iv_root_list = iv_root_list
iv_root_object = iv_root_object ).
endmethod.
If the test went successful, the new field can be added to the screen configuration of view MainSearch in UI component BP_HEAD_SEARCH and by doing so it is made available to the WebClient:
And that’s it! The enhancement which was made in the Business Layer can now be used both in the developer tools within the Business Layer as well as in the screen configuration in the Presentation Layer and is made available in the WebClient.
Adding new relations to existing Business Objects
The way to define this new relation is by going to the GenIL customizing in the IMG and enter the following:
method read.
data:
lr_relation_details type ref to if_genil_container_object,
ls_record type ts_record,
lr_relation type ref to if_genil_container_object,
ls_relation_key type crmt_bupa_il_relation_key.
“Cast the supplied object to a GenIL container object
lr_relation_details ?= iv_ref.
“Attributes requested?
check lr_relation_details->check_attr_requested( ) = abap_true.
“Determine the key
lr_relation_details->get_key( importing es_key = ls_record-key ).
if ls_record-key is initial.
“Get the key of the parent object BuilRelationship
lr_relation = lr_relation_details->get_parent( ).
lr_relation->get_key( importing es_key = ls_relation_key ).
move-corresponding ls_relation_key to ls_record-key.
endif.
“Try to read any relation details
select pavip
parem
into ls_record-attr
from but051 up to 1 rows
where partner1 = ls_relation_key-partner1
and partner2 = ls_relation_key-partner2
and date_to = ls_relation_key-validuntildate
and reltyp = ls_relation_key-relationshipcategory.
endselect.
check sy-subrc = 0.
“Initialize the new object
lr_relation_details->copy_self_with_structure( is_object_key = ls_record-key ).
lr_relation_details->set_attributes( ls_record-attr ).
endmethod.
Creating completely new Business Objects
ls_obj_props-object_name = ‘DemoObject’.
ls_obj_props-object_kind = if_genil_obj_model=>root_object.
ls_obj_props-key_struct = ‘ZDEMO_OBJ_KEY’.
ls_obj_props-attr_struct = ‘ZDEMO_OBJ’.
append ls_obj_props to rt_obj_props.
clear ls_obj_props.
“Query object
ls_obj_props-object_name = ‘DemoObjectSearch’.
ls_obj_props-object_kind = if_genil_obj_model=>query_object.
ls_obj_props-attr_struct = ‘ZDEMO_OBJ_SEARCH’.
ls_obj_props-result_obj_name = ‘DemoObject’.
append ls_obj_props to rt_obj_props.
clear ls_obj_props.
Final thought
4 responses to “The other side of the Business Object Layer (BOL)”
Olaf, I'm impressed with this explanation. This is a really great job and a great blog.
Many thanks.
Very useful and in simple way. Thanks a ton.
Chandra
This flow is explained in a simple and most effective way….thanks a lot.good job
Thanks sir