
Search Customer Management by custom Lifecycle Status
Enable search by status on Opportunity and Service Request search screens in SAP S/4HANA for Customer Management.
Display status description on Opportunity and Service Request search result screens in SAP S/4HANA for Customer Management.
Optimize performance of 1Order status search by avoiding joining on CRM_JEST status table in S/4HANA CM.
Functional and Technical consultants.
No coding skills are needed.
Status search was available on Opportunity and Service Request screens as standard field STATUS_COMMON which provided a concatenated combination of user status and status profile for all process types in the system. From a technical point of view, the search required either to JOIN on CRM_JEST and CRMD_ORDER_INDEX tables or just using view CRMV_INDEX_JEST which considered the tables. The approach was correct and available almost out of the box but it had two side effects:
The status search known from CRM 7.0 is no longer available. Field STATUS_COMMON is still technically available but it is obsolete and the search engine is not working out of the box (see note https://me.sap.com/notes/2768599).
There is a new data model which gave up CRMD_ORDER_INDEX (and join on CRM_JEST) for CRMS4D_OPPT_H and CRMS4D_SERV_H tables. Luckily, a new version of the system brought us a new possibility which is the so-called Lifecycle Status (see note https://me.sap.com/notes/3074858). Customization is available in tcode SM34 cluster view CRMS4VC_STAT_LC. Requires two steps:
The concept is well explained in the blog post: https://blogs.sap.com/2018/03/08/one-order-status-component-in-s4hana-for-customer-management/
Despite the fact that the above blog is amazing, some extra steps still must be performed to provide a fully working solution:
1. Use the below report to validate status profile customizing and to generate Status Lifecycle customizing by Status code (TXT04) or Status description (TXT30) of status profiles resolved from process types
1.1 Go to tcode SE38, create new report ZCRM_GENERATE_STATUS_LIFECYCLE
1.2 Paste code from the code snippet, save and activate. NOTE: Report can only insert new entries in Status Lifecycle customizing, it has not update/delete statements.
*&---------------------------------------------------------------------* *& Report ZCRM_GENERATE_STATUS_LIFECYCLE *&---------------------------------------------------------------------* *& Report to validate status profile customization in TJ30T table *& and generate Status Lifecycle based on status profiles resolved *& from provided process types. *& *& Disclaimer: *& Author does not hold the reliability of any of any side effects of the program. *& Author hereby declare that any reliance upon this program shall be at your sole *& own risk. Under any circumstance author will not be liable for any direct, *& indirect, incidental, punitive or consequential damages of any kind whatsoever *& with respect to this program. *& *& Version: 1.0 *&---------------------------------------------------------------------* REPORT ZCRM_GENERATE_STATUS_LIFECYCLE. TYPES: BEGIN OF lty_proc_type, process_type TYPE crmt_process_type, user_stat_proc TYPE j_stsma, END OF lty_proc_type. DATA: lv_proc_type TYPE crmt_process_type_db. DATA: lt_tj30t TYPE TABLE OF tj30t. DATA: ls_tj30t TYPE tj30t. DATA: ls_tj30t_temp TYPE tj30t. DATA: lt_proc_type TYPE TABLE OF lty_proc_type. DATA: lv_i TYPE crms4_user_stat_lifecycle. DATA: lv_hint TYPE abap_bool. DATA: ls_cust_stat TYPE crms4c_stat_lc. DATA: lt_cust_stat TYPE TABLE OF crms4c_stat_lc. DATA: lt_cust_stat_check TYPE TABLE OF crms4c_stat_lc. DATA: ls_cust_stat_t TYPE crms4c_stat_lc_t. DATA: lt_cust_stat_t_check TYPE TABLE OF crms4c_stat_lc_t. DATA: lt_cust_stat_t TYPE TABLE OF crms4c_stat_lc_t. DATA: ls_cust_map TYPE crms4c_status. DATA: lt_cust_map TYPE TABLE OF crms4c_status. DATA: lt_cust_map_check TYPE TABLE OF crms4c_status. SELECTION-SCREEN BEGIN OF BLOCK blk1. SELECT-OPTIONS: proctype FOR lv_proc_type. PARAMETERS : language TYPE spras OBLIGATORY DEFAULT 'E', txt30 RADIOBUTTON GROUP mode, txt04 RADIOBUTTON GROUP mode DEFAULT 'X', fieldnam TYPE fieldname DEFAULT 'STAT_LIFECYCLE', append TYPE abap_bool AS CHECKBOX DEFAULT 'X', testrun TYPE abap_bool AS CHECKBOX DEFAULT 'X'. SELECTION-SCREEN END OF BLOCK blk1. "first check if any customization for stat_lifecycle is in place SELECT SINGLE * INTO ls_cust_stat FROM crms4c_stat_lc. IF sy-subrc = 0. WRITE: / |Warning: Found existing customization in table crms4c_stat_lc.| COLOR COL_NORMAL. ENDIF. SELECT SINGLE * INTO ls_cust_stat_t FROM crms4c_stat_lc_t. IF sy-subrc = 0. WRITE: / |Warning: Found existing customization in table crms4c_stat_lc_t.| COLOR COL_NORMAL. ENDIF. SELECT SINGLE * INTO ls_cust_map FROM crms4c_status. IF sy-subrc = 0. WRITE: / |Warning: Found existing customization in table crms4c_status.| COLOR COL_NORMAL. ENDIF. CLEAR: ls_cust_stat, ls_cust_stat_t, ls_cust_map. "get status profiles for process types SELECT process_type user_stat_proc FROM crmc_proc_type INTO TABLE lt_proc_type WHERE process_type IN proctype. "get user status texts for selected status profiles in leading language CHECK lt_proc_type IS NOT INITIAL. SELECT stsma estat spras txt04 txt30 FROM tj30t INTO CORRESPONDING FIELDS OF TABLE lt_tj30t FOR ALL ENTRIES IN lt_proc_type WHERE stsma = lt_proc_type-user_stat_proc. LOOP AT lt_tj30t ASSIGNING FIELD-SYMBOL(<fs_tj30t>). <fs_tj30t>-txt04 = condense( <fs_tj30t>-txt04 ). <fs_tj30t>-txt30 = condense( <fs_tj30t>-txt30 ). ENDLOOP. "give hint if TXT04 can be added IF txt04 = 'X'. SORT lt_tj30t BY txt04 txt30. LOOP AT lt_tj30t INTO ls_tj30t WHERE spras = language. IF to_upper( ls_tj30t-txt04 ) = to_upper( ls_tj30t_temp-txt04 ) AND to_upper( ls_tj30t-txt30 ) NE to_upper( ls_tj30t_temp-txt30 ). lv_hint = abap_true. EXIT. ENDIF. ls_tj30t_temp = ls_tj30t. ENDLOOP. CLEAR: ls_tj30t_temp, ls_tj30t. IF lv_hint = abap_true. ULINE. WRITE: / |Generation status lifecycle by TXT04 cannot be performed.| COLOR COL_NEGATIVE. WRITE: / |Please retry to generate status lifecycle by selecting TXT30 or fix following entries.|. WRITE: / |There are multiple long texts TXT30 for the same TXT04 in table tj30t for provided process types.|. LOOP AT lt_tj30t INTO ls_tj30t WHERE spras = language. IF to_upper( ls_tj30t-txt04 ) = to_upper( ls_tj30t_temp-txt04 ) AND to_upper( ls_tj30t-txt30 ) NE to_upper( ls_tj30t_temp-txt30 ). WRITE: / |TXT04: | && ls_tj30t-txt04 && | in stat profile | && ls_tj30t-stsma && | TXT30 '| && ls_tj30t-txt30 && |' vs. TXT30 '| && ls_tj30t_temp-txt30 && |' in stat profile | && ls_tj30t_temp-stsma. ENDIF. ls_tj30t_temp = ls_tj30t. ENDLOOP. CLEAR: ls_tj30t_temp, ls_tj30t. EXIT. ELSE. ULINE. WRITE: / |Generation status lifecycle by TXT04 can be performed.| COLOR COL_POSITIVE. ENDIF. ENDIF. IF append = 'X' AND txt04 = ''. ULINE. WRITE: / |Append mode based on TXT30 field is not allowed.| COLOR COL_NEGATIVE. WRITE: / |It's only possible to append new values for customization generated based on TXT04 field.| COLOR COL_NEGATIVE. EXIT. ENDIF. IF txt30 = abap_true. "first determine stat_lifecycle for leading language SORT lt_tj30t BY txt30. LOOP AT lt_tj30t INTO ls_tj30t WHERE spras = language. IF to_upper( ls_tj30t-txt30 ) = to_upper( ls_tj30t_temp-txt30 ). CONTINUE. ENDIF. ADD 1 TO lv_i. ls_tj30t_temp = ls_tj30t. ls_cust_stat_t-language = ls_tj30t-spras. ls_cust_stat-stat_lifecycle = |{ lv_i ALPHA = IN }|. ls_cust_stat_t-stat_lifecycle = |{ lv_i ALPHA = IN }|. ls_cust_stat_t-description = ls_tj30t-txt30. INSERT ls_cust_stat INTO TABLE lt_cust_stat. INSERT ls_cust_stat_t INTO TABLE lt_cust_stat_t. ENDLOOP. "second determine stat-lifecycle for other languages LOOP AT lt_tj30t INTO ls_tj30t WHERE spras <> language. "get TXT30 of the leading language READ TABLE lt_tj30t INTO ls_tj30t_temp WITH KEY stsma = ls_tj30t-txt30 estat = ls_tj30t-estat spras = language. IF sy-subrc = 0. "based on TXT30 from leading language determine stat_lifecycle READ TABLE lt_cust_stat_t INTO ls_cust_stat_t WITH KEY description = ls_tj30t_temp-txt30. IF sy-subrc = 0. "now we have stat_lifecycle for leading language, change translation language and description ls_cust_stat_t-language = ls_tj30t-spras. ls_cust_stat_t-description = ls_tj30t-txt30. INSERT ls_cust_stat_t INTO TABLE lt_cust_stat_t. ENDIF. ELSE. WRITE: |Not found status translation in leading language. Check your status profile translation.| COLOR COL_NEGATIVE. WRITE: / ls_tj30t. EXIT. ENDIF. ENDLOOP. ELSEIF txt04 = abap_true. "in this case we only need to worry to find unique values of TXT04 SORT lt_tj30t BY txt04. LOOP AT lt_tj30t INTO ls_tj30t. IF to_upper( ls_tj30t-txt04 ) NE to_upper( ls_tj30t_temp-txt04 ). ls_cust_stat-stat_lifecycle = to_upper( ls_tj30t-txt04 ). INSERT ls_cust_stat INTO TABLE lt_cust_stat. ENDIF. ls_tj30t_temp = ls_tj30t. ls_cust_stat_t-language = ls_tj30t-spras. ls_cust_stat_t-stat_lifecycle = to_upper( ls_tj30t-txt04 ). ls_cust_stat_t-description = ls_tj30t-txt30. INSERT ls_cust_stat_t INTO TABLE lt_cust_stat_t. ENDLOOP. ENDIF. IF lt_cust_stat IS NOT INITIAL. SORT lt_cust_stat. DELETE ADJACENT DUPLICATES FROM lt_cust_stat. SORT lt_cust_stat_t. DELETE ADJACENT DUPLICATES FROM lt_cust_stat_t. SELECT stat_lifecycle FROM crms4c_stat_lc INTO CORRESPONDING FIELDS OF TABLE lt_cust_stat_check FOR ALL ENTRIES IN lt_cust_stat WHERE stat_lifecycle = lt_cust_stat-stat_lifecycle. IF lt_cust_stat_check IS NOT INITIAL AND append = ''. ULINE. WRITE: / |Status lifecycle values couldn't be generated for table crms4c_stat_lc.| COLOR COL_NEGATIVE. WRITE: / |There is overlapping in existing status lifecycle customization in below entries.|. IF txt30 = 'X'. WRITE: / |Please remove below status lifecycle customization or change TXT30 for affected status profiles and try again:|. ELSEIF txt04 = 'X'. WRITE: / |Please remove below status lifecycle customization or change TXT04 for affected status profiles and try again:|. ENDIF. LOOP AT lt_cust_stat_check INTO ls_cust_stat. WRITE: / CONV string( ls_cust_stat ). ENDLOOP. ULINE. WRITE: / |Status lifecycle values which were planned to be added for table crms4c_stat_lc:| COLOR COL_NORMAL. LOOP AT lt_cust_stat INTO ls_cust_stat. WRITE: / CONV string( ls_cust_stat ). ENDLOOP. ELSE. IF testrun = ''. IF append = ''. INSERT crms4c_stat_lc FROM TABLE lt_cust_stat. INSERT crms4c_stat_lc_t FROM TABLE lt_cust_stat_t. ELSE. INSERT crms4c_stat_lc FROM TABLE lt_cust_stat ACCEPTING DUPLICATE KEYS. INSERT crms4c_stat_lc_t FROM TABLE lt_cust_stat_t ACCEPTING DUPLICATE KEYS. ENDIF. ENDIF. ULINE. WRITE: |Status lifecycle values generated for table crms4c_stat_lc:| COLOR COL_POSITIVE. LOOP AT lt_cust_stat INTO ls_cust_stat. WRITE: / CONV string( ls_cust_stat ). ENDLOOP. ULINE. WRITE: |Status lifecycle values generated for table crms4c_stat_lc_t:| COLOR COL_POSITIVE. LOOP AT lt_cust_stat_t INTO ls_cust_stat_t. WRITE: / CONV string( ls_cust_stat_t ). ENDLOOP. ENDIF. ELSE. ULINE. WRITE: |Can't generate any customization based on provided process types.| COLOR COL_NEGATIVE. WRITE: |Check if provided process types exist, if they have assigned status profiles,|. WRITE: |if status profiles are not empty.|. EXIT. ENDIF. "now take care about User Status mapping for Reporting (CRMS4C_STATUS) IF txt30 = abap_true. "first determine status profile and estat for leading language LOOP AT lt_tj30t INTO ls_tj30t WHERE spras = language. IF sy-subrc = 0. "based on TXT30 from leading language determine stat_lifecycle READ TABLE lt_cust_stat_t INTO ls_cust_stat_t WITH KEY description = ls_tj30t-txt30. IF sy-subrc = 0. "now we have stat_lifecycle for leading language, change translation language and description ls_cust_map-fieldname = fieldnam. ls_cust_map-fieldvalue = ls_cust_stat_t-stat_lifecycle. ls_cust_map-status_profile = ls_tj30t-stsma. ls_cust_map-user_status = ls_tj30t-estat. INSERT ls_cust_map INTO TABLE lt_cust_map. ENDIF. ENDIF. ENDLOOP. ELSEIF txt04 = abap_true. "in this case we only need to worry to find unique values of TXT04 LOOP AT lt_tj30t INTO ls_tj30t. IF sy-subrc = 0. "based on TXT04 from leading language determine stat_lifecycle READ TABLE lt_cust_stat_t INTO ls_cust_stat_t WITH KEY stat_lifecycle = ls_tj30t-txt04. IF sy-subrc = 0. "now we have stat_lifecycle for leading language, change translation language and description ls_cust_map-fieldname = fieldnam. ls_cust_map-fieldvalue = ls_cust_stat_t-stat_lifecycle. ls_cust_map-status_profile = ls_tj30t-stsma. ls_cust_map-user_status = ls_tj30t-estat. INSERT ls_cust_map INTO TABLE lt_cust_map. ENDIF. ENDIF. ENDLOOP. ENDIF. IF lt_cust_map IS NOT INITIAL. SORT lt_cust_map. DELETE ADJACENT DUPLICATES FROM lt_cust_map. "check against overwritting mapping table SELECT fieldname fieldvalue status_profile user_status FROM crms4c_status INTO CORRESPONDING FIELDS OF TABLE lt_cust_map_check FOR ALL ENTRIES IN lt_cust_map WHERE fieldname = lt_cust_map-fieldname * AND fieldvalue = lt_cust_map-fieldvalue AND status_profile = lt_cust_map-status_profile AND user_status = lt_cust_map-user_status. IF lt_cust_map_check IS NOT INITIAL AND append = ''. ULINE. WRITE: / |Status lifecycle mapping couldn't be generated for table crms4c_status.| COLOR COL_NEGATIVE. WRITE: / |There is overlapping in existing mapping customization in below entries.|. WRITE: / |Please remove below mapping customization or change FIELDNAM and try again:|. LOOP AT lt_cust_map_check INTO ls_cust_map. WRITE: / CONV string( ls_cust_map ). ENDLOOP. ULINE. WRITE: / |Status lifecycle mappings which were planned to be added for table crms4c_status:| COLOR COL_NORMAL. LOOP AT lt_cust_map INTO ls_cust_map. WRITE: / CONV string( ls_cust_map ). ENDLOOP. ELSE. IF testrun = ''. IF append = ''. INSERT crms4c_status FROM TABLE lt_cust_map. ELSE. INSERT crms4c_status FROM TABLE lt_cust_map ACCEPTING DUPLICATE KEYS. ENDIF. ENDIF. ULINE. WRITE: / |Status lifecycle mapping generated for table crms4c_status:| COLOR COL_POSITIVE. LOOP AT lt_cust_map INTO ls_cust_map. WRITE: / CONV string( ls_cust_map ). ENDLOOP. ENDIF. ELSE. ULINE. WRITE: / |Can't generate any mapping customization based on provided process types.| COLOR COL_NEGATIVE. EXIT. ENDIF.
1.3 To generate Lifecycle Status customization for Service Requests and Opportunities:
1.3.1 Execute report with parameters (for Service Request):
1.3.2 In case of any red line (error), correct the problem according to the section Troubleshoting and try again
1.3.3 If test run of the report returns no error (no red lines) execute report again with the same parameters but change field:
1.3.4 Execute report with parameters (for Opportunity):
1.3.5 In case of any red line (error), correct the problem according to the section Troubleshoting and try again
1.3.6 If test run of the report returns no error (no red lines) execute report again with the same parameters but change field:
1.5 Go to tcode SM34 View Cluster CRMS4VC_STAT_LC and add customization to transport request.
2. Enable correct values display in column Lifecycle Status on the Opportunity search result screen. In my system version, column Lifecycle Status (STAT_LIFECYCLE_OPPT_DESC) could only show standard A-E Lifecycle Status descriptions, custom Lifecycle Status descriptions were not displayed.
2.1 Go to tcode SE18, select BAdI Name: CRM_BADI_RF_Q1O_READ and select Enhancement Implementation > Create
2.2 In new window specify below and confirm:
2.3 In new window specify below and confirm:
2.4 Go to section Filter Values in left panel, Select filter values BTQOPP = OBJ_IL
2.5 Go to section Implementing Class in left panel, Double click on IF_CRM_RF_Q1O_READ~READ and confirm
2.6 Paste code from the code snippet, save and activate.
METHOD if_crm_rf_q1o_read~read. CONSTANTS: lc_domname TYPE dd07l-domname VALUE 'CRMS4_STAT_LIFECYCLE_OPPT', lc_fieldname TYPE fieldname VALUE 'STAT_LIFECYCLE_OPPT'. DATA: lt_cust_stat_t TYPE TABLE OF crms4c_stat_lc_t. DATA: lt_domain TYPE TABLE OF dd07v. FIELD-SYMBOLS: <fs_query_result> TYPE crmst_query_r_opp_btil. *get status lifecycle definition SELECT * FROM crms4c_stat_lc_t INTO TABLE lt_cust_stat_t WHERE language = sy-langu. *get standard lifecycle definition CALL FUNCTION 'GET_DOMAIN_VALUES' EXPORTING domname = lc_domname text = 'X' TABLES values_tab = lt_domain EXCEPTIONS no_values_found = 1 OTHERS = 2. IF sy-subrc <> 0. * Implement suitable error handling here ENDIF. * fill standard result fields CALL FUNCTION 'CRM_BSP_OIC_1O_READ_FROM_RF' EXPORTING it_object_key = it_object_key iv_screen_structure_name = iv_result_structure_name IMPORTING et_screen_structure = et_result_structure. LOOP AT et_result_structure ASSIGNING <fs_query_result>. CHECK <fs_query_result>-stat_lifecycle_oppt IS NOT INITIAL. READ TABLE lt_cust_stat_t INTO DATA(ls_cust_stat_t) WITH KEY stat_lifecycle = <fs_query_result>-stat_lifecycle_oppt. IF sy-subrc = 0. <fs_query_result>-stat_lifecycle_oppt_desc = ls_cust_stat_t-description. ELSE. READ TABLE lt_domain INTO DATA(ls_domain) WITH KEY domvalue_l = <fs_query_result>-stat_lifecycle_oppt. IF sy-subrc = 0. <fs_query_result>-stat_lifecycle_oppt_desc = ls_domain-ddtext. ELSE. <fs_query_result>-stat_lifecycle_oppt_desc = ls_cust_stat_t-stat_lifecycle. ENDIF. ENDIF. ENDLOOP. ENDMETHOD.
2.7 Optionally you can redefine IF_CRM_RF_Q1O_READ~READ_TSTMP and just keep it blank to get rid of the warning message.
2.8 Activate Enhancement
3. Ensure that Status Lifecycle code and Status Lifecycle description are exposed on the WebUI views:
- search Opportunity view BT111S_OPPT/Search (BOL: BTQOpp), field: Lifecycle Status (STAT_LIFECYCLE_OPPT)
- result Opportunity view BT111S_OPPT/Result (BOL: BTQOpp), field: Lifecycle Status (STAT_LIFECYCLE_OPPT_DESC)
- search Service Request view SRQM_INCIDENT_S/IncidentSR (BOL: BTQSrvReq), field: Life Cycle Status (STAT_LIFECYCLE)
- result Service Request view SRQM_INCIDENT_S/IncidentSRL (BOL: BTQRSrvReq), field: Life Cycle Status (STAT_LIFECYCLE_DESC)
4. Since now, every document save action (within specified process types) will automatically save the Status Lifecycle in the CRMS4D_OPPT_H-STAT_LIFECYCLE_OPPT (for Opportunities) and CRMS4D_SERV_H-STAT_LIFECYCLE (for Service Requests).
Those documents which were saved after performing the above steps are searchable in Opportunity and Service Request views.
A) In case of a more restrictive mode (TXT04), report will compare all selected status profiles by field TXT04. It must be only one status per status profile having a unique Status code TXT04. SAP standard throws a warning once another status with the same TXT04 is being added within the same status profile.
Example: Status profile ZLRC0001 has user status E0004, TXT04 status CANC and description in TXT30 'Cancelled'. The same Status profile ZLRC0001 has user status E0007, TXT04 status CANC and description in TXT30 'Discarded'. The easiest way to fix the issue is to align the description from status profile ZLRC0001, user status E0007, TXT04 CANC and change status code TXT04 from CANC to DISC.
B) In case of more restrictive mode (TXT04), report will compare all selected status profiles by field TXT04. Corresponding descriptions in field TXT30 should be the same for given TXT04 in all status profiles.
Example: Status profile ZOPPT1 has user status E0001, TXT04 status OPEN and description in TXT30 'Open'. Status profile ZOPPT2 has user status E0002, TXT04 status OPEN and description in TXT30 'Initial'. The easiest way to fix the issue is to align description from status profile ZOPPT2, user status E0002, TXT04 OPEN and change description from 'Initial' to 'Open' or adjust Status code TXT04 from OPEN to INIT in status profile ZOPPT2.
C) If points A and B can’t be resolved, there is another mode TXT30 which can be used. In this case the Lifecycle Status will be generated by Status description, not Status code. Please note that this function may not support APPEND mode and different field names.
D) Above validation is executed only for the leading language specified in the report by parameter LANGUAGE. The assumption is that status description TXT30 translations to other languages are consistent. For example, status profile ZOPPT1 has status code TXT04 OPEN and English description 'Open' and Spanish description 'Abierto'. Status profile ZOPPT2 having status code TXT04 OPEN and English description 'Open' must have Spanish description 'Abierto', not e.g. 'Iniciar'.
In case when any status profile is updated with new statuses - report ZCRM_GENERATE_STATUS_LIFECYCLE should be executed for the corresponding process type to the changed status profile. Report will generate mapping for the newly created statuses. Don't forget to add new mappings to transport request.
In case when any status is deleted from status profile - to keep the customization clean, please go to tcode SM34 View Cluster CRMS4VC_STAT_LC and remove corresponding mappings manually.
In case when description or translation is changed in status profile - to keep the customization clean, please go to tcode SM34 View Cluster CRMS4VC_STAT_LC and update corresponding mappings manually.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.