Message Check on Save

Identify Message Class and Number
You can activate extended message tracking by setting user parameter BSPWD_USER_LEVEL (and CRM_USER_LEVEL) to value 9 in transaction SU3 resp. SU01. Now you will see the wanted details on mouse hover of the message in Web UI.

Correct Error Flag
Sometimes it happen, that a Business Transaction contains no error messages but is still flagged as erroneous.

This inconsistency can be solved using report CRM_MESSAGES_CHECK like mentioned in SAP Note „1971092 – Wrong System Status ‚Contain Errors'“. However this report is not able to identify all issues: If a business transaction has no message log but is flagged as erroneous, it will not be identified. But if the message log exists and is empty it will be identified.

Error Message Replacement
Sometimes an error message shown in SAP Web Client UI might be too technical. In this case it is possible to replace it by a user-friendly one. The SAP Web Client UI standard feature “Message Replacement” can be used here.

  1. (Activate business function UI_FRW_1 and UI_FRW_1_DOCU in transaction SFW5.)
  2. Assigning function profile MSG_REPLACE to your business role.
  3. Create own message classes and messages using transaction SE91.
  4. Configure all wanted message replacements SPRO -> CRM -> UI Framework -> UI Framework Definition -> Define Messages to Be Replaced.

Mandatory Field Check on Save
Sometimes fields are configured as mandatory in SAP Web Client UI. In case of empty mandatory fields end-users will get an error message. It is still possible to save. To avoid saving you can activate the “SAP Web Client UI Mandatory Field Check on Save” feature.

  1. Configure your Web UI and mark fields as mandatory.
  2. Maintain parameter CRMORDER-NO_SAVE_MAND_FIELDS in configuration table SMOFPARSFA.

More details:

  • SAP Note „1353553 – Opportunity: Behavior of mandatory fields in Web UI“
  • http://scn.sap.com/message/14553524

Message Check on Save
Sometimes business transactions contains error messages. Usually end-users can still save. In most cases this is acceptable because status change to next status is not allowed in case of errors. In some cases saving is needed, because some activities are performed on save which might resolve the error together with the error message. However, in some seldom cases save shall be blocked for certain error messages.

One example is COM_PARTNER 145 „Business Partner is not a valid business partner.“

In SAP standard there exist no feature to disallow saving dependent on an certain error message. Therefore you have to develop it by creating a configuration table containing fields CLIENT, OBJECT_NAME, MSGTY, MSGID, MSGNO, LANGU and TEXT and by implementing BADI ORDER_SAVE (method CHECK_BEFORE_SAVE).

  1. Check if dialog mode is active using function module COM_PARTNER_DIALOG_MODE_CHECK (Check should only be performed in case of online/foreground processing)
  2. Check if SAP Web Client UI is active using method cl_thtmlb_util=>get_business_role_name (Check should only be performed in case of online/foreground processing)
  3. Select all configured messages using view /GLB/MECOS_R.
  4. Get all messages for current business transaction using function module CRM_MESSAGES_SEARCH.
  5. Get details for all messages using function module CRM_MESSAGES_GET_MSG_INFO.
  6. Check whether business transaction contains configured messages. Check on Object Name, Message Type, Message Class and Message Number. All fields can be left empty in configuration which means “all”.
  7. Cancel save by raising exception DO_NOT_SAVE. If an error message is configured transfer this customer specific error message.
METHOD if_ex_order_save~check_before_save.

DATA:
lv_profile    TYPE crmt_ui_profile,
lt_message    TYPE TABLE OF /glb/mecos_r,
* ls_msg_idno TYPE bal_s_idno,
* lt_msg_idno TYPE bal_r_idno,
lt_msg_handle TYPE bal_t_msgh,
ls_msg_info   TYPE crmt_msg_info,
ls_msg        TYPE bal_s_msg.

FIELD-SYMBOLS:
<fs_message>    LIKE LINE OF lt_message,
<fs_msg_handle> LIKE LINE OF lt_msg_handle.

*-------------------------------------------------------------------------

