Syncing After-Sales Rejection Refund Orders from Jushuitan to Kingdee Cloud QJB: A Hands-On Guide
What This Strategy Solves
In e-commerce operations, "rejection refunds" are the most overlooked link in after-sales flows. When a customer refuses delivery, Jushuitan generates a pending after-sales order that must be mirrored as a refund-outbound bill in Kingdee Cloud QJB. Otherwise, inventory and customer subledger balances drift apart. In one retail project we worked on, this link was unstable and the month-end reconciliation showed a 3-SKU gap between refund quantities and actual inbound stock — it took a full week to trace back to unsynced rejection orders. This guide unpacks the strategy end-to-end.
Data Flow and Field Mapping
The flow is unidirectional: Jushuitan (source) → Qeasy middleware → Kingdee Cloud QJB (target). We use the Qeasy (轻易云数据集成平台) integration platform to pull the after-sales orders, perform cleaning, mapping, and default-value enrichment in the middleware, and then call Kingdee's open API to write the refund bill.
Key field mapping:
| Business Meaning | Jushuitan (Source) | Middleware Logic | Kingdee Cloud QJB (Target) |
|---|---|---|---|
| After-sales order no. | as_id | Pass-through | billno (document no.) |
| Shop / Customer | shop_id | Encoding mapping table | customer_number |
| Inventory org | — | Fixed constant 100 | org_number |
| Document type | type | Fixed mapping im_SalOutBill_STD_BT_S_R | billtype_number |
| Settlement currency | — | Fixed constant CNY | settlecurrency_number |
| Sales org | — | Shop-based lookup | bizorg_number |
| Line items | After-sales lines | Line expansion + encoding map | Body entry array |
The most critical middleware job is mapping shop_id from Jushuitan to customer_number in Kingdee. This is also where things most often break — we will revisit it.
How to Configure on Qeasy
Source (Jushuitan): API is /open/refund/single/query, called via POST, with the pull window based on modification time. The request body always carries modified_begin (last sync time) and modified_end (current time), pagination uses page_index + page_size=50, and status is locked to WaitConfirm so only rejection-refund orders are pulled.
Target (Kingdee Cloud QJB): API is /kapi/v2/null/im/im_saloutbill/batchAddV2, a RESTful POST that batch-writes the refund bill in one call. A reliable engineering pattern here is header and body phased delivery: validate the header (org_number, customer_number, billtype_number, billno, etc.) first, then submit the body line items.
Initial cursor: Initialize LAST_SYNC_TIME to midnight of the go-live date; each subsequent schedule advances it automatically. Source scheduling uses cron 05,35 * * * * (at :05 and :35 every hour); target uses 20,50 * * * *, offset by 15 minutes to avoid simultaneous pressure on both ends.
Implementation Steps
- One-time full pull: Before go-live, pull the last 90 days of rejection-refund orders and run a backfill script to push everything confirmed into Kingdee. Do this in a business off-peak window.
- Establish the incremental cursor: After the backfill, switch
LAST_SYNC_TIMEto the go-live moment and move to incremental mode. - Daily schedule: Source pulls every half-hour, target writes near the hour. Qeasy retries failures 3 times; after that the record goes to a dead-letter queue and needs manual handling.
- Reconciliation: Weekly, run a "Jushuitan confirmed after-sales vs Kingdee refund bill" diff report checking document no., SKU, and quantity.
Running full and incremental in parallel is the most common stable pattern among Qeasy customers.
Pitfalls and Lessons Learned
- Never scatter shop-encoding mappings inside scripts. Early on we hard-coded mappings inline, and three months later when shops grew from 5 to 12, every change caused regressions. The safer approach is centralized encoding mapping — maintain a single "shop-to-customer-code" mapping table inside Qeasy.
- Don't lock
statustoo rigidly. The rejection-refund status isWaitConfirm, but some customers also wantConfirmedincluded. A safer pattern is to keep the whitelist on the source side rather than filter in middleware. - **
billnocollisions. If a Jushuitan order is edited and re-pushed under the same document number, Kingdee rejects it. Add an idempotency key (document no. + revision no.) on the Kingdee side. - Be cautious with hard-coded
100for the inventory org. Multi-org customers will route everything to the wrong org if you write it in. Drive it from a "shop-to-inventory-org" mapping table instead. - Time-zone issues in private deployments. On-prem servers often run in UTC, and if
modified_beginuses local time, you will either drop records or duplicate them. Confirm the time zone of the Qeasy runtime node.
When to Use and When Not to
Use when: e-commerce retailers where Jushuitan handles online sales and Kingdee Cloud QJB handles financial inventory, and you need rejection-refund orders mirrored for accounting. Do not use when: you require bidirectional sync (Kingdee back into Jushuitan), need real-time sub-second sync (this design is half-hour granularity), or the source ERP is a different vendor.