One of the most important and at the same time one of the worst designed tables in ChaRM is TSOCM_CR_CONTEXT. This table is used to store cycle assignment of CR and CD. At the same time it is used to plan the scope of a CR. There is no proper API existing, there are a lot of code snippets which are manipulating or evaluating the entries of this table mostly without sense.

This blog should help you to understand this table from technical point of view.

Code snippets / Reference:

  • cl_al_crm_cm_utility=>get_sub_docs_4_cyc_by_cr_ctxt (SAP note 2592607)
  • cl_wdcm_extchreq_scoping_asst=>GET_CR_PROJECT_BY_FOLLOW_ON (SAP note 2581812)


  • cl_ai_crm_cm_cr_cont_run_btil=>update_cr_context
  • cl_wdcm_extchreq_scoping_asst=>read_context_db
  • cl_wdcm_extchreq_scoping_asst=>update_context_db
  • cl_aic_cm_scope_backend_api=>read
  • cl_aic_cm_scope_backend_api=>UPDATE
  • cl_aic_cm_scope_backend_api=>SAVE_INTO_DB

Header Context:

  • GUID: GUID of Transaction
  • CREATED_GUID: Empty for CR, = GUID for CD
  • CREATED_BY: Empty
  • CREATED_ON: Empty
  • PROCESS_TYPE: Process Type of Transaction (CR and CD)
  • IBASE: Empty
  • PRODUCT_ID: Empty
  • SID: Empty
  • MANDT: Empty
  • PROJECT_ID: Assigned change cycle (SM 7.0/7.1: ID of assigned Project)
  • SOLUTION_ID: Empty (SM 7.0/7.1: ID of assigned Solution)
  • SLAN_ID: Change Control landscape or Solution
  • SBRA_ID: Branche
  • APPR_RESULT: Empty
  • APPROVED: Empty

Scope Context:

  • GUID: GUID of CR Transaction
  • ITEM_GUID: = Unique GUID (can be GUID of CD if scope context was created after CD creation)
  • CREATED_GUID: Empty if CD is not created yet, otherwise GUID of CD
  • CREATED_ON: Creation Timestamp (see CRMD_ORDERADM_H-CREATED_AT of CD)
  • PROCESS_TYPE: Process Type of CD Transaction (see CRMD_ORDERADM_H-PROCESS_TYPE of CD)
  • IBASE: Ibase (will be transferred to REFOBJ on CD creation)
  • IBASE_INSTANCE: IBase Instance (will be transferred to REFOBJ on CD creation)
  • PRODUCT_ID: Product ID of IBase Component
  • SID: System ID of IBase Component (if LMDB object)
  • MANDT: Client of IBase Component (if LMDB object)
  • PROJECT_ID: Assigned change cycle
  • SOLUTION_ID: Empty
  • SLAN_ID: Change Control landscape or Solution
  • SBRA_ID: Branche
  • APPR_RESULT: „A“ or „F“ for approved, „“ for unapproved
  • APPROVED: Empty
  • APPROVE_STATUS: Used to store user status of CR in case of scope extension process

How to get configuration item system data fresh from CR/CD (maybe to update TSOCM_CR_CONTEXT)?

Solution 1 (working for LMDB and CMDB objects but not for text components):

  1. cl_ai_crm_object_api=>get_object_id_from_order
  2. cl_hf_helper=>get_sys_data
  3. cl_hf_helper=>get_ibase_comp_4_product

Solution 2 (working for text components as well):

  1. cl_hf_helper=>get_ibase_instance_of_chng_doc
  3. Extract OBJECT_ID (not PRODUCT_ID!)
  4. cl_hf_helper=>get_sys_data

How to get transaction data (needed to build context entries)?

  • cl_hf_helper=>get_header_of_chng_doc
  • cl_hf_helper=>get_proc_type_of_chng_doc
  • cl_hf_helper=>get_predoc_of_chng_doc
  • cl_hf_helper=>get_sucdocs_of_chng_doc
  • cl_hf_helper=>get_bo_links_of_chng_doc (to get assigned cycle of CD)
  • cl_hf_helper=>get_bo_tasklist_of_chng_doc (to get assigned tasklist of CD)
  • cl_al_crm_cm_utility=>get_smi_project_by_tasklist (to get cycle id or SM 7.0/7.1 project id of task list)


Note: These information are taken from my ABAP report which was developed to create entries in TSOCM_CR_CONTEXT table for old SM 7.0/7.1 change transactions after upgrade to SM 7.2. These information are not sufficient to re-implement this report. However I hope it will help you to understand the technical dependencies.




Selecting a specific BADI implementation by customizing


Sometimes we want to implement customer specific logics and to activate them by customizing context sensitively. Most famous examples are checks, calculations or conversations.

