Sei sulla pagina 1di 63

This is the first part of the blog. Here we will be creating a Z BOL object.

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 2: Go to the customizing path as shown in the screenshot.

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 5: Go to tcode SM30. Open the view as shown in the screenshot.

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 11: Enter object ID and click the button find.

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.

Extend BOL Model BT with custom table type relationship

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

EXTERN_CASE_NO type CRMT_OBJECT_ID

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

How to display a z-table in an assignment block

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

Structure: ZBP_FAVS_S Table type: ZBP_FAVS_TAB

2. Create Component & Window


To add a new, custom assignment block must we create our own component (with a window) and view. This is done in the BSP Component Workbench - transaction BSP_WD_CMPWB. Type in a suitable name for the Component and choose create (also remove the Enhancement Set, if existing). Follow the instructions and name the Window.
Component: ZBP_FAVS Window: MainWindow

3. Create View & Context Nodes


Display the newly created component and and in the tree on the left side right-click on View and choose Create View.Do changes in following steps of the wizard:

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.

Finish the wizard.


View: ZBPFavorites Context Nodes: PARTNER (Model Node with BOL Entity BuilHeader) ZBP_FAVS (Value/Table Node like Structure ZBP_FAVS_S

4. Set Runtime Repository


The tree to the left side in the Component Workbench can display different things. The normal one is Browse Component Structure. In order to change the Runtime Repository click on Runtime Repository Editor and after click on the edit-icon. We have to do three steps:

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.

Save the Runtime Repository with the disc-icon.

5. Bind Model Node with Component Controller


Go back to Browse Component Structure. The Model Context Node we created in Step 3 now needs to be bound to the Component Controller. This will make sure that when our z-component is called all the attributes from the BOL entity are passed to our node. Double click on Component Controller, right click on Context Node and choose Create. Follow the wizard and create the same Model Node as in Step 3 (preferably also with the same name).
Context Nodes: PARTNER (Model Node with BOL Entity BuilHeader)

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

6. Create refresh Event for dependent Value Node


Our table is dependent on the partner - therefore do we need to create an Event that refreshes the table display whenever the partner changes. Double click the view, open the nodes Context and Context Node, open the Table Node ZBP_FAVS and double click its Implementation Class. Go into edit mode and add a new method calledON_NEW_FOCUS. Open the method-attributes (puzzle-piece-icon) and tick "Event Handler for" (see the box below). Go to the Parameters and add the parameters of the Event by clicking on the icon with the small blue square. We leave the coding empty for now.
Impl. Class: Method: Event Class: Event: Parameters: ZL_ZBP_FAVS_ZBPFAVORITES_CN01 ON_NEW_FOCUS (Event Handler) CL_BSP_WD_COLLECTION_WRAPPER NEW_FOCUS FOCUS_BO (Importing - Type Ref To - IF_BOL_BO_PROPERTY_ACCESS)

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.

7. Get data from the ERP System


Now our component is ready to be filled with data. So we have to create a RFC function module in the ERP system which later will be called from the CRM system. The only two parameters needed are the Partner Number (as importing) and the table with the favorite things (as exporting). Code a simple SELECT statement which gets the data from the database table.
Function Module: Z_CRM_GET_FAVS_FOR_BP (Remote Enabled) Import: IV_PARTNER (Type - BU_PARTNER) Export: ET_FAVS (Type - ZBP_FAVS_TAB)

8. Fill the Table Node with data


The next step is to get the data from the ERP system into the CRM. We do this in the Event Handler method ON_NEW_FOCUS which we created in Step 6 (so that every time the partner is changed, the new data from the ERP system is selected). Following coding is a possible way to do it:
data: lr_wrapper lr_entity lv_bp_nr lv_partner type ref to cl_bsp_wd_collection_wrapper, " BP collection wrapper type ref to if_bol_bo_property_access, " wrapper entity type string, " BP (business partner) number as string type bu_partner, " BP number in correct format (for RFC call) type smof_erpsh, " structure of the RFC destination

ls_smof_erpsh

lr_col lr_valuenode lr_tabline lt_favs ls_favs

type ref to type ref to type ref to type type

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.

field-symbols: <fs_favs> type

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

<%

endif. %> </table>

10. Add assignment block to Overview page


As our last step, we need to add our z-component to the Overview page of the Business Partner. Go to the BSP Component Workbench - transaction BSP_WD_CMPWB and display component BP_HEAD. First we have to make our z-component available in this component. Go to the Runtime Repository Editor and choose edit mode. Open ViewSets, ViewSet BP_HEAD/BPHEADOverview and ViewAreaOverviewPage. Right-Click on the ViewArea and choose Add View. Type in the z-component as BSPApplication and choose the correct View. Save the Runtime Repository with the disc-icon. Go back to the Component Structure, locate View BPHEADOverview and double click it. Change into the Configuration tab and select the Configuration with your Role Key (or copy the configuration to your Role Key). At the right side under Avaiable Assignment Blocks you'll now see our z-component. Mark it and add it with the arrow pointing right to the Displayed Assignment Blocks. Give it a suitableTitle and choose the Load Option. *And once you saved the configuration, you're done!*

CRM WebUI -- Dynamic table type Context nodes

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

Created on Author(s) Bio

: :

03/03/3010 Ranganatha Prasad Kurupati

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

Applies to: Summary Author(s):

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

1. Database table design


Opportunit y Sales rep Product Commission%

100001

Rep1

P1

50

100001

Rep2

P1

50

100001

Rep2

P2

100

2. Create Internal Table during run-time

How to display a z-table in an assignment block

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

Structure: ZBP_FAVS_S Table type: ZBP_FAVS_TAB

2. Create Component & Window


To add a new, custom assignment block must we create our own component (with a window) and view. This is done in the BSP Component Workbench - transaction BSP_WD_CMPWB. Type in a suitable name for the Component and choose create (also remove the Enhancement Set, if existing). Follow the instructions and name the Window.
Component: ZBP_FAVS Window: MainWindow

3. Create View & Context Nodes


Display the newly created component and and in the tree on the left side right-click on View and choose Create View.Do changes in following steps of the wizard:

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.

Finish the wizard.


View: ZBPFavorites Context Nodes: PARTNER (Model Node with BOL Entity BuilHeader) ZBP_FAVS (Value/Table Node like Structure ZBP_FAVS_S

4. Set Runtime Repository


The tree to the left side in the Component Workbench can display different things. The normal one is Browse Component Structure. In order to change the Runtime Repository click on Runtime Repository Editor and after click on the edit-icon. We have to do three steps:

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.

Save the Runtime Repository with the disc-icon.

5. Bind Model Node with Component Controller


Go back to Browse Component Structure. The Model Context Node we created in Step 3 now needs to be bound to the Component Controller. This will make sure that when our z-component is called all the attributes from the BOL entity are passed to our node. Double click on Component Controller, right click on Context Node and choose Create. Follow the wizard and create the same Model Node as in Step 3 (preferably also with the same name).
Context Nodes: PARTNER (Model Node with BOL Entity BuilHeader)

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

6. Create refresh Event for dependent Value Node


Our table is dependent on the partner - therefore do we need to create an Event that refreshes the table display whenever the partner changes. Double click the view, open the nodes Context and Context Node, open the Table Node ZBP_FAVS and double click its Implementation Class. Go into edit mode and add a new method calledON_NEW_FOCUS. Open the method-attributes (puzzle-piece-icon) and tick "Event Handler for" (see the box below). Go to the Parameters and add the parameters of the Event by clicking on the icon with the small blue square. We leave the coding empty for now.
Impl. Class: Method: Event Class: Event: Parameters: ZL_ZBP_FAVS_ZBPFAVORITES_CN01 ON_NEW_FOCUS (Event Handler) CL_BSP_WD_COLLECTION_WRAPPER NEW_FOCUS FOCUS_BO (Importing - Type Ref To - IF_BOL_BO_PROPERTY_ACCESS)

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.

7. Get data from the ERP System


Now our component is ready to be filled with data. So we have to create a RFC function module in the ERP system which later will be called from the CRM system. The only two parameters needed are the Partner Number (as importing) and the table with the favorite things (as exporting). Code a simple SELECT statement which gets the data from the database table.
Function Module: Z_CRM_GET_FAVS_FOR_BP (Remote Enabled) Import: IV_PARTNER (Type - BU_PARTNER) Export: ET_FAVS (Type - ZBP_FAVS_TAB)

8. Fill the Table Node with data


The next step is to get the data from the ERP system into the CRM. We do this in the Event Handler method ON_NEW_FOCUS which we created in Step 6 (so that every time the partner is changed, the new data from the ERP system is selected). Following coding is a possible way to do it:
data: lr_wrapper lr_entity lv_bp_nr lv_partner type ref to cl_bsp_wd_collection_wrapper, " BP collection wrapper type ref to if_bol_bo_property_access, " wrapper entity type string, " BP (business partner) number as string type bu_partner, " BP number in correct format (for RFC call) type smof_erpsh, " structure of the RFC destination

ls_smof_erpsh

lr_col lr_valuenode lr_tabline lt_favs ls_favs

type ref to type ref to type ref to type type

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.

field-symbols: <fs_favs> type

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

<%

endif. %> </table>

10. Add assignment block to Overview page


As our last step, we need to add our z-component to the Overview page of the Business Partner. Go to the BSP Component Workbench - transaction BSP_WD_CMPWB and display component BP_HEAD. First we have to make our z-component available in this component. Go to the Runtime Repository Editor and choose edit mode. Open ViewSets, ViewSet BP_HEAD/BPHEADOverview and ViewAreaOverviewPage. Right-Click on the ViewArea and choose Add View. Type in the z-component as BSPApplication and choose the correct View. Save the Runtime Repository with the disc-icon. Go back to the Component Structure, locate View BPHEADOverview and double click it. Change into the Configuration tab and select the Configuration with your Role Key (or copy the configuration to your Role Key). At the right side under Avaiable Assignment Blocks you'll now see our z-component. Mark it and add it with the arrow pointing right to the Displayed Assignment Blocks. Give it a suitableTitle and choose the Load Option. *And once you saved the configuration, you're done!*

Copy BOL node trees dynamically

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

fetch all child objects and append to table


LOOP AT lt_relations INTO lv_rel_name. CLEAR: ls_child. ls_child-parent = lr_obj_to_copy->get_name( ). lr_orig_rel = lr_obj_to_copy->get_related_entities( iv_mode = cl_crm_bol_entity=>bypassing_buffer iv_relation_name = lv_rel_name ). ls_child-relation = lv_rel_name. ls_child-objects ?= lr_orig_rel. APPEND ls_child TO lt_children. ENDLOOP.

Create a new BuilSalesArrangement object


TRY. lr_entity = lr_header->create_related_entity( iv_relation_name = 'BuilSalesArrangementRel' ). CATCH cx_crm_genil_model_error cx_crm_genil_duplicate_rel. should never happen ENDTRY.

Bind the newly created object to BP


IF lr_entity IS BOUND.

typed_context->builsalesarrangement->collection_wrapper->add( iv_entity = lr_entity iv_set_focus = abap_true ).

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.

* *

* *

How to Guide - Enhancing the UI in CRM 7.0

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.

Enhancing an Existing UI Component


Let's assume that you would like to change the name of the CRM campaign object to 'tactics'. In short, your task is to change the corresponding page titles, .assignment block names, labels and message texts containing 'campaign'. First we will modify the title of the campaign overview page. Typically, the title text comes from IF_BSP_WD_HISTORY_STATE_DESCR~GET_STATE_DESCRIPTION, implemented as part of the hosting window controller. Let's open an existing campaign instance and navigate to the technical details of the "parent" window (place the cursor on any of the input fields and press F2).

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.

How does Session Management Work?


For the explanation we consider a service based on the Internet Transaction Server (ITS). The service is started with a LaunchURL containing the ITS location, name of the service and a set of parameters (user, password, language and so on). Example: http://pgwp211a.wdf.sap-ag.de:1080/scripts/wgate/webgui/ !? ~transaction=sm04&sapwp_active=1&~client=050&~login=wpdev&~ language=de&~passwd=blue When we enter the LaunchURL directly on the client, the content page, that is generated by the ITS, is displayed. Because of the stateless connection, the responsible ITS is not informed whether the running ITS session is still valid or should be terminated. That is not a reliable session management. If the user closes the browser, navigates to another location or chooses the Back button in the browser, the ITS session is kept alive on the server until the predefined timeout occurs. To overcome this problem, a main page is created that consists of an IFrame (displaying the content from the ITS) and a special JavaScript object called Distributed Session Manager (DSM). The DSM is responsible for session management handling in the page. Every content page includes a JavaScript code that is processed on the client after the page has been loaded. This JavaScript code creates a new JavaScript object called SessInfo with the unique identification of the ITS session SessInfo.GUSID and the callback URL SessInfo.SessURL. The callback URL is the address where the SISP commands will be sent to. See section SessInfo Object Properties for more details. After the content page in the IFrame has been loaded, the SessInfo object is transferred from the content page to the main page and is saved by the DSM. If the user exits the browser, navigates to another location or chooses theBack button, the DSM is activated by receiving the browser event onunload. DSM sends the termination commands to all registered callback URLs and terminates the ITS sessions on the server. Following restrictions apply: JavaScript origin policy The SessInfo object and script can only be transfer over IFrame borders, if both pages (main page and content page) use the same document domain. The main page comes from the Enterprise Portal server, for example,http://epserver.mycomp.com, and the content page comes from the ITS server, for example, http://itsserver.mycomp.com. Both domains must be aligned to the same denominator, such as mycomp.com, to allow scripting. See JavaScript Origin Policy for more details. Browser event onunload The transmission of a termination command from the DSM back to the ITS server must be triggered by a client event. If the DSM simply registers the onunload event and tries to send one or more HTTP requests from the JavaScript, there is no guarantee that all requests are transmitted. If the connection is slow, the browser can be terminated before all requests have been sent. The browser event onbeforeunload solves this problem, but only the Microsoft Internet Explorer supports this event. A browser independent solution is, to send the termination commands from a Java applet. Received SessInfo objects are collected directly by the applet and the termination commands are sent to the servers in thedestroy()method of the applet. The applet runs in its own JVM and the destroy()method of the applet is executed independently of the browser JVM, so the applet is still executed, even if the browser is already terminated. When the browser has no Java support, the commands can be sent from the External Window. Applet origin policy

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

Server: Workplace server components/services


EPCM Object (Portal service) The EPCM object is involved in the page assembly process. It generates page stubs into predefined page locations. It is responsible to place DSM interfaces, DSM applets and the EPCF infrastructure into the header and body of the page. Launcher (Portal component) The Launcher includes an IFrame, with the size of 100% by 100%, on the Portal page with the LaunchURL. Terminator (Portal component) The Terminator is invisible. It receives a list of termination commands from the client and sends them back to the ITS. Every page assembled by the EPCM includes one URL of the Terminator component as the parameter of the applet. See also section Terminator Component for more details. DSM (Portal component) The DSM is used for testing. If this component is included in the same page as the Launcher, the processed SessInfo object can be displayed easily and terminated manually.

Client: Scripts & Applet


DSM Interface The DSM interface is JavaScript code that is fully integrated into the Workplace Client Manager EPCM and therefore automatically included in every portal page generated by the EPCM Object. It provides methods to communicate with the DSM Applet and a definition of the function SAPWP_receiveSessInfo(), which collects the SessInfo objects coming from the content IFrame. See section DSM Interface for more details. DSM Applet The DSM applet is integrated with the applet com.sap.portal.epcf.EPCMfactory. It implements the saving of the SessInfo object in a hash table and a communication channel to the server using Client Data Channel. The methods can be accessed using the DSM Interface. SISP Code generated by the ITS in the content page The ITS server generates JavaScript code to create the SessInfo object and transfers it to the main page. External Window The External Window is an additional window to the regular portal page that is used for browsers with no Java support.

Session Management Step by Step


Clients with Java Support

... ...

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.

Clients without Java Support

... ...

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.

Client scripts DSM Interface (Step 1)


<SCRIPT src= "/irj/portalapps/com.sap.portal.epcf.loader/script/standard/js13_epcf.js" > </SCRIPT> <SCRIPT> <!-EPCM.init( 2, 2, '8a50298ad8156b33d0445ae7e4f9062e', 1, 5.5, 1 ); EPCM.DSM.init("http://p45462.wdf.sapag.de:8080/irj/servlet/prt/portal/prtroot/DSMTerminator.default"); function SAPWP_receiveSessInfo( sessInfo, frameRef ){ EPCM.DSM.processSession( sessInfo ); EPCM.DSM.notifyMonitor( sessInfo ); } //--> </SCRIPT>

DSM Applet as the Part of EPCM Object (Step 1)


<APPLET CODEBASE="/irj/services/epcfloader/applet" CODE="com.sap.portal.epcf.EPCMfactory" ID="_EPCMfactory_" NAME="_EPCMfactory_" STYLE="POSITION: absolute;" WIDTH="0" HEIGHT="0" MAYSCRIPT> <PARAM name="trace.level" value="2"> <PARAM name="DSM.serverUrl" value="http://p45462.wdf.sapag.de:8080/irj/servlet/prt/portal/prtroot/DSMTerminator.default"> <PARAM name="DSM.scope" value="8a50298ad8156b33d0445ae7e4f9062e"> </APPLET>

IFrame with Content (Step 2)


<IFRAME width="100%"height="100%"border="0" src="http://pgtlsp4c.wdf.sap-g.de:1080/scripts/wgate/fielddump/!? ~client=001&~language=EN& ~logingroup=SPACE&sapwp_active=1& ~login=p80000001&passwd=welcome"> </IFRAME> Function SAPWP_receiveSessInfo is the entry point for every SessInfo Object. The SessInfo object is transferred to the DSM Applet using the method EPCM.DSM.registerSession() from the DSM Interface. The applet parameter DSM.serverUrl specifies the URL of the Terminator component. The collected termination commands will be sent to this URL (Step 6).

SISP Code Example Generated by the ITS (Step 3)


<SCRIPT>

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

Testing the Session Management


The portal has two components to test the session management: DSM TestLaunch. Creates the docking IFrame for the ITS response. DSM Monitor

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

Test 1: DSM Displays SessInfo Objects


If the session management works correctly, all received SessInfo objects are displayed in the DSM and you can display all properties of the SessInfo objects. If there are no SessInfo objects displayed in the DSM following problems are possible:
...

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.

Test 2: DSM Interface to DSMTerminator Component Connection


SessInfoobjects will be processed during the page unload event. The termination command is sent by the Java applet to DSMTerminator component. The transfer protocol can be displayed on the Java console of your browser. The Java console of the MS Internet Explorer can be enabled as follows: Tools Internet Options Advanced Microsoft VM If there is an error message in the Java console, you should first check if the proxy settings http.proxyHost, http.proxyPort and http.nonProxyHosts in your servlet environment are correct.

Test 3: Destroying of ITS Sessions


Every SessInfo object represents a session on the ITS. You can directly start the R/3 system to which the ITS server is connected and check with the transaction SU04 which sessions have been destroyed during the page unloadevent.

See also
SessInfo Object Properties DSM API Terminator Component

SessInfo Object Properties


The following SessInfo properties are defined by the SISP protocol version 1.0. Properties Property GUSID sessUrl lastSessCmd redirectURL Description Global Unique Session ID. URL where the session commands and termination command is sent to. Last session command. URL which can be used for chaining the application (close the current one and start new one with givenredirectURL). Timeout value for session response. Description of session. Provides information of the version of the protocol. The current version released is 1.0.

dTimeout Label protocolVersion

Data Session Management (DSM) API


The DSM uses this API to access the properties of the SessInfo object. See section Session Management for more details.

EPCM.DSM.init (String url)


This method Initializes the DSM and registers the URL at the Terminator component. Parameter Description Parameter url Type String Description URL that is registered at the Terminator component.

EPCM.DSM.processSession (sessInfo)
This method is the entry point for the session management (handler for SAPWP_receiveSessInfo).

Parameter Description Parameter sessInfo Type Object Description SessInfo object.

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.

Configuring the DSMTerminator component


The default Terminator portal component DSMTerminator can be customized by changing the properties of the iView. DSMTerminator Properties Property Description The DSMTerminator component sends requests to the servers it is told to. With this property you can define, if the URL is validated before it is sent. If the property is set to true, every URL will be validated against the trustedHost andrestrictedHost list. This semicolon separated list specifies the hosts to which the DSMTermination component is allowed to connect. A host entry can also be specified as pattern with one wildcard (*). Example: *.myfirm.com;*yourfirm.com This semicolon separated list specifies the hosts to which the DSMTermination component is not allowed to connect. A host entry can also be specified as pattern with one wildcard (*). Example: *.badfirm.com;*anotherbadfirm.com Allows that cookies from the incoming requests are passed on to the all requested destinations. This is required when you integrate components based on the BSP (Business Server Pages).

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.

Filter=<NOCOPY | ESCAPE | COPY>

Using Another Terminator Component


You can define another portal component or an external script or process specified by full qualified URL (for example, servlet or ASP) as Terminator component. The specified component has to implement the basic functions of aTerminator component. See section EPCF Configuration for more details.

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.

applet.archive = < on | off >

applet.trace.level = < 0 | 1 | 2 >

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.

framework.level = < 0 | 1 | 2 >

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

WorkProtect Feature for EP 6.0


To match the concept of the WorkProtect feature, a portal application must meet the following requirements: Maintain the dirty indicator

Adjust portal links (This function is currently only supported by CRM).

Maintaining the Dirty Indicator


The dirty indicator status of a portal application informs the portal that there is unsaved data.

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.

Adjusting Portal Links


The portal can only check the current dirty indicator and perform the navigation without losing data, if the portal application replaces all the links that can destroy the contents of the content area with links having the following syntax (analogous to New Navigation Model / WorkProtect Mode , section Cross Navigation ): <A HREF=myLink onclick=return EPCM.doNavigate('any_PCD_URL')> The parameter <any_PCD_URL> specifies the location of a page or an external service in the user role. Constants must be enclosed in quotation marks. You can find the correct value for the page in the Role Editor. Make sure that you update the corresponding parameter values for the <PCD_URL> in the secondary links and navigation targets when you change the role structure.

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

System Administration Support Support Desk Client Framework

WorkProtect Feature for EP 6.0


To match the concept of the WorkProtect feature, a portal application must meet the following requirements: Maintain the dirty indicator Adjust portal links (This function is currently only supported by CRM).

Maintaining the Dirty Indicator


The dirty indicator status of a portal application informs the portal that there is unsaved data.

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.

Adjusting Portal Links


The portal can only check the current dirty indicator and perform the navigation without losing data, if the portal application replaces all the links that can destroy the contents of the content area with links having the following syntax (analogous to New Navigation Model / WorkProtect Mode , section Cross Navigation ): <A HREF=myLink onclick=return EPCM.doNavigate('any_PCD_URL')> The parameter <any_PCD_URL> specifies the location of a page or an external service in the user role. Constants must be enclosed in quotation marks. You can find the correct value for the page in the Role Editor. Make sure that you update the corresponding parameter values for the <PCD_URL> in the secondary links and navigation targets when you change the role structure.

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

System Administration Support Support Desk Client Framework


Adobe Forms in WebUI

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.

Adobe Forms in WebUI


Satish Reddy Palyam Business Card Posted on Jul. 07, 2011 10:52 AM in CRM

Subscribe Print Permalin k Share

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.

Here we go.. Steps in nutshell:

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.

Lets discuss the above steps in more detail fashion..

1. Enhance Print Preview Button Event Handler method.

Enhance the UI Component BT112H_SC (Service Contract Header) in component Work Bench. Please choose your own component header according to the transaction type.

View & Event handler class are shown above.

2. Construct URL and Trigger POPUP window


Make use of method create_url in the class cl_crm_web_utility to construct URL

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

3. Define ICF Service for PDF PRINT PREVIEW.


Now, it is required to define a custom BSP ICF (Internet Communication Framework) Service. Tx: SICF Copy the standard ICF service for CRM_PDF_PRINT to the ZCRM_PDF_PRINT.

Define a Handler class to it like ZCL_CRM_PREVIEW_PDF, make of template method in standard class CL_CRM_PREVIEW_PDF

4. Populate the PDF data to the URL


Now, we need to bring up the PDF data to populate as PDF Xstring and applicantion type as pdf, which will eventually open as PDF file in the popup. Method IF_HTTP_EXTENSION~HANDLE_REQUEST Get the URL Params using the below method. ls_header_guid = server->request->get_form_field( 'guid' ). Now, the header_guid is available. Using the header_guid, we need to call a custom built method to bring the PDF Xstring data. I will show how to achieve this in next step. call method me->get_output_data exporting i_header_guid = ls_header_guid importing fpcontent = lv_pdf_xstring. Get the length of the PDF String. call function 'SCMS_XSTRING_TO_BINARY' exporting buffer = lv_pdf_xstring importing output_length = lv_pdf_length tables binary_tab = l_bin. Define the application as PDF. lv_file_size = lv_pdf_length. lv_contenttype = 'application/pdf'. ls_guid_str = ls_header_guid. concatenate ls_guid_str '.pdf' into lv_filename. lv_file_name = lv_filename. server->response->append_data( data = lv_pdf_xstring length = lv_pdf_length ). Set the response parameters concatenate 'inline; filename=' lv_filename into lv_contentdisposition. call method server->response->set_header_field exporting name = 'content-disposition' value = lv_contentdisposition. call method server->response->set_header_field exporting name = 'content-type' value = lv_contenttype. call method server->response->set_header_field exporting name = 'content-filename' value = lv_filename.

server->response->delete_header_field( name = 'Cache-Control' ). server->response->delete_header_field( name = 'Expires' ).

"#EC NOTEXT

5. Method: GET_OUTPUT_DATA to fetch the PDF DATA


With Header guid, read all the Service contract information and pass on the same to the Adobe PDF Forms. Get the Output parameters, most importantly, getpdf = X, fp_outputparams-nodialog = 'X'. fp_outputparams-getpdf = 'X'. fp_outputparams-preview = 'X'. call function 'FP_JOB_OPEN' changing ie_outputparams = fp_outputparams exceptions cancel =1 usage_error =2 system_error = 3 internal_error = 4 others = 5. Get the form related FM call function 'FP_FUNCTION_MODULE_NAME' exporting i_name = lv_formname importing e_funcname = fm_name. Call the FM and export the form related data. This is usual way of calling Adobe forms. Output will not go to spool, rather it gives in XString format. call function fm_name exporting /1bcdwb/docparams = fp_docparams importing /1bcdwb/formoutput = fp_result. Import the PDF XSTING DATA fp_1 = fp_result-pdf. IF it is required to attach more PDF forms to the same output file, then,

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

UI Framework News: F4-Help


Yohan Kariyawasan Business Card Company: SAP AG Posted on Mar. 18, 2009 06:00 AM in CRM

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.

Simple Value Help

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

How to adapt CRM Web UI descriptions in the runtime ...


Christophe Steeno Business Card Company: SAP Posted on Sep. 01, 2009 01:18 AM in CRM, ABAP

Print Permalin k Share

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.

OCA demystified, One-click actions in a list view ...


Christophe Steeno Business Card Company: SAP Posted on Sep. 03, 2009 07:50 AM in ABAP, CRM

Subscribe Print Permalin k Share

ABOUT ONE-CLICK ACTIONS.


So called One-Click Actions (OCA later on in the text) are dedicated to table list processing. They offer immediate and discrete operations on any row of a table in a view. In the SAP CRM Web UI, the OCA can be represented by an Icon or a text, they are often used to delete or edit a row. The purpose of this blog is to provide you with a quick introduction on the use of OCA via a case study. Please consider the following statement from Tim Back & Nadine Beigel (SAP Corp) in a paper on OCA published on August 2009:

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

1. Context node setup


. We focus on the class handling the table, here the context node class is ZL_Z01_DEMO__MASSMAINTAIN0_CN00 . Firstly modify the method GET_TABLE_LINE_SAMPLE where you declare a new attribute thtmlb_oca. The attribute will appear on your context node. Please bear in mind there's one unique OCA attribute required to declare all possible OCA's.

. 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

Conventional Approch for data exchange between different context node:

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.

The New Approach:


Now imagine, if you can get the instance of CTXT class in a context node class itself (i.e. the class ending with CNxx e.g. CN00, CN01 etc.)? Then you can access all other context nodes through this instance. Not only that you can access other context node's attributes just to read but you can also use set properties, get properties to set/reset attributes too. Sounds great right ?? sounds simple too and trust me it's really simple to implement this and we are going to do that next.

Illustration on the New Technique:


Let's take an as example, very close to above mentioned thread . Component/View = BP_ADDR/ Standard Address view StandardAddress has two context nodes. 1) Header 2) StandardAddress. Requirement: - 'HEADER' has an attribute which needs to be processed depending upon the value of attribute "Country" of node 'STANDARDADDRESS'. Let's, for example, we need to set NAME4 attribute of HEADER as say RESIDENT OF by reading COUNTRY attribute of STANDARDADDRESS node. Thus if country field of standard address node has value as DK then in NAME4 field we will put value as Denmark Resident .This is just a condition for sake of illustration. Since we need to read context node STANDARDADDRESS's attribute 'country' in context node HEADER, let's begin coding in context node HEADER class. (I assume that you have enhanced the component and the view and the context nodes)When you open CTXT class and look into Tab Attributes, you will find that the context node you enhanced, system added one more context node same as the enhanced node but in Z namespace and private scope. So when you enhanced context node HEADER, system must have created a replica of this header node as ZHEADER in CTXT class with scope as Private. We need to change the scope to "Protected" as shown in the pic. below

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

Potrebbero piacerti anche