iVendNextDevelopers Request a sandbox

S7 — a system sync: a customer's own ERP, order system or warehouse system in step with iVendNext

This sample keeps a customer's own back-office system in step with iVendNext. Items, prices and stock go out to the shop; booked sales and returns come back, once each; a nightly report names anything the two disagree on. It is for a developer who connects a large customer's ERP, order system or warehouse system to their shops.

Runs outside the shop, over the record API and the event feed (recipes/event_feed.md); written up as a recipe: recipes/system_sync.md.

When to use it: another system is the master for items, prices or stock, and it must also learn of every sale.

How it works

  1. Out: items, prices and stock — only what changed since the cursor — are written to the shop.
  2. In: booked sales and returns are read from the event feed and written to the ERP, once each.
  3. Reconcile: a nightly, read-only report, by name, of anything that differs. It never fixes anything.

The files

File What
erp.py the customer's ERP as a stand-in: a SQLite file with items, prices per price list, stock movements, the orders and returns it is told about, and a numbered change feed
sync.py the sync: out (items, prices, stock — only what changed since the cursor) · in (booked sales and returns, once each, from the event feed) · reconcile (a nightly, read-only report by name) · the identity map
tests/test_s7.py 18 tests that run on a laptop: the sync against an in-memory shop and feed

Run it

No screen shows a sync working, so here is the command. What a test run printed is under Technical notes.

SYNC_KEY=… SYNC_SECRET=… python3 samples/s7_system_sync/sync.py run --base https://shop.example --app "My Sync" --erp erp.sqlite --state sync.sqlite …

Before you build on it

When the sync stops halfway

Restart it. Each write to the shop is found again by its own key, so a crash between the write and the cursor does no harm: nothing is lost and nothing is doubled. Each sale arrives once.

Technical notes

The tests

File What
tests/test_s7.py 18 laptop tests, no bench: the sync against an in-memory shop and feed
our test bench's own run (not in the kit) the bench tests: a full cycle, a crash on the way out and on the way in, a return, a deleted item, three reconciliation canaries; and the money-kit run with the sync running

What our test bench's run printed

No screen of ours shows a sync working, so here is the command and what our test bench's run printed (2026-10-07, 29 of 29 checks; the run's own words, trimmed):

== T1 a full cycle: items, prices and stock out; sales in; the books agree
PASS T1 out wrote 4 items, 4 prices and 4 stock entries
PASS T1 a second out writes nothing (the cursor is at the end)
PASS T1 the three sales are in the ERP, once each
PASS T1 the ERP's stock fell by what was sold, and equals the shop's
== T2 the sync stopped mid-batch on the way OUT, restarted: nothing lost, nothing doubled
PASS T2 every ERP movement is in the shop exactly once (8 movements, 8 entries, no key twice)
PASS T2 stock on hand: ERP == shop (10 + 15 − 3 = 22 on both sides)
== T6 the reconciliation can fail — it names what differs, and it never fixes anything
PASS T6 canary: a total that is one unit off is named with both figures

Why this way (R6)

The 10-line version (a script that copies every item and sale each night) — rejected: a lost or doubled record is exactly what a large customer cannot afford, and a full copy cannot say which. A cursor and a key per write (picked, ~330 lines): each write to the shop is found again by its own key, so a crash between the write and the cursor does no harm; each sale arrives once because the feed's seen-set and the ERP's unique invoice number both say so. A queue service between the two — rejected: a second thing to run and lose records in.

Bounds

One instance per ERP per shop — the sync takes no lock (recipe, Bounds). Not used, because it has not shipped: a feed key scoped to one application (P-FEED) — the sync uses today's integration-user grant, which the recipe says cannot be scoped; a payment-time check (P-CHECK). Never done: a stock figure is a Stock Entry the engine books, never a number the sample sets; a price is written to the price list, never onto a sale.

This page in the kit