At a Glance
Module: costing · Total scenarios: ~18 cross-persona + ~84 per-persona · Personas covered: Finance, Inventory Controller, Auditor
Run order: Audit / Config setup → primary persona happy paths → cross-persona scenarios
Each persona's drill-down is04-test-scenarios-<role>.md
This page is the overview entry point for the test-scenarios set of the costing module. It groups coverage by the three personas that interact with the cost-flow lifecycle (Finance, Inventory Controller, Auditor), inventories the per-persona test files, captures the cross-persona handoff scenarios that stitch individual paths together, and maps every cross-persona scenario back to the canonical inventory + GRN + credit-note E2E surfaces (900-period-end.spec.ts, 501-grn.spec.ts, 601-cn.spec.ts, 701-sr.spec.ts, 720-stock-issue.spec.ts) since costing has no dedicated spec file — every cost-flow effect fans out from an upstream transaction post. The scope is deliberately wider than a pure functional pass: each persona file includes functional happy paths (cost-pick at outbound, WA inbound recompute, credit-note revaluation, period close + open rollforward), RBAC / permission-denial cases (Controller attempts cost edit, Finance attempts method change without drain), edge cases (FIFO consumption spanning lots; WA average exactly at boundary precision; credit-note-amount driving lot cost to zero or negative; period-rollforward FIFO sequence preservation; method-change-with-on-hand blocking), and method-consistency audits (Auditor verifies cost-flow chain, FIFO-WA shadow drift, configuration history).
The cross-persona scenarios in Section 4 are the integration layer above the per-persona suites. They describe end-to-end journeys that cross a handoff boundary recorded in 03-user-flow.md Section 4 — for example, Controller surfaces cost anomaly → Finance approves credit-note revaluation → costing engine writes diff_amount on the lot → downstream FIFO consumption picks up the revalued cost; Auditor verifies the chain. Section 5 maps the inventory + GRN + credit-note E2E describe blocks back to those journeys so gaps in automated coverage are visible; note that the costing module is partially exercised by the upstream module specs, and many cost-flow-specific concerns (per-lot cost-pick, WA shadow on FIFO, method-change drain) are likely manual / planned tests.
tb_period.status = closed → locked.The table below is the integration layer. Each row spans at least one handoff from 03-user-flow.md Section 4 and ends with the cost-layer ledger in a terminal or steady state. "Personas in order" lists the actors in execution sequence; "Pre-condition" captures the system state required to begin; "Expected end state" anchors the cost-layer effect, GL fan-out, and period state.
| # | Scenario | Personas in order | Pre-condition | Expected end state |
|---|---|---|---|---|
| 1 | FIFO outbound spanning two lots — Controller approves | Inventory Controller | Product at FIFO-configured business unit; two existing lots at the source location with different lot_seq_no and cost_per_unit; SR-approved issue for qty larger than the oldest lot's balance. |
Single outbound tb_inventory_transaction; two outbound cost-layer rows — first consumes oldest lot fully at its cost_per_unit, second consumes remainder from next-oldest lot at its cost_per_unit per COST_CALC_001 / COST_POST_002. Controller's cost-pick preview matches the two-row result. |
| 2 | WA inbound recompute — Controller approves | Inventory Controller | Product at WA-configured business unit; existing on-hand at one cost; new GRN receipt at a different cost. | GRN commit writes inbound cost-layer row; average_cost_per_unit = (prior_on_hand × prior_average + in_qty × in_cost) / (prior_on_hand + in_qty) per COST_CALC_003; subsequent outbound at this (location, product) reads the new average. |
| 3 | Credit-note-amount revaluation — Finance approves | Inventory Controller (variance surfaced) → Finance | committed GRN exists with a lot at cost_per_unit = X; vendor concedes a −฿100 price reduction post-receipt; credit-note tb_credit_note raised by Receiver / Finance Officer at pending. |
Finance approves; inventory module fires INV_POST_007 → costing engine fires COST_POST_003; cost-layer row written with in_qty = 0, out_qty = 0, diff_amount = −฿100, transaction_type = credit_note_amount; originating lot's cost_per_unit recalculated per COST_CALC_005; downstream FIFO consumption from the lot picks up the revalued cost. GL: Dr AP / Cr Inventory ฿100. |
| 4 | Count-variance valuation by configured method | Inventory Controller → (per-tenant configured physical_count_costing_method) |
Physical count completes with variance lines at a location; tenant has configured enum_physical_count_costing_method = last_receiving; Controller commits the count-variance rollup. |
One tb_stock_in / tb_stock_out per count direction; each line's cost_per_unit resolved by COST_CALC_008 reading the most recent inbound layer at (location, product); cost-layer rows written via COST_POST_009 (which routes through COST_POST_001 / COST_POST_002 with the picked count-variance cost). |
| 5 | Period-end valuation rollforward (FIFO) — Finance closes | Inventory Controller → Finance → Finance Manager (lock later) | Closing period at open; Controller has signed off variance (no unresolved cost anomalies, no pending corrective adjustments); reconciliation passes; FIFO business unit with residual lots at multiple (location, product) keys. |
Finance closes the period: INV_POST_009 + COST_POST_007 write tb_period_snapshot rows with per-key closing_qty / closing_cost_per_unit / closing_total_cost. Chained COST_POST_008 writes open_period cost-layer rows for the next period with lot_seq_no preserved per COST_CALC_007 — FIFO sequence carries across the period boundary. |
| 6 | Period-end valuation rollforward (WA) — Finance closes | Same as Scenario 5 but WA business unit | Closing period; running average_cost_per_unit per (location, product). |
COST_POST_007 writes snapshot with closing_cost_per_unit = current_running_average; COST_POST_008 writes single open_period cost-layer row per (location, product) carrying the prior closing average; the next period's first outbound reads from this anchor. |
| 7 | Calculation-method change blocked by non-zero on-hand | System Administrator | Existing business unit at calculation_method = average with non-zero on-hand for at least one product; Sysadmin attempts to change to fifo. |
Impact preview rejects per COST_VAL_009: "Cannot change calculation_method on business unit <code>: <N> products have non-zero on-hand. Drain stock or run elevated migration." Configuration not saved. |
| 8 | Calculation-method change after drain — happy path | Finance → Store Keeper → Inventory Controller → System Administrator | Business unit at calculation_method = average; Finance has coordinated drain of all on-hand at the business unit (transfer-out, write-off, or migration); Sysadmin re-attempts the change. |
Impact preview passes; Sysadmin saves; tb_business_unit.calculation_method = fifo persisted; configuration-history entry written; subsequent inbound assigns lot_seq_no ascending; subsequent outbound consumes by FIFO; new movements use FIFO from the moment of save. |
| 9 | Standard-cost update — recipe baseline + count-variance | Finance | Tenant's monthly standard-cost update batch; tb_product.standard_cost updated for N products; tenant enum_physical_count_costing_method = standard. |
tb_product.standard_cost updated per product; configuration history written; no cost-layer effect per COST_POST_010 (prospective only). Subsequent count-variance posts at affected products pick the new standard_cost per COST_CALC_008; recipe baseline costs refresh on next access. |
| 10 | Cost-pick preview anomaly — Controller rejects stock-out | Store Keeper → Inventory Controller | FIFO business unit; product has a stale 6-month-old lot at lot_seq_no = 1 with anomalously high cost (vendor pricing event); Store Keeper raises a stock-out (e.g. breakage write-off); cost-pick preview shows FIFO consuming the stale lot at the anomalous cost. |
Controller rejects with comment "FIFO cost-pick consumes lot LOT-1 at ฿X (high vs current pricelist ฿Y); rotation issue needs operational review before write-off." Document returns to Store Keeper at draft; no cost-layer row written; rotation issue routed to operational follow-up. |
| 11 | Lot-cost chain-of-custody trace — recall investigation | Auditor | Lot LOT-RECALL-42 introduced by a GRN, partially issued via SR, partially written off via stock-out, with a credit-note-amount revaluation; recall investigation requires the cost-flow chain. |
Backward trace returns the GRN that introduced the lot at cost_per_unit = X. Forward trace returns all downstream consumption: SR issues (cost picked from the lot or revalued lot), stock-out write-off, credit-note quantity adjustment. Plus the credit-note-amount revaluation row showing diff_amount and the lot's revalued cost_per_unit. Chain-of-custody report exports for the recall file; no transaction state change. Mirrors inventory Scenario 13 viewed from the cost dimension. |
| 12 | Period-snapshot verification — Auditor reconciles | Auditor | Closed period 2026-04; tb_period_snapshot rows written; Auditor runs the independent reconstruction query. |
Per-key reconciliation: snapshot's closing_total_cost equals independent reconstruction opening_total_cost + receipt_total_cost − issue_total_cost + adjustment_total_cost + Σ diff_amount per COST_CALC_006; rollforward continuity confirmed (closing_qty / closing_cost_per_unit matches next period's opening_qty / opening_cost_per_unit); FIFO lot_seq_no preserved across boundary. Clean — verification report exports. |
| 13 | FIFO-WA shadow drift — within tolerance | Auditor | FIFO business unit; period of normal activity; Auditor runs the shadow-drift audit. | Each cost-layer row's average_cost_per_unit (shadow WA maintained even under FIFO per COST_CALC_004) matches the independent WA recompute within rounding tolerance (e.g. ฿0.10 per location-product per period). Drift report shows no above-tolerance rows; verification clean. |
| 14 | Sub-ledger ↔ GL reconciliation variance — Finance resolves | Inventory Controller (drill) → Finance | Reconciliation pass at period close surfaces a ฿156 variance at a location; drill identifies a missed GL journal for a credit-note-amount revaluation that posted to cost-layer but didn't replicate to GL. |
Finance posts compensating GL journal Dr Inventory ฿156 / Cr <gap-account> ฿156; reconciliation re-runs to within tolerance; period close proceeds. Costing-side: cost-layer ledger unchanged (it was correct); GL caught up. |
| 15 | Period re-open for credit-note revaluation in closed period | Auditor flags missed revaluation → Finance Manager re-opens → Finance approves credit-note → Finance closes again | Period 2026-04 at closed within audit window; external audit identifies a vendor credit-note that should have revalued a lot in 2026-04 but was posted in 2026-05; impact is material. |
Finance Manager re-opens 2026-04 per INV_AUTH_006; credit-note posted with date in 2026-04 (now allowed since period is open); COST_POST_003 writes the revaluation; lot cost_per_unit updated; Finance re-runs the period-end close, COST_POST_007 writes the corrected tb_period_snapshot; period re-closes. Audit log records the re-open / re-close. |
| 16 | Transfer cost mismatch attempt — rejected | (negative test) | Source location FIFO cost-pick produces transfer_out.cost_per_unit = ฿10; a manual override attempts to set transfer_in.cost_per_unit = ฿12 (different cost). |
Post rejected per COST_VAL_010: "Transfer cost mismatch: transfer_in.cost_per_unit must equal transfer_out.cost_per_unit." Transfer transaction not written; the source-document edit returns the error. |
| 17 | Direct-cost location receipt — no cost-layer row | Store Keeper (via GRN) | GRN receipt to a location with tb_location.location_type = direct. |
tb_inventory_transaction header + detail written (audit); no cost-layer row per COST_VAL_011 / COST_POST_005. GL: Dr Department Expense / Cr AP directly. No average_cost_per_unit update; no lot_seq_no assignment. Mirrors inventory Scenario 14. |
| 18 | Consignment location receipt — memo cost layer | Store Keeper (via GRN) | GRN receipt to a location_type = consignment location. |
Cost-layer row written with the consignment cost flagged via dimension / info JSON per COST_POST_006; no AP debit, no Inventory credit at receipt. On later consumption, AP and COGS post simultaneously at the consignment cost. Mirrors inventory Scenario 15. |
The costing module is partially exercised by the inventory + GRN + credit-note + SR + stock-issue Playwright specs. There is no dedicated costing.spec.ts because every cost-flow effect fans out from an upstream transaction post. Coverage is distributed across the source-module specs; many cost-flow-specific assertions (per-lot cost-pick details, WA shadow on FIFO, configuration-history audits) are likely manual / planned.
| Spec / describe block | Cross-persona scenarios covered (Section 4) |
|---|---|
900-period-end.spec.ts |
5 (FIFO period rollforward), 6 (WA period rollforward), 15 (period re-open for revaluation) |
501-grn.spec.ts — Stock Movements / Commit describe blocks |
2 (WA inbound recompute on GRN commit), 17 (direct-cost location receipt), 18 (consignment location receipt) |
701-sr.spec.ts (store-requisition) |
1 (FIFO outbound spanning lots — SR-driven), 16 (transfer cost-mismatch rejection) |
720-stock-issue.spec.ts |
1 (FIFO outbound spanning lots via stock-issue path), 10 (Controller rejects on anomalous cost-pick) |
601-cn.spec.ts (credit-note) |
3 (credit-note-amount revaluation — cost-side effect) |
| Stock-in / Stock-out admin (no canonical spec yet) | 4 (count-variance valuation by configured method), 8 (method change after drain — happy path), 10 (cost-pick preview anomaly rejection) |
Configuration / Sysadmin specs (likely 080-location.spec.ts and a future business-unit config spec) |
7 (method change blocked by on-hand), 9 (standard-cost update — prospective) |
| Audit module specs (outside the inventory module spec set) | 11 (lot-cost chain-of-custody), 12 (snapshot verification), 13 (FIFO-WA shadow drift), and the configuration-history audits — these are read-only audit queries typically planned manual tests in the Auditor persona file |
Gaps relative to Section 4:
900-period-end.spec.ts (the reconciliation gate at period close) but the cost-layer-specific drill is likely manual.../carmen-inventory-frontend-e2e/tests/900-period-end.spec.ts — canonical period-end E2E covering the close + rollforward paths.../carmen-inventory-frontend-e2e/tests/501-grn.spec.ts — GRN commit's inventory-side effect (Stock Movements describe block); inbound cost-layer writes covered indirectly.../carmen-inventory-frontend-e2e/tests/601-cn.spec.ts — credit-note inventory + cost-layer effect (Scenario 3).../carmen-inventory-frontend-e2e/tests/701-sr.spec.ts — store-requisition inventory effects; FIFO outbound coverage (Scenario 1).../carmen-inventory-frontend-e2e/tests/720-stock-issue.spec.ts — stock-out / stock-issue path; Controller approval surface (Scenario 1, 10).