MM Customisation Guide (is it possible — and where is the hook?)

REFERENCE · ALL SCENARIOS ⏱️ read once, use forever config → field selection → BAdI → user exit → code
👤 Who this page is for — and what it is not

This is a page for a functional MM consultant, not for a developer. Your job is never to write the ABAP. Your job is to answer three questions with confidence:

  1. Can standard SAP already do this? (most of the time, yes — and you save the client money)
  2. If not, is there an official place to hook custom logic in? (and does it actually work on this system?)
  3. Should we? (every line of custom code is a permanent cost at every upgrade)

The scenario pages stay free of developer detail on purpose. When a scenario reaches the end of what configuration can do, it says so and sends you here — to the exact section for that topic.

☁️ Working on SAP Cloud, not on-premise? Start with “Which SAP are you on?” — the tools are completely different, and almost every transaction on this page is unavailable in Public Cloud.

⛔ Read-only on our shared IDES — please do not activate anything
An active enhancement runs for every user, on every document, immediately. One mistake in a purchase-order check stops the whole system from saving purchase orders. Everything on this page is written so you can look, search and understand. The finding and the searching are the functional skill — and they are completely safe. Creating and activating an implementation is a developer task on a private development system.

🌍 First — which SAP are you on? The toolbox is completely different

This matters more than anything else on the page. The business problem is identical in every SAP. The tools you are allowed to touch are not. Someone who learned customisation on an on-premise system and then walks into a Public Cloud project will find that almost every transaction they know has been taken away.

🏢 On-Premise

The system runs on hardware you (or your hosting partner) control. You can do anything — full SPRO, full ABAP, your own tables and programs.

Our practice IDES is this one.

🏗️ Cloud, Private Edition

Your own single-tenant system, but hosted and upgraded by SAP. Technically almost the same freedom as on-premise — but SAP pushes you hard to stop using it.

The usual home for a company moving off ECC.

☁️ Cloud, Public Edition

A shared, standardised system SAP upgrades every quarter, for everybody. You get a fixed set of Fiori apps. There is no SPRO and no SE38.

You may only use what SAP has officially released.

🧼 "Clean core" — the one idea behind all of it

Old SAP projects changed SAP's own programs. Then every upgrade broke, cost a fortune to re-test, and companies stopped upgrading. Clean core is SAP's answer: never touch the standard — only plug into the sockets SAP officially provides.

Everyday picture: renting a flat. You may hang a picture on the hooks the landlord left in the wall. You may not knock a hole through the wall — even if the hole would look better — because the landlord repaints every three months and the wall must still be a wall.

Same job, different tool — the translation table

What you want to do🏢 On-Premise & 🏗️ Private Cloud (what this page teaches)☁️ Public Cloud
Change a settingSPRO — the whole IMG tree, thousands of activities❌ no SPRO. You get a fixed list of self-service configuration screens (SSCUIs), opened from the Manage Your Solution app → Configure Your Solution (newer tenants use SAP Central Business Configuration instead). If SAP did not publish an SSCUI for it, you cannot change it.
Look inside a tableSE16 / SE16N — any table❌ not available. You use released CDS views and analytical apps instead.
Add a field to a screenAppend structure + screen exit + ABAP✅ Custom Fields and Logic app — a key user adds the field, and SAP extends the table, the CDS view and the OData service for you. Usually no code at all.
Find a BAdISE18, or SE16 → SXS_ATTRT✅ the Custom Logic app lists the released BAdIs (SAP calls each one an Extension Point). The catalogue is much smaller — only what SAP guarantees to keep.
Write the BAdI codeSE19 + full ABAP in SE80/ADT✅ a small ABAP web editor inside the Custom Logic app. ⚠️ Restricted ABAP only — you may call released APIs and nothing else. No SELECT straight from a table.
Classic user exit (SMOD/CMOD)✅ available (older, needs an access key)❌ gone completely. There is no replacement — if no released BAdI exists, the answer is genuinely "no".
Write a full program / reportSE38, any ABAP⚠️ only through Developer Extensibility — ABAP Cloud written in Eclipse/ADT, restricted language, and only if your project has a 3-system landscape. Otherwise it must live outside, on SAP BTP.
Who is allowed to do itDeveloper with S_DEVELOP + access keyA key user (often the functional consultant!) for tiers 1; a developer for tier 2; a BTP team for tier 3.

