Order Sync - Technical Reference

In this article

Order Matching Key

Sync Decision Sequence

Customer Matching and Guest Orders

Diagnosing Common Support Cases

This article documents the internal order de-duplication, matching, and customer-linking logic used by the Shopify Business Central Connector when it processes staged Shopify orders into Customer Orders. It exists to help support and development staff diagnose the two most common order-sync tickets: an order was created twice ("duplicate order"), or a change made in Shopify did not appear in Business Central ("order didn't update"). Every rule described below is taken directly from Codeunit 71079035 "LSC Shpfy Order" (procedure ProcessShopifyOrder) and Codeunit "LSC Shpfy Customer" (procedure GetContact). This is a technical companion to Order Management and Fulfillment; see that article for the end-user workflow steps.

Order Matching Key

Every incoming staged Shopify order (table Shpfy Order Header) is matched against Business Central Customer Orders using a single composite key, the External ID, built as:

StrSubstNo('%1 [%2]', ShopifyOrderHeader."Shopify Order No.", ShopifyOrderHeader."Shopify Order Id")

For example, a Shopify order with order number 1001 and internal Shopify order ID 5734567890123 produces the External ID 1001 [5734567890123]. This exact string is what the connector looks up - it is not the Shopify order number alone - so both the human-readable order number and the underlying Shopify order ID must match for two orders to be considered "the same order".

This key is checked, in order, against two tables:

  • LSC Customer Order Header."External ID" - open (not yet posted) Customer Orders.
  • LSC Posted CO Header."External ID" - Customer Orders that have already been posted.

Note: Because both tables are checked before a new Customer Order is ever created, a genuine duplicate Customer Order for the same Shopify order should not be possible as long as the External ID was written correctly when the order was first created. If a duplicate is reported, the first thing to verify is whether the External ID on the two Customer Orders is actually identical (that is, same Shopify Order No. and same Shopify Order Id) - see Diagnosing Common Support Cases.

Sync Decision Sequence

For every staged Shopify order processed by the scheduler job (or a manual Sync Order from Shopify), the connector runs the following decision sequence, in this exact order. Processing of one incoming order stops as soon as one of the "Result" actions below is reached; the connector then moves on to the next staged order.

