Consignment Transfer Return to Direct Transfer (Return) Sync Solution
What This Strategy Solves
In multi-org, multi-inventory supply chain environments, a retail enterprise often faces a real problem: consignment transfer-return inbound docs created at the front end must be re-expressed as "direct transfer (return)" docs in the back-end ERP. Otherwise the two ledgers drift apart and audits become painful. We use Qeasy to push the source inbound doc into a return-direction direct transfer doc on the target side, preserving the business trail while keeping semantics consistent.
Data Flow and Field Mapping
The flow is unidirectional: Source → Qeasy middleware → Target. The middleware handles three things: code mapping, field rewriting, and doc-type conversion.
Key field mapping:
| Business Meaning | Source Field | Target Field | Notes |
|---|---|---|---|
| Doc number | goodsdocNo | Doc number | Echoed as idempotency key |
| Transfer direction | inouttype | FTransferDirect | Mapped to RETURN |
| Business type | — | FBizType | Fixed: CONSIGNMENT |
| Doc type | — | FBillTypeID | Standard direct transfer: ZJDB01_SYS |
| Transfer type | — | FTransferBizType | InnerOrgTransfer |
| Source warehouse | fromWarehouseCode | FSaleOrgId | Translated via mapping table |
| Time window | startDate / endDate | — | Maintained via {{LAST_SYNC_TIME}} / {{CURRENT_TIME}} |
Centralizing the code-mapping table is one of the common patterns on Qeasy: all warehouse, org, and customer codes are maintained in a single mapping table, and field mapping only references keys rather than hard-coded values.
How to Configure on Qeasy
The source API is the WebAPI POST endpoint erp.storage.goodsdocin.v2, effect QUERY, with pageIndex/pageSize pagination (default 50 per page). The incremental time window uses {{LAST_SYNC_TIME|datetime}} to {{CURRENT_TIME|datetime}}, and the doc number is used for idCheck.
The target API uses the EXECUTE-type batchSave, POST submit. Key points:
- Doc type FBillTypeID: fix as
ZJDB01_SYS(standard direct transfer). Don't mix with other business-type codes or the target will reject the batch. - Transfer direction FTransferDirect: hard-code
RETURNto match the return semantics. - Business type FBizType: hard-code
CONSIGNMENTto align with consignment. - Transfer type FTransferBizType: fixed
InnerOrgTransfer, the standard value in the target's drop-down list. - Org fields FSaleOrgId / FSettleOrgId: do not directly pass warehouse codes; translate them through the middleware mapping table into the target org IDs. We recommend handling this in a dedicated field-mapping node on Qeasy.
- Idempotency: target idCheck=true. Echo the source doc number straight into the target so repeated pushes do not create duplicate docs.
Implementation Steps
We split it into three phases, a typical "incremental baseline + full re-trigger + schedule frequency" dual-track pattern:
Phase 1 — Incremental baseline. Before go-live, run a one-time full load to backfill historical consignment return docs. After go-live, switch to incremental with {{LAST_SYNC_TIME}} as the watermark. The source cron 14 6-23 * * * covers the business hours window with hourly granularity.
Phase 2 — Full re-trigger. At key checkpoints such as month-end or quarter-end, manually or via script trigger a full reload to reconcile both ledgers. The same strategy can be reused on Qeasy by only changing the time window.
Phase 3 — Schedule frequency. The target cron 47 * * * * runs hourly but offsets the minute (source at :14, target at :47) so the two ends do not race each other. Keep both ends on hourly windows and leave enough buffer for transformation in between.
Lessons Learned
From several on-site rollouts we have seen these recurring issues:
- Wrong doc type.
ZJDB01_SYSthroughZJDB06_SYSlook like minor code differences, but target-side validation is strict; mixing them causes the whole batch to be rejected. The safe approach is to maintain FBillTypeID as a constant, not buried inside field mapping. - Passing warehouse codes as org IDs. A "warehouse" on the source side and an "organization" on the target side are not the same concept; passing values directly makes the two ledgers unreconcilable. This is exactly why the code-mapping table must be centralized on Qeasy.
- Bad incremental baseline. On the first go-live
{{LAST_SYNC_TIME}}may be empty, resulting in either empty pulls or full dumps. Run a historical backfill first and pin the watermark to a clear point in time. - Lost idempotency key. Target-side batchSave idempotency relies on idCheck, so the source doc number must be echoed stably. If the middleware rewrites it, duplicates appear.
- Both ends pulling on the same minute. If source and target crons collide, the target may receive half-transformed data. Offsetting the minutes is the safe pattern.
When to Use and When Not to Use
Use this strategy in private-deployment environments where the source system and target system are connected, and there are inter-org consignment transfer-return flows that need to be aligned with direct-transfer (return) semantics in the ledger. Do not use it for non-consignment flows (standard purchase returns, sales returns, etc.), do not use it for bidirectional sync, and do not use it when the source side lacks a stable goodsdocNo idempotency field.