*Get dialog mode state.
CALL FUNCTION 'COM_PARTNER_DIALOG_MODE_CHECK'
EXCEPTIONS
no_dialog = 1
OTHERS    = 2.

*We are in dialog mode (online/foreground processing).
CHECK sy-subrc = 0.

*Get Business Role
CALL METHOD cl_thtmlb_util=>get_business_role_name
RECEIVING
rv_role = lv_profile.

*We are in SAP Web Client UI (online/foreground processing).
CHECK lv_profile IS NOT INITIAL.

*Alle registrierten Fehlermeldungen lesen.
SELECT *
INTO TABLE lt_message[]
FROM /glb/mecos_r.

*There are some messages configured.
CHECK lt_message[] IS NOT INITIAL.

**Build search conditions.
* REFRESH lt_msg_idno[].
* LOOP AT lt_message ASSIGNING <fs_message>.
*
* ls_msg_idno-low-msgid = <fs_message>-msgid.
* ls_msg_idno-low-msgno = <fs_message>-msgno.
* CLEAR ls_msg_idno-high.
* ls_msg_idno-sign = 'I'.
* ls_msg_idno-option = 'EQ'.
* APPEND ls_msg_idno TO lt_msg_idno.
*
* ENDLOOP.

*Search for matching messages.
CALL FUNCTION 'CRM_MESSAGES_SEARCH'
EXPORTING
* it_r_msgidno = lt_msg_idno[]
iv_ref_object   = iv_guid
iv_ref_kind     = 'A'
* IV_CALLER_NAME =
* IT_LOGICAL_KEYS =
* IV_PROBCLASS =
* IV_DETLEVEL =
IMPORTING
et_msg_handle   = lt_msg_handle
EXCEPTIONS
appl_log_error  = 1
error_occurred  = 2
OTHERS          = 3.

*There should never occur an error here.
*We found some messages.
CHECK sy-subrc = 0 AND lt_msg_handle[] IS NOT INITIAL.

LOOP AT lt_msg_handle ASSIGNING <fs_msg_handle>.

*Get message details.
CALL FUNCTION 'CRM_MESSAGES_GET_MSG_INFO'
EXPORTING
is_msg_handle           = <fs_msg_handle>
* IV_GET_CALLER_NAME = TRUE
IMPORTING
es_info                 = ls_msg_info
es_msg                  = ls_msg
EXCEPTIONS
not_found               = 1
wrong_context_structure = 2
data_error              = 3
OTHERS                  = 4.

*There should never occur an error here.
CHECK sy-subrc = 0.

*Check all details.
LOOP AT lt_message
ASSIGNING <fs_message>
WHERE ( object_name = ls_msg_info-object_name OR object_name IS INITIAL ) AND
( msgty       = ls_msg-msgty            OR msgty       IS INITIAL ) AND
( msgid       = ls_msg-msgid            OR msgid       IS INITIAL ) AND
( msgno       = ls_msg-msgno            OR msgno       IS INITIAL ).

*Check IV_CALLER_NAME.

*All details are correct.
CHECK sy-subrc = 0.

*Prepare own error message for save abort.
IF <fs_message>-text IS NOT INITIAL.

cv_own_message = abap_true.
MESSAGE <fs_message>-text TYPE 'A' RAISING do_not_save.

ELSE.

*Abort save now (using standard error message).
RAISE do_not_save.

ENDIF.

ENDLOOP.

ENDLOOP.

ENDMETHOD.

Display and Search Business Partner Names in SAP Web UI

Issue „Display“

If a business partner is displayed in SAP Web Client UI, you will see „Firstname Lastname“ for natural persons or „Name1“ (address data maintained) or „Name 1 Name2“ (no address data maintained) for organizational Units. SAP Standard will never display „Name2“ even if your common design logic ensures that name1 is always prefix of name2.

Issue „Search“

The search is only working for „Lastname“, „Firstname Lastname“ and „Lastname, Firstname“ resp. „Name1“, „Name2 Name1“ and „Name1, Name2“. Search by „Name1 Name2“ or „Name2“ is not working for organizational units. Maybe it is working but only if Name2 contains spaces and if first word of Name2 is equal to Name1.

