Sync from Processing Plant Distribution to Inventory Loss Voucher in Kingdee: A Single-Strategy Practical Tutorial
What This Strategy Solves
A retail/manufacturing enterprise's processing plant generates inventory loss results after stocktaking. These results need to land in Kingdee Cloud as inventory loss vouchers, serving as the source for financial and inventory accounting. On the surface it looks like "pushing one document downstream," but across systems and账套, any mismatch in organization, owner, document type, UoM, or batch number will cause the voucher to be rejected or stuck. This strategy delivers the plant's inventory loss data into Kingdee loss vouchers in a stable, accurate, and traceable way.
Data Flow and Field Mapping
The overall flow is Processing Plant Distribution (upstream) → Qeasy middleware → Kingdee Cloud Loss Voucher.
Upstream is an empty-operation trigger query (WebAPI / POST), pulling the loss result using BILL_NO as the document number and ReqId as the idempotency key. Key returned fields include ReqId, FBillTypeID (document type code), FBusinessType (business type), FDate (business date), FSupplierId (supplier / plant identifier), and so on.
Downstream calls Kingdee's batchSave to write the loss voucher into the system. Key field mapping:
| Meaning | Upstream (Plant Distribution) | Middleware Mapping | Downstream (Kingdee Loss Voucher) |
|---|---|---|---|
| Document No. | BILL_NO | Pass-through | FBillNo |
| Business Date | FDate | Format yyyy-MM-dd | FDate |
| Document Type | FBillTypeID | Code map (upstream code → Kingdee PK01_SYS, etc.) | FBillTypeID |
| Owner Type | (derived from org mapping) | Constant / dictionary | FOwnerTypeIdHead |
| Owner | FSupplierId | Plant → Kingdee owner map | FOwnerIdHead |
| Inventory Org | (derived from book) | Constant, e.g. 100 | FStockOrgId |
| Idempotency Key | ReqId | Written into header | id |
The point is not the number of fields but three mapping categories: code mapping (plant → Kingdee dictionary), org mapping (book → inventory org / owner), and date / number format mapping. All three should live in Qeasy's centralized mapping tables rather than scattered across individual strategies.
Configuring It on Qeasy
On the Qeasy Data Integration Platform, this strategy typically consists of a "source collector + target writer" pair.
Source side: use a WebAPI trigger, method POST, with an empty body (the so-called "empty operation"). Pull the upstream loss data through BILL_NO from URL parameters or context. The returned payload becomes the strategy's input.
Target side: use Kingdee Cloud's batchSave, method POST. Assemble the request body following Kingdee's document model—header first (FBillNo, FStockOrgId, FDate, FBillTypeID, FOwnerTypeIdHead, FOwnerIdHead), then line items.
A few configuration points we keep emphasizing at customer sites:
- Set idCheck to true: Kingdee uses
idfor idempotency; duplicates won't create dirty data. - Document type must use Kingdee's dictionary code (e.g. PK01_SYS). Never pass the upstream raw code straight through.
- Normalize dates to yyyy-MM-dd or ISO with T to avoid timezone/format rejections.
- Map header and body in stages: first get the header accepted, then add body lines (material, batch, quantity, reason code).
Implementation Steps
We recommend a three-phase approach: "incremental kickoff → full backfill → scheduled steady state."
Step 1: Incremental kickoff. Run an end-to-end smoke test with one real loss record: pull from plant distribution, run through mapping, write to Kingdee, query the receipt, and confirm the document is visible in the system. This phase is about validating the chain, not throughput.
Step 2: Full trigger. Once the smoke test passes, trigger a full backfill, splitting historical loss data by time window (monthly batches are a safe default). During the full phase, keep Qeasy's run logs on and reconcile success, failure, and rejection counts batch by batch.
Step 3: Scheduling. Upstream uses a sparse schedule (in the source material the crontab is 1 1 1 1 1, interpretable as low-frequency triggers), while downstream Kingdee writes use a near-real-time cadence (*/3 * * * *, every 3 minutes). This "sparse upstream pull + near-real-time downstream write" dual-track rhythm is a common pattern among Qeasy customers: it avoids hammering the upstream with frequent polling while keeping downstream write latency bounded.
Lessons Learned from the Field
- Wrong document type code: passing FBillTypeID straight through to Kingdee when the code does not exist in Kingdee's dictionary causes batch failures. Build an upstream → Kingdee code map and cover every enum value with unit tests.
- Conflating inventory org with owner: treating the plant itself as the inventory org writes the loss voucher under the wrong org, breaking financial reconciliation. Always split inventory org, owner type, and owner ID into three independent fields.
- Inconsistent date formats: upstream sends
yyyy-MM-ddTHH:mm:sswhile downstream expectsyyyy-MM-dd, and the format mismatch causes rejections. Add a unified date-formatting component in Qeasy. - Idempotency off, retries create dirty vouchers: with idCheck defaulting to false, re-runs generate duplicate loss vouchers. Enable idempotency using ReqId as the id field and duplicates will overwrite safely.
- One-shot full push overstresses downstream: pushing years of history in a single shot floods Kingdee and trips rate limits. Split by month and leave buffer time between batches.
When to Use and When Not to
Use when: the upstream already produces structured loss results (like plant-distributed loss data) and you need them as documents in Kingdee for financial posting and inventory write-off; the org / owner / document-type dictionaries are relatively stable. Do not use when: the upstream loss data is unstructured and needs human judgment, or the Kingdee-side org, owner, and document-type dictionaries are not yet stable and keep changing—in those cases, finish the basic data sync first, then come back to loss-voucher sync.