Skip to Content

Test determination is a feature that allows filling automatically Text Collection of SAP TM documents with, well, texts. For instance, in Air Freight scenarios, the texts for Nature of Goods are quite standardized and can be filled automatically with predefined templates that need only minor adjustments. Other scenarios require an automatic propagation of e.g. shipping instructions – from forwarding orders or ERP-based requirements (OTR/DTR) to the freight documents, so that they can be transmitted to carriers during subcontracting.

The functionality was intended actually for SAP TM 9.0, but it required a coordinated development in two software components – in SAPTM as well as in Business Suite Foundation (SAP_BS_FND), since the Text Collection is actually a reusable business object from this layer. Due to some TM-specific modelling particularities, the out-of-the-box BS FND functionality did not work properly in TM 9.0.

The development can be used fully in 9.1 and 9.2 – even if it took some additional SAP Notes (2111951, 2113678, 2113736, 2114090, 2116402 and 2116403) to have it working satisfactorily.

The text determination can be set up in the customizing of Text Schema (IMG path Cross-Application Components -> Processes and Tools for Enterprise Applications -> Reusable Objects and Functions for BOPF Environment -> Dependent Object Text Collection -> Maintain Text Schema). I assume the reader is familiarized with the text collection concepts – if not, feel free to consult the documentation. Also, it should have gone without saying: some basic knowledge about TM internal modelling (business objects, nodes, associations) is a prerequisite when setting up this feature.
IMG path

Text Schemas can be attached to SAP TM documents via type customizing (e.g. IMG path Transportation Management -> Forwarding Order Management -> Forwarding Order -> Define Forwarding Order Types).

Coming back to Text Schema customizing, the functionality is activated by specifying an Access Sequence for a text type while maintaining Text Type to Text Schema Assignment. The access sequence is a collection of so-called Accesses – steps that attempt to find a text according to some logic. Both concepts can be maintained in the same customizing cluster – we’ll see immediately how.
Text Type to Text Schema Assignment

When an access sequence is maintained in the type-schema assignment, the flag Reference becomes meaningful:

  • If left empty, the result of the determination is written immediately in the target document, but there is no “update handling” (if the source of the texts changes, the text in the target document remains untouched).
  • If the flag is set, the result of text determination is not persisted completely in the target document – the text content is left intentionally empty. Every time the collection is accessed, the text determination is executed again and the consumer (e.g. the UI) sees its current result. As soon as the text is modified in the target document, it becomes “local”: the changed value is saved in the text content and the reference flag is removed. It’s worth noting that this option poses a certain runtime overhead, since the determination must be executed more often.

There are four types of accesses: (1) association navigation, (2) association navigation with node attributes, (3) external BO access and (4) external source. #1 and #2 are similar to each other – they attempt to follow some BOPF associations to reach another text collection representation node, from which the requested text type is copied (if existing). #3 and #4 rely on external classes, implementing certain ABAP interfaces.

I am going to describe now the necessary steps required to set up the text determination for the following use cases:

  1. Use a given standard text (maintained using t-code SO10) as soon as the TM document is created.
  2. Copy a text from one related TM document
  3. Copy and/or adjust texts from more related TM documents

Use-case 1: standard text

Standard texts can be defined in transaction “Define Standard texts” (SO10):
Define Standard Text
Sample Standard Text

To use them in text determination, we need an access of type External Source (we obviously cannot use BOPF associations to get there, and we need to provide some parameters – the identification of the text). External source require a so-called external text determination class. For this particular case, there is already a library class that can be used, delivered in BS Foundation software component – /BOFU/CL_ACCESS_SO10_TEXT:
External Source

The parameters accepted by this (unfortunately still undocumented) class are ID, NAME and OBJECT, which correspond to the unique identification of a SO10 text:
External Source Parameter Definition

Afterwards, create a new access, using this external source:
Access

Set the actual values for the parameters (this way, you can create more accesses with the same external source, each one pulling a specific standard text):
Access Parameters

