Qeasy Cloud
Get Started

Sync Kingdee Cloud Customer Master Data to MySQL: A Single-Strategy Practical Guide

· 何海波· Integration Solutions· 18 views· 3 min read
MySQLKingdee Cloud客户主数据Incremental Sync轻易云供应链集成

What This Strategy Solves

In one real project, a retail enterprise used Kingdee Cloud as the ERP source of truth for master data, while downstream BI and the business middle platform needed a flattened customer master table for profiling and store-level analytics. The Kingdee BD_Customer interface returns a structure of "base data IDs plus nested objects," which is nearly unusable if pushed directly into BI. This strategy does only one thing: incrementally pull Kingdee customers filtered by FModifyDate into the MySQL table tp_jd_customer, isolate organization TP000, and flatten the nested objects for country, region, province, and city.

Data Flow and Field Mapping

Flow: Kingdee Cloud (executeBillQuery, FormId=BD_Customer) → Qeasy Data Integration Platform → MySQL (tp_jd_customer).

Key field mapping:

Target FieldSource FieldMapping TypeNotes
FCUSTIDFCUSTIDDIRECTPrimary key, used for upsert
FNumberFNumberDIRECTCustomer code, business key
FNameFNameDIRECTCustomer name
FCOUNTRY_FNumberFCOUNTRY.FNumberTRANSFORMPre-extracted at source, flattened
FCOUNTRY_FNameFCOUNTRY.FDataValueTRANSFORMSame as above
FPROVINCE_FNumberFPROVINCE.FNumberTRANSFORMProvince code
FCITY_FNameFCITY.FDataValueTRANSFORMCity name
FCustType_FNameFCustTypeId.FDataValueTRANSFORMCustomer category name
FGroup_FNumberFGroup.FNumberTRANSFORMCustomer group code
FUseOrgIdFUseOrgId.FNumberTRANSFORMUse organization, also the filter condition
FModifyDateFModifyDateDIRECTIncremental cursor

Note that FCustTypeId in the source carries an Id suffix, while the target is named FCustType_. Mixing these up is a common pitfall.

How to Configure It on Qeasy

The source is Kingdee Cloud's WebAPI (executeBillQuery), and the target is MySQL's SQL executor (batchexecute). On the Qeasy Data Integration Platform, there are four typical configuration points:

  1. In the source request configuration, use dot-path syntax such as {{FCOUNTRY.FNumber}} and {{FCustTypeId.FDataValue}} to let Kingdee flatten the nested objects at the API layer, so the target table does not need any extra expressions.
  2. Write the filter as FModifyDate>='{{LAST_SYNC_TIME|datetime}}' and FUseOrgId.fnumber='TP000'. Put the incremental cursor and organization isolation on the source side to minimize network round-trips.
  3. On the target side, use REPLACE INTO tp_jd_customer (...) VALUES (...), with the primary key FCUSTID and idCheck enabled, for a natural upsert.
  4. Cap each batch at 200 rows; anything more gets paginated.

Implementation Steps

We usually follow four steps on the customer site, in strict order:

  • Step 1: Build the full baseline. Set the FModifyDate starting point to a very early date (e.g., 2000-01-01), run it once manually, and confirm that the target row count matches the Kingdee customer count after filtering by TP000. The output of this step is a full baseline.
  • Step 2: Turn on incremental sync. Switch LAST_SYNC_TIME to be automatically maintained by the platform. The source runs on */7 * * * * (every 7 minutes), and the target runs on 3-59/7 * * * * (every 7 minutes, offset 3 minutes from the source). Pull first, write later, to keep the timing stable.
  • Step 3: Reconciliation and monitoring. Run a daily morning reconciliation: Kingdee customer count for TP000 vs row count in tp_jd_customer. Alert if the difference exceeds a threshold.
  • Step 4: Exception fallback. If a customer is disabled and then re-enabled in Kingdee, FModifyDate does not refresh. Add a separate sync for freeze/forbid status changes; do not rely solely on the modification date.

Pitfall Recap

  1. Forgetting to flatten nested objects. Dumping raw Kingdee JSON into MySQL leaves BI queries with no value for FCOUNTRY.FNumber. The safe approach is to pre-extract at the source request configuration, so the target only receives flattened fields.
  2. Wrong field name mapping. FCustTypeId (source) maps to FCustType_FName / FCustType_FNumber (target). It differs by an Id and an extra underscore. A typical mistake is to copy the source name directly, which leaves the whole column NULL.
  3. Inverted organization filter. FUseOrgId.fnumber is the use organization, while FCreateOrgId is the create organization. A multi-org customer can exist in both. A wrong filter leads to "exists in Kingdee, missing in MySQL."
  4. Incremental cursor not updated. If the scheduler uses a global timestamp, concurrent strategies will overwrite each other. On Qeasy, it is recommended to maintain a separate LAST_SYNC_TIME for each strategy in the strategy metadata, not a shared global variable.
  5. Confusing idCheck and id semantics. The source id is set to FCUSTID with idCheck=false (because FCUSTID may be 0 in the Kingdee response). The target id is set to id with idCheck=true, relying on the MySQL primary key constraint for deduplication. The two sides have different semantics, do not mix them up.

Suitable and Unsuitable Scenarios

Suitable: ERP master data is centrally pushed to a data warehouse or middle platform, with a flattened structure, high-frequency incremental updates, and multi-organization isolation.

Unsuitable: when cross-system lookup is needed to enrich customer fields (in that case, add _findCollection on the source side), or when handling complex multi-currency, multi-language customer models. In the latter case, split into multiple strategies and land them separately.

Original content. Please credit the source when reposting: https://www.qeasy.cloud/insights/solutions/strat-mysql-kingdee-cloud-8096-mysql-81e07e3b

Comments