Wednesday, February 6, 2013

Enhancing Product Search with Business Role dependent field.

During an implementation of SAP CRM we focus a lot on tuning the system to user requirements. By configuring the UI based on user roles we have the opportunity to hide or show fields as the role requires. This is not always the case for filter values and search fields.

The standard product search in CRM will show the user all materials in the system. For this blog we want to help users to quickly find the right products depending on the role they use in the UI. Not all of these requirements can be solved with authorization so in this blog we describe the steps needed to enhance the standard product search with the field Item Category group and limit the values of this field per Business Role.

Adding the new field to the Product Search

Extending search structure

Using the Genil model browser you can find the corresponding attribute structure for a query. For the product search this is the CRMT_PRIL_QUERY_ADVSEARCH_PROD structure. Via SE11 you can extend this structure using below append.

Adding Search Customizing

We now have the field available in the search structure but we need to specify where the system needs to search for this attribute. This can be done in the IMG:

Customer Relationship Management -> Master Data -> Products -> Basic Settings -> Add Attributes to Search Structure.

Configuration of view

You can now add the field to the view configuration of component PRD01QR. There are two views, Search for the generic product search and SearchHelp for the product search pop-up.

Please note that if you do not deactivate the hiding of fields in customizing the additional field will not be visible in the configuration.

Customer Relationship Management -> UI Framework -> UI Framework Definition -> Design Layer -> Deactivate Hiding of Fields.

Limit the values based on Business Role

Now we see the Item Category Group field on the product search, since this will show all available item category Groups including all SAP standards this is not very user friendly. To limit the results we will enhance this standard component and implement a custom customizing table to restrict values based on the business role. Since the list will be much smaller we will also make it a pick list.

Create Customizing table

Since we want to limit the values based on the business role we create a custom table with the following fields. We have also created a field for SEARCH_FIELD, this makes it possible to use the same table for filtering other fields in the same structure.

As an example for this blog we have filled the table with the following values.


Enhance Component, Views and redefine method

We need to enhance the component PRD01QR and also the Views SearchHelp and Search.

To make the field a pick list we have generated a GET_P method and implemented below code:

CASE iv_property.
WHEN if_bsp_wd_model_setter_getter=>fp_fieldtype.
     rv_value = cl_bsp_dlc_view_descriptor=>field_type_picklist.

In below class we need to redefine method CHANGE_DQUERY_DEF_EXTENSION.

In method we then filter the values with the following sample implementation:

lv_role TYPE string,
lt_prod_src_flt TYPE STANDARD TABLE OF zzip_prd_src_flt,

BEGIN OF ls_src_range,
     search_field TYPE zzip_itm_cat_flt-search_field,
     search_value TYPE RANGE OF zzip_itm_cat_flt-search_value,
END OF ls_src_range,

ls_range_value LIKE LINE OF ls_src_range-search_value,
lt_src_range LIKE STANDARD TABLE OF ls_src_range.

<lfs_result> TYPE crms_thtmlb_search_field_info,
<lfs_prod_src_flt> TYPE zzip_itm_cat_flt,
<lfs_src_range> LIKE ls_src_range.

* Call SUPER
CALL METHOD super->change_dquery_def_extension
     ct_result = ct_result.* Determine Business Role
     lv_role = cl_crm_ui_profile=>get_instance( )->get_profile( ).

* Get Product Search Filter conditions - Based on Business Role
SELECT * FROM zzip_prd_src_flt
    WHERE business_role = lv_role.

* Continue only if Filter conditions are found!
CHECK sy-subrc = 0.

* Create a range table for each field to be filtered
LOOP AT lt_prod_src_flt ASSIGNING <lfs_prod_src_flt>.
     CLEAR ls_range_value.

     "Read filter range for field     READ TABLE lt_src_range
         ASSIGNING <lfs_src_range>
         WITH KEY search_field = <lfs_prod_src_flt>-search_field.

     "Not found? Then create it! (First filter condition for current field)
     IF sy-subrc NE 0.
         APPEND INITIAL LINE TO lt_src_range
         ASSIGNING <lfs_src_range>.

    <lfs_src_range>-search_field = <lfs_prod_src_flt>-search_field.

    "Add filter condition
    ls_range_value-sign = 'I'.
    ls_range_value-option = 'EQ'.
    ls_range_value-low = <lfs_prod_src_flt>-search_value.
    ls_range_value-high = ''.
    APPEND ls_range_value TO <lfs_src_range>-search_value.

* Process Product Search Filter conditions
LOOP AT lt_src_range ASSIGNING <lfs_src_range>.
     "Read field to be filtered
     READ TABLE ct_result
        ASSIGNING <lfs_result>
        WITH KEY field = <lfs_src_range>-search_field.

     "Apply filter
     IF sy-subrc = 0.
         DELETE <lfs_result>-ddlb_options
               WHERE key
               NOT IN <lfs_src_range>-search_value.

If you have multiple implementations for filtering, you could move this code to a generic class and calling that class in this method.


The field is shown in the product search and the dropdown list only shows the customized values.