- Created by Sebastian Kiesel, last modified on Jun 07, 2021
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:
Method | Description |
---|---|
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_GEN2 | S4ECTR 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:
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.
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
Component | Typing method | Component Type |
---|---|---|
.INCLUDE | Types | MKAL |
TAB_INDEX | Types | TTIDX |
ZMKAL_KEY
Component | Typing method | Component Type |
---|---|---|
.INCLUDE | Types | MKAL_KEY |
TAB_INDEX | Types | TTIDX |
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"
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
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 /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:
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