Supplier Account Sync in Practice: A Single-Strategy Implementation from DingTalk Approval to MySQL Master Data
What This Strategy Solves
At one retail group, supplier payment workflows run on DingTalk YiDa. Finance staff had to re-enter bank accounts, account names, and branch details from 'Create Supplier' approval forms into the MySQL reconciliation system by hand—repetitive work that routinely produced month-end mismatches. We used the Qeasy Data Integration Platform to deliver a single strategy that incrementally writes approved 'Create Supplier' instances into the MySQL supplier_account table, so that the moment an approval closes, reconciliation-ready data exists. This single strategy looks like simple form-to-table movement, but it is the foundation for straight-through bank reconciliation and month-end automation that follows.
Data Flow and Field Mapping
Data flow: DingTalk YiDa process instances (incremental) → Qeasy middleware layer (filtering, null-value fallback, code mapping) → MySQL supplier_account table.
Key field mapping:
| Target Field (MySQL) | Source Field (DingTalk YiDa) | Mapping Type | Notes |
|---|---|---|---|
| supplier_code | textField_kr3bzvp9 | DIRECT | Supplier code |
| account_type | selectField_kmtur42a | DIRECT / COLLECTION | Payment method; optional code mapping |
| account_name | selectField_kq8ryqku / textField_kquqiisp | TRANSFORM | Prefer dropdown; fall back to text |
| bank_branch | textField_kquqiisq / selectField_kq97ayh6 | TRANSFORM | Prefer text branch; fall back to dropdown |
| account | textField_kqvmf2oz | DIRECT | Bank account or Alipay account |
| source_Id | processInstanceId | DIRECT | Source-system primary key for reconciliation and write-back |
| status | 1 | CONSTANT | Enabled by default |
| create_time | createTimeGMT | DIRECT | Instance creation time |
| create_by | originator | DIRECT | Originator user |
How to Configure in Qeasy
For the source side, choose the DingTalk connector, use the QUERY action against v1.0/yida/processes/instances, set page size to 50, store the app ID and system token in the credential vault, and add searchFieldJson constraints for instanceStatus=COMPLETED and approvedResult=agree. Filter by a 'creation time range' for incremental extraction.
For the target side, choose the MySQL connector with the EXECUTE action. Write main_sql as a standardized INSERT template, using Qeasy's <{field}> placeholder syntax for each column. Enable idCheck so the platform checks for existence using source_Id and avoids duplicate inserts.
In the mapping layer we follow a pattern we often see in successful Qeasy rollouts: 'centralized code mapping.' Maintain DingTalk's payment-method options in a global code collection inside Qeasy. If the target system's coding scheme changes later, you update one mapping, not the SQL. Handle null-value fallback with _function expressions in the mapping layer so the SQL stays clean.
Implementation Steps
Step one, set the 'incremental anchor': in the source metadata change createFromTimeGMT from a fixed value to {{LAST_SYNC_TIME|datetime}} to achieve true incremental sync; backfill historical data once before go-live. Step two, run a 'full-load trigger': use a one-time full backfill script to push existing approved instances into the target table, and at the same time anchor LAST_SYNC_TIME to the go-live timestamp. Step three, enable 'staggered scheduling': set the source crontab to 20 1-8 * * * and the target crontab to 55 1-8 * * *, offset by 35 minutes to leave the reconciliation system room for transaction commits and index updates. Step four, wire up monitoring and alerts on three indicators—rows pulled, rows written, and idCheck hits—and alert whenever any indicator drifts from baseline.
Lessons Learned
First, writing null-value fallback directly in SQL is a classic mistake. On one engagement, a customer embedded case when straight into main_sql. The moment an account name contained a single quote, the SQL broke. The reliable approach is to use _function in the mapping layer and let SQL receive only clean parameters.
Second, idCheck must use the business unique key. In one case we took a shortcut and used the auto-increment id, which meant that re-running the same approval instance inserted duplicate rows. The correct approach is to use source_Id (i.e., processInstanceId) as the business unique key for deduplication.
Third, sub-table data is easy to miss. DingTalk's 'Payment Information' is the sub-table tableField_ks8du8cn. If you forget to enable buildModel, all account rows collapse into one. After enabling sub-table expansion, use sub-table path syntax to generate one account record per row.
Fourth, using a fixed timestamp as the incremental anchor is a common pitfall. A customer originally hard-coded createFromTimeGMT to the go-live date. After a data-fix exercise one week later, the fixed records were silently skipped. Switching to {{LAST_SYNC_TIME|datetime}} lets the platform continue from the last successful run automatically.
Fifth, do not put source filtering only in scripts. Filtering in AfterSourceInvoke is flexible, but by then the pull has already brought back unwanted data and wasted quota. Push instanceStatus and business-type conditions down into searchFieldJson so the filtering happens at the source.
When to Use and When Not to Use
Use this pattern when approval events are the system of record for master data, when the source side is singular and the field schema is stable, and when you need business-unique-key deduplication plus clear reconciliation write-back. Do not use it when source fields change frequently, when sub-table structures are not yet stable, or when complex merge-and-conflict rules are required—those cases are better served by event-driven real-time integration or bi-directional sync.