Risk Supplier Reinstatement: Two-Phase Approval Sync Between DingTalk and Kingdee Cloud Cosmos
What This Strategy Solves
A retail enterprise manages risk suppliers by routing "reinstatement" through a DingTalk approval flow. Once approved, the supplier master data in Kingdee Cloud Cosmos must be flipped back from "disabled" to "active" and re-enabled for business use. It sounds like a simple status toggle, but in practice three headaches appear: the approval form only carries the supplier code (FNumber) while Kingdee's batchSave requires the internal FSupplierId; instance detail cannot be fetched through a plain list endpoint, you must iterate by instance ID; and the reinstatement step plus the downstream enable step are two independent writes — if their order slips, you get dirty states like "enabled before reinstated." This strategy, built on the Qeasy Data Integration Platform, turns the whole cross-system chain into a schedulable, observable two-phase pipeline.
Data Flow and Field Mapping
The flow runs DingTalk (process instance detail) → Qeasy middleware → Kingdee Cloud Cosmos (BD_Supplier). An upstream strategy calls topapi/processinstance/listids by template code and start time, writing processInstanceId values into a hub. This strategy, as phase two, references that upstream output via process_instance_id_strategy, and the platform loops over each process_instance_id to call topapi/processinstance/get for full details.
Key field mapping:
| Target (Kingdee) | Source / Rule | Mapping Type | Note |
|---|---|---|---|
| FSupplierId | _findCollection find FSupplierId from supplier hub where FNumber={{value}} | COLLECTION | Look up internal ID from the DingTalk form code |
| FBaseInfo | (empty object) | CONSTANT | Reinstatement fields filled later in the platform mapping |
| FormId | "BD_Supplier" | CONSTANT | Kingdee supplier business object |
| Operation | "batchSave" | CONSTANT | Execute batch save (reinstatement) |
| IsVerifyBaseDataField | true | CONSTANT | Enable base-data validation |
| IsAutoSubmitAndAudit | false | CONSTANT | Do not auto submit-and-audit; leave for downstream enable |
In the source response, value is a stringified form payload containing FNumber, and title typically looks like "XXX submitted risk supplier reinstatement." An AfterTargetInvoke script can use mb_substr to slice out the supplier name from the title prefix.
Configuring on Qeasy
For the Source side, pick the WebAPI adapter. Set API to topapi/processinstance/get, method=POST, effect=QUERY, take process_instance_id as the ID, enable idCheck and autoFillResponse. In the request body, set process_instance_id_strategy to the fixed upstream ID-pull strategy identifier, and use {{DAYS_AGO_s30|datetime}} for last_sync_time to define a 30-day incremental window.
For the Target side, pick the Kingdee Cloud Cosmos adapter. Set API to batchSave, type=EXECUTE. Hard-code FormId as BD_Supplier, Operation as batchSave, and keep IsAutoSubmitAndAudit false. The FSupplierId field must not be a constant — use a _findCollection expression that joins on FNumber={{value}} against the supplier master-data hub. This is the "centralized code mapping" pattern we see most often in Qeasy deployments.
Both schedules run inside business hours: source at 12 7-22 * * *, target at 22 7-22 * * * — ten minutes behind the source so the upstream IDs are already persisted.
Implementation Steps
- Incremental starting point: bring up the upstream ID-pull strategy first. Use
start_timepluslast_sync_timeto capture the last 30 days of processInstanceIds. Only enable this strategy after the hub contains rows. - Prepare the code hub: run the Kingdee supplier master-data query strategy once on Qeasy so FNumber→FSupplierId mappings land in the hub. Without this,
_findCollectionreturns nothing. - Full backfill: on first go-live, replay the backlog of the past 30 days and confirm SuccessEntitys in the Kingdee response carry valid Ids.
- Schedule cadence: one round per hour during business hours, paused at night — approvals rarely fire after hours.
- Downstream handoff: in the AfterTargetInvoke script, push SuccessEntitys,
value, andtitleinto the input queue of the enable strategy, enforcing "reinstate first, enable after."
Pitfalls We Have Hit
- Hard-coding the join field: a common mistake is mapping
FSupplierIddirectly to{{value}}. Kingdee then rejects with "primary key not found." Keep all cross-system code mappings inside_findCollectionand maintain the hub as a separate asset on Qeasy. - IsAutoSubmitAndAudit set to true by accident: once auto submit-and-audit kicks in, the downstream enable strategy loses the "pending enable" state and you end up with a supplier that is logically active yet still disabled. Keep it false and let the independent ExcuteOperation Enable strategy do its job.
- Schedules too tight between the two phases: source at minute 12 and target at minute 13 can cause this strategy to read an empty ID set before the upstream has finished writing. Offset by at least 10 minutes and add a "skip if upstream produced nothing" guard.
- value is a JSON string: some DingTalk forms nest FNumber inside a JSON payload. A direct lookup fails. Parse the value with
_functionor_mongoQueryfirst, then join. - Name extraction depends on title prefix:
mb_substr(title, 0, pos)only works when the title format is stable. If business owners change the template, the slice drifts. Better to surface the supplier name as a standalone form field.
When to Use and When Not to
Use it when approval flows drive master-data state transitions (reinstate, enable, disable) and cross-system identity can only be reconciled via business codes. Do not use it for strict two-phase-commit scenarios (this pipeline is eventually consistent), nor when the approval form has no supplier code at all and you are forced to fuzzy-match titles.