Plan-to-Produce (P2Pr) automated data generator that creates end-to-end production documents via JCo RFC: production order, release, and confirmation with automatic backflush (goods issue + goods receipt). Generates realistic SAP PP transaction data on S/4HANA IDES using the bike finished goods family (MZ-FG-*).
Everything runs from the local Mac — no need to SSH into sapidess4 or sapidesecc8.
Client 100 is used for all operations.
Connects directly over the network using JCo 3. No SSH tunnel needed.
| Parameter | Value |
|---|---|
| Host | sapidess4.fivetran-internal-sales.com |
| System Number | 03 (port 3303) |
| Client | 100 |
| User | IDES |
| Password | (see vault) |
| Language | EN |
Required local files (in ../SAPjco/):
sapjco3.jar — Java JCo librarylibsapjco3.dylib — macOS ARM64 native libraryjava -Xmx512m -cp .:../SAPjco/sapjco3.jar \ -Djava.library.path=../SAPjco SAPP2PrWorkflow full 1
Connect via SSH tunnel for direct SQL. Only the tunnel uses SSH — you never log into the server.
| Parameter | Value |
|---|---|
| Tunnel | localhost:30015 → sapidess4:30015 |
| Database | FIV (S/4HANA tenant) |
| User | SAPHANADB |
| Password | (see vault) |
| Python lib | pip3 install hdbcli |
# Start SSH tunnel (one-time, runs in background)
ssh -f -N -L 30015:127.0.0.1:30015 root@sapidess4
# Query via Python
python3 -c "
from hdbcli import dbapi
conn = dbapi.connect(address='localhost', port=30015,
user='SAPHANADB', password='(see vault)', databaseName='FIV')
cur = conn.cursor()
cur.execute(\"SELECT AUFNR, OBJNR FROM AUFK WHERE AUART='YBM1'\")
for row in cur.fetchall(): print(row)
"
All finished goods below are FERT materials with BOM + Routing in plant 1710, BESKZ='E' (in-house production), standard price (VPRSV=S).
| Material | Description | Std Price (USD) | Components |
|---|---|---|---|
MZ-FG-C900 | C900 BIKE | 312.88 | 7 ROH |
MZ-FG-C950 | C950 BIKE | 513.02 | 7 ROH |
MZ-FG-C990 | C990 Bike | 810.00 | 7 ROH |
MZ-FG-M500 | M500 BIKE | 668.16 | 7 ROH |
MZ-FG-M525 | M525 BIKE | 1,119.01 | 7 ROH |
MZ-FG-M550 | M550 BIKE | 2,842.02 | 7 ROH |
MZ-FG-R100 | R100 BIKE | 457.63 | 7 ROH |
MZ-FG-R200 | R200 Bike | 3,100.22 | 7 ROH |
MZ-FG-R300 | R300 Bike | 5,873.88 | 7 ROH |
Each bike has 7 ROH components following the naming pattern MZ-RM-{model}-01 through
MZ-RM-{model}-07. 9 models × 7 components = 63 raw materials total.
| # | Part | Example (C900) | UoM | Stock Qty |
|---|---|---|---|---|
| 01 | Frame | MZ-RM-C900-01 | ST | 10,000 |
| 02 | Handle Bars | MZ-RM-C900-02 | ST | 10,000 |
| 03 | Seat | MZ-RM-C900-03 | ST | 10,000 |
| 04 | Wheels | MZ-RM-C900-04 | ST | 20,000 |
| 05 | Forks | MZ-RM-C900-05 | ST | 10,000 |
| 06 | Brakes | MZ-RM-C900-06 | ST | 10,000 |
| 07 | Drive Train | MZ-RM-C900-07 | ST | 10,000 |
step0-stock (movement type 501, GR without PO) before creating production
orders, or Goods Issue (Step 3) will fail with M7/021 insufficient stock.
BOM base quantity = 100,000; component quantity = 100,000 → 1:1 ratio per unit produced.
BOM type: STLTY='M' (material BOM).
| Table | Description | Key Fields |
|---|---|---|
MAST | Material-to-BOM link | MATNR, WERKS, STLAN, STLNR |
STKO | BOM header | STLNR, STLAL, STLTY='M', BMENG (base qty) |
STPO | BOM items (components) | STLNR, STLKN, IDNRK (component material), MENGE |
Each bike has a 2-operation routing:
| Operation | Work Center | Description |
|---|---|---|
0010 | Z_ASM1 / Z_ASM2 / Z_ASM3 | Assembly |
0020 | Z_INSP1 / Z_INSP2 / Z_INSP3 | Inspection |
| Table | Description | Key Fields |
|---|---|---|
MAPL | Material-to-routing assignment | MATNR, WERKS, PLNNR, PLNAL |
PLPO | Routing operations | PLNNR, PLNKN, VORNR, ARBID |
CRHD | Work center header | OBJID, ARBPL, WERKS |
-- Check BOM structure for all bikes
SELECT m.MATNR, k.STLNR, k.STLAL, k.BMENG, p.IDNRK, p.MENGE
FROM MAST m
JOIN STKO k ON m.STLNR = k.STLNR AND k.STLTY = 'M'
JOIN STPO p ON k.STLNR = p.STLNR
WHERE m.MATNR LIKE 'MZ-FG%' AND m.WERKS = '1710'
ORDER BY m.MATNR, p.STLKN;
CO03 to display order details and document flow.
RGEKZ=1 (Always Backflush) in MARC.
During final confirmation, SAP automatically issues components (261) and receives the finished good (101).
Manual GI (Step 3) and manual GR (Step 5) are not needed in the automated pipeline.
Posts initial stock for all 63 raw materials using movement type 501 (GR without PO).
Uses GM_CODE = 05 (Other goods receipts). Checks current MARD stock and only posts the delta.
This is a one-time setup step.
| Function Module | Purpose |
|---|---|
BAPI_GOODSMVT_CREATE | Post goods movement (mvt 501, GM_CODE 05) |
RFC_READ_TABLE | Check current stock in MARD |
BAPI_TRANSACTION_COMMIT | Persist changes (WAIT='X') |
| Structure | Field | Value |
|---|---|---|
GOODSMVT_HEADER | PSTNG_DATE | Today |
| DOC_DATE | Today | |
GOODSMVT_CODE | GM_CODE | 05 (Other goods receipts) |
GOODSMVT_ITEM | MATERIAL | e.g. MZ-RM-C900-01 |
| PLANT | 1710 | |
| STGE_LOC | 171A | |
| MOVE_TYPE | 501 | |
| ENTRY_QNT | 10,000 (or 20,000 for Wheels) | |
| ENTRY_UOM | ST |
| Table | Description | Impact |
|---|---|---|
MATDOC | Material Document | 1 document per material |
MARD | Storage Location Stock | LABST increased |
MBEW | Material Valuation | LBKUM (total stock qty) updated |
Creates a production order for a randomly selected bike finished good with order type
YBM1 (standard discrete manufacturing). SAP automatically explodes the BOM
and creates component reservations in RESB, and copies the routing to order operations (AFVC).
| Tcode | Purpose |
|---|---|
CO01 | Create Production Order |
CO02 | Change Production Order |
CO03 | Display Production Order |
| Function Module | Purpose |
|---|---|
BAPI_PRODORD_CREATE | Create production order with material, qty, dates |
BAPI_TRANSACTION_COMMIT | Persist changes (WAIT='X') |
| Field | Value | Notes |
|---|---|---|
MATERIAL | e.g. MZ-FG-C900 | Random bike from pool of 9 |
PLANT | 1710 | |
ORDER_TYPE | YBM1 | Standard discrete manufacturing |
QUANTITY | 5–20 (random) or --qty N | |
BASIC_START_DATE | Today | |
BASIC_END_DATE | Today + 5 days |
ORDER_NUMBER (12-digit, zero-padded).
RETURN is an export structure (not a table) —
use getExportParameterList().getStructure("RETURN").
| Table | Description | Key Fields Written |
|---|---|---|
AUFK | Order Master (header) | AUFNR, AUART='YBM1', AUTYP, OBJNR |
AFKO | Order Header Data (PP) | AUFNR, PLNBEZ (material), GAMNG (qty), AUFPL, GMEIN |
AFPO | Order Item | AUFNR, POSNR, MATNR, PSMNG (planned qty), MEINS |
AFVC | Order Operations | AUFPL, APLZL, VORNR (0010/0020), ARBID |
RESB | Reservations (component requirements) | RSNUM, RSPOS, AUFNR, MATNR, BDMNG (required qty) |
-- Production order details
SELECT a.AUFNR, a.PLNBEZ, a.GAMNG, a.GMEIN, a.IGMNG
FROM AFKO a WHERE a.AUFNR = '000001XXXXXX';
-- Component reservations
SELECT RSNUM, RSPOS, MATNR, BDMNG, ENMNG, MEINS
FROM RESB WHERE AUFNR = '000001XXXXXX';
Changes order status from CRTD (Created) to REL (Released), enabling goods movements. A released order can have components issued and finished goods received.
| Tcode | Purpose |
|---|---|
CO02 (Release button) | Release individual order |
COHV | Mass processing (release multiple orders) |
| Function Module | Purpose |
|---|---|
BAPI_PRODORD_RELEASE | Release one or more production orders |
BAPI_TRANSACTION_COMMIT | Persist changes (WAIT='X') |
| Parameter | Type | Notes |
|---|---|---|
ORDERS table | Table | ORDER_NUMBER field (12-digit) |
RETURN | Export structure | Use getExportParameterList().getStructure("RETURN") |
DETAIL_RETURN | Table | Detailed messages per order |
| Table | Description | Impact |
|---|---|---|
AUFK | Order Master | Status object (OBJNR) updated |
JEST | Individual Object Status | STAT='I0002' (REL) activated, STAT='I0001' (CRTD) deactivated |
Reports yield (completed quantity) per operation using time ticket confirmation.
Reads AFKO for order qty, AFVC for operations, then posts confirmations with
final confirmation (FIN_CONF='X') on the last operation. Because all raw materials have
RGEKZ=1 (Always Backflush), the confirmation automatically posts GI (261) and GR (101).
| Tcode | Purpose |
|---|---|
CO11N | Enter Confirmation (Time Ticket) |
CO14 | Display Confirmation |
CO13 | Cancel Confirmation |
| Function Module | Purpose |
|---|---|
RFC_READ_TABLE | Read AFKO for order quantity (GAMNG, GMEIN, PLNBEZ) |
RFC_READ_TABLE | Read AFVC for operations (VORNR list) |
BAPI_PRODORDCONF_CREATE_TT | Post time ticket confirmation (per operation) |
BAPI_TRANSACTION_COMMIT | Persist changes (WAIT='X') |
| Field | Value | Notes |
|---|---|---|
ORDERID | Production order number | 12-digit |
OPERATION | Operation number (from AFVC) | e.g., 0010, 0020 |
POSTG_DATE | Today | |
YIELD | Order quantity (from AFKO.GAMNG) | |
CONF_ACTI_UNIT1 | H | Activity unit (hours) |
CONF_ACTIVITY1 | 1.0 (or 0.5 for last op) | Explicit activity qty — bypasses cost rate lookup |
EXEC_START_DATE | Today | |
EXEC_FIN_DATE | Today | |
FIN_CONF | X (last op only) | Final confirmation — triggers backflush GI+GR |
CLEAR_RES | X (last op only) | Clear remaining open reservations |
BAPI_PRODORDCONF_CREATE_HDR)
triggers cost rate lookup via CSSL/COST tables, which requires activity rates for the current fiscal year.
The time ticket BAPI (BAPI_PRODORDCONF_CREATE_TT) accepts explicit activity quantities per operation,
bypassing the cost rate lookup entirely. This avoids RU/085 errors.
When the final confirmation is posted, SAP automatically performs:
| Auto-Posting | Mvt Type | GM_CODE | Effect |
|---|---|---|---|
| Goods Issue (components) | 261 | 03 | Raw material stock decreased, 1 MATDOC item per component |
| Goods Receipt (finished good) | 101 | 02 | Finished good stock increased, MBEW updated |
| Table | Description | Impact |
|---|---|---|
AFRU | Order Confirmations | One row per operation: AUFNR, VORNR, LMNGA (yield), BUDAT |
MATDOC | Material Document (GI) | BWART='261', 1 item per component (auto backflush) |
MATDOC | Material Document (GR) | BWART='101', finished good receipt (auto backflush) |
MARD | Storage Location Stock | LABST decreased (components) and increased (finished good) |
MBEW | Material Valuation | LBKUM, SALK3 updated for finished good |
RESB | Reservations | ENMNG (withdrawn qty) updated by backflush |
ACDOCA | Universal Journal | GI: consumption debit (GBB) + stock credit (BSX). GR: stock debit (BSX) + production variance (PRD) |
JEST | Object Status | DLV (Delivered) + CNF (Confirmed) activated |
-- Confirmations for order
SELECT AUFNR, VORNR, LMNGA, GMNGA, BUDAT, ERSDA
FROM AFRU WHERE AUFNR = '000001XXXXXX';
-- Material documents (GI 261 + GR 101) created by backflush
SELECT MBLNR, BWART, MATNR, MENGE, MEINS, AUFNR
FROM MATDOC WHERE AUFNR = '000001XXXXXX';
| Table | Description | Category | Populated By |
|---|---|---|---|
AUFK | Order Master (header) | Order Header | Step 1 |
AFKO | Order Header Data (PP specific) | Order Master | Step 1 |
AFPO | Order Item | Order Items | Step 1 |
AFVC | Order Operations | Operations | Step 1 |
RESB | Reservation / Dependent Requirements | Reservations | Step 1, updated Step 3 (backflush) |
AFRU | Order Confirmations | Confirmations | Step 3 |
JEST | Individual Object Status | Status | Steps 1, 2, 3 |
| Table | Description | Category |
|---|---|---|
MAST | Material BOM Link | BOM Assignment |
STKO | BOM Header | BOM Header |
STPO | BOM Items (Components) | BOM Items |
MAPL | Material-to-Routing Assignment | Routing Assignment |
PLPO | Routing Operations | Routing Ops |
CRHD | Work Center Header | Work Centers |
| Table | Description | Category | Populated By |
|---|---|---|---|
MATDOC | Material Document (S/4HANA unified) | Mat. Document | Steps 0, 3 (backflush GI 261 + GR 101) |
MARD | Storage Location Stock | Stock Levels | Steps 0, 3 (updated by backflush) |
MBEW | Material Valuation | Valuation | Steps 0, 3 (updated by backflush GR) |
| Table | Description | Category | Populated By |
|---|---|---|---|
ACDOCA | Universal Journal Entry (S/4HANA) | Universal Journal | Step 3 (backflush GI + GR) |
BKPF | Accounting Document Header | FI Doc Header | Step 3 (backflush GI + GR) |
| Table | Description | Category |
|---|---|---|
MARA | Material General Data | General |
MARC | Material Plant Data (MRP, Production) | Plant |
MARD | Storage Location Stock | Stock |
MAKT | Material Descriptions | Texts |
MBEW | Material Valuation | Valuation |
| Table | Description | Purpose |
|---|---|---|
T001 | Company Codes | Company code 1710 |
T001K | Valuation Area | Plant-to-company code assignment |
T001W | Plants | Plant definitions |
T003O | Order Types | YBM1, PP01, PP02 |
T030 | Account Determination (OBYC) | BSX, GBB, PRD transaction keys |
MARV | MM Posting Period | Current posting period (LFMON/LFGJA) |
CKMLHD | ML Material Header | Material Ledger header per material |
CKMLPP | ML Period Records | Period status (continuous, no gaps) |
CKMLCR | ML Currency Records | CURTP 10+30 per period |
| Mvt Type | GM_CODE | Description | Step |
|---|---|---|---|
501 | 05 | GR without PO (initial stock posting) | Step 0 |
261 | 03 | GI for production order (components) | Step 3 (auto backflush) |
101 | 02 | GR for production order (finished good) | Step 3 (auto backflush) |
262 | 04 | Return of GI 261 (reversal) | — |
102 | 06 | GR reversal | — |
| Type | Description | Notes |
|---|---|---|
YBM1 | Standard discrete manufacturing | Used by automation (bike family) |
YBM3 | Configurable production | Not used |
PP01 | Standard SAP production | SAP default |
PP02 | Standard SAP process | Process manufacturing |
| Area | ECC Tables | S/4HANA Table | Notes |
|---|---|---|---|
| Material Documents | MKPF + MSEG | MATDOC | Single unified table |
| Accounting | BSEG + FAGLFLEXA + COEP | ACDOCA | Universal Journal |
| Stock | MCHB, MSKA, MSSL | MARD + MATDOC | Consolidated |
| Material Ledger | Optional | Always active | ML infrastructure mandatory in S/4 |
| CDS View | Description | Base Tables |
|---|---|---|
I_ProductionOrder | Production order header | AUFK, AFKO |
I_ProductionOrderItem | Production order items | AFPO |
I_ProductionOrderOperation | Order operations | AFVC |
I_ProductionOrderComponent | Order components (reservations) | RESB |
I_MfgOrderConfirmation | Order confirmations | AFRU |
| CDS View | Description | Base Tables |
|---|---|---|
I_MaterialDocumentHeader_2 | Material document header | MATDOC |
I_MaterialDocumentItem_2 | Material document items | MATDOC |
| CDS View | Description | Base Tables |
|---|---|---|
I_Product | Product (material) master | MARA, MAKT |
I_ProductPlantBasic | Plant-level data | MARC |
I_ProductValuation | Valuation data | MBEW |
I_BillOfMaterial | BOM header | STKO |
I_BillOfMaterialItem | BOM items | STPO |
| App ID | Name | Step |
|---|---|---|
| F2430 | Manage Production Orders | Order |
| F3703 | Release Production Orders | Release |
| F3422 | Confirm Production Order | Confirmation |
| F0843 | Post GR for PO | GR |
| F2432 | Order Progress Overview | Analytics |
Generate N production cycles, stopping at any stage:
# First time: post raw material stock
./p2prwf.sh step0-stock --verbose
# Then generate production cycles
./p2prgen.sh 1 # 1 full cycle (Order→Release→Confirm)
./p2prgen.sh 10 order # 10 production orders only
./p2prgen.sh 100 release # 100x Order→Release
./p2prgen.sh 100 confirm # 100x full pipeline (auto GI+GR)
./p2prgen.sh 10 confirm --qty 10 --verbose
./p2prwf.sh step0-stock --verbose # Post raw material stock
./p2prwf.sh step1-order 5 --verbose # Create 5 production orders
./p2prwf.sh step2-release <orderNumber> # Release order
./p2prwf.sh step4-confirm <orderNumber> # Confirm (auto GI+GR via backflush)
./p2prwf.sh status <orderNumber> # Show order details
| Stage | Pipeline | SAP Tables Created |
|---|---|---|
order | Create order | AUFK, AFKO, AFPO, AFVC, RESB |
release | Order → Release | + JEST (status) |
confirm | Order → Release → Confirm (auto GI+GR) | + AFRU, MATDOC (261+101), ACDOCA |
| Flag | Description |
|---|---|
--verbose | Print BAPI details and all return messages |
--dry-run | Validate only (no BAPI_TRANSACTION_COMMIT) |
--stop-at STAGE | Stop after stage: order, release, confirm (default: confirm) |
--pause N | Seconds between steps (default: 3) |
--qty N | Fixed production quantity per order (default: random 5-20) |
.
┌── SAPP2PrWorkflow.java # Main automation program
┌── p2prgen.sh # Bulk data generator script
┌── p2prwf.sh # Workflow wrapper script
┌── compile.sh # Compilation helper
┌── docs/
│ └── SAP_PP_Workflow_Documentation.html # This document
└── skill/
└── plan-to-produce.md # Claude Code skill file
| Error | Cause | Fix |
|---|---|---|
C+/065 ML header missing |
Material Ledger header (CKMLHD) not found | Insert CKMLHD for MANDT='100' with KALN1 from client 100 MBEW |
C+/073 ML period missing |
Material Ledger periods have gaps | Insert continuous CKMLPP+CKMLCR (CURTP 10+30) for all months, no gaps |
M7/021 Insufficient stock |
Component raw materials have no stock | Run step0-stock first to post 10,000 units per material |
M3/351 Material not maintained |
Material does not exist in plant 1710 | Verify material exists in MARC for plant 1710. Remove from material list if not present. |
RU/085 Error in determining actual costs |
CSSL/COST activity rate tables missing for current fiscal year | Use BAPI_PRODORDCONF_CREATE_TT with explicit CONF_ACTIVITY1 to bypass cost rate lookup |
M7/509 No movements for reservation |
Backflush materials (RGEKZ=1) have XWAOK='X' — reservation-based GI not possible | Do NOT post manual GI. Backflush handles GI automatically during confirmation. |
M7/022 Order quantity exceeded |
Manual GR attempted after backflush already posted GR | Do NOT post manual GR. Backflush handles GR automatically during confirmation. |
| No reservations found | BOM not exploded or order doesn't exist | Verify order in AFKO. Check BOM exists in MAST for plant 1710. |
| Order stuck in CRTD | Release (Step 2) not performed or failed | Run step2-release with --verbose to see DETAIL_RETURN |
| Confirmation rejected | Order not released, or already finally confirmed | Check status with status command. FIN_CONF=X means final. |
SAP S/4HANA requires continuous CKMLPP period records with no gaps for any goods movement. The same Material Ledger issues documented in the P2P workflow apply here.
| Table | Requirements |
|---|---|
CKMLHD | One row per material. KALN1 from MBEW. MANDT='100'. |
CKMLPP | One row per month. STATUS='10' (closed) or '01' (open). No gaps from material creation to current period. |
CKMLCR | Two rows per period: CURTP 10 (company code currency) and CURTP 30 (group currency). |
-- Check ML headers for bike materials
SELECT MATNR, BWKEY, KALN1 FROM MBEW
WHERE MATNR LIKE 'MZ-RM%' AND BWKEY = '1710';
-- Check ML periods (should be continuous)
SELECT KALNR, BDATJ, PESSION, STATUS FROM CKMLPP
WHERE KALNR IN (SELECT KALN1 FROM MBEW WHERE MATNR LIKE 'MZ-RM%' AND BWKEY = '1710')
ORDER BY KALNR, BDATJ, PESSION;
| BAPI | Gotcha | Correct Approach |
|---|---|---|
BAPI_PRODORD_CREATE |
RETURN is export structure, not table. No table parameters at all. | getExportParameterList().getStructure("RETURN") |
BAPI_PRODORD_CREATE |
Date fields are BASIC_START_DATE / BASIC_END_DATE | Not BASIC_START / BASIC_END |
BAPI_PRODORD_RELEASE |
RETURN is export structure. DETAIL_RETURN is table. | Check both for errors |
BAPI_PRODORDCONF_CREATE_TT |
Confirmation table is TIMETICKETS, one row per operation | getTableParameterList().getTable("TIMETICKETS") |
BAPI_PRODORDCONF_CREATE_TT |
Must set CONF_ACTIVITY1 + CONF_ACTI_UNIT1 to bypass cost rate lookup (RU/085) | Set FIN_CONF='X' and CLEAR_RES='X' only on the last operation |
BAPI_GOODSMVT_CREATE |
GOODSMVT_CODE is a structure, not a string | getStructure("GOODSMVT_CODE").setValue("GM_CODE","03") |
| Test | Result | Details |
|---|---|---|
| Post stock for 61 raw materials | PASS | MatDocs 4900007748–4900007808, 10,000–20,000 EA per material |
| Step | Result | Details |
|---|---|---|
| Order | PASS | Order 1002162 (MZ-FG-C950 × 17) |
| Release | PASS | Status CRTD → REL |
| Confirm (auto GI+GR) | PASS | 2 ops confirmed. MatDoc 4900007817 (GR 101) + 4900007818 (GI 261) |
| Metric | Value |
|---|---|
| Orders created | 1002163, 1002164, 1002165 |
| Total completed | 3 / 3 |
| Failures | 0 |
BAPI_PRODORDCONF_CREATE_TT (time ticket) with explicit activity quantities.