The three tiers of cloud extensibility — in plain words

TierNameWhat you can doWhere you workWho
1 Key user (in-app) MM can do this Add custom fields · write small checks and calculations · implement a released BAdI · build simple custom business objects, CDS views and analytical queries · change the screen layout Fiori apps inside the system: Custom Fields and Logic, Custom Logic, Custom Business Objects, UI adaptation ⭐ A key user — very often the functional consultant. This tier is the reason MM people should read this page.
2 Developer (on-stack) ABAP Real ABAP applications, but written in the restricted ABAP Cloud language, using only released APIs. Also called "embedded Steampunk". Eclipse with ABAP Development Tools (ADT), connected to the system A developer. ⚠️ On Public Edition this is only available with a 3-system landscape.
3 Side-by-side BTP team A separate application that talks to SAP through released APIs and events. Any language — ABAP, Java, Node.js. SAP BTP (Business Technology Platform) — outside the SAP system A BTP / integration team. Used when the logic is big, or must survive independently of SAP's upgrades.
⚠️ The one sentence that changes how you answer a client on Public Cloud

"If SAP has not released it, it cannot be done — and there is no workaround."

On-premise, "no" almost always really means "yes, but it will cost you". On Public Cloud, "no" can mean no. So the evaluation below gains one extra question at the front: is there a released extension point for this at all? If there is not, the honest answers are: change the business process, wait for SAP to release it (you can request it), or build it side-by-side on BTP.

📌 So what applies to our practice system, and what should you learn?

Our IDES is an on-premise system, so everything from Step 1 downwards on this page is the on-premise / private-cloud toolbox — SE18, SMOD, SE16 and the rest, and you can practise all of it safely by looking.

⭐ But the thinking transfers 100%, and the thinking is what gets you hired:

💡 In interviews this is a favourite question. The clean answer is: "On-premise I search SXS_ATTRT for a BAdI and fall back to a classic user exit. On Public Cloud there are no classic exits, so I check the Custom Logic app for a released Extension Point, and if there is none the honest answer is a process change or a side-by-side extension on BTP. Both start the same way — prove configuration cannot do it first."

🔍 Step 1 — How to check whether something can be customised

🏢🏗️ The tools below are the on-premise / private-cloud toolbox — which is what our practice IDES is. On ☁️ Public Cloud the order of the questions is the same, but the tools are the Fiori ones from the table above.

Somebody asks for a change. Before you answer, run these six checks in this order. Stop at the first one that works — that is the cheapest answer, and the cheapest answer is almost always the right one.

#CheckHow you check it — the exact clickIf yes…
1 Is it already a setting? MM SPRO → the IMG tree → use Edit → Find and type a keyword. Or search the transaction list: SE16 → TSTCT → TTEXT = *your keyword*, language E. ✅ Done — no code, no risk, no upgrade cost.
2 Is it just field selection? MM A surprising number of "we need a change" requests are really "make this field mandatory / hidden / display-only". Material master: OMS9. Purchasing documents: OLME → Field Selection. Movement types: OMJJ. ✅ Done — still configuration.
3 Is there a BAdI? MM finds it ⭐ The most useful search you will ever learn:
SE16 → SXS_ATTRT → SPRSL = E, EXIT_NAME = a pattern such as ME_* (purchasing), MB* (goods movements), MRM* (invoices), *MATERIAL*, *BATCH*. You get the name and a plain-English description.
Then SE18 → type the name → Display to read what it offers.
✅ Best case. Modern, no access key, survives upgrades.
4 Is there a classic user exit? MM finds it SE16 → MODSAPT → SPRSL = E, NAME = MM06E*, MB*, M06B*, MG*… → you get the enhancement name and its description.
Then SMOD → type the enhancement → Display → Components to see its function exits, screen exits and menu exits.
⚠️ Works, but older. Needs CMOD and often an access key.
5 Is the hook actually USABLE here? BASIS/ABAP ⭐⭐ The check everybody skips. "The exit exists" ≠ "the exit is ready". Confirm the function module really exists: SE16 → TFDIR → FUNCNAME = the exit name. Then ask a developer to confirm the customer function group behind it has been generated. See the warning box below — this is how promises get broken.
6 Should we? MM Ask: how much of the need does the config answer already cover? Is the rest cosmetic? Who tests this at every upgrade for the next ten years? The judgement that separates a senior consultant from a junior one.
⚠️ Step 5 in real life — a true story from this system

