Zuordnungsblöcke bzw. Tabs im SAP Web Client UI dynamisch ausblenden

Mittels UI-Konfiguration lassen sich Zuordnungsblöcke in der Vorgangsbearbeitung flexibel konfigurieren. Teilweise kann die Konfiguration abhängig von der Vorgangsart oder dem Status gestaltet werden, sofern dies von der UI-Komponente vorgesehen ist.

Ein dynamisches Ausblenden von Zuordnungsblöcken, z.B. bei fehlender Berechtigung, ist jedoch nicht vorgesehen. Mit einer kleinen Erweiterung des SAP-Standards ist das aber kein Problem. Diese Erweiterung funktioniert sowohl für SAP CRM als auch für SAP Solution Manager ITSM und SAP Solution Manager ChaRM.

Erweiterung am Ende von Methode cl_crm_uiu_bt_tools=>get_ovviews_header:

*Here we hide one customer_h assignment block according to authority.

data:
  ls_deactive_views like line of lt_deactive_views.

*Perform authority check
AUTHORITY-CHECK OBJECT ...

IF sy-subrc NE 0.
  ls_deactive_views-component = 'BTCUSTOMER_H'.
  ls_deactive_views-viewname = 'ZUBTCustomerH_01.BTCUSTOMER_H/MainWindow'.
  append ls_deactive_views to lt_deactive_views.
endif.

*Compare on component name and view name is not enough, because we need to compare on component usage in case we have more than one BTCUSTOMERH assignment blocks.
data(lt_static_views) = it_static_views.
loop at lt_static_views assigning field-symbol(<fs_static_views>) where viewid cp 'ZUBTCustomerH*'.
  <fs_static_views>-VIEWNAME = <fs_static_views>-viewid.
endloop.

*Rebuild result.
get_ovviews_return_tables( EXPORTING it_static_views = lt_static_views it_deactive_views = lt_deactive_views IMPORTING et_views_to_detach = et_views_to_detach et_views_to_reattach = et_views_to_reattach ).
*Here we hide all unauthorized assignment blocks (tabs).

data:
  ls_deactive_views like line of lt_deactive_views.

loop at it_static_views assigning field-symbol(<fs_static_views>).

*Perform authority check
AUTHORITY-CHECK OBJECT ...

IF sy-subrc NE 0.
  ls_deactive_views-component = <fs_static_views>-component.
  ls_deactive_views-viewname = <fs_static_views>-viewname.
  append ls_deactive_views to lt_deactive_views.
endif.

endloop.

*Rebuild result.
get_ovviews_return_tables( EXPORTING it_static_views = lt_static_views it_deactive_views = lt_deactive_views IMPORTING et_views_to_detach = et_views_to_detach et_views_to_reattach = et_views_to_reattach ).

E-Mail-Benachrichtigungen richtig konfigurieren

Eine sehr wichtige Funktionalität im SAP Solution Manager ITSM und SAP Solution Manager ChaRM ist die Versendung von E-Mail-Benachrichtigungen beim Statuswechsel. Früher mussten hier umständlich Smartform-Entwicklungen getätigt werden. Das geht mittlerweile dank der HTML-Mail-Forms deutlich einfacher. Dennoch ist die Konfiguration immer noch sehr aufwändig und fehleranfällig.

Hiermit gebe ich Ihnen gern ein paar Tipps an die Hand, um den Aufwand zu reduzieren und die Fehler zu minimieren:

  1. Deaktivieren Sie BADI CRM_ACTION_BADI in Transaktion SE19, da sonst die Benachrichtigung nicht korrekt funktioniert, sobald der Empfänger in mehreren Partnerfunktionen eingetragen ist.
  2. Definieren Sie möglichst wenige Mail-Formulare. In der Regel reicht ein einziges Formular mit Vorgangsnummer, Vorgangsbezeichnung und Anwenderstatus aus.
  3. Überlegen Sie sich eine sinnvolle Namenskonvention für die PPF-Aktionen, z.B. <Vorgangsart>_SEND_MAIL_<Rolle>_<Status>.
  4. Achten Sie auf folgende Eigenschaften der PPF-Aktionen:
    1. Sortiernummer größer als zugehörige [oder alle] Statuswechselaktion[en], da E-Mail nach dem Statuswechsel versendet werden soll.
    2. Verarbeitung beim Sichern
    3. Automatisch einplanen
    4. Partnerabhängig mit korrekter Partnerfunktion
    5. Einmalig: Max. 1 Aktion je Aktionsdefinition
      Mehrmalig: Max. 1 unverarbeitete Aktion je Aktionsdefinition
    6. Pflege der ID des zuvor angelegten MAIL-Formulars als Parameter der Verarbeitungsmethode SEND_MAIL_WITH_MAIL_FORMS (Registrierung des Mailformulars im Transportauftrag nicht vergessen! Standardmäßig werden Mail-Formulare nicht transportiert.)
  5. Planen Sie die Aktionen mit folgenden Bedingungen ein. Verwenden Sie für die Bedingungsdefinitionen am besten die gleichen Namen wie für die PPF-Aktionen. Es ist sehr unwahrscheinlich und zudem sehr gefährlich, dass Sie die Bedingungen für andere Aktionen wiederverwenden.
    1. Einmalige Aktionen beim Anlegen
      • Einplanbedingung: Keine
      • Startbedingung: keine
    2. Einmalige Aktionen bei Statuswechsel im Vordergrund mittels PPF-Aktion
      • Einplanbedingung: Keine
        Einplanbedingung: Vorangehender Status
      • Startbedingung: Aktueller Status
    3. Einmalige Aktionen bei Statuswechsel im Hintergrund durch Massenänderung CRM_SOCM_SERVIE_REPORT oder Folgebeleg SET_PREDOC oder Genehmigungsprozess oder Dropdownbox
      • Einplanbedingung: Keine
        Einplanbedingung: Aktueller Status
      • Startbedingung: Aktueller Status
    4. Einmalige Aktionen
      • Einplanbedingung: Keine
        Einplanbedingung: Vorangehender oder Aktueller Status
      • Startbedingung: Aktueller Status
    5. Mehrmalige Aktion bei Statuswechsel im Vordergrund mittels PPF-Aktion
      • Einplanbedingung: Vorangehender Status
      • Startbedingung: Aktueller Status
    6. Mehrmalige Aktion bei Statuswechsel im Hintergrund durch Massenänderung CRM_SOCM_SERVIE_REPORT oder Folgebeleg SET_PREDOC oder Genehmigungsprozess oder Dropdownbox
      • Einplanbedingung: Aktueller Status
      • Startbedingung: Aktueller Status und „STATUS_CHANGE = X“
    7. Mehrmalige Aktion
      • Einplanbedingung: Vorangehender oder Aktueller Status
      • Startbedingung: Aktueller Status und „STATUS_CHANGE = X“
    8. Beliebige Aktion
      • Einplanbedingung: Vorangehender oder Aktueller Status
      • Startbedingung: Aktueller Status und „STATUS_CHANGE = X“
    9. Hinweise:
      • Der Statuswechsel „CR: Laufende Implementierung -> Realisiert“ erfolgt im Hintergrund durch die Folgebelege
      • Der Statuswechsel „CR: Zu Genehmigen -> Genehmigt“ erfolgt im Hintergrund durch den Genehmigungsprozess
      • Incident, Problem und Service Request nutzen in der Regel keine PPF-Aktionen für den Statuswechsel. Das Verhalten ist hier analog zu den Hintergrundänderungen.
  6. Vergessen Sie das Testen nicht:
    1. Bedenken Sie beim Testen, dass der Empfänger verschieden vom Absender sein muss. Tragen Sie daher bei der Empfängerpartnerfunktion einen Geschäftspartner mit einer abweichenden E-Mail-Adresse ein.
    2. Spielen Sie die Prozesse (z.B. Änderungsantrag und Änderungsdokumente) einmal komplett mit den entsprechenden Statuswechseln durch.
    3. Durchlaufen Sie Schleifen mindestens zweimal. Vergessen Sie Sonderfälle wie das Zurückziehen oder den Vorabimport nicht.
    4. Führen Sie Statuswechsel einmal online und einmal per Massenänderung (z.B. Bestätigen von Änderungsdokument und Änderungsantrag) durch.

