SAP CRM Web UI Simple Objects - Creating custom 1...n Bol entities - ZFORECAST
Author: Jignesh Trivedi
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...
1Created new table :
2Create a lock object " EZFORECAST" for our table ZFOREACT. (Lock mode E)
3Define the customizing entry for simple objects in :
"spro->crm->cross appl. comp-> genil->comp. spe. Setting->define SO"
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'
4Add the SO2 object to our ONEORDER Component
5Create a mapping entry for our "Simple object - ' ZFORECAST', table name - 'ZFORECAST' and lock object - ' EZFORECAST " in the table "CRMC_TBLOBJ_MAP"
6Execute 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
7Let'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
8Declare these Button attributes in the attribute section of the ZFOREC view's implementation class.
9Modify the code of " ZFOREC.htm" BSP page code with the below code.
<%@pagelanguage="abap"%>
<%@extensionname="htmlb"prefix="htmlb"%>
<%@extensionname="xhtmlb"prefix="xhtmlb"%>
<%@extensionname="crm_bsp_ic"prefix="crmic"%>
<%@extensionname="bsp"prefix="bsp"%>
<%@extensionname="chtmlb"prefix="chtmlb"%>
<%@extensionname="thtmlb"prefix="thtmlb"%>
<%
datalv_xmltypestring.
lv_xml=controller->configuration_descr->get_config_data().
%>
<thtmlb:areaFrameSettertoolbarButtons="<%=controller->tb_button%>"
maxButtonNumber="2"
displayMode="<%=controller->view_group_context->is_view_in_display_mode(controller)%>"
/>
<chtmlb:tableExtensiontableId="Table1"
layout="FIXED"
<chtmlb:configTablexml="<%=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>
10Click on Configuration tab of "ZFOREC" view move required field to be shown on the right side under displayed field.
11Define three buttons Create, Delete, Edit List in do_prepare_output method of the implementation class.
DATA:ls_buttonTYPEcrmt_thtmlb_button.
DATA:lr_entityTYPEREFTOcl_crm_bol_entity,
lv_lockedTYPEchar1,
lv_enabledTYPEcrmt_booleanVALUEabap_true,
lr_collTYPEREFTOif_bol_bo_col,
lv_coll_sizeTYPEsytabix,
lv_displayTYPEboolean.
*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.
IFlv_displayEQabap_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.
CALLMETHODsuper->do_prepare_output.
lr_coll=me->typed_context->zforec->collection_wrapper->get_marked().
IFlr_collISBOUND.
lv_coll_size=lr_coll->size().
IFlv_coll_size=0.
lv_enabled=abap_false.
ELSE.
lv_enabled=abap_true.
ENDIF.
ENDIF.
************************
CLEAR:tb_button,ls_button.
ls_button-text='EditList'.
ls_button-on_click='EDIT'."#ECNOTEXT
ls_button-enabled=me->view_group_context->is_view_in_display_mode(me).
APPENDls_buttonTOtb_button.
CLEARgt_button.
ls_button-text='Insert'.
ls_button-on_click='CREATE'."#ECNOTEXT
ls_button-enabled=abap_true.
APPENDls_buttonTOgt_button.
CLEARls_button.
ls_button-type=cl_thtmlb_util=>gc_icon_delete.
ls_button-on_click='DELETE'."#ECNOTEXT
ls_button-enabled=abap_true."lv_enabled.
APPENDls_buttonTOgt_button.
CLEARls_button.
12Create three event's "CREATE","DELETE","EDIT" in "ZFOREC" view via wizard & add the required logic in each event method as per below.
methodEH_ONCREATE.
DATA:lr_entityTYPEREFTOcl_crm_bol_entity,
lv_collectionTYPEREFTOif_bol_bo_col,
lr_compTYPEREFTOcl_bt111h_o_bspwdcomponen_impl.
*cl_bt111h_o_bspwdcompone0_impl.
DATA:lr_coreTYPEREFTOcl_crm_bol_core,
lr_facTYPEREFTOcl_crm_bol_entity_factory,
lt_paramsTYPEcrmt_name_value_pair_tab,
ls_paramsTYPEcrmt_name_value_pair,
lr_entTYPEREFTOcl_crm_bol_entity,
lv_objidTYPEcrmd_orderadm_h-object_id,
lv_quot_idTYPEcrmd_orderadm_h-object_id,
lv_pred_guidTYPEcrmt_object_guid,
lv_cmp_guidTYPEcrmt_object_guid,
ls_boridentTYPEborident,
it_neighbor_objectsTYPETABLEOFrelroles,
is_neighbor_objectsTYPErelroles,
lt_zforecastTYPETABLEOFzforecast,
lv_new_monthTYPEzforecast-z_month,
lv_cur_zvalueTYPEzforecast-z_value,
lv_new_zvalueTYPEzforecast-z_value,
lr_cocoTYPEREFTOzl_bt111h_o_bspwdcomponen_impl,
lr_entity_soTYPEREFTOcl_crm_bol_entity,
lr_entity_curTYPEREFTOcl_crm_bol_entity,
ls_zforecastTYPEzforecast.
lr_comp?=me->comp_controller.
CHECKlr_compISBOUND.
lr_entity?=lr_comp->typed_context->btadminh->collection_wrapper->get_current().
*"Readingthebtadminhentity,whichisboundtocomponentcontroller's
*btadminhcontextnode.
me->typed_context->zforec->deselect_all().
*me->typed_context->ZFOREC->select_all().
IFlr_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).
IFlr_entISBOUND.
CHECKlr_ent->lock()=abap_true.
*****************
CLEAR:lv_cmp_guid,lv_objid,
lv_pred_guid,lv_quot_id.
*ReadtheparententityBTADMINHguid
*"CopyBtAdminhGuidtoForecasttableOpportunityGuid
lr_entity->get_property_as_value(EXPORTINGiv_attr_name='GUID'
IMPORTINGev_result=lv_cmp_guid).
lr_ent->set_property(iv_attr_name='Z_HD_OPPT_GUID'
iv_value=lv_cmp_guid).
**Objectid/Docnoisgeneartedonlyaftersave,somaybeblankwhileincreatemode.
lr_entity->get_property_as_value(EXPORTINGiv_attr_name='OBJECT_ID'
IMPORTINGev_result=lv_objid).
lr_ent->set_property(iv_attr_name='Z_HDR_OPPT_NO'
iv_value=lv_objid).
******************Defaultthevaluesforquotno*******************************
*PREDECESSOR_GUIDQuotGuidwhencreatefollowupdocisselected
lr_entity->get_property_as_value(EXPORTINGiv_attr_name='PREDECESSOR_GUID'
IMPORTINGev_result=lv_pred_guid).
lr_ent->set_property(iv_attr_name='Z_HDR_QUOT_GUID'
iv_value=lv_pred_guid).
**SOMETIMESPREDECESSOR_GUIDisemptythengetitfromtransactionhistory
IFlv_pred_guidISINITIAL.
ls_borident-objkey=lv_cmp_guid.
ls_borident-objtype='BUS2000111'.
ls_borident-logsys=''.
CALLFUNCTION'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.
IFsy-subrc=0.
*MESSAGEIDSY-MSGIDTYPESY-MSGTYNUMBERSY-MSGNO
*WITHSY-MSGV1SY-MSGV2SY-MSGV3SY-MSGV4.
LOOPATit_neighbor_objectsINTOis_neighbor_objects
WHEREroletype='VORGAENGER'"Precedingdoc
ANDobjtype='BUS2000115'."quotes
lv_pred_guid=is_neighbor_objects-objkey.
ENDLOOP.
ENDIF.
ENDIF.
*GetPREDECESSORQuotnowhencreatefollowupdocisselected
IFlv_pred_guidISNOTINITIAL.
SELECTSINGLEobject_idINTOlv_quot_id
FROMcrmd_orderadm_hWHEREguid=lv_pred_guid.
*lr_entity->get_property_as_value(EXPORTINGiv_attr_name='PREDECESSOR_GUID'
*IMPORTINGev_result=lv_pred_guid).
lr_ent->set_property(iv_attr_name='Z_HDR_QUOT_NO'
iv_value=lv_quot_id).
ENDIF.
*****************************************************************************
*Readthelastrecordfromcollectionwrapper
lr_coco?=me->comp_controller.
IFlr_cocoISBOUND.
CLEAR:lv_new_month,lv_new_zvalue.
*GettheLastentity
lr_entity_so?=lr_coco->ztyped_context->zforecast->collection_wrapper->get_last().
IFlr_entity_soISBOUND.
**Getprevmonth
lr_entity_so->get_property_as_value(EXPORTINGiv_attr_name='Z_MONTH'
IMPORTINGev_result=lv_new_month).
***Add1monthfornewentry
IFlv_new_month+4(2)='12'."ifdecemberthataddnewyr
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."add1month
ENDIF.
lr_ent->set_property(iv_attr_name='Z_MONTH'
iv_value=lv_new_month).
**********
****Getthecurrentzvalue
*lr_entity_cur?=lr_coco->ztyped_context->zforecast->collection_wrapper->get_current().
*IFlr_entity_curISBOUND.
*lr_entity_cur->get_property_as_value(EXPORTINGiv_attr_name='Z_VALUE'
*IMPORTINGev_result=lv_cur_zvalue).
*ENDIF.
***
lr_entity_so->get_property_as_value(EXPORTINGiv_attr_name='Z_VALUE'
IMPORTINGev_result=lv_new_zvalue).
**newvalue=currqty*????
*lr_ent->set_property(iv_attr_name='Z_VALUE'
*iv_value=lv_new_zvalue).
lr_entity_so->get_property_as_value(EXPORTINGiv_attr_name='Z_CUR_QTY'
IMPORTINGev_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.
CATCHcx_crm_genil_model_error.
EXIT.
CATCHcx_sy_ref_is_initial.
ENDTRY.
ENDIF.
endmethod.
methodEH_ONDELETE.
DATA:lr_entityTYPEREFTOcl_crm_bol_entity,
lr_currentTYPEREFTOif_bol_bo_property_access,
lr_colTYPEREFTOif_bol_bo_col,
lr_coreTYPEREFTOcl_crm_bol_core,
lv_sizeTYPEi.
lr_col?=typed_context->ZFOREC->collection_wrapper->get_marked().
lv_size=lr_col->size().
IFlv_size0.
DOlv_sizeTIMES.
IFsy-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.
methodEH_ONEDIT.
DATA:lr_txTYPEREFTOif_bol_transaction_context,
lr_entityTYPEREFTOcl_crm_bol_entity,
lr_comptypeREFTOCL_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.
Checklr_compisBOUND.
lr_entity?=lr_comp->typed_context->btadminh->collection_wrapper->get_current().
CHECKlr_entityISBOUND.
IFlr_entity->lock()=abap_true.
me->view_group_context->set_view_editable(me).
ENDIF.
lr_entity?=me->typed_context->ZFOREC->collection_wrapper->get_first().
WHILElr_entityISBOUND.
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
13Set handler in Connect nodes method of the CTXT class.
methodCONNECT_NODES.
DATA:coll_wrapperTYPEREFTOcl_bsp_wd_collection_wrapper,comp_controllerTYPEREFTOZL_BT111H_O_BSPWDCOMPONEN_IMPL.
coll_wrapper=me->BTADMINH->get_collection_wrapper().
setHANDLERme->ZFOREC->on_new_focusforcoll_wrapperACTIVATIONiv_activate.
endmethod.
14As 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.
15Now 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
16Further 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.
17Redefine eh_onsave event of the save method in "BT111H_OPPT/OpportunityOVViewSet" component/view.
methodEH_ONSAVE.
*CALLMETHODSUPER->EH_ONSAVE
**EXPORTING
**htmlb_event=
**htmlb_event_ex=
*.
DATA:lv_itemsTYPEREFTOcl_bt111h_o_itemslistov_impl.
DATA:lv_successTYPEcrmt_boolean.
DATA:lv_success_saveTYPEcrmt_boolean.
DATA:lr_entTYPEREFTOcl_crm_bol_entity,
lr_txTYPEREFTOif_bol_transaction_context.
data:lr_controllerTYPEREFTOcl_bsp_wd_appl_controller,
lr_msg_srvTYPEREFTOcl_bsp_wd_message_service.
data:lr_tx_ctxtTYPEREFTOif_bol_transaction_context,"lr_tx
lr_coll_wrTYPEREFTOcl_bsp_wd_collection_wrapper,
my_tx_contextTYPEREFTOcl_crm_bol_custom_tx_ctxt,"Zcntx
lr_entity_soTYPEREFTOcl_crm_bol_entity,
rv_successTYPEabap_bool,
lr_tx_managerTYPEREFTOif_crm_uiu_bt_channel_aspects,"cl_crm_uiu_bt_channel_asp_fac,
*lr_tx_managerTYPEREFTOcl_mktprj_transaction_mgr.
lr_cocoTYPEREFTOZL_BT111H_O_BSPWDCOMPONEN_IMPL.
*cancelsavebecauseofmandatoryfiels
lr_controller?=comp_controller->m_parent.
lr_msg_srv?=me->view_manager->get_message_service().
IFcl_crm_uiu_bt_tools=>mandatory_flds_no_save_allowed(ir_controller=lr_controller
ir_msg_srv=lr_msg_srv)=abap_true.
EXIT.
ENDIF.
IFcl_crm_uiu_bt_partner_popup=>get_quick_create_status()=abap_trueORgc_abcEQabap_true.
*Savebusinesspartner-accountsandrelatedobjects(contacts,conditions,..)
lv_success=cl_crm_uiu_bp_tools=>save().
cl_crm_uiu_bt_partner_popup=>set_quick_create_status(EXPORTINGiv_quick_create=abap_false).
gc_abc=abap_false.
ELSE.
lv_success=abap_true.
ENDIF.
CALLMETHODcl_crm_uiu_bt_tools=>save(EXPORTINGir_node=me->typed_context->btorder).
*****************
CLEAR:lr_tx_ctxt,my_tx_context.
CREATEOBJECTmy_tx_context.
**lr_tx_manager=cl_mktprj_transaction_mgr=>get_instance().
*lr_tx_manager=cl_crm_uiu_bt_channel_asp_fac=>get_instance().
*my_tx_context->add_tx_context(lr_tx_manager).
lr_coco?=me->comp_controller.
IFlr_cocoISBOUND.
*GettheFirstentity
lr_entity_so?=lr_coco->ztyped_context->ZFORECAST->collection_wrapper->get_first().
*Looponthecollection
WHILElr_entity_soISBOUND.
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().
**Getthenextentity
lr_entity_so?=lr_coco->ztyped_context->ZFORECAST->collection_wrapper->get_next().
ENDWHILE.
ENDIF.
rv_success=cl_crm_uiu_bp_tools=>save().
*IFlr_entity_soISBOUND.
*my_tx_context->if_bol_transaction_context~save().
*my_tx_context->if_bol_transaction_context~commit().
*ENDIF.
IFrv_success=abap_trueANDme->view_group_contextISNOTINITIAL.
*eh_oncancel().
ENDIF.
****************
*removeandaddentityinordertorefreshallcontextnodes(selections,etc.)
*andlockregistrationisdone
lr_ent?=me->typed_context->btorder->collection_wrapper->get_current().
me->typed_context->btorder->collection_wrapper->clear().
IFlr_entISBOUND.
me->typed_context->btorder->collection_wrapper->add(iv_entity=lr_ent
iv_set_focus=abap_true).
ENDIF.
***getcurrent
lr_entity_so?=lr_coco->ztyped_context->ZFORECAST->collection_wrapper->get_current().
me->ztyped_context->ZFOREC->collection_wrapper->clear().
endmethod.
18.Add the following code in on_new_focus method, here logic is to retrieve the order entities collection related to campaign only if parent entity "campaign" changes..
methodON_NEW_FOCUS.
DATA:entityTYPEREFTOcl_crm_bol_entity,
lr_oldTYPEREFTOcl_crm_bol_entity,
queryTYPEREFTOcl_crm_bol_query_service,
resultTYPEREFTOif_bol_bo_col,
lv_old_guidTYPEcrmt_object_guid,
lv_guidTYPEcrmt_object_guid.
entity?=focus_bo."aDMINHentity
CHECKentityisBOUND.
entity->get_property_as_value(EXPORTINGiv_attr_name='GUID'
IMPORTINGev_result=lv_guid).
lr_old?=me->collection_wrapper->get_current().
iflr_oldisBOUND.
lr_old->get_property_as_value(EXPORTINGiv_attr_name='Z_HD_OPPT_GUID'
IMPORTINGev_result=lv_old_guid).
ENDIF.
*FireQueryonlyifadminhentityischanged
"lv_old_guid-opptguidEntityguid"lv_guid-adminhguid
iflv_guidnelv_old_guid.
query=cl_crm_bol_query_service=>get_instance('ZFORECAST_SRC').
query->set_property(iv_attr_name='Z_HD_OPPT_GUID'
iv_value=lv_guid).
result?=query->get_query_result().
me->set_collection(result).
ENDIF.
endmethod.
18Add the ZFOREC view to runtime repository..
19Expose "ZFOREC" view on BT111H_OPPT/OpportunityOVViewSet Configuration page, maintain view title and save...
20That's it ...this is how it appears within WebUi page of opportunity with Create/Edit/Delete functionality.