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.
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.
Put the checking chain in the order MDG runs it.
- 1BAdI checks in USMD_RULE_SERVICE
- 2BRFplus validation and derivation rules
- 3Messages merged and shown to the user
- 4Data model checks (keys, check tables)
- 5Backend checks of the reuse area
- 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.
Try it: sort the rule spreadsheet
The business sent these supplier and cost center rules. Where does each one belong?
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.
What happens when the user clicks Check
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.
" 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.
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.
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.