Shopify–ERPNext integration acceptance test pack Companion to https://harmatiq.com/insights/ecommerce-erp-integration/ Reviewed 24 October 2026. Review it again before launch and after any connector, ERPNext, Frappe or Shopify application programming interface (API) change. What this pack is for A connector can report success and still create the wrong business result. An order may appear twice after a retry. Stock may reach the wrong Shopify location. A refund may increase stock before the item comes back. Use these files to test those outcomes with real records in a safe test environment: - This file explains what to prepare, what to test and who signs off. - Test cases: https://harmatiq.com/assets/shopify-erpnext-acceptance-test-cases.csv - Who-owns-what matrix: https://harmatiq.com/assets/shopify-erpnext-system-of-record-matrix.csv Every CSV test starts as NOT RUN. Change it to PASS only after you have seen the expected Shopify and ERPNext records. Mark it FAIL when the result is wrong. Use NOT IN SCOPE only when a named owner approves the exclusion and records why. Attach evidence without customer details, payment data or credentials. What this pack is not It is not a claim that every flow below comes with the connector. It is not a report from an installed Shopify shop and ERPNext site. Reading documentation and source code can tell us what to test, but it cannot create a PASS result or approve a launch. Which code was reviewed? The main reference is Frappe ecommerce_integrations 1.20.3 at commit ff9364dbab1a06bdcd4118dd2898a63c75421f14, committed on 29 April 2026. Its project file declares Frappe and ERPNext 15 support, not 16. We also checked the newer develop branch at commit 7bf1d7f7587081c24610b0ae5562d90f891512d4 on 24 October 2026. It contains different authentication work. Do not treat main and develop as interchangeable. Record the connector commit installed on your ERPNext site and test that exact version. The source links below point to the exact main commit, so they will not change when the repository changes. 0. First, write down exactly what you are testing [ ] Frappe version/commit: ____ ERPNext version/commit: ____ Connector version/commit: ____ Custom apps/patches: ____ Shopify app type and permissions (access scopes): ____ Shopify software development kit (SDK) version: ____ Test shop and location IDs: ____ Test date/environment: ____ API version requested by the connector: ____ API version Shopify returned in the response: ____ API version on the webhook (automatic Shopify message): ____ What we found in the code: constants.py requests Shopify API version "2024-01". Shopify may serve another version when an old version is no longer available. The requested version is therefore not proof of the version your test shop received. Record Shopify's response and webhook headers, then run the cases against that version. Stop the release if the version changed and nobody has checked the behavior. Evidence: https://github.com/frappe/ecommerce_integrations/blob/ff9364dbab1a06bdcd4118dd2898a63c75421f14/ecommerce_integrations/shopify/constants.py https://github.com/frappe/ecommerce_integrations/blob/ff9364dbab1a06bdcd4118dd2898a63c75421f14/pyproject.toml https://shopify.dev/docs/api/usage/versioning 1. Agree who owns each record before switching the sync on [ ] Product and variant: which system owns the identity and mapping? ____ [ ] Customer and order: which Shopify IDs must appear on the ERPNext records? ____ [ ] Stock: which ERPNext warehouse feeds each Shopify location, and what counts as sellable? ____ [ ] Paid order: should ERPNext create an invoice, a payment record, both or neither? Finance approval: ____ [ ] Shopify fulfilment: should ERPNext create a Delivery Note? Warehouse approval: ____ [ ] ERPNext dispatch: should it send fulfilment and tracking back to Shopify? Where has that path been proved? ____ [ ] Refund and return: who owns the credit, payment refund, physical receipt and inspection? ____ What we found in the code: the reviewed event list handles created, paid, fulfilled, cancelled and partially fulfilled orders. It does not include a refund-created event. Code that receives Shopify fulfilments does not prove that ERPNext can send shipment and tracking updates back to Shopify. Entries for another connector, Unicommerce, are not Shopify features. Keep the Shopify order ID, order number, variant mapping and original line identity on the ERPNext records. Test similar product titles, repeated SKU lines, discounts, tax, shipping and currency rounding. An ERPNext invoice or payment record does not prove that the gateway payout reached the bank; finance still needs a separate settlement check. https://github.com/frappe/ecommerce_integrations/blob/ff9364dbab1a06bdcd4118dd2898a63c75421f14/ecommerce_integrations/shopify/order.py https://github.com/frappe/ecommerce_integrations/blob/ff9364dbab1a06bdcd4118dd2898a63c75421f14/ecommerce_integrations/shopify/invoice.py 2. Test locations and quantities [ ] Map each Shopify location to one intended ERPNext warehouse. Put the same SKU at two locations with different quantities. Confirm that each Shopify location receives only its own quantity. [ ] Send a fulfilment from a location with no warehouse mapping. The reviewed code can fall back to the default warehouse. Either prove that fallback is correct for the business or block the record. Posting to the wrong warehouse is a failure, even if the log says success. [ ] Reserve the same SKU for Shopify and another sales channel. Confirm that the sellable quantity removes each reservation once, not twice. Keep quarantined and safety stock separate unless the agreed formula says otherwise. [ ] Test fractional quantities, a negative source balance and a conversion from packs or cases into individual units. Record the number Shopify receives and the rounding rule the business approved. Reject unsupported fractions rather than quietly changing an order quantity. What we found in the code: the inventory path converts on-hand and reserved quantities to integers separately, then subtracts reserved from on-hand. It does not contain a complete business rule for quarantine, safety stock or every other unavailable state. Test the exact numbers on the installed Frappe build, especially fractions and negative balances. The connector runs stock updates on a configured schedule. The documentation's 30–60 minute suggestion is not a promise that every update will arrive in that time. Agree how old the Shopify quantity may be and who gets alerted when it is older. https://github.com/frappe/ecommerce_integrations/blob/ff9364dbab1a06bdcd4118dd2898a63c75421f14/ecommerce_integrations/shopify/inventory.py https://github.com/frappe/ecommerce_integrations/blob/ff9364dbab1a06bdcd4118dd2898a63c75421f14/ecommerce_integrations/controllers/inventory.py https://docs.frappe.io/erpnext/shopify_integration https://shopify.dev/docs/apps/build/orders-fulfillment/inventory-management-apps/manage-quantities-states 3. Test two shipments against one order [ ] Place a ten-unit Shopify order. Fulfil four units at mapped location A, then six at B using distinct fulfilment IDs. Turn on `sync_delivery_note`, the connector setting that creates ERPNext Delivery Notes from Shopify fulfilments. Expect one ERP Sales Order and separate Delivery Notes for 4 and 6, linked by order and fulfilment IDs. Open quantity after the first shipment must remain six. [ ] Resend the first Shopify fulfilment after ERPNext has created its Delivery Note. No second Delivery Note or stock deduction should appear. Also send two copies at nearly the same time; a serial retry is the easier case. [ ] Repeat with two order lines that use the same item code, different discounts, and an edited order. Confirm that quantities stay attached to the right source line. Matching only by item code may not be enough. What we found in the code: the reviewed path can turn Shopify fulfilments into ERPNext Delivery Notes and checks for an existing Shopify fulfilment ID. That is useful, but it does not prove that simultaneous copies are safe, that order edits are handled correctly, or that a cancelled shipment is reversed. It also does not prove the opposite direction, where an ERPNext dispatch sends tracking back to Shopify. Test or build those paths separately when the business needs them. https://github.com/frappe/ecommerce_integrations/blob/ff9364dbab1a06bdcd4118dd2898a63c75421f14/ecommerce_integrations/shopify/fulfillment.py 4. Cancellation, refund and physical return are different tests [ ] Cancel an unfulfilled, uninvoiced Shopify order. Expect cancellation of its submitted ERP Sales Order and no remaining reservation. Confirm actual stock did not change. [ ] Cancel after a Delivery Note or Sales Invoice exists. Expect the Shopify financial status copied to linked ERP documents, NOT automatic reversal. A named operator must create/approve the required cancellation, credit or return records under the business's policy. [ ] Refund two units of the ten-unit order without physical receipt. Expect the refund/credit reconciliation to identify the original order, amount/tax and payment reference; warehouse stock must not increase. [ ] Receive the two units into quarantine later. Expect a separate receipt/return document, quarantined quantity two, available unchanged until inspection and approved disposition. What we found in the code: cancelling in Shopify can cancel the ERPNext Sales Order only when no invoice or delivery exists. If later records already exist, the code updates status fields instead of reversing those records. The reviewed event list has no refund handler. Do not assume that the connector creates a credit note, sends money back through the payment provider or decides what to do with returned stock. Use an approved manual process or a separately tested integration for each required step. https://github.com/frappe/ecommerce_integrations/blob/ff9364dbab1a06bdcd4118dd2898a63c75421f14/ecommerce_integrations/shopify/order.py 5. Prove that retries and late messages do not damage records [ ] Deliver the identical orders/create webhook three times, then concurrently. Expect ONE linked Sales Order and no duplicate customer/item/financial effects. Keep source event IDs, destination IDs and counts as evidence. [ ] Deliver the paid or fulfilled message before the order-created message. The reviewed code records an error when it cannot find the Sales Order. After the order appears, prove that the team or recovery job can pick up the failed message and apply it once. An error log on its own is not recovery. [ ] Deliver an old status after a newer one. The order must not move backwards or bring a cancelled order back to life. If the integration cannot compare versions or timestamps, document how staff will catch and correct the case. [ ] Simulate a timeout after ERPNext has saved the record, a Shopify rate limit, expired credentials and a stopped worker. Recovery must find the record already created and continue without making a second order, invoice, Payment Entry or Delivery Note. Send unknown SKUs and tax mappings to a named person instead of retrying them forever. [ ] Drop one webhook completely. A separate comparison between Shopify and ERPNext must find the missing record within ____ minutes/hours and alert ____. [ ] Send one valid and one invalid webhook signature. Reject the invalid one. Check that logs do not contain secrets or customer data the operator does not need. What we found in the code: the webhook receiver checks the signature, logs the request and sends the work to a queue. It does not contain one general safeguard for duplicate webhook IDs or messages arriving in the wrong order. Later functions do check whether some orders, invoices or Delivery Notes already exist, but those checks are narrower than a promise that every retry is safe. Test what happens when two copies arrive together and when ERPNext saves a record just before the connection times out. Shopify says webhooks can arrive out of order and recommends a separate comparison job rather than relying on delivery alone: https://shopify.dev/docs/apps/build/webhooks/best-practices https://github.com/frappe/ecommerce_integrations/blob/ff9364dbab1a06bdcd4118dd2898a63c75421f14/ecommerce_integrations/shopify/connection.py 6. List what the connector does not cover Do not sign off because the Shopify and ERPNext logos appear on the same screen. Refunds, credits, return inspection, tracking sent from ERPNext to Shopify, bundles, fractional selling units, unusual price or credit rules, multiple legal companies, edited orders and warehouse mappings may need more work. Product upload also has documented limits around variants, templates and imported data. For each gap, record the owner, the agreed manual step or custom work, and the test that must keep passing after an upgrade. 7. Hand the process to the people who will run it [ ] The commerce owner approves Shopify access and order behavior. The warehouse owner approves locations, quantities and returns. Finance approves invoices, payments, tax and credits. The integration owner approves recovery, the regular Shopify-to-ERPNext comparison and alerts. [ ] Attach actual record IDs and before/after evidence for every required test. Resolve unexplained differences. A source-code review is not a passing test report. [ ] Handover includes the field and warehouse mappings, deployed code/configuration versions, a safe way to rotate credentials, alert destination and comparison schedule. [ ] Handover also includes step-by-step recovery instructions, permissions, rollback steps and the tests to rerun after an upgrade. Do not put tokens in this document. [ ] Agree business-hours/coverage, incident channel, response targets and who changes vendor apps, hosting and custom code. No 24/7 or real-time commitment is implied. [ ] Rehearse one failure and one replay with the operator who will own it after launch. Test result record (copy for each case) Case ID: ____ Environment/date: ____ Tester: ____ Input/source IDs and timestamps: ____ Expected Shopify records/state: ____ Expected ERP records/state: ____ Observed records/quantities/values: ____ Evidence location (redacted): ____ PASS / FAIL / NOT IN SCOPE: ____ Gap/resolution owner: ____ Retest: ____ Final signoff Commerce owner/date: ____ Warehouse owner/date: ____ Finance owner/date: ____ Integration owner/date: ____ Unresolved blockers: ____ Approved exclusions: ____ Release approval belongs to the business owner; this document does not grant it.