Production Report Sync in Practice: Engineering the Pull from Kingdee Cloud to Qeasy DataHub
What This Strategy Solves
In one discrete manufacturing project, MES lives in MySQL while ERP runs on Kingdee Cloud. Production reports are entered by the shop floor in MES, but they need to be persisted in ERP as queryable, auditable documents. We used Qeasy (轻易云数据集成平台) to implement the "GH Production Report Query" strategy. In essence, it periodically pulls existing production reports from Kingdee Cloud into the integration platform, where they become the data source for reconciliation, status write-back, and shop-floor dashboards. It looks like a simple "query," but in practice you have to design the WebAPI invocation, the incremental cursor, the field alignment, and the schedule carefully to keep it stable.
Data Flow and Field Mapping
The data flow is a one-way pull: Kingdee Cloud → Qeasy DataHub (intermediate layer) → downstream consumers (reconciliation table / status sync / MES write-back).
| Business Meaning | Kingdee Cloud Field | Qeasy Intermediate Field | Notes |
|---|---|---|---|
| Bill primary key | FID | id | Idempotency key |
| Bill number | FBillNo | number | External identifier |
| Entry primary key | FEntity_FEntryID | entry_id | Body-row identifier |
| Source production order | FMoBillNo | mo_bill_no | Traceability |
| Material code | FMaterialId.FNumber | material_code | Nested object must be flattened |
Note that FMaterialId in Kingdee Cloud is a base-data field that returns a nested object with FNumber. You must flatten it to material_code in the intermediate layer, otherwise downstream reconciliation will fail.
How to Configure It in Qeasy
The source is Kingdee Cloud's executeBillQuery WebAPI, POST method, QUERY effect. A few key points when configuring in Qeasy:
- API selection: Kingdee Cloud's
executeBillQuerysupports custom return fields. Be sure to include FID, FBillNo, FEntity_FEntryID, FMoBillNo, and FMaterialId.FNumber. Without FBillNo, downstream reconciliation cannot locate bills. - Enable idCheck: The source metadata explicitly sets
idCheck: true. Always enable idempotency checks to avoid duplicate rows on re-pull. - Target is a "no-op write": The target API is configured as a no-op write, POST method, EXECUTE effect. This is a common Qeasy pattern—persist to the intermediate table only, do not push directly downstream. It fits a layered "query + persist" design.
- Centralized code mapping: Material codes, organization codes, and other base data should be maintained centrally in Qeasy's mapping module, not scattered across strategies. This is the most common pattern among Qeasy customers—one change propagates everywhere later.
Implementation Steps
We split the rollout into three phases to avoid hammering Kingdee Cloud with high-frequency schedules from day one.
- Step 1: Align the incremental cursor. Use Kingdee Cloud's FModifyDate or FDate as the incremental watermark. Backfill the past 3 days first, validate field mapping, and confirm row counts.
- Step 2: Run a one-time full pull. Pull all historical production reports without a time window. After it completes, record the maximum FID as the new incremental starting point.
- Step 3: Switch on the schedule. The source crontab is
*/2 * * * *—the query fires every 2 minutes. The target write runs on*/10 7-22 * * *—writes only during work hours, every 10 minutes. This "high-frequency polling at the source, work-hour landing at the target" dual-track pattern is a mature convention among Qeasy customers: near-real-time on the source, but no overnight writes filling up the database.
Lessons Learned (Reactive Post-mortem)
- Mistake 1: Ignoring the nested FMaterialId.FNumber. Pulling FMaterialId as a plain string causes downstream reconciliation to fail. The safe approach is to flatten it on the source side, or write a transformation script in Qeasy's field mapping.
- Mistake 2: Crontab set too aggressively. */2 is an empirical value; some teams shorten it to */1 and immediately hit Kingdee Cloud's rate limits. The safe approach is to run */2 for a week first, observe response-time distribution, and then decide whether to tighten it.
- Mistake 3: Writing into real business tables at the target. The target is intentionally a no-op. If you mistakenly point it at a real business table, header and body rows can land in separate transactions and leave dirty data. The safe pattern is phased landing—write the header first, then the body asynchronously, with retry on failure.
- Mistake 4: idCheck not enabled. Kingdee Cloud's query API has no built-in deduplication. Without idCheck, the same FBillNo appears multiple times in the intermediate table.
- Mistake 5: No gap handling across midnight. The source runs */2 all day, but the target only lands during 7-22 on a */10 schedule. Anything pulled at 22:10 will not be persisted until 7:00 the next morning—a 9-hour lag. The safe fix is either to extend the target to */10 around the clock, or to add a "night-accumulation" filter on the source side.
When This Fits and When It Doesn't
Fits: Shop floors that record production reports in MES and need them reconciled or audited in ERP; organizations that already run Kingdee Cloud as their ERP and want a clean intermediate layer for distribution.
Doesn't fit: Scenarios that need sub-second real-time push to ERP—use Kingdee Cloud's real-time API instead of polling. Also not suitable when the source is not Kingdee Cloud, or when the target must be a real business table—this strategy is designed for intermediate-layer persistence only.