From Kingdee Cloud Material to JKY Goods SKU: A Single-Strategy Integration Tutorial
What This Strategy Solves
Syncing material master data from the ERP to downstream business systems looks simple, but it is the most common source of integration pain: inconsistent code rules, missing unit names, and un-extended hooks for batch/expiry/serial management mean numbers stop matching within three months of going live. In real projects, we use the Qeasy iPaaS to host this pipeline—pulling Kingdee Cloud materials incrementally by approval date and writing them into JKY goods SKUs, forming the foundation for upstream-downstream master-data unification across the supply chain.
Data Flow & Field Mapping
The data flow is straightforward: Kingdee Cloud (Material BD_MATERIAL) → Qeasy middleware → JKY (Goods SKU). The source uses the executeBillQuery API; the target uses the erp.goods.skuimportbatch bulk-import API.
| Target Field (JKY) | Source/Rule (Kingdee) | Mapping Type | Notes |
|---|---|---|---|
| goodsName | {{FName}} | DIRECT | Goods name |
| goodsNo | {{FNumber}} | DIRECT | Goods code, business key |
| goodsAlias | {{FName}} | DIRECT | Alias same as name |
| unitName | {{FPurchaseUnitId_FName}} | DIRECT/COLLECTION | Unit name; source only returns base-unit code, lookup needed |
| outSkuCode | {{FNumber}} | DIRECT | External SKU code |
| skuBarcode | {{FBARCODE}} | DIRECT | Barcode |
| skuName | {{FSpecification}} | DIRECT | Specification |
| isBatchManagement | 0 | CONSTANT | Batch management; later extend to TRANSFORM |
| isPeriodManage | 0 | CONSTANT | Expiry management |
| isSerialManagement | 0 | CONSTANT | Serial-number management |
| goodsAttr | 1 | CONSTANT | Goods attribute: 1 = finished goods |
Centralized code mapping: Qeasy's COLLECTION (collection mapping) and
_findCollectioncross-strategy lookup keep unit names, material attributes, and inventory categories translated in one mapping table rather than scattered across every strategy.
How to Configure on Qeasy
Source configuration highlights:
- api:
executeBillQuery, type QUERY, method POST - FormId: fixed as
BD_MATERIAL - number/id/idCheck:
FNumber/FMasterId/true - Pagination: Limit=2000, StartRow uses the
{{PAGINATION_START_ROW}}placeholder - FilterString:
FApproveDate>='{{LAST_SYNC_TIME|dateTime}}'—only pulls rows approved after the last sync timestamp - crontab:
0-59/5 7-22 * * *, every 5 minutes during business hours
Target configuration highlights:
- api:
erp.goods.skuimportbatch, type EXECUTE - crontab:
1-59/5 7-22 * * *, offset by one minute from the source to avoid race conditions where the next round fires before the previous one commits - idCheck: true, uses
goodsNo/outSkuCodeas the business key to determine insert vs. update
The field-mapping layer binds the {{source field}} placeholders to target fields one by one; constant fields take 0 or 1 directly with no expression needed.
Implementation Steps
- Initialize the incremental watermark: In the Qeasy scheduler, set
LAST_SYNC_TIMEto a historical timestamp (e.g., the day before go-live) and run one full backfill round to ensure all historical materials land in JKY. This step is often skipped—and results in an empty JKY in week one. - Full trigger & validation: Manually trigger one Source → Target end-to-end run; reconcile the goods count and spot-check key fields in the target; only then switch to scheduled execution.
- Bring the schedule online: Source
0-59/5 7-22 * * *, target1-59/5 7-22 * * *. Roll out header (basic) fields first, then body/extended fields in stages to limit per-change blast radius. - Reserve extension points: Ship
isBatchManagement,isPeriodManage,isSerialManagementas constant0first, then convert to_functionexpressions reading Kingdee'sFIsBatchManage,FIsKFPeriod,FIsSNManagewhenever needed. - Monitoring & alerts: Configure "3 consecutive rounds with zero data" and "retry-failure over threshold" alerts in Qeasy's run monitor, so newly approved materials land within 5 minutes.
Post-Mortem Lessons
- Classic mistake #1: unit name comes back empty. The source
executeBillQueryreturns onlyFBaseUnitId_FNumber(base-unit code), but the target wants a name. The safe approach is to use_findCollectionin Qeasy to look upFNamefrom the unit-of-measure scheme—rather than hard-codingunitNameas a constant. - Classic mistake #2: filter only on approval date. If someone changes a material's specification without re-approving, the target never updates. Later you can fold
FModifyDateorFForbidStatusinto FilterString for a dual-condition increment. - Classic mistake #3: batch/expiry/serial hard-coded as constants. At go-live the business is indeed all finished goods with no batch, but three months later they enable batch management—changing three fields is ten times more painful than changing one. Bind them to source fields via
_functionfrom day one; fix the values later if needed. - Classic mistake #4: source and target crontabs perfectly aligned. Both fire at the same second; the target tries to match keys while the source is still paging, causing duplicate writes or missed updates. Offsetting by one minute is the safest pattern.
- Classic mistake #5: goodsAttr fixed to finished goods. Kingdee's
FErpClsIDis a material-attribute code; JKY uses a 1/2/3/4 enumeration. Long-term hard-coding misaligns all semi-finished and raw-material data. Build the code-mapping table from the start and maintain it via COLLECTION.
When to Use / Not Use
Use when: the ERP is the master-data source of truth and downstream e-commerce/OMS/WMS systems consume by code; material attributes are stable with manageable change frequency; traceable incremental sync is required.
Don't use when: you need bidirectional master-data sync where both code schemes must coexist; the source system frequently merges/splits records without an approval flow; you require sub-minute real-time push via messaging instead of polling.