In most cases we can implement a SAP standard BADI and filter the context by development or BADI filter conditions. Every time the context changes, we have to change the BADI definition (filter criteria) or the source code of the BADI implementation (if or check statement). A consultant has no chance to change the context without help of a developer. That is very bad.

Solution for Classic BADIs:

To solve this issue, we need to use a bridge in order to connect the business context with the technical BADI implementation. This bridge is normally called „check id“, „condition id“, „filter id“ etc. It is configured in an own customizing table, used in some other customizing table (where we want to assign an implementation) and used as single-value filter id in the BADI implementation of a specific BADI definition. Sometimes we have to define such a filter id first and then create a BADI implementation including assign it to the filter id. Sometimes we don’t need to create the filter id as first step because it will automatically be created resp. added by the BADI when defining it.

This solution is working fine for classic BADIs. One prominent example is BADI EXEC_METHODCALL_PPF which is used to implement processing methods for PPF actions.

Solution for new BADIs:

New BADIs still have the feature to assign a data element (with value table) to a filter criteria. But the feature to specify the filter value as „enhanceable“ got lost.

The good news is, that there exist a very easy way to implement such an „enhanceable“ solution. For this solution we don’t need a customizing table to hold the filter id. Therefore the implementation effort is very lower.

  1. Create a new BADI definition.
  2. Set the flag „Limited Filter Use“ in the „Usability“ area.
  3. Define one filter criteria. (More are not allowed)
  4. Define and implement some BADI implementations. Each BADI implementation needs to be assigned to a filter value using the equal operator (other operators are not allowed). One BADI implementation can still be registered for more than one filter values using the OR operator.
  5. Define or extend a customizing table where you want to select a specific BADI implementation. Here you need a field which is used to store the filter value. Please create an own data element (if not done yet) to use proper names like „check id“ or „condition id“.
  6. To provide a proper value help please use search help /RTF/BADI_IMP_FILTER. Here you have to mention the name of the BADI definition in field „BADI_NAME“. Now this value help will always show all active BADI implementation with their corresponding filter values of the fixed BADI definition.
  7. Please maintain the customizing table and select the requested filter values. In program code you now have to read the customizing table based on the current business context. You have to extract the filter value, to get the BADI based on the filter value and to call the BADI with providing some context data (maybe including filter value).

That’s all. Very simple. It’s working!

Restriction: Search help /RTF/BADI_IMP_FILTER is supporting only filter values up to 4 characters. If you need more, you have to implement your own search help similar to the existing one. Just copy the search help + search help exit and exchange the data element.

That’s all. Very simple. It’s working!

SAP Performance Analysis


  • ABAP: SAT – SAP ABAP Trace
  • SQL: ST01/ST05 – SAP SQL Trace
  • JOB: ST13 (BACKGROUND_JOB_ANALYSIS) – Background Job Analysis
  • AUTH: ST01 – SAP Authority Trace

Hinweis: Nur für konkrete Sachverhalte geeignet. Explizites Aktivieren und Deaktivierung notwendig. Hat Auswirkungen auf die Performance.


  • ABAP: /SDF/UPL_CONTROL – Usage & Procedure Logging
  • ABAP: [SCOV – SAP Coverage Analyzer]
  • SQL: SQLM – SQL Monitor
  • AUTH: STAUTHTRACE – System Trace for Authority Checks

Hinweis: Sollte immer angeschaltet sein. Auch in der Produktion. Keine signifikanten Performanceauswirkungen.

Mein Favorit:

SAT erspart einem stundenlanges Debugging. Gerade bei tief verschachtelten pseudo-objektorientierten Entwicklungen mit vielen parallelen oder nachgelagerten Prozessen. Wichtig ist zuvor eine eigene Variante anzulegen und die Agregation auszuschalten. Denn nur dann erhält man den kompletten Aufrufpfad. Um alle parallelen Prozesse zu erwischen, sollte auf Userebene (und nicht Prozess- oder Transaktionsebene) getract werden.


How to detect status changes?

Sometimes we want to trigger an activity (e.g. PPF action) only if a (or if no) status change is performed. Sometimes it can be complicated to detect status changes since error messages are raising system status changes or since status changes can be cancelled.

Dependent on the requirements, we can try following solutions:

  1. Real status changes: Use function module CRM_STATUS_READ_OW and check the fields ACTIVE and ACTIVE_OLD of parameter ET_STATUS_WRK. Alternatively compare the result against CRM_STATUS_READ_DB.
  2. Real status changes or Status cancel: Use function module CRM_EVENT_PASS_INFO_EXE_OW with execution time ‚080‘ and check whether parameter contains ET_EVENT_CALLS contains object „STATUS“. If you are only interested in status changes on header level, please ensure that ORDER_GUID and OBJ_GUID are equal.
  3. Real status changes(?): Use method GET_PREV_STATUS_OF_CHNG_DOC of class CL_HF_HELPER.
  4. Real PPF action triggered status change: Define a PPF action check previous user status in Schedule condition and new user status in start condition. Ensure that the sort number of this action is higher than the sort number of the status change action.

