Sync Sales Outbound from Jushuitan to Kingdee Cloud Cosmic: A Single-Strategy Tutorial
What This Strategy Solves
A multi-store retail group takes orders and ships from Jushuitan, but finance and cost settlement live in Kingdee Cloud Cosmic. The two systems each carry their own document model — statuses, document numbers, organizations, customer master data — and they drift apart: a store manager clicks "Confirmed" in Jushuitan, yet finance never sees the document, and by the time it's manually re-entered the accounting period is already closed. Sales outbound sync solves exactly one thing — pulling Jushuitan's Confirmed sales outbound orders into Kingdee Cloud Cosmic on an incremental cadence as standard sales outbound documents, so inventory and accounting can finally speak the same language.
Data Flow and Field Mapping
The flow is Jushuitan → Qeasy integration platform → Kingdee Cloud Cosmic. The middle layer handles retrieval, cleansing, code mapping, and landing.
| Dimension | Jushuitan (source) | Qeasy middle layer | Kingdee Cloud Cosmic (target) |
|---|---|---|---|
| Document number | io_id | Pass-through | FBillNo |
| Outbound date | io_date | Normalized to yyyy-MM-dd | FDate |
| Status | status | Only Confirmed allowed | Not written; used as pre-filter |
| Store | shop_id | Mapped via "store–customer" table | FCustomerID |
| Sales org | Not in source | Fixed by strategy config | FSaleOrgId |
| Doc type | Not in source | Fixed by strategy config | FBillTypeID |
| Item lines | items[] | Code map + line expansion | FEntity entries |
| Sync boundary | Modification window | start_time / end_time | — |
Worth highlighting: Jushuitan's API enforces a maximum 7-day window between start_time and end_time, and these two slots are precisely what drive the incremental window on the source side. FBillTypeID and FSaleOrgId do not exist in the source at all — they must be injected as constants inside the Qeasy strategy.
How to Configure in Qeasy
When we run this strategy on the Qeasy data integration platform, we typically break the configuration into four blocks.
Source connector: pick Jushuitan·Qimen, bind to jushuitan.saleout.list.query. Both pagination params — page_index and page_size — must be enabled; respect the platform's 50 rows/page cap. Bind the incremental fields to start_time / end_time, injecting {{LAST_SYNC_TIME|datetime}} and {{CURRENT_TIME|datetime}}.
Target connector: Kingdee Cloud Cosmic, calling batchSave to write sales outbound documents. Note that the target side is a line-item document type — line mapping (FEntity) must be enabled in the strategy, and Qeasy will expand rows accordingly.
Centralized code mapping: store/customer/SKU mappings belong in Qeasy's "mapping table", not scattered across per-strategy scripts. On one real project we extracted shop_id → FCustomerID into a single table — opening a new store meant editing one row, and every dependent strategy picked it up automatically.
Pre-filter and status gate: data pulled from the source is filtered in Qeasy first by status = Confirmed, then narrowed to the target stores by shop_id (the source material illustrates the "Trendy Store 3" style of logical sharding), and only then pushed to Kingdee.
Implementation Steps
Cut the rollout into three phases — it makes the whole thing easier to reason about.
Phase 1 — full backfill (first run): push start_time back far enough to cover history and manually trigger once to flush all confirmed historical orders. In Qeasy this is just a "manual trigger + time-window override" — no change to the strategy structure is needed.
Phase 2 — switch to incremental (steady state): after the first success, set the source cadence to every 30 minutes (*/30 * * * *) and the target writer to every 40 minutes (*/40 * * * *). The two are offset to avoid instantaneous pressure on either side. The incremental cursor is Qeasy's LAST_SYNC_TIME variable, which the platform persists automatically.
Phase 3 — monitoring and re-injection: Qeasy's built-in run logs directly surface "rows fetched / rows written / rows failed". Field experience: if "rows fetched" sits at zero for a long time, first check whether the cursor was manually edited on the source side; when "rows failed" alarms go off, look at Kingdee-side field validation errors first — most often it's an FDate format issue or a missing customer record.
Lessons from the Trenches
-
The 7-day window trap: Jushuitan hard-caps the window at 7 days. If the scheduler is down for more than a week,
start_timefalls outside the window and the API errors out directly. The safe approach is to add a "window trimmer" inside Qeasy that splits anything over 7 days into multiple loops automatically. -
Confirmed orders overwritten on rewrite: the source occasionally rewrites or rolls back the
Confirmedstatus, and without idempotency the Kingdee side ends up with duplicates. UseFBillNo = {{io_id}}as the idempotency key in Qeasy, paired with an "update if exists, else insert" write policy — that keeps the books clean. -
Mismatched store codes: Jushuitan uses auto-increment numeric
shop_id, while Kingdee uses string codes from its base-data master. On one project we initially kept the mapping inside each strategy's Python script — changing three stores meant editing a dozen places. Migrating everything into Qeasy's mapping table dropped the ops cost to near zero. This is the classic payoff of centralized code mapping. -
Header and body phased rollout: the first go-live put the header and body in a single strategy, and when something broke it was painful to diagnose. We later split it into two steps — first stabilize the header (confirm the document lands), then release the body (confirm the lines match). That's the safe practice of phasing header and body.
-
Dual-track incremental + full: during peak season or period cutover we sometimes need to backfill specific historical ranges. Instead of touching the main strategy, we spin up a separate "backfill strategy" running full mode, then stop it — the main strategy stays on incremental forever. That's the common dual-track incremental + full pattern.
Applicable and Non-applicable Scenarios
Applicable: multi-store retail where confirmed outbound orders must feed finance and cost settlement; scenarios that require store-level sharding and cross-system idempotency.
Not applicable: stores that need sub-second real-time sync (the 30-minute cadence is too coarse); businesses with frequent status rollbacks on the source side (idempotency will not hold); and cases where the source provides no modification-time field and can only be polled by order number.