User Exits Part 4: MV45AFZZ — Sales Order Exits and Save Logic
Use the main sales order exits correctly: USEREXIT MOVE FIELD TO VBAK/VBAP/VBKD for defaults, USEREXIT SAVE DOCUMENT PREPARE for checks and final changes, USEREXIT SAVE DOCUMENT for own tables, custom fields via VBAK/VBAP appends, and working with XVBAP/YVBAP and UPDKZ.
Explanation
📌 KEY POINTS
✅ USEREXIT_MOVE_FIELD_TO_VBAK / _VBAP / _VBKD: fill (custom) fields while the user enters data.
✅ USEREXIT_SAVE_DOCUMENT_PREPARE: last point to check and change the document before saving; error messages here stop the save.
✅ USEREXIT_SAVE_DOCUMENT: SAP is saving; use it to write own tables (in update task) — no more changes to the order here.
⚠️ Changing XVBAP in SAVE_DOCUMENT_PREPARE requires setting UPDKZ = 'U' for existing items, otherwise the change is not saved.
━━━━━━━━━━━━━━━━━━━━
▶ WHERE WE ARE
Part 3 found the exits. MV45AFZZ is the most used user-exit include in SD — this lesson covers its key FORMs.
━━━━━━━━━━━━━━━━━━━━
▶ 1. DEFAULTS DURING ENTRY
- USEREXIT_MOVE_FIELD_TO_VBAK — header: set custom field ZZ… or defaults based on customer data.
- USEREXIT_MOVE_FIELD_TO_VBAP — item: runs when an item is created/changed; VBAP is the current item.
- USEREXIT_MOVE_FIELD_TO_VBKD — business data (payment terms, incoterms…).
- Only set a field if it is initial or clearly derived, so user input is not overwritten.
━━━━━━━━━━━━━━━━━━━━
▶ 2. CUSTOM FIELDS
- Append structure to VBAK/VBAP with ZZ fields (SE11).
- Screen: customer subscreens (tabs "Additional data B") in SAPMV45A screens 8309 (header) / 8459 (item) — code in MV45AFZZ/MV45AFZB or the screen PBO/PAI.
- Copy control: data transfer routines if values must be copied from quotation to order.
━━━━━━━━━━━━━━━━━━━━
▶ 3. CHECKS BEFORE SAVE
USEREXIT_SAVE_DOCUMENT_PREPARE:
- Loop at XVBAP WHERE updkz <> 'D' to check items.
- MESSAGE type E stops saving and returns to the order (dialog). In BAPI calls, the error comes back in RETURN.
- Avoid POPUP functions; the exit runs in background too.
━━━━━━━━━━━━━━━━━━━━
▶ 4. FINAL CHANGES BEFORE SAVE
- Changing header: modify VBAK and, if needed, VBAK-UPDKZ handling is done by SAP for the header.
- Changing items: modify XVBAP; for existing items set updkz = 'U' if it is initial, then MODIFY xvbap.
━━━━━━━━━━━━━━━━━━━━
▶ 5. SAVE TIME
USEREXIT_SAVE_DOCUMENT: SAP writes the document; you can write own Z tables via update FM (IN UPDATE TASK) — the order number (VBAK-VBELN) is available here for new orders.
━━━━━━━━━━━━━━━━━━━━
▶ STEP BY STEP
- Add a ZZ field via VBAK append (sandbox) and default it in MOVE_FIELD_TO_VBAK.
- Implement a PO number check in SAVE_DOCUMENT_PREPARE.
- Write a log table entry in SAVE_DOCUMENT using an update FM.
✅ CHECKPOINT: you use the right MV45AFZZ FORM for defaults, checks, final changes and own tables.
Code example
* ===== MV45AFZZ =====FORM userexit_move_field_to_vbap.* Default a custom item field only if the user left it empty IF vbap-zzproject IS INITIAL AND vbak-zzproject IS NOT INITIAL. vbap-zzproject = vbak-zzproject. " inherit from header ENDIF.ENDFORM. FORM userexit_save_document_prepare. DATA: ls_item TYPE vbapvb, lv_tabix TYPE sy-tabix. CHECK t180-trtyp <> 'A'. " not in display mode * ----- Check: PO number mandatory for ZOR ----- IF vbak-auart = 'ZOR' AND vbak-bstnk IS INITIAL. MESSAGE e001(zsd). " stops the save (dialog) / RETURN (BAPI) ENDIF. * ----- Final change: set a custom flag on items above a value ----- LOOP AT xvbap INTO ls_item WHERE updkz <> 'D'. lv_tabix = sy-tabix. IF ls_item-netwr > 100000 AND ls_item-zzapproval IS INITIAL. ls_item-zzapproval = 'X'. IF ls_item-updkz IS INITIAL. " existing, unchanged item ls_item-updkz = 'U'. " otherwise the change is not saved ENDIF. MODIFY xvbap FROM ls_item INDEX lv_tabix. ENDIF. ENDLOOP.ENDFORM. FORM userexit_save_document.* Document is being saved: VBAK-VBELN is known. Only own tables here. DATA ls_log TYPE zso_log. ls_log-vbeln = vbak-vbeln. ls_log-ernam = sy-uname. ls_log-erdat = sy-datum. CALL FUNCTION 'Z_SO_LOG_SAVE' IN UPDATE TASK " saved with SAP's commit EXPORTING is_log = ls_log.ENDFORM.Real project scenario
An approval flag set on high-value items in SAVE_DOCUMENT_PREPARE worked for new orders but not for changed orders. The developer had modified XVBAP without setting UPDKZ = 'U' for existing items, so SAP did not update them.
After the fix, the team also noticed that the check message appeared as a hard error in the e-commerce BAPI and was returned correctly in the RETURN table — confirming the exit worked in both paths.
Common mistakes
- Changing XVBAP without UPDKZ handling.
- Overwriting user input in MOVE_FIELD exits.
- Popups or COMMIT in save exits.
- Checking deleted items (UPDKZ = 'D').
- Changing the order in USEREXIT_SAVE_DOCUMENT (too late).
Best practices
- Defaults in MOVE_FIELD exits only when initial.
- Checks and final changes in SAVE_DOCUMENT_PREPARE.
- Own tables via update task in SAVE_DOCUMENT.
- Respect UPDKZ and T180-TRTYP.
- Keep code in Z includes/classes; document each use.
Interview angle
Questions: "Which MV45AFZZ exit do you use for a check before save?", "How do you add a custom field to the sales order?", "Why is my XVBAP change not saved?"
Strong answer: MOVE_FIELD_TO_VBAK/VBAP/VBKD for defaults; SAVE_DOCUMENT_PREPARE for checks (MESSAGE E) and final changes; SAVE_DOCUMENT for own tables via update task; custom fields via VBAK/VBAP append + customer subscreen; XVBAP changes need UPDKZ 'U' for existing items; skip deleted items and display mode.
Practice this lesson
Quick check
1. A check in USEREXIT_SAVE_DOCUMENT_PREPARE should apply only to standard orders. What is missing if it also blocks returns?
2. USEREXIT_MOVE_FIELD_TO_VBAP is called:
3. USEREXIT_SAVE_DOCUMENT_PREPARE runs:
Interview questions
1. A compliance validation in MV45AFZZ worked in VA01 but unexpectedly blocked returns and credit memo requests. What went wrong and how do you fix it?
Answer it in your own words first, then compare.
2. You must prevent saving sales orders without a purchase order reference. Where?
Answer it in your own words first, then compare.
Reference-verified: the steps are checked against official SAP documentation and tutorials, and object and field names in the sample code are checked for consistency. The code has not been compiled or run on an SAP system by ERPClimb. Syntax marked release-dependent varies by SAP release, so check it in your own system.
More lessons in this topic
- User Exits Part 1: What SD User Exits Are and How They Work
- User Exits Part 2: User Exits vs Customer Exits vs BAdIs — When to Migrate
- User Exits Part 3: Finding User Exits in Real Transactions
- User Exits Part 5: MV50AFZ1 — Delivery User Exit Patterns
- User Exits Part 6: RV60AFZZ — Billing User Exit Patterns
- User Exits Part 7: Safe Coding Rules Inside User Exits
- User Exits Part 8: Performance Risks in User Exits