Page tree
Skip to end of metadata
Go to start of metadata


How is it possible to enhance ECTR with customer specific generic objects and details for this objects?



 


  • Since ECTR 5.1.14 / ECTR 510 SP14 / S4ECTR 100 SP10 it is possible to enhance ECTR with customer specific generic objects.
  • Since ECTR 5.2.3 / ECTR 520 SP03 / S4ECTR 110 SP03 the generic framework has been enhanced with further features. Use the page history to see the differences.
  • S/4 systems: Please take care that note 2947857  is installed before you start.

Backend

In order to enable support of Customer Objects in the SAP ECTR BADI /DSCSAG/PLM_OBJ_DETAILS shall be implemented.

BADI interface /DSCSAG/IF_PLM_OBJ_DETAILS consists of two methods:

MethodDescription
GET_OBJ_CONFIG

Method to provide Customer Object Name and Customer Object details Structure name

GET_OBJ_DETAILS_GEN ECTR 510: Method to provide Customer Object details to SAP ECTR.
GET_OBJ_DETAILS_GEN2S4ECTR 110 / ECTR 520: Method to provide Customer Object details to SAP ECTR.

GET_OBJ_PREVIEW_DOC

Method to provide a generic object preview document for this object.

GENERIC_DROPHANDLER

Method to provide the logic for objects dropped on this generic object.

GET_OBJ_LONGTEXT

Method to provide a longtext for this generic object.

It also will be needed to create Data Dictionary structure for the Customer Object Details.


In this example we create an object for the "Material product version" "DE: Material Fertigungsversion":

Start with SE18 and implement the BAdI:



Object Type

The string of the object type has to be defined in backend.

If there exists no official BOR-Object for the object type the customer shall use a "Z" or "Y"-Prefix for a customer specific object type.

In the example we are using here the <OBJECT_TYPE> is "PRODVERS".

Object Key

Maximum length of 50 (EHP8), 90 (S/4). Upper case values only!

BAdI Methode GET_OBJ_CONFIG

The purpose of this method is to let SAP ECTR know that some extra Customer Object has been introduced and it configuration provided in this BADI method implementation.

This achieved via adding extra line to the table parameter ET_STRUCT_MAPPING (‘Changing’).

The structure of this extra line - /DSCSAG/OBJ_TYPE_STRUCT_S - has fields OBJECT_TYPE and OBJECT_STRUCTURE, both should be filled, see screenshot and code snippet below for coding example:

/DSCSAG/IF_PLM_OBJ_DETAILS~GET_OBJ_CONFIG
method /DSCSAG/IF_PLM_OBJ_DETAILS~GET_OBJ_CONFIG.

* Define the table "MKAL" as the basic data for the type "PRODVERS"

  FIELD-SYMBOLS:  <ls_struct_mapping>    TYPE /dscsag/obj_type_struct_s.

  READ TABLE et_struct_mapping  TRANSPORTING NO FIELDS WITH KEY object_type =  'PRODVERS'.
  IF sy-subrc <> 0.
    APPEND INITIAL LINE TO et_struct_mapping  ASSIGNING <ls_struct_mapping>.
    <ls_struct_mapping>-object_type  =  'PRODVERS'.
    <ls_struct_mapping>-object_structure = 'MKAL'.
  ENDIF.

endmethod.


Generic Object type = Field ET_STRUCT_MAPPING-OBJECT_TYPE

Generic Object Details Structure = ET_STRUCT_MAPPING-OBJECT_STRUCTURE


BAdI Method GET_OBJ_DETAILS_GEN / GET_OBJ_DETAILS_GEN

Purpose of this method to feed SAP ECTR with the Generic Object Details.

Method receives input table IT_OBJECTS filled by ECTR with Generic Object keys, then Generic Object details are read with BAdI specific logic and finally method returns Generic Object details to the ECTR via flat output table ET_OBJECT_DATA.

Next fields filled by ECTR in the Input table IT_OBJECTS:

  • DOKOB - Generic Object Type name;
  • OBJKY - Generic Object Key; (upper case values only!)
  • TAB_INDEX - Unique Index of the Generic Object (must be the same in the output ET_OBJECT_DATA).

Following fields are expected by ECTR to be filled by BAdI specific logic in the output ET_OBJECT_DATA:

  • TAB_INDEX – Unique Index of the Customer Object (should correspond to the input IT_OBJECTS).
  • LINE_INDEX - Line number in the case when fieldvalue longer than VALUE (not in GET_OBJ_DETAILS_GEN2)
  • FIELDNAME - Name of the field from the Customer Object Details Structure;
  • VALUE - Value of the according field of the Customer Object Details Structure;

Output table ET_OBJ_SYSTEM_STATUS - reserved for future developments.

/DSCSAG/IF_PLM_OBJ_DETAILS~GET_OBJ_DETAILS_GEN
METHOD /dscsag/if_plm_obj_details~get_obj_details_gen.

  DATA: ls_data TYPE          /dscsag/obj_data_s,
        lt_mkal TYPE TABLE OF zmkal,
        ls_key TYPE zmkal_key,
        lt_key TYPE TABLE OF zmkal_key.

  FIELD-SYMBOLS: <ls_objects>        TYPE /dscsag/object,
                 <ls_mkal> TYPE zmkal.

*Object  Type  and   Key received, map it  to  Details reading  functionality
  LOOP AT it_objects  ASSIGNING <ls_objects> WHERE dokob = 'PRODVERS'.
    CLEAR ls_key.
    MOVE <ls_objects>-objky(18) TO ls_key-matnr.
    MOVE <ls_objects>-objky+18(4) TO ls_key-werks.
    MOVE <ls_objects>-objky+22(4) TO ls_key-verid.
    ls_key-tab_index    = <ls_objects>-tab_index.
    APPEND ls_key TO lt_key.
  ENDLOOP.

  IF lt_key[] IS INITIAL.
    RETURN.
  ENDIF.

  REFRESH lt_mkal.
  SELECT * FROM mkal
    INTO CORRESPONDING FIELDS OF TABLE lt_mkal
    FOR ALL ENTRIES IN lt_key
    WHERE matnr = lt_key-matnr AND
          verid = lt_key-verid AND
          werks = lt_key-werks.
  IF sy-subrc NE 0.
    RETURN.
  ENDIF.

* It is important to fill the tab_index properly
  LOOP AT lt_key INTO ls_key.
    READ TABLE lt_mkal ASSIGNING <ls_mkal>
       WITH KEY matnr = ls_key-matnr
                verid = ls_key-verid
                werks = ls_key-werks.
    IF sy-subrc EQ 0.
      <ls_mkal>-tab_index    = ls_key-tab_index.
    ENDIF.
  ENDLOOP.

  /dscsag/cl_obj_details=>map_object_details( EXPORTING iv_object_type    = 'PRODVERS'
                                                       iv_structure_name = 'ZMKAL'
                                                       it_data           = lt_mkal[]
                                             CHANGING  et_object_data    = et_object_data[] ).

ENDMETHOD.

Used Structures:

ZMKAL

ComponentTyping methodComponent Type
.INCLUDE

Types

MKAL
TAB_INDEXTypesTTIDX

ZMKAL_KEY

ComponentTyping methodComponent Type
.INCLUDE

Types

MKAL_KEY
TAB_INDEXTypesTTIDX

BAdI Method GET_OBJ_PREVIEW_DOC

  • Purpose of this method to return a document containing a preview original for this generic object.
  • Method receives input table CT_OBJECTS filled by ECTR with Generic Object keys, then in table CT_PREVIEW_DIR the documents containing the previews have to be returned. See FM /DSCSAG/OBJ_GET_PREVIEW_DOC for futher details. 
  • Example Coding see: Class /DSCSAG/CL_PLM_OBJ_INSTANCES

BAdI Method GENERIC_DROPHANDLER

  • Purpose of this method is to provide the logic for objects dropped on this generic object.
  • Method receives structure IS_TARGET_OBJECT filled by ECTR with Generic Object key of the object some other objects in table IT_OBJECTS_LINK_ADD are dropped on. 
  • You have to provide the logic now to create this links in Backend for these objects.
  • The table IT_OBJECTS_LINK_DEL contains objects which should be removed from IS_TARGET_OBJECT.
  • Example Coding see: Class /DSCSAG/CL_OBJ_DETAILS_PLM_CR

