Kingdee Cloud Customer Master Sync to WMS: An Incremental Strategy on Qeasy
What this strategy solves
In retail and distribution environments, Kingdee Cloud usually acts as the authoritative source for customer master data, while a downstream WMS relies on that profile to determine receivers and merge logic. In one of our field projects, the Kingdee Cloud → WMS customer modification strategy handles exactly that: it pulls existing but recently modified customers from the source using executeBillQuery, then writes the changes to base_customer via UPDATE. In short, it keeps the warehouse copy of the customer profile always current, never missing.
Data flow and field mapping
Data flow: Kingdee Cloud (BD_Customer) → Qeasy Data Integration Platform middle layer → MySQL (WMS base_customer). The business key is the customer code FNumber ↔ customerCode, mapped one-to-one.
| Target field | Source field | Mapping type | Notes |
|---|---|---|---|
| customerCode | FNumber | DIRECT | Customer code, used in UPDATE WHERE |
| customerName | FName | DIRECT | Customer name |
| isPartakeMerge | FIsTrade | TRANSFORM | Whether to participate in order merging; requires boolean/number conversion |
Other source fields (create org, use org, short name, address, phone, salesperson, etc.) are not mapped in this strategy. They are reserved for other strategies to consume, which keeps each strategy focused.
How to configure it on Qeasy
We typically deploy this in three steps on site:
- Create the source scheme: pick Kingdee Cloud, interface
executeBillQuery, select fieldsFNumber / FName / FIsTrade / FUseOrgId.FNumber / FModifyDatein the request body. - Create the target scheme: pick MySQL, interface
execute, place the UPDATE statement intomain_sql, and let the parameter objectmain_paramscarry{customerCode, customerName, isPartakeMerge}. - Wire them up in the strategy editor: do the field mapping; for
isPartakeMerge, use a_functionexpression to normalizetrue/falseinto1/0, e.g.case when {{FIsTrade}}=true then '1' else '0' end.
Two Qeasy customer patterns show up here. The first is centralized code mapping — this strategy uses a direct mapping for customer code, with no cross-strategy lookup; if you later need conversion for customer category or group, put it in a shared code-mapping set instead of scattering it across N strategies. The second is header/body staged rollout — this strategy only writes three header-level fields, while address, phone and other body-level extensions live in separate strategies, so that troubleshooting can be sliced by field domain.
Implementation steps
Phased scheduling is the heart of this strategy:
- Incremental anchor: the source
FilterStringusesFModifyDate>='{{MINUTE_AGO_30|datetime}}', combined with two static conditionsFUseOrgId.FNumber='100'andFFORBIDSTATUS='A', scoping down to customers modified in the last 30 minutes, belonging to the specified org, and currently enabled. - Full trigger: on first go-live, disable the time filter and backfill historical customers in WMS; then switch back to incremental.
- Crontab: source runs at
7-59/20 * * * *(every 20 minutes, offset to avoid the top of the hour), target runs at*/2 * * * *(every 2 minutes). A coarse source plus a fine target is the classic slow-source / fast-target dual-track pattern in Qeasy — slow at pulling, fast at consuming, which smooths out spikes effectively.
The target SQL must also encode its boundaries directly: where shipperId='...' and customerCode not in (...) ensures that only the specified shipper is touched, and historical special customer codes are excluded.
Pitfalls from the field
- Forgetting the modification timestamp. A common mistake is filtering only on create date, which means legacy customers never get synced. The safe move is to explicitly use
FModifyDatein the sourceFilterString, and prefer a relative-time macro likeMINUTE_AGO_30to avoid timezone pitfalls at midnight. FIsTradetype drift. Some Kingdee environments returntrue/false, others return'1'/'0'. A direct mapping can produce invalid values on the target side. Always normalize via a_functionexpression, and centralize the rule on Qeasy.- Putting shipper / exclusion filters in application code. In one project, an engineer placed the
shipperIdfilter in intermediate Java code, which caused gaps in multi-shipper scenarios. The safer approach is to bake shipper and excluded codes into the target SQL's WHERE clause, decoupling them from the application layer so they survive database migration. - Mismatched scheduling cadence. A 2-minute source poll will hammer Kingdee; a 20-minute target poll will lose freshness. The slow source / fast target combination is the most stable cadence we have run on Qeasy.
- Disabled customers flowing into WMS. Forgetting
FFORBIDSTATUS='A'lets disabled customers get written downstream, and the WMS ends up allocating shipments to a disabled account.
Where this fits and where it does not
Fits: single or few organizations, clear enable/disable states, Kingdee as the authoritative source, and scenarios where only lightweight fields (merge flag + name) need to be written back.
Does not fit: cases that require writing back address, phone, or bank info (use a separate strategy); brand-new customer creation scenarios (use an "insert" strategy instead of UPDATE); multi-org sharing with frequent org-dimension changes — this strategy uses a static FUseOrgId.FNumber filter, which would need redesign for multi-org.