Challenge
If you want to change & harmonize this logic (especially to resolve the mismatch between display and search), you have to implement BADI BUPA_DESCRIPTION_GET which is used by function module BUPA_DESCRIPTION_GET, BUP_PARTNER_DESCRIPTION_GET and CRM_BUPA_DESCRIPTION_READ.

In SAP CRM standard (and therefore in some cases of SAP Solution Manager as well), the first address line determined by function module ADDRESS_INTO_PRINTFORM is used if the business partner has valid address data (please have a look at method method MOD_ATTR_DATA of class CL_CRM_PARTNER_RUN_BTIL). To change the building logic of the address lines, you have to create and register an own address layout key (900..999) in customizing view V_T005_BAS. You have to implement user exit SZAD0001. BADI BUPA_DESCRIPTION_GET or ADDR_PRINTFORM_SHORT cannot be used here. However in SAP CRM this additional implementation is needed but in SAP Solution Manager you can assume, that mostly BADI BUPA_DESCRIPTION_GET will work, if you have implemented SAP note „2157087 – Partner function „Support team“ only show Name1 in display mode“ in an extended version (Implement it. Remove restriction to a specific partner function and to display mode. Implement it for UI component AIC_CMCR_H and AIC_CMCD_H as well – not only for AIC_INCIDENT_H).

The search logic is located in function module COM_PARTNER_IDENTIFY which is called by method identify_partner of class cl_crm_uiu_bt_partner. (Please search for call of form fill_matchcode_fields). There is no BADI available, therefore you have to use modification or implicit enhancement techniques. Please ensure that SAP notes „1713745 – Search of Org. Unit by name is not working“ and „2280570 – Search of Org. Unit by name is not working II“ are implemented, because these notes change the search logic for organizational units. Please perform a modification in function module COM_PARTNER_IDENTIFY and replace „CONCATENATE LV_ENTRY ‚*‘ INTO LS_SELECTION_OPTION-LOW“ by „MOVE LV_ENTRY TO LS_SELECTION_OPTION-LOW“ in case search by name2 is not working for organizational units having no space in name2. You also have to replace „if not name1 is initial.“ by „if not name2 is initial.“ a few lines before (line 812 in my code).

*"----------------------------------------------------------------------
*"Methoden Signatur:
*"  Importing
*"     VALUE(IS_BUT000) TYPE BUT000
*"     VALUE(IV_ADDRNUMBER) TYPE AD_ADDRNUM
*"     VALUE(IV_VALDT) TYPE BAPIBUS1006_VALIDITY-VALID_DATE
*"     VALUE(IV_BAPI_ENVIROMENT) TYPE FLAG
*"  Changing
*"     VALUE(EV_DESCRIPTION) TYPE BU_DESCRIP
*"     VALUE(EV_DESCRIPTION_NAME) TYPE BU_DESCRIP
*"     VALUE(EV_DESCRIP_NAME_LONG) TYPE BU_DESCRIP_NAME_LONG
*"     VALUE(EV_DESCRIPTION_LONG) TYPE BUS000FLDS-DESCRIP_LONG
*"----------------------------------------------------------------------

METHOD if_ex_bupa_description_get~modify.

  DATA:
    lv_ext_id TYPE string.

  CASE is_but000-type.

*- Person ------------------------------------------------------------------------
    WHEN 1.

*Return Full Name
      ev_description_long = is_but000-name1_text.

*If Full Name is empty, return first and last name.
      IF ev_description_long IS INITIAL.
        ev_description_long = condense( is_but000-name_first && ` ` && is_but000-name_last ).
      ENDIF.

*- Organization ------------------------------------------------------------------------
    WHEN 2.

*Return Name 2 (Full Organization Name)
        ev_description_long = is_but000-name_org2.

*If Name 2 is empty, return Name 1 only (Short Organization Name)
        IF ev_description_long IS INITIAL.
          ev_description_long = is_but000-name_org1.
        ENDIF.

*- Group ------------------------------------------------------------------------
    WHEN 3.

