iVendNextDevelopers Request a sandbox

S45 — Restaurant back office (recipes off stock, allergens, food cost, sales by day part)

What the shop does

A café or restaurant rings its dishes at the till as it does today. A dish is a plain item that is not stocked, with the shop's own recipe on it: the engine's bill of materials, the parts and how much of each makes one dish (a recipe may hold another, such as a sauce made per portion). Once a day, after the close, the manager presses Issue ingredients on the app's settings record, and the ingredients of everything sold come off the kitchen's stock.

What happens When
One issue per store and day: the sales it takes up, every line of them (for the sales report), and the ingredients its dishes used. Then the shop's own Material Issue of those ingredients, from the store (or the kitchen store the settings name), dated at the day's last sale Issue ingredients pressed; each sale booked since the settings' start moment that no issue names yet
Nothing booked twice: an issue names its sales before any stock moves; a press again finds them taken a second press, a retry, a press that stopped half way
A sale made offline and posted later is taken up the next press after it posts (it looks back 7 days by default)
The issue is booked at the moment of the press instead of the sales' time the stock was booked in after the sales (a delivery entered late): at the sales' time the store was short
The issue reads Short, names every short part with what it needs and what the store has, and nothing of that store-day comes off the store is short of a part now too; the next press after a delivery or a count books it
The issue reads Refused, with the shop's own words the shop refuses the stock entry for another reason (a whole-unit ingredient used by half, a closed period): fix it and press again; the next press works the parts out again from the recipes as they are then. A manager may set a Short, Refused or Pending issue to Left out instead: its sales stay taken up and it is never tried again
The issue reads Refused with why, and nothing is booked a recipe goes round in a loop, or the sales name no store and the settings no kitchen store: fix it, and the next press works it out again
Work out food cost fills a food cost record: per ingredient, what the recipes used, what was sold as it is, what other issues took (waste, staff meals) and what the count found missing; the cost by recipe and the actual cost, each as a percentage of the period's sales the button pressed on a record naming a store and a period
Check allergens writes every finding to a check record and opens it: each ticked dish that leaves out an allergen one of its recipe's ingredients carries (at every depth, a stocked sauce's own recipe included), a variant with none of its template's allergens, a dish with none typed whose recipe carries none either, and any word not on the shop's allergen list. It changes nothing on an item the button pressed on the Item list or an item's form
The till shows a dish's allergens under its line, and the shipped receipt prints them under the item the shop adds two field rules in POS Studio to each theme its tills wear (setup step 6)
What the shop sees (on a demo shop, 2026-10-23)
A dish rung at the till: its allergens under the line
The receipt prints them under the dish
The company's settings: the start moment, the look-back, the kitchen store, the day parts
After Issue ingredients: the store-day's issue, Issued, its Material Issue and the ingredients it took
Sales by item: each sale's lines, net of tax, from the issues
Work out food cost on a store and a day: cost by recipe and actual, against sales
Check allergens: a dish that leaves out Milk, which its cheese carries

What it costs the shop. The ingredients are booked as any issue of stock: to each ingredient's own expense account (its Item Defaults, else its Item Group's, else the company's stock adjustment account). A shop that wants them under cost of goods sold sets that account on its ingredients' Item Defaults or their group; the app sends no account of its own.

Bounds, said plainly.

What the shop does to set it up

  1. Install manifest.json (the shop's administrator, on the install screen; on your sandbox, tools/deploy/deploy.py). It adds PP RBO Settings, PP RBO Issue, PP RBO Food Cost, PP RBO Allergen Check and their tables, the Allergens field on Item, the issue's link on Stock Entry, two reports, three buttons and their services (switched off), the feed registration PP RBO Back office feed and the role PP RBO Integration.
  2. In Role Permissions, give PP RBO Integration read on POS Invoice, POS Profile, Item, BOM, Bin, Stock Ledger Entry, Stock Reconciliation and Warehouse, and read, write, create and submit on Stock Entry. Stock Managers may already set an issue to Left out; no one may delete an issue (its sales would be taken up again). ⚠ With these rights the key can book a stock issue of any item in any store of the company: give the role to this app's user alone. If the shop limits back-dated stock entries to a role (Stock Settings), give that role to the app's user too, or every issue is booked at the press.
  3. Make the app's integration user with that role and generate its API key; choose it on the feed registration PP RBO Back office feed (leave the feed off).
  4. Make a PP RBO Settings record for each company: Issue sales booked from (now), the kitchen store where one kitchen cooks for several stores or brands (else each store's own), the day parts (Breakfast 06:00 to 11:00 …; a part whose end is before its start runs past midnight), and the allergen list (the EU's 14 to start).
  5. Give each dish its recipe: a Bill of Materials on the item, submitted and default. ⚠ The Desk form's item picker lists only stock items for the dish: type the dish's code. Give dishes and ingredients their Allergens.
  6. In POS Studio, on each theme your café's tills wear (save a shipped theme as a new one first), Fields: show pp_rbo_allergens on A line of the sale and on The receipt, labelled Allergens. For variants, type Allergens on each, or, where every variant has the template's allergens, add it to Item Variant Settings. A role you add to Check allergens also needs read on PP RBO Allergen Check, or Desk cannot open its findings.
  7. In Retail Extension Subscription, open each of the three services, read what it is sent, tick the consent and switch it on; switch the three buttons on in Retail Desk Action. For a hosted service, press Connect again on the app's package record.

What leaves the shop

The shop calls nothing outside but the service's own address (allowed_urls), on a press: the pressing user's login and language, and the record's name (with the company, or the food cost record's store and dates, or the items' names). The service then reads, with the app's own user: the company's till sales and their lines, the tills' stores, items and their recipes, stock levels, the stock ledger and counts for a food cost, and its own records. It writes: its issues and food cost records, the press stamp on the settings record, and the shop's Material Issues. It keeps nothing of a press.

Run it

python3 -m unittest discover -s samples/s45_restaurant_back_office/tests -p 'test_*.py'
python3 samples/s45_restaurant_back_office/tests/canaries.py

On a sandbox, with the integration user's key in service/.env.local (never committed: PP_BASE, PP_KEY, PP_SECRET, PP_SECRET_ISSUE, PP_SECRET_FOODCOST, PP_SECRET_ALLERGENS, handed back once at install as pp_rbo:sub:issue …):

python3 samples/s45_restaurant_back_office/service/app.py samples/s45_restaurant_back_office/service/.env.local

Many shops (the app template's handshake, chapter 14b): set IVN_LIBRARY_APP and a shops store; each shop's site connects itself to the app's one *.ivendnext.app address after its install and hands over its integration user's key once the shop presses Connect again. It only answers presses, so it runs as a function, paid per call.

Make it your own

A partner usually changes: the allergen list for its market (the settings record), the day parts, the reports' columns, and a schedule instead of a press (a container on its own hosting, or a function schedule where its host has one, calling the same issue). The prefix comes from RBO_PREFIX (PP RBO here; IVENDNEXT RBO for the App library's copy); tools/manifest/rename.py makes a copy under your own reserved prefix, and tools/deploy/copy_records.py moves the settings records.

Technical notes

What was proven where

Needs this serves

This page in the kit