SAP CRM Web Client UI Session Timeout

Die aktuelle SAP CRM Web Client UI Sitzung wird im SAP CRM, im SAP Solution Manager IT Service Management und im SAP Solution Manager Change Request Management standardmäßig nach 30 Minuten Inaktivität automatisch beendet.

Um dieses Verhalten zu ändern, ist der Profilparameter „rdisp/plugin_auto_logout“ in Transaktion RZ11 entsprechend zu ändern. Zum Beispiel bewirkt ein Wert von 3600, dass die Sitzung eine Stunde lang erhalten bleibt.

Bitte beachten Sie, dass inaktive Sitzungen Systemressourcen belegen und eine Veränderung dieses Parameters negative Auswirkungen auf die Performance Ihres Systems haben kann. Außerdem bleiben Objektsperren die ganze Zeit erhalten.

Sollte die Sitzung trotz Änderung des Wertes früher als geplant ablaufen, prüfen Sie bitte auch die Profilparameter „icm/keep_alive_timeout“ und „icm/server_port_0 -> TIMEOUT“ (Siehe auch Transaktion SMICM -> Springen -> Parameter). Bitte stellen Sie außerdem sicher, dass die Änderungen entweder sofort wirken oder dass das System neu gestartet wird. Bitte stellen Sie außerdem sicher, dass die Änderungen bei einem Systemneustart erhalten bleiben.

Bitte beachten Sie, dass Sie zusätzlich im Technischen Profil der Benutzerrolle (SPRO -> CRM -> UI-Framework -> Technische Rollendefinition -> Technisches Profil) einstellen können, wie lange die Sitzung erhalten bleiben soll, wenn das SAP CRM Web Client UI verlassen wird (Browser schließen oder Navigation zu externer Webseite). Hier sollte der Wert auf wenige Sekunden eingestellt werden. Andernfalls werden Ihre Anwender vermehrt das Phänomen haben, dass Vorgänge von vermeintlich korrekt geschlossenen Sitzungen gesperrt sind und erst nach längerer Zeit wieder freigegeben werden.

Method to exchange Business Partner in Business Transactions on DB level which is working for closed documents as well

*Parameters:
*IV_HEADER_GUID	TYPE CRMT_OBJECT_GUID	| GUID of a CRM Order Object
*IV_BP_OLD	    TYPE BPARTNER	| Business Partner
*IV_BP_NEW	    TYPE BPARTNER	| Business Partner
*ERROR_OCCURRED	     Something happened

METHOD exchange_partner_db.

  DATA:
    lv_partner_guid   TYPE but000-partner_guid,
    lv_partner_number TYPE but000-partner,
    lv_partner_id     TYPE but000-partner,

    lt_crmd_partner     TYPE TABLE OF crmd_partner,
    lt_crmd_order_index TYPE TABLE OF crmd_order_index,

    lv_addr_nr          TYPE  adrnr,
    lv_addr_np          TYPE  adrnp,
    lv_addr_type        TYPE  addr_type,
    lv_addr_origin      TYPE  comt_addr_origin,
    lv_addr_operation   TYPE  bu_operation,
    lv_relation_partner TYPE  bu_partner_guid,
    lv_addr_is_standard TYPE  comt_partner_std_bp_address.

  FIELD-SYMBOLS:
         LIKE LINE OF lt_crmd_partner,
     LIKE LINE OF lt_crmd_order_index.

