Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 

Applies to:

SAP CRM 7.0, EHP1 and EHP2

Summary

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

Author Bio

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 .

Custom Table & Structure Creation for BOL Objects

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

GENIL Component Creation & SPRO Settings

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.

Object Table & Model Table Creation

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 Creation

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.

  1. ENDMETHOD.

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.

  1. ENDMETHOD.

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.

  1. ENDMETHOD.

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.

  1. ENDMETHOD.

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.

  1. ENDMETHOD.

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.

Guided Page Activity/ Task type UI component creation

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 ).

  1. ENDMETHOD.

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.

  1. ENDMETHOD.

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.

Testing the working mode of task type ui

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.

11 Comments
Labels in this area