*Return Full Name
      ev_description_long = is_but000-name1_text.

*If Full Name is empty, return Name 1 and Name 2.
      IF ev_description_long IS INITIAL.
        ev_description_long = condense( is_but000-name_grp1 && ` ` && is_but000-name_grp2 ).
      ENDIF.

  ENDCASE.

*Return the same value for all returning parameters.
  ev_description = ev_description_name = ev_descrip_name_long = ev_description_long.

ENDMETHOD.

METHOD CL_AIC_CMCR_AICCMCRHEADER_CN04->get_header_fct.
METHOD CL_AIC_CMCD_BTPARTNERSET_CN->get_header_fct.

  DATA: lo_bol_entity     TYPE REF TO if_bol_bo_property_access.

  CLEAR rv_partner_value.

  lo_bol_entity = cl_ai_crm_bp_helper=>get_partner_bol_entity(
    iv_process_type      = me->mo_view_controller->get_process_type( )
    iv_partner_fct_order = iv_partner_fct_order
    io_col_iterator      = io_col_iterator
    io_col_wrapper       = me->collection_wrapper ).

*{   REPLACE
*\  rv_partner_value = cl_crm_uiu_bt_partner=>get_partner2( lo_bol_entity ).
*SAP Note 2157087 extended version:
      DATA lv_value             TYPE bu_partner.
      DATA lv_value_full        TYPE bu_partner.
      DATA lv_description_name TYPE bu_descrip.
      DATA lt_return           TYPE TABLE OF bapiret2.
      lv_value = cl_crm_uiu_bt_partner=>get_partnerno( lo_bol_entity ).
      CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'
        EXPORTING
          input  = lv_value
        IMPORTING
          output = lv_value_full.

      CALL FUNCTION 'BUPA_DESCRIPTION_GET'
        EXPORTING
          iv_partner          = lv_value_full
*           IV_PARTNER_GUID     =
*           IV_VALDT            = SY-DATLO
        IMPORTING
          ev_description_name = lv_description_name
        TABLES
          et_return           = lt_return.

      MOVE lv_description_name TO rv_partner_value.
*}   REPLACE

ENDMETHOD.

Änderung des Internetbrowsers für SAP CRM Web UI funktioniert nicht mit Single Sign On

  1. Bitte stelle sicher, dass Firefox, Google Chrome, Opera etc. dein Standardbrowser ist. Wie das geht ist hier erklärt: https://support.google.com/chrome/answer/95417?hl=en
  2. Ab jetzt sollten die Transaktionen WUI, CRM_UI und SM_CRM diesen Internet Browser und nicht mehr den Microsoft Internet Explorer (IE) nutzen.
  3. Falls die Transaktionen WUI und CRM_UI funktionieren, SM_CRM aber nicht, dann liegt das am Single Sign On (SSO). Es sieht so aus, also ob bei aktivem Single Sign On automatisch der IE genutzt wird. Konkret verifizieren kannst du das mit der Transaktion START_BSP und der BSP-Anwendung „CRM_UI_START“. Der Folgende Artikel bestätigt, dass bei SSO ein IE-ActiveX-Control verwendet wird, um den Aufruf zu realisieren: https://scn.sap.com/thread/1406302

Lösung:

  1. Bitte erstelle einen SAP Incident. Die Erfolgswahrscheinlichkeit ist allerdings sehr gering, da es sich streng genommen um keinen Bug sondern eine Funktionsverbesserung handelt.
  2. Verwende nicht den SAP GUI. Hinterlege und nutze stattdessen den SAP CRM Web UI Link als Windows-Verknüpfung, Browser-Favorit oder Portallink. Teilweise kannst du Username und Passwort als Klartextparameter der URL mitgeben (Verknüpfung, Favorit). Teilweise wird SSO unterstützt (Portallink).

Get Multi Level Category