*-------------------------------------------------------------------------
*Get partner identifications of old partner.

  SELECT SINGLE partner_guid
    INTO lv_partner_guid
    FROM but000
    WHERE partner = iv_bp_old.

  SELECT SINGLE partner
    INTO lv_partner_number
    FROM but000
    WHERE partner = iv_bp_old.

  IF lv_partner_number IS NOT INITIAL.
    CALL FUNCTION 'CONVERSION_EXIT_ALPHA_OUTPUT'
      EXPORTING
        input  = lv_partner_number
      IMPORTING
        output = lv_partner_id.
  ENDIF.

  IF lv_partner_guid IS INITIAL OR lv_partner_number IS INITIAL.
*Partner number &1 is invalid.
    MESSAGE e050(/glb/9gtis_solman) WITH iv_bp_old RAISING error_occurred.
  ENDIF.

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

*Select partner dataset for header.
  SELECT *
    INTO TABLE lt_crmd_partner
    FROM crmd_partner
    WHERE partner_guid IN ( SELECT p~partner_guid
                              FROM crmd_partner AS p
                                   JOIN crmd_link AS l ON ( l~guid_set = p~guid AND l~objtype_hi = '05' AND l~objtype_set = '07' )
                                   JOIN crmd_orderadm_h AS h ON ( l~guid_hi = h~guid )
                              WHERE h~guid = iv_header_guid AND
                                    ( p~partner_no = lv_partner_guid OR
                                    p~partner_no = lv_partner_number OR
                                    p~partner_no = lv_partner_id ) AND
                                    ( p~no_type = '  ' OR p~no_type = 'BP' )
                          ).

*Select partner dataset for item.
  SELECT *
    APPENDING TABLE lt_crmd_partner
    FROM crmd_partner
    WHERE partner_guid IN ( SELECT p~partner_guid
                              FROM crmd_partner AS p
                                   JOIN crmd_link AS l ON ( l~guid_set = p~guid AND l~objtype_hi = '06' AND l~objtype_set = '07' )
                                   JOIN crmd_orderadm_i AS i ON ( l~guid_hi = i~guid )
                              WHERE i~header     = iv_header_guid AND
                                    ( p~partner_no = lv_partner_guid OR
                                    p~partner_no = lv_partner_number OR
                                    p~partner_no = lv_partner_id ) AND
                                    ( p~no_type = '  ' OR p~no_type = 'BP' )
                          ).

  IF lt_crmd_partner IS INITIAL.
*Dataset not found in CRMD_PARTNER.
    MESSAGE e051(/glb/9gtis_solman) WITH iv_bp_old RAISING error_occurred.
  ENDIF.

*Select index dataset for header or item.
  SELECT *
    INTO TABLE lt_crmd_order_index
    FROM crmd_order_index
    WHERE header = iv_header_guid AND
          ( partner_no = lv_partner_number OR
          partner_no = lv_partner_id ).

*-------------------------------------------------------------------------
*Get partner identifications of new partner.

*Get Partner GUID.
  CALL FUNCTION 'COM_PARTNER_CONVERT_GUID_TO_NO'
    EXPORTING
      iv_partner             = iv_bp_new
    IMPORTING
      ev_partner_guid        = lv_partner_guid
    EXCEPTIONS
      partner_does_not_exist = 1
      OTHERS                 = 2.

  IF sy-subrc <> 0.
*Partner number &1 is invalid.
    MESSAGE e050(/glb/9gtis_solman) WITH iv_bp_new RAISING error_occurred.
  ENDIF.

*Get Address data.
  CALL FUNCTION 'COM_PARTNER_ADDRESS_DETERMINE'
    EXPORTING
      iv_partner                 = iv_bp_new
*     iv_std_addr_only           = 'X'
    IMPORTING
      ev_addr_nr                 = lv_addr_nr
      ev_addr_np                 = lv_addr_np
      ev_addr_type               = lv_addr_type
      ev_addr_origin             = lv_addr_origin
      ev_addr_operation          = lv_addr_operation
      ev_relation_partner        = lv_relation_partner
      ev_addr_is_standard        = lv_addr_is_standard
    EXCEPTIONS
      partner_not_defined        = 1
      partner_does_not_exist     = 2
      rel_partner_does_not_exist = 3
      no_address_found           = 4
      OTHERS                     = 5.

  IF sy-subrc <> 0.
*No address data for partner &1 found.
*    MESSAGE e052(/glb/9gtis_solman) WITH iv_bp_new RAISING error_occurred.
  ENDIF.

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

*Exchange partner.
  LOOP AT lt_crmd_partner ASSIGNING .

*Exchange partner
    -partner_no = lv_partner_guid.
    -no_type = '  '. "Now key is a GUID
    -display_type = 'BP'. "Enrure that partner is shown as BP

*Exchange address.
    IF -addr_origin = 'A' OR -addr_origin = 'C' OR -addr_origin IS INITIAL.
      -addr_nr        = lv_addr_nr.
      -addr_np        = lv_addr_np.
      -addr_type      = lv_addr_type.
      -addr_origin    = lv_addr_origin.
      -addr_operation = lv_addr_operation.
      -relation_partner = lv_relation_partner.
      -std_bp_address = lv_addr_is_standard.
    ENDIF.

  ENDLOOP.

*Correct index table used by reporting.
  LOOP AT lt_crmd_order_index ASSIGNING .

    -partner_no = iv_bp_new.

  ENDLOOP.

*-------------------------------------------------------------------------
*Save data to database.

  UPDATE crmd_partner FROM TABLE lt_crmd_partner[].
  UPDATE crmd_order_index FROM TABLE lt_crmd_order_index[].

ENDMETHOD.

Report to add, change or delete Business Partners from/to/of Business Transactions

REPORT  ztemp_partner_change.

TABLES: bapibus20001_object_id.

SELECT-OPTIONS:
  s_objid FOR bapibus20001_object_id-object_id OBLIGATORY. "Object ID of Business Transaction

PARAMETERS:
  p_pfct TYPE comt_partner_wrk-partner_fct OBLIGATORY, "Partner Function to be changed.
  p_pnum TYPE but000-partner.                          "Partner Number (can be left empty to delete partner)

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

