Return-to-Inbound Sync in Practice: End-to-End Landing from Marketing Cloud Return Orders to Kingdee Cloud Xingchen
What This Strategy Solves
The return process at a certain retail enterprise was stuck between two systems: the front-end Marketing Cloud held return orders submitted by distributors, while the back-end Kingdee Cloud Xingchen needed sales inbound orders generated as soon as possible to write off inventory and receivables. Manual daily transfer was both slow and error-prone, and after three days the quantities on both sides began to diverge. This strategy has only one goal—to write audited Marketing Cloud return orders into Kingdee Cloud Xingchen stably, with low latency, and in a replayable way, with no lost orders and no duplicate orders.
Data Flow and Field Mapping
The data flow is linear: Marketing Cloud (source) → Qeasy middleware → Kingdee Cloud Xingchen (target). The source calls POST /erp/api/order/query/saleReturnOrder, incrementally pulling audited return orders by tenantId + status=1 + beginTime/endTime; the target calls POST /jdy/v2/scm/sal_in_bound to execute the inbound.
Key field mapping (simplified):
| Business Meaning | Marketing Cloud (Source) | Kingdee Cloud Xingchen (Target) | Handling |
|---|---|---|---|
| Document number | number | id (idempotency key) | Source number as target idempotency key |
| Distributor/Customer | tenantId | customer_id | Look up customer via _findCollection by external code |
| Document date | auditTime | bill_date | Format via `{{auditTime |
| Document remark | remark | remark | Concatenate "from Marketing Cloud-{number}" for traceability |
| Contact info | shippingAddress, contactLinkman | contact_address, contact_linkman | Pass through directly |
The line items follow a "header-then-body phased" pattern: first push the header to obtain the target id, then attach detail lines through a nested array or a separate line-item interface. This avoids a single bad line field ruining the entire document.
How to Configure on Qeasy
We use the Qeasy data integration platform to host this. A typical configuration has four parts:
- Source model: WebAPI / QUERY, with
numberas the unique key,idCheckenabled, and response auto-fill. The incremental field is bound tobeginTimeusing{{LAST_SYNC_TIME|datetime}}, so the platform remembers the cutoff moment of the last successful run for us. - Target model: WebAPI / EXECUTE, with
bill_sourcefixed toISVandidas the idempotency key. For external dependencies such as the customer master, the lookup is done in the middleware via_findCollection find id from {collection ID} where number={{extCusCode}}— Qeasy centralizes this kind of lookup logic in a "mapping table" so that return orders, sales orders, and outbound orders all share the same mapping. When a new distributor is added, you do not need to modify each strategy. - Transformation scripts: Handle unit conversion, tax-rate fallback, and null-value replacement. For critical line-item fields such as quantity and tax-inclusive unit price, perform explicit null checks. If a value is missing, send the record to a "manual completion" queue rather than writing it in directly.
- Scheduling:
*/8 8-21 * * *, a run every 8 minutes covering daytime business hours. A nightly full reconciliation script runs in parallel with the daytime incremental — this is the common "incremental plus full reconciliation dual-track" approach seen among Qeasy customers.
Implementation Steps
Roll this out in three phases. Do not jump straight into a full run:
- Phase 1 · Incremental starting point: Choose a historical timestamp as the initial
LAST_SYNC_TIME, such as 00:00 of the current day. Manually backfill all "audited" return orders before 00:00 so that the target system has a complete baseline. - Phase 2 · Full trigger: Run a dedicated full backfill script for un-synced historical data with
idCheckenabled, allowing replay. Once the backfill is done, switch to incremental scheduling. - Phase 3 · Scheduling frequency: Pull every
*/8minutes during business hours (8-21), and either lower the frequency or stop during nighttime, leaving only full reconciliation. Monitor three things: day-over-day document count, retry failure count, and the count of customers that cannot be looked up forcustomer_id.
Pitfall Recap
customer_idlookup failure aborts the entire order: A classic mistake is to hardcode the external code intocustomer_id. The safe approach is to pass the source value if available, otherwise fall back to_findCollectionagainst the mapping table. When a lookup fails, send the entire order to the exception queue — never silently drop it.auditTimetimezone drift: Marketing Cloud's time string carries timezone information, and using it directly causes boundary orders to be missed across days. Truncate consistently to date in the business timezone before passing tobill_date.- Replay causes duplicate inbound entries: When the source pulls by time window, an "audited" order whose price is changed inside the window will be written again on replay. The safe approach is
idCheck=trueon the target, with the document number as the idempotency key, and an additional(document number + line number)deduplication at the line-item level. - Unit mismatch on line items: Marketing Cloud uses "case" while Kingdee uses "box". Do not hardcode the conversion inside the strategy. Maintain it per SKU in the "mapping table" so that order sync and outbound sync can also reuse it.
remarkfield overwritten: Passing the sourceremarkstraight through wipes out traceability information. The common practice is to concatenate "{remark}-from Marketing Cloud-{number}", preserving the original remark while leaving a traceability tag.
Applicable and Non-applicable Scenarios
Applicable: Retail or distribution scenarios where a front-end business system generates audited return orders and the back-end ERP needs to generate sales inbound orders in near-real-time for inventory and receivable write-offs, with daily volumes in the low thousands. Not applicable: Complex manufacturing scenarios that require write-offs down to batch or shelf-life level, or instant cost-price recalculation across legal entities. Also not applicable to scenarios where the return order status frequently rolls back (from audited back to unaudited) while strict bidirectional sync is required — in those cases, add a state-machine intermediate table first.