Consignment Transfer Outbound to Sales Order: A Single-Strategy Sync Tutorial
What this strategy solves
In a private-deployment scenario for a manufacturing enterprise, consignment warehouse transfer-out documents must generate corresponding sales orders in the downstream ERP (here, Kingdee Cloud). It looks like a simple "align two documents" task, but anyone who has run it knows the trap: consignment outbound documents carry many fields, use a special document type, and must carry batch/serial numbers. Miss one and the downstream team ends up doing manual rework. In Qeasy, we collapse this into a single strategy—pull the source consignment transfer-out documents by an incremental window, run them through field transformation and master-data mapping, then write them into the target sales-order endpoint. Below we break the strategy down piece by piece.
Data flow and field mapping
Overall flow: Consignment Transfer-Out (source) → Qeasy middleware (mapping/transform/validate) → Sales Order (target).
The source calls erp.storage.goodsdocout.v2 (WebAPI, POST, QUERY semantics), paginated by pageIndex / pageSize = 50, scoped by an incremental startDate / endDate window (from {{LAST_SYNC_TIME}} to {{CURRENT_TIME}}), with the document number field being goodsdocNo and idCheck enabled.
The target calls batchSave (WebAPI, POST, EXECUTE semantics) and writes into the sales-order model. Key fields:
| Business meaning | Source field | Target field | Note |
|---|---|---|---|
| Sales organization | Source warehouse/org context | FSaleOrgId | Derived from toWarehouseCode |
| Document date | Outbound date | FDate | inOutDate |
| Customer | Ship-to/receive-from customer | FCustId | Derived from toWarehouseCode; requires customer master-data mapping |
| Document type | Doc-type code | FBillTypeID | Fixed value XSDD02_SYS (sales order) |
| Source warehouse | Source warehouse code | FPRESETBASE1 | warehouseCode |
| Target warehouse | Target warehouse code | FPRESETBASE2 | Requires warehouse mapping table |
| Document number | goodsdocNo | FBillNo | idCheck enabled — critical for idempotency |
How to configure in Qeasy
For the source resource we use the "Query WebAPI" template, binding startDate / endDate to the built-in time macros — never hard-code them. Enable the incremental cursor: persist LAST_SYNC_TIME to Qeasy's cursor table so each run resumes from the last successful checkpoint.
For the target use the "Execute WebAPI" template and map the request into the batchSave payload. We strongly recommend centralized code mapping: warehouse, customer, item, and material mappings live in a single Qeasy mapping table maintained as source-raw → intermediate → target-code. Process header and body in phases — write the header first, confirm the document number is echoed back, then push the body, so half-written documents never pollute the downstream system.
Keep idCheck=true. The source goodsdocNo is sent over and the target uses FBillNo for idempotency check, automatically skipping duplicates so the whole batch is replayable.
Implementation steps
We suggest three steps, each with a clear artifact.
Step 1: Align the incremental starting point. Manually specify a start time (e.g., Monday 00:00) and run a "full trigger" to backfill history, while persisting LAST_SYNC_TIME. In Qeasy this is "Manual execution + choose start time."
Step 2: Switch daily scheduling to incremental. Source cron: 9 6-23/2 * * * (every 2 hours from 06:00 to 23:00, minute 9). Target cron: 55 */2 * * * (every 2 hours, minute 55). The stagger is intentional: ~46 minutes of buffer between the source finishing and the target starting, which absorbs peak document volumes.
Step 3: Dual-track operation + cutover. Run incremental and full in parallel for two weeks. Use Qeasy run logs to reconcile document numbers and amounts on both sides; only then cut the upstream business system over to "the integration platform is the source of truth." This step often gets compressed on customer sites, but it's exactly where things break.
Lessons learned
-
Pulling consignment and regular outbounds together. The source endpoint does not always distinguish business types, so on the first run we accidentally dragged normal sales outbounds in too. The safe fix is to add a business-type filter on the source request, or use Qeasy's "data filter" node to split by document type.
-
Going live without the warehouse mapping table maintained. On the first run, 200 documents all failed with "warehouse code does not exist." This is a textbook mistake we see on nearly every customer site — code mapping must be live before the business strategy. Use Qeasy's "dependency order" to schedule the master-data sync strategy ahead of this one.
-
Disabling
idCheckto "make things work." During one ops session, an engineer turned off idempotency to get documents through, and an upstream retry ended up writing the same document twice. Idempotency is the lifeline of these sync solutions; Qeasy enables it by default — don't turn it off. -
Header first, body later, leaving the document in "incomplete" state. The downstream system is sensitive to half-finished documents; reports pick up dirty data. The "header then body in phases" pattern above exists specifically to prevent this.
-
Time-zone / time-format mismatch. The source
startDateis a string without a timezone; the targetFDaterequires adatetime. Cross-time-zone customers hit this repeatedly. In Qeasy, use the{{LAST_SYNC_TIME|datetime}}macro and explicitly set the timezone — that resolves it in one shot.
When it fits and when it doesn't
Fits: private deployment, stable document volume, clear warehouse/customer/item mapping governance, and a desire to collapse consignment-transfer-to-sales-order into a single strategy. Does not fit: multi-version booksets coexisting across orgs, consignment business types not yet standardized upstream, or scenarios requiring real-time reverse writes from the downstream — those call for splitting into multiple strategies or moving to event-driven patterns.