INCLUDE crm_object_kinds_con.

DATA:
  lv_partner_guid        TYPE but000-partner_guid,
  lt_header_guid         TYPE crmt_object_guid_tab,
  lt_partner_wrk         TYPE crmt_partner_external_wrkt,
  lt_partner_com         TYPE comt_partner_comt,
  ls_partner_com         LIKE LINE OF lt_partner_com,
  lv_partner_handle      LIKE ls_partner_com-ref_partner_handle,
  lt_input_field         TYPE crmt_input_field_tab,
  ls_input_field         TYPE crmt_input_field,
  ls_partner_logical_key TYPE comt_partner_logic_partner_key,
  ls_input_field_name    TYPE crmt_input_field_names,
  lt_active_switch       TYPE crmt_active_switch_t,
  ls_active_switch       LIKE LINE OF lt_active_switch.

FIELD-SYMBOLS:
         LIKE LINE OF lt_header_guid,
         LIKE LINE OF lt_partner_wrk.

**Convert Partner Number to Partner GUID.
*IF p_pnum IS NOT INITIAL.
*
*  CALL FUNCTION 'BUPA_NUMBERS_READ'
*    EXPORTING
*      iv_partner              = p_pnum
*    IMPORTING
*      ev_partner_guid         = lv_partner_guid
*    EXCEPTIONS
*      no_partner_specified    = 1
*      no_valid_record_found   = 2
*      inconsistent_parameters = 3
*      OTHERS                  = 4.
*
*  IF sy-subrc <> 0.
*    MESSAGE ID sy-msgid TYPE 'E' NUMBER sy-msgno
*            WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
*    EXIT.
*  ENDIF.
*ELSE.
*  CLEAR lv_partner_guid.
*ENDIF.

*Select all business transactions according to selection criteria.
SELECT guid
  INTO TABLE lt_header_guid
  FROM crmd_orderadm_h
  WHERE object_id IN s_objid.

*Read partner data for all selected business transactions (if partners are already maintained).
CALL FUNCTION 'CRM_ORDER_READ'
  EXPORTING
    it_header_guid       = lt_header_guid
  IMPORTING
    et_partner           = lt_partner_wrk
*   ET_EXCEPTION         =
  EXCEPTIONS
    document_not_found   = 1
    error_occurred       = 2
    document_locked      = 3
    no_change_authority  = 4
    no_display_authority = 5
    no_change_allowed    = 6
    OTHERS               = 7.

IF sy-subrc <> 0.
  MESSAGE ID sy-msgid TYPE 'E' NUMBER sy-msgno
          WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  EXIT.
ENDIF.

*Process every single business transaction.
LOOP AT lt_header_guid ASSIGNING .

  CLEAR ls_partner_com.

*Read corresponding partner (if already maintained). We assume that there can be only one per partner function.
  READ TABLE lt_partner_wrk
    ASSIGNING 
    WITH KEY ref_guid =  ref_partner_fct = p_pfct.

*Create a new entry to insert partner.
  IF sy-subrc <> 0.

    ls_partner_com-ref_guid           = .
    ls_partner_com-ref_kind           = gc_object_kind-orderadm_h. "Header
    ADD 1 TO lv_partner_handle.
    ls_partner_com-ref_partner_handle = lv_partner_handle.

*Take over all data from existing entry to change or delete partner.
  ELSE.

    MOVE-CORRESPONDING  TO ls_partner_com.

  ENDIF.

*Delete partner.
  IF p_pnum IS INITIAL.
    CLEAR:
      ls_partner_com-partner_fct,
      ls_partner_com-partner_no.

*Insert or change partner.
  ELSE.
    ls_partner_com-partner_fct        = p_pfct.
* ls_partner_com-partner_no         = lv_partner_guid.
* ls_partner_com-no_type            = '  '. "Value is a GUID
    ls_partner_com-partner_no         = p_pnum.
    ls_partner_com-no_type            = 'BP'. "Value is a Business Partner Number
    ls_partner_com-display_type       = 'BP'.
    ls_partner_com-kind_of_entry      = 'D'. "Origin: Interface

  ENDIF.

*Do some general data preparations.
  INSERT ls_partner_com INTO TABLE lt_partner_com.

*Build input_fields.
  MOVE-CORRESPONDING ls_partner_com TO ls_input_field.
  ls_input_field-objectname = 'PARTNER'.
  MOVE-CORRESPONDING ls_partner_com TO ls_partner_logical_key.
  ls_input_field-logical_key = ls_partner_logical_key.
  ls_input_field_name-fieldname = 'PARTNER_FCT'.
  INSERT ls_input_field_name INTO TABLE ls_input_field-field_names.
  ls_input_field_name-fieldname = 'PARTNER_NO'.
  INSERT ls_input_field_name INTO TABLE ls_input_field-field_names.
  ls_input_field_name-fieldname = 'DISPLAY_TYPE'.
  INSERT ls_input_field_name INTO TABLE ls_input_field-field_names.
  ls_input_field_name-fieldname = 'NO_TYPE'.
  INSERT ls_input_field_name INTO TABLE ls_input_field-field_names.
  ls_input_field_name-fieldname = 'KIND_OF_ENTRY'.
  INSERT ls_input_field_name INTO TABLE ls_input_field-field_names.
  INSERT ls_input_field INTO TABLE lt_input_field.

*Deactivate fieldcheck to change partners which are read-only.
  MOVE-CORRESPONDING ls_partner_com TO ls_active_switch.
  ls_active_switch-fieldcheck = abap_true.
  INSERT ls_active_switch INTO TABLE lt_active_switch.

ENDLOOP.

*Perform all changes.
CALL FUNCTION 'CRM_ORDER_MAINTAIN'
  EXPORTING
    it_partner                    = lt_partner_com
  it_active_switch              = lt_active_switch
