Qeasy Cloud
Get Started

Writeback Sync Status to CRM: A Closed-Loop Strategy in Practice

· 何海波· Integration Solutions· 26 views· 4 min read
小满OKKICRMWDTCRM与ERP集成状态反写轻易云销售订单闭环同步

What This Strategy Solves

On a real customer project, after orders were pushed from the CRM to the order system, sales reps still saw "unsynchronized" in the CRM every day and had to switch to another backend to compare records. The actual job here is plain and simple: take the orders that the order system has confirmed as synchronized, and write the "synchronized" status back to the corresponding sales orders in the CRM, so that reps can see the closed-loop result right inside the CRM.

Data Flow and Field Mapping

The data flow of this strategy is "order system → Qeasy middle layer → CRM". It is essentially a status writeback action, not a master-data downstream push.

The source (order system) pulls the self-operated order list through the WebAPI sales.RawTrade.searchSelfOrder. The paging parameter and business parameter go into the params object body. The key fields in the response are tid (order number) and rec_id (record primary key), which together form the idempotency key.

The target (CRM) execution endpoint is /v1/invoices/order/push. The request body contains two key fields: order_id and a custom field representing the "ERP sync status". order_id is not directly passed from the source system's tid; instead, it uses _findCollection to look up the CRM-side order primary key in the intermediate table produced by the previous "sales order sync" strategy by tid; the status field directly writes the constant string "已同步" (synchronized).

RoleFieldSource/ValueNotes
Sourcetidorder system responseoriginal order number, used as the lookup key
Sourcerec_idorder system responseprimary key, idempotent de-duplication
Middle layerorder_no → id mappingprevious strategy output_findCollection association
Targetorder_idfrom middle layerrequired in edit scenario
Targeterp sync statusconstant "已同步"status writeback field

How to Configure on Qeasy

We use the Qeasy data integration platform to handle this lightweight closed loop. There are several configuration points worth elaborating on.

First, attach this strategy as downstream of the previous main sync strategy, and explicitly declare the depends_on relationship to avoid a race condition where the main order has not yet landed in the middle layer but the writeback has already started.

Second, on the source side, set metadata.number to tid and id to rec_id, and enable idCheck to prevent the same order from being written repeatedly. Keep autoFillResponse enabled so Qeasy automatically assembles paging and parameters.

Third, the value of the target-side order_id field should not be hard-coded. Use the _findCollection find order_id from <previous strategy id> where order_no={{tid}} syntax to centrally manage the order-number-to-CRM-primary-key mapping. This is a common pattern among Qeasy customers: centralized encoding mapping management, which avoids hard-coding IDs in the strategy.

Fourth, the status field value is directly written as the constant "已同步". If you later need to distinguish between "sync success / partial success / failure", it is recommended to upgrade this column into an expression rather than a hard-coded string.

Fifth, for scheduling, the source-side pull is configured as 1-59/10 6-23 * * * (every 10 minutes with a non-zero offset), and the target-side writeback as 8-59/10 6-23 * * * (offset by a few minutes). This "staggered + offset" approach prevents both ends from hitting the API at the exact same second.

Implementation Steps

Step 1: stabilize the previous "sales order sync" strategy first, ensuring the intermediate table has the order_no → id mapping data. Step 2: create the new strategy in Qeasy, with the source pointing to searchSelfOrder of the order system and the target pointing to /v1/invoices/order/push of the CRM, and explicitly mark strategy_type=EXECUTE. This is not a SYNC; it is a single-sided execution. Step 3: do a one-time full writeback (manually triggered) to backfill the status of historical synchronized orders and establish a baseline. Step 4: spot-check 20-30 orders in the CRM against the full writeback result; after confirmation, switch to incremental. Step 5: set the incremental starting point to "source return timestamp > last successful time", with a scheduling frequency of every 10 minutes and staggered offsets. Step 6: observe the logs for one week, focusing on the number of idCheck hits and the details of writeback failures.

Lessons Learned from the Trenches

First, directly passing the source system's tid as order_id is a typical mistake. The CRM order primary key and the order system's order number are two different systems and must be looked up through the intermediate mapping table; otherwise the CRM will fail to find the order, or the write will target the wrong object.

Second, running the strategy without setting depends_on. The consequence is that while the main sync has not yet landed in the middle layer, the writeback strategy has already started looking up IDs by tid. When the lookup fails it writes empty values, the CRM status does not change, and the rep assumes the sync failed while the main document is still in transit. The safe approach is to explicitly declare upstream and downstream dependencies.

Third, hard-coding the status field as "已同步". In the second month after going live, the business side requested distinguishing between "partially shipped" and "fully shipped". It took a whole day to refactor the code. If an expression or mapping table had been used from the start, only one place would need to change.

Fourth, using the same on-the-hour schedule for both source and target (for example, both */10 * * * *). When instantaneous concurrency spikes, the CRM throttles and the batch returns 429. Here we adopted the "incremental and full dual-track + staggered offset" approach: source 1-59/10, target 8-59/10, spreading out simultaneous concurrency.

Fifth, choosing the wrong idempotency key. Initially we used rec_id as the idempotency key. As a result, when an order failed to write back and was retried, rec_id did not change but the status indeed was not written, so the retry logic was ineffective. After switching to a composite idempotency key of (tid + status field), retries became stable.

Applicable and Non-applicable Scenarios

Applicable: CRM-to-order/ERP system integration where the CRM side needs to display sync results or trigger subsequent business processes (such as pushing delivery orders downstream or closing orders). Non-applicable: when the content to be written back exceeds a single status field (for example, writing back tracking numbers or detail line items). Such scenarios should use a full SYNC strategy rather than a single EXECUTE status writeback.

Original content. Please credit the source when reposting: https://www.qeasy.cloud/insights/solutions/strat-okkicrm-wdt-7404-n9f9cf921-e51e2f02

Comments