We needed a batch number with a letter prefix. The exit EXIT_SAPLV01Z_002 exists in TFDIR. The enhancement SAPLV01Z exists in MODSAP. A CMOD project ZZBATCH exists and is active. Everything looked ready.

It was not. Creating the code container failed with message DS027 — "Program names ZX... are reserved for includes of exit function groups" — because the customer function group behind the exit had never been generated on this system. Fixing that is a developer job (SE80), and often needs an SSCR access key from SAP.

💡 The lesson to carry into every project: confirm the hook is usable before you promise a date. Four green lights and one missing piece still means "no".

🪜 Step 2 — The five layers, cheapest first

Every requirement lands on one of these five rungs. Always start at the top.

RungLayerCode?What it is — in plain words
1Configuration MM❌ noneSettings in SPRO — number ranges, movement types, tolerance limits, search strategies, account determination. Most requirements end here. No upgrade cost, ever.
2Master data MM❌ noneTicks and values on the material, vendor, info record, batch, class, characteristic. Often mistaken for a system change when it is really just data.
3BAdI MM scopes ABAP writes✅ smallA socket SAP deliberately left in its own program. No access key, SAP’s code untouched, survives upgrades. Always look for one of these before rung 4.
4Classic user exit MM scopes ABAP writes✅ yesThe older mechanism: an enhancement switched on by a project, with your code in a Z… container. Works, but needs more plumbing — and sometimes an access key.
5Custom objects / modification ABAP✅ yesYour own tables and programs — or, worst case, changing SAP’s own code. A permanent maintenance cost. Almost never the right answer in MM.
📏 The rule of thumb from our own batch project
Nine of the ten things we wanted came from rungs 1 and 2 — with no code at all. Only one cosmetic request reached rung 4, and it turned out to be the hardest, riskiest and least valuable item on the list. That ratio is normal.

🧰 Step 3 — What must be in place before any code is written

You do not need these to search and evaluate — searching is safe and is the functional consultant's job. You need them the moment somebody actually builds something.

WhatWhy it is neededWho arranges itWhat breaks without it
A development system — never productionAn active enhancement runs immediately for everyone.BASISA bug stops live business.
Developer authorisation (S_DEVELOP)To open SE18/SE19/SE38 in change mode.BASISYou can display but not create.
Developer access key (SSCR)SAP asks for a one-time key before you touch objects in SAP's own namespace — which classic user exits are.BASIS requests it from SAPYou are stopped at the last step, after everyone thinks it is done.
A package + transport requestTo carry the change from DEV → QA → Production.BASISChoosing $TMP (Local Object) means the work can never leave this system. Fine for learning; fatal for a project.
Customer namespace — names start with Z or YSAP guarantees it will never ship an object with that name.MM agrees the naming standardAn upgrade overwrites your work.
A written functional specSays exactly when the logic fires, what data it receives, what it must return, and what must NOT change.⭐ MM — this is your deliverableThe developer guesses, and the guess is wrong.
A test plan, including the negative caseProve it fires when it should — and, more importantly, that everything else still works.MMYou discover on go-live that goods receipts no longer post.
✍️ What a good functional spec actually contains — the four lines a developer needs
  1. The hook: "BAdI ME_PROCESS_PO_CUST, method CHECK."
  2. What it receives: "the whole purchase order header and items."
  3. What it must do: "raise an error message and stop the save when <the rule> is broken."
  4. What it must NOT touch: "any document that is not document type NB in company code PSPK."

