Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
In the second part we will use this Z BOL object in our Web component.
Step 1: Create a Ztable with the following fields.
Step 3: Create an object name. Specify our table name as the "attrib structure" and "Mand. flds at create".
Step 4: Define Search object definition. This is very important because using this, we will fill the data in the BOL object.
Step 6: Click New entries and do the mapping between the object and the table which we have created. Basically maintain the entries as shown in the screenshot.
Step 7: Open tcode GENIL_BOL_BROWSER. Click the button "New Root Object" as shown in the screenshot. In the left hand side of the screen you will see the BOL object which we have created. Double click it.
Step 8: Click the button "Create Object". Maintain some entries and then click save.
Step 9: In Tcode Se16 you will be able to see the following entries.
Step 10: Open tcode GENIL_BOL_BROWSER. Click the button "New Search" as shown in the screenshot.
Step 12: If the other entries get populated as shown in the screenshot means our BOL object is working fine.
Next we will be using this in our web component. That I will be writing in my next blog.
Attachments:9 Added by Arun Prakash Karuppanan, last edited by Arun Prakash Karuppanan on Sep 14, 2010 (view change)
Link to Content's target Space : http://wiki.sdn.sap.com/wiki/display/CRM/CRM+Web+Client+UI+Framework Applies to: SAP CRM 6.0/7.0 Summary Extend the standard BOL model BT with a custom relationship to accomodate your z-table. Author(s): Arun Prakash Karuppanan Company: Created on: Author(s) Bio Arun Prakash Karuppanan is a software programmer wmployed with Accenture, working on CRM implementations. Intro There's been a few discussions in the forums about finding a way to add a custom table to the standard BOL models. It's a bit tricky, but possible. In this WIKI, I will show you how to enhance the BOl model BT with a new 1..n relationship. The advantages are obvious. Any change in your custom data will register in the BOl layer, you will be able to capture the BOl Core Reset and Order Init(revert) events, use the BOL model node wizards etc., Enhancing a few standard classes are in order. So, knowing how to enhance the methods using the implicit enhancement points is necessary. In this example, we will create the relationship under the administration header(BTAdminH). Actually, two relationships. One will be a read only relationship(similiar to BTItems) that is linked and the other will be the 1..n relation that corresponds to your database. My custom database ZORD has the following fields. CLIENT GUID REF_GUID NOTE type MANDT "Client Accenture April 15 2010
type CRMT_OBJECT_GUID "guid of table entry(key) type CRMT_OBJECT_GUID "guid of order object "end-user usable type CHAR120 "end-user usable
A structure 'ZORD_STRUCT' that corresponds to the table structure and a table type 'ZORD_STRUCT_TAB' is available. Step 1 : Studying the event handler model
Maintain API Object Name In transaction CRMC_OBJECTS, maintain the API object name of our custom object. In our case, the name is ZORD. This information will be used further below. This will allow us to define our own transaction events. Maintain Object dependency This step is to ensure that the transaction events which we will be defining later on, will be called only when necessary. This step is optional and you should be able to figure out if your scenario needs this or not. For example, if you are extending only the opportunity transaction type, declare ZORD as a sub-object of Opportunity(BUS2000111). Maintain this information in view maintenance CRMV_OBJECT_ASSI Identify positions for defining custom events for transactions We will have to define three basic events in the transaction event model that will take care of our custom objects. These are 1. Initialization -> When the order is being initialized say, during lock/revert scenarios, we want our object to be initialized too. 2. Save -> When the order is being saved, save our data too. 3. Delete -> When the order is deleted, we need to delete corresponding data from our custom table For this, you must identify the correct places to insert our event callback function modules. If not already done, set your user parameter CRM_EVENT_TRACE to "X". Next, do something say, create transactions, modify it, save it and delete it. After each action, look at the events raised in transaction CRMD_EVENT_TRACE. Study this data carefully and decide on the points in which to insert
Description
You have a z-table in your ERP system which you would like to display on the CRM WebUI in its own Assignment Block. Let's say this table even depends on one of the objects of CRM; the Business Partner (henceforth called just partner or BP). This guide describes step by step a possible way to do this. Please note that there might be other, easier ways and what is described below is what I found out and it worked for me so I thought it could work for others too.
Added by Melanie Lauber, last edited by Sara Licht on Jun 01, 2009 (view change)
Technical data
Before I start a development, I always like to know all the technical data and write them down so I don't have to look them up all the time during developing. I said before this z-table has data which belongs to partners. This means I have to find out the Overview Page for the BP details display - there we will eventually add our assignment block.
Component: BP_HEAD View: BPHEADOverview
Development Step-by-Step
1. Create a Structure and Table type
We need a structure and a table type in the CRM system which look the exact same as the table in the ERP system. Let's assume this table in the ERP system contains the favorite color, meal and sport of a partner (not saying that makes much sense but it's easier if we have an example). So the structure could look something like this: Component Description
MANDT
Client
PARNR
Partner Number
COLOR
Favorite Color
MEAL
Favorite Meal
SPORT
Favorite Sport
Define Name: type in a suitable name for the view Add Model Node: because the data from the z-table is dependent on the BP we have to add a Context Node which has the corresponding BOL entity. The Business Partner header data has the BOL entity BuilHeader. Add the model node PARTNER with that BOL Entity. Add Value Node: we need a value node for our z-table (which will become a node for a table in Select View Type). Simply type a name for the node. Add Model Attributes to Model Node: here we decide which attributes of the partner (header data) we would like to have. In our case we only need the partner number. Add it with the plus-icon. Add Value Attributes to Context Node: here we have to add every component (field) of our table. This is best done with the plus-icon. Choose the correct Context Node (the Value Node for the z-table) and type in the structure we created in Step 1. Press enter, mark all attributes and add them. Select View Type: choose View Type "Table View" and the Context Node we created for the z-table in Add Value Node.
Add View to Window: Open the Window node, find your window, right click on it and choose Add View. Select the view you created in Step 3. Add Window to Component Interface: Open the Component Interface node, right click on Interface View and choose Add. Select your Window and View. Add Component Usage: Open the Component Usages node, right click on Component Usage and choose Add Interface View. Select the Interface View you added above.
Double click the View we've created in Step 3. Open the node Context and double click on the Context Implementation Class. Locate the method CREATE_PARTNER (Model Node) and go into its coding. Add the binding to the Component Controller at the end of the method as shown below:
Context Class: ZL_ZBP_FAVS_ZBPFAVORITES_CTXT Method: CREATE_PARTNER * data binding with Component Controller 'PARTNER' owner->do_context_node_binding( iv_controller_type = cl_bsp_wd_controller=>co_type_component iv_target_node_name = 'PARTNER' iv_node_2_bind = partner ).
Now we have to call this Event Handler. Go into the Context Class (just like in Step 5) and open the coding of method CREATE_ZBP_FAVS (Value/Table Node). Add the call of method ON_NEW_FOCUS depending on the Model Node as shown below:
Context Class: ZL_ZBP_FAVS_ZBPFAVORITES_CTXT Method: CREATE_ZBP_FAVS * dependent node settings coll_wrapper = partner->get_collection_wrapper( ). TRY. entity ?= coll_wrapper->get_current( ). CATCH cx_sy_move_cast_error. ENDTRY. IF entity IS BOUND. zbp_favs->on_new_focus( focus_bo = entity ). ENDIF.
ls_smof_erpsh
if_bol_bo_col, cl_bsp_wd_value_node, zbp_favs_s, " table zbp_favs_tab, " local zbp_favs_s. " local
" collection to fill node ZBP_FAVS " value nodes to fill a collection line reference to fill value node table with data from ERP-table ZBP_FAVS structure of table above
* get partner entity and partner number try. lr_entity ?= focus_bo. catch cx_sy_move_cast_error. return. endtry. lv_bp_nr = lr_entity->get_property_as_string( 'BP_NUMBER' ). if lv_bp_nr is initial. " no partner... return. "...return without selection endif. * get RFC destination of ERP system, if needed if ZL_ZBP_FAVS_ZBPFAVORITES_IMPL=>gv_destination is initial. call function 'CRM_GET_ERP_SYSTEM' * exporting * iv_rfcdest = * iv_siteid = importing es_smof_erpsh = ls_smof_erpsh. if sy-subrc = 0 and ls_smof_erpsh-rfcdest is not initial. ZL_ZBP_CUCL_ZCURRENCYCLAU_IMPL=>gv_destination = ls_smof_erpsh-rfcdest. endif. endif. * get favorite things for partner lv_partner = lv_bp_nr. " call RFC function in ERP system call function 'Z_CRM_GET_FAVS_FOR_BP' destination ZL_ZBP_CUCL_ZCURRENCYCLAU_IMPL=>gv_destination exporting iv_partner = lv_partner importing et_favs = lt_favs exceptions others = 4. if sy-subrc <> 0. " should never happen endif. * create collection object to transfer data create object lr_col type cl_crm_bol_bo_col. * loop through all found data... loop at lt_favs into ls_favs. "...create line object create data lr_tabline. "...create value object with current line for colleciton create object lr_valuenode exporting iv_data_ref = lr_tabline. "...set current line data lr_valuenode->set_properties( ls_favs ). "...add current line to collection lr_col->add( lr_valuenode ). endloop. * set collection me->set_collection( lr_col ).
9. Display data
Unfortunately we're not done yet. I don't know why, but the standard created HTML-page doesn't display the Table Node we filled with a data collection in Step 8. Therefore I programmed my own workaround. Go to the HTML-page which is located under View Layout. Double click to get into the HTML editor. Please note: the html-table you'll find in the coding below _considers the user's Layout settings_ but it's not the official coding - just something I figured out myself.
View (HTML): ZBPFavorites.htm <%@page language="abap"%> <%@ extension name="htmlb" prefix="htmlb"%> <% * data definitions ***************************************************** data: lr_wrapper type ref to cl_bsp_wd_collection_wrapper, lr_entity type ref to if_bol_bo_property_access, lt_favs ls_favs lv_value type type type zbp_favs_tab, zbp_favs_s, string. any.
* fill local Currency Clause table ************************************* " get collection wrapper lr_wrapper = zcucl->get_collection_wrapper( ). if lr_wrapper is bound. " get first entity... lr_entity = lr_wrapper->get_first( ). "...then loop through all entities while lr_entity is bound. " Partner number assign component 'PARNR' of structure ls_favs to <fs_favs>. try. lv_value = lr_entity->get_property_as_string( 'PARNR' ).
catch cx_sy_conversion_error . endtry. <fs_favs> = lv_value. " Color assign component 'COLOR' of structure ls_favs to <fs_favs>. try. lv_value = lr_entity->get_property_as_string( 'COLOR' ). catch cx_sy_conversion_error . endtry. <fs_favs> = lv_value. " Meal assign component 'MEAL' of structure ls_favs to <fs_favs>. try. lv_value = lr_entity->get_property_as_string( 'MEAL' ). catch cx_sy_conversion_error . endtry. <fs_cucl> = lv_value. " Sport assign component 'SPORT' of structure ls_favs to <fs_favs>. try. lv_value = lr_entity->get_property_as_string( 'SPORT' ). catch cx_sy_conversion_error . endtry. <fs_favs> = lv_value. " add favorites to local table append ls_favs to lt_favs. " get next entity lr_entity = lr_wrapper->get_next( ). endwhile. endif. %> <% * display BP Favorites table ************************************************** %> <table class="th-tv th-tv-table"> <% loop at lt_favs into ls_favs. if sy-tabix = 1. %> <!-- table header --> <thead class="th-tv-header"> <tr> <!--<th class="th-clr-cel th-tx-header1"><%= otr(ZCRM/Partner) %></th>--> <th class="th-clr-cel th-tx-header1"><%= otr(ZCRM/Color) %></th> <th class="th-clr-cel th-tx-header1"><%= otr(ZCRM/Mail) %></th> <th class="th-clr-cel th-tx-header1"><%= otr(ZCRM/Sport) %></th> </tr> <!-- end of table header --> </thead> <!-- table body --> <tbody> <% endif. %> <tr> <td class="th-ip-td1 th-tv-cel-txt"><%= ls_favs-color %></td> <td class="th-ip-td1 th-tv-cel-txt"><%= ls_favs-mail %></td> <td class="th-ip-td1 th-tv-cel-txt"><%= ls_cucl-sport %></td> </tr> <% if sy-tabix = sy-tfill. %> <!-- end of table body --> </tbody> <% endif. endloop. if sy-subrc <> 0. %> <tr> <td class="th-tv-noresult"> <img src="images/infoMessage.gif" border="0"> <span><%= otr(ZCRM/noResults) %></span> </td> </tr>
<%
Added by Ranganath Prasad, last edited by Stephen Johannes on Mar 03, 2010 (view change)
Applies to:
SAP CRM 6.0/7.0 CRM Web UI Model View Controller
Summary
You may sometimes need to find out the attributes of an internal table during runtime, that were not statically available. In this kind of situation, if you want to build an internal table, we can use ABAP RTTS ( Runtime Type Service) concept. Alternativly we can also create dynamic internal table by passing ALV field catalog to the class method --cl_alv_table_create=>create_dynamic_table. In this wiki I will describe the steps of creating dynamic tableView using CRM Web UI MVC framework.
Author(s):
: :
I'm currently working as a CRM Consultant in Win IC, Web IC , Sales, Service and Marketing areas. I have over 10 years of experience across SAP modules and specialized in SAP SRM, CRM, cProjects, Travel and Expense mgmt and Workflow.Previously worked on SAP projects across industry verticals -- Pharma, Hi-tech, Accounting, Agri-business and Oil&Gas). Table of Contents
Introduction
Development steps
Introduction
Related Content
1. Database table design 2. Create Internal Table during run-time 3. Create View and Context node 4. Implement GET_TABLE_LINE_SAMPLE method in the Table Node 5. Fill Table node from Dynamic table data 6. Display the Data using model Binding 7. Make the tableView data Editable 8. Read data from Table node and Save to DB
Before you start reading my blog, I would recommend you to read/practice a very nice blog written by Melanie Lauber--How to display a z-table in an assignment block , which explains about displaying a custom table on WebUI. I don't want to duplicate all the steps here, but I want to describe the steps which are different from that blog. I will try to provide sample code where it is necessary. I'm assuming reader is expert in using Field Symbols, Dynmic internal tables, BSP, MVC, Web UI and writing custom Iterator class for tableView THTMLB tag..
Development steps
100001
Rep1
P1
50
100001
Rep2
P1
50
100001
Rep2
P2
100
Description
You have a z-table in your ERP system which you would like to display on the CRM WebUI in its own Assignment Block. Let's say this table even depends on one of the objects of CRM; the Business Partner (henceforth called just partner or BP). This guide describes step by step a possible way to do this. Please note that there might be other, easier ways and what is described below is what I found out and it worked for me so I thought it could work for others too.
Added by Melanie Lauber, last edited by Sara Licht on Jun 01, 2009 (view change)
Technical data
Before I start a development, I always like to know all the technical data and write them down so I don't have to look them up all the time during developing. I said before this z-table has data which belongs to partners. This means I have to find out the Overview Page for the BP details display - there we will eventually add our assignment block.
Component: BP_HEAD View: BPHEADOverview
Development Step-by-Step
1. Create a Structure and Table type
We need a structure and a table type in the CRM system which look the exact same as the table in the ERP system. Let's assume this table in the ERP system contains the favorite color, meal and sport of a partner (not saying that makes much sense but it's easier if we have an example). So the structure could look something like this: Component Description
MANDT
Client
PARNR
Partner Number
COLOR
Favorite Color
MEAL
Favorite Meal
SPORT
Favorite Sport
Define Name: type in a suitable name for the view Add Model Node: because the data from the z-table is dependent on the BP we have to add a Context Node which has the corresponding BOL entity. The Business Partner header data has the BOL entity BuilHeader. Add the model node PARTNER with that BOL Entity. Add Value Node: we need a value node for our z-table (which will become a node for a table in Select View Type). Simply type a name for the node. Add Model Attributes to Model Node: here we decide which attributes of the partner (header data) we would like to have. In our case we only need the partner number. Add it with the plus-icon. Add Value Attributes to Context Node: here we have to add every component (field) of our table. This is best done with the plus-icon. Choose the correct Context Node (the Value Node for the z-table) and type in the structure we created in Step 1. Press enter, mark all attributes and add them. Select View Type: choose View Type "Table View" and the Context Node we created for the z-table in Add Value Node.
Add View to Window: Open the Window node, find your window, right click on it and choose Add View. Select the view you created in Step 3. Add Window to Component Interface: Open the Component Interface node, right click on Interface View and choose Add. Select your Window and View. Add Component Usage: Open the Component Usages node, right click on Component Usage and choose Add Interface View. Select the Interface View you added above.
Double click the View we've created in Step 3. Open the node Context and double click on the Context Implementation Class. Locate the method CREATE_PARTNER (Model Node) and go into its coding. Add the binding to the Component Controller at the end of the method as shown below:
Context Class: ZL_ZBP_FAVS_ZBPFAVORITES_CTXT Method: CREATE_PARTNER * data binding with Component Controller 'PARTNER' owner->do_context_node_binding( iv_controller_type = cl_bsp_wd_controller=>co_type_component iv_target_node_name = 'PARTNER' iv_node_2_bind = partner ).
Now we have to call this Event Handler. Go into the Context Class (just like in Step 5) and open the coding of method CREATE_ZBP_FAVS (Value/Table Node). Add the call of method ON_NEW_FOCUS depending on the Model Node as shown below:
Context Class: ZL_ZBP_FAVS_ZBPFAVORITES_CTXT Method: CREATE_ZBP_FAVS * dependent node settings coll_wrapper = partner->get_collection_wrapper( ). TRY. entity ?= coll_wrapper->get_current( ). CATCH cx_sy_move_cast_error. ENDTRY. IF entity IS BOUND. zbp_favs->on_new_focus( focus_bo = entity ). ENDIF.
ls_smof_erpsh
if_bol_bo_col, cl_bsp_wd_value_node, zbp_favs_s, " table zbp_favs_tab, " local zbp_favs_s. " local
" collection to fill node ZBP_FAVS " value nodes to fill a collection line reference to fill value node table with data from ERP-table ZBP_FAVS structure of table above
* get partner entity and partner number try. lr_entity ?= focus_bo. catch cx_sy_move_cast_error. return. endtry. lv_bp_nr = lr_entity->get_property_as_string( 'BP_NUMBER' ). if lv_bp_nr is initial. " no partner... return. "...return without selection endif. * get RFC destination of ERP system, if needed if ZL_ZBP_FAVS_ZBPFAVORITES_IMPL=>gv_destination is initial. call function 'CRM_GET_ERP_SYSTEM' * exporting * iv_rfcdest = * iv_siteid = importing es_smof_erpsh = ls_smof_erpsh. if sy-subrc = 0 and ls_smof_erpsh-rfcdest is not initial. ZL_ZBP_CUCL_ZCURRENCYCLAU_IMPL=>gv_destination = ls_smof_erpsh-rfcdest. endif. endif. * get favorite things for partner lv_partner = lv_bp_nr. " call RFC function in ERP system call function 'Z_CRM_GET_FAVS_FOR_BP' destination ZL_ZBP_CUCL_ZCURRENCYCLAU_IMPL=>gv_destination exporting iv_partner = lv_partner importing et_favs = lt_favs exceptions others = 4. if sy-subrc <> 0. " should never happen endif. * create collection object to transfer data create object lr_col type cl_crm_bol_bo_col. * loop through all found data... loop at lt_favs into ls_favs. "...create line object create data lr_tabline. "...create value object with current line for colleciton create object lr_valuenode exporting iv_data_ref = lr_tabline. "...set current line data lr_valuenode->set_properties( ls_favs ). "...add current line to collection lr_col->add( lr_valuenode ). endloop. * set collection me->set_collection( lr_col ).
9. Display data
Unfortunately we're not done yet. I don't know why, but the standard created HTML-page doesn't display the Table Node we filled with a data collection in Step 8. Therefore I programmed my own workaround. Go to the HTML-page which is located under View Layout. Double click to get into the HTML editor. Please note: the html-table you'll find in the coding below _considers the user's Layout settings_ but it's not the official coding - just something I figured out myself.
View (HTML): ZBPFavorites.htm <%@page language="abap"%> <%@ extension name="htmlb" prefix="htmlb"%> <% * data definitions ***************************************************** data: lr_wrapper type ref to cl_bsp_wd_collection_wrapper, lr_entity type ref to if_bol_bo_property_access, lt_favs ls_favs lv_value type type type zbp_favs_tab, zbp_favs_s, string. any.
* fill local Currency Clause table ************************************* " get collection wrapper lr_wrapper = zcucl->get_collection_wrapper( ). if lr_wrapper is bound. " get first entity... lr_entity = lr_wrapper->get_first( ). "...then loop through all entities while lr_entity is bound. " Partner number assign component 'PARNR' of structure ls_favs to <fs_favs>. try. lv_value = lr_entity->get_property_as_string( 'PARNR' ).
catch cx_sy_conversion_error . endtry. <fs_favs> = lv_value. " Color assign component 'COLOR' of structure ls_favs to <fs_favs>. try. lv_value = lr_entity->get_property_as_string( 'COLOR' ). catch cx_sy_conversion_error . endtry. <fs_favs> = lv_value. " Meal assign component 'MEAL' of structure ls_favs to <fs_favs>. try. lv_value = lr_entity->get_property_as_string( 'MEAL' ). catch cx_sy_conversion_error . endtry. <fs_cucl> = lv_value. " Sport assign component 'SPORT' of structure ls_favs to <fs_favs>. try. lv_value = lr_entity->get_property_as_string( 'SPORT' ). catch cx_sy_conversion_error . endtry. <fs_favs> = lv_value. " add favorites to local table append ls_favs to lt_favs. " get next entity lr_entity = lr_wrapper->get_next( ). endwhile. endif. %> <% * display BP Favorites table ************************************************** %> <table class="th-tv th-tv-table"> <% loop at lt_favs into ls_favs. if sy-tabix = 1. %> <!-- table header --> <thead class="th-tv-header"> <tr> <!--<th class="th-clr-cel th-tx-header1"><%= otr(ZCRM/Partner) %></th>--> <th class="th-clr-cel th-tx-header1"><%= otr(ZCRM/Color) %></th> <th class="th-clr-cel th-tx-header1"><%= otr(ZCRM/Mail) %></th> <th class="th-clr-cel th-tx-header1"><%= otr(ZCRM/Sport) %></th> </tr> <!-- end of table header --> </thead> <!-- table body --> <tbody> <% endif. %> <tr> <td class="th-ip-td1 th-tv-cel-txt"><%= ls_favs-color %></td> <td class="th-ip-td1 th-tv-cel-txt"><%= ls_favs-mail %></td> <td class="th-ip-td1 th-tv-cel-txt"><%= ls_cucl-sport %></td> </tr> <% if sy-tabix = sy-tfill. %> <!-- end of table body --> </tbody> <% endif. endloop. if sy-subrc <> 0. %> <tr> <td class="th-tv-noresult"> <img src="images/infoMessage.gif" border="0"> <span><%= otr(ZCRM/noResults) %></span> </td> </tr>
<%
Added by Florian Wunderle, last edited by Stephen Johannes on Mar 25, 2010 (view change)
This was developed on CRM 2007 and may work on CRM 4.0 A quite common problem in the last projects was the lack of standard functionality to copy trees of BOL nodes dynamically. This is for example necessary when editing sales area data of business partners. Sales Area data often contains many fields or tables which have to be maintained for each Sales Area. The most of the fields are however similar for more than one sales area and it might be interesting to copy the values from one Sales Area to another. This example shall explain how to copy the data from one object to another. Declares the local data:
TYPES: BEGIN OF ltype_child_object, parent TYPE crmt_ext_obj_name, relation TYPE crmt_relation_name, objects TYPE REF TO if_bol_entity_col, END OF ltype_child_object. DATA: lr_entity TYPE REF TO cl_crm_bol_entity, lr_obj_to_copy TYPE REF TO cl_crm_bol_entity, lr_orig_rel TYPE REF TO if_bol_entity_col, lr_child_ent TYPE REF TO cl_crm_bol_entity, lr_header TYPE REF TO cl_crm_bol_entity, lv_index TYPE int4, ls_sales_area TYPE crmt_bus_sales_area, lt_return TYPE bapiret2_t, ls_return TYPE bapiret2, lr_object_model TYPE REF TO if_genil_obj_model, lr_object_model_ TYPE REF TO cl_crm_genil_obj_model, lr_relations TYPE REF TO crmt_relation_name_tab, lv_rel_name TYPE crmt_relation_name, lt_relations TYPE crmt_relation_name_tab, lt_components_loaded TYPE genil_component_tab, ls_child TYPE ltype_child_object, lt_children TYPE TABLE OF ltype_child_object, lr_rel_ent TYPE REF TO cl_crm_bol_entity, lv_att_struc_name TYPE strukname, ref_rowtype TYPE REF TO cl_abap_structdescr, lv_relname TYPE crmt_relation_name, lv_is_11 TYPE crmt_boolean, ref_wa TYPE REF TO data. FIELD-SYMBOLS: <attr> TYPE ANY, <value> TYPE ANY TABLE.
Gets the components loaded and fetches the sub relations and assignes it to relations table
lr_object_model = cl_crm_genil_model_service=>get_runtime_model( ). lr_object_model_ ?= lr_object_model. lt_components_loaded = lr_object_model_->get_components_loaded( ). lr_relations = lr_object_model->get_modeled_relations( iv_object_name = 'BuilSalesArrangement' ). ASSIGN lr_relations->* TO <value>. lt_relations = <value>.
Now we have to fill the newly created object and create child objects containing the copied values from the original object. In order to do this two loops can be used: First loop through all possible sub objects and loop in a inner loop throught the entities in the entity collection
LOOP AT lt_children INTO ls_child. lr_rel_ent ?= ls_child-objects->if_bol_entity_col~get_first( ). WHILE lr_rel_ent IS BOUND. * get relation name lr_rel_ent->get_parent_relation( IMPORTING ev_relation_name = lv_relname ev_relation_is_11 = lv_is_11 ). get the name of the structure of the BOL object and create a new field symbol with this type lv_att_struc_name = lr_rel_ent->get_attr_struct_name( ). ref_rowtype ?= cl_abap_typedescr=>describe_by_name( lv_att_struc_name ). CREATE DATA ref_wa TYPE HANDLE ref_rowtype. ASSIGN ref_wa->* TO <attr>. get properties of subobject into field symbol lr_rel_ent->if_bol_bo_property_access~get_properties( IMPORTING es_attributes = <attr> ). create new subobject for copied sales organization with the original values lr_child_ent = lr_entity->create_related_entity( iv_relation_name = lv_relname ). lr_child_ent->set_properties( <attr> ). lr_rel_ent = ls_child-objects->if_bol_entity_col~get_next( ). ENDWHILE. lv_index = typed_context->builsalesarrangement->collection_wrapper->size( ). ENDLOOP. ENDIF.
* *
* *
Attachments:11 Added by Tzanko Stefanov.., last edited by Tzanko Stefanov.. on Oct 01, 2009 (view change)
If you are not new to SAP CRM, you might already know some of the tools related to customer enhancements. The enhancement set concept can be used to redefine and enhance existing UI components. If you are not happy with the layout of a given view, you can change it via the UI configuration tool. Both of these tools offer modification free means of altering the default delivery as per the customer's needs. It is also worth mentioning that customers can add new fields to existing CRM applications. My previous blogs on the application enhancement tool (you can find them here) covers that topic in details. Therefore, in this guide, I will focus on the other (non-structural) enhancement tools. A common task that our customers often face is to adjust the semantics of the CRM applications so that they fit better their business domain and terminology. Both the configuration tool and the enhancement sets address the required UI layer adjustments. However, they do not tackle one important aspect - the corresponding message texts. Luckily, SAP CRM 7.0 offers a remedy called message replacement. In this guide, I will walk you through the above scenario. If you are new to SAP CRM, you will have the chance to get a quick introduction into the above mentioned UI framework tools. Those of you who are already familiar with enhancement sets and view configurations will learn about the new message replacement tool. I will also briefly mention how the existing tools have been improved in CRM 7.0.
As per the above screenshot, we need to enhance the MainWindow of the CPG_MAIN component. Now, let's go to the component workbench and create an enhancement set for the CPG_MAIN component. As you probably already know, an enhancement set groups several enhanced components and contains the enhancement definitions that show which components were altered. If you need more information on the topic, please refer to the user documentation. The component workbench in SAP CRM 7.0 comes with some usability improvements that facilitate the creation and manipulation of enhancements. For example you can create (or delete) an enhancement set in the workbench, as soon as you need one and without navigating
away.
As per our example, we will create an enhancement for the CPG_MAIN component and redefine the MainWindow's controller. While executing these tasks, you will notice that in CRM 7.0 you can access the enhancement set definition repository directly in the workbench - from the System menu.
In CRM 7.0 you could delete not only enhancement sets, but also component enhancements - again without leaving the component workbench. For simplicity reasons, I have implemented a very rudimentary redefinition of the GET_STATE_DESCRIPTION method. I have substituted the 'Campaign' string (I happen to know its OTR's alias) with 'Tactics'.
If you go back to the Web UI and open a corporate account, you will see that it reads 'Tactics now.
However, the names of two assignment blocks still refer to "campaign". In addition, a column header in the campaign elements block needs to be modified as well.
Configuring the UI
As you already know, the UI configuration tool allows SAP CRM customers to adjust the user interface as per their corporate identity and business needs. In our example, we will use it to rename two assignment blocks and change a column header in one of them. In CRM 7.0 we have improved the usability of the configuration tool. For example, you can drag and drop fields in an intuitive way.
SAP recommends that you always create a copy of the SAP delivered configurations and implement your changes there. You need to go into the view configuration of the tactics element assignment block and change the column header to 'Tactics Element'.
Replacing Messages
Your might be tempted to think that you are done. However, there are messages that refer to campaign. For example, if we have a tactics/campaign element that is not assigned to a workflow, you might get a warning message that says 'No workflow is assigned to a campaign element with successor'.
In the past, in order to change the message text, you would have to change the code itself. This was not a modification free way of customizing the system. As a result, you had to maintain your changes with each upgrade.
As of CRM 7.0, the UI framework offers a new feature that supports message replacement. It is available in IMG (and in the component workbench).
First, you need to define a message replacement profile. In our example we will use DEFAULT. Next, you need to redefine the original message with a new one.
The message replacement is business role "sensitive". You need to assign the message replacement profile name to the business role that needs to be affected by the message texts changes. In order to do so, go to Define Business Role in IMG and add a function profile MSG_REPLACE and set its value to the corresponding message replacement profile (DEFAULT as per our example).
If you try to invoke the same warning message now, you will get the new message text.
Summary
The example presented above was quite simple, but it puts into perspective three powerful concepts: enhancement sets, view configuration and message replacement. While the first two have undergone a relatively minor "facelift" in CRM 7.0, replacing messages is a new feature. Those of you who are new to CRM should note that the enhancement set concept allows you to do a lot more than changing texts. You can alter buttons, navigations, views, and much more. Most importantly, your enhancements are "modification free". In this guide I have just scratched the surface of this powerful tool, but feel free to read and experiment further.
Labels
Session Management
Business applications use a stateful protocol with a dedicated client (GUI). This allows server sessions to be terminated correctly and all server resources (for example, memory) are released when the client closes the session, for example, by logging off from the portal. If an application runs on the Web, the connectionless HTTP protocol works in request/response cycles and does not check if the client has already terminated the session. In this scenario the server sessions and resources of the business application are usually released after a predefined timeout (about 5-10 minutes). This delay can cause the following situations: Servers can become overloaded and run out of resources by sessions that have already been terminated.
Locks for the application are held until timeout. In some cases an application can be deadlocked even if there are many servers available. The SAP Internet Session Protocol (SISP) included in the SAP Workplace 2.10 overcomes this problem.
A termination command is HTTP request from the client to the ITS. Since the applet can only connect to the server from which it is loaded, you must have the same applet on every ITS. To overcome this problem the applet code should be loaded from the Workplace Middleware Server. Instead of sending the termination commands from the DSM directly to the ITS, the commands are sent to the dedicated portal component Terminator. TheTerminator component finally distributes the commands to the ITS.
Components
Server: ITS server/ ITS services
No modifications are necessary for the ITS; the customer can use the existing ITS transactions in Workplace 2.10/Workplace 2.11 and integrate them into the new portal by customizing the Launcher component
... ...
1. 2.
The EPCM Object includes the DSM Interface and DSM Applet in the portal page. The Launcher creates the LaunchURL for the ITS service and includes the IFrame in the portal page. There is an instance of the Launcher in the portal page for every IFrame that points to a different ITS service. 3. The page is processed in the browser. Every IFrame generated loads its contents from the ITS. The ITS returns the content page with the generated SISP Code as the response to LaunchURL. The SISP Code creates theSessInfo object and transfers it to the main page. 4. SessInfo objects are collected by the DSM Interface, transferred to the DSM Applet and stored in the applet. 5. If the user navigates to another location, closes the browser or chooses the Back button in the browser, the registered ITS sessions become invalid and must be terminated. The browser triggers the unload event and the DSM Applet starts to process its own destroy() method. 6. The destroy() method of the DSM Applet computes the URL to terminate the sessions on the ITS for every SessInfo object stored. All URLs are collected and placed into one single HTTP post request (parameterTermString) and sent to the Terminator component. 7. The Terminator component splits the TermString parameter from the HTTP request into single URLs and sends the URLs to the different ITS servers with a new URLConnection. The server sessions on the ITS are then terminated. 8. Every SessInfo object is reported by the EPCF to the DSM.
... ...
1. 2.
3.
4. 5.
6.
The EPCM Object includes the DSM Interface on the portal page. The event handler in the DSM Interface is attached to the onunload event. The Launcher creates the LaunchURL for the ITS service and includes the IFrame into the portal page. There is an instance of the Launcher in the portal page for every IFrame that points to a different ITS service. The page is processed in the browser. Every IFrame generated loads its contents from the ITS. The ITS returns the content page with the generated SISP Code as the response to the LaunchURL. The SISP Code creates the SessInfo object and transfers it to the main page. SessInfo objects are collected by the DSM Interface and stored in a JavaScript array. If the user navigates to another location, closes the browser or chooses the Back button in browser, the registered ITS sessions become invalid and must be terminated. The browser fires the unload event. The onunload event handler creates an External Window, in addition to the existing portal page, with the URL of the Terminator component. The browser sends a HTTP get request (parameter TermString) to theTerminator. After the request has been sent the External Window can be closed automatically using the JavaScript timeout function.
7.
The Terminator component splits the TermString parameter from the HTTP request into single URLs and sends the URLs to the different ITS servers with a new URLConnection. This terminates the server sessions on the ITS. 8. Every SessInfo object is reported by the EPCF to DSM.
Scripts
Here are some scripts that are used for the session management. The different examples refer to the steps, for example Step 1, shown in the previous section Session Management Step by Step.
// --------------------------------------------------------------------------function SAPWF_sendSessInfo( cltSessInfo ) { var lsDomain = ""; var liBehindFirstDot = location.hostname.indexOf( "." ) + 1; if (liBehindFirstDot > 0) { document.domain = location.hostname.substr( liBehindFirstDot ); } var loCF = window; // current frame var loPF = (loCF.opener != null)? loCF.opener: loCF.parent; // parent fra me while (loCF != loPF) { // while top frame not reached if ("object" == typeof( loPF.document ) ) { // is parent frame scriptable ? if (loPF.SAPWP_receiveSessInfo != null) { // workplace frame found, deliver sessinfo loPF.SAPWP_receiveSessInfo( cltSessInfo, loCF ); return true; } else { // try upper frame loCF = loPF; loPF = (loPF.opener != null)? loPF.opener: loPF.parent; } } else { // access to foreign frame denied, stop here return false; } } // top frame reached, but no workplace frame found return false; } function SAPCLT_SessInfo() { var prot = ( "off" == "on" ? "https://" : "http://" ) ; this.protocolVersion = "1.0"; this.sessUrl = prot + "pgtlsp4c.wdf.sap-ag.de:1080" + "/scripts/wgate" + "/" + "fielddump" + "/?~session="+"QW2-A:pgwdf062:0000.0040.afa108fd"; this.GUSID = "QW2-A:pgwdf062:0000.0040.afa108fd"; this.lastSessCmd = "USR_OPEN"; this.redirectURL = ""; this.dTimeout = "120"; } SAPWF_sendSessInfo( new SAPCLT_SessInfo()); </SCRIPT>
Allows you to check the Public API functions and displays the SessInfo object list and other information. Both components must be included on the same portal page for the test. The DSMTestLaunch component properties must be configured to start an ITS service. As already shown in the section Session Management Step by Stepthe transfer of the SessInfo objects is processed in several steps. The DSM component can test Step 4, Step 5 and Step 6 even if the ITS is not available. The DSM component can be started in single component mode with the following URL: <Portal_URL>/irj/ servlet/prt/portal/prtroot/com.sap.portal.dsm.Monitor The test results of the session termination are displayed on the Java console of the browser (browsers with Java support) or on the External Window after the resize of the window is done (browsers with no Java support).
1.
ITS did not include the SISP coding stub into the response Check if the service parameter SAPWP_ACTIVE is set in ITS. You can add to the LaunchURL following string: SAPWP_ACTIVE=1 The ITS server and Workplace server use different domains The typical local test installations at SAP do not have a specific IP address. The Workplace Server can be accessed using localhost instead of a specific server name or IP address (for example,http://localhost:8080/irj/servlet/prt/portal) and the ITS server uses a server name like itsserver.wdf.sap-ag.de. This does not comply with the JavaScript origin policy and therefore the DSM can not display a SessInfo object. To solve this problem, use a specific IP-address for the computer or define a synonym in the hosts file of the computer (for example, Windows NT keeps that file at location C:\WINNT\system32\drivers\etc\hosts). The entries for the synonym look like that: 127.0.0.1 localhost 127.0.0.1 myhost.wdf.sap-ag.de Now you can access your Portal Runtime (PRT) from your computer locally using the address: http://myhost.mycomp.com/irj/servlet/prt/portal
2.
The name myhost.wdf.sap-ag.de is only known on your local computer and can not be accessed from another computer.
See also
SessInfo Object Properties DSM API Terminator Component
EPCM.DSM.processSession (sessInfo)
This method is the entry point for the session management (handler for SAPWP_receiveSessInfo).
EPCM.DSM.notifyMonitor (sessInfo)
This method notifies the DSM when the new SessInfo object is available. Parameter Description Parameter sessInfo Type Object Description SessInfo object.
EPCM.DSM.registerSession (sessInfo)
This method registers the SessInfo object. Parameter Description Parameter sessInfo Type Object Description SessInfo object.
EPCM.DSM.removeSessionByGUSID (gusid)
This method removes the SessInfo object associated with the Global Unique Session ID (GUSID) from the register. Parameter Description Parameter gusid Type String Description GUSID.
EPCM.DSM.teminateByGUSID (gusid)
This method terminates the sessions associated with GUSID and removes them from the register. Parameter Description Parameter gusid Type String Description GUSID.
EPCM.DSM.teminateAll ()
This method terminates all registered sessions and clears the register.
EPCM.DSM.getAllToArray ()
This method makes a copy of all active SessInfo objects in a JavaScript Array object. The SessInfo objects can be used and processed by the client application.
EPCM.DSM.getSize ()
This method returns the number of registered SessInfo objects in the DSM.
Terminator Component
The Terminator component sends HTTP request to servers, to terminate the registered sessions.
Basic functions
The Terminator component receives a HTTP request (either get or post), with the parameter TermString, TermString contains escaped URLs concatenated with an ampersand (&).The special characters must be escaped (see JavaScript functions escape/unescape) so that the URLs are transmitted correctly. Format of the parameter TermString: escaped(escaped(URL1)+"&"+escaped(URL2)+"&"+...escaped(URLn)) The Terminatorcomponent splits und unescapes the TermString parameter into single URLs and sends for every of them one single HTTP post request to the target system (usually ITS). The portal uses by default the portal component DSMTerminator as Terminator component. You can customize this component or define another component or portal component as Terminator component.
validationEnabled=<true|false>
trustedHosts=<host_name_list>
restrictedHosts=<host_name_list>
cookieThroughEnabled=<true|false>
The DSMTerminator component can also be used standalone by specifying the URL of the DSMTerminator component (<Portal_URL>/irj/servlet /prt/portal/prtroot/DSMTerminator.default ) with following parameters:
DSMTerminator Parameter Property Description Optional parameter specifies all URLs to which the requests should be distributed. If the parameter not specified or empty, no request is distributed.
TermUrl=<String>
Autoclose=<positive_Number>
Optional parameter that specifies the delay before the External Window (used for browsers with no Java support) is closed. If not specified, the External Window will not be closed. Optional parameter that specifies how the single responses returned after the request distribution should be handled by the DSMTerminatorcomponent, when the final (collective) response is assembled. COPY The single responses are copied into the collective response. ESCAPE Is similar to COPY but all special characters will be converted (escaped) so that the string is properly displayed on the HTML page. NOCOPY The single responses are not copied into the collective response. If the parameter is not specified, the NOCOPY option is selected.
EPCF Configuration
To configure the EPCF service you have to be logged in as administrator. Configuration steps:
...
1. 2. 3. 4. 5.
Choose the command System Administration in the top level navigation. Choose the commands System Configuration Service Configuration Choose the Browse tag and open the node Applications. Open the node com.sap.portal.epcf.loader. Open the subnode Services and you will see the entry epcfloader.
6. Click the epcfloader entry with the right mouse key and select Edit. The property page is displayed and you can modify the values. To save the changes, choose the Save button.
If you are working in a cluster environment, you have to restart the EPCF service so that the changes take immediate effect on all cluster nodes. If the EPCF property values are not set correctly, the EPCF service uses the default settings at runtime. EPCF Properties Property Description Defines if the classes of the Java applet are transferred as single class files or in one Java archive (JAR). This setting has only an affect if theframework.level property is set to 2. on: All classes are loaded from the server to the client in one JAR file. off: Every class is loaded from the server to the client individually. For a productive system we recommend the valueon.
This setting only has an affect if theframework.level property is set to 2. The applet.trace.level controls the level of error messages displayed. A higherapplet.trace.level reduces the portal performance. 0: Display errors only. 1: Display errors and warnings. 2: Display errors, warnings and information. For a productive system we recommend the value0.
Defines the EPCF service level in use. Please refer to section EPCF Level for more details. The default setting is 2.
See also
Work Protect Mode for EP 6.0 Properties for EP 5.0
The portal application sets the dirty indicator when the user enters a new value into an input field. The portal application resets the dirty indicator when the user saves the value (for example when the user chooses theSave button). See section WorkProtect and Cross Navigation APIfor more details.
Configuration Test
Test tool: com.sap.portal.epcf.loader.Dirty The test tool supports the tracing and solving of problems related to the dirty indicator. You can find the tool under
The portal application sets the dirty indicator when the user enters a new value into an input field. The portal application resets the dirty indicator when the user saves the value (for example when the user chooses theSave button). See section WorkProtect and Cross Navigation APIfor more details.
Configuration Test
Test tool: com.sap.portal.epcf.loader.Dirty The test tool supports the tracing and solving of problems related to the dirty indicator. You can find the tool under
Added by Satish Reddy Palyam, last edited by Satish Reddy Palyam on Jul 09, 2011
Print & Print Preview is supported by SAP only for SAP Smartforms. Its really strange for me why SAP does not have any standard approach for providing Adobe forms on WebUi, some how it works in SAPGUI of SAP CRM. Adobe forms are more interactive and much intuitive and easy to create, modify, update forms. It has slight edge over smart forms. May be SAP will come up in future to support adobe forms in CRM webui. But as of CRM 7.0 EHP1 this is not available. I did put up my own efforts to crack through this requirement and finally came up with impressive solution which is quiet easy to implement. The actual SAP Smart forms required Actions to be defined and implemented, where as in my approach of adobe forms action definitions are NOT required. Here we go.. Steps in nutshell:
1.
1. 2. 3. 4. 5.
Enhance the underlying Event Handler method of the Print Preview Button, UI Component BT112H_SC (service contract) Create a BSP ICF Service, similar to the standard print service CRM_PDF_PRINT, call it as ZCRM_PDF_PRINT In the even handler method (Step 1), construct the URL based on the Service defined in Step 2 and call the popup. Set up a Handler class for the service defined in Step 2, call it as ZCL_CRM_PREVIEW_PDF (Prototype CL_CRM_PREVIEW_PDF) In its handler method, call the method which is responsible to bring the pdf output in Xstring format. Set the pdf content to the response of the service with the application as pdf.
Lets discuss the above steps in more detail fashion.. Please refer my blog for more details.
Purpose
To provide Print Preview with SAP Adobe forms of the any Business Transaction (here I have taken Service Contract)
Print & Print Preview is supported by SAP only for SAP Smartforms. Its really strange for me why SAP does not have any standard approach for providing Adobe forms on WebUi, some how it works in SAPGUI. Adobe forms are more interactive and much intuitive and easy to create, modify, update forms. It has slighe edge over smart forms. May be SAP will come up in future to support adobe forms in CRM webui. But as of CRM 7.0 EHP1 this is not available. I did put up my own efforts to crack through this requirement and finally came up with impressive solution which is quiet easy to implement. The actual SAP Smart form required Actions to be defined and implemented, where as in my approach of adobe forms action definitions are NOT required.
1. Enhance the underlying Event Handler method of the Print Preview Button, UI Component BT112H_SC
(service contract) 2. 3. 4. 5. 6. Create a BSP ICF Service, similar to the standard print service CRM_PDF_PRINT, call it as ZCRM_PDF_PRINT In the even handler method (Step 1), construct the URL based on the Service defined in Step 2 and call the popup. Set up a Handler class for the service defined in Step 2, call it as ZCL_CRM_PREVIEW_PDF (Prototype CL_CRM_PREVIEW_PDF) In its handler method, call the method which is responsible to bring the pdf output in Xstring format. Set the pdf content to the response of the service with the application as pdf.
Enhance the UI Component BT112H_SC (Service Contract Header) in component Work Bench. Please choose your own component header according to the transaction type.
concatenate 'scenario=P&guid=' lv_adminh_guid into lv_query. * get URL lv_url = cl_crm_web_utility=>create_url( iv_path = '/sap/crm/zcrm_pdf_print' iv_query = lv_query iv_in_same_session = 'X' ).
URL will have to set up in the ICF service, this we will see in further steps. Create a popup with the help of window controller and make use of standard URL POPUP Interface View. lr_popup = me->comp_controller->window_manager->create_popup( iv_interface_view_name = 'GSURLPOPUP/MainWindow' iv_usage_name = 'CUGSURLPopup' iv_title = lv_title ). Set the URL paramaters like Header_guid which will be retrived in the service handler class later. lr_cn = lr_popup->get_context_node( 'PARAMS' ). Set up Popup configuration Settings like ls_params-url = lv_url. ls_params-height = '800'. ls_params-width = '800'. lr_obj->set_properties( ls_params ). lr_popup->set_display_mode( if_bsp_wd_popup=>c_display_mode_plain ). lr_popup->set_window_width( 820 ). lr_popup->set_window_height( 800 ). lr_popup->open( ).
Define a Handler class to it like ZCL_CRM_PREVIEW_PDF, make of template method in standard class CL_CRM_PREVIEW_PDF
"#EC NOTEXT
Call multiple forms in desired order of sequence and attach the same using the following class: p_dest = cl_fp=>get_ads_connection( ). * Get FP reference. l_fp = cl_fp=>get_reference( ). * Create PDF Object. l_pdfobj = l_fp->create_pdf_object( connection = p_dest ).
* *
Set document. l_pdfobj->set_document( pdfdata = fp_out ). Set attachment. concatenate 'Attachment' sy-uzeit into l_attachment-name separated by space. concatenate 'Cover_letter' 'pdf' into l_attachment-filename separated by '.'. l_attachment-mimetype = 'application/pdf'. l_attachment-description = l_attachment-name. l_attachment-data = fp_2. insert l_attachment into table l_attachments. l_pdfobj->set_attachments( attachments = l_attachments ). Execute, call ADS.
l_pdfobj->execute( ).
Get result. l_pdfobj->get_document( importing pdfdata = fp_out ). Finally, export the PDF data in Xstring to the Handler method defined above.
Subscri be Print Permali nk Share
In this issue of the UI Framework News, I would like to introduce you to the F4-help and make you aware of some precautions to consider: One of the common tasks for a CRM developers / consultants is to provide a F4-help for a business object attribute displayed in his/her CRM component. F4-help allows the user to select a valid entry from a popup. Depending on the output mapping the F4-help can fill in one or more fields on the form it was launched from. The valid entries available in the F4-help popup depend on the input mapping provided. For more details about input mapping and output mapping read the how-to document about F4 An object that contains a F4-help would look as below.
Pressing on the icon will open a popup and until the popup is open user will not know what kind of an F4-help it is as there are two main types F4-helps, which could be used in the business object.
Advanced Value Help (Which the user has the possibility to filter the results)
Implementing the F4-help is not as user intuitive the first time around compared to the other UI elements. The consultant has to either redefine the get_v method in the component work bench or provide the F4-help tag attributes (helpId, etc) to the inputField tag in a freestyle mode. More details on how to implement a F4-help can be found here. Please be aware that the F4-help should be used with care to avoid situations such as:
Making sure that opening F4-help does NOT require opening subsequent F4-helps. The number of columns displayed in the result table should be the most significant columns from the users perspective to avoid larger popups which are not as user friendly. Also consider using a drop down list box instead of a F4-Help in cases where the number of rows is small as the DDLB is easier and quicker for the user.
Subscribe
ABOUT FIELD DESCRIPTION IN THE CRM WEB UI. The Controller class of the View (the one following the ...IMPL pattern) handles various tasks, amongst which the specification of the description text for each field rendered on the View, including table header texts. In the CRM Web UI, starting from CRM 6.0 onwards, the description of a field can have multiple origins.
When the Attribute of the context node is attached to a BOL object, it is a so called Model Attribute; the defaulted description is inherited from the Data Dictionary of the corresponding structure attached to the BOL Object. When the Attribute of the context node is created locally, meaning in the application, it is so called a Value Attribute; the defaulted description is defined in the Wizard at the time you create this new Attribute.
These descriptions are defaulted and can be overwritten in different ways, sequenced hereafter by priority (increasing order).
1. The description can be overwritten in the configuration of the view. A simple yet efficient way to customize your view with the field labels of your organization. 2. The description can be overwritten by a Design Layer object, a convenient method to maintain a description centrally, across various views or even applications. 3. The description can be overwritten via the code logic of the view's Controller class. Though this method requires (a bit of) Abap knowledge, it allows you to play with your description dynamically.
This blog approaches the latter way of overriding the description of Attributes. CASE STUDY. In SAP implementations, my thoughts obviously firstly go for less coding as possible, though sometimes like these it can bring even more flexibility in the handling of your application. To illustrate the case, I come up with a customer requirement where a dedicated View contained a list of business transaction documents meant to be maintained altogether; a mass maintainance tool allowing the user to easily adapt the status and the partners of up to 6 partner functions. The tricky part was that the chosen 6 partner functions could be adapted via a customizing table. The column header text could not be stored statically, rather determined according to the setup of the customizing.
HOW TO.
"Rules on OCA apply only in case you are using table/cellerator view configuration. The THTMLB table/cellerator view tag itself does not support any One Click Actions."
CASE STUDY.
In our previous blog, https://www.sdn.sap.com/irj/scn/weblogs?blog=/pub/wlg/15603 we approached a case where a Web UI application was built from scratch to meet a particular customer requirement regarding the mass maintainance of business documents. We will keep this sample case to illustrate the use of OCA. The application
enables the user to updates the informations regarding the status and the partner profiles, then saves all document at once. We consequently expect all documents to be successfully saved with the updated information, but circumstances may lead to a situation where several documents cannot be saved. The logical unit of work is the document, meaning each document is saved disregardless of what happens with the other documents. In this context, the idea about the use of OCA came up with a need to get a status of the processing for each document. An icon is shown besides each row where a problem occurred. Clicking on the icon provides the user with a description of the error encountered, this information is embedded into popup window.
HOW TO.
In the Web UI Infrastructure, the Table list is handled as a Context node of type table. Though the definition of the OCA in terms of look, feel and action is location on the context node class, the event it triggers is handled on the level of the Controller like other classical view events.
. Create the Getter method GET_THTMLB_OCA for your new field (take any Getter method as a sample). . Create the Property method GET_P_THTMLB_OCA (copy the template method _GET_P_XYZ). Feed the method with the code below. This method declares the behaviour of the new Attribute THTMLB_OCA as a One-click Action and also specifies the releted Controller Event to call.
. Once an Attribute is declared as a One-click Action, an OCA Getter is systematically called to further define its properties. This extra getter method GET_OCA_T_TABLE is already available on the Context node class. We redefine the method to specify the Icon or Text of any OCA and the associated Id used to identify which OCA is hit by the user. Extra settings include the Tooltips, and the (de)activation of the OCA. This method offers an Index parameter IV_INDEX to locate the row currently processed. In the sample code below, we stored all errors in a global attribute table GT_MessageBoard, the method checks whether a message is available for our row and displays the icon accordingly.
2. Controller setup
. We now define the processing of the Event, that is, what happens once the user hits the icon. What happens here is up to your imagination (which most of the time is constrained by your customer's requirements). In this case study, as explained above, the event displays a popup window to show the message collected on the processing of the row. At the declaration of the OCA attribute above, we assigned the event _ONE_CLICK_ACTION, we now create an Event Handler method EH_ON_ONE_CLICK_ACTION with the sample code provided hereafter. The logic retrieves the Icon Id (which Icon hit) and the row index (which row considered) from the available HTMLB import parameter (HTML Business Java).
CRM WEB UI Technical- How to read one context node data in other context node ?
Applies to:
SAP CRM WEB UI Framework version CRM2007 and CRM7.0
Attachments:7 Added by Suchita Phulkar, last edited by Moshe Naveh on Oct 03, 2010 (view change)
Summary
This article explains about a technique that can read/modify one context node attributes from some other context node attribute's methods like GETTER-SETTER methods or any other method of context node class (i.e. CNxx class). The beauty of this technique is no need to code in Controller class ( IMPL class) .
Author(s):
Company: Q2Con ApS, Copenhagen, Denmark Created on: Author(s) Bio Suchita has been working in SAP CRM domain from 5+ years and have worked on almost all SAP CRM versions from 4.0 till 7.0 including CRM2007 with Innovative and Extremely quality conscious approach and a great eye for analytical details. She is experienced on several SAP CRM Implementation projects globally & also have been awarded for some of her project executions. Her areas of experties include SAP CRM 2007 & CRM7.0 WEB UI Customizations and developments using BOL-GENIL programming, ABAP, OOABAP & BSP programming. 29.09.2010
One common requirement in WEB UI is to exchange the data between different context nodes of a view. We generally need to exchange the data (basically attribute values) in situations where value of one context node attribute depends on the other context node attribute. I have often found that technical consultants achieve this in View Controller class - IMPL class because it has access to all context nodes through TYPED_CONTEXT attribute. Following is a sample code that illustrates this approach : Here we are required to set some attribute, say ATTR2 (Dependant) of Context node B by evaluating some condition on an attribute, say ATTR1 (Dependable), of context node A. The conventional approch is 1) Read Dependable attribute, ATTR1 . 2) Put its value in a temporary holder, say ZTEMP attribute of Context Node B 3) In getter-setter of Dependant attribute, ATTR2 ,use the ZTEMP which reflect value of ATTR1. ZTEMP is a must in this approch to act as a Flag because ATTR1 and ATTR2 can not share their data directly as they belong to different context node and thus not accessible in their respective context node classes. Write code in IMPL class for steps 1) and 2) becuase IMPL can access context node A and B both.
lv_entityA ?= me->typed_context->node A->collection_wrapper->get_current( ). lv_value = lv_entityA~if_bol_bo_property_access->get_property_as_srting( 'ATTR1' ) . If <some condition> lr_entityB ?= me->typed_context->node B->colloction_wrapper->get_current( ) . lv_entityB~if_bol_bo_property_access->set_property( name = 'ZTEMP' Value = lv_value ). Endif.
then write code in Context node B class (CNxx), typically in GET_ATTR2 method, to set the ATTR2 from ATTR1 via this Z attribute. There is no harm in this approach and I would like to share this thread where the guy struggled so much to read one context node attribute in other context node and finally above said approach came to his rescue. I, myself, have used this same long approach previously in my work and then one day it made me think, why code in IMPL class? Just because it has access to all context nodes via CTXT class instance called typed context ? And if so, then why not have a CTXT class instance itself in my context node class ? Then I can easily read all context nodes. As we all know, all the context nodes are attributes of view's context class, i.e. the class ending with _CTXT. Now the View controller class, i.e. the one ending with IMPL, has a public attributetyped_context TYPE CL______CTXT.Hence, in controller class, i.e. IMPL class, you can access any context node as
me->typed context->context node name.
step 1) In the context node class of node HEADER, Create an attribute of the context class (CTXT class). GR_OWNER class) Instance Attribute Public Type Ref To CL_XX_XX_XXXX_CTXT (give the name of Context
step 2) Now in the view context class (CTXT class) there will be a method CREATE_HEADER( ). Write following code in this method as shown in the pic. You just need to add the highlighted code lines shown in the image below. Let rest of the code remain as it is as generated by system.
Step 3) Now in the context node class, you can access any other context node as you have the instance to CTXT class with you and CTXT class has all context nodes as its attributes. So you can get the other context node entity as follows:
DATA lr_entity type ref to cl_crm_bol_entity . CHECK gr_owner IS BOUND." get the current entity of other context node lr_entity ?= gr_owner->OtherContextNodeName->collection_wrapper ->get_current( ). CHECK lr_entity IS BOUND. " read the property of other context node Lr_entity->if_bol_bo_property_access~get_property( iv_atrribute = 'AN ATTRIBUTE' EXPORTING value = lv_value )
The image below illustrated the code in GET_NAME4 method of context node HEADER.
As you can see, now using gr_owner attribute, we can access the other context node and can call its GETTER_SETTER for any of its attributes.
Now add the NAME4 field on the View using config tool. Also we keep it as display only by ticking the checkbox for display only in view config tool.
Find below the result as appeared on Web UI after we added the NAME4 attribute of HEADER on the view and copied the country_text attribute from node STANDARDADDRESS into it.
As you can see, the Name4 field has the value Denmark, which is as read from the context node STANDARDADDRESS attribute "county_text".