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: 
Former Member
0 Kudos

This document shows how to create custom 1...n entities in sap crm via bol browser, which can be linked to any other crm objects by
keeping the guid of that object in our simple object.There are multiple simple object genil classes provided by sap which provided the basic CRUD operations by default, we don't have to modify these genil classes for create/read/update/delete (CRUD) operations. In this e.g we had a requirement to create ZFORECAST as a table view which will be embebded in Sales opportunity page as a new assignment block.This table will store multiple Forecast data aginast opportunity header guid.


To start with...

  1. Created new table :

  2. Create a lock object " EZFORECAST" for our table ZFOREACT. (Lock mode E)

3. Define the customizing entry for simple objects  in :

"spro->crm->cross appl. comp->genil->comp. spe. Setting->define SO"

4 . Create a SO entry in the object definition.

Object Name  - 'ZFORECAST'

Implementation
Class  - 'CL_CRM_GENIL_GEN_TABLE_OBJ'

Att str --  ' ZFORECAST'  "Define attribute
structure of your SO, usually it would be similar to the DB table which will
store data"

Structure of mand.Field at create: ' ZFORECAST' -

Key Struc. - GUID (key structure would be "GUID" only as the genil class CL_CRM_GENIL_GEN_TABLE_OBJ

Create  entry in the search object definition under
simple object...Search Object name -- 'ZFORECAST_SRC'

Structure
name - '
ZFORECAST' 

4.1 .  Add the SO2 object to our ONEORDER Component

5. Create a mapping entry for our "Simple object - ' ZFORECAST', table name - 'ZFORECAST'  and lock object - ' EZFORECAST " in the table "CRMC_TBLOBJ_MAP"

6 . Execute Genil_bol_browser


Create new root object... select 'ZFORECAST_SRC'-->'ZFORECAST'


Check the new entries in Table 'ZFORECAST':



So up till now we created the SO object for ZFORECAST table which is now
part of BOL in SO2 component and in the below steps now in below steps we will create
Table View In Web UI


7. Let's start with creating new view "ZFOREC" under "BT111H_OPPT" bsp component in BSP Workbench.

Specify Context node name "ZFOREC" and Bol entity as the simple object created from the previous "ZFORECAST". Click
next till last step, in the last screen select view type as "Table view", tick the Configurable and Change/Display check boxes


After adding ZFOREC node also add BTADMINH which will be needed further to read the opportunity header Guid

8. Declare these Button attributes in the attribute section of the ZFOREC view's implementation class.


9. Modify the code of " ZFOREC.htm" BSP page code with the below code.

<%@page language="abap" %>
<%@extension name="htmlb" prefix="htmlb" %>
<%@extension name="xhtmlb" prefix="xhtmlb" %>
<%@extension name="crm_bsp_ic" prefix="crmic" %>
<%@extension name="bsp" prefix="bsp" %>
<%@extension name="chtmlb" prefix="chtmlb" %>
<%@extension name="thtmlb" prefix="thtmlb" %>

<%
data lv_xml type string.

lv_xml =  controller->configuration_descr->get_config_data( ).
%>

<thtmlb:areaFrameSetter toolbarButtons =
"<%= controller->tb_button %>"

                        maxButtonNumber =
"2"

                        displayMode  =
"<%= controller->view_group_context->is_view_in_display_mode( controller ) %>"/>

<chtmlb:tableExtension tableId =
"Table1"

                        layout  =
"FIXED" >

<chtmlb:configTable
xml              = "<%= lv_xml %>"

                   
id                    = "Table1"

                    navigationMode        =
"BYPAGE"

                    onRowSelection        =
"select"

                   
table                = "//ZFOREC/Table"

                   
width                = "100%"

                    displayMode          =
"<%= controller->view_group_context->is_view_in_display_mode( controller ) %>"

                    headerVisible        =
"FALSE"

                    hasLeadSelection      =
"TRUE"

                    usage                =
"ASSIGNMENTBLOCK"

                    personalizable        =
"FALSE"

                    actions              =
"<%= controller->gt_button %>"

                    allRowsEditable      =
"TRUE"

                    actionsMaxInRow      =
"3"

                    downloadToExcel      =
"TRUE"

                    selectedRowIndex      =
"<%= ZFOREC->SELECTED_INDEX %>"

                    selectedRowIndexTable =
"<%= ZFOREC->SELECTION_TAB %>"

                    selectionMode        =
"<%= ZFOREC->SELECTION_MODE %>"

                    visibleFirstRow      =
"<%= ZFOREC->VISIBLE_FIRST_ROW_INDEX %>"

                    visibleRowCount      =
"6"

                    />



</chtmlb:tableExtension>


10.Click on Configuration tab of  "ZFOREC" view move required field to be shown on the right side under displayed field.



11. Define three buttons Create, Delete, Edit List in do_prepare_output method of the implementation class.


DATA:  ls_button    TYPE crmt_thtmlb_button.

 
DATA : lr_entity    TYPE REF TO cl_crm_bol_entity,

        lv_locked   
TYPE char1,

        lv_enabled 
TYPE crmt_boolean VALUE abap_true,

        lr_coll     
TYPE REF TO if_bol_bo_col,

        lv_coll_size
TYPE sytabix,

        lv_display 
TYPE boolean.


*me->view_group_context->set_view_editable( me ).



  lv_display = me->view_group_context->is_view_in_display_mode( me ).
*lv_display = me->view_group_context->set_view_editable.



 
IF lv_display EQ abap_true.

    typed_context->zforec->set_selection_mode( iv_selection_mode = cl_bsp_wd_context_node_tv=>selmode_none ).

 
ELSE.

    typed_context->zforec->set_selection_mode( iv_selection_mode = cl_bsp_wd_context_node_tv=>selmode_lineedit ).

 
ENDIF.



 
CALL METHOD super->do_prepare_output.



  lr_coll =  me->typed_context->zforec->collection_wrapper->get_marked( ).

 
IF lr_coll IS BOUND.

    lv_coll_size = lr_coll->size( ).

   
IF lv_coll_size = 0.

      lv_enabled = abap_false.

   
ELSE.

      lv_enabled = abap_true.

   
ENDIF.

 
ENDIF.
************************



 
CLEAR : tb_button, ls_button.

  ls_button-
text    = 'Edit List'.

  ls_button-on_click =
'EDIT'.                              "#EC NOTEXT

  ls_button-enabled  = me->view_group_context->is_view_in_display_mode( me ).

 
APPEND ls_button TO tb_button.



 
CLEAR gt_button.

  ls_button-
text    = 'Insert'.

  ls_button-on_click =
'CREATE'.                            "#EC NOTEXT

  ls_button-enabled  = abap_true.

 
APPEND ls_button TO gt_button.

 
CLEAR ls_button.



  ls_button-
type    = cl_thtmlb_util=>gc_icon_delete.

  ls_button-on_click =
'DELETE'.                            "#EC NOTEXT

  ls_button-enabled  = abap_true.     
"lv_enabled.

 
APPEND ls_button TO gt_button.

 
CLEAR ls_button.


12.Create three event's "CREATE","DELETE","EDIT" in "ZFOREC" view via wizard & add the required logic in each event method as per below.

method EH_ONCREATE.

   
DATA :  lr_entity TYPE REF TO cl_crm_bol_entity,

          lv_collection
TYPE REF TO if_bol_bo_col,

          lr_comp
TYPE REF TO cl_bt111h_o_bspwdcomponen_impl.
*          cl_bt111h_o_bspwdcompone0_impl.



 
DATA : lr_core    TYPE REF TO cl_crm_bol_core,

        lr_fac     
TYPE REF TO cl_crm_bol_entity_factory,

        lt_params 
TYPE        crmt_name_value_pair_tab,

        ls_params 
TYPE        crmt_name_value_pair,

        lr_ent     
TYPE REF TO cl_crm_bol_entity,

        lv_objid
TYPE crmd_orderadm_h-object_id,

        lv_quot_id
TYPE crmd_orderadm_h-object_id,

        lv_pred_guid 
TYPE        crmt_object_guid,

        lv_cmp_guid 
TYPE        crmt_object_guid,

        ls_borident 
TYPE borident,

        it_neighbor_objects
TYPE TABLE OF relroles,

        is_neighbor_objects
TYPE relroles,

        lt_zforecast
TYPE TABLE OF zforecast,

        lv_new_month
TYPE zforecast-z_month,

        lv_cur_zvalue
TYPE zforecast-z_value,

        lv_new_zvalue
TYPE zforecast-z_value,

        lr_coco
TYPE REF TO zl_bt111h_o_bspwdcomponen_impl,

        lr_entity_so 
TYPE REF TO cl_crm_bol_entity,

        lr_entity_cur 
TYPE REF TO cl_crm_bol_entity,

        ls_zforecast
TYPE zforecast.



  lr_comp ?= me->comp_controller.

 
CHECK lr_comp IS BOUND.

  lr_entity ?= lr_comp->typed_context->btadminh->collection_wrapper->get_current( ).
*"Reading the btadminh entity, which is bound to component controller's
*  btadminh context node.

  me->typed_context->zforec->deselect_all( ).
*    me->typed_context->ZFOREC->select_all( ).



 
IF lr_entity->is_changeable( ) = abap_true.

    lr_core = cl_crm_bol_core=>get_instance( ).

    lr_fac = lr_core->get_entity_factory(
'ZFORECAST' ).

    lt_params = lr_fac->get_parameter_table( ).

   
TRY.

        lr_ent = lr_fac->create( lt_params ).

       
IF lr_ent IS BOUND.

         
CHECK lr_ent->lock( ) = abap_true.
*****************

         
CLEAR:lv_cmp_guid,lv_objid,

                lv_pred_guid,lv_quot_id.
* Read the parent entity BTADMINH guid
* " Copy BtAdminh Guid to Forecast table Opportunity Guid

          lr_entity->get_property_as_value(
EXPORTING iv_attr_name = 'GUID'

                                           
IMPORTING ev_result = lv_cmp_guid ).

          lr_ent->set_property( iv_attr_name =
'Z_HD_OPPT_GUID'

                                iv_value = lv_cmp_guid ).


** Objectid/ Doc no is genearted only after save , so may be blank while in create mode.

          lr_entity->get_property_as_value(
EXPORTING iv_attr_name = 'OBJECT_ID'

                                           
IMPORTING ev_result = lv_objid ).

          lr_ent->set_property( iv_attr_name =
'Z_HDR_OPPT_NO'

                                iv_value = lv_objid ).


******************  Default the values for quot  no *******************************
*PREDECESSOR_GUID Quot Guid when create follow up doc is selected

          lr_entity->get_property_as_value(
EXPORTING iv_attr_name = 'PREDECESSOR_GUID'

                                           
IMPORTING ev_result = lv_pred_guid ).

          lr_ent->set_property( iv_attr_name =
'Z_HDR_QUOT_GUID'

                                iv_value = lv_pred_guid ).


** SOMETIMES PREDECESSOR_GUID is empty then get it from transaction history

         
IF lv_pred_guid IS INITIAL.

            ls_borident-objkey  = lv_cmp_guid.

            ls_borident-objtype =
'BUS2000111'.

            ls_borident-logsys  =
''.



           
CALL FUNCTION 'Z_DISPLAY_LIST_OF_RELATIONS'

             
EXPORTING

                object              = ls_borident

                max_hops            =
'99'

             
TABLES

                it_neighbor_objects = it_neighbor_objects

             
EXCEPTIONS

                no_logsys          =
1

                internal_error      =
2

               
OTHERS              = 3.

           
IF sy-subrc = 0.
* MESSAGE ID SY-MSGID TYPE SY-MSGTY NUMBER SY-MSGNO
*        WITH SY-MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.

             
LOOP AT it_neighbor_objects INTO is_neighbor_objects

               
WHERE roletype = 'VORGAENGER' "Preceding doc

               
AND objtype = 'BUS2000115'"quotes

                lv_pred_guid = is_neighbor_objects-objkey.

             
ENDLOOP.

           
ENDIF.



         
ENDIF.
*Get PREDECESSOR Quot no when create follow up doc is selected

         
IF lv_pred_guid IS NOT INITIAL.

           
SELECT SINGLE object_id INTO lv_quot_id

             
FROM crmd_orderadm_h WHERE guid = lv_pred_guid.
*          lr_entity->get_property_as_value( EXPORTING iv_attr_name = 'PREDECESSOR_GUID'
*                                            IMPORTING ev_result = lv_pred_guid ).

            lr_ent->set_property( iv_attr_name =
'Z_HDR_QUOT_NO'

                                  iv_value = lv_quot_id ).

         
ENDIF.
*****************************************************************************
*Read the last record from collection wrapper

          lr_coco ?= me->comp_controller.

         
IF lr_coco IS BOUND.

           
CLEAR: lv_new_month,lv_new_zvalue.
* Get the Last entity

            lr_entity_so ?= lr_coco->ztyped_context->zforecast->collection_wrapper->get_last( ).



           
IF lr_entity_so IS BOUND.
**Get prev month

              lr_entity_so->get_property_as_value(
EXPORTING iv_attr_name = 'Z_MONTH'

                                               
IMPORTING ev_result = lv_new_month ).
*** Add 1 month for new entry

             
IF lv_new_month+4(2) = '12'"if december that add new yr

                lv_new_month+
0(4) = lv_new_month+0(4) + 1 .

                lv_new_month+
4(2) = '1'.

                lv_new_month = lv_new_month.

             
ELSE.

                lv_new_month = lv_new_month +
1" add 1 month

             
ENDIF.



              lr_ent->set_property( iv_attr_name =
'Z_MONTH'

                                                iv_value =  lv_new_month ).
**********
**** Get the current zvalue
*              lr_entity_cur ?= lr_coco->ztyped_context->zforecast->collection_wrapper->get_current( ).
*              IF lr_entity_cur IS BOUND.
*                lr_entity_cur->get_property_as_value( EXPORTING iv_attr_name = 'Z_VALUE'
*                                                IMPORTING ev_result = lv_cur_zvalue ).
*              ENDIF.
***

              lr_entity_so->get_property_as_value(
EXPORTING iv_attr_name = 'Z_VALUE'

                                               
IMPORTING ev_result = lv_new_zvalue ).
**new value =  curr qty  * ????
*              lr_ent->set_property( iv_attr_name = 'Z_VALUE'
*                                                iv_value =  lv_new_zvalue ).



              lr_entity_so->get_property_as_value(
EXPORTING iv_attr_name = 'Z_CUR_QTY'

                                               
IMPORTING ev_result = ls_zforecast-z_cur_qty ).

              lr_ent->set_property( iv_attr_name =
'Z_PREV_QTY'

                                            iv_value =  ls_zforecast-z_cur_qty ).



              lr_entity_so ?= lr_coco->ztyped_context->zforecast->collection_wrapper->get_next( ).



           
ENDIF.

         
ENDIF.
*****************************





          me->typed_context->zforec->collection_wrapper->add( iv_entity = lr_ent ).

          me->typed_context->zforec->visible_first_row_index = me->typed_context->zforec->collection_wrapper->size( ).

       
ENDIF.

     
CATCH cx_crm_genil_model_error.

       
EXIT.

     
CATCH cx_sy_ref_is_initial.

   
ENDTRY.

 
ENDIF.


endmethod.




method EH_ONDELETE.

 
DATA :    lr_entity TYPE REF TO cl_crm_bol_entity,

          lr_current
TYPE REF TO if_bol_bo_property_access,

          lr_col
TYPE REF TO if_bol_bo_col,

          lr_core
TYPE REF TO cl_crm_bol_core,

          lv_size
TYPE i.



  lr_col ?= typed_context->ZFOREC->collection_wrapper->get_marked( ).

  lv_size = lr_col->size( ).

 
IF lv_size > 0.

   
DO lv_size TIMES.

     
IF sy-index = 1.

        lr_current = lr_col->get_first( ).

     
ELSE.

        lr_current = lr_col->get_next( ).

     
ENDIF.

      lr_entity ?= lr_current.

      typed_context->ZFOREC->collection_wrapper->remove( lr_current ).

      lr_entity->delete( ).

   
ENDDO.

    lr_core = cl_crm_bol_core=>get_instance( ).

    lr_core->modify( ).

    typed_context->ZFOREC->deselect_all( ).



 
ENDIF.
endmethod.








method EH_ONEDIT.

   
DATA:    lr_tx          TYPE REF TO if_bol_transaction_context,

          lr_entity     
TYPE REF TO cl_crm_bol_entity,

          lr_comp
type REF TO CL_BT111H_O_BSPWDCOMPONEN_IMPL.
*          cl_bt111h_o_bspwdcompone0_impl.


*lr_entity ?= me->typed_context->ZFOREC->collection_wrapper->get_first( ).
*lr_entity ?= me->typed_context->ZFOREC->collection_wrapper->get_next( ).


*me->view_group_context->set_view_editable( me ).





  lr_comp ?= me->comp_controller.

 
Check lr_comp is BOUND.

  lr_entity ?= lr_comp->typed_context->btadminh->collection_wrapper->get_current( ).

 
CHECK lr_entity IS BOUND.

 
IF lr_entity->lock( ) = abap_true.

    me->view_group_context->set_view_editable( me ).

 
ENDIF.



  lr_entity ?= me->typed_context->ZFOREC->collection_wrapper->get_first( ).

 
WHILE lr_entity IS BOUND.

    lr_entity->lock( ).

    lr_entity ?= me->typed_context->ZFOREC->collection_wrapper->get_next( ).

 
ENDWHILE.
endmethod.

Create On_new_focus method in the "ZFOREC" context node, specify it as a event handler for collection wrapper new_focus event.


Create the  event parameter

13. Set handler in Connect nodes method of the CTXT class.


  method CONNECT_NODES.
DATA: coll_wrapper TYPE REF TO cl_bsp_wd_collection_wrapper,         

      comp_controller TYPE REF TO ZL_BT111H_O_BSPWDCOMPONEN_IMPL.

coll_wrapper = me->BTADMINH->get_collection_wrapper( ).

set HANDLER me->ZFOREC->on_new_focus for coll_wrapper ACTIVATION iv_activate.
endmethod.

14. As Save event is handled in different view (BT111H_OPPT/OpportunityOVViewSet), ZFOREC data has to be bind to custom/component controller to access it in other views.



15. Now create new Custom controller "ZFORECAST" with ZFORECAST and BTADMINH node and perform the binding as shown below using the binding wizard.

So with this binding now ZFORECAST can be called in any page view in this component

16 .Further now also add the ZFOREC node to BT111H_OPPT/OpptDetailsCuCo custom component as per  below, so that ZFOREC can be now displayed in the opportunity details page.

17 . Redefine eh_onsave event of the save method in  "BT111H_OPPT/OpportunityOVViewSet" component/view.


method EH_ONSAVE.
*CALL METHOD SUPER->EH_ONSAVE
**  EXPORTING
**    htmlb_event    =
**    htmlb_event_ex =
*    .
 
DATA: lv_items TYPE REF TO cl_bt111h_o_itemslistov_impl.

 
DATA: lv_success TYPE crmt_boolean.

 
DATA: lv_success_save TYPE crmt_boolean.

 
DATA:lr_ent              TYPE REF TO      cl_crm_bol_entity,

      lr_tx             
TYPE REF TO      if_bol_transaction_context.

 
data: lr_controller TYPE REF TO cl_bsp_wd_appl_controller,

        lr_msg_srv
TYPE REF TO cl_bsp_wd_message_service.

 
data:lr_tx_ctxt TYPE REF TO if_bol_transaction_context, "lr_tx

      lr_coll_wr
TYPE REF TO cl_bsp_wd_collection_wrapper,

      my_tx_context 
TYPE REF TO cl_crm_bol_custom_tx_ctxt, " Z cntx

      lr_entity_so 
TYPE REF TO cl_crm_bol_entity,

      rv_success   
TYPE        abap_bool,

      lr_tx_manager
TYPE REF TO if_crm_uiu_bt_channel_aspects,"cl_crm_uiu_bt_channel_asp_fac,
*    lr_tx_manager TYPE REF TO cl_mktprj_transaction_mgr.

      lr_coco
TYPE REF TO ZL_BT111H_O_BSPWDCOMPONEN_IMPL.
* cancel save because of mandatory fiels

  lr_controller ?= comp_controller->m_parent.

  lr_msg_srv ?= me->view_manager->get_message_service( ).

 
IF cl_crm_uiu_bt_tools=>mandatory_flds_no_save_allowed( ir_controller = lr_controller

                                                          ir_msg_srv    = lr_msg_srv ) = abap_true.

   
EXIT.

 
ENDIF.

 
IF cl_crm_uiu_bt_partner_popup=>get_quick_create_status( ) = abap_true OR gc_abc EQ abap_true.
*Save business partner-accounts and related objects (contacts, conditions,..)

    lv_success = cl_crm_uiu_bp_tools=>save( ).

    cl_crm_uiu_bt_partner_popup=>set_quick_create_status(
EXPORTING iv_quick_create = abap_false ).

    gc_abc = abap_false.

 
ELSE.

    lv_success = abap_true.

 
ENDIF.



 
CALL METHOD cl_crm_uiu_bt_tools=>save( EXPORTING ir_node = me->typed_context->btorder ).

 
CLEAR:lr_tx_ctxt,my_tx_context.



 
CREATE OBJECT my_tx_context.
  lr_coco ?= me->comp_controller.

 
IF lr_coco IS BOUND.
* Get the First entity

    lr_entity_so ?= lr_coco->ztyped_context->ZFORECAST->collection_wrapper->get_first( ).
* Loop on the collection

   
WHILE lr_entity_so IS BOUND.

      lr_tx_ctxt = lr_entity_so->get_transaction( ).

      my_tx_context->add_tx_context( lr_tx_ctxt ).

      my_tx_context->if_bol_transaction_context~save( ).

      my_tx_context->if_bol_transaction_context~
commit( ).
*      * Get the next entity

      lr_entity_so ?=lr_coco->ztyped_context->ZFORECAST->collection_wrapper->get_next( ).

   
ENDWHILE.
 
ENDIF.
  rv_success = cl_crm_uiu_bp_tools=>save( ).


 
IF rv_success = abap_true AND me->view_group_context IS NOT INITIAL.
*    eh_oncancel( ).

 
ENDIF.
****************


* remove and add entity in order to refresh all context nodes (selections, etc.)
* and lock registration is done

  lr_ent ?= me->typed_context->btorder->collection_wrapper->get_current( ).

  me->typed_context->btorder->collection_wrapper->clear( ).

 
IF lr_ent IS BOUND.

    me->typed_context->btorder->collection_wrapper->add( iv_entity    = lr_ent

                                                        iv_set_focus = abap_true ).

 
ENDIF.


*  ** get current

  lr_entity_so ?= lr_coco->ztyped_context->ZFORECAST->collection_wrapper->get_current( ).

  me->ztyped_context->ZFOREC->collection_wrapper->clear( ).
endmethod.

Add the following code in on_new_focus method,here logic is to retrieve the order entities collection related to Order only if parent entity opportinity changes

18.Add the ZFOREC view to runtime repository..


19. Expose "ZFOREC" view on BT111H_OPPT/OpportunityOVViewSet Configuration
page, maintain view title and save...

20. That's it ...this is how it appears within WebUi page of opportunity with Create/Edit/Delete functionality.



 

2 Comments
Labels in this area