Search This Blog

Wednesday, July 14, 2010

SAP CRM : How to use your custom BOL Object for webclient within assignment block

In the last Blog i showed how can you create your own custom BOL object that meet your personal requirements .

Now that we have our BOL Object we might want to use it for our purposes.

Let's say that we want to add several fileds to assignment block and display them on the screen ,for instance we take the fields from our Z table the we use in the creation of our BOL Object .
we also want to keep the connection for the original transaction context .
the steps for doing that are :
1) we need to add a filed to our Z table BP_GUID which will keep us connected to the main transaction context .
2) perform the adjustment for the Z Table
3) Search for the right BP_GUID that fit to our user account .
4) create new record that contain the details that we want to diasply for the spesific account

See the following screen shot.

 Here we should add the BP_GUID feild to our table and mark the field as a part of the table key .
See the following screen shot

Now we need to perform some adjustment for our table . choose the Database Utility from the menu
See the following screen shot

once you choose this option you'll get the next screen .

In our case we will choose the Delete data option becuse we want to create a new record, you also have to know that if you choose the Save data option there's no 100  percent guarantee that your data in the table will be saved , so you should consider the use of Database Utility very careful. 

After we perform the adjustment and activated the table we can step forward to the next step which is the creation of a new record with the details that we want to display on the screen . 

First to the record creation we should find the key which is the BP_GUID that will connect us to the account context . 
 to find the right BP_GUID enter transaction GENIL_BOL_BROWSER and insert the BP_APPL_COND  in the component set field.
See the following screen shot
when you enter to the component set choose the predefined search named BuilEmpSearch  
 See the following screen shot.

Now we can look for any partner , in my case i'll choose to search  my user and i'll get the compatible

BP_GUID which is : DF21EBC73A26F8F1A2B0001F29644FC0
See the following screen shot.

 Now let's create a new record in the DataBase table ZUSR_BOL_TB with user name, BP_GUID , First and last names.
See the following screen shot.

for now we finish with the database side and we wiil go to perform some improvement in our BOL object to support the different searching options.

so let's go to transaction SE24 and put ZCL_OWN_BOL in the input filed.
click on Local Types button and put the lines inside :

TYPES: BEGIN OF ty_general_rng ,
                sign TYPE bapisign,
                option TYPE bapioption,
                low TYPE string ,
               high TYPE string ,
END OF ty_general_rng .

TYPES: tt_general_rng TYPE STANDARD TABLE OF ty_general_rng . 
See the following screen shot:

Now go back to the method list and edit the method :IF_GENIL_APPL_INTLAY~GET_DYNAMIC_QUERY_RESULT
replace the exsiting code with the bellow lines:
METHOD if_genil_appl_intlay~get_dynamic_query_result.

DATA: lr_object TYPE REF TO if_genil_cont_root_object,
            lt_result TYPE TABLE OF zusr_bol_st,
            lv_dyn_where TYPE string,
            lv_len TYPE i ,
            ls_range TYPE ty_general_rng.

DATA: lt_bp_guid TYPE tt_general_rng,
            lt_bname_range TYPE tt_general_rng,
           lt_name_first TYPE tt_general_rng,
           lt_name_last TYPE tt_general_rng.

FIELD-SYMBOLS: "" TYPE zusr_bol_st,
                                "" TYPE genilt_selection_parameter.

* decomposition of selection parameters and build a dynamic where condition

LOOP AT it_selection_parameters[] ASSIGNING "".
   MOVE: ""-sign TO ls_range-sign ,
                ""-option TO ls_range-option ,
                ""-low TO ls_range-low ,
                ""-high TO ls_range-high.

CASE -attr_name.
     APPEND ls_range TO lt_bname_range[].
     CONCATENATE lv_dyn_where 'bname in lt_bname_range[] and'
         INTO lv_dyn_where  SEPARATED BY space .
 APPEND ls_range TO lt_bp_guid[].
CONCATENATE lv_dyn_where 'bp_guid in lt_bp_guid[] and'
   INTO lv_dyn_where SEPARATED BY space .

APPEND ls_range TO lt_name_first[].
CONCATENATE lv_dyn_where 'name_first in lt_name_first[] and'
  INTO lv_dyn_where SEPARATED BY space .


