SAP CRM 7.0, EHP1 and EHP2
This particular document illustrates step by step procedure to create guided page activity (Popularly known as Task type UI View in SAP CRM terminology). This document also provides procedure to create the ZBOL and custom GENIL class in order to do data handling and then will be using the same in BSP workbench as guided page activity view.
Author(s): Rajwin Singh Sood
Company: Atos
Created on: 25th Feb 2014
Rajwin Singh Sood is currently working as Team lead/Solution Architect at Atos. He has got experience of about 9 years in SAP ABAP and SAP CRM web UI. He is also a SAP CRM EHP2 Certified associated consultant. Prior to working with Atos he had worked with SAP India(SAP Global Delivery), Capgemini , Accenture and Infosys. He worked in SAP CRM Web Ui in areas like BSP enhancements, transaction launchers, BOL Programming, BRFPlus .
We’ll be using two custom tables in order to illustrate the task type UI the tables snapshots are given below:-
This particular table will be saving the data with respect to the employee personal data where the emp_no will be primary key. Structure for the same is also created the snapshot is given below:-
And the other table which is dependent table is used to save employee information table the snap shot is given below :-
The structure for the BOL is also created and the snap shot is given below:-
You have to make entries in the SPRO for Genil component and component set. While creating a new entry for the Genil component, you need to specify Genil class, description, model table and object table.
Object table will contain the list of BOL objects and their structure types and model table will contain relationship between those BOL objects and cardinality.
CRM->CRM Cross application components->Generic interaction layer->Basic Settings
Create a new entry for your custom Genil component, its description, implementation class, object table and model table.
Create a new component set.
Assign your component to component set.
The object table and model table are the one where the whole business logic of the BOL lies as the GENIL class is always dependent on these to talk to the data base tables. The object table ZEMP_DET_OBJ is created for the same
The entries in the table are for root object which corresponds to the Employee personal table which is the root table and the access object which corresponds to the employee official table which will be used together in the Task type UI.
The model table is used to show the cardinality between the root and access object by this we mean that between the employee personal information and employee official data we have the cardinality defined as 1 to 1. This is just for illustration you can change the cardinality accordingly.
Here cardinality A corresponds to the relationship of object A(employee personal information) where entry C corresponds to 1 and the CARD B corresponds to the relationship of object(employee official information) which means there could either 0 or more than 1 entry.
Genil class is the one which will be containing the business logic to database handling.
Create the class using transaction se 24 change the super class to CL_CRM_GENIL_ABSTR_COMPONENT
Which is the standard SAP class containing all the necessary methods to deal with the data base handling.
The methods which we need to redefine are:-
IF_GENIL_APPL_INTLAY~CREATE_OBJECTS: this method is required to be redefined as this method is always called whenever new record for Employee personal information is created. The code snippet is given below:-
METHOD if_genil_appl_intlay~create_objects.
DATA:
ls_create_root TYPE zemp_pers_data,
lv_err TYPE string,
lt_request_obj TYPE crmt_request_obj_tab,
ls_request_obj LIKE LINE OF lt_request_obj,
lt_bapireturn TYPE bapiret2_tab.
CALL METHOD super->if_genil_appl_intlay~create_objects
EXPORTING
iv_object_name = iv_object_name
iv_number = iv_number
it_parameters = it_parameters
iv_root_list = iv_root_list.
CHECK iv_object_name = 'ZEMP_Details'.
* get create parameters:
CALL METHOD cl_crm_genil_abstr_component=>fill_struct_from_nvp_tab
EXPORTING
it_parameters = it_parameters
CHANGING
cs_parameter = ls_create_root.
****create new employee in the system
CALL METHOD me->create_new_emp
EXPORTING
i_new_emp = ls_create_root
RECEIVING
e_err_during_save = lv_err.
* IF lv_err IS INITIAL AND ls_create_root IS NOT INITIAL.
iv_root_list->add_object( iv_object_name = 'ZEMP_Details' "#EC NOTEXT
is_object_key = ls_create_root-emp_no ).
* ENDIF.
* read the attributes:
me->if_genil_appl_intlay~get_objects(
it_request_objects = lt_request_obj
iv_root_list = iv_root_list ).
ENDMETHOD.
IF_GENIL_APPL_INTLAY~GET_OBJECTS: This particular method picks up the entries from the object table. To understand that same please paste the below code snippet and put a break point on the statement and then run the transaction GEINL_MODEL_BROWSER. The code snippet is given below:-
METHOD if_genil_appl_intlay~get_objects.
CALL METHOD super->if_genil_appl_intlay~get_objects
EXPORTING
it_request_objects = it_request_objects
iv_root_list = iv_root_list.
** Local Objects
DATA: lo_object TYPE REF TO if_genil_container_object,
lo_msg_cont TYPE REF TO cl_crm_genil_global_mess_cont,
lo_attr_props TYPE REF TO if_genil_obj_attr_properties.
DATA: ls_emp_per TYPE zemp_pers_data,
ls_emp_off TYPE zemp_off_data.
DATA: lv_key TYPE zemp_no,
lv_selected_val TYPE zemp_no,
lv_name TYPE crmt_ext_obj_name.
lo_object = iv_root_list->get_first( ).
WHILE lo_object IS BOUND.
lv_name = lo_object->get_name( ).
CASE lv_name.
WHEN 'ZEMP_Details'.
IF lo_object->check_attr_requested( ) = abap_true.
CALL METHOD lo_object->get_key
IMPORTING
es_key = lv_key.
lv_selected_val = lv_key.
SELECT SINGLE * FROM zemp_pers_data INTO CORRESPONDING FIELDS OF ls_emp_per WHERE emp_no = lv_selected_val.
lo_object->set_attributes( ls_emp_per ).
lo_attr_props = lo_object->get_attr_props_obj( ).
lo_attr_props->set_all_properties( if_genil_obj_attr_properties=>changeable ).
ENDIF.
WHEN 'Zemp_off_data'.
IF lo_object->check_attr_requested( ) = abap_true.
CALL METHOD lo_object->get_key
IMPORTING
es_key = lv_key.
lv_selected_val = lv_key.
SELECT SINGLE * FROM zemp_off_data INTO CORRESPONDING FIELDS OF ls_emp_off WHERE emp_no = lv_selected_val.
lo_object->set_attributes( ls_emp_per ).
lo_attr_props = lo_object->get_attr_props_obj( ).
lo_attr_props->set_all_properties( if_genil_obj_attr_properties=>changeable ).
ENDIF.
WHEN OTHERS.
ENDCASE.
lo_object = iv_root_list->get_next( ).
ENDWHILE.
IF_GENIL_APPL_INTLAY~MODIFY_OBJECTS
The modify method is called whenever we make any changes in the employee data. So when ever we tried to create new employee official information at that point of time this method will be called from GENIL. The code snippet is given below:-
METHOD if_genil_appl_intlay~modify_objects.
CALL METHOD super->if_genil_appl_intlay~modify_objects
EXPORTING
iv_root_list = iv_root_list
iv_return_root_list = iv_return_root_list
IMPORTING
et_changed_objects = et_changed_objects.
DATA:
ls_create_root TYPE zemp_pers_data,
lv_err TYPE string,
lt_request_obj TYPE crmt_request_obj_tab,
ls_request_obj LIKE LINE OF lt_request_obj,
lt_bapireturn TYPE bapiret2_tab.
DATA:
lr_root_object TYPE REF TO if_genil_cont_root_object,
lt_changed_objects TYPE crmt_genil_obj_instance_tab,
ls_changed_object TYPE crmt_genil_obj_instance,
ls_emp_off TYPE zemp_off_data,
lr_emp_offical_det TYPE REF TO if_genil_container_objectlist,
lr_emp_object TYPE REF TO if_genil_container_object,
lv_err_msg TYPE string,
lv_objname TYPE crmt_ext_obj_name.
CLEAR:
et_changed_objects.
* start the modify process
lr_root_object = iv_root_list->get_first( ).
*read the employee personal data from which we'll retrieve the employee offcial data and then update it accordingly.
WHILE lr_root_object IS BOUND.
* get the name of the root object:
lv_objname = lr_root_object->get_name( ).
CASE lv_objname.
WHEN 'ZEMP_Details'.
****update the root object before checking out the children of the root node
CALL METHOD lr_root_object->if_genil_cont_simple_object~get_attributes
IMPORTING
es_attributes = ls_create_root.
***create new employee in the system
CALL METHOD me->create_new_emp
EXPORTING
i_new_emp = ls_create_root
RECEIVING
e_err_during_save = lv_err.
IF lv_err IS INITIAL.
ls_changed_object-object_name = 'ZEMP_Details'.
ls_changed_object-object_id = ls_create_root-emp_no.
APPEND ls_changed_object TO et_changed_objects.
ENDIF.
****get the children of the root node which is nothing but the data containing employee
CALL METHOD lr_root_object->if_genil_container_object~get_children
EXPORTING
iv_as_copy = abap_false
RECEIVING
rv_result = lr_emp_offical_det.
WHEN OTHERS.
ENDCASE.
lr_root_object = iv_root_list->get_next( ).
ENDWHILE.
****after getting the children modify the offical data of employee by calling the modify method
IF lr_emp_offical_det IS BOUND.
lr_emp_object = lr_emp_offical_det->get_first( ).
IF lr_emp_object IS BOUND.
CALL METHOD lr_emp_object->if_genil_cont_simple_object~get_attributes
IMPORTING
es_attributes = ls_emp_off.
IF ls_emp_off IS NOT INITIAL.
CALL METHOD me->modify_emp_off_data
EXPORTING
i_off_data = ls_emp_off
RECEIVING
e_err_during_save = lv_err_msg.
IF lv_err_msg IS INITIAL.
ls_changed_object-object_name = 'Zemp_off_data'.
ls_changed_object-object_id = ls_emp_off-emp_no.
APPEND ls_changed_object TO et_changed_objects.
ENDIF.
ENDIF.
ENDIF.
ENDIF.
IF_GENIL_APPL_MODEL~GET_MODEL
This particular method will picking up the cardinalities between the objects from the model table which we had created in previous section.
ETHOD if_genil_appl_model~get_model.
CALL METHOD super->if_genil_appl_model~get_model
RECEIVING
rt_relation_det = rt_relation_det.
DATA:
ls_relation_detail TYPE crmt_relation_detail.
DATA: lt_emp_rel TYPE STANDARD TABLE OF zemp_det_mod,
ls_emp_rel TYPE zemp_det_mod.
SELECT * FROM zemp_det_mod INTO TABLE lt_emp_rel.
IF sy-subrc IS INITIAL.
LOOP AT lt_emp_rel INTO ls_emp_rel.
MOVE-CORRESPONDING ls_emp_rel TO ls_relation_detail.
APPEND ls_relation_detail TO rt_relation_det.
ENDLOOP.
ENDIF.
IF_GENIL_APPL_MODEL~GET_OBJECT_PROPS
this particular method is used pick up the object properties like the key fields of the table, the fields which should appear on screen while creating new entries and so on.
METHOD if_genil_appl_model~get_object_props.
CALL METHOD super->if_genil_appl_model~get_object_props
RECEIVING
rt_obj_props = rt_obj_props.
DATA: ls_obj_properties TYPE crmt_obj_properties,
lt_emp TYPE STANDARD TABLE OF zemp_det_obj,
ls_emp TYPE zemp_det_obj.
SELECT * FROM zemp_det_obj INTO TABLE lt_emp.
IF sy-subrc IS INITIAL.
LOOP AT lt_emp INTO ls_emp.
ls_obj_properties-object_name = ls_emp-object_ext.
ls_obj_properties-attr_struct = ls_emp-attr_structure.
ls_obj_properties-create_struct = ls_emp-attr_structure.
ls_obj_properties-key_struct = 'CRMT_PRIL_OBJEXT'.
MOVE-CORRESPONDING ls_emp TO ls_obj_properties.
APPEND ls_obj_properties TO rt_obj_props.
ENDLOOP.
ENDIF.
CREATE_NEW_EMP
This particular method is used to update data with respect to employee personal information and will be called while creating the data in GENIL class:-
METHOD create_new_emp.
IF i_new_emp IS NOT INITIAL.
i_new_emp-mandt = sy-mandt.
CALL FUNCTION 'ENQUEUE_EZEMP_DEMO_LOCK'
EXPORTING
mandt = sy-mandt
emp_no = i_new_emp-emp_no
* X_EMP_NO = ' '
EXCEPTIONS
foreign_lock = 1
system_failure = 2
OTHERS = 3.
IF sy-subrc <> 0.
* Implement suitable error handling here
CONCATENATE : 'Employee data with employee number '
i_new_emp-emp_no
' already locked' INTO e_err_during_save SEPARATED BY space.
ELSE.
MODIFY zemp_pers_data FROM i_new_emp.
IF sy-subrc IS NOT INITIAL.
CONCATENATE : 'Data for employee '
i_new_emp-emp_name
'cant be saved due to system issue' INTO e_err_during_save SEPARATED BY space.
ELSE.
CALL FUNCTION 'DEQUEUE_EZEMP_DEMO_LOCK'
EXPORTING
mandt = sy-mandt
emp_no = i_new_emp-emp_no
* X_EMP_NO = ' '
.
ENDIF.
ENDIF.
ENDIF.
MODIFY_EMP_OFF_DATA
This particular method is used whenever we are trying to create/update the employee official data.
METHOD modify_emp_off_data.
IF i_off_data IS NOT INITIAL.
i_off_data-mandt = sy-mandt.
CALL FUNCTION 'ENQUEUE_EZEMP_OFF_LOCK'
EXPORTING
mandt = sy-mandt
emp_no = i_off_data-emp_no
* X_EMP_NO = ' '
EXCEPTIONS
foreign_lock = 1
system_failure = 2
OTHERS = 3.
IF sy-subrc <> 0.
* Implement suitable error handling here
CONCATENATE : 'Employee data with employee number '
i_off_data-emp_no
' already locked' INTO e_err_during_save SEPARATED BY space.
ELSE.
MODIFY zemp_off_data FROM i_off_data.
IF sy-subrc IS NOT INITIAL.
CONCATENATE : 'Data for employee number '
i_off_data-emp_no
'cant be saved due to system issue' INTO e_err_during_save SEPARATED BY space.
ELSE.
CALL FUNCTION 'DEQUEUE_EZEMP_OFF_LOCK'
EXPORTING
mandt = sy-mandt
emp_no = i_off_data-emp_no
* X_EMP_NO = ' '
.
ENDIF.
ENDIF.
ENDIF.
ENDMETHOD.
Now we need to create a BSP component using workbench transaction BSP_WD_CMPWB.
After the component is create go to run time repository editor and in that click one edit (pencil Icon) and right mouse click the model to add the model which is the component set which we create in SPRO ZEMP_DEMO
After this we need to create the views which we need in the TASKTYPE UI the views created are EmployeeOffDetail and EmployeePerDetails with the BOL models as Zemp_off_data and ZEmp_details.
In the view employee per Detail we need to make changes in do_init_context so that when ever the taskui start it should have the screen with employee personal information in editable mode for the user to enter data
METHOD do_init_context.
CALL METHOD super->do_init_context
.
DATA: lo_core TYPE REF TO cl_crm_bol_core,
lo_order TYPE REF TO cl_crm_bol_entity,
lo_temp TYPE REF TO if_bol_bo_property_access,
lt_params TYPE crmt_name_value_pair_tab,
ls_params TYPE crmt_name_value_pair,
lo_factory TYPE REF TO cl_crm_bol_entity_factory.
CLEAR: ls_params, lt_params, lo_order.
FREE: lo_core,
lo_order.
lo_core = cl_crm_bol_core=>get_instance( ).
lo_factory = lo_core->get_entity_factory( 'ZEMP_Details' ).
ls_params-name = 'EMP_NO'. "#EC NOTEXT
ls_params-value = ' '.
APPEND ls_params TO lt_params.
ls_params-name = 'EMP_NAME'. "#EC NOTEXT
ls_params-value = ' '.
APPEND ls_params TO lt_params.
ls_params-name = 'EMP_LNAME'. "#EC NOTEXT
ls_params-value = ' '.
APPEND ls_params TO lt_params.
lo_order = lo_factory->create( lt_params ).
lo_temp ?= lo_order.
me->typed_context->empper->collection_wrapper->add(
iv_entity = lo_temp
iv_set_focus = abap_true ).
Now we create the task type UI
In the configuration of the taskUi view add the views which you need in steps as in step1 screen for employee personal information will appear and then second one will be employee official data
We need to handle the event next so whenever the next button is clicked we need to create the blank screen for employee official information.
For that first we need to redefine the handle event method in the controller class of the task ui view
IF_BSP_CONTROLLER~HANDLE_EVENT
ETHOD if_bsp_controller~handle_event.
CALL METHOD super->if_bsp_controller~handle_event
EXPORTING
event = event
htmlb_event = htmlb_event
htmlb_event_ex = htmlb_event_ex
global_messages = global_messages
RECEIVING
global_event = global_event.
IF event EQ 'frwdbutton'.
eh_onnextroadmapitem( ).
ENDIF.
EH_ONNEXTROADMAPITEM
METHOD eh_onnextroadmapitem.
DATA: lr_emp_per TYPE REF TO cl_crm_bol_entity,
lr_cuco TYPE REF TO zl_zemp_dat_bspwdcomponen_impl,
ls_emp_per_details TYPE zemp_pers_data,
ls_emp_off_details TYPE zemp_off_data,
lr_emp_off TYPE REF TO cl_crm_bol_entity.
lr_cuco ?= me->comp_controller.
CHECK lr_cuco IS BOUND.
lr_emp_per ?= lr_cuco->typed_context->empper->collection_wrapper->get_current( ).
lr_emp_off ?= lr_cuco->typed_context->offdetail->collection_wrapper->get_current( ).
IF lr_emp_per IS BOUND.
CALL METHOD lr_emp_per->if_bol_bo_property_access~get_properties
IMPORTING
es_attributes = ls_emp_per_details.
ENDIF.
IF ls_emp_per_details IS NOT INITIAL AND lr_emp_off IS NOT BOUND.
lr_emp_off = lr_emp_per->create_related_entity( iv_relation_name = 'employee_relation' ).
IF lr_emp_off IS BOUND.
lr_emp_off->switch_to_change_mode( ).
ls_emp_off_details-emp_no = ls_emp_per_details-emp_no.
CALL METHOD lr_emp_off->if_bol_bo_property_access~set_properties
EXPORTING
is_attributes = ls_emp_off_details.
lr_cuco->typed_context->offdetail->collection_wrapper->add( lr_emp_off ).
ENDIF.
ENDIF.
ENDMETHOD.
After completing the coding to test the application just click on the test button
After which you come to screen
Enter the new data to be entered
And click on next button
Enter the bank details and click on finish button
Now check the data base tables to see whether the data has flowed in
When you click on execute
So employee has been created now pick up the emp_no and check it in employee official information table
the above was just an illustration or simple example as to how we can use guided page activity, it could be used for more complex scenarios where in we would have cases involving steps to save data for multiple database tables.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
37 | |
10 | |
5 | |
4 | |
4 | |
3 | |
3 | |
3 | |
2 | |
2 |