Additional Blogs by Members
cancel
Showing results for 
Search instead for 
Did you mean: 
former_member184549
Participant

Recently, I've had the requirement to set the multi-level categorization on a CRM service request/order. After going ten rounds with it, I think it worth writing a blog post describing the trials and tribulations and the best approach that can be used. It should save someone out there a lot of wasted effort and frustration to know the principal of how to set these fields.

Some of the information out there is not exactly helpful, especially for programmers looking for BAPI/API calls that can be made to set the categorization.  It may even be suggested that one should the use the BOL programming model ( see http://scn.sap.com/thread/1434317 ) - this is not so easily accomplished, especially in the absence of documentation.

So how do you do it? (Spoiler at the end of this paragraph!). Very quickly one might find that the values are stored on tables CRMD_SRV_OSSET and CRMD_SRV_SUBJECT, can be read via function CRM_ORDER_READ (they come back in the SUBJECT table) and that there are many tantalizing low-level functions in package CRM_ERMS_CATEGORIZATION. But, if you were to debug how the web gui sets a categorization on an order you would find that the standard code does this by calling function CRM_ORDER_MAINTAIN. And that is how you do it - by calling that function in the same way, with the same parameters as the standard code does. There are several pages on SCN where such a call is described, but bear in mind that the example code given on these pages (and at the end of this post) are specific to someone else's system and not your own.

So, the general principle is to call function CRM_ORDER_MAINTAIN. This is easier said than done. If you debug, you'll find that two tables provided to this function are critical -it_service_os and ct_input_fields. Within the service_os table there is an "osset" table and within each row of this table there is a "subject" table that holds the lowest tier of the multi-level categorization that is being set. At each of these levels, the entity is referred to either by it's GUID or by a handle (if the entity is still being created). Since in my particular case this is for a pre-existing order to which we are adding categorization then a GUID is used and not a handle. But where do you get the GUIDs from? In my case they are obtained as follows:

- The order GUID (as per table CRMD_ODERADM_H) should be set on the service_os table and input_fields tables.

- The "osset" table GUID can be obtained by calling function CRM_SERVICE_OS

- The lowest level "subject" table GUID is generated yourself (for example by calling function CRM_GUID_CREATE).

A DISCLAIMER is due here: this information was all obtained through trial and error and debugging, it seems that there isn't an officially supported way to do what is probably quite a common requirement. Our lives would be a lot simpler if there was an official way and documentation, and I would love to be proven wrong and have someone point out that these exist.

One more thing, it is not enough to simply call CRM_ORDER_MAINTAIN. CRM_ORDER_SAVE also needs to be called to save changes to the database. I've also found through experience that these functions may need to be called in a seperate process to the work process that creates the order. (For instance, by scheduling a background job using functions JOB_OPEN etc; scheduling a function to run in update task didn't seem to be suitable for this problem either.)

I'm loath to offer my code here (that I used to solve my particular problem) as people may be inclined to simply paste it onto their systems and expect it to run immediately. However, an example is a good aid too, so it is being offered below. Bear in mind that things will need to be changed in this code. Your profile type fields, and mode values may be different. So first and foremost debug and see how CRM_ORDER_MAINTAIN is being called and adjust this code accordingly:

function zcrm_add_categorization.
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     VALUE(IV_CATEGORY) TYPE  STRING
*"     VALUE(IV_ACTIVITY_GUID) TYPE  GUID_32
*"     VALUE(IV_ACTIVITY_OBJECT_ID) TYPE  CRMT_OBJECT_ID
*"----------------------------------------------------------------------
* Add a categorization to an existing service request ("activity")
*
* IV_ACTIVITY_GUID is the order GUID, as per table CRMD_ORDERADM_H
* IV_ACTIVITY_OBJECT_ID is the order number
* IV_CATEGORY is the cat id as per table CRMD_SRV_SUBJECT
*LOCAL
  include crm_object_names_con.
  include crm_object_kinds_con.
  data lr_aspect             type ref to if_crm_erms_catego_aspect.
  data lr_categoryif         type ref to if_crm_erms_catego_category.
  data lr_category           type ref to cl_crm_erms_catego_ca_default.
  data lv_cat                type crmt_erms_cat_ca_buf.
  data ls_conc               type zcrmt_erms_cat_code_trip.
  data lv_obj_guid           type crmc_erms_cat_ln-obj_guid.
  data lv_obj_extkey         type crmc_erms_cat_ok-obj_extkey.
  data lv_process_type       type crmt_process_type.
  data ls_service_h          type crmc_service_h.
  data ls_crmt_srv_osset_wrk type crmt_srv_osset_wrk.
  data ls_temp_osset         type crmt_srv_osset_wrk1.
  data lv_osset_guid         like ls_temp_osset-guid.
  data lv_cat_id             type crm_erms_cat_ca_id.
  data lt_subject            type crmt_srv_subject_comt.
  data ls_subject            type line of crmt_srv_subject_comt.
  data ls_osset              type crmt_srv_osset_com1.
  data lt_service_os         type crmt_srv_osset_comt.
  data ls_service_os         like line of lt_service_os.
  data lt_input_fields       type crmt_input_field_tab.
  data ls_input_fields       like line of lt_input_fields.
  data ls_input_field        like line of lt_input_fields.
  data ls_input_field_names  like line of ls_input_field-field_names.
  data lt_objects            type crmt_object_guid_tab.
  data lv_service_guid       type crmt_object_guid.
  data ls_log                type zcrm_erms_sr_log.