Step Condition checked Result
1 An open LSC Customer Order Header exists with a matching External ID. The order already exists in Business Central as an open Customer Order. No new Customer Order is created. Instead, steps 1a-1d below run against that existing order, then the connector moves to the next incoming order.
1a - Cancel Shopify order's Cancelled At is not empty (0DT), and the Customer Order's CancelledOrder flag is still false. Full order cancellation is sent to LSCCustomerOrderCancelUtils. Whether or not the cancel actually ran (it's skipped if CancelledOrder is already true), processing for this order stops here - steps 1b-1d below are not evaluated once Cancelled At is set.
1b - Fulfill Shopify Fulfillment Status is Fulfilled or Partially Fulfilled, and the Customer Order's (calculated) Processing Status is not DELIVERED. "LSC Importing Order" is set to true and fulfillment/shipment handling runs (matches shipment lines, posts the Sales Order if configured). If Processing Status is already DELIVERED, this step is skipped entirely (no re-fulfillment).
1c - Edit Field/line differences are detected between the Shopify order and the Customer Order, and Processing Status = OPEN. The detected changes are applied via LSCCustomerOrderEditV2Utils (Edit Type General if any line changed, otherwise Header only). If Processing Status is not OPEN (e.g. already picked/shipped), the differences are still detected but the update is never applied - this is a key cause of "order didn't update" tickets.
1d - Cancel lines The edit check in 1c flagged one or more lines as cancelled in Shopify, and the header is still OPEN. Just those lines are cancelled via LSCCustomerOrderCancelUtils (partial/line-level cancel), independent of the full-order cancel in step 1a.
2 No open Customer Order matched (step 1 failed), but an LSC Posted CO Header exists with a matching External ID. Skip. The order was already fully processed and posted previously; nothing more is done for it.
3 No open or posted Customer Order matched, and the Shopify order's Cancelled At is set, or Closed At is not empty. Skip. Business Central never had this order open, and Shopify already considers it cancelled or closed, so no Customer Order is created for it at all.
4 - Create None of the above matched: this is a genuinely new, still-open Shopify order. A new Customer Order is built (header, lines, discounts, payments) and created via LSCCustomerOrderCreateV6Utils. On success, the Sales Order and Sales Lines are stamped with the Shopify Order No./Id, the Shopify staging record is stamped with the new LSC Customer Order No., and if the order arrived already fulfilled/closed in Shopify, fulfillment handling (step 1b's routine) runs immediately for it. On failure, the error is logged and the order is retried on the next sync (it still has no matching External ID).

Note:

  • Steps 1a-1d are only reachable when step 1 matches an open Customer Order - none of the edit/cancel/fulfillment logic ever runs against a posted order.

  • The scheduler only re-evaluates Shopify orders whose staging record has changed since the last run (filtered by SystemRowVersion against a per-shop/per-job checkpoint), not every staged order on every run.

Customer Matching and Guest Orders

While building the new-order data (GetCustomerOrderData), the connector looks up a loyalty member to attach to the order by calling LSCShpfyCustomer.GetContact. The result only ever feeds the Customer Order's Member Card No. field - it does not gate whether the order can be created. The lookup runs in this order:

  1. Match an LSC Member Contact by External ID = the Shopify Customer Id on the order.

  2. If not matched by Customer Id: if the Shopify order has no e-mail address at all, the lookup stops immediately and returns no card - the order proceeds as an order with no linked member (email is required to attempt the next match).

  3. If an e-mail address is present: match an LSC Member Contact by E-Mail = the Shopify order's e-mail.

  4. If a contact was found (by either Customer Id or e-mail): look up its LSC Membership Card (by Contact No. + Account No.) and return that card number. If the matched contact currently has no card, an empty card number is returned.

  5. If no contact was found by either Customer Id or e-mail:

    • If the shop's LSC Create Member setting is disabled: no contact is created and no card is linked - the order is created as a normal Customer Order with a blank Member Card No.. This is the effective "guest order" path; the code does not use the word "guest" anywhere, but functionally an unmatched customer with member-creation turned off is processed exactly like one.
    • If LSC Create Member is enabled: a new LSC Member Contact is created from the order's Bill-to fields (name, address, phone, e-mail) via LSCMemberContactCreateUtils, and the new card number is returned. If only one of First/Last Name is present on the order, the shop's LSC Contact Name Missing text is used to fill in the other, so the new contact is never saved with a blank name part.

Note: Guest checkout in Shopify (no Shopify customer account) does not by itself prevent order creation - it only affects whether a Member Card No. gets attached. As long as the order carries an e-mail address (or a Shopify Customer Id), and LSC Create Member is enabled, a new member contact can still be created and linked even for a "guest" checkout.

Diagnosing Common Support Cases

Report Where to look
"Duplicate order" - two Customer/Posted Orders for one Shopify order Compare the External ID on LSC Customer Order Header and LSC Posted CO Header for both records - it must be exactly <Shopify Order No.> [<Shopify Order Id>]. A mismatch here (for example a manually re-keyed order, or a record whose External ID was never set) is the only way two Customer Orders for the same Shopify order can exist, since both tables are checked before any new order is created (step 1 and step 2 of the Sync Decision Sequence).
"Order didn't update" - a change made in Shopify never appeared in BC Check the Customer Order's Processing Status. Edits are detected regardless of status, but only applied when Processing Status = OPEN (step 1c); fulfillment sync is likewise skipped once Processing Status = DELIVERED (step 1b). If the order has moved past OPEN (picked, shipped, etc.), further Shopify-side edits to that order are silently dropped by design.
"New Shopify order never appeared in BC" Check whether the Shopify order was already Cancelled or Closed by the time BC first saw it (step 3) - if so, it is skipped by design and no Customer Order is ever created for it.
"Order has no loyalty member / card attached" Check the shop's LSC Create Member setting and whether the order carries a Shopify Customer Id or e-mail address - see Customer Matching and Guest Orders.

See also

Order Management and Fulfillment - for end-user workflow steps.