Echoing Jushuitan Sales Order IDs Back to DingTalk Material Sample Approval: A Practical Sync Strategy
What This Strategy Solves
In one real project, a retail enterprise moved the "material sample requisition" process from paper forms into DingTalk OA: employees submit requests in DingTalk, and once approved, sales orders are auto-generated in Jushuitan and shipped out. After go-live we found that applicants returning to DingTalk only saw an empty approval—they had no idea whether the order had shipped, what the tracking number was, or who to contact. The customer asked us to "sync the order IDs over." That sounds like one sentence, but two real problems show up immediately: the Jushuitan side gives us business IDs (so_id / o_id / io_id), while DingTalk's comment API requires the approval instance's internal ID; and the same order may be modified several times, so naive re-syncs flood the approval with duplicate comments. This strategy is designed to reliably write the key Jushuitan order IDs back as comments on the right DingTalk approval, without errors and without spam.
Data Flow and Field Mapping
The data flow is Jushuitan → integration middleware (Qeasy / 轻易云 data integration platform) → DingTalk. The source is Jushuitan's single-order query (/open/orders/single/query); the target is DingTalk's approval instance comment API (topapi/process/instance/comment/add).
Key source fields: so_id (online order number), o_id (internal order number), io_id (outbound order number), l_id (logistics number), io_date (outbound time), status, modified.
Key target field mapping:
| Target Field | Source / Rule | Mapping Type | Notes |
|---|---|---|---|
| request.process_instance_id | _mongoQuery [DingTalk material sample requisition hub ID] findField=content.id where={"content.extend.business_id":{"$eq":"{{so_id}}"}} | COLLECTION | Reverse lookup approval instance ID by so_id |
| request.text | Concat: Online order:{{so_id}} Internal order:{{o_id}} Outbound order:{{io_id}} Logistics:{{l_id}} Outbound time:{{io_date}} | TRANSFORM | Comment body |
| request.file | Not passed | CONSTANT | Optional attachment |
The heart of the mapping is so_id → process_instance_id. The source only gives us a business ID, but DingTalk's comment API requires the approval instance's internal ID. We therefore use _mongoQuery against the upstream "DingTalk material sample requisition → Jushuitan sales order" strategy's hub, matching extend.business_id = so_id and returning content.id. If the extend structure is simple and contains no special characters, _findCollection is also a viable alternative.
How to Configure It in Qeasy
On the strategy editing page of the Qeasy data integration platform (轻易云), we usually follow these configuration points:
- Source component: WebAPI / QUERY mode, POST, with request body fields
modified_begin,modified_end,page_size,page_index,status. Setpage_sizeaccording to the vendor's per-page limit (the materials reference 25; verify against current vendor docs). SetidCheckto true and enableautoFillResponse. - Target component: EXECUTE mode, POST, API
topapi/process/instance/comment/add, primary key is theidreturned by DingTalk. - Code mapping: In the field mapping panel, set
request.process_instance_idmapping type to COLLECTION and fill in the_mongoQueryexpression above; setrequest.textto TRANSFORM with the concatenation template. - Idempotency: The comment API supports appending, so it does not de-duplicate natively. If the business cannot tolerate duplicates, add a
statusfilter on the source side so only shipped orders are echoed back, or use_functionto skip records whoseio_idis empty.
Implementation Steps
- Confirm the upstream linkage: Make sure the upstream strategy (DingTalk → Jushuitan) has already written
extend.business_idinto the Jushuitan order asso_id. This is the prerequisite for the reverse lookup. - Set the incremental anchor: Set source
modified_beginto{{LAST_SYNC_TIME|datetime}}andmodified_endto{{CURRENT_TIME|datetime}}, keeping the window within 7 days. - Run a small pilot: First run with a one-day window and verify that
_mongoQueryconsistently hits the approval instance ID and the comment text matches expectations. - Trigger a one-off full pull: Shortly after go-live, manually backfill historical data to cover recently shipped orders so older approvals are not left empty.
- Configure scheduling: Source crontab
1-59/9 7-23 * * *(every 9 minutes); target crontab1-59/10 7-23 * * *(every 10 minutes). Stagger the two so they do not pile up. - Monitoring and alerts: Turn on the log panel in Qeasy and watch two specific anomalies: "lookup returned no result" (usually means the upstream did not write
so_id) and "comment write failed" (usually means DingTalk access token expired).
Lessons Learned (Field Notes)
- Classic mistake: passing
so_iddirectly asprocess_instance_id. The DingTalk API will not error out; the comment simply lands on a non-existent instance and the applicant never sees it. The safe move is to validate_mongoQueryresults in a test environment before going live. - Type mismatch on
extend.business_idbreaks the match. If the upstream writesso_idas a string but the_mongoQuerycondition forgets the quotes, MongoDB type comparison fails silently. Always write{"$eq":"{{so_id}}"}, not{"$eq":{{so_id}}}—this small detail is where most rollbacks happen. - Window over 7 days gets rejected by the source. Jushuitan explicitly requires the time span to be within 7 days. If the schedule is paused and resumes, the first batch may fail. A common pattern at customer sites is a hard cap of "look back at most 6 days"—better to lose data than to violate the window.
- Duplicate comments flood the approval. The comment API allows multiple appends, so every order modification triggers another echo. Common remedies: only echo for shipped orders, or use
_functionto comparemodifiedagainst the last echoed timestamp and skip when unchanged. - No scheduling stagger. Source every 9 minutes, target every 10 minutes looks asynchronous but can still collide under load. A typical pattern we have seen at customer sites is to start with source 9 / target 10 minutes, then adjust based on log volume.
When to Use and When Not to Use
Use it when: approvals drive sales orders and the approval side must surface order fulfillment IDs; the order side has clear business IDs that can be reverse-mapped to approval instance IDs. Do not use it when: the requirement is to write back into DingTalk approval form fields (rather than comments); when structured multi-line detail rows must be echoed; or when the approval instance is already archived or deleted and can no longer accept comments.