* IMPORTING
*   ET_EXCEPTION                  =
  CHANGING
    ct_input_fields               = lt_input_field
  EXCEPTIONS
    error_occurred                = 1
    document_locked               = 2
    no_change_allowed             = 3
    no_authority                  = 4
    OTHERS                        = 5.

IF sy-subrc <> 0.
  MESSAGE ID sy-msgid TYPE 'E' NUMBER sy-msgno
          WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  EXIT.
ENDIF.

*Perform transaction save.
CALL FUNCTION 'CRM_ORDER_SAVE'
  EXPORTING
    it_objects_to_save           = lt_header_guid[]
*   IV_UPDATE_TASK_LOCAL         = FALSE
   it_active_switch             = lt_active_switch
* IMPORTING
*   ET_SAVED_OBJECTS             =
*   ET_EXCEPTION                 =
*   ET_OBJECTS_NOT_SAVED         =
  EXCEPTIONS
    document_not_saved           = 1
    OTHERS                       = 2.

IF sy-subrc <> 0.
  MESSAGE ID sy-msgid TYPE 'E' NUMBER sy-msgno
          WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.

*ROLLBACK.
  CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.

  EXIT.
ENDIF.

*COMMIT WORK AND WAIT.
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
  EXPORTING
    wait = 'X'.

*Clear buffers.
CALL FUNCTION 'CRM_ORDER_INITIALIZE'
  EXPORTING
    it_guids_to_init = lt_header_guid[]
  EXCEPTIONS
    error_occurred   = 1
    OTHERS           = 2.

Button to generate and send URL of change request or document

Requirement:

Sometimes you want to send an e-mail with a link to a change request or change document, but there is no feature to generate such a URL / e-mail.

Solution:

In SAP Solution Manager 7.2 such a feature is available as standard feature, but in SAP Solution Manager 7.1 you have to implement it by your own. However it is very easy.

Implementation steps:

  • Add button „Link“ to AIC_CMCR_H/AICCMCROverview and AIC_CMCD_H/AICCMCDOverview. To use icons please use report SHOWICON to search for icon_mail (@1S@) or similar. Then use method cl_ai_crm_utility=>get_icon_name to convert it to an icon source.
  • Add event to AIC_CMCR_H/AICCMCROverview and AIC_CMCD_H/AICCMCDOverview
    • Get admin header data analogous to IF_BSP_WD_TOOLBAR_CALLBACK~GET_BUTTONS
    • Get URL by cl_ai_crm_ui_api=>wd_start_crm_ui_4_display. If you want to use Single Sign On (SSO) by using SAP Netweaver Portal redirect, you have to add something as prefix.
    • Build mailto URL
      • lv_recipient = “.
      • lv_subject = |CR { ls_admin_h-object_id }: { ls_admin_h-description }|.
      • lv_body = |{ lv_document_url }|.
      • lv_url = |mailto:{ lv_recipient }?subject={ cl_http_utility=>escape_url( lv_subject ) }&body={ cl_http_utility=>escape_url( lv_body ) } |.
    • set attribute lc_ui_enhancement->bpca_url_to_start

Known issues:

  • Solution is working for change documents but not for change requests? Ensure that HTML code of AIC_CMCR_H/AICCMCRHeaderEF is processing lc_ui_enhancement->bpca_url_to_start in correct way analogous to AIC_CMCD_H/AICCMCDHeaderEF (No use of iframe. That is a bug in older releases)
  • You want to enable feature for Incidents as well? For incidents the steps are similar (web UI component AIC_INCIDENT_H). Additionally you have to adjust the html web page of AIC_INCIDENT_H/IncidentHeaderEF to process lc_ui_enhancement->bpca_url_to_start.
  • You face the issue that Microsoft Outlook is opening only on first click? You face the issue that solution is working only if details form is visible which is not the case if you collapse it or if you are using tile layout? This is a bug in SAP standard. To solve it you have to perform following addition implementation steps:
    • Create a new web UI component (Z_LINK_POPUP)
    • Create a new form view for it with no context nodes
    • Place the HTML source code which is processing lc_ui_enhancement->bpca_url_to_start. You can add additional information. You can also
    • Assign view to window. Publish window as interface.
    • Define component usage to new UI component in AIC_CMCR_H and AIC_CMCD_H and AIC_INCIDENT_H (ZLinkPopup).
    • Improve event implemented before to generate and open a popup with new UI component as content.

That’s all. It is easy. It is working. It helps a lot.

method EH_ONLINK.
* Added by wizard: Handler for event 'LINK'

  DATA:
    lr_cn             TYPE REF TO cl_bsp_wd_context_node,
    lr_entity         TYPE REF TO cl_crm_bol_entity,
    ls_admin_h        TYPE crmst_adminh_btil,

    lv_portal         TYPE string,
    lv_portlet        TYPE string,
    lv_document_url   TYPE string,

    lv_recipient      TYPE string,
    lv_subject        TYPE string,
    lv_body           TYPE string,
    lv_url            TYPE string,

    lc_ui_enhancement TYPE REF TO cl_aic_ui_enhancment,
    lr_popup          TYPE REF TO if_bsp_wd_popup,
    lv_title          TYPE string.
*   lv_text           TYPE string.

*Get Current Business Transaction.
  lr_cn = me->get_context_node( gc_cn_btadminh ).
  IF lr_cn IS BOUND.
    lr_entity ?= lr_cn->collection_wrapper->get_current( ).
    IF lr_entity IS BOUND.
      lr_entity->get_properties( IMPORTING es_attributes = ls_admin_h ).
    ENDIF.
  ENDIF.

*Get URL of document
  CALL METHOD cl_ai_crm_ui_api=>wd_start_crm_ui_4_display
    EXPORTING
      i_guid      = ls_admin_h-guid
    IMPORTING
      e_link      = lv_document_url.