That last line is the one juniors forget, and it is the one that prevents a system-wide outage. An enhancement should change as little as possible.

📚 Step 4 — The catalogue: what MM offers on this system

Every name below was read live from our IDES (DEV / client 250) using the two searches taught above — SXS_ATTRT for BAdIs and MODSAPT for classic user exits. These are not textbook lists; they are what this system really has. Jump to your topic:

🔢 Batch management

Batch numbers, and batch data filled automatically at goods movement

🛒 Purchase orders

Checks before save, your own fields, your own tab, pricing

📝 Purchase requisitions

Checks, own data, source determination, re-approval

📦 Goods movements / MIGO

Document checks, your own MIGO tab, reservations

🧾 Invoice verification

Header checks, tolerances, payment terms

🏷️ Material master

Field checks, defaults, number assignment

✅ Release strategy

Who approves, and on what value

🖨️ Output & forms

Where labels and printouts are really changed

🔢 Batch management — the hooks that exist, and the one that does not

Referenced from Scenario 16, Part C.

⚠️ There is NO BAdI for batch number assignment. We searched every batch-related BAdI on this system (SXS_ATTRT, pattern *BATCH* → 12 results) and none of them fits. Most of them are not even about material batches — CM_BADI_BATCH_JOBS, PLM_AUDIT_BATCH_JOBS and friends are about background jobs. ⚠️ A classic naming trap: always read the description, never trust the name.
RequirementHook (verified live)TypeNotes
⭐ Batch number must carry a text prefix (e.g. RMLL000001) EXIT_SAPLV01Z_002 — assign internal batch number
(_001 = check an externally typed batch number)
user exit
enhancement SAPLV01Z
SAP receives material and plant, and expects the finished batch number back. Switch it on with OMJJ → Create New Batch = B ("Automatic/manual and check in USER EXIT"). ⛔ Blocked on our system — see the DS027 warning above. Try configuration first: numeric bands per material type do 90% of this with zero risk (Scenario 16 · B3).
Propose a batch number on the goods-movement screen MBCFC010 — Propose batch number on Inventory Management item screen user exit A softer alternative to the one above: it suggests a number in the screen field instead of generating it deep in the posting logic. Often enough.
Maintain batch master data automatically during a goods movement MBCFC003 — Maintenance of batch master data for goods movements user exit e.g. fill the supplier, country of origin or production date on the batch automatically at goods receipt.
Fill batch characteristics automatically MBCFC004 — Maintenance of batch specifications for goods movements user exit Writes classification values without anyone typing them in MSC2N.
Extra checks on the batch master screens BATCH_MASTER BAdI ✅ Fires in MSC1N/MSC2N. ⚠️ Not for number generation — a common confusion.
Classify a batch before the goods receipt posts MILL_BEFORE_BATCH_CL BAdI ✅ Mill Products add-on; classification only.

↩️ Back to Scenario 16 — Batch Management.

🛒 Purchase orders — the richest set of hooks in MM

Our system has 50 BAdIs whose name starts ME_. These are the ones you will actually use.

