Skip to Content

The Occasion

Since 2006 we use ChaRM to manage our SAP ABAP changes. But the dark side of our IT department, the infrastructure team, always successfully avoided the contact with it as well with SAP at all. Time passes and a new infrastructure boss decided that also the non-SAP fraction has to document changes by change documents.

Panic.

In order to mitigate this existential shock I customized a strongly simplified business role for my colleagues (“YSOLMAN_INFS“) and set up ready to be used Request for Change (RfC) templates (YMCT) with already initialized partners and the category id the infrastructure team owns (ITFS) and a scope assignment block with a ready to be used general change (YMCG), too. To avoid chaos we have a naming convention for the description of the RfC templates, and the templates of infrastructure teams should start with “ITFS“.

The non-SAP colleagues are expected to use the “Create Request for Change from Template” functionality. Pitifully this opens at first a pop-up with an empty search for RfC templates. To make things really really easy I thought to initialize this search pop-up such that the proper templates are only one click on the search button away by searching for these attributes:

  • status IS “Released
  • Category ID IS “ITFS
  • Description STARTS WITH “ITFS

First Try: Initialize Using GET_VALUE1

With F2 it is easy to find the component of the search: AIC_CMCR_S, View AIC_CMCR_S/CMSR. I enhance this view so that I can reach the attributes:

To initialize a search with default values you have to redefine the getter of two special attributes: VALUE1 for the low value and VALUE2 for the high value. For our goal the low value is enough:

The coding is very simple. If the infrastructure business role YSOLMAN_INFS is active, then catch the attributes to be initialized and do it:

  METHOD get_value1.
* 2018-05.16 r.escher created - prefill when infrastructure business role
    CALL METHOD super->get_value1
      EXPORTING
        attribute_path = attribute_path
        iterator       = iterator
      RECEIVING
        value          = value.

    CHECK value    IS INITIAL.

    " determine the business role, but only once
    " cv_profile_name will be empty at every new search view instance
    IF cv_profile_name  IS INITIAL.
      DATA(lv_profile)  = cl_crm_ui_profile=>get_instance( ).
      IF lv_profile     IS BOUND.
        cv_profile_name = lv_profile->get_profile( ).
      ELSE.
        cv_profile_name = abap_true. "dummy to jump out the next time
        RETURN.
      ENDIF.
    ENDIF.

*
    CASE cv_profile_name.
      WHEN cc_business_role_infrastructur.
        TRY.
            IF iterator IS BOUND.
              DATA(lr_current)    = iterator->get_current( ).
            ELSE.
              lr_current          = me->parameter_collection->get_current( ).
            ENDIF.
            
            value  = COND #( LET att = lr_current->get_property_as_string( iv_attr_name = 'ATTR_NAME' ) IN
                                  WHEN att = 'USER_STATUS_KEY'  THEN 'YMCT:E0006'	"RfC Template Status Released 
                                  WHEN att = 'DESCRIPTION_UC'   THEN 'ITFS'		"Naming convention
                                  WHEN att = 'CATEGORY_ID'      THEN 'ITFS (INCIDENT_CATEGOR)'	"1st level catetory (<Catego Schema>)
                              ).
          CATCH cx_root.
        ENDTRY.
    ENDCASE.
  ENDMETHOD.

The operands are set in the configuration.

It works:

But then I discovered that this search is also used by the normal searches of the ChaRM workcenter:

and here the initial value of the status “Released” is disturbing, because you may want to search for templates that are not yet released but in editing mode.

So we need a switch. If in pop-up mode initialize also the status, else keep it empty. But how to check in the getter method if I am inside the search pop-up or not? I didn’t find a way. So I decided to initialize the pop-up from the calling side, where I definitely know that I am in pop-up mode.

I deleted the row with the initialization of the user status and set out on my way to find the source of the rainbow.

Second Try: Initialize Using The Inbound Plug of the Pop-Up

Where Is My PopUp Plug?

First we have to find the way in the thicket of links and relations.There is a very nice blog from Ashish Walke explaining how to create navigation links, but here we have to go the reverse way, we need to discover how an existing link works. And with the help of our CRM guru Hendrik Beck I left layer seven where I usually move and lion-heartedly plunged into the deeper layer of the Web UI.