*"----------------------------------------------------------------------
*"Methoden Signatur:
*"  Importing
*"    IV_GUID TYPE CRMT_OBJECT_GUID
*"    IV_CATALOG_TYPE TYPE CRMT_CATALOGTYPE
*"  Returning
*"     VALUE(RT_RESULT) TYPE CRMT_ERMS_CAT_CA_LANG_TAB
*"----------------------------------------------------------------------
************************************************************************
* Method GET_CATEGORY                                                  *
* Date   26.01.2015                                                    *
*                                                                      *
*----------------------------------------------------------------------*
* Get Multi Level Category.                                            *
************************************************************************
METHOD get_category.

*Low Level Function for Debugging: CRM_ERMS_CAT_CA_READ + CRM_ERMS_CAT_AS_READ.

  TYPES:
    tt_category TYPE TABLE OF REF TO if_crm_erms_catego_category.

  DATA:
    li_aspect	    TYPE REF TO if_crm_erms_catego_aspect,
    li_category   TYPE REF TO if_crm_erms_catego_category,
    lr_categories TYPE REF TO data,
    ls_cat_lang   TYPE crmt_erms_cat_ca_lang.

  FIELD-SYMBOLS:
    <ft_category> TYPE tt_category,
    <fi_category> LIKE li_category.

*Ensure valid result.
  REFRESH rt_result[].

*Get Assigned Category.
  CALL METHOD cl_crm_ml_category_util=>get_categoryfirst
    EXPORTING
      iv_ref_guid     = iv_guid
      iv_ref_kind     = 'A'
      iv_catalog_type = iv_catalog_type
    IMPORTING
      er_aspect       = li_aspect
      er_category     = li_category.

  CHECK li_aspect IS BOUND AND li_category IS BOUND.

*Get All Parent Nodes.
  CALL METHOD cl_crm_ml_category_util=>get_cat_pars_all
    EXPORTING
      ir_aspect     = li_aspect
      ir_category   = li_category
    IMPORTING
      er_categories = lr_categories.

  CHECK lr_categories IS BOUND.

  ASSIGN lr_categories->* TO <ft_category>.

*Don't forget our assigned Category.
  INSERT li_category INTO <ft_category> INDEX 1.

  LOOP AT <ft_category> ASSIGNING <fi_category>.

*Get Category Details.
    CALL METHOD <fi_category>->get_details
*  EXPORTING
*    iv_auth_check = ' '
       IMPORTING
*        ev_cat        = ls_cat
         ev_cat_lang   = ls_cat_lang.

*Ensure that description is filled.
    IF ls_cat_lang-cat_desc IS INITIAL.
      ls_cat_lang-cat_desc = ls_cat_lang-cat_labl.
    ENDIF.

    IF ls_cat_lang-cat_desc IS INITIAL.
      ls_cat_lang-cat_desc = ls_cat_lang-cat-cat_id.
    ENDIF.

*Transfer Result
    INSERT ls_cat_lang INTO rt_result[] INDEX 1.

  ENDLOOP.

ENDMETHOD.

Get business partner description for a given partner function or user name

*"----------------------------------------------------------------------
*"Methoden Signatur:
*"  Importing
*"    IV_GUID TYPE CRMT_OBJECT_GUID
*"    IV_PARTNER_FCT TYPE CRMT_PARTNER_FCT
*"    IV_PARTNER_PFT TYPE CRMT_PARTNER_PFT
*"  Exporting
*"    EV_NUMBER TYPE BU_PARTNER
*"    EV_DESCRIPTION_NAME TYPE BU_DESCRIP
*"    EV_DESCRIPTION_SHORT TYPE COMT_PARTNER_ADDRESS_WO_STREET
*"    EV_DESCRIPTION_LONG TYPE COMT_PARTNER_ADDRESS_W_STREET
*"----------------------------------------------------------------------
************************************************************************
* Method GET_PARTNER_OF_FCT                                            *
* Date   26.01.2015                                                    *
*                                                                      *
*----------------------------------------------------------------------*
* Get Partner for given Partner Function.                              *
************************************************************************
METHOD GET_PARTNER_OF_FCT.

  DATA:
    ls_partner          TYPE crmt_partner_external_wrk,
    lv_description      TYPE bus000flds-descrip,
    lv_description_name	TYPE bus000flds-descrip,
    lv_description_long	TYPE bus000flds-descrip_long.

  CLEAR:
    ev_number,
    ev_description_name,
    ev_description_short,
    ev_description_long.