RequirementHook (verified live)TypeNotes
⭐ "Block the save when our rule is broken" ME_PROCESS_PO_CUST → method CHECK BAdI ✅ The single most-used hook in MM. Interface IF_EX_ME_PROCESS_PO_CUST, Multiple Use, 13 methods: INITIALIZE · OPEN · PROCESS_HEADER · PROCESS_ITEM · PROCESS_SCHEDULE · PROCESS_ACCOUNT · ⭐CHECK (just before SAVE) · POST · CLOSE · 4 × FIELDSELECTION_*. SAP ships a worked example class CL_EXM_IM_ME_PROCESS_PO_CUST — read it in SE24.
"Make a field mandatory / hidden only in certain cases"ME_PROCESS_PO_CUST → FIELDSELECTION_*BAdI ✅Try plain field selection (OLME) first — it is rung 1.
"We need our own tab / our own fields on the PO"ME_GUI_PO_CUST (screen) + MM06E005 (the data)BAdI ✅ + user exitAlways used as a pair: the BAdI draws the screen, the exit stores the values. A genuinely common request.
"Change how the price is calculated"ME_PO_PRICING_CUSTBAdI ✅Last resort — pricing is normally solved with condition types and calculation schemas (configuration).
"Do something after the PO is saved" (interface, e-mail, log)ME_PURCHDOC_POSTEDBAdI ✅Fires after a successful save — the safe place for follow-on actions.
"Extra rules when choosing the source of supply"ME_CHECK_SOURCESBAdI ✅Additional checks in source determination.
"Turn off Hold / Park"ME_HOLD_POBAdI ✅Small but frequently asked.
"Add a column to the PO list report"ME_CHANGE_OUTTABBAdI ✅Enrich the ALV output in Purchasing.
"Our own document numbering rule"MM06E003 — number range and document numberuser exitOnly after you have proved SNRO cannot do it.
"Change the document overview in ME21N"MEQUERY1user exit—
📝 Purchase requisitions
RequirementHook (verified live)TypeNotes
⭐ "Check or change a requisition as it is entered"ME_PROCESS_REQ_CUSTBAdI ✅The requisition twin of ME_PROCESS_PO_CUST — same idea, same method pattern.
"Our own fields on the requisition"MEREQ001 — Customers' Own Data in Purchase Requisitionuser exit—
"Do something after the requisition is saved"ME_REQ_POSTEDBAdI ✅—
"Force a buyer to re-approve after a change"ME_REQ_APPROVALBAdI ✅Control of buyer approval after changes to a PR item.
"Create a new PR version on change"ME_REQ_NEW_VERSIONBAdI ✅—
"Group requisitions differently when converting to POs"ME590001user exitPO split in ME59.
📦 Goods movements & MIGO
RequirementHook (verified live)TypeNotes
⭐ "Check or change a material document before it posts"MB_DOCUMENT_BADIBAdI ✅The goods-movement equivalent of the PO CHECK method.
"React when MSEG / MKPF are updated"MB_DOCUMENT_UPDATE, or user exit MB_CF001BAdI ✅ / user exitUpdate-time logic. Be careful — this runs inside the database update.
"We want our own tab inside MIGO"MB_MIGO_BADIBAdI ✅External detail subscreens in MIGO — the official way to add your own fields to the goods receipt.
"Change item data in MIGO on the fly"MB_MIGO_ITEM_BADIBAdI ✅—
"Extra rules on the quantity check"MB_QUAN_CHECK_BADIBAdI ✅—
"Default the storage location automatically"MBCF0009 — Filling the storage location fielduser exitTry configuration first: the material master and movement-type settings can often do this.
"Our own text on the GR / GI slip"MBCF0005 · MBCF0002user exitSlip printing and segment text.
"Rules on reservations"MB_RESERVATION_BADI, MBCF0007BAdI ✅ / user exitMB21/MB22.
"GR default quantity / tolerance behaviour"MEVME001user exitOver- and under-delivery tolerance is configuration first.
🧾 Invoice verification (MIRO)
RequirementHook (verified live)TypeNotes
⭐ "Extra checks before the invoice is accepted"MRM_HEADER_CHECKBAdI ✅Additional checks of the document header data.
"Pre-fill fields when the invoice opens"MRM_HEADER_DEFAULT · MRM_TRANSACT_DEFAULTBAdI ✅—
"Different tolerance per supplier"MRM_TOLERANCE_GROUPBAdI ✅Standard tolerance keys (OMR6) come first — that is configuration.
"Set the payment terms by our own rule"MRM_PAYMENT_TERMSBAdI ✅—
"Extra checks before a blocked invoice is released"MRM_RELEASE_CHECKBAdI ✅—
"Spread unplanned delivery costs our way"MRM_UDC_DISTRIBUTEBAdI ✅—
"Our own fields on the invoice"MRM_ITEM_CUSTFIELDSBAdI ✅—
"Change ERS (self-billing) behaviour"MRM_ERS_HDAT_MODIFY · MRM_ERS_IDAT_MODIFY · MM08R001BAdI ✅ / user exit—
🏷️ Material master
RequirementHook (verified live)TypeNotes
⭐ "Refuse to save a material that breaks our data rules"BADI_MATERIAL_CHECKBAdI ✅Enhanced checks for material master tables. The clean way to enforce a data standard.
"Pre-fill defaults for new materials"BADI_MATERIAL_REFBAdI ✅Customer-defined default data.
"Our own checks / extra logic on the views"MGA00001 — Material Master (Industry): Checks and Enhancementsuser exitThe classic route.
"Our own material numbering rule"MGA00002 — number assignmentuser exitOnly after MMNR configuration has been proved insufficient.
"Add a whole new object/tab to the material"BADI_MATERIAL_ODBAdI ✅Larger job — usually a project in itself.
✅ Release strategy (approval)