We start with the workcenter. We call transaction CRMC_UI_NBLINKSDefine NavBar Profile” (SPRO -> CRM -> UI Framework -> Technical Role Definition -> Define Navigation Bar Profile) and open our minimized profile YSOLMANPRO_MIN to determine the workcenter id “SM-CHANGE

With this value we determine the ChaRM “Create” group id “SM-CM-CR“:

Now we are able to find out the logical link id “SM-CRF-CR” of the Create RfC from Template functionality:

Now it gets tricky. We look up the logical link definition, which targets the id TCRFCR and open the F4 search for this target id:

Found! The component is AIC_CMCR_M (obviously naming convention experts would immediately look at _M components for _S components, but I wanted to show how the links work).

We call transaction CRMC_UI_WA_COMP_REP  (SPRO -> CRM -> UI Framework -> Technical Role Definition -> Define Work Area Component Repository) and look up this component to see which inbound plug is used:

Yes! The plug name looks very promising. Let’s open it in BSP_WD_CMPWB:

METHOD ip_create_from_tmpl.

* Create Request for Change from Template
  me->gv_ui_object_tmpl_type = if_ags_crm_const=>gc_ui_aic_ob_cmcr_templ.
  me->view_manager->navigate(
    source_rep_view = me->rep_view
    outbound_plug   = 'FromRFCMToRFCSTemplatePopupNavbar'
    data_collection = iv_collection ).

ENDMETHOD.

Look at the commentary: very hot! Now we open the runtime repository editor and look at the navigation link ‘FromRFCMToRFCSTemplatePopupNavbar‘ finding the inbound plug of the target:

As the target is in another component, the navigation adds a ComponentUsage to the target window.

Here is the target plug:

This seems to be enough for our enhancements. Let’s go!

Enhance Inbound Plug

We open component AIC_CMCR_S in the component workbench and enhance AIC_CMCR_S/MainWindow.

In the resulting implementation class we add the public class attribute ZCT_DEFAULT_PARAMS of type GENILT_SELECTION_PARAMETER_TAB so that we have a place where we can store the default values:

Then we redefine IP_TEMPLATE_POPUP_NAVBAR:

  METHOD ip_template_popup_navbar.

    set_default_params( iv_collection ). "prepare the prefilled attributes
    
    CALL METHOD super->ip_template_popup_navbar
      EXPORTING
        iv_collection = iv_collection.
  ENDMETHOD.

The private method set_default_params is unspectacular:

  METHOD set_default_params.
*   store default params globaly
    zct_default_params = VALUE #( ( attr_name = 'USER_STATUS_KEY' sign = 'I' option = 'EQ' low = 'YMCT:E0006' ) ).
  ENDMETHOD.

(obviously I will replace the literals with interface constants 😉 )

We don’t switch at the business role here because this use case is valid for all RfC template pop-ups: you shall always search only for released templates!

We have already enhanced the view AIC_CMCR_S/CMSR in our first try. Now we redefine DO_PREPARE_OUTPUT method to set the default attributes. First we have to navigate the parentship upwards and jump over the view set, so that we can consume the prepared zct_default_params table by adding its values to the query object:

  METHOD do_prepare_output.
* 2018-06-07 r.escher created
    DATA: lr_parent_window  TYPE REF TO ycl_1s_aic_cmcr_mainwind0_impl,
          lr_parent_viewset TYPE REF TO cl_aic_cmcr_cmviewset_impl.

    TRY.
        DATA(lr_parent)      = me->m_parent.
        CHECK lr_parent      IS BOUND.
        lr_parent_window     ?= lr_parent.
      CATCH cx_sy_move_cast_error.
        "not our custom class, a viewset? Exactly one seond try
        TRY.
            lr_parent_viewset  ?= lr_parent.
            lr_parent_window   ?= lr_parent_viewset->m_parent.
          CATCH cx_sy_move_cast_error.
        ENDTRY.
    ENDTRY.

    IF lr_parent_window IS BOUND AND
       lr_parent_window->zct_default_params IS NOT INITIAL.
      TRY.
          "eh_onclear( ).
          DATA(lr_qs)     = me->get_current_dquery( ).
          lr_qs->delete_empty_selection_params( ).
          LOOP AT lr_parent_window->zct_default_params[] ASSIGNING FIELD-SYMBOL(<lf_param>).
            lr_qs->add_selection_param(
                     iv_attr_name   = <lf_param>-attr_name
                     iv_sign        = <lf_param>-sign
                     iv_option      = <lf_param>-option
                     iv_low         = <lf_param>-low
                     iv_high        = <lf_param>-high ).
          ENDLOOP.
        CATCH cx_root.
      ENDTRY.
    ENDIF.
    CALL METHOD super->do_prepare_output
      EXPORTING
        iv_first_time = abap_false.
    CLEAR lr_parent_window->zct_default_params[].
  ENDMETHOD.

