Wednesday, January 22, 2014

Access Sequence on Role Cofiguration key

The CRM WEB UI is a flexible user interface that lets you alter based on a user's Business role. This leads to many user requirement during our CRM implementations. However if we look at all the views that we alter we see that there is a big overlap in views. In other words, for several business roles the same custom view will be required while for other views the same business roles require a different view. Until now this meant creating a new role configuration key and copying all custom views. Since this can be a time consuming activity and it leads to high maintenance cost in case of changes, this blog will show an easy way to dynamically find the correct view using an access sequence.

Business case with standard customizing

Changing views in the CRM Web UI is done using a Role Configuration Key. The key is linked to one or more business roles that use the same views. So if you have the requirement for 4 custom views for the business role Sales and the same  4 views for the role Sales Executive, only for this role one of the 4 views needs a change. (note that in most implementations the number of custom views per business role is much higher). You will then create two business roles and two role configuration keys. Now you can create the custom views, 8 in total.

It is clear that in case of  more business roles and more customized views per business role, the number of copied views with the same configuration can grow rapidly.

Let's see how to prevent this.

Business case with enhencement

We will still need two business roles each with its own role configuration key. For the Sales role we customize all 4 view lay-outs. For the Sales Exec. role we only customize the deviating 4th view.
Now we need to create an enhencement that will refer to teh Sales role if there is no custom view found for the Sales Exec role. This will be done by using a custom access sequence tabel and a BAdI implementation.

Creating the Access Sequence Tables

In order to register the access sequence we use a custom table. We register the main role configuration key the access number and the related role configuration key. By doing this, we can create a standard role for the entire business, one for sales and one for service. As shown in the picture.

BAdI Implementation

SAP CRM provides a BAdI to influence the determined view, this is the enhancement spot BSP_DLC_ACCESS_ENHENCEMENT. In our implementation we would like to call SAP standard determination for each role configuration key. Unfortunately the SAP standard code is in a private class, class CL_BSP_DLC_XML_STORAGE2. In order to still use this functionality we copy two methods of this class to the class that is created with our BAdI implementation. Below we will post the entire code.
  1. BUILD_ACCESS_SEQUENCE - we optimized the SAP code, result is the same
  2. CHOOSE_CONFIG_BY_AC_SEQ - we changed some data types to match the data types of the BAdI.
In the BAdI we first check if there are any custom views for this component and if the role access key of the business role is in the customizing table. If one of these checks fails we return to the SAP standard code.

Next step is to check if our copy of the SAP Standard codes returns a Custom view configuration for the provided role config key. If this is the case we select this view.

If no Custom config was found we start a loop over the access defined in the access sequence table.
We each step we check if a custom view configuration is found and if so use that and stop the loop, otherwise continue to the next step.
In case we do not find any custom configuration, SAP standard takes over and will determine the standard view.
We do recommend not to build too large access sequences due to possible performance issues but 3 or 4 steps should not be a problem.

The Code

CLASS zaccess_seqeunce DEFINITION
  
PUBLIC
  FINAL
  
CREATE PUBLIC .

  
PUBLIC SECTION.
*"* public components of class ZACCESS_SEQEUNCE
*"* do not include other source files here!!!

    
INTERFACES if_badi_interface .
    
INTERFACES if_dlc_config_access .

    
METHODS choose_config_by_ac_seq
      
IMPORTING

        !is_search_key 
TYPE bsp_dlcs_conf_sem_key_var_part
        !it_config_cus 
TYPE 
bsp_dlct_context_semantic_key
        !it_config_sap 
TYPE 
bsp_dlct_context_semantic_key
      
EXPORTING

        !es_config_data 
TYPE bsp_dlcs_context_semantic_key
        !es_successfull_key 
TYPE 
bsp_dlcs_conf_sem_key_var_part
        !ev_config_data_origin 
TYPE bsp_dlc_config_data_origin .

    
METHODS build_access_sequence
      RETURNING
        