These solutions are partially also working for partner changes, appointment changes, text changes etc.



Use Case 1:

In ChaRM there is always a consistency check performed after status change. It might be useful to perform consistency checks on every transaction save to validate transaction consistency. However, this check should not be performed if the framework is perfoming it (because of performance reasons and because the check result might be different). Therefore we need to detect status change activities which includes real status changes as well as cancelled status changes. This can be done by solution (2).

Use Case 2:

In SAP Solution Manager IT Service Management status changes are not triggered by PPF actions, therefore solution (4) is not working. The same issue we have for ChaRM if status changes are triggered by CRM_SOCM_SERVICE_REPORT. If we want to trigger an action (e.g. e-mail notification) on status change only, we have to follow solution (1). Please note, that this solution is already available in SAP standard: Note 1007346 – Scheduling of actions only after resetting a status.

*"Methoden Signatur:
*"  Importing
*"  Exporting

METHOD if_ex_eval_startcond_ppf~evaluate_start_condition.

    lr_crm_order        TYPE REF TO cl_doc_crm_order,
    lv_header_guid      TYPE crmt_object_guid,
    lv_exec_mode        TYPE sppfdxmode,
    lv_on_database_flag TYPE abap_bool,
    lt_events           TYPE crmt_event_call_tab.

* default false
  ep_rc = 4.

*Get Execution Mode
  lv_exec_mode = cl_manager_ppf=>get_instance( )->execution_mode.

*Get Header GUID
      lr_crm_order ?= io_context->appl.
    CATCH cx_root.

  lv_header_guid = lr_crm_order->get_crm_obj_guid( ).

*We need a Business Transaction.
  CHECK lv_header_guid IS NOT INITIAL.

*First Save?
      iv_orderadm_h_guid  = lv_header_guid
      ev_on_database_flag = lv_on_database_flag.

*We only want to allow our action in dialog mode or if we change the Transaction.
  CHECK lv_exec_mode IS INITIAL OR lv_on_database_flag = abap_false.

**Get Status
*      iv_guid        = lv_header_guid
*      iv_only_active = abap_false
*      et_status_wrk  = lt_status_wrk1[]
*      not_found      = 1
*      OTHERS         = 2.
*  CHECK sy-subrc = 0.

*Find out wich objects are really changed.
      iv_exetime          = '080'
      iv_order_guid       = lv_header_guid
      iv_obj_kind         = 'A'
      et_event_calls      = lt_events
*     et_segments_changed = lt_segments
      OTHERS              = 99.

*We are only interested in changed objects on header level.
*Therefore we have to ignore/delete every change on item level.
  DELETE lt_events WHERE obj_guid <> lv_header_guid.

*Are there any status changes (including error free flag, including status change cancel)
  READ TABLE lt_events
    WITH KEY obj_name = 'STATUS'.

*Fine. We are in normal save mode without any status change activity.
  CHECK sy-subrc <> 0 OR lv_on_database_flag = abap_false.

*Are there any header changes (CHANGED_AT)
  READ TABLE lt_events
    WITH KEY obj_name = 'ORDERADM_H'.

*Fine somthing has really changed.
  CHECK sy-subrc = 0.

*OK. Action is allowed to be executed.
  ep_rc = 0.


class based exception handling (ABAP OO exceptions)

There exist two kinds of exception handling in ABAP OO – The classical one and the object orientated one.

The classical one is similar to exception handling used by function modules: We can raise an exception together with a message (using ABAP statement „message … raising“). The caller need to catch and to handle this exception.

The object orientated exception solution (raised using the ABAP statement „RAISE EXCEPTION TYPE „) has the important positive issue that the caller doesn’t need to handle the exception. If the caller is not able or willing to handle the exception, it will be propagated to the caller of the caller automatically.

However, the object orientated exception is more complicated in cases we just want to throw an error message because we need to create an exception class first.

Good News: This is very simple.

  1. We can use or inherit from exception class CX_T100_MSG if we know message id and number at runtime only and these information are available in variables like SY-MSGID, SY-MAGNO, SY-SMG-TY, SY-MSGVX.
  2. We can use or inherit from class CX_RSR_BAPIRET2 if we have message information available in a BAPIRET2 structure used by many BAPI function modules. Since CX_RSR_BAPIRET2 is final, we cannot inherit from it. Therefore we once need to create a copy first.
  3. If we know message id and numbers (can be several!) at design time but message parameters only at run time, we can create an exception class based on interface IF_T100_MESSAGE (or simply flag „With Message Class“ at creation). For details, we can use the following guides: