Working with SAP MDG (Master Data Governance) often means balancing two realities: robust governance and agile adaptability. One of the common we face during MDG implementation is managing field validations with user-friendly alerts.
Whether a field should be hidden, mandatory or optional often depends on multiple factors like CR type, entity, company code or user role etc. Traditionally, these validations are implemented via BRF+ expressions, Enhancements in feeder classes, Hard-coded logic in the UI layer/BAdIs.
MDG validations are crucial for maintaining clean and consistent master data. However, the standard methods come with limitations & most teams rely on:
- While these are functional, they’re rigid, developer-dependent, and non-scalable. This complexity makes it difficult for functional/ business teams to adapt validations quickly and every change creates a dependency on development teams reducing agility.
- But what if we could avoid coding and development cycle every time specially for simple level properties or validations, yet still provide fully dynamic, context-sensitive field behaviour.
To address these challenges, a custom configuration table was designed to serve as a central validation engine covers easy level validations. Field behaviour across various MDG entities and scenarios was defined through this table eliminating the need for code changes every time.
- These rules are consumed at runtime ensuring the UI responds dynamically based on master data context.
- Validation Types : M = Mandatory, O = Optional, H = Hidden, R = Read Only
- This table is maintained via a simple maintenance view or SM30 transaction/T-Code assigned to TMG accessible to key users or functional consultants.
All this happens without modifying feeder classes or enhancing the UI every time.
[ Fig. 1.0. Table Contents ]
METHOD if_ex_usmd_acc_fld_prop_cds~modify_fld_prop_attr.
DATA:lr_model TYPE REF TO if_usmd_app_context.
CALL METHOD cl_usmd_app_context=>get_context
RECEIVING
eo_context = lr_model.
IF lr_model IS BOUND.
CALL METHOD lr_model->get_attributes
IMPORTING
ev_crequest_type = DATA(lv_cr_type)
ev_crequest_step = DATA(lv_cr_step).
ENDIF.
DATA: go_tab_descr TYPE REF TO cl_abap_tabledescr,
go_struc_descr TYPE REF TO cl_abap_structdescr,
lt_components TYPE abap_component_tab.
DATA: name_range TYPE RANGE OF zfi_mdg_valt-condition_tech.
"Pre-Exception Handling To Get Valid Fields For it_data As not-valid entry entered in Condition Property
go_tab_descr ?= cl_abap_tabledescr=>describe_by_data( it_data ).
CHECK sy-subrc = 0.
go_struc_descr ?= go_tab_descr->get_table_line_type( ). "Get the structure of your internal table
lt_components = go_struc_descr->get_components( ).
REFRESH name_range.
name_range = VALUE #( FOR wa IN lt_components ( sign = 'I' option = 'EQ' low = wa-name ) ).
"Check Mandatory(*)/Hide/Read Only/Optional Attribute Property
SELECT * FROM zfi_mdg_valt INTO TABLE (it_mdg_val)
WHERE cr_type = _cr_type AND cr_step = _cr_step AND entity_type = _entity
AND zmodule = '0G' AND active = 'X'.
IF sy-subrc = 0.
LOOP AT ct_fld_prop ASSIGNING FIELD-SYMBOL(<fs_data_2>).
ASSIGN COMPONENT 'USMD_FP' OF STRUCTURE <fs_data_2> TO FIELD-SYMBOL(<fs_fld_prop_2>).
LOOP AT it_mdg_val INTO DATA(wa_val) WHERE entity_type = iv_entity. "Traverse Custom Defined Properties
IF wa_val-condition_tech IS NOT INITIAL. "Check If Condition maintained or free of any condition
IF wa_val-condition_tech IN name_range. "Preventive Action
READ TABLE it_data ASSIGNING FIELD-SYMBOL(<fs_data_con>)
WITH KEY (wa_val-condition_tech) = wa_val-condition_val.
"Condition is not matching, continue with next iteration of properties of it_mdg_val
IF sy-subrc NE 0.
CONTINUE.
ENDIF.
ELSE.
CONTINUE. "Not Valid Condition Attribute/Property
ENDIF.
ENDIF.
"Check for further tech property
ASSIGN COMPONENT wa_val-tech_name OF STRUCTURE <fs_fld_prop_2> TO FIELD-SYMBOL(<ls_field_2>).
IF <ls_field_2> IS ASSIGNED.
<ls_field_2> = wa_val-property.
ENDIF.
UNASSIGN <ls_field_2>.
ENDLOOP.
UNASSIGN <fs_fld_prop_2>.
ENDLOOP.
ENDIF.
ENDMETHOD.
METHOD if_ex_usmd_rule_service~check_entity.
DATA: lr_model TYPE REF TO if_usmd_app_context.
DATA: go_tab_descr TYPE REF TO cl_abap_tabledescr,
go_struc_descr TYPE REF TO cl_abap_structdescr,
lt_components TYPE abap_component_tab.
DATA: name_range TYPE RANGE OF zfi_mdg_valt-condition_tech.
CALL METHOD cl_usmd_app_context=>get_context
RECEIVING
eo_context = lr_model.
IF lr_model IS BOUND.
CALL METHOD lr_model->get_attributes
IMPORTING
ev_crequest_type = DATA(lv_cr_type)
ev_crequest_step = DATA(lv_cr_step).
ENDIF.
"Pre-Exception Handling To Get Valid Fields For it_data As not-valid entry entered in Condition Property
go_tab_descr ?= cl_abap_tabledescr=>describe_by_data( it_data ).
CHECK sy-subrc = 0.
go_struc_descr ?= go_tab_descr->get_table_line_type( ). "Get the structure of your internal table
lt_components = go_struc_descr->get_components( ).
REFRESH name_range.
name_range = VALUE #( FOR wa IN lt_components ( sign = 'I' option = 'EQ' low = wa-name ) ).
"Mandatory Check Working for FI : GL,CC,PC
SELECT * FROM zfi_mdg_valt INTO TABLE (it_zfi_mdg_valderv)
WHERE cr_type = _cr_type AND cr_step = _cr_step
AND zmodule = '0G' AND property = 'M' AND active = 'X'.
LOOP AT it_zfi_mdg_valderv INTO DATA(wa_val).
LOOP AT it_data ASSIGNING FIELD-SYMBOL(<ls_data>).
IF <ls_data> IS ASSIGNED.
IF wa_val-condition_tech IS NOT INITIAL. "Check If Condition maintained or free of any condition
IF wa_val-condition_tech IN name_range. "Preventive Action
ASSIGN COMPONENT wa_val-condition_tech OF STRUCTURE <ls_data> TO FIELD-SYMBOL(<ls_con>).
IF <ls_con> IS ASSIGNED AND <ls_con> IS NOT INITIAL.
IF <ls_con> NE wa_val-condition_val.
CONTINUE.
ENDIF.
UNASSIGN <ls_con>.
ENDIF.
ELSE.
APPEND VALUE #( msgty = 'E' msgv1 = 'Please check entity name' msgv2 = wa_val-condition_tech ) TO et_message.
CONTINUE.
"msgid = 'zfi_mdg_message' msgno = 000
ENDIF.
ENDIF.
ASSIGN COMPONENT wa_val-tech_name OF STRUCTURE <ls_data> TO FIELD-SYMBOL(<ls_value>).
IF <ls_value> IS ASSIGNED AND <ls_value> IS INITIAL.
APPEND VALUE #( msgid = wa_val-msgid msgty = wa_val-msgty
msgno = wa_val-msgno msgv1 = wa_val-msgv1 msgv2 = wa_val-msgv2 ) TO et_message.
UNASSIGN <ls_value>.
ENDIF.
ENDIF.
ENDLOOP.
ENDLOOP.
ENDMETHOD.
1.1. With Loading, Business area is hidden, Profit Center is mandatory, Department & User Responsible are not mandatory.
[ Fig 1.1 : Initial Screen ]
1.2. With entering Company code = ‘0001’, Department becomes mandatory (*).
[ Fig 1.2 : Department is mandatory ]
2.1. For Company code = ‘0003’, Department is not mandatory
[ Fig 2.1 : Department not mandatory ]
3.1. With loading, User Responsible is not mandatory by default.
[ Fig 3.1 : User Responsible not mandatory ]
3.2. With Cost center category = ‘%’, User Responsible becomes mandatory.
[ Fig 3.2 : User Responsible mandatory ]
3.3. Click on Check: As Profit Center & User Responsible are blank, we got error messages defined in our Z table.
[ Fig 3.3 : Messages ]
3.4.Errors on Check
[ Fig 3.4 : Messages ]
To troubleshoot scenario where user has maintained conditional-tech-property/attribute as not-valid property value ( By mistake ; ) So below error will appear on hitting Check.
As we are using this conditional-tech-property to read IT_DATA, it’s safe idea to check pre-hand whether the property is valid and actually present in IT_DATA to refrain from last moment surprises. (or technically a dump ; )
[ Fig. 4.1. Preventive Code ]
[ Fig : 4.2. conditional tech attribute = ‘CCODECCTR1’ is not valid attribute of data model ]
[ Fig : 5 Message Class ]
- SAP MDG is built to empower governed, agile master data. But flexibility shouldn’t mean fragility. With a configurable validation engine, we’ve transformed how we think about field behavior turning a developer-led task into a business-led control mechanism and maximum governance.
Thanks !
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
10 | |
8 | |
7 | |
6 | |
6 | |
4 | |
4 | |
4 | |
4 | |
4 |