value(resultTYPE bsp_dlct_conf_access_sequence .

  
PROTECTED SECTION.
*"* protected components of class ZACCESS_SEQEUNCE
*"* do not include other source files here!!!
  
PRIVATE SECTION.
*"* private components of class ZACCESS_SEQEUNCE
*"* do not include other source files here!!!

    
CLASS-DATA gt_access_sequence TYPE bsp_dlct_conf_access_sequence .
ENDCLASS.



CLASS ZACCESS_SEQEUNCE IMPLEMENTATION.


* <SIGNATURE>--------------------------------------------------------------------------------+
* | Instance Public Method ZACCESS_SEQEUNCE->BUILD_ACCESS_SEQUENCE
* +------------------------------------------------------------------------------------------+
* | [<-()] RESULT                         TYPE        BSP_DLCT_CONF_ACCESS_SEQUENCE
* +--------------------------------------------------------------------------------------</SIGNATURE>
  
METHOD build_access_sequence.

    
TYPESBEGIN OF ty_seq_options,
                    options 
TYPE char4,
           
END   OF ty_seq_options.

    
DATAlt_seq_options TYPE STANDARD TABLE OF ty_seq_options,
          ls_access_sequence  
TYPE bsp_dlcs_conf_access_keys.

    
FIELD-SYMBOLS <sequence_options> TYPE ty_sequence_options.

    
"Sequence options role_key/component_usage/object_type/object_sub_type
    
APPEND INITIAL LINE TO lt_seq_options ASSIGNING <sequence_options><sequence_options> 'XXXX'.
    
APPEND INITIAL LINE TO lt_seq_options ASSIGNING <sequence_options><sequence_options> 'XXX '.
    
APPEND INITIAL LINE TO lt_seq_options ASSIGNING <sequence_options><sequence_options> 'X XX'.
    
APPEND INITIAL LINE TO lt_seq_options ASSIGNING <sequence_options><sequence_options> ' XXX'.
    
APPEND INITIAL LINE TO lt_seq_options ASSIGNING <sequence_options><sequence_options> '  XX'.
    
APPEND INITIAL LINE TO lt_seq_options ASSIGNING <sequence_options><sequence_options> 'X X '.
    
APPEND INITIAL LINE TO lt_seq_options ASSIGNING <sequence_options><sequence_options> '  X '.
    
APPEND INITIAL LINE TO lt_seq_options ASSIGNING <sequence_options><sequence_options> 'XX  '.
    
APPEND INITIAL LINE TO lt_seq_options ASSIGNING <sequence_options><sequence_options> ' X  '.
    
APPEND INITIAL LINE TO lt_seq_options ASSIGNING <sequence_options><sequence_options> 'X   '.
    
APPEND INITIAL LINE TO lt_seq_options ASSIGNING <sequence_options><sequence_options> '    '.

    
LOOP AT lt_seq_options ASSIGNING <sequence_options>.
      ls_access_sequence
-role_key        <sequence_options>(1).
      ls_access_sequence
-component_usage <sequence_options>+1(1)
.
      ls_access_sequence
-object_type     <sequence_options>+2(1)
.
      ls_access_sequence
-object_sub_type <sequence_options>+3(1)
.
      
APPEND ls_access_sequence TO result.

    
ENDLOOP.

  
ENDMETHOD.                    "build_access_sequence


* <SIGNATURE>--------------------------------------------------------------------------------+
* | Instance Public Method ZACCESS_SEQEUNCE->CHOOSE_CONFIG_BY_AC_SEQ
* +------------------------------------------------------------------------------------------+
* | [--->] IS_SEARCH_KEY                  TYPE        BSP_DLCS_CONF_SEM_KEY_VAR_PART
* | [--->] IT_CONFIG_CUS                  TYPE        BSP_DLCT_CONTEXT_SEMANTIC_KEY
* | [--->] IT_CONFIG_SAP                  TYPE        BSP_DLCT_CONTEXT_SEMANTIC_KEY
* | [<---] ES_CONFIG_DATA                 TYPE        BSP_DLCS_CONTEXT_SEMANTIC_KEY
* | [<---] ES_SUCCESSFULL_KEY             TYPE        BSP_DLCS_CONF_SEM_KEY_VAR_PART
* | [<---] EV_CONFIG_DATA_ORIGIN          TYPE        BSP_DLC_CONFIG_DATA_ORIGIN
* +--------------------------------------------------------------------------------------</SIGNATURE>
  
METHOD choose_config_by_ac_seq.

    
DATAlv_found      TYPE boole_d,
          ls_key        
TYPE bsp_dlcs_conf_sem_key_var_part,
          ls_access_key 
TYPE bsp_dlcs_conf_access_keys,
          lv_to_read    
TYPE string,
          lv_i          
TYPE int4.

    
CLEARes_config_dataes_successfull_keyev_config_data_origin.

    
IF cl_bsp_dlc_config_util=>is_sap_system( ) EQ abap_true.
      lv_to_read 
'SAP'.
      lv_i 
1.
    
ELSE.
      lv_to_read 
'CUS'.
      lv_i 
2.
    
ENDIF.

    gt_access_sequence 
build_access_sequence( ).

    
DO lv_i TIMES.

      
LOOP AT gt_access_sequence INTO ls_access_key.
        ls_key 
is_search_key.
        
IF ls_access_key-role_key IS INITIAL.
          ls_key
-role_key '<DEFAULT>'.
        
ENDIF.
        
IF ls_access_key-component_usage IS INITIAL.
          ls_key
-component_usage  '<DEFAULT>'.
        
ENDIF.
        
IF ls_access_key-object_type IS INITIAL.
          ls_key
-object_type  '<DEFAULT>'.
        
ENDIF.
        
IF ls_access_key-object_sub_type IS INITIAL.
          ls_key
-object_sub_type '<DEFAULT>'.
        
ENDIF.

        
IF lv_to_read 'CUS'.
          
READ TABLE it_config_cus WITH KEY role_key        ls_key-role_key
                                            component_usage 
ls_key-
component_usage
                                            object_type     
ls_key-
object_type
                                            object_sub_type 
ls_key-
object_sub_type
                                   
INTO es_config_data.

          
IF sy-subrc 0.
            lv_found 
abap_true.
* select config data / customer
            es_successfull_key 
ls_key.
            ev_config_data_origin 
'CUS'.
            
EXIT.
          
ENDIF.

        
ELSE.
          
READ TABLE it_config_sap WITH KEY role_key        ls_key-role_key
                                            component_usage 
ls_key-
component_usage
                                            object_type     
ls_key-
object_type
                                            object_sub_type 
ls_key-
object_sub_type
                                   
INTO es_config_data.

* select config data / SAP
          
IF sy-subrc EQ 0.
            lv_found 
abap_true.
            es_successfull_key 
ls_key.
            ev_config_data_origin 
'SAP'.
            
EXIT.
          
ENDIF.
        
ENDIF.
      
ENDLOOP.

      
IF lv_found EQ abap_true.
        
EXIT.
      
ENDIF.
      lv_to_read 
'SAP'.
    
ENDDO.

  
ENDMETHOD.                    "choose_config_by_ac_seq


* <SIGNATURE>--------------------------------------------------------------------------------+
* | Instance Public Method ZACCESS_SEQEUNCE->IF_DLC_CONFIG_ACCESS~CHOOSE_CONFIG
* +------------------------------------------------------------------------------------------+
* | [--->] IV_COMPONENT                   TYPE        BSP_WD_COMPONENT_NAME
* | [--->] IV_VIEWNAME                    TYPE        O2PAGEEXT
* | [--->] IS_CONFIG_SEARCH_KEY           TYPE        BSP_DLCS_CONF_SEM_KEY_VAR_PART
* | [--->] IT_CONFIG_SAP                  TYPE        BSP_DLCT_CONTEXT_SEMANTIC_KEY
* | [--->] IT_CONFIG_CUS                  TYPE        BSP_DLCT_CONTEXT_SEMANTIC_KEY
* | [<---] ES_CONFIG_CHOOSEN              TYPE        BSP_DLCS_CONTEXT_SEMANTIC_KEY
* | [<---] EV_CONFIG_CHOOSEN_ORIGIN       TYPE        BSP_DLC_CONFIG_DATA_ORIGIN
* +--------------------------------------------------------------------------------------</SIGNATURE>
  
METHOD if_dlc_config_access~choose_config.

    
DATAlt_access_config           TYPE STANDARD TABLE OF zaccess_config,
          ls_config_search_key       
TYPE bsp_dlcs_conf_sem_key_var_part,
          ls_access_config           
TYPE zaccess_config,
          ls_successfull_key         
TYPE bsp_dlcs_conf_sem_key_var_part,
          ls_config_data_origin      
TYPE bsp_dlc_config_data_origin.

    
CLEARes_config_choosenev_config_choosen_origin.


      
"If no Customer configuration exist end search.
      
IF it_config_cus IS INITIALRETURNENDIF.

      
"Read values from customizing table.
      
"If Role Config Key even exists in customizing table.
      
SELECT FROM zaccess_config INTO TABLE lt_access_config
                                   
WHERE config_key is_config_search_key-role_key.


      
IF sy-subrc NE 0RETURNENDIF.

      
"Check Config Key of user
      choose_config_by_ac_seq
EXPORTING is_search_key         is_config_search_key
                                         it_config_cus         
it_config_cus
                                         it_config_sap         
it_config_sap
                               
IMPORTING es_successfull_key    
ls_successfull_key
                                         ev_config_data_origin 
ls_config_data_origin )
.

      
"Customer configuration found for role_key

      
IF ls_config_data_origin 'C'.
        