*Build mailto URL
  lv_recipient = ''.
  lv_subject   = |INC { ls_admin_h-object_id }: { ls_admin_h-description }|.
  lv_body      = |{ lv_document_url }|.
  lv_url       = |mailto:{ lv_recipient }?subject={ cl_http_utility=>escape_url( lv_subject ) }&body={ cl_http_utility=>escape_url( lv_body ) } |.

*Send result to web ui component.
  lc_ui_enhancement = cl_aic_ui_enhancment=>get_instance( ).
  lc_ui_enhancement->bpca_url_to_start = lv_url.

**Generate popup.
*  lv_title = 'Generate e-mail with link to document'(902).
*  lv_text  = lv_url.
*  CALL METHOD comp_controller->window_manager->create_popup_2_confirm
*    EXPORTING
*      iv_title          = lv_title
*      iv_text           = lv_text
*      iv_btncombination = comp_controller->window_manager->co_btncomb_ok
*    RECEIVING
*      rv_result         = lr_popup.
*
**Open popup.
*  lr_popup->open( ).

*Generate popup.
  lv_title = 'Generate e-mail with link to document'(902).
  CALL METHOD comp_controller->window_manager->create_popup
    EXPORTING
      iv_interface_view_name = 'Z_LINK_POPUP/MainWindow'
      iv_usage_name          = 'ZLinkPopup'
      iv_title               = lv_title
    RECEIVING
      rv_result              = lr_popup.

*Open popup.
  lr_popup->open( ).

endmethod.
POPUP.HTML

<%@page language="abap" %>
<%@extension name="thtmlb" prefix="thtmlb" %>
<%@extension name="chtmlb" prefix="chtmlb" %>
<%@extension name="bsp" prefix="bsp" %>
<%-- <thtmlb:grid cellSpacing = "1"
     columnSize  = "8"
     height      = "100%"
     rowSize     = "6"
     width       = "100%" />  --%>
<%-- Check if the pop-up needs to be opened form the BPCA url due to BPCA integration --%>
<%
DATAMV_URL_OPENNED       TYPE STRING.
DATAlc_ui_enhancement    TYPE REF TO    cl_aic_ui_enhancment.
lc_ui_enhancement cl_aic_ui_enhancment=>get_instance).
IF lc_ui_enhancement->bpca_url_to_start IS NOT INITIAL AND
cl_http_utility=>is_valid_urllc_ui_enhancement->bpca_url_to_start abap_true.
Concatenate '"' lc_ui_enhancement->bpca_url_to_start '"' INTO MV_URL_OPENNED.
%>
<script type="text/javascript">
window.open(<%= mv_url_openned %>,"","scrollbars=yes");
window.close();
</script>
Microsoft Outlook should open automatically.<br>Please click <a href=<%= mv_url_openned %>>here</a> if not.
<%
CLEAR lc_ui_enhancement->bpca_url_to_start.
ENDIF.
%>

Conditional mandatory field checks for tables

In Web UI it is possible to specify mandatory fields which should be checked by Web UI framework on every round trip. This is working for normal fields on details screen as well as for table fields. Developers don’t need to check these fields. They don’t need to create or delete corresponding error messages. Framework is doing it for free.

Please note that fields on detail screen can be configured as mandatory. However configuration is not working for tables. And: Configuration is not working for conditional mandatory fields at all. That is why we sometimes need following solution which is very powerful and easy to implement.

Actions you have to perform as developer:

  1. Redefine method DO_VALIDATE_INPUT of view controller.
  2. Perform some checks to find out whether fields are mandatory or not (in case they are not always mandatory).
  3. Build binding string and attribute path. For tables it is „//<contextnode>/Table[<index>].<fieldname>“. For structure fields it is „//<contextnode>/STRUCT.<fieldname>“ (standard fields from BOL/GenIL) or „//<contextnode>/EXT.<fieldname>“ (AET fields) or „//<contextnode>/<fieldname>“ (virtual fields).
  4. Register mandatory field by using method POST_MANDATORY_FIELD.

Important remark for tables: Sometimes it happens that mandatory checks are getting confused: Framework is not alerting empty fields or framework is alerting even if fields are not empty. Also custom sorting can be skipped or raising short dumps or just going wrong. In general (and especially in these cases) please ensure that you call method CLEAR_LAST_LINE in method ON_NEW_FOCUS before you perform sorting or mandatory checks.

Please note: SAP Solution Manager IT Service Management has an own solution to perform status dependent mandatory field checks. Maybe if we integrate this check here we would enable the framework to display mandatory fields with red color and star. I haven’t tried it yet. But I would expect this helpful behaviour…

Validate partner types / Restrict partner functions to specific partner types only

In ChaRM and ITSM we are using several partner functions. These partner functions can hold contact partners (external business partners, e.g. Requester), employees (internal end-users, e.g. Developer) and organizational units resp. groups (of internal organizational model, e.g. Support Team).

We want to validate that for partner functions which should hold a organizational unit only organizational units can be maintained/selected. We also want to ensure that employees are always business partners with a valid SAP user id assigned. A contact partner should always be a business partner with the role „Contact Partner“.

However this validation cannot be done in SAP CRM standard, because SAP CRM standard is not supporting the check „Organizational Unit only“.

Solution:

Please create your own partner function types using view cluster COMV_PARTNER_PFT (SM34). Note that „0005 Emloyee“ and „0007 Contact Person“ can be used as it is. But „0008 Person Responsible“, „0016 Support Team“ and „0034 Organization Responsible“ needs to be copied in customer namespace 9XXX and corrected. Please ensure following flags:

  • 0005: Not unique at Doc./Item Level, Central Person
  • 0007: Not unique at Doc./Item Level, Contact Person
  • 9008: Unique at Doc./Item Level, Central Person
  • 9016: Not unique at Doc./Item Level, Central Person + Central Person or Org.Unit
  • 9034: Unique at Doc./Item Level, Central Person + Central Person or Org.Unit

Please adjust definition of partner functions in view COMV_PARTNER_FCT (SM30) and exchange partner function type by our (new) types. Note that you are not allowed to do this for SAP standard partner functions.