APPEND ls_range TO lt_name_last[].
CONCATENATE lv_dyn_where 'name_last in lt_name_last[] and'
  INTO lv_dyn_where SEPARATED BY space .




lv_len = STRLEN( lv_dyn_where ) - 4 . "remove the last 'AND' in the condition
lv_dyn_where = lv_dyn_where(lv_len) .

CHECK STRLEN( lv_dyn_where ) > 0.

SELECT * FROM zusr_bol_tb INTO TABLE lt_result[] WHERE (lv_dyn_where).

CHECK LINES( lt_result[] ) > 0.

LOOP AT lt_result[] ASSIGNING "".

lr_object = iv_root_list->add_object( iv_object_name = 'Root'
                                                             is_object_key = ""-bname ).

CHECK lr_object IS BOUND.
lr_object->set_query_root( abap_true ).

Save and Activate your code .

We might want to add the BNAME ,NAME_LAST,NAME_FIRST fileds to a view that we will create
personaly i choosed the BP_HEAD component but you can choose any component that you may use .

 OK. So let's get in and execute transaction BSP_WD_CMPWB_NEW and choose BP_HEAD component with our enhancement set which is spesificaly in my case called ZENH_CRM and hit the  display button and go to Runtime Repository Editor , open the MODELS folder to see with which BOL component set the BP_HEAD component use.

See the following screen shot.

we can see now that the component BP_HEAD use the Model BP_APPL_COND and we want that our BOL object will appear in the repository of the BP_HEAD component so that we can use it for our pupose.

To do that we need to go to the component set definition .
See the following screen shot.
now choose the appropriate component set which is in our case BP_APPL_COND.
See the following screen shot.
now click on component assignment make new entry and add our BOL object named ZBOLOB.
See the following screen shot.
don't forget to save the new entry .
after you saved it successfully enter again to BSP_WD_CMPWB_NEW transaction with BP_HEAD component and click on the BOL Model Browser tab , we want to check here that we can see our BOL entity ready for use .
See the following screen shot.

Now we can see that our BOL entity Root that we created is ready for use in the enhancement of BP_HEAD component.  We will go to Component Structure Browser tab and create our view .
See the following screen shot.

we'l choose a name for our view .
See the following screen shot.

 after we named the view we need to add 2 model nodes , one for BuilHeader and one
 for our Root BOL object .
 The first one is for getting the relevant BP_GUID from the custom controller and get the appropriate
 first name last name and user name accroding to our table .

 See the following screen shot.

The next step is to add the fields that we might use in our view to context which we working on .
we start with the BuilHeader fields .

See the following screen shot.

we use also attributes from the Root BOL object .
See the following screen shot.

we got the whole attributes as shown bellow.
See the following screen shot.

we move to the nest step .
here we need to define the view type and it's properties.
the view type we choose form view without buttons and in the properties we make it configurable 
and that for keep to our self the option to Add/Remove attributes from the view .
See the following screen shot.

Now we finish the view addtion with the wizard we will see that our view is listed with
the other views in the component.
See the following screen shot.

After we added the view we should create a binding to the custom controiller context node BUILHEADER.

so we put the mouse curser on the context node BUILHEADER pressing teh right mouse
click and create the binding .
See the following screen shot.

we will create the binding for our context node to the same context node in the custom controller.
See the following screen shot.

After we create the apropriate binding we need to add the attributes to the view .
so we move to the configuration tab when we working on the view and the we switch to edit mode .
we see that we have the 2 BOL objects that we added when we wroking with the wizard in time of the view creation .

in our case we will add the attributes from the Root BOL object .
See the following screen shot.

After we add the attributes to our view we need to add our view as an assignment block .
First we need to add our view to the BPHEADOverview viewset , to do this we will go to the
Runtime Repository Editor and we will add our view to the OverviewPage of
BPHEADOverview viewset .

See the following screen shot.

After we add the view to the BPHEADOverview viewset we will go to the configuration tab of
BPHEADOverview viewset and switch to edit mode and add our view TestBOLroot to the list of views
that appears as assignment blocks in the BPHEADOverview viewset by click on the arrow button
and moving it from the left side to the right side .

See the following screen shot.

After we handle the addition of adding our view as an assignment block we need to handle some code
addtions for the right treatment in the attributes in our view .

First we will go to the ROOT context node within our view and redefine
the method IF_BSP_MODEL~INIT.

See the following screen shot.