READ TABLE it_config_cus INTO es_config_choosen
                                 
WITH KEY role_key ls_successfull_key-
role_key
                                          component_usage 
ls_successfull_key-
component_usage
                                          object_type 
ls_successfull_key-
object_type
                                          object_sub_type 
ls_successfull_key-object_sub_type.

        ev_config_choosen_origin 
'CUS'.
        
RETURN.
      
ENDIF.

      ls_config_search_key 
is_config_search_key.

      
"Now try and find customer configuration with lower level config_key.
      
LOOP AT lt_access_config INTO ls_access_config.
        ls_config_search_key
-role_key ls_access_config-step_config.

        choose_config_by_ac_seq
EXPORTING is_search_key         ls_config_search_key
                                           it_config_cus         
it_config_cus
                                           it_config_sap         
it_config_sap
                                 
IMPORTING es_successfull_key    
ls_successfull_key
                                           ev_config_data_origin 
ls_config_data_origin )
.

        
"Customer configuration found for role_key

        
IF ls_config_data_origin 'C'.
          
READ TABLE it_config_cus INTO es_config_choosen
                                   
WITH KEY role_key ls_successfull_key-
role_key
                                   component_usage 
ls_successfull_key-
component_usage
                                   object_type 
ls_successfull_key-
object_type
                                    object_sub_type 
ls_successfull_key-object_sub_type.

          ev_config_choosen_origin 
'CUS'.
          
RETURN.
        
ENDIF.
      
ENDLOOP.


  
ENDMETHOD.                    "if_dlc_config_access~choose_config
ENDCLASS.



No comments:

Post a Comment