Please note that it can happen that you have to adjust mapping configuration in view AIC_PARTNER_FCT + CRMV_ORLALL_BTIL as well in case you are changing partner function types. This is specific to ITSM/ChaRM only.

Please note that it can happen that you have to configure business partner relationship assignment or that you have to adjust partner determination based on business partner relationship. (Only needed if you are changing partner function type. If you are in parallel changing business partner relationship. If you are using partner determination based on business partner relationship.)

Depending on you changes, it can also happen that you have to run report CRM_INDEX_REBUILD (if order index fields get changed because of partner function type change).

Please modify function module COM_PARTNER_CHECK_MASTER_DATA:

  • Check for Central Person: Perform check only if check for „Central Person“ is activated and check for „Central Person or Org.Unit“ is deactivated.
  • Check for Central Person or Org.Unit: Perform check only if check for „Central Person“ is deactivated and check for „Central Person or Org.Unit“ is activated.
  • Check for Org.Unit (new check): Perform check only if check for „Central Person“ is activated and check for „Central Person or Org.Unit“ is activated. Here check for object type „O“ using function module BP_BUPA_GET_HROBJECT.

If you want, you can use SAP CRM Web UI message replacement feature to replace error messages COM_PARTNER-135 and COM_PARTNER-136:

  • Replace “Partner &1 (&2) is neither an employee nor an organizational unit” by “Partner &1 cannot be a &2. Please select a group.”
  • Replace “Partner &1 (&2) is not an emloyee” by “Partner &1 cannot be a &2. Please select a person.”

Remark: You can define and use your own partner function types. The given types were just examples.

Remark: This solution is not able to validate a partner function agains a business partner role „Developer“, „Tester“, „Change Manager“ etc. It is not able to validate against corresponding PFCG roles. Therefore this improvement is just a simple but very helpful improvement.

Sorting on calculated (virtual) fields in Web UI

Assignment blocks usually contain tables. The content of these tables can be sorted by clicking the header column and selecting ascending or descending. This sorting feature is supported out of the box and managed by the Web UI framework.

However, this feature is supported only for attributes which are part of the business object layer (BOL entity level). It is not working for calculated (virtual) attributes which are implemented at the context node level only.

To support real and virtual attributes you have to implement a solution similar to

SAP CRM WebUI : Sorting custom columns (custom attributes)

  1. Use a callback method to perform the comparison by implementing interface if_bol_col_sorting. You can place this method in context node class by implementing the sorting interface. There is no need to implement a independent class.
  2. Use a method cl_crm_uiu_bp_tools=>is_a_greater_b, cl_crm_uiu_bp_tools=>is_date_a_greater_b or similar to perform the comparison on context node level instead of BOL entity level.
  3. Perform custom or multiple-field sorting in method ON_NEW_FOCUS after reading/refreshing collection. Use method me->collection_wrapper->if_bol_bo_col~sort. Attribute name must be if_bol_col_sorting=>custom and iv_sort_callback must be the class implementing interface if_bol_col_sorting.
  4. Ensure that you are calling method CLEAR_LAST_LINE before performing sorting otherwise sorting might going wrong on next round trip.

Automated creation of follow-up transactions. How to use and enhance COPY_DOCUMENT?

To create follow-up documents automatically from a business transaction we can use a ppf action with method COPY_DOCUMENT.

We have to use the parameter „process_type“ to specify to transaction type.

The title of the ppf action will be taken over as description of the follow-up transaction. There is no way to deactivate this feature except the title of the ppf action will be left empty. Then it depends on the copy control what will happen, mostly description of the predecessor transaction will be transferred then. If we always want to take over description from predecessor transaction, we have to de-comment line/parameter iv_actiontext on call of lc_action_execute->copy_document in PPF method COPY_DOCUMENT (BADI Def. EXEC_METHODCALL_PPF -> BADI Impl. COPY_DOCUMENT -> Method EXECUTE). Either via modification or via copy, past and adjust.

The long text of the ppf action can be transferred to a text type of the follow-up document. If we want to do this, we just need to configure and use a text determination access sequences using function module CRM_REFERENCE_TEXT_GET (ref object and ref text type can be left empty in customizing).

If we want to set some more values (i.e. priority, category, …), we have to put these static values in the ppf action container like parameter process_type. We also have to enhance method copy_document of class cl_action_execute to transfer these data to the follow-up document. There is currently no standard solution to default/transfer some data to the follow-up document.

If we want to set a partner for a specific partner function we should do it using partner determination or BRF+ based on a field which is already defaulted using solution mentioned above (i.e. category). We should never try to default a partner by the follow-up creation routine itself because the partner number will be different in different systems and the assignment rule might change very often.

The copy control is per default active for the follow-up creation, which means that data can be overtaken from the current transaction to the follow-up transaction.

Unfortunately there is currently no way to create a follow-up based on a template transaction. Only SAP CRM Service is using such a feature for Service Plans (we can have a look at ppf action method CREATE_ORDER_SRVPLAN and transaction CRMD_SERV_CYCLE). However, this solution is specific for this use case only and cannot be used for other use cases as well.

For a lot of use cases COPY_DOCUMENT (with the mentioned extensions) will be sufficient to implement the requirements. However there exist some other ppf action methods which handles items and document flow in a different way. If we want to use/copy items we should try COPY_DEF_ITEMS (create follow-up and copy items), COPY_ITEM_LOCAL (create/copy items in a transaction locally) and COPY_ITEM_TO_TASK (create follow-up transaction with current item as predecessor).

How to work with timestamp attributes in SAP Web Client UI?

It happens very often, that we want to use additional TIMESTAMPs in context of Business Transaction Management.

If we are introducing additional date types (appointments) via configuration, the SAP CRM standard is managing the display, storage and data conversion. We just need to add context nodes for it to our UI components. We should have a look at already existing date/time context nodes and reuse the context node classes used here to ensure standard-like behaviour (virtual fields, value helps, data conversion, …).

