Refactor production and stock tests to remove UOM dependency
- Updated production.spec.ts, stock-adjustments.spec.ts, and stock-transfers.spec.ts to eliminate UOM references in API seeder and test cases. - Adjusted ApiSeeder methods to remove UOM parameters from stock receiving and production template creation. - Revised documentation to reflect changes in UOM handling, emphasizing that stock is counted in base UOM only. - Introduced new enums for MeasureUnit and StageQtyUnit to clarify content size and stage input quantities. - Implemented ItemContent service to validate and normalize content sizes. - Updated smoke tests to validate production stage inputs expressed in content units, ensuring correct consumption calculations. - Modified frontend UOM label handling to reflect the removal of per-line UOMs in document lines.
This commit is contained in:
@@ -4,6 +4,37 @@ Legend: `[ ]` not started · `[~]` in progress · `[x]` done
|
||||
Spec: `docs/10-BACKEND-PHASE1.md` (model + rules) · `docs/11-BACKEND-PHASE1.md` (API)
|
||||
Convention: `docs/01-DOC-GUIDE.md §6`. Update this file in the **same commit** as the code. When ticking `[x]`, append a short note + any deviation.
|
||||
|
||||
## UOM re-model (2026-08-11) — supersedes every "UOM conversion" note below
|
||||
|
||||
Per-item UOM conversion is **gone**. Entries further down this file that describe
|
||||
`IUomConverter`, `PUT /items/{id}/uom-conversions`, `uom_conversions`, or a line-level
|
||||
`uomId` are historical and no longer describe the code.
|
||||
|
||||
What replaced it:
|
||||
|
||||
- **One unit per item.** `Item.BaseUomId` is the pack an item is stocked and counted in, and
|
||||
every quantity in the system — stock layers, ledger rows, GRN/PO/sales/bundle/transfer lines
|
||||
— is a plain count of it. A differently sized pack is a different item. `UomId` was dropped
|
||||
from all six document-line entities; `Uom` itself survives as the lookup.
|
||||
- **Optional content size on `Item`**: `ContentQty` + `ContentUnit` as entered (`Ml|L|G|Kg`),
|
||||
normalised on write into `ContentBaseQty` + `ContentBaseUnit` (only ever `Ml` or `G`, L/Kg
|
||||
×1000). All four null ⇒ nothing measurable to hold. `ItemContent` is the pure normaliser.
|
||||
- **Production is the only content consumer.** `StageInput.QtyUnit` (`Pack|Content`) says what
|
||||
`QtyPerBatch` means; `IItemMeasure` divides a `Content` quantity by the item's content size
|
||||
to get packs. **Fractional packs are legal** — 300 ml of a 500 ml bottle consumes 0.6000.
|
||||
Outputs are always pack counts, so scrap stays in whole broken bottles.
|
||||
- **WIP keeps a label.** `StageOutput.UomId`/`RunStageOutput.UomId` are now nullable and
|
||||
required *only* when `ItemId` is null (`422 WIP_UNIT_REQUIRED`), since an item-bearing output
|
||||
takes its unit from the item. WIP never touches stock, so the label is never converted.
|
||||
- **Two live defects fixed as a consequence.** `SalesPostingService` injected `IUomConverter`
|
||||
and never called it, so a sales line in a non-base UOM consumed the wrong quantity outright;
|
||||
`GrnService` accrued `poLine.QtyReceived += line.Qty` and range-checked over-receipt across
|
||||
the same unit boundary. Both are now like-for-like by construction.
|
||||
- **`BaseUomId` is frozen once an item has stock history** (`409 MASTER_IN_USE`) — it is the
|
||||
sole meaning of every recorded quantity, so changing it would silently reinterpret all of it.
|
||||
- Smoke: `m4b_uom_conversion.py` deleted; `m4c_content_units.py` added (whole packs, fractional
|
||||
packs, and the contentless-item guard).
|
||||
|
||||
## 8. Sales
|
||||
- [x] Sales bootstrap data seeded locally for development: warehouses, UOMs, categories, items, customers, current-year `SI`/`SSL` sequences, plus sample invoice/slip headers and lines. Existing data is preserved.
|
||||
- [x] Sales report API consolidated into `GET /api/v1/reports/sales` (catalog), `GET /api/v1/reports/sales/{reportId}` (report metadata), and `POST /api/v1/reports/sales/query` (filtered data). Legacy per-report GET routes removed; invalid report/filter combinations now fail validation.
|
||||
|
||||
Reference in New Issue
Block a user