Syncing Real-Time Inventory from ERP to Retail Frontend: A Single-Strategy Deep Dive
What This Strategy Solves
The retail frontend needs to reflect real-time inventory to store associates and members, while the authoritative ledger lives in the ERP. In one real engagement, the question we kept hearing was: "Is every 10 minutes frequent enough? What happens during peak outbound hours?" This strategy pulls instant inventory from the ERP at the SKU + warehouse granularity and pushes it to the retail frontend's item master, keeping the "on-hand quantity" shown on the frontend aligned with the ERP ledger within minutes.
Data Flow and Field Mapping
The source is an ERP of the Kingdee Cloud type; the target is a retail frontend platform of the Baison ME3 type. The flow is ERP → Retail Frontend.
The source calls executeBillQuery to retrieve instant inventory. The core returned fields are: FID, FStockId (warehouse ID), FMaterialId (material ID), FBaseQty (on-hand quantity), and FBaseAVBQty (available quantity). The intermediate layer does two things: first, warehouse code mapping — translating ERP FStockId into the retail frontend's warehouse code; second, assembling multiple records into the array-shaped kc_data, where each element carries the item code and quantity.
The target writes via stock.synckc. The field correspondence is:
| Source ERP Field | Intermediate Layer | Target Frontend Field | Note |
|---|---|---|---|
| FStockId | Warehouse code mapping | ckdm | Warehouse code |
| FMaterialId.FNumber | Item code mapping | kc_data[].id | Unique item identifier |
| FBaseQty | Pass-through | kc_data[].kcsl | On-hand quantity |
| Constant | Fixed value | sync_type=0 | 0 = on-hand, 1 = available |
Note the semantics of sync_type: a single call updates only one kind of inventory. On-hand and available are two independent chains.
How to Configure on Qeasy
We use the Qeasy Data Integration Platform to host this strategy. The typical configuration points are:
- Source component: pick the RESTful query node, method POST, API
executeBillQuery, and enable "auto-fill response" (autoFillResponse=true) to skip writing response parsing by hand. - Field mapping: build two helper tables in the mapping canvas — warehouse code mapping and item code mapping. The item code is the core primary key, maintained centrally in Qeasy's mapping center so it can be reused by other strategies, rather than re-defined per strategy.
- Target component: pick the GET execution node, API
stock.synckc, and setkc_dataas an array of items passed from the source batch. - Payload assembly: in Qeasy's script block, reshape the flat source data into a nested array. This is where most implementation engineers get stuck — the safe approach is to run a single record end-to-end in the debug panel first, then unlock the batch.
- Scheduling: configure two schedules for source pull and target push, offset in time so that read and write never collide at the same instant.
Implementation Steps
We typically roll out in three phases:
Phase 1 — Incremental Starting Point (Go-Live Night). Take a static snapshot of inventory in the ERP and push it once to the retail frontend as the "zero position." Manual sampling is mandatory: pick 10 random SKUs and reconcile across both sides. If any difference exceeds 1 unit, stop and investigate.
Phase 2 — Full Trigger (First Reconciliation Round). Within the next 1–2 days, run a full overwrite that refreshes every material + warehouse combination. The purpose of the full trigger is not to replace the incremental flow, but to backfill records that the incremental starting point missed, that are in an abnormal state, or that were just created.
Phase 3 — Steady-State Scheduling (10-Minute Increments). Source cron is */10 8-22 * * *, pulling every 10 minutes during business hours. Target cron is 3-59/10 8-22 * * *, offset by 3 minutes from the source to leave room for parsing and mapping. The job stops outside business hours, reducing wasted calls.
The 10-minute boundary is an empirical value that works for most retail scenarios. If peak outbound hours clearly cluster at certain clock times, you can temporarily densify the window and revert later.
Pitfalls Revisited
- One warehouse code maps to multiple IDs, pushing to the wrong warehouse. In one retail engagement, the same warehouse code in the ERP existed under multiple organizations. Without mapping,
FStockIdwas passed through and the frontend ended up showing "Warehouse A's inventory under Warehouse B." The safe approach is to enumerate "ERP warehouse ID → frontend warehouse code" explicitly in the mapping center; never let the frontend useFStockIddirectly as the key. - Item code drift. The ERP's
FMaterialId.FNumberis stable, but item listing/delisting/disabling can invalidateFMaterialId. Never useFIDas the key — the frontend only recognizesFNumber. - Misuse of
sync_type. Pushing available quantity as on-hand (or vice versa) inflates the "still buyable" number on the frontend and causes member orders to fail. Keep the two chains strictly separate; do not merge them. - Schedules colliding at the same tick. When both source pull and target push were set to
*/10, both fired at the exact top of the window and the target occasionally timed out. A 3-minute offset is a cheap and effective safety net. - Rate-limited by the retail frontend with no batching. When a batch of items is too large, Baison ME3-style endpoints trigger rate limiting. We hit this in one engagement. The safe approach is to submit in batches of roughly 200 items; refer to the target's documentation for the exact threshold.
When to Use and When Not to
Use when: store associate tools, member mini-programs, and flagship e-commerce sites need "minute-level" on-hand inventory, the source ledger is in the ERP, and the SKU count stays within 100k. Do not use when: second-level inventory, cross-organization consolidated inventory, or scenarios that require merging on-hand and available quantities are needed — the latter should be split into two strategies with a secondary processing node in between.