erp-brick-inventory
Where every item is and how many you have: warehouses and their shelves, goods received from suppliers, picked and delivered to customers, moved between shelves and sites, and counted, with every movement recorded so the quantity on a shelf and the value of the stock always add up, and nobody sells the last unit twice.
Built from the inventory module spec (erp-method modules/inventory/module.yaml, version 3, namespace inv, tables inv_).
Read AGENTS.md before changing anything.
- Stock is a ledger. Every quantity that moves is an append-only move from one place to another, in the product's BASE unit,
converted exactly by product's
GET /products/{id}/convert(numerator / denominator kept beside it). On hand is the sum of the moves, derived on read, never a stored number somebody edits. A mistake is a reversing move. - The last unit goes to one writer. Every move out of a stock-holding place, and every reservation, claims a row with a plain
INSERT on a key the other writer needs too (
inv_claim); the loser gets 23505, re-reads and is refused or retries. - Value is average cost per product per company, appended per move (
inv_valuation), or standard cost if the owner chooses. The move that empties a product takes the remaining value, so zero quantity is zero value. - Neighbours are called by their spec routes: product (convert, units used), purchasing (the ONE way a receipt is recorded; it
posts each line back here), sales-order (
record_delivery, reservations), gl (POST /journal-entry/journals).
python -m venv .venv && .venv/bin/pip install -e ../erp-platform -e '.[test]'
.venv/bin/pytest -q --tb=short
.venv/bin/ruff check src tests
.venv/bin/python scripts/gen_schema.py # schema.sql + migrations/00001_init from infrastructure/tables.py