Put the next ilnes into the method save and aactivate the method.

TYPES: BEGIN OF ltype_attr_struct,
                       mandt TYPE mandt,
                       bp_guid TYPE bu_partner_guid,
                       bname TYPE xubname,
                      name_last TYPE bu_namep_l,
                      name_first TYPE bu_namep_f,
END OF ltype_attr_struct.

DATA: lrf_data_struct TYPE REF TO ltype_attr_struct,
           lrf_value_node TYPE REF TO cl_bsp_wd_value_node,
           lrf_bol_collection TYPE REF TO if_bol_bo_col.

super->if_bsp_model~init( id = id owner = owner ).

CREATE DATA lrf_data_struct.

CREATE OBJECT lrf_value_node
          iv_data_ref = lrf_data_struct.

CREATE OBJECT lrf_bol_collection TYPE cl_crm_bol_bo_col.
 lrf_bol_collection->add( lrf_value_node ).
 me->set_collection( lrf_bol_collection ).
After we add the above lines to the method we will go to the implementation class of our view,
which is in our case is ZL_ZBP_HEAD_TESTBOLROOT_IMPL.

we will double click on the class name and we will move to display mode of the class in a way that
all the method could be shown. 

The first thing to do is to write our own method for performing the right query when we need to
display the attributes on the screen .

After that we will redefine the method DO_PREPARE_OUTPUT.

so let's create a new method named root_query which is an Instance Method , and the visibility of
it is Private.

put the next lines to the method .

METHOD root_query.

DATA: lrf_advanced_query TYPE REF TO cl_crm_bol_dquery_service,
           lrf_root_result_collection TYPE REF TO if_bol_entity_col,
           lrf_root_result_bol_entity TYPE REF TO cl_crm_bol_entity,
           lrf_current_root TYPE REF TO if_bol_bo_property_access,
           lrf_current_builheader TYPE REF TO if_bol_bo_property_access,
           lt_params TYPE crmt_name_value_pair_tab,
           ls_params TYPE crmt_name_value_pair,
           ls_builheader_properties TYPE crmst_header_object_buil,
           lv_low_value TYPE string ,
           ls_root_properties TYPE zusr_bol_st.

ls_params-name = 'MAX_HITS' .
ls_params-value = '1'. "we don't need in this case more the single record for result
APPEND ls_params TO lt_params.

lrf_current_root ?= me->typed_context->root->collection_wrapper->get_current( ).
CHECK lrf_current_root IS BOUND .

lrf_current_root->get_properties( IMPORTING es_attributes = ls_root_properties ).

CHECK ls_root_properties IS INITIAL . " means that we don't have any values in our
                                                                 "fields and  therfore wi'll excute the query
lrf_current_builheader ?=
  me->typed_context->builheader->collection_wrapper->get_current( ).

CHECK lrf_current_builheader IS BOUND .

lrf_current_builheader->get_properties( IMPORTING es_attributes = ls_builheader_properties ).

CHECK ls_builheader_properties-bp_guid IS NOT INITIAL .

lv_low_value = ls_builheader_properties-bp_guid.
lrf_advanced_query = cl_crm_bol_dquery_service=>get_instance( 'Search' ).
lrf_advanced_query->set_query_parameters( it_parameters = lt_params ).
lrf_advanced_query->add_selection_param( iv_attr_name = 'BP_GUID'
                                                                iv_sign = 'I'
                                                                iv_option = 'EQ'
                                                                iv_low = lv_low_value
                                                                iv_high = '' ).

lrf_root_result_collection = lrf_advanced_query->get_query_result( ).

IF lrf_root_result_collection IS BOUND . "if we found something that match our selection

lrf_root_result_bol_entity = lrf_root_result_collection->get_first( ).
lrf_root_result_bol_entity->get_properties( IMPORTING es_attributes = ls_root_properties ).
lrf_current_root->set_properties( is_attributes = ls_root_properties ).

Save and activate your code .
the next step is to redefine the method DO_PREPARE_OUTPUT.

put the next lines into the method .



                  iv_first_time = iv_first_time.

me->ROOT_QUERY( ).



save and activate your code .

Now all job is done our BOL object is wroking like a Rolls-Royce and it's time to derive pleasure from .
We will go to the webclient , choose our account and display it .

we can see that we have our attributes shown on the screen .

See the following screen shot.