Technology Blog Posts by Members
cancel
Showing results for 
Search instead for 
Did you mean: 
Nimii
Explorer
887
Overview

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.

The Problem: Code Dependency in Field Validation

MDG validations are crucial for maintaining clean and consistent master data. However, the standard methods come with limitations & most teams rely on:

  • Feeder class logic: Feeder class enhancements require ABAP expertise and testing cycles.
  • UI rule maintenance is scattered and often difficult to track.
  • BRF+ rules or hardcoded validations code: Every new business scenario (e.g. different behaviour based on company code or region) means new logic and testing.
  • No centralized view of how validations are controlled across the application.

- 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.

Challenges: Too Much Code, Too Little Agility
  • Hide/Show fields based on Role UI logic  is non-transparent.
  • Maintain field rules over time - Static logic -No visibility for business teams.
  • The key pain point: Every small validation change turns into a development cycle.

- 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.

Solution: Rule the Config-Driven Field Validation Framework [ All In One Place]

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.

Benefits of This Approach
  • No More Coding: New validation rules don’t require any ABAP changes at-least for simple validations.
  • Business Empowerment: Functional/Business teams can maintain rules via a user-friendly view.
  • Central Governance: One place to view and manage all field control rules along with by whom & when it’s added or changed.
  • Audit-friendly: clearly see why and when a rule applies.
  • No BRF+ overload: clean separation of decision logic.
  • Faster Change Cycles: No transports or regression testing required for every new validation rule.
  • Scalable to all MDG domains MDG – S,M,C (Supplier, Material, Customer)
Real Impact
  • After rollout: Reduced ~70% of validation-related change requests.
  • Built an enterprise-grade, reusable framework used across modules.
  • Delivered faster time-to-compliance for changing regulatory/market needs.
  • It's a shift from “write code to validate” ➝ to “configure to adapt”
How It Works: Plug-In Logic, Zero Enhancement for later changes
  1. Custom Table is maintained in SM30 or Z/Y T-code (or via custom UI).
  2. Lightweight enhancement logic is added once to retrieve rules based on runtime values.
  3. The UI behaviour adjusts: field becomes hidden, read-only mandatory or optional.
  4. No need to touch feeder classes again & ever.
You can even combine this with:
  • Workflow context (field is mandatory only in approval steps)
  • User or Role-level personalization (validation based on user group)
  • For multiple conditions can add different Sr. No conditions. E.g. Department is mandatory for Company Code =  ‘0001’  & '0005', So Can add two records with different Sr. No.
Requirement - For CR Type: ZCCT1P2: Create Cost Center with Hry. Assignments:
  1.    Business Area to be hidden.
  2.    Profit Center is mandatory.
  3.    Department is mandatory for Company Code =  ‘0001’
  4.    User Responsible is mandatory for cost center category = ‘%’.
Implementation

Nimii_0-1749533166874.png

[ Fig. 1.0. Table Contents ]

  • ZCCT1P2: Create Cost Center with Hry. Assignments.
  • Step ‘0’ defines Requestor Level.
  • Tech Property  & Conditional Tech-Property stores technical attributes.
  • Table also contains audit columns to track changes.
  1. BAdI: USMD_ACC_FLD_PROP_CUST_DEP_SET
  • EI: ZFI_ES_MDG_FLD_PROP
  • BAdI Implementation: ZFI_MDG_FLD_PROP
  • Class: ZCL_FI_MDG_FLD_PROP
  • Method: IF_EX_USMD_ACC_FLD_PROP_CDS~MODIFY_FLD_PROP_ATTR
  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.
       2.  BAdI: USMD_RULE_SERVICE
  • EI: ZFI_ES_MDG_VAL
  • BAdI Implementation: ZFI_MDG_VAL
  • Class: ZCL_FI_MDG_VAL
  • Method: IF_EX_USMD_RULE_SERVICE~CHECK_ENTITY
  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.
Output
  1. Scenario I

       1.1. With Loading, Business area is hidden, Profit Center is mandatory, Department & User Responsible are not mandatory.

Nimii_0-1749533769528.png

[ Fig 1.1 : Initial Screen ]

1.2.  With entering Company code = ‘0001’, Department becomes mandatory (*).

Nimii_1-1749533919996.png

[ Fig 1.2 : Department is mandatory ]

2. Scenario II

2.1. For Company code = ‘0003’, Department is not mandatory

Nimii_2-1749533973480.png

[ Fig 2.1 : Department not mandatory ]

3. Scenario III

3.1. With loading, User Responsible is not mandatory by default.

Nimii_3-1749533997551.png

[ Fig 3.1 : User Responsible not mandatory ]

3.2. With Cost center category = ‘%’, User Responsible becomes mandatory.

Nimii_4-1749534027291.png

[ 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.

Nimii_5-1749534051467.png

[ Fig 3.3 : Messages ]

3.4.Errors on Check

Nimii_6-1749534084656.png

[ Fig 3.4 : Messages ]

4. Additional Sanity Check:

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 ; )

Nimii_7-1749534121014.png

[ Fig. 4.1. Preventive Code ]

Nimii_8-1749534164052.png

[ Fig : 4.2. conditional tech attribute = ‘CCODECCTR1’ is not valid attribute of data model ]

5. Message Class: Generic 000, So No transport required every time for new messages.

Nimii_9-1749534184200.png

[ Fig : 5 Message Class ]

Conclusion

- 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 !   

6 Comments
Pradatta
Discoverer

Nice work. Keep it up.

Akansha1
Discoverer

Good, detailed documentation.

SugguSandeep
Contributor
0 Kudos

Nice Blog 🙂 @Nimii  with clear explanation

SugguSandeep
Contributor
0 Kudos

@Nimii A Question, how to make USMD_REASON Field Mandatory which related to change request, which is present in General Data UIBB Section ?

SugguSandeep
Contributor
0 Kudos

Similar ones, 

Field property BADI - Implementation 



Field property BADI - Using custom table


SAP Master Data Governance 
Thanks, 
Sandeep Suggu.

SugguSandeep
Contributor
0 Kudos

The Question which i asked for How to call USMD_REASON (Change Request Reason) Link of question

It can be achieved through below API:

cl_umsd_conv_som_gov_api

SAP Master Data Governance 
Thanks, 
Sandeep Suggu.