Release strategies are configuration (characteristics, class type 032, release groups and codes) — see Scenario 13. You only need these when the value the strategy looks at does not exist as a standard field.

RequirementHook (verified live)TypeNotes
⭐ "Approve on a value SAP does not offer" (e.g. a custom field)M06E0004 — changes to communication structure, purchasing docs
M06B0002 — same, for requisitions
user exitYou add your field to the communication structure CEKKO/CEBAN, then use it as a characteristic like any other.
"Decide who approves, by our own rule"M06E0005 (POs) · M06B0001 (PRs)user exitRole determination for release.
"Overall release of a requisition on a custom value"M06B0005user exit—
🖨️ Output, labels and printed forms

Almost nothing here is a BAdI. Printing in SAP is output determination (configuration) plus a form (a developer or forms specialist). See Scenario 27 — Barcode Labels & Scanning for the whole chain worked through.

LayerWhereWhoWhat you do there
Decide when something printsNACE → application (EF = purchase order, ME = inventory management, MR = invoice verification)MMOutput types, procedures, access sequences — pure configuration.
Decide for whom it printsMN21 / MN04 — condition recordsMMMaster data, no code.
What the paper looks likeSMARTFORMS / Adobe FormsABAPYou supply the layout and the field list; a specialist builds it.
Barcodes on that paperSE73 — system barcodesBASISSAP already ships Code 128, Code 39, EAN-13, QR — usually nothing to create.
Where it physically printsSPAD — printersBASIS—

⚖️ Step 5 — Deciding, and saying it out loud

🎯 The three sentences that make you useful
  1. "Standard can do most of this." — name the setting, and say how much of the need it covers.
  2. "The rest needs an enhancement, and here is the exact hook." — name it, and say you confirmed it is usable on this system.
  3. "Here is what it will cost you forever." — testing at every upgrade, one more thing that can break, one more person who must understand it.
🗣️ How to answer this in an interview
"Before writing code I test configuration first. On a batch-prefix requirement I proved the number range is numeric-only and keyed to material type, checked every batch BAdI on the system, and confirmed the only route was the classic user exit EXIT_SAPLV01Z_002 — which was not even usable there, because the customer function group had never been generated. I advised the client that numeric bands per material type met about 90% of the need at zero risk, and that the custom prefix would add a permanent upgrade cost for a cosmetic benefit."

That answer shows config knowledge, enhancement knowledge, and commercial judgement — which is exactly what the question is testing.

🔎 The four searches — keep these

To find…Do this
A BAdI by topicSE16 → SXS_ATTRT → SPRSL=E, EXIT_NAME=*keyword* → read the description, then SE18 to open it
A classic user exit by topicSE16 → MODSAPT → SPRSL=E, NAME=M* → then SMOD → Components
Which enhancement owns a function exitSE16 → MODSAP → MEMBER = the EXIT_… name
Whether an exit really existsSE16 → TFDIR → FUNCNAME = the EXIT_… name

💡 These four work in every SAP module, not just MM. They are probably the most transferable thing on this whole site.

← Back to
Scenario 16: Batch Management
Browse →
All P2P Scenarios