READ PART 1 FIRST — FUNCTIONAL OVERVIEW
This document is the technical continuation of the functional blog published on SAP Community: “3-Level Advanced Intercompany Stock Transfer” (https://community.sap.com/t5/enterprise-resource-planning-blog-posts-by-sap/3-level-advanced-interco…). If you haven't read that one yet, it's worth doing — it covers the business case, the process flow, and the Financial Chain concept that everything here is built on.
This is the first of two technical posts. It walks through the architecture and custom development that drives the order creation part of the 3-Level STO process — the VCM configuration, the Financial Chain plumbing, the value chain steps, and the ABAP classes we built to handle them.
Introduction
Before we dive in, a quick recap of the problem. SAP S/4HANA 2023 FPS2 Private Cloud Edition ships Advanced ICo Stock Transfer as a two-company process — one delivering plant, one receiving plant, done. But, we need three. There's a Receiving Company that raises the Stock Transport Order, a Delivering Company that physically ships the goods, and an Intermediate Company sitting in the middle that handles the legal and financial leg between the two.
We couldn't just flip a configuration switch to get there — the standard framework simply doesn't support it. So we built on top of it. The design principle we held to throughout: no modifications to core Value Chain Framework internals, all custom logic isolated so it only fires for the 3-Level STO scenario, and the implementation stays close enough to SAP's own product direction that upgrading later won't be a nightmare.
The Three Legal Entities
Each company owns a distinct set of documents in the value chain:
|
ENTITY |
DOCUMENTS IN VALUE CHAIN |
|
Receiving Company (RC) |
Stock Transport Order (ZRC_STO), IC Purchase Order (ZRC_PO), Inbound Delivery, GR to storage location, ICo Supplier Invoice (MIRO) |
|
Intermediate Company (IC) |
ICo Sales Order (ZIC_SO), ICo Purchase Order (ZIC_PO), Goods Receipt in Transit Plant, Goods Transfer to SIT, Goods Issue from SIT, ICo Customer Invoice, ICo Supplier Invoice |
|
Delivering Company (DC) |
ICo Sales Order (ZDC_SO), Outbound Delivery (ZDC_OD), Goods Transfer to SIT (ZDC_GT), Goods Issue from SIT (ZDC_GI), ICo Customer Invoice |
The Intermediate Company never physically handles the goods. It exists purely in the financial and legal layer — it buys from the Delivering Company on paper, sells to the Receiving Company on paper, and the goods go straight from one physical plant to the other. That's the whole point of having a Financial Chain rather than trying to model this as two consecutive 2-Level STOs.
- VCM Configuration Objects
The first thing we did was carve out a separate configuration namespace for the 3-Level STO. A dedicated chain category (ZIT3) and chain type (ZIC_STOCKTRANSFER_3L) mean the two processes are cleanly independent from the VCM perspective.
|
OBJECT TYPE |
TCODE / PATH |
VALUE |
DESCRIPTION |
|
VCM Chain Category |
VCM_CHAIN_CAT |
ZIT3 |
3-Level Advanced Intercompany Stock Transfer — the top-level grouping for our custom process |
|
VCM Chain Type |
VCM_CHAIN_TYPE |
ZIC_STOCKTRANSFER_3L |
Full value chain definition holding all 18 steps and their handler class assignments |
|
Purchase Doc. Type |
MM Customizing |
ZBIC |
References standard UB; assigned to category ZIT3. This is what the user creates in ME21N. |
|
Sales Order Type |
VCM Assignment |
ZAIS |
Assigned to ZIT3 with Process Relevance set to Delivering / Intermediate Company |
|
Item Category |
VCM Assignment |
CBIC |
Used for Sales and Stock Transfer items under ZIT3 |
|
Step Handler ZRC_STO |
VCM_VC_CHAIN_TYPE |
ZCL_PO_IC_VCMS_INIT_STO |
Our custom handler registered for the initiating STO step |
|
Step Handler ZRC_PO |
VCM_VC_CHAIN_TYPE |
ZCL_PO_IC_VCMS_STO2PO |
Our custom handler for the IC PO creation step in Receiving Company |
|
Step Handlers — GMs |
VCM_VC_CHAIN_TYPE |
ZCL_MMIM_STEP_HANDLER_3L |
Shared goods movement handler registered for ZDC_GI, ZIC_GR, and ZIC_GT steps |
- Financial Chain
If you read the functional blog, you already know what a Financial Chain is conceptually. Here's what it looks like from a code perspective.
Every STO item that qualifies for 3-Level processing gets a Financial Chain ID assigned to it — stored in the custom field ZZFIN_CHAIN_ID. That ID tells you exactly which legal entities are involved, what the transit plant is, and what the delivering plant is. From that point on, every downstream document copies the ID from its predecessor. If it's missing anywhere in the chain, something went wrong.
Financial Chain Path
|
ENTITY |
ROLE |
PLANT |
|
Delivering Company |
Ships goods physically |
Delivering Plant |
|
Intermediate Company |
Legal / paper entity only — no physical goods |
Transit Plant |
|
Receiving Company |
Final stock destination |
Receiving Plant |
BAdI: Financial Chain Determination for STO Items
The actual determination of which Financial Chain applies to a given STO item happens via a BAdI in our case.
ZZFIN_CHAIN_ID Propagation Map
Once the Financial Chain ID is stamped on the STO item, it has to travel cleanly through every document that follows. We appended ZZFIN_CHAIN_ID to each relevant structure and set up implicit enhancements to copy it forward at each step transition. The rule is simple: wherever VCM creates a new document from a predecessor, the ID comes with it.
|
DOCUMENT |
STRUCTURE / TABLE |
MECHANISM |
|
Stock Transport Order |
EKPODATA, MEPOITEM_DATA |
Structure append; BAdI populates the field when the STO is saved |
|
ICo Sales Order Items |
VBAP (custom append) |
Implicit enhancement ZCL_IM_SD_ADD_FCID_IN_SO at end of IF_SD_SLS_IC_SOTOPO~SO_DATA_TO_PO_DATA |
|
ICo Purchase Order Items |
MMPUR_S_PO_IC_STO_CHG_ITEM — append ZAMMPUR_S_PO_IC_STO_CHG_ITEM |
Implicit enhancement ZCL_IM_MM_ADD_FCID_IN_PO in GENERATE_NEW_PO_ITEM_DATA; reads FC ID from VBAP via the predecessor SO item |
|
Outbound Delivery Items |
OD item structure |
Copied from STO item by the VCM step handler during OD creation |
|
Material Documents |
Material document item |
Each goods movement step handler copies from its predecessor step |
|
Supplier Invoice (MIRO) |
EK08RZ append ZAEK08RZ; RSEG append ZARSEG |
B2B interface enhancement; copied from the corresponding ICo PO item |
- Value Chain Step Configuration
The chain type ZIC_STOCKTRANSFER_3L is where the full process gets wired up. TCode – VCM_CHAIN_TYPE
|
STEP |
DESCRIPTION |
TYPE |
PREDECESSOR |
|
ZRC_STO |
Receiving Company — Stock Transport Order (Initiating) |
Initiating |
— |
|
ZRC_PO |
Receiving Company — IC Purchase Order (to IC) |
Synchronous |
ZRC_STO |
|
ZIC_SO |
Intermediate Company — IC Sales Order (from RC) |
Synchronous |
ZRC_PO |
|
ZIC_PO |
Intermediate Company — IC Purchase Order (to DC) |
Synchronous |
ZIC_SO |
|
ZDC_SO |
Delivering Company — IC Sales Order (from IC) |
Synchronous |
ZIC_PO |
|
ZDC_OD |
Delivering Company — Outbound Delivery |
External |
ZRC_STO (precond: ZDC_SO, ZIC_PO, ZIC_SO, ZRC_PO) |
|
ZDC_GT |
Delivering Company — Goods Transfer (Stor. Loc → SIT) |
External |
ZDC_OD |
|
ZDC_GI |
Delivering Company — Goods Issue from SIT |
Synchronous |
ZDC_GT |
|
ZIC_GR |
Intermediate Company — Goods Receipt in Transit Plant |
Synchronous |
ZDC_GI |
|
ZRC_ID |
Receiving Company — Inbound Delivery |
Synchronous |
ZDC_OD |
|
ZIC_GT |
Intermediate Company — Goods Transfer (Transit → SIT) |
Synchronous |
ZIC_GR |
|
ZIC_GI |
Intermediate Company — Goods Issue from SIT |
Synchronous |
ZIC_GT |
|
ZRC_GR |
Receiving Company — Goods Receipt in Transit Plant |
Synchronous |
ZIC_GI |
|
ZRC_GT |
Receiving Company — Goods Transfer (SIT → Storage Loc.) |
External |
ZRC_ID |
|
ZDC_CI |
Delivering Company — ICo Customer Invoice |
External |
ZDC_OD |
|
ZIC_CI |
Intermediate Company — ICo Customer Invoice |
External |
ZDC_OD |
|
ZIC_SI |
Intermediate Company — ICo Supplier Invoice |
External (B2B) |
ZIC_GR |
|
ZRC_SI |
Receiving Company — ICo Supplier Invoice |
External (B2B) |
ZRC_GR |
- VCM Step Handler Classes
The classes below were created new or enhanced for the individual VCM steps mentioned. For the remaining steps of the value chain, we used the standard classes of 2 level STO value chain steps.
|
ZCL_PO_IC_VCMS_INIT_STO Step Handler — ZRC_STO (Initiating Step) Handles the initiating STO step. Its main job is filtering: before VCM processes items downstream, this class checks that each STO item actually has confirmed quantities. Items without confirmed qty that are also new to the IC PO in the receiving company get filtered out — they're not ready yet. Key Methods ▸ IF_VCM_STEP_HANDLER~FILTER_OUTBOUND_ITEMS — main filter logic ▸ READ_PURCHASE_ORDER — reads STO data via CL_MM_PUR_PO_IC_FACTORY ▸ HAS_CONFIRMED_QUANTITY — checks for at least one schedule line with confirmed qty ▸ IS_ITEM_NEW — checks whether the item already has a corresponding IC PO item ▸ INITIALIZE_BUFFERS — clears instance buffers at the start of each run
|
|
ZCL_PO_IC_VCMS_STO2PO Step Handler — ZRC_PO (IC Purchase Order in Receiving Company) Orchestrates the creation of the ICo Purchase Order in the Receiving Company. It groups the inbound bundle items, delegates to the synchronizer class, and maps the results back to VCM as an outbound bundle. Think of it as the coordinator — the actual PO logic lives in the synchronizer and POM classes below. Key Methods ▸ IF_VCM_STEP_HANDLER~EXECUTE — called once per inbound bundle group; kicks off PO creation ▸ IF_VCM_STEP_HANDLER~GROUP_INBOUND_ITEMS — groups STO items into bundle groups before EXECUTE ▸ IF_VCM_STEP_HANDLER~GET_EXECUTABLE_ITEMS — propagates completed items to the next step ▸ GET_ITEMS_FOR_IC_PO — extracts STO item keys from the inbound bundle
|
|
ZCL_PO_IC_SYNC_STO2PO Singleton Synchronizer This is the singleton that actually manages the grouping of STO items into PO objects and drives the create/update logic. It keeps a buffer (G_TAB_POM_ORDERS) of PO objects across items so that multiple STO items that belong to the same IC PO get handled in one go. Key Methods ▸ GET_INSTANCE (static) — returns the singleton instance for the current LUW ▸ GROUP_INBOUND_ITEMS — creates ZCL_PO_IC_POM_ITEM objects and groups them into PO objects ▸ CREATE_PO_FROM_STO — fetches the PO object for a given bundle group and calls SYNCHRONIZE ▸ ADD_ITEM_TO_PO — adds an item to an existing or newly created ZCL_PO_IC_POM_ORDER object ▸ GET_EXISTING_IC_PO_FOR_STO — looks up existing IC POs for update scenarios ▸ PRELOAD_POM_ORDERS — pre-loads existing IC PO objects into the buffer for change handling
|
|
ZCL_PO_IC_POM_ORDER PO Object Model — Order Implements IF_MM_PUR_PO_IC_POM_ORDER. Represents a single ICo Purchase Order being built or updated. On create, it calls CREATE_PURCHASE_ORDER from the standard DAO CL_MM_PUR_PO_IC_DAO_BUILD_POH. On update, it uses GET_DATA_FOR_CHANGE and UPDATE_PURCHASE_ORDER from the same DAO. Supplier and goods supplier are determined by calling ZCL_ICSTO_HELPER. Key Methods ▸ IF_MM_PUR_PO_IC_POM_ORDER~SYNCHRONIZE — entry point; branches to create or update path ▸ IF_MM_PUR_PO_IC_POM_ORDER~SET_VCM_CHAIN_CATEGORY — sets ZIT3 on the PO object ▸ GENERATE_NEW_IC_PO_DATA — builds PO header and calls GENERATE_NEW_IC_PO_ITEM_DATA per item ▸ MERGE_NEW_AND_OLD_IC_PO_DATA — applies latest STO changes to an existing IC PO's builder data ▸ GET_PO_ITEM_NUMBER_INTERVAL — returns item number interval based on purchasing document type
|
|
ZCL_PO_IC_POM_ITEM PO Object Model — Item Implements IF_MM_PUR_PO_IC_POM_ITEM. One object per IC PO item being created. It reads the STO item data (via CL_MM_PUR_PO_IC_FACTORY), picks up the Financial Chain ID from the STO item, and builds the IC PO item payload. The split criteria it calculates — STO doc number + FC ID + Sales Org + Division + Distribution Channel — determines which items end up in the same IC PO. Key Methods ▸ SET_STO_REFERENCE — sets target operation and calls READ_STO_ITEM_DATA ▸ READ_STO_ITEM_DATA — fetches STO data via factory class; maps ZZFIN_CHAIN_ID ▸ DETERMINE_SPLIT_CRITERIA — calculates the grouping key for IC PO item assignment ▸ IF_MM_PUR_PO_IC_POM_ITEM~GET_ITEM_DATA_FOR_UPDATE — applies latest STO changes to existing IC PO item ▸ DETERMINE_PO_ITEM — finds the existing IC PO item number for an STO item in update scenarios ▸ MAP_ITEM_DATA_TO_PORDER_ITEM — maps STO item fields to IC PO builder structure ▸ MAP_SCHEDULE_TO_PORDER_ITEM — maps STO schedule line data to IC PO schedule lines
|
|
ZCL_ICSTO_HELPER Helper Class Central utility class for 3-Level STO operations. Determines supplier and goods supplier from the Financial Chain ID — this is where the lookup into the financial chain definition happens to find the correct business partner numbers. Also provides the CHECK_IS_VCM_CATEGORY_ZIT3 method that all the standard enhancements call to decide whether to apply 3-Level logic. Key Methods ▸ DETERMINE_SUPPLIER — derives supplier for IC PO from the Financial Chain definition ▸ DETERMINE_GOODS_SUPPLIER — derives goods supplier (always the physical delivering plant) from FC ▸ CHECK_IS_VCM_CATEGORY_ZIT3 — returns true if the PO item's VCM chain category is ZIT3 ▸ READ_BILLDOC — fetches customer invoice data and checks 3-Level sales / STO relevance ▸ ENHANCE_GR_INFORMATION — enriches invoice item data with GR details for B2B invoice linking ▸ PERFORM_3L_IC_CHECK_BEFORE_CRT — validates invoice data before creation in the B2B flow ▸ CHECK_CREDIT_MEMO_RELEVANCE — checks credit memo applicability for reversal documents ▸ PROCESS_INVC_AFTER_APPL — handles VCM integration after the invoice application interface
|
|
ZCL_MMIM_STEP_HANDLER_3L Material Document Step Handler Common handler for all the goods movement steps. Rather than writing a separate handler class for each goods movement step, we used one class with dedicated PREPARE_* methods per step. This class is shared with the 3-Level Advanced ICo Sales value chain too — the logic for preparing a GR document is the same regardless of whether the initiating document was a Sales Order or a Stock Transport Order. Key Methods ▸ PREPARE_IC_GI — prepares Goods Issue from Delivering Company SIT (ZDC_GI) ▸ PREPARE_IC_GR — prepares Goods Receipt in Intermediate Company Transit Plant (ZIC_GR) ▸ PREPARE_IC_GT — prepares Goods Transfer in Intermediate Company Transit Plant to SIT (ZIC_GT) ▸ PREPARE_RC_GR — prepares Goods Receipt in Receiving Company Transit Plant (ZRC_GR)
|
- SAP Standard Enhancements
Class Enhancements on Standard VCM Classes
|
STANDARD CLASS |
ENHANCEMENT |
WHAT IT DOES |
|
CL_MM_PUR_PO_IC_VCMI_STO |
Class enh. ZCL_PO_IC_VCMI_STO |
Groups STO items by FC ID and creates a separate VCM instance per Financial Chain. This is what makes one STO → multiple VCM chains possible. |
|
CL_MM_PUR_PO_IC_VCMI_OUT |
Class enh. ZCL_PO_IC_VCMI_OUT |
Holds 3-Level-specific VCM process data across create/update/delete operations. Buffers are cleared via a pre-exit on INITIALIZE. |
|
CL_MM_PUR_PO_IC_VCMI_ADAPTER |
Spots ZSP_START_VALUE_CHAIN, ZSP_CREATE_VALUE_CHAIN |
Fetches VCM instance GUID after chain creation and persists it to Z_VCMCHAIN_INS. Also supplies the correct GUID for delta items during change operations. |
|
CL_MM_PUR_PO_IC_VCMI_STO |
Methods: TRIGGER_VCM_PROCESS_FROM_BADI, GET_ITEMS_FOR_VCM_UPDATE, ADD_UPDATE_ITEM_IF_RELEVANT, GET_ITEMS_FOR_VCM_DELETE |
Extended to handle create/update/delete flows for 3-Level; items are tagged with the appropriate operation (CREATE / UPDATE / DELETE) for downstream VCM processing. |
|
CL_LE_SHP_ICO_VCM_STEP_IDRC |
Impl. ZCL_LE_SHP_ICO_VCM_STEP_IDRC, ZCL_LE_SHP_RETRY_VCM_CHAINS |
Maps VCM data for the inbound delivery creation step; handles retry of related VCM chains when the inbound delivery is processed for 3-Level STO. |
|
CL_MM_PUR_PO_IC_VCMI_FACTORY |
Enh. ZCL_MM_PUR_PO_IC_VCMI_FACTOR on CREATE_VCMI_FILTER |
Sets the correct delivery class instance for the 3-Level STO scenario. |
|
CL_SDBIL_VCM_HANDLER |
Enh. ZSP_3L_SDBIL_VCM_HANDLER on IF_SDBIL_VCM_HANDLER~CHECK_CANCELLATION |
Ensures the step type is determined correctly during intercompany invoice cancellation. |
|
CL_MMIV_IC_BADI_VCM_APP_CANCEL |
Enh. ZSP_IS_CANCELLABLE on IS_CANCELLABLE |
Returns true when the step type is ZIC_SI, ZSC_SI, or ZRC_SI — enabling cancellation of 3-Level supplier invoice steps. |
Include and Function Module Enhancements
|
OBJECT |
ENHANCEMENT SPOT / IMPL. |
WHAT IT DOES |
|
Include LEINRF2I |
ZSP_LEINRF2I |
Sets VCM chain category to ZIT3 on outbound delivery GI posting |
|
Include LV50SF10 |
ZSP_3L_STO_UPDATE_VCM_CAT |
Sets correct VCM step types based on chain category during delivery processing |
|
Include LEINRF2C |
ZSP_LEINRF2C |
Populates Financial Chain ID during PGR confirmation search |
|
Include LEINRF2A |
ZSP_LEINRF2A |
Fetches the correct document during PGR for 3-Level STO |
|
Include MM07MFB7_BESTELLUNG_WA_PRUEFEN |
ZSP_BESTELLUNG_WA_PRUFEN_03 |
Skips a standard error message during GI for STO when the chain category is ZIT3 |
|
Include MM07MFB7_BESTELLUNG_PRUEFEN |
ZSP_BESTELLUNG_PRUEFEN |
Skips error M7-E011 if the VCM chain category is ZIT3; checked via ZCL_ICSTO_HELPER~CHECK_IS_VCM_CATEGORY_ZIT3 |
|
Include MM07MFB7_BESTELLUNG_UEBERNEH02 |
ZSP_BESTELLUNG_UEBERNEH02 |
Clears the receipt indicator (kzzug) for movement type 107 when category is ZIT3 — needed for GR in the inbound delivery to post correctly |
|
FM MEX_PSTYP_KNTTP |
ZSP_MEX_PSTYP_KNTTP |
Skips the account assignment error for 3-Level STO items — the account assignment category combination is different for this process and would otherwise cause a false error |
|
FM ME_CONFIRMATION_SEARCH_GR |
ZSP_ME_CONFIRMATION_SEARCH_G |
Populates Financial Chain ID during GR confirmation search for supplier invoice confirmation |
COMING UP IN PART 3
The second technical post covers the runtime side of the process: how the Goods Movement steps are executed and timed using Transfer of Control Dates, why we switched to B2B interfaces for Supplier Invoice instead of letting VCM trigger it, how the change and delete scenarios work at the code level.



