Qeasy Cloud
Get Started

Closed-Loop Sync Strategy: Pushing Audit Status from Kingdee Cloud to DingTalk Notifications

· 冯潇· Integration Solutions· 14 views· 5 min read

What This Strategy Solves

A common pain point on the ground is this: expense reports and payment requests start their life in a DingTalk approval flow. Once they get approved there, they are pushed into Kingdee Cloud for ledger posting. But finance still needs to run an additional audit step inside Kingdee before the document is truly settled. Applicants and approvers have no visibility into that second step and end up asking repeatedly, "Has my document gone through yet?"

This strategy is designed for exactly that scenario. It polls Kingdee Cloud on a schedule to retrieve the audit status of a given document. As soon as the status transitions from "unaudited" to "audited", it calls DingTalk's approval-flow comment API and posts a "has been audited" notice on the originating approval instance. The whole loop runs without anyone manually switching between the two systems. The Qeasy data integration platform takes care of translating a status change into a message that is visible on the DingTalk side.

Data Flow and Field Mapping

The chain can be broken into three segments: source system, middle layer, and target system. The source is Kingdee Cloud. The middle layer is Qeasy's own status record. The target is a DingTalk approval instance.

On the source side, we use King's executeBillQuery interface to pull out document number, entity primary key, document status, creator, and approver. Only three columns really matter: FBillNo (document number), FDOCUMENTSTATUS (document status), and FID (entity primary key). Other fields can be skipped in the first version and added later when you actually need to trace the responsible person. Keeping the mapping table thin at the start is healthier.

The middle layer on Qeasy does two things: translate the status codes returned by King into business-readable strings, and build an index keyed by document number that records the "last notified status" so we can detect whether a transition has actually occurred this round.

The target side calls DingTalk's topapi/process/instance/comment/add interface and attaches the comment back to the original approval instance. The request body only needs three fields assembled: the approval instance ID, the user ID to notify, and the comment text. Other DingTalk-native extension fields can stay at their defaults.

A key-field crosswalk looks like this:

MeaningKing sideMiddle layerDingTalk side
Document numberFBillNobill_no (index key)Embedded in comment body
Document statusFDOCUMENTSTATUSlast_status—
Approval instance ID(passed in or mapped externally)process_instance_idrequest.process_instance_id
Status change flag—status_changed (boolean)Trigger condition

How to Configure It on Qeasy

When configuring this strategy, keep the source-side metadata's idCheck set to true so that the platform uses the entity primary key for idempotent checks. That prevents the same document from being scanned repeatedly.

On the source side, set metadata.api to executeBillQuery, method to POST, and include FDOCUMENTSTATUS in the filter fields. In the request field list, only select the three fields that actually drive the decision: FBillNo, FDOCUMENTSTATUS, and FID. Leaving the rest unchecked noticeably reduces the size of the response payload.

On the target side, set metadata.api to topapi/process/instance/comment/add. The request structure is a nested object where request is a required object that holds three child fields: process_instance_id, userid, and comment. In Qeasy's field-mapping area, bind the middle-layer-derived process_instance_id to request.process_instance_id and bind a templated string such as "Your document {bill_no} has been audited" to request.comment.

A common pattern among Qeasy customers is to centralize all "King status code → Chinese description" mappings into one code table rather than scattering them across individual strategies. When approvers change or new status codes are added, only that one place needs editing.

Implementation Steps

Phase one is to stabilize the incremental starting point. Pick one real, already-audited document and manually enter its document number into Qeasy's "initially notified status" table. This prevents it from being misjudged as "transitioned from empty to audited" and triggering a notification right away.

Phase two is to trigger a full inspection. Manually run the source-side query once to pull every document with FDOCUMENTSTATUS = audited over a recent window and compare them one by one with the middle-layer index. If the comparison surfaces omissions, go back and check whether the filter condition is wrong or whether the source interface itself never returned that record.

Phase three is to enter the regular schedule. The source side uses */10 8-22 * * *, which means scan King every 10 minutes during business hours. The target side uses */6 8-22 * * *, which pushes every 6 minutes. The source scans less frequently than the target pushes because King's executeBillQuery carries call cost and there is no point scanning more often than we push.

Phase four is staged validation of header versus line items. Bring the header (the document's own status) online first. Only after a week of clean operation should you consider pulling in line-level status as well.

Lessons Learned from the Field

First, status-code comparison must use a "last status" cache. You cannot just check whether the current value is "audited". Without the cache, every time King re-saves a document, FDOCUMENTSTATUS will be returned again, and Qeasy will mistakenly think the status changed and fire another notice. The DingTalk side ends up flooded.

Second, the process_instance_id mapping has to be aligned with the originating strategy from day one. We once saw a project where the originating side used the DingTalk form ID while the lookup side passed the approval instance ID, and the comments ended up attached to the wrong instance. On Qeasy the recommended practice is to maintain a separate "DingTalk instance ↔ King document number" cross-reference table that both strategies share.

Third, scheduling windows have to align with business hours. The crontab on both source and target is constrained to the 8-22 window. No scans and no pushes happen overnight or on weekends. Without this constraint, the status King returns during its overnight daily close can be an in-between state. Qeasy would cache it as the real status and chaos would ensue the moment business resumes the next morning.

Fourth, DingTalk's comment API has a per-tenant rate limit. A schedule of 10-minute scans and 6-minute pushes is more than adequate for organizations with modest document volume. But once volume grows, the right move is to switch the target side to DingTalk's batch push API rather than calling the single-instance endpoint over and over.

Fifth, a typical mistake is to focus only on the document status itself while ignoring the approver field. Once a document is rejected and resubmitted, FDOCUMENTSTATUS goes through "audited → rejected → audited" repeatedly, and if Qeasy only watches the status code it will push over and over. The safe approach is to bring FAPPROVERID into the comparison too. As long as the approver has not changed, push only once.

When This Strategy Fits and When It Does Not

This strategy fits three-stage flows such as expense reports, payments, and reimbursement requests where the journey is "raise in DingTalk → post in King → audit in King". Document volume ranges from a few dozen to a few hundred per day, and the business is sensitive to status visibility. It does not fit scenarios where King has no clear "audited" status field, where the DingTalk flow has no commentable instance ID, or where volume is so high that even minute-level delay is unacceptable. In those last cases, event-stream integration is a better fit than scheduled polling.

Original content. Please credit the source when reposting: https://www.qeasy.cloud/insights/solutions/strat-kingdee-cloud-dingtalk-2294-n66e1d258-4827b8ba

Comments