BAdI Method GET_OBJ_LONGTEXT

  • Purpose of this method is to provide a longtext for this generic object.
  • Method receives input table IT_OBJECTS filled by ECTR with Generic Object keys, then the tables ET_LONGTEXT and ET_CATEGORY has to be filled.
  • Example Coding see: Class /DSCSAG/CL_OBJ_DETAILS_PLM_CR


Container for Generic object

Smart container for generic objects.

Example for object "Product Version"

z_dsc_prodvers_mat
FUNCTION z_dsc_prodvers_mat .
*"--------------------------------------------------------------------
*"*"Local Interface:
*"  EXPORTING
*"     VALUE(VERSION_ID) TYPE  /DSCSAG/VERSION_ID
*"     VALUE(RETURN) TYPE  BAPIRET2
*"     VALUE(RUNTIME) TYPE  /DSCSAG/RUNTIME
*"  TABLES
*"      IT_PARAMETERS STRUCTURE  /DSCSAG/SET_NAME_VALUE OPTIONAL
*"      IT_CONTAINER_OBJECTS STRUCTURE  /DSCSAG/OBJECT OPTIONAL
*"      ET_CONTAINER_OBJECTS STRUCTURE  /DSCSAG/OBJECT OPTIONAL
*"--------------------------------------------------------------------

  DATA lv_runtime TYPE p.
  GET RUN TIME FIELD lv_runtime.

  DATA: lt_mkal TYPE TABLE OF mkal,
        ls_out_object TYPE /dscsag/object.

  FIELD-SYMBOLS: <ls_parameter> TYPE /dscsag/set_name_value,
                 <ls_mkal> TYPE mkal,
                 <ls_in_object> TYPE /dscsag/object.

* Return the material to a product version (Fertigungsversion)

  READ TABLE it_container_objects INDEX 1 ASSIGNING <ls_in_object>.
  IF sy-subrc NE 0 AND
    <ls_in_object>-dokob NE 'PRODVERS'.
    RETURN.
  ENDIF.

  MOVE <ls_in_object>-objky(18) TO ls_out_object-objky.
  ls_out_object-dokob = 'MARA'.
  ls_out_object-tab_index = 1.
  APPEND ls_out_object TO et_container_objects.

*----------------------------------------------------------------------*
* Ending
*----------------------------------------------------------------------*

  runtime = /dscsag/utils=>get_runtime( lv_runtime ).
ENDFUNCTION.


Example to find object "Product Version" for a material number

z_dsc_mat_prodvers
FUNCTION z_dsc_mat_prodvers .
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  EXPORTING
*"     VALUE(VERSION_ID) TYPE  /DSCSAG/VERSION_ID
*"     VALUE(RETURN) TYPE  BAPIRET2
*"     VALUE(RUNTIME) TYPE  /DSCSAG/RUNTIME
*"  TABLES
*"      IT_PARAMETERS STRUCTURE  /DSCSAG/SET_NAME_VALUE OPTIONAL
*"      IT_CONTAINER_OBJECTS STRUCTURE  /DSCSAG/OBJECT OPTIONAL
*"      ET_CONTAINER_OBJECTS STRUCTURE  /DSCSAG/OBJECT OPTIONAL
*"----------------------------------------------------------------------

  MOVE 'V 1.00' TO version_id.

  DATA lv_runtime TYPE p.
  GET RUN TIME FIELD lv_runtime.

  DATA: lt_mkal TYPE TABLE OF mkal,
        ls_out_object TYPE /dscsag/object.

  FIELD-SYMBOLS: <ls_parameter> TYPE /dscsag/set_name_value,
                 <ls_mkal> TYPE mkal,
                 <ls_in_object> TYPE /dscsag/object.

* Return all existing product (Fertigungsversion) versions to a material

  READ TABLE it_container_objects INDEX 1 ASSIGNING <ls_in_object>.
  IF sy-subrc NE 0 AND
    <ls_in_object>-dokob NE 'MARA'.
    RETURN.
  ENDIF.

  CLEAR: lt_mkal[].

  SELECT * FROM mkal INTO CORRESPONDING FIELDS OF TABLE lt_mkal
                WHERE matnr = <ls_in_object>-objky.     "#EC CI_NOFIRST

  LOOP AT lt_mkal ASSIGNING <ls_mkal>.

    MOVE <ls_mkal>-matnr TO ls_out_object-objky(18).
    MOVE <ls_mkal>-werks TO ls_out_object-objky+18(4).
    MOVE <ls_mkal>-verid TO ls_out_object-objky+22(4).
    ls_out_object-dokob = 'PRODVERS'.
    ls_out_object-tab_index = 1.
    APPEND ls_out_object TO et_container_objects.

  ENDLOOP.


*----------------------------------------------------------------------*
* Ending
*----------------------------------------------------------------------*
  runtime = /dscsag/utils=>get_runtime( lv_runtime ).
ENDFUNCTION.


Observer for Generic Objects 

To use the update feature of ECTR for changes in backend for the generic objects as well, the Observer can be switched on for the object.

Enable Observer:

Method GET_OBJ_CONFIG
method /DSCSAG/IF_PLM_OBJ_DETAILS~GET_OBJ_CONFIG.

* Define the table "MKAL" as the basic data for the type "PRODVERS"

  FIELD-SYMBOLS:  <ls_struct_mapping>    TYPE /dscsag/obj_type_struct_s,
                  <ls_configuration>    TYPE /dscsag/name_value_dokob2_s.

  READ TABLE et_struct_mapping TRANSPORTING NO FIELDS WITH KEY object_type =  'PRODVERS'.
  IF sy-subrc <> 0.
    APPEND INITIAL LINE TO et_struct_mapping  ASSIGNING <ls_struct_mapping>.
    <ls_struct_mapping>-object_type  =  'PRODVERS'.
    <ls_struct_mapping>-object_structure = 'MKAL'.
  ENDIF.

  READ TABLE et_configuration TRANSPORTING NO FIELDS WITH KEY dokob =  'PRODVERS'.
  IF sy-subrc <> 0.
    "Observer is enabled
    APPEND INITIAL LINE TO et_configuration  ASSIGNING <ls_configuration>.
    <ls_configuration>-dokob  =  'PRODVERS'.
    <ls_configuration>-name = /DSCSAG/CL_CONSTANTS=>MC_PLM_OBJ_DET_OBSERVER. "'OBSERVER.
    <ls_configuration>-value = /DSCSAG/CL_CONSTANTS=>MC_SRV_TRUE. "'TRUE'
  ENDIF.
endmethod.


Trigger the observer for the new object:

Enhancement for CM_FV_PROD_VERS_SAVE
   DATA: ls_chobj          TYPE /DSCSAG/CH_OBJ2,
         lv_timestamp      TYPE timestampl,
         lv_timestamp_char TYPE char27.
   FIELD-SYMBOLS: <ls_mkal_aend> TYPE MKAL_AEND.
 
   LOOP AT lt_mkal_aend ASSIGNING <ls_mkal_aend>. "for all changed/deleted/created PRODVERS objects call observer trigger
     CLEAR ls_chobj.
     ls_chobj-mandt       = <ls_mkal_aend>-mandt.
     GET TIME STAMP FIELD lv_timestamp.
 *    ls_chobj-changed_at  = <ls_mkal_aend>-aedat.
 * Timestamp datatype has format YYYYMMDDhhmmss.mmmuuun, /DSCSAG/CH_OBJ2-change_at has lenght 15, so we need to remove .
 * and add one digit of milliseconds
     lv_timestamp_char = lv_timestamp.
     REPLACE '.' WITH '' INTO lv_timestamp_char.
     CONDENSE lv_timestamp_char NO-GAPS.
     ls_chobj-changed_at  = lv_timestamp_char.
 
     ls_chobj-objecttable = 'PRODVERS'.
 
 *Get object key for prodvers object (like in Z_CL_ROPD_VERS_DETAILS method GET_OBJ_DETAILS_GEN)
     MOVE <ls_mkal_aend>-matnr TO ls_chobj-OBJECTKEY(18).
     MOVE <ls_mkal_aend>-werks TO ls_chobj-OBJECTKEY+18(4).
     MOVE <ls_mkal_aend>-verid TO ls_chobj-OBJECTKEY+22(4).
 
     IF <ls_mkal_aend>-aenam IS INITIAL.
       ls_chobj-changed_by  = <ls_mkal_aend>-annam.     "observer trigger for recently created document
     ELSE.
       ls_chobj-changed_by  = <ls_mkal_aend>-aenam.     "observer trigger for existing document
     ENDIF.
 
     ls_chobj-savecounter = <ls_mkal_aend>-VBKZ.        "TODO
 
     /dscsag/cl_obj_details=>observer_trigger( is_object = ls_chobj
                                               iv_commit = space
                                               iv_in_update_task = 'X' ).
   ENDLOOP.



Frontend

<ObjectType> = "GEN_<Table_Type>"

<ObjectKey> = "<ObjectType>*<SapKey>"

...\customize\config\default.txt

General switch for this feature

# Switch on support for generic objects
# true=Generic and customer specific objects will be evaluated and shown in frontend
# false=No support for generic objects 

plm.generic.object.support.enabled=true 

Function Group (optional)

# For a different configuration of the pop up menu a function group can be used (used for OMFs)
# A special property of the object controls the function group

# plm.om.generic.business.object.<OBJECT_TYPE>.function.group.property=<PROPERTY_KEY> (Default: empty)

plm.om.generic.business.object.GEN_PRODVERS.function.group.property=

Display Group (optional)

# For a different configuration of the layout of a generic object one property can be used to control the display group

# plm.om.generic.business.object.<OBJECT_TYPE>.display.group.property=<PROPERTY_KEY> (Default: empty)

plm.om.generic.business.object.GEN_PRODVERS.display.group.property= 

Description Property (mandatory)

# Define the field which is used for the description text in the header panel of the Object Browser

# plm.om.generic.business.object.<OBJECT_TYPE>.description.property=<PROPERTY_KEY> (Default: empty)
plm.om.generic.business.object.GEN_PRODVERS.description.property=TEXT1

Containers (optional)

# Define the available containers for a gernic object

# plm.om.<OBJECT_TYPE>.containers= SMART_CONT(<ID1>); SMART_CONT(<ID2>); SMART_CONT(<ID2>);

plm.om.GEN_PRODVERS.containers= SMART_CONT(PRODVERS_MARA)

plm.smart.container.PRODVERS_MARA.name = Material of a Product version
plm.smart.container.PRODVERS_MARA.macro = generic_SmartContainer_macro.txt
plm.smart.container.PRODVERS_MARA.params.0  = FM:Z_DSC_PRODVERS_MAT
plm.smart.container.PRODVERS_MARA.icon = {0}/sap/material_white_2       

Use in container (optional)

# The generic objects can be used in containers of existing objects

plm.om.MAT.containers      = OLINKS;REVISIONS;MAT_BOM_ROOT;MAT_WHEREUSED;CLASSES;EQUI_CONT;SMART_CONT(PRODVERS)

plm.smart.container.PRODVERS.name = Product version in material
plm.smart.container.PRODVERS.macro = generic_SmartContainer_macro.txt
plm.smart.container.PRODVERS.params.0  = FM:Z_DSC_MAT_PRODVERS
plm.smart.container.PRODVERS.icon = {0}/sap/folder_open         


StatusFlags (optional)

# Define additional icons for generic objects

# plm.om.generic.business.object.<OBJECT_TYPE>.icon.<POSITION> = flag_$(PROPERTY_KEY1)_$(PROPERTY_KEY2) 

plm.om.generic.business.object.GEN_PRODVERS.icon.2 = productversion_status_$(PRFG_F)



StatusFlags \customize\aux-files\customer_icons.txt

# Add the mapping for the generic objects

#     Not yet checked => message_warning 
# 1    Last check o.k. => message_success
# 2    Last check with warning => message_warning_2
# 3    Last check with error => message_error

productversion_status_ = {0}/sap/message_warning
productversion_status_1 = {0}/sap/message_success
productversion_status_2 = {0}/sap/message_warning_2 
productversion_status_3 = {0}/sap/message_error

Tool-Tip (optional)

# Show a tooltip text in the Object Browser

# plm.om.generic.business.object.<OBJECT_TYPE>.tooltip.pattern= Text $(<PROPERTY_KEY>) text $(<PROPERTY_KEY>) (Default: empty)

plm.om.generic.business.object.GEN_PRODVERS.tooltip.pattern = Product Version $(VERID) $(TEXT1)


Drag & Drop (optional)

# Support drag and drop for generic objects into object lists

# plm.om.generic.business.object.<OBJECT_TYPE>.drag.supported Default(true)

