Sales Order to Outbound Delivery Sync Strategy: A Practical Guide
What This Strategy Solves
In one retail project we worked on, the marketing cloud handles front-end store and channel orders, while the back-office ERP (Kingdee Cloud Xingguang in this case) handles outbound delivery and inventory. A common pain point: once an "order" is approved in the marketing cloud, it must quickly become an outbound delivery in the ERP—otherwise shipments are delayed, inventory drifts, and reconciliation becomes a headache. This article focuses on a single strategy: synchronizing new-version orders from the marketing cloud to the ERP sales outbound document on an incremental basis. The full supply chain integration involves dozens of strategies; this one strategy is enough to explain the minimum closed loop for "document sync."
Data Flow and Field Mapping
The end-to-end flow is: Marketing cloud (source) → Qeasy integration platform (middleware) → ERP target system. The middleware handles code mapping, field conversion, and idempotency control; the source and target never talk directly.
Key field mapping (extracted from the source and target API metadata):
| Business Meaning | Marketing Cloud Source Field | ERP Target Field | Handling |
|---|---|---|---|
| Document number | no | bill_no | Passed through, used as idempotency key |
| Approval time | approveDt | bill_date | Date portion only |
| Customer code | clientAppNo | customer_id | Looked up via customer master mapping using findCollection |
| Remarks | remark | remark | Passed through |
| Contact / phone | contactLinkman / phone | contact_linkman / contact_phone | Passed through |
| Line items | orderItems[] | Expanded into multiple entries | Header and lines handled in phases |
| Warehouse | warehouseCode | stock_id | Warehouse mapping table |
A common pitfall here: customer, item, and warehouse master data must be synchronized before any document sync runs, otherwise the customer_id lookup fails and the entire document is wasted.
How to Configure on Qeasy
On the Qeasy data integration platform, we use the "source system + target system + strategy" three-piece model:
- Register two system instances: source is the marketing cloud (typed as WebAPI), target is the ERP (typed as the ERP adapter). Tenants and credentials are managed centrally in the console.
- Create a new strategy: choose "Document Sync" as the strategy type, attach the source API
/api/openapi/v1/erp/order/honour/agreement/header(POST query) and the target API/jdy/v2/scm/sal_out_bound(POST write). - Configure metadata: lay out source and target fields as a table and perform mapping in the middleware. Customer, item, and warehouse mappings are placed in Qeasy's centralized code-mapping management module so that every strategy shares one table—change once, propagate everywhere.
- Write logic:
bill_sourceis fixed to ISV; the customer uses{{clientAppNo}}with findCollection to look up the ERP internal ID; the date is truncated with{{approveDt|date}}. - Save and enable scheduling.
Implementation Steps
We rolled out this strategy in three phases:
- Phase 1: Incremental kickoff. Pull historical documents once using
id > starting cursor, verify the mapping, and confirm the ERP can accept the document. The safe approach is to first run 3–5 documents in the ERP test tenant and manually reconcile the amount, inventory, and customer. - Phase 2: Full trigger. Switch to
lastModifyTimeincremental mode, using the source approval time as the cursor. Our approach on Qeasy is a dual-track of incremental and full: incremental runs every 2 minutes in normal operation (avoiding ERP nightly maintenance), with a monthly full reconciliation as a safety net. - Phase 3: Steady-state operation. Monitor for a week and watch three classes of indicators: failure rate, document status in the ERP (approved vs. unapproved), and inventory book variance. The source scheduling frequency is
*/2 8-21 * * *(every 2 minutes during business hours), and the target write frequency is*/3 7-23 * * *(slightly staggered to avoid collision).
Lessons Learned
- Customer code not found, whole batch fails. On the first go-live, the marketing cloud had a new store that was not created in the ERP; findCollection returned empty and the target API errored out. The safe approach is to add a fallback in the middleware—when a code is not found, route the document to a "suspend queue" instead of letting the entire batch blow up.
- Wrong idempotency key causes duplicate outbound documents. A typical mistake is using
idas the idempotency key, while onlybill_nois unique on the ERP side, resulting in the same document being pushed twice. The correct approach is to use the source business document numbernoas the idempotency key and setidCheck=truein Qeasy. - Header and body synced together, fields misaligned. The marketing cloud's body has more fields than the ERP (gift items, promotional prices) and lacks a few custom fields. We adopted a header/body phased approach: the header is written first, then the body is written in batch, with field differences handled by mapping scripts.
- Cross-day documents suffer from time-zone drift. The source sends
approveDtwith a time zone, and a direct|datetruncation assigns overnight documents to the previous day. The safe approach is to explicitly format according to the enterprise time zone (+08:00). - Retry storms crash the ERP. Failed tasks default to 3 retries; when they cluster, the ERP rate-limits. The experience on Qeasy is to configure exponential backoff plus a maximum concurrency limit, and to alert when failures exceed a threshold instead of retrying indefinitely.
Applicable and Non-Applicable Scenarios
Applicable: high-frequency sales document sync between marketing/e-commerce middle platforms and ERP, converting external orders into ERP outbound/sales documents, where customer, item, and warehouse master data have unified coding. Not applicable: inter-company settlement (requires a separate inter-company settlement strategy), return orders (require a dedicated reverse-sync strategy), or real-time picking scenarios where sub-second latency is required (a 2-minute polling interval cannot meet that need).