Supply Chain Management Blogs by SAP
Expand your SAP SCM knowledge and stay informed about supply chain management technology and solutions with blog posts by SAP. Follow and stay connected.
cancel
Showing results for 
Search instead for 
Did you mean: 
Dragoș
Employee
Employee
As everyone familiar with SAP TM knows, our UIs "remember" (using implicit WD personalization) the expand/collapse state of individual panels, as well as the last visited assignment block in a stack.

In the screenshot below of an Air Freight Booking, we have three stacks (sometimes referred to as "tabstrips"). The first one is expanded and the other two are collapsed. The last visited assignment blocks are: Capacity and Cargo, Notes and Document Flow respectively.



After closing this screen, when opening another document (or creating a new one) the system will show me the same picture.

There are users that prefer the system to show a certain assignment block, usually the one labelled General Data, whenever they start the screen - regardless of what they visited last time. In a "create" scenario, this requirement makes a lot of sense, since data entry is performed usually in a certain sequence.

Unfortunately, Floorplan Manager - the technology employed by TM - does not offer this possibility. In the OVP configuration, we can mark an assignment block as default:



But as soon as the system finds WD personalization for the affected user, the definition from the configuration is overwritten by personalization data. We can either enable user personalization (and then the last state is remembered), or disable it altogether (case in which other useful personalization features are lost).

However, this can be reached with a small code enhancement. Luckily, FPM offer powerful APIs, which allow the application to do many things, including, to quote an (in)famous character, “many bad things”. But as long as we avoid the dark side, we’re good.

For this example, we’ll use a phase called OverrideEventOVP in the FPM processing model. The phase can be processed by the application controller, if it implements a suitable FPM interface (and TM controller does).

I’ll post the complete code, then explain what it does and where to put it. I assume that everyone still reading at this point has a bit of FPM background, thus I won’t go into detail of every FPM-specific concept.
    IF io_ovp->get_event( )->mv_event_id EQ cl_fpm_event=>gc_event_start.

"find default main page
TRY.
io_ovp->get_content_areas(
IMPORTING
et_content_area = DATA(lt_page) ).
CATCH cx_fpm_floorplan ##no_handler.
ENDTRY.
READ TABLE lt_page ASSIGNING FIELD-SYMBOL(<page>)
WITH KEY default = abap_true
type = if_fpm_constants=>gc_content_area_type-main_area.

IF sy-subrc EQ 0.
"get all UBBS from this page
io_ovp->get_uibbs(
EXPORTING
iv_content_area = <page>-id
IMPORTING
et_uibb = DATA(lt_uibb) ).
"lookup general data -> by text
READ TABLE lt_uibb ASSIGNING FIELD-SYMBOL(<uibb>)
WITH KEY title = cl_wd_utilities=>get_otr_text_by_alias( '/SCMTMS/UI_CMN/GENERAL_DATA' ).
IF sy-subrc EQ 0.
"set this as default and not collapsed, if needed
IF <uibb>-default_in_stack NE abap_true OR
<uibb>-collapsed NE abap_false.
<uibb>-default_in_stack = abap_true.
<uibb>-collapsed = abap_false.
TRY.
io_ovp->change_uibb(
EXPORTING
is_uibb = <uibb> ).
CATCH cx_fpm_floorplan ##no_handler.
ENDTRY.
ENDIF.
"reset the flag of all other UIBBs from the same stack
LOOP AT lt_uibb ASSIGNING FIELD-SYMBOL(<sibling>)
WHERE location = <uibb>-location
AND row = <uibb>-row
AND fpm_primary_attribute NE <uibb>-fpm_primary_attribute.
IF <sibling>-default_in_stack NE abap_false.
<sibling>-default_in_stack = abap_false.
TRY.
io_ovp->change_uibb(
EXPORTING
is_uibb = <sibling> ).
CATCH cx_fpm_floorplan ##no_handler.
ENDTRY.
ENDIF.
ENDLOOP.
ENDIF.
ENDIF.

ENDIF.