# Support drop support for folders

# plm.om.generic.business.object.<GEN_OBJ>.dragto.FLD.supported Default (true)

plm.om.generic.business.object.GEN_PRODVERS.drag.supported=true
plm.om.generic.business.object.GEN_PRODVERS.dragto.FLD.supported = true


# Allow drop on this object  
  plm.om.generic.business.object.<GEN_OBJ>.dnd.allowed=true


IndicationIcon

# Define the main icon of the generic object

# plm.om.generic.business.object.<OBJECT_TYPE>.icon.1 (Dafault: default_bo_icon)
plm.om.generic.business.object.GEN_PRODVERS.icon.1= {0}/sap/process

...\customize\dictionary\<LANGU>\customer.txt

Container Label in Folder

# Define the text which is shown in the containers of the list view for folders in the object browser

# plm.om.generic.business.object.<OBJECT_TYPE>.label (Default: OBJECT_TYPE)

plm.om.generic.business.object.GEN_PRODVERS.label = Product versions

HeaderPanel

# Define the texts in the Object Browser Header Panel

# plm.om.generic.business.object.<OBJECT_TYPE>.header.name (Default: Name)
# plm.om.generic.business.object.<OBJECT_TYPE>.header.description (Default: Description)

plm.om.generic.business.object.GEN_PRODVERS.header.name = Product Version
plm.om.generic.business.object.GEN_PRODVERS.header.description = Short Text

ApiGeneric

# Define the texts for the generic functions

# fnc.api.generic2(<function name>) = Menu name

fnc.api.generic2(C223) = Production Version Mass Processing


...\customize\aux-files\api_definitions2.xml

ApiGeneric

# All properties of the generic objects are supported.

# type=<OBJECT_TYPE>

    <function apiname="/DSCSAG/TRANSACTION_CALL2" name="C223" refresh="true" transaction="bright" background="false" type="GEN_PRODVERS" getecm="active">
        <import>
            <parameter name="TCODE" string="C223"/>
            <parameter name="PLANT" value="WERKS"/>
            <parameter name="MATERIAL" value="MATNR"/>
        </import>
        <tables/>
    </function>

...\customize\config\menu.guidef

ApiGeneric

# Define functions of generic objects

# +  om.popup.menu.<OBJECT_TYPE> = <function>

+  om.popup.menu.GEN_PRODVERS = fnc.api.generic2(C223)


Add new Search function for generic objects

Create new search macro in directory ...\customize\scripts\macros\wizard

Example prodversionByMaterial.txt:

p = GET_MASK_INPUT( "STANDARD_MAT", "mat.mask.title", "MAT")
setId = SEARCH( "mat", p )
setId = TRANSFORM_SET(setId, "FM:Z_DSC_MAT_PRODVERS")
keylist = KEYLIST_FROM_SET( setId )
WRITE_RESULTLIST(keylist)


...\customize\config\default.txt

plm.macro.wizard.icon.for.prodversionByMaterial.txt = {0}/sap/process

...\customize\dictionary\<LANGU>\customer.txt

plm.macro.wizard.value.for.prodversionByMaterial.txt = Product version
fnc.add.with.macro(prodversionByMaterial.txt) = Product version



...\customize\config\menu.guidef

+  om.custom.tool.FLD_TMP.ctx_desk      = fnc.favorite.folder.manager
                                        = fnc.cdesk.srv.search
                                        = -----------------------------
                                        = mnu.flyout.add
                                           = fnc.doc.add
                                           = fnc.mat.add
                                           = fnc.ecm.add
                                           = fnc.add.with.macro(prodversionByMaterial.txt)
...
+  om.popup.menu.FLD_TMP                = fnc.tmp.fld.set.as.active.list
                                        = fnc.tmp.fld.set.as.persistent.list
                                        = -----------------------------
                                        = mnu.flyout.add
                                           = fnc.doc.add
                                           = fnc.mat.add
                                           = fnc.ecm.add
                                           = fnc.add.with.macro(prodversionByMaterial.txt)
...


...\customize\aux-files\customer_icons.txt

fnc.add.with.macro(prodversionByMaterial.txt) = {0}/sap/process








Related Content

  • 2947857 - ECTR: Fixed: Wrong data type for generic object detail value





  • No labels