dodil/erp-brick-inventory

DODIL ERP brick: inventory

README.md

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