*Get partner for a given partner function or partner function type.
  CALL FUNCTION 'CRM_PARTNER_READ_OW'
    EXPORTING
      iv_ref_guid            = iv_guid
      iv_ref_kind            = 'A'
      iv_partner_fct         = iv_partner_fct
      iv_partner_pft         = iv_partner_pft
      iv_mainpartner_only    = 'X'
      iv_get_bp_numbers      = 'X'
*     IV_REFRESH_ADDRESS_REF = ' '
    IMPORTING
      es_partner_wrk         = ls_partner
    EXCEPTIONS
      error_occurred         = 1
      parameter_error        = 2
      entry_does_not_exist   = 3
      OTHERS                 = 4.

*Partner not found.
  CHECK sy-subrc = 0.

*Get Description
  CALL FUNCTION 'BUP_PARTNER_DESCRIPTION_GET'
    EXPORTING
      i_partnerguid      = ls_partner-bp_partner_guid
    IMPORTING
      e_description      = lv_description
      e_description_name = lv_description_name
      e_description_long = lv_description_long
    EXCEPTIONS
      partner_not_found  = 1
      wrong_parameters   = 2
      internal_error     = 3
      OTHERS             = 4.

*Partner not found.
  CHECK sy-subrc = 0.

*Transfer data.
  MOVE:
    ls_partner-partner_no TO ev_number,
    lv_description_name   TO ev_description_name,
    lv_description        TO ev_description_short,
    lv_description_long   TO ev_description_long.

*Alternatively we could use function CRM_PARTNER_TO_DISPLAY_OW.
*But here we get all partners and have to filter/select the wanted partner entry with own coding.
ENDMETHOD.

*"----------------------------------------------------------------------
*"Methoden Signatur:
*"  Importing
*"    IV_UNAME TYPE SYUNAME
*"  Exporting
*"    EV_DESCRIPTION_NAME TYPE BU_DESCRIP
*"    EV_DESCRIPTION_SHORT TYPE COMT_PARTNER_ADDRESS_WO_STREET
*"    EV_DESCRIPTION_LONG TYPE COMT_PARTNER_ADDRESS_W_STREET
*"----------------------------------------------------------------------
************************************************************************
* Method GET_PARTNER_BY_UNAME                                          *
* Date   26.01.2015                                                    *
*                                                                      *
*----------------------------------------------------------------------*
* Get Partner for given User Name.                                     *
************************************************************************
METHOD get_partner_by_uname.

  DATA:
    lv_partner_guid     TYPE bu_partner_guid,
    lv_description      TYPE bus000flds-descrip,
    lv_description_name	TYPE bus000flds-descrip,
    lv_description_long	TYPE bus000flds-descrip_long.

  CLEAR:
    ev_description_name,
    ev_description_short,
    ev_description_long.

*Get Partner for Username
  CALL FUNCTION 'BP_CENTRALPERSON_GET'
    EXPORTING
      iv_username         = iv_uname
    IMPORTING
      ev_bu_partner_guid  = lv_partner_guid
    EXCEPTIONS
      no_central_person   = 1
      no_business_partner = 2
      no_id               = 3
      OTHERS              = 4.

*Partner not found.
  CHECK sy-subrc = 0.

*Get Description
  CALL FUNCTION 'BUP_PARTNER_DESCRIPTION_GET'
    EXPORTING
      i_partnerguid      = lv_partner_guid
    IMPORTING
      e_description      = lv_description
      e_description_name = lv_description_name
      e_description_long = lv_description_long
    EXCEPTIONS
      partner_not_found  = 1
      wrong_parameters   = 2
      internal_error     = 3
      OTHERS             = 4.

*Partner not found.
  CHECK sy-subrc = 0.

*Transfer data.
  MOVE:
    lv_description_name   TO ev_description_name,
    lv_description        TO ev_description_short,
    lv_description_long   TO ev_description_long.

ENDMETHOD.