First, it’s important to execute the tweak only once per application lifetime – and I chose the “start” event. Since this phase is executed for every single event in the FPM processing loop, failure to do wo will lead to inability of the user to switch to a different assignment block!
IF io_ovp->get_event( )->mv_event_id EQ cl_fpm_event=>gc_event_start.

The next step is to identify the page (“content area”) that is relevant for the tweak. In my sample code, I am searching for the one with type “main page” which is marked as “default”. This is the very page that is displayed after the button “Continue” is pressed on the initial screen. An alternative method would be to use a hard-coded page ID, as defined in OVP configuration (usually, but not always, it’s simply called MAIN).
"find default main page
TRY.
io_ovp->get_content_areas(
IMPORTING
et_content_area = DATA(lt_page).
CATCH cx_fpm_floorplan ##no_handler.
ENDTRY.

READ TABLE lt_page ASSIGNING FIELD-SYMBOL(<page>)
WITH KEY default = abap_true
type = if_fpm_constants=>gc_content_area_type-main_area.

Identifying the assignment block is the trickiest part. One could look up by UIBB key (component + window name + configuration ID + instance ID), but these are document specific, and might change even in time. I chose to look up using the title text that is displayed on the screen, in this case “General Data”. As this is language dependent, we should never use a string literal – instead, use the OTR artefact that is referenced in the OVP configuration (do not forget that $OTR: is not part of the element identification!).
"get all UBBS from this page
io_ovp->get_uibbs(
EXPORTING
iv_content_area = <page>-id
IMPORTING
et_uibb = DATA(lt_uibb) ).

"lookup general data -> by text
READ TABLE lt_uibb ASSIGNING FIELD-SYMBOL(<uibb>)
WITH KEY title = cl_wd_utilities=>get_otr_text_by_alias( '/SCMTMS/UI_CMN/GENERAL_DATA' ).

The rest is straightforward. If our screen contains an assignment block that fulfils our search criteria, then this is marked as “expanded” and “default” (overwriting whatever personalization settings were remembered by FPM at the last visit). Of course, no other assignment blocks from the same stack can be marked as default, so in the last step the potential conflicts are identified and corrected.
"set this as default and not collapsed, if needed
IF <uibb>-default_in_stack NE abap_true OR
<uibb>-collapsed NE abap_false.
<uibb>-default_in_stack = abap_true.
<uibb>-collapsed = abap_false.
TRY.
io_ovp->change_uibb(
EXPORTING
is_uibb = <uibb> ).
CATCH cx_fpm_floorplan ##no_handler.
ENDTRY.
ENDIF.
"reset the flag of all other UIBBs from the same stack
LOOP AT lt_uibb ASSIGNING FIELD-SYMBOL(<sibling>)
WHERE location = <uibb>-location
AND row = <uibb>-row
AND fpm_primary_attribute NE <uibb>-fpm_primary_attribute.
IF <sibling>-default_in_stack NE abap_false.
<sibling>-default_in_stack = abap_false.
TRY.
io_ovp->change_uibb(
EXPORTING
is_uibb = <sibling> ).
CATCH cx_fpm_floorplan ##no_handler.
ENDTRY.
ENDIF.
ENDLOOP.

That’s it.

The question is where to put the code. As mentioned, the TM application controller implements the interface, so one place would be as enhancement (a post-exit) of method IWCI_IF_FPM_OVP_CONF_EXIT~OVERRIDE_EVENT_OVP of class /SCMTMS/CL_UI_CONTROLLER_CMN.

I personally recommend, however, to use the so-called controller exits (which are called during standard processing of the above method). The result will be the same, but it’s easier for us to provide assistance if something goes wrong.

If the enhancement is intended to be applied for all screens, the place to add the coding is method /BOFU/IF_FBI_CONTROLLER_EXIT~OVERRIDE_EVENT_OVP of class /SCMTMS/CL_UI_CTRLEXIT_CMN. However, in this case, my sample code requires slight adjustments, as you could see from the very first screenshot of this post, Air Freight Booking UI does not have a “General Data” block…

If the enhancement is intended to be executed only for some documents, e.g. for Forwarding Order UI only, then use the corresponding subclass of the common exit (e.g. /SCMTMS/CL_UI_CTRLEXIT_TRQ).
1 Comment