This is the foundation every other Craftivus component depends on. Set this up first.
env/ already requires.bench new-site needs it. There's no way around this; know it before you start.Every customer gets their own site. For local development, one site is enough:
cd ~/frappe-bench
bench new-site pos.local \
--mariadb-root-password '<root-password>' \
--admin-password admin \
--mariadb-user-host-login-scope='%'
--mariadb-user-host-login-scope='%' replaces the older --no-mariadb-socket flag (deprecated, but functionally the same thing) — it lets the site's DB user connect from more than just the Unix socket, which local dev setups often need.
bench --site pos.local install-app erpnext
This alone gives you Company, Item, Warehouse, Price List, Customer, and every other doctype craftivus_core builds on. Do not skip running ERPNext's setup wizard (or manually creating the equivalent records) — a bare install-app does not seed Territory, Customer Group, Item Group, UOM, or Warehouse Type records, and several of craftivus_core's own patches and API calls assume at least a minimal set of these exist. If you hit LinkValidationError: Could not find Warehouse Type: Transit (or similar for Territory/Customer Group/Item Group/UOM) while setting up test data, that's this — create the missing root records once, and it won't recur.
# craftivus_core is its own git repo, branch version-16, no remote yet -
# get the source however your team currently distributes it, placed at
# apps/craftivus_core
bench --site pos.local install-app craftivus_core
bench --site pos.local migrate
This applies every patch in craftivus_core/patches.txt in order — the custom fields on Sales Invoice, POS Profile, Customer, Subscription Plan, and the doctypes (POS Device, POS Cashier, POS Shift, POS Correction, Craftivus Subscription State, and their child tables). Always run migrate again after pulling new craftivus_core code — new patches are additive and safe to re-run; already-applied ones are skipped automatically.
bench start
This runs the web server, the background worker, the scheduler, and (in dev) the asset watcher, all from one Procfile-driven process group. For local development this is normally all you need — don't run bench serve/redis manually alongside it, that leads to port conflicts (bench start already owns them).
If your bench serves multiple sites, bench start picks up common_site_config.json's default_site and pins every request to it unless you explicitly run it as bench --site "" start — the empty --site value is what enables genuine multi-site Host-header-based routing on the dev server. If you only ever run one site locally, you don't need to think about this at all.
curl http://localhost:8000/api/method/frappe.ping
# {"message":"pong"}
A working ERPNext site with craftivus_core installed — but no outlet configured yet. craftivus_core deliberately has no self-serve outlet-creation flow (see ADR 0001 — the customer never touches Desk, so someone has to set this up on their behalf). Before a till can activate against this site, you need, via Desk (/app) as Administrator:
Mode of Payment with type = Cash is the minimum for shift cash-reconciliation to mean anything).is_sales_item = 1 and an Item Price on your selling price list.status = Pending) — this pre-registers a till and generates the activation_code a real device will redeem. Create it via Desk; the activation code appears once you save.status = Pending, pos_role = Manager for at least one) — same idea, generates a setup_code a cashier redeems on the till.Once these exist, move on to Installation: Till to actually activate a device against this site.
| Symptom | Cause | Fix |
|---|---|---|
Access denied for user 'root'@'localhost' on bench new-site |
MariaDB root needs a password and you didn't supply one (or supplied the wrong one) | Pass --mariadb-root-password explicitly; there's no interactive prompt fallback in a non-interactive shell |
LinkValidationError: Could not find Warehouse Type: Transit (or Territory/Customer Group/Item Group/UOM) |
ERPNext installed without its setup wizard, so root taxonomy records were never seeded | Create the missing root record(s) once via Desk or frappe.get_doc(...).insert() |
frappe.exceptions.PermissionError from deep inside an ERPNext-internal call (get_mapped_doc, .cancel(), .submit()) |
That ERPNext function checks the calling session's permissions, and a device session intentionally has none | See Architecture: the session-swap pattern — this is an expected shape of bug, not a new one, if you're extending craftivus_core |
A newly added whitelisted method returns "not whitelisted" / PermissionError immediately after you add it |
Frappe's whitelist registry is cached | bench --site <site> clear-cache |
bench migrate fails with ModuleNotFoundError referencing a patch that looks concatenated with another (e.g. ...pos_fieldscraftivus_core.patches...) |
patches.txt got corrupted by an append (>>) that didn't respect a trailing newline |
Open the file and make sure every patch is on its own line |