But big surprise! It does not work, the user status search attribute remains empty. In the debugger we see that the zct_default_params table is empty. So what?

Enhance The Second Inbound Plug

Did you really thought we were done with the first inbound plug we found? The search window we enhanced is not yet the pop-up window, it will wait invisible in the background and become visible only if you cancel the pop-up. The pop-up window is a second instance of our class, so we have to find out which additional plug we have to enhance.

Our jorney goes on. To discover the next navigation, we have to look at the coding to find our way. super->ip_template_popup_navbar (cl_aic_cmcr_mainwindow0_impl) looks like this:

METHOD ip_template_popup_navbar.
  CALL METHOD me->ip_template_popup
    EXPORTING
      iv_collection = iv_collection.


  me->view_manager->navigate( source_rep_view = me->rep_view
                              outbound_plug   = 'CreateFromTemplate'
                              data_collection = iv_collection ).
ENDMETHOD.

In me->ip_template_popup it simply flags for a pop-up window:

method IP_TEMPLATE_POPUP.
  set_flags( iv_popup = abap_true iv_template = abap_true ).
endmethod.

And this navigation link ‘CreateFromTemplate‘ will navigate to the search result view AIC_CMCR_S/CMSRL inbound plug CREATE_FROM_TEMPLATE, which is in the same component and therefore has not need for a component usage:

This inbound plug IP_CREATE_FROM_TEMPLATE will create a new instance of the window as pop-up identified by:

  • gv_interface_view_name = ‘AIC_CMCR_S/MainWindow
  • gv_search_usage_for_template = ‘CUAICChangeMS

These values are intialized in the CONSTRUCTOR of the result view class CL_AIC_CMCR_CMSRL_IMPL:

method CONSTRUCTOR.
CALL METHOD SUPER->CONSTRUCTOR.

me->view_name = 'CMSRL.htm'.

include crm_object_types_con.

  me->gv_otr_alias_for_template        = if_ags_crm_const=>gc_otr_alias_for_cmcr.
  me->gv_interface_view_name           = 'AIC_CMCR_S/MainWindow'.
  me->gv_search_usage_for_template     = 'CUAICChangeMS'.

endmethod.

This is the way how the inbound plug of the result view creates the new instance as a pop-up and calls another inbound plug of our window:

METHOD ip_create_from_template .
*  me->eh_onnew_from_template( ).
* initialize it once
  IF gv_template_search_popup IS INITIAL.
    DATA: lv_title TYPE string.
    lv_title = cl_wd_utilities=>get_otr_text_by_alias( gv_otr_alias_for_template ).
    gv_template_search_popup = comp_controller->window_manager->create_popup(
             iv_interface_view_name = gv_interface_view_name
             iv_usage_name          = gv_search_usage_for_template
             iv_title               = lv_title ).
  ENDIF.

  gv_template_search_popup->set_on_close_event( iv_view = me iv_event_name = 'TEMPLATESEL_CLOSED' ).
  gv_template_search_popup->set_display_mode( if_bsp_wd_popup=>c_display_mode_surrounded ).
  gv_template_search_popup->open( 'TEMPLATE_POPUP' ).
ENDMETHOD.

If we look at the first import parameter of the open method we see it is named iv_inbound_plug. And effectively we find in AIC_CMCR_S/MainWindow this window inbound plug, which we redefine:

Same coding as the first inbound plug we did redefine:

  METHOD ip_template_popup.
*   2018-06-07 r.escher created
    set_default_params( iv_collection ). "prepare the prefilled attributes
    CALL METHOD super->ip_template_popup
      EXPORTING
        iv_collection = iv_collection.
  ENDMETHOD.

Result

We are done! This time our do_prepare_output routine finds the default values and can initialize the search attribute for user status! And this happens only in pop-up mode.

A happy user again:

To report this post you need to login first.

1 Comment

You must be Logged on to comment or reply to a post.

Leave a Reply