*  field-symbols <ls_activity> like line of it_activities.
  constants cv_link_type type char8              value 'IS_CODE'.
  constants cv_asp_id    type crm_erms_cat_as_id value 'Z_YOUR_CAT_SCHEMA'.
*Need the external key, so that we know the code group, etc.
*...determine cat guid
  lv_cat_id = iv_category.
  cl_crm_erms_catego_ma_default=>if_crm_erms_catego_manager~get_aspect(
    exporting iv_asp_id = cv_asp_id
              iv_asp_state  = if_crm_erms_catego_const=>gc_as_state_executable
    importing ev_instance = lr_aspect ).
  call method lr_aspect->get_cat
    exporting
      iv_cat_id   = lv_cat_id
    importing
      ev_instance = lr_categoryif.
  lr_category ?= lr_categoryif.
  call method lr_category->if_crm_erms_catego_category~get_details
    importing
      ev_cat = lv_cat.
*...with the cat guid we can now determine the external key
  select single obj_guid
    from crmc_erms_cat_ln
    into lv_obj_guid
    where cat_guid = lv_cat-cat_guid
    and   lnk_type = cv_link_type.
  if sy-subrc = 0.
    select single obj_extkey
      from crmc_erms_cat_ok
      into lv_obj_extkey
      where obj_guid = lv_obj_guid.
    if sy-subrc = 0.
      ls_conc = lv_obj_extkey.
    endif.
  endif.
*...call functions to get the guids we're going to need to put in the service_os table
  select single process_type
    from crmd_orderadm_h
    into lv_process_type
    where guid = iv_activity_guid.
  check sy-subrc = 0.
  call function 'CRM_ORDER_SERVICE_H_SELECT_CB'
    exporting
      iv_process_type = lv_process_type
    importing
      es_service_h    = ls_service_h
    exceptions
      entry_not_found = 1
      others          = 2.
  if sy-subrc <> 0.
    clear ls_service_h.
  endif.
  lv_service_guid = iv_activity_guid.
  call function 'CRM_SERVICE_OS_READ_OB'
    exporting
      iv_ref_guid          = lv_service_guid
      iv_ref_kind          = 'A'
    importing
      es_srv_osset_wrk     = ls_crmt_srv_osset_wrk
    exceptions
      entry_does_not_exist = 1
      error_occured        = 2
      parameter_error      = 3
      others               = 4.
  check sy-subrc = 0.
*...subject table
  ls_subject-katalogart   = ls_conc-code_cat.
  ls_subject-codegruppe   = ls_conc-code_grp.
  ls_subject-code         = ls_conc-code_id.
  ls_subject-asp_id       = cv_asp_id.
  ls_subject-cat_id       = lv_cat_id.
  ls_subject-katalog_type = 'D'.
  ls_subject-mode         = 'B'.
  call function 'CRM_GUID_CREATE'
    importing
      ev_guid = ls_subject-ref_guid.
  insert ls_subject into table lt_subject .
*...osset, contains the subject table
  clear ls_osset.
  ls_osset-subject         = lt_subject.
  ls_osset-ref_guid        = lv_osset_guid.
  ls_osset-subject_profile = ls_service_h-subject_profile. ".'         '
  ls_osset-profile_type    = ls_temp_osset-profile_type.".'A'
*...service os data, constains osset
  clear ls_service_os.
  append ls_osset to ls_service_os-osset.
  ls_service_os-ref_guid = iv_activity_guid.
  ls_service_os-ref_kind = 'A'.
  refresh lt_service_os.
  append ls_service_os to lt_service_os.
*...input fields
  clear ls_input_field.
  refresh lt_input_fields.
  ls_input_field-ref_guid    = iv_activity_guid.
  ls_input_field-ref_kind    = gc_object_kind-orderadm_h.
  ls_input_field-objectname  = gc_object_name-service_os.
  ls_input_field_names-fieldname = 'ASP_ID'.
  insert ls_input_field_names into table ls_input_field-field_names.
  ls_input_field_names-fieldname = 'CAT_ID'.
  insert ls_input_field_names into table ls_input_field-field_names.
  ls_input_field_names-fieldname = 'CODE'.
  insert ls_input_field_names into table ls_input_field-field_names.
  ls_input_field_names-fieldname = 'CODEGRUPPE'.
  insert ls_input_field_names into table ls_input_field-field_names.
  ls_input_field_names-fieldname = 'KATALOGART'.
  insert ls_input_field_names into table ls_input_field-field_names.
  ls_input_field_names-fieldname = 'MODE'.
  insert ls_input_field_names into table ls_input_field-field_names.
  ls_input_field_names-fieldname = 'REF_GUID'.
  insert ls_input_field_names into table ls_input_field-field_names.
  insert ls_input_field  into table  lt_input_fields.
*Effect change by calling functions to maintain and save CRM order
  call function 'CRM_ORDER_MAINTAIN'
    exporting
      it_service_os     = lt_service_os
    changing
      ct_input_fields   = lt_input_fields
    exceptions
      error_occurred    = 1
      document_locked   = 2
      no_change_allowed = 3
      no_authority      = 4
      others            = 5.
  ls_log-subrc1 = sy-subrc.
  check sy-subrc = 0.
  refresh lt_objects.
  append iv_activity_guid to lt_objects.
  call function 'CRM_ORDER_SAVE'
    exporting
      it_objects_to_save = lt_objects
    exceptions
      document_not_saved = 1
      others             = 2.
endfunction.
5 Comments