PRD: Lots, Expiry & Picking Strategy
| Module | Inventory | PRD ID | PRD-LSE-001 |
| Status | Superseded | FEAT | LSE |
| Epic | — | Plane | — |
| Date | 2026-07-13 | Version | v1.0 |
| Packages | @nx/inventory | URD | LSE |
| Surface | Client · Owner/Mgr | ||
| Owner | Phát Nguyễn | ||
What a lot is
A lot is one batch of goods received together, sharing one lot code and one expiry date. Ten cartons of milk received this morning expiring 2026-08-01 are one lot; ten cartons received next week with a different expiry are another lot.
A merchant turns lot tracking on per item, right inside the item edit form. The flag is off by default. Turn it on and that item's stock at each inventory location is split out by lot. Several merchants sit under one organizer, and each merchant decides for itself which items need lots.
The four numbers in stock
Lifted from Stock locations & levels so there is no need 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 in the location |
| Reserved | reserved | Already promised to another document, no longer sellable to anyone else |
| Available | available | The part still sellable |
| Incoming | incoming | Left the source location, not yet arrived at the destination |
The invariant, true at every moment:
Available = On-hand - ReservedTurn lots on and these four numbers drop one level further down: every lot carries its own four numbers, and the item's stock at a location is the sum of the lots there.
Why a single stock number is not enough
The same SKU does not mean interchangeable units. A crate of milk received today and one received last week expire on different days. If the system keeps a single stock number for "fresh milk", nobody knows which part is about to expire, and staff grab whatever crate is nearest. The old milk sits there until it has to be thrown out.
Only with lots can the system answer the two questions F&B and fresh-goods retail ask every day: what is about to expire, and which goods go out first when we sell.
One lot-tracked item, end to end
Fresh milk, on the earliest expiry first (FEFO) strategy. Receive two lots, then sell 4 cartons. The cashier picks no lot.
| What happens | Lot A · expires 08-01 · received 07-01 | Lot B · expires 07-20 · received 07-05 | Total stock |
|---|---|---|---|
| Receive lot A: 5 cartons | 5 | 0 | 5 |
| Receive lot B: 3 cartons | 5 | 3 | 8 |
| Sell 4 cartons | 4 | 0 | 4 |
- Lot B expires sooner, so it is drawn down first: all 3 cartons. The remaining 1 carton spills over into lot A.
- One sale touches two lots, and the inventory ledger writes two lines: minus 3 from lot B, minus 1 from lot A.
- Switch this item to the first in, first out (FIFO) strategy and lot A is drawn down first, because lot A entered stock on 07-01, earlier than lot B.
- A few days later lot A crosses the alert threshold (7 days by default) and appears on the near-expiry lot list.
The easiest thing to get wrong
The picking strategy is not a valuation method
FIFO here is a lot pick order: which lot leaves the shelf first. It says nothing about the money attached to that carton of milk.
Inventory valuation is a separate config, set on the Inventory Valuation screen, and it has only two options: weighted moving average or standard cost. Changing the picking strategy does not move the valuation, and changing the valuation method does not reorder lot picking.
When two lots tie, the system evaluates each key in turn until the tie is broken, so the result is always explainable and repeatable. A lot with no expiry always sorts after lots that have one.