Sales Return Sync in Practice: A Single-Strategy Implementation from Jushuitan to Kingdee Cloud Xingchen
What This Strategy Solves
In the day-to-day operations of a retail enterprise, Jushuitan handles front-end orders and after-sales, while Kingdee Cloud Xingchen handles back-end finance and inventory accounting. Sales return documents must stay consistent across the two systems: returns that occur in Jushuitan need to form corresponding return-in entries and receivable offsets in Xingchen. Once the two systems drift apart, you end up with "warehouse returned the goods but finance never recorded it" or "amounts don't reconcile." The goal of this strategy is to push Jushuitan sales returns into Xingchen according to the business rules, making documents traceable and amounts reconcilable.
Data Flow and Field Mapping
The overall flow is one-way sync: Jushuitan (source) → Qeasy Data Integration Platform (middleware, responsible for extraction, cleansing, and mapping) → Kingdee Cloud Xingchen (target).
Key field mapping (desensitized; refer to the latest API docs in real projects):
| Business Meaning | Jushuitan (Source) | Qeasy Middleware | Kingdee Cloud Xingchen (Target) |
|---|---|---|---|
| Document No. | io_id / co_id | Keep original, prefix to avoid duplicates | FBillNo (custom doc no.) |
| Document Type | Type enum | Map to return-type identifier | FBillTypeID (Return Order) |
| Customer Code | shop_id / buyer_nick | Map via customer master data to Xingchen code | FCustomerID |
| Item Code | sku_id | Map via item master data to Xingchen material code | FMaterialID |
| Warehouse | warehouse | Warehouse mapping table (centrally managed) | FStockID |
| Quantity | qty | Pass through | FQty |
| Price / Amount | price / amount | Recalculate per Xingchen precision, avoid float drift | FPrice / FAmount |
| Refund Amount | refund | Validate against upstream amount; block if delta exceeds threshold | FReceiveAmount |
| Document Date | created / modified | Unified to business date | FDate |
| Line Remark | remark | Concatenate source doc no. for traceability | FEntryNote |
There's an engineering consensus here: don't scatter code mappings across every strategy. On Qeasy we maintain a centralized "code mapping table"—one for customers, one for items, one for warehouses—and every sync strategy references the same table. Later adjustments happen in one place.
How to Configure on Qeasy
The configuration follows a three-stage pattern: extract → transform → write.
- Source extract node: Use the Jushuitan sales-return API, set the incremental field (typically modification time), and enable pagination. The incremental starting point must be an explicit timestamp, not "full."
- Transform node: Handle three things—code mapping (look up the mapping table), amount precision (recalculate per Xingchen's decimal rules), and header/line split. Process header and lines in phases: write the header first, then the lines. This prevents downstream header-validation failures from discarding the entire document.
- Target write node: Use Kingdee Cloud Xingchen V2's sales return order API. Pay attention to Xingchen's hard constraints on document number format, required fields, and approval status. When fields are missing, leave the document in "Saved" state rather than forcing submission.
Implementation Steps
We split go-live into three phases to avoid the risk of running full-volume from day one.
- Phase 1: Calibrate the incremental starting point. Freeze a historical timestamp (e.g., 7 days before go-live) as the starting point, run incremental-only for 3–5 days, and reconcile document numbers and amounts on both sides. Only after verification, expand the window.
- Phase 2: Trigger full volume and reconcile. Manually trigger a one-time full backfill to cover historical returns before go-live. After the full run, use Qeasy's "reconciliation view" to compare daily document counts and total amounts. Differences exceeding a threshold (e.g., 0.5% or 100 RMB per document) enter the manual review queue.
- Phase 3: Steady-state scheduling. Run incremental and full volume on dual tracks. Incremental pulls every 10–15 minutes; full volume runs daily or weekly as a safety net. Enable failure retry and alerting.
Qeasy supports crontab expressions, so incremental and full-volume tasks live in separate strategy instances and don't interfere with each other.
Lessons Learned
- Don't use "full" as the incremental starting point. Going straight to full triggers duplicate pushes of historical documents; if downstream deduplication isn't ready, you'll see duplicate orders. The safe approach is to freeze a timestamp first and run incremental.
- Don't pass amount fields through verbatim. Jushuitan and Xingchen often differ on decimal places and rounding rules. Passing values through leaves a permanent reconciliation gap. Recalculate in the middleware per Xingchen's precision.
- Code mapping must be centrally managed. One customer originally kept mappings inside transform scripts. When a batch of item codes changed, they spent a week updating a dozen strategies—and still missed some. A centralized mapping table is a lifesaver.
- Write header and lines in phases. Writing the whole document at once means a line-level validation failure can cause the entire document to be discarded, with no header trace left. Phased writing at least lets you locate the issue: "header landed, lines failed."
- Block refund amounts that exceed the threshold. When the source amount and refund amount differ too much, don't push hard—route to manual review. We've seen projects where an upstream refund field was picked up wrong, pushing a batch of negative orders.
When It Fits and When It Doesn't
Fits: Jushuitan as the front-end OMS, Xingchen as the back-end ERP, return volumes in the hundreds to thousands per day, with standard APIs on both sides. Doesn't fit: scenarios that require bidirectional sync (Xingchen adjustment orders writing back to Jushuitan), returns that go through complex approval flows (multi-level approval plus conditional branching), or extremely high volumes (hundreds of documents per minute) that require message queues rather than scheduled polling.