If we decide to create a field enhancement using Application Enhancement Tool (AET), we dont need an additional context node since we are using context node BTAdminH or BTCustomerH. However, we will now face the challenge, that there is no proper value help available for timestamps. Therefore we need to create two additional virtual attributes for DATE and TIME which are referring to the TIMESTAMP attribute.

(Der Quellcode wird später hier noch ergänzt….)

How to calculate virtual fields for table enhancements created with AET?

All tables, structures, function modules and classes will be generated automatically, if you create a table enhancement using Application Enhancement Tool (AET). However, sometimes you might want to calculate some fields instead of storing it in database.

The AET is not supporting such virtual fields. Therefore you have to implement it manually.

Solution 1: Create an additional attribute in the context node of the generated UI component and place a calculation in the getter method. Deactivate coding of setter and i-getter method.

Solution 2: Enhance structures ?_WORK, ?_ATTR and ?_BOL_ATTR by an additional attribute. Place your calculation at the end of method GET_DETAIL of class CL_AXT_TABLES_API (define and use a table name dependent BADI for high quality solution). Add a value attribute with the same name to context node of the generated UI component. Don’t change the generated code here since it will read the data from BOL/GenIL as wanted.

Conclusion 1: Development should be restricted to a minimum. Whenever source code can be avoided, it should be avoided. Therefore solution 1 is preferred from a supportability perspective, if there are only few virtual fields required.

Conclusion 2: Business logic should be placed in API or BOL/GenIL layer instead of UI layer to be reused UI independently. Therefore solution 2 is preferred from an architecture perspective, if several virtual fields are required or if a high quality and high flexible solution is requested.

Such- und Wertehilfen im SAP Web Client UI

Das SAP Web Client UI ist ein mächtiges und flexibles Framework zur Entwicklung nutzerfreundlicher User Interfaces. Doch manchmal hat SAP SE die Lösung nicht zuende gedacht. Als Beispiel sei hier der üblicherweise ungerechtfertigt hohe Entwicklungsaufwand zur Implementierung Feldprüfungen bei Eingabe, Feldaufbereitungen bei Ausgabe und Such- bzw. Wertehilfen genannt.

Folgende Lösungen stehen zur Verfügung:

  • Die genannten Logiken sind in den Kontextknoten implementiert. Wird also ein Kontextknoten benutzt, der in einer anderen UI-Komponente bereits existiert, sollte geprüft werden, ob der Kontextknotenkontroller wiederverwendet werden kann. Nachdem die Super-Klasse des eigenen Kontextknoten durch die Standard-Kontextknotenkontrollerklasse ausgetauscht wird, stehen in der Regel sämtliche vom Standard gewohnte Prüfungen und Aufbereitungen zur Verfügung.
  • Bei Nutzung des Design Layers können dem Feld Dictionary-Suchhilfen zugeordnet werden. Diese werden dann automatisch gezogen.
  • Für Felderweiterungen mittels Application Enhancement Toolset (AET) werden automatisch die Dictionary-Suchhilfen bzw. -Wertehilfen genutzt. Ohne Programmieraufwand.
  • Im Artikel SAP CRM & SAP Solution Manager Business Transaction Search Enhancement habe ich beschrieben, wie die AET-Automatik auch für SAP-Standard-Felder oder manuell ergänzte Kundenfelder aktiviert werden kann. Dieser Weg wird jedoch von SAP SE nicht supportet.
  • Wenn alle anderen Wege versagen, dann muss am Ende doch klassich die V-Getter-Methode im Kontextknotenkontroller ausprogrammiert werden. Für einfache Dropdown-Listen gibt es jedoch bereits eine Hilfsklasse cl_crm_uiu_ddlb die uns die meiste Arbeit abnimmt:
method GET_V_NAME_OF_THE_ATTRIBUTE.

DATA:
lr_valuehelp_pldescr TYPE REF TO cl_crm_uiu_ddlb.

*Create Value Help Descriptor
CREATE OBJECT lr_valuehelp_pldescr
EXPORTING
iv_source_type = if_bsp_wd_valuehelp_pldescr=>source_type_table.

*Build up dropdown list based on data element.
CALL METHOD lr_valuehelp_pldescr->set_data_element
EXPORTING
iv_data_element      = 'NAME_OF_THE_DATA_ELEMENT'
* iv_add_initial_entry =
.

*Return value help descriptor
rv_valuehelp_descriptor ?= lr_valuehelp_pldescr.

endmethod.

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.

SAP CRM & SAP Solution Manager PPF Action Condition Enhancement

How to add attributes for PPF action conditions?

The PPF action framework is a powerful framework to trigger actions (= sending smartforms or executing methods) dependent on several events & issues (= schedule and start conditions).
However in SAP standard there is only a small set of business transaction related attributes which can be evaluated. This document explains how to enhance the PPF by additional customer or SAP standard attributes with minimum development effort.

PPF Action Condition Enhancement.pdf (559.8 KiB)

SAP CRM & SAP Solution Manager E-Mail Notification Enhancement

How to send E-Mails to business partners not mentioned in the current business transaction?

We want to send e-mail notifications on certain conditions to certain partners. However some recipients are only valid on the level of predecessor transactions. SAP standard only supports e-mail notifications to partners of the current Business Transaction.
This little solution removes this limitation and opens the way to send notifications to partners of the current and predecessor transaction.

E-Mail Notification Enhancement.pdf (299.9 KiB)

SAP CRM & SAP Solution Manager Business Transaction Search Enhancement

How to implement business transaction search enhancements with minimum development?

There exist several guides in SCN. These guides always explain how to do big developments in context of search enhancement. These big development activities are needed if we need special value helps or if we need to adjust existing selection criteria or result list or if we want to enhance other searches than business transaction search.
In most cases we simply want to add some additional search criteria and result list fields. In these cases, we are able to implement this low effort solution with minimum development.

Business Transaction Search Enhancement.pdf (808.1 KiB)