Production orders
Route: /org/inventory/production · Module: org_inv_production — 6 permissions
Permission to view: View Production and Manufacturing Trends
1. What production is
Turning raw materials into finished goods. A production order says make 20 of this variation, pulls its bill of materials, and — on completion — posts the whole movement to the ledger in one go.
The screen's own subtitle states the contract: "Manufacture finished goods — auto-consumes raw materials per BOM on completion."
2. How an order moves
| Status | Editable | Can complete | Can cancel |
|---|---|---|---|
| DRAFT | ✅ quantity and ingredients | ✅ | ✅ |
| COMPLETED | ❌ | ❌ already done | ❌ ledger already posted |
| CANCELLED | ❌ | ❌ | idempotent — cancelling again is a no-op |
The exact refusal is completed orders cannot be cancelled — ledger already posted. Completion
writes real ledger rows; reversing them would mean deleting audit history.
To correct a completed run, post a compensating adjustment. Both entries stay visible.
3. Creating an order
Two inputs only.
Finished Good to Produce — a variation, not a product. The recipe belongs to the variation.
Planned Quantity — defaults to 1, must be greater than 0.
The button says CREATE AS DRAFT, and that is not a choice: CreateProductionOrder always sets
status DRAFT.
What happens on create
For every BOM line on that variation, the app stores an ingredient row:
planned ingredient quantity = BOM quantity_required × planned_quantity
From this moment the order carries its own ingredient list. Editing the BOM afterwards does not change orders already created — which is what makes a historic order auditable.
Nothing warns you. The order is created, it completes happily, and it posts a PRODUCTION_IN row
with no corresponding consumption — finished goods appearing from nowhere.
4. Reading the list
| Column | Notes |
|---|---|
| Order | The first 8 characters of the order UUID, e.g. #fb75ec9f |
| Finished good | Product name, variation and SKU |
| Planned / Produced | Produced stays 0 until completion |
| Status | The pill |
| Created | Do not use — see below |
| 👁 | Opens the detail drawer |
It reads 01 Jan 0001, 00:53 for every order — visible on all five rows in Figure 3. The list query never selects created_at, so the
zero value is serialised and rendered.
The same query orders by o.id DESC — by random UUID, not by date — so the list is not in
chronological order either. Use the detail drawer's Completed timestamp, which is correct.
5. Permissions — and what the UI does not check
| Action | Permission |
|---|---|
| View | production.view |
| Menu | production.menu |
| Create | production.create |
| Edit a DRAFT | production.edit |
| Complete | production.complete |
| Cancel | production.cancel |
New Production Order, Complete and Cancel all render for anyone holding
production.view. The API enforces the real permission, so the user meets a failure instead of a
hidden control. See Permissions.
6. The admin contract
| Must be true | Or else |
|---|---|
| A project is selected | The list is empty |
| The variation has a BOM | The order consumes nothing on completion |
| Raw materials exist with units | The BOM cannot exist in the first place |
7. Troubleshooting
| Symptom | Cause |
|---|---|
| List is empty | No project selected |
All Created dates read 01 Jan 0001 | Known defect — see §4 |
| The list is in a strange order | It is ordered by UUID, not date |
| Cannot cancel an order | It is COMPLETED — the ledger is posted |
| Completing produced no consumption rows | The variation had no BOM |
| Edit is refused | Only DRAFT orders can be edited: only DRAFT orders can be edited (current: …) |