Indu Learning Platform
Course/Unit 2 · ABAP for MDG
Lesson 2-2

Validations and derivations with BAdIs

Where each MDG check runs, when BRFplus is enough, and how to write, test and debug a validation or derivation BAdI in ABAP.

Watch firstValidations and derivations using Badi - Simple · Koushik KondaOpen on YouTube ↗

The checking chain

On Check, Submit or step completion, MDG runs its checks in layers and shows all messages together. You configured most layers as a functional consultant; now you write the last one. Put each rule in the lowest layer that can express it: code is the most powerful layer, and the most expensive to change.

User: Check / SubmitUI or APIData model checkskeys, check tablesBackend checksreuse area: BP, MMBRFplus rulesMDGIMGBAdI checksUSMD_RULE_SERVICEMessages to UIerrors block submit
Errors from any layer stop the change request; warnings do not.
Try it · Put in order

Put the checking chain in the order MDG runs it.

  1. 1BAdI checks in USMD_RULE_SERVICE
  2. 2BRFplus validation and derivation rules
  3. 3Messages merged and shown to the user
  4. 4Data model checks (keys, check tables)
  5. 5Backend checks of the reuse area
  6. 6User clicks Check or Submit

BRFplus or BAdI?

BRFplus suits rules the business should read and maintain. A BAdI suits rules that need transactional or external data, cross-object loops, or speed in mass change requests.

BRFplusBusiness can read and maintain itField-level checks and simple derivationsDecision tables per country / groupLow code, faster to changeBAdI (ABAP)Reads transactional or external dataCross-entity and cross-object checksComplex loops, heavy lookupsUnit-testable, version-controlled codevs
Start in BRFplus. Move to code when the rule needs data or logic BRFplus cannot reach cleanly.

Try it: sort the rule spreadsheet

Try it · Sort

The business sent these supplier and cost center rules. Where does each one belong?

Data model check
BRFplus
BAdI
Click an item, then a bucket (or drag it).

Anatomy of a BAdI

SAP defines an interface; you implement it in a class; MDG calls it. USMD_RULE_SERVICE is filtered by data model, so your cost center logic never runs for BP. Open it in SE18 on your release to confirm the exact methods and parameters.

Enhancement spot (MDG rules)BAdI definitionUSMD_RULE_SERVICEfilter: data modelInterfaceIF_EX_USMD_RULE_SERVICECHECK_ENTITYDERIVE_ENTITYYour implementationZEI_CCTR_RULES (SE19)filter value 0Gclass ZCL_CCTR_RULES
SAP owns the spot, definition and interface. You own the implementation and its class.

What happens when the user clicks Check

Step through · 1 of 6
User clicks CheckCR in step 00MDG frameworkcollects changed entitiesBAdI callfilter 0GCHECK_ENTITYyour classRule classZCL_CCTR_VALIDATORMessagesback to the UI
The requester changed cost center 4711. All data sits in the change request's staging area, not the active area.
Set a breakpoint in CHECK_ENTITY and click Check to watch this live.

Writing the validation

Reject a cost center whose company code is in a custom blocked list. Three habits: one SELECT for all rows, the decision in a separate class, and messages from a message class so they translate.

ABAP
" OUTLINE: check exact parameter names in SE18 on your release
METHOD if_ex_usmd_rule_service~check_entity.
  CHECK id_entitytype = 'CCTR'.
  " 1. Collect company codes of the changed cost centers -> lt_bukrs
  " 2. One SELECT for all of them, never one per row:
  "    SELECT bukrs FROM zmdg_blocked_cc
  "      FOR ALL ENTRIES IN @lt_bukrs WHERE bukrs = @lt_bukrs-table_line
  "      INTO TABLE @DATA(lt_blocked).
  " 3. Delegate the decision, return messages:
  "    IF NEW zcl_cctr_validator( lt_blocked )->is_blocked( <ls_cctr>-bukrs ).
  "      APPEND VALUE #( msgid = 'ZMDG' msgty = 'E' msgno = '001'
  "                      msgv1 = <ls_cctr>-bukrs ) TO et_message.
  "    ENDIF.
ENDMETHOD.

Implement via the MDGIMG BAdI activity or SE19, set the filter to your data model, activate.

Derivations: filling fields for the user

A derivation sets values instead of checking them. It runs often, so it must be cheap and idempotent: running twice gives the same result. Usually fill only empty fields so manual entries survive.

Input in the change requestDerived fieldCost center: company codeCost center: responsible userSupplier: countryMaterial: product hierarchyCurrency (from T001-WAERS)Person responsible nameRegion default / sort keyDivisionlookupuser masterdefault rulecustom table
Decide whether a derivation overwrites user input or only fills empty fields.

Testing and debugging

Unit-test the validator class with a fake blocked list: no database, no change request. For the integration, set an external breakpoint (MDG UIs run in the browser) and click Check.

RequesterMDG UIMDG frameworkBAdI classDatabaseChange CCTR 4711, Checkcheck change requestCHECK_ENTITY (filter 0G)one SELECT on custom tableblocked company codeset_message: E ZMDG 001merged messageserror shown, submit blocked
The BAdI reads, decides and returns messages. It never writes.
Try it · What would you do?

You set an external breakpoint in CHECK_ENTITY, open the cost center change request in the browser and click Check. The debugger never stops. What do you check first?

Remember

  • Checks run in layers: data model, backend, BRFplus, then BAdIs; put each rule in the lowest layer that can express it.
  • USMD_RULE_SERVICE is filtered by data model; confirm methods and signatures in SE18 on your release.
  • Validations and derivations are read-only: no COMMIT, no writes. Keep the decision in a tested plain class.

Check yourself

A rule must check that a supplier has no open purchase orders before it can be blocked. Where should it go?
Why must a validation BAdI avoid COMMIT WORK?
For a rule 'bank details mandatory for account group ZSUP', the best first choice is…