Create a new access sequence:
Sequence

Add the created access to the sequence. You can have more accesses here, the processing stops as soon as one of them successfully finds a text (so the sequence number is important):
Access in Sequence

Now go the text type to text schema assignment and fill in the created access sequence for the desired text type:
Assignment

In the my example, I modified the SAP-delivered schema FWOHDR, which is assigned to the forwarding order type FWO. As a result of the steps above, creating a forwarding order of this type leads to the automatic creation of a NOTE text having content To be packed with extra care.

Use-case 2: copy FWO/OTR/DTR text to freight unit

Here we can use the simplest method – association navigation. The “business entities” must be defined in advance in another Foundation customizing (IMG path Cross-Application Components -> Processes and Tools for Enterprise Applications -> Reusable Objects and Functions for BOPF Environment ->General Settings -> Maintain Business Entities) and represent a combination of BOPF business object and node:
Access

The path to be followed must described in Access Details – starting from the target documents to the requested text collection object representation node of the source document. So we’ll use the association BO_TRQ_ROOT to navigate from freight unit header (the ROOT node of business object /SCMTMS/TOR) to forwarding order/ERP-requirement header (ROOT node of /SCMTMS/TRQ), then the association TEXTCOLLECTION from there to the representation node. It looks like a rudimentary version of the TM Data Crawler:
Access Parameters

Then create an access sequence:
Sequence

Attach the new access to the new sequence:
Access in Sequence

Finally, attach the sequence to the desired text type of the relevant text schema (here I use a newly created schema, since there is no SAP-delivered schema for freight units… yet):
Assignment

As soon as a freight unit (which has a type that references this schema…) is created, the corresponding NOTE text from FWO/OTR/DTR header is copied.

One side-remark: in most FWO-based scenarios, the freight unit is created automatically soon as the consistency checks allows it – entering a text in forwarding order after this point does not lead to the update of the freight unit! This can be overcome by either disabling the automatic creation of freight units (in FWO type customizing), or by changing the items in FWO (which usually lead to a rebuild of the freight unit). In ERP integration scenarios, however, the document (OTR/DTR) is usually created completely in one step, including texts, before freight units are built. But if some texts are added manually in OTR/DTR afterwards, these too are not propagated automatically.

Who knows, perhaps SAP will offer in the near future a possibility to manually trigger the text determination to overcome such cases (e.g. a button in the Notes UI). 😉

This procedure can be used every time when a 1:1 relationship between business entities exists. For instance, you can use it to propagate FOW/OTR/DTR header/item texts to freight order items as well.

Copy texts from more source documents into one text

Let’s consider a more exotic requirement – to propagate the freight unit texts to the freight order header. Here there is a problem: usually there are more freight units assigned to a FO, but a certain text can only be created only once in a text collection. Therefore, the association-based approach described above does not work (the text from one freight unit only will be determined).

One solution is to concatenate the text content – but this is a more complex procedure, that can only be covered again by a specialized determination class. We’ll use again external source as access type.

The most important step is to create a class, implementing the interface /BOFU/IF_ACCESS_EXTERNAL_TEXT, and then write the code for method GET_EXTERNAL_TEXTS. I attached the source code of my demo class to this article. In a nutshell, my implementation finds all freight units attached to a freight order by using the association REQ_TOR, then goes to their header-level text collection and finally concatenates the matching texts into one content, inserting in the process some contextual information (the identfication of the freight unit) as separator. When the texts are available in the requirement documents (FWO/OTR/DTR), one can use in coding the association BO_TRQ_ROOT_ALL to directly access the ROOT nodes of these documents – this avoids the additional determination required to propagate the texts from there to freight units.
~~01.png

After the class is created and activated, create a new external source and specify the new determination class; my implementation does not require parameters (although one can imagine a more generic class that can find texts in various documents):
External Source

Create a new access, and specify the new external source:Access

Then again create a corresponding access sequence:
Sequence

Attach the access to it:
Access in Sequence

And attach the access sequence in the type-schema assignment (again, there is no standard text schema delivered by SAP for freight orders, so I created a new one and attached it to my FO type):
Assignment
New Schemas

After attaching some freight units to my freight order, the text NOTE contains now a concatenation of the corresponding freight unit texts:
Result

My sample code takes data from the NOTE text of the freight units, but with external access some other options are possible, like combining more text types into a single entity in the target document.

Another fact worth mentioning: text determination is usually executed only when the corresponding node instance is created. For freight orders, there is a special logic – the determination at header level is executed every time a requirement is added to (or removed from) the freight order.

To report this post you need to login first.

12 Comments

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

  1. Former Member

    Thanks Dragos! very detailed and useful doc!

    it will be nice if SAP can add some of these instructions in simple text form in the customizing screen. its all blank now!

    Regards,

    Ramesh

    (0) 
    1. Dragos Mihai Florescu Post author

      Hi,

      Oh, I did at the time of creation, but it looks the migration from the old SCN space to the new community page lost the attachment functionality..

      The sample code (as usual, provided as-is, no warranty):

      CLASS zmdf_cl_text_fo_from_fu DEFINITION
        PUBLIC
        FINAL
        CREATE PUBLIC .
      
        PUBLIC SECTION.
          INTERFACES /bofu/if_access_external_text .
        PROTECTED SECTION.
        PRIVATE SECTION.
          METHODS _get_lang
            IMPORTING
              !iv_langu       TYPE sylangu
            RETURNING
              VALUE(rv_descr) TYPE sptxt .
      ENDCLASS.
      
      CLASS ZMDF_CL_TEXT_FO_FROM_FU IMPLEMENTATION.
      
      * <SIGNATURE>---------------------------------------------------------------------------------------+
      * | Instance Public Method ZMDF_CL_TEXT_FO_FROM_FU->/BOFU/IF_ACCESS_EXTERNAL_TEXT~GET_EXTERNAL_TEXTS
      * +-------------------------------------------------------------------------------------------------+
      * | [--->] IV_BO_KEY                      TYPE        /BOBF/CONF_KEY
      * | [--->] IV_NODE_KEY                    TYPE        /BOBF/CONF_KEY
      * | [--->] IV_KEY                         TYPE        /BOBF/CONF_KEY
      * | [--->] IV_TEXT_TYPE                   TYPE        /BOBF/TXC_TEXT_TYPE
      * | [--->] IT_PARAMETERS                  TYPE        /BOFU/T_EXT_PARAM_VALUE(optional)
      * | [<---] ES_TEXT_DATA                   TYPE        /BOFU/S_TEXT_DETAILS
      * +--------------------------------------------------------------------------------------</SIGNATURE>
      METHOD /bofu/if_access_external_text~get_external_texts.
      
        CONSTANTS c_n TYPE char1 VALUE cl_abap_char_utilities=>newline ##NO_TEXT.
        DATA:
          lt_fo_root TYPE /scmtms/t_tor_root_k,
          lt_fu_root TYPE /scmtms/t_tor_root_k,
          lt_tc_text TYPE /bobf/t_txc_txt_k,
          lt_tc_cont TYPE /bobf/t_txc_con_k.
      
        CLEAR es_text_data.
      
        DATA(lo_frw) = /bobf/cl_tra_serv_mgr_factory=>get_service_manager( /scmtms/if_tor_c=>sc_bo_key ).
      
      *--------------------------------------------------------------------*
      * Determine runtime DO keys and read required data
      *--------------------------------------------------------------------*
      
        "unfortunately, the BOFU exit class does not have the access ID in signature
        "so we need to go the long way
        lo_frw->retrieve(
          EXPORTING
            iv_node_key  = /scmtms/if_tor_c=>sc_node-root
            it_key       = VALUE #( ( key = iv_key ) )
            iv_fill_data = abap_true
          IMPORTING
            et_data      = lt_fo_root ).
      
        READ TABLE lt_fo_root ASSIGNING FIELD-SYMBOL(<data>)
          WITH TABLE KEY key = iv_key.
        IF sy-subrc GT 0.
          RETURN.
        ENDIF.
        DATA(lt_ttype)  = /bofu/cl_txc_helper=>get_text_types( <data>-text_schema ).
        READ TABLE lt_ttype ASSIGNING FIELD-SYMBOL(<ttype>)
          WITH TABLE KEY text_schema_id = <data>-text_schema
                         text_type_code = iv_text_type.
        IF sy-subrc GT 0.
          RETURN.
        ENDIF.
      
        "get runtime keys of the DO text collection nodes under FU.Root
        /scmtms/cl_tor_helper_text_col=>get_txc_key_mapping(
          EXPORTING
            iv_node            = /scmtms/if_tor_c=>sc_node-textcollection
          IMPORTING
            es_txc_key_mapping = DATA(ls_txckey) ).
      
        "follow the association to the text collection of FU
        lo_frw->retrieve_by_association(
          EXPORTING
            iv_node_key    = /scmtms/if_tor_c=>sc_node-root
            iv_association = /scmtms/if_tor_c=>sc_association-root-req_tor
            it_key         = VALUE #( ( key = iv_key ) )
          IMPORTING
            et_target_key  = DATA(lt_key_fu) ).
      
        IF lt_key_fu IS INITIAL.
          RETURN.
        ENDIF.
      
        lo_frw->retrieve(
          EXPORTING
            iv_node_key    = /scmtms/if_tor_c=>sc_node-root
            it_key         = lt_key_fu
            iv_fill_data   = abap_true
          IMPORTING
            et_data        = lt_fu_root ).
      
        lo_frw->retrieve_by_association(
          EXPORTING
            iv_node_key    = /scmtms/if_tor_c=>sc_node-root
            iv_association = /scmtms/if_tor_c=>sc_association-root-textcollection
            it_key         = lt_key_fu
          IMPORTING
            et_target_key  = DATA(lt_key_txc) ).
      
        IF lt_key_txc IS INITIAL.
          RETURN.
        ENDIF.
      
        lo_frw->retrieve_by_association(
          EXPORTING
            iv_node_key    = ls_txckey-root_key
            iv_association = ls_txckey-text_asc
            it_key         = lt_key_txc
            iv_fill_data   = abap_true
          IMPORTING
            et_data        = lt_tc_text ).
      
        DELETE lt_tc_text WHERE text_type NE iv_text_type.
        IF lt_tc_text IS INITIAL.
          RETURN.
        ENDIF.
      
        /scmtms/cl_common_helper=>extract_frwkey_from_tables(
          EXPORTING
            it_table   = lt_tc_text
          IMPORTING
            et_frw_key = DATA(lt_key) ).
      
        lo_frw->retrieve_by_association(
          EXPORTING
            iv_node_key    = ls_txckey-text_key
            iv_association = ls_txckey-cont_asc
            it_key         = lt_key
            iv_fill_data   = abap_true
          IMPORTING
            et_data        = lt_tc_cont ).
      
      *--------------------------------------------------------------------*
      * Finally, compose the concatenated text
      *--------------------------------------------------------------------*
        DATA(lv_text) = es_text_data-text. "initial...
      
        LOOP AT lt_tc_text ASSIGNING FIELD-SYMBOL(<txc_text>).
      
          READ TABLE lt_tc_cont ASSIGNING FIELD-SYMBOL(<txc_cont>)
            WITH KEY parent_key COMPONENTS parent_key = <txc_text>-key.
          CHECK sy-subrc EQ 0.
          CHECK <txc_cont>-text IS NOT INITIAL.
      
          READ TABLE lt_fu_root ASSIGNING FIELD-SYMBOL(<fu_root>)
            WITH TABLE KEY key = <txc_text>-root_key.
          CHECK sy-subrc EQ 0.
      
          DATA(lv_desc) = /scmtms/cl_tor_helper_root=>return_ident_fortor_key( is_tor_root = <fu_root> ).
      
          IF lv_text IS NOT INITIAL.
            lv_text = |{ lv_text }{ c_n }{ c_n }------{ c_n }|.
          ENDIF.
          lv_text = |{ lv_text }>> { lv_desc }, { _get_lang( <txc_text>-language_code ) }:{ c_n }{ <txc_cont>-text }|.
      
        ENDLOOP.
      
        "and fill the output structure
        es_text_data-text      = lv_text.
        es_text_data-text_type = iv_text_type.
        es_text_data-access_id = <ttype>-acc_seq_id.
        es_text_data-reference = <ttype>-reference.
        es_text_data-lang_indp = <ttype>-lang_indep.
        IF <ttype>-lang_indep IS INITIAL.
          es_text_data-langu = sy-langu.
        ENDIF.
      
      
      ENDMETHOD.
      
      * <SIGNATURE>---------------------------------------------------------------------------------------+
      * | Instance Private Method ZMDF_CL_TEXT_FO_FROM_FU->_GET_LANG
      * +-------------------------------------------------------------------------------------------------+
      * | [--->] IV_LANGU                       TYPE        SYLANGU
      * | [<-()] RV_DESCR                       TYPE        SPTXT
      * +--------------------------------------------------------------------------------------</SIGNATURE>
      METHOD _get_lang.
        SELECT SINGLE sptxt
          FROM t002t
          INTO rv_descr
          WHERE spras = sy-langu
            AND sprsl = iv_langu.
      ENDMETHOD.
      
      ENDCLASS.
      (1) 
      1. Former Member

         

        Hi Dragos,

        thanks for this coding and the help on text Determination which I have used at several occasions. Please Keep posting these infos. They are extremely helpful in the daily work of TM Projects.

         

        Take care

        Petra

        (0) 
  2. Former Member

    Hi Dragos,

     

    I have implemented the case 3. It works very well while creation of a FO.

    But the problem is when ever you change something in the FWO this is not reflected in the FO UI. But it is updated in the backend of the FO. When I debugged I see that the class is not getting called for all the text types but only to the very first text type of the FO. This indicated its not called in a loop. What are your comments on this? If there is a OSS note to rectify this error please let me know.

    Thanks for the blogs. Great Stuff.

     

     

    (0) 
  3. Vikas Chhabra

    Hello Dragos,

     

    Thanks for this good blog.

    In my current project, we are implementing SAP TM in S/4 HANA 1709 for a client dealing majorly in Distribution of Dangerous Goods.

     

    We require use case 1 – standard text, so I configured as per instructions and I was able to default the text type (for example in the “Create Freight Order”, I could populate default “EMERGENCY CONTACT NUMBER” for US (for example, 1800-001-0002), and this is to be printed on the “US Consignment Note” printed from SAP TM Freight Order).

     

    Same way, I would have an emergency contact number for Canada as well, which I would like to pull and print on CA Consignment Note.

     

    What are different ways to have relevant text type populating in the right freight order for a purchase organization. Ofcourse, no one would like to create so many text schemas and FO types per purchasing org. Also, any text schema determination condition doesnot seem to exist, that could have been used.

     

    So, what are the available options here, that I can explore:

     

    1. Same Text Schema, with a list of text type, but text types being dynamically called based on purchase organization being used in the Freight Order (with challenge that text picks up before specifying Pur Org in Freight Order)
    2. Looks like Access ID (I am using determination class /BOFU/CL_ACCESS_SO10_TEXT) can be of some use but trying to figure it out.

     

    Any pointers will be appreciated.

     

    Best Regards,

    Vikas Chhabra

     

    (0) 

Leave a Reply