PRD: Bill of Materials
| Module | Inventory | PRD ID | PRD-BOM-001 |
| Status | No item | FEAT | BOM |
| Epic | — | Plane | — |
| Date | 2026-07-13 | Version | v1.0 |
| Packages | @nx/inventory | URD | BOM |
| Surface | Client · Owner/MgrSale · POS | ||
| Owner | Phát Nguyễn | ||
What a bill of materials is
A bill of materials (Recipe) is the quantity sheet of one item: one glass of milk tea takes 50ml of milk, 5g of tea, 30g of pearls. The owner writes it once on the Bill of Materials screen in the Inventory area of a merchant (Merchant), and both the POS and production orders read that same sheet.
A bill of materials works directly on the stock of each inventory location (InventoryLocation): tapping an item into the order reserves the materials (Material), and completing the order is when the materials physically leave the location.
The four stock numbers
Lifted from Stock Items & Levels so you do not have to open another PRD. Every item at every location carries four numbers:
| Number | What the system calls it | Meaning |
|---|---|---|
| On hand | on-hand | Goods physically sitting at the location |
| Reserved | reserved | Already promised to another document, no longer sellable to anyone else |
| Available | available | The part still on offer |
| Incoming | incoming | Already left the source location, not yet arrived at the destination |
The invariant, true at every moment:
Available = On hand - ReservedReserving materials at tap time moves stock from available into reserved. On hand only drops when the order completes.
Why a bill of materials is more than a quantity sheet
An F&B merchant does not sell "a can of soda", it sells "a glass of milk tea". What sits in the store room is milk, tea, pearls and sugar. What the customer orders is a name on the menu.
The owner's hard problem is not writing the recipe, it is the three questions that come with it. When this item sells, what gets drawn down: the item itself, or its materials? When do we know it has run out: finding out the milk is gone after the customer has already paid is far too late. And when does the ledger move: at tap time, at payment, or when the kitchen finishes the dish?
BANA answers the first question by adding no mode switch at all. The product catalog already carries the item type and a track-stock flag. Those two together derive every drawdown path, wrapped in one matrix that closes off every combination. A third flag would only spawn contradictory combinations that nobody can explain.
Second question: check and reserve the materials the moment the item is tapped into the order, not after the money is collected. Third question: deduct from the ledger at payment by default, and merchants running a kitchen display turn on an option that moves it to when the kitchen marks the item done.
A bowl of pho from start to finish
Broth is a semi-finished item with stock tracking on: it has stock of its own. The bowl-of-pho recipe calls for 200ml of broth. The pot-of-broth recipe calls for 5kg of bones per 50 litres.
| What happens | Bones (kg) | Broth on hand (l) | Broth reserved (l) |
|---|---|---|---|
| Start of shift: 15kg of bones on hand, no broth yet | 15 | 0 | 0 |
| A production order cooks a 50-litre pot, eating 5kg of bones | 10 | 50 | 0 |
| The cashier taps 1 bowl of pho into the order | 10 | 50 | 0.2 |
| The customer pays, the order completes | 10 | 49.8 | 0 |
- The bones are deducted exactly once, at the production order that cooked the pot of broth.
- Selling the bowl of pho draws down broth only. The explosion stops at broth, because broth has stock of its own.
- Tapping the item into the order reserves 200ml, it does not deduct. Broth on hand only drops when the order completes.
The easiest thing to get wrong
Explosion STOPS at every component that has STOCK OF ITS OWN
The deciding question is "does this component have its own stock", not "does this component have a nested recipe".
The pot of broth above was cooked by a production order, and that order already deducted 5kg of bones. If selling a bowl of pho made the system explode THROUGH the broth down to the bones, those same 5kg of bones would be deducted a second time. The book would report the bones gone while the bones are still sitting on the shelf.
Only recurse through a component with no stock of its own, meaning a prepared item. A component that has stock of its own is drawn down on that stock and the explosion stops right there.
Consequence: running out of broth mid-shift sends broth stock negative with a warning. The system does not deduct bones to make up for it. That negative number is exactly the signal that the kitchen cooked more without logging a production order.