At a Glance
Module: inventory-adjustment · Total scenarios: ~22 cross-persona + ~130 per-persona · Personas covered: Store Keeper, Inventory Controller, Finance, Audit / Config
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 inventory-adjustment module. It groups coverage by the four persona groups that interact with the adjustment document lifecycle (Store Keeper, Inventory Controller, Finance, Audit / Config), 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 Playwright spec 031-adjustment-type.spec.ts (the canonical adjustment-type / reason-code admin E2E surface) plus the adjustment-adjacent specs (720-stock-issue.spec.ts for stock-out paths, 900-period-end.spec.ts for period-end orchestration, 501-grn.spec.ts for the cost-layer side of receipt postings that adjustments mirror).
The scope is deliberately wide: each persona file includes functional happy paths (auto-approve stock-in / stock-out, above-threshold Controller approval, count-rollup commit, Finance approval, void via compensating reversal), RBAC / permission-denial cases (Store Keeper attempts Controller approval, Controller attempts Finance approval, Sysadmin attempts to raise an adjustment), validation (negative tests against ADJ_VAL_001–ADJ_VAL_014 at submit time and at edit time), edge cases (threshold boundary, decimal precision, concurrent posts, lot identity collision, period rollover during draft, new-lot zero-cost, FIFO override for expiry write-off), and configuration / audit-trail cases (reason-code CRUD, threshold change, SoD compliance, lot-recall trace, void-chain verification).
The cross-persona scenarios in Section 4 describe end-to-end journeys that cross a handoff boundary recorded in 03-user-flow.md Section 4 — for example, Store Keeper raises stock-in → auto-approve below threshold → posts to inventory; Store Keeper raises above-threshold stock-out → Controller approves → posts; Controller commits count variance → auto-rollup creates and posts stock-in / stock-out; Finance approves above-Controller-threshold recall write-off → posts; Finance reviews period-end adjustment activity → Finance Manager closes period. Section 5 maps the adjustment-relevant E2E specs back to those journeys so gaps in automated coverage are visible; note that the document-creation / posting flow is partially covered (stock-issue spec covers the stock-out path; period-end spec covers the period-end review; the adjustment-type spec covers Sysadmin reason-code CRUD) — many adjustment-side document concerns are validated through the upstream module specs (count, GRN credit-note), with the per-persona test files cataloguing scenarios that may be manual / planned.
tb_stock_in / tb_stock_out for routine non-GRN / non-SR adjustments, attaches evidence, documents the reason, submits for auto-approve (below threshold) or routes to Controller (above threshold or new-lot).tb_adjustment_type reason codes (including info.glAccount), tenant thresholds, RBAC, workflow definitions; Auditor who runs read-only audit-log queries, SoD compliance checks, lot-recall traces, void-chain verification.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 system 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 document doc_status, the inventory transaction effect (tb_inventory_transaction written, cost-layer rows, GL entry), and any cross-module side effects.
| # | Scenario | Personas in order | Pre-condition | Expected end state |
|---|---|---|---|---|
| 1 | Routine stock-in below threshold — auto-approve | Store Keeper | Existing lot at the location; total cost < auto-approve threshold; period open; reason FOUND_STOCK. |
tb_stock_in.doc_status = completed; one tb_inventory_transaction (inventory_doc_type = stock_in, enum_transaction_type = adjustment_in); inbound cost-layer row (in_qty > 0); on-hand advances at (location, product, lot); no Controller handoff. |
| 2 | Above-threshold stock-out for breakage — Controller approves | Store Keeper → Inventory Controller | Reason BREAKAGE; cost above auto-approve threshold but below Controller threshold; period open. |
After Controller approval: tb_stock_out.doc_status = completed; outbound tb_inventory_transaction (enum_transaction_type = adjustment_out); outbound cost-layer (FIFO or WA per product); on-hand reduced; workflow_history records Controller approval. |
| 3 | Above-Controller-threshold recall write-off — Finance approves | Store Keeper → Inventory Controller → Finance | Reason RECALL_WRITE_OFF; cost above Controller threshold; period open; recall notice attached. |
After Finance approval: tb_stock_out.doc_status = completed; outbound inventory transaction; cost-layer rows (FIFO multi-row if spanning lots); GL Dr Product Recall Loss / Cr Inventory at the resolved info.glAccount. |
| 4 | New-lot stock-in (below threshold) — routes to Controller | Store Keeper → Inventory Controller | Reason FOUND_STOCK or VENDOR_FREE_REPLACEMENT; new lot (no prior cost-layer row at (product, location, lot_no)); cost user-entered; total below auto-approve threshold. |
Per ADJ_AUTH_003, new-lot routes for Controller approval regardless of cost. After Controller approval: tb_stock_in.doc_status = completed; new lot created in cost-layer (in_qty > 0, new lot_no, new lot_seq_no = max+1); on-hand at (location, product, lot) initialised to the line qty. |
| 5 | Physical count variance commit — auto-rollup post | Inventory Controller | physical-count completed with variance lines (some overage, some shortage); Controller commits. | Two rollup documents created and auto-posted: one tb_stock_in (overage lines, reason COUNT_OVERAGE); one tb_stock_out (shortage lines, reason COUNT_SHORTAGE). Both doc_status = completed; info.countId = <count_uuid>. tb_count_stock.status = completed_posted. Per ADJ_POST_006 / ADJ_XMOD_002. |
| 6 | Spot-check variance commit — auto-rollup post | Inventory Controller | spot-check completed with variance lines on a subset; Controller commits. | Same as Scenario 5 but scoped to the spot-checked subset; rollup documents reference the spot-check via info.spotCheckId. Per ADJ_XMOD_003. |
| 7 | FIFO outbound spanning two lots | Store Keeper → Inventory Controller | Product with costing_method = FIFO; two lots at the source location with different lot_seq_no and cost_per_unit; stock-out qty larger than the oldest lot's balance; cost above auto-approve. |
Single outbound tb_inventory_transaction; two outbound cost-layer rows — one consuming oldest lot fully at its cost_per_unit, one consuming remainder from next-oldest at its cost_per_unit. Per ADJ_CALC_006 / inventory INV_CALC_005. |
| 8 | Weighted-average inbound recompute on stock-in | Store Keeper | Product with costing_method = WEIGHTED_AVERAGE; existing on-hand at one cost; stock-in for existing lot at a different cost; below auto-approve. |
Inbound cost-layer row carries new cost and recomputed average_cost_per_unit = (prior_on_hand × prior_average + adj_qty × adj_cost) / (prior_on_hand + adj_qty) per ADJ_CALC_005. Subsequent outbound at the location reads new average. |
| 9 | Negative-balance attempt on stock-out — rejected | Store Keeper | Outbound stock-out for qty larger than current on-hand at the picked lot; tenant policy "no negative balance" (default). | Submit rejected pre-post per ADJ_VAL_012 / inventory INV_VAL_005 with "Outbound movement would drive on-hand below zero. Available: X, requested: Y." Document stays draft. |
| 10 | Backdated post into closed period — rejected | Store Keeper / Controller / Finance | Document with si_date / so_date inside a closed tb_period. |
Submit / approve rejected per ADJ_VAL_011 with "Cannot post into period <YYMM>: period is closed." Document stays draft. Finance Manager re-open path possible per inventory INV_AUTH_006. |
| 11 | Direct-cost location adjustment — rejected | Store Keeper | Stock-in or stock-out raised against a tb_location.location_type = direct location. |
Rejected at submit per ADJ_VAL_003 / ADJ_POST_007 with "Direct-cost locations cannot be the target of an adjustment." Location picker filters direct-type out on the UI; direct API submission re-checks. |
| 12 | Consignment location stock-in — memo-only | Store Keeper | Stock-in to location_type = consignment (e.g. found vendor-owned stock during count); below auto-approve. |
tb_stock_in.doc_status = completed; tb_inventory_transaction written; consignment-flagged cost-layer row; no Inventory asset debit, no AP credit at receipt per ADJ_POST_008 / inventory INV_POST_004. Per-consumption COGS + AP fires later per INV_POST_005. |
| 13 | Void posted document via compensating reversal | Inventory Controller / Finance | tb_stock_in at doc_status = completed; identified as wrong (e.g. duplicate-post discovered, cost-mapping error). |
Two-step: (a) compensating tb_stock_out raised with info.voidsAdjustmentId = <original>, same lines reversed; submits and posts per ADJ_POST_002. (b) Original tb_stock_in.doc_status = voided. Per ADJ_POST_004 / inventory INV_POST_012. |
| 14 | SoD violation — Store Keeper writes off own receipt above threshold | Store Keeper | Store Keeper raises tb_stock_out against a lot they themselves received via GRN; cost above SoD threshold per ADJ_AUTH_010. |
Submit rejected with "You created the receipt for this lot; an independent adjuster must initiate the write-off (SoD)." Document stays draft; SK escalates to Controller or a different SK raises. |
| 15 | Reason-code direction mismatch — rejected | Store Keeper | Reason BREAKAGE (type = stock_out) selected on a tb_stock_in document — typically a UI race or direct API misuse. |
Rejected at submit per ADJ_VAL_002 with "Adjustment reason is required and must match the document direction." Picker filters reasons by direction on the UI. |
| 16 | Required-attachment missing — rejected | Store Keeper | Reason flagged info.requiresDocument = true (e.g. THEFT_WRITE_OFF) but no attachment uploaded. |
Rejected at submit per ADJ_VAL_010 with "Supporting document attachment is required for this adjustment reason." SK adds attachment; resubmits. |
| 17 | Requires-quality-check bypass auto-approve | Store Keeper → Inventory Controller | Reason flagged info.requiresQualityCheck = true (e.g. EXPIRY_WRITE_OFF); total cost below auto-approve threshold. |
Document routes to Controller despite below-threshold (auto-approve fast path bypassed per 03-user-flow.md Section 2.2). Controller approves; document doc_status = completed. |
| 18 | Period-end review: variance-flagged hold | Inventory Controller → Finance | Period has open count-variance items at "investigate" flag; Controller has not signed off variance. | Finance period-end approve blocked — Controller hasn't signed off variance. Finance communicates the hold; Controller resolves the investigation; signs off; Finance re-runs period-end approve and Finance Manager closes per inventory INV_AUTH_006. |
| 19 | Sysadmin adds a new reason code with GL-account mapping | System Administrator | New business case (e.g. insurance-claimable losses) requires a new reason code. | tb_adjustment_type row created with code = INSURANCE_WRITE_OFF, type = stock_out, info.glAccount = "6535", info.requiresDocument = true. Immediately available in Store Keeper / Controller / Finance pickers. Audit-logged per ADJ_AUTH_008. Exercised by 031-adjustment-type.spec.ts. |
| 20 | Auditor verifies SoD compliance for the period | Auditor | All tb_stock_out posts in the period available; SoD threshold configured. |
Audit query joins tb_stock_out.created_by_id against tb_good_received_note.created_by_id for the same lot above SoD threshold. Findings list flagged pairs (receiver / adjuster). Cross-references ADJ_AUTH_010 / inventory INV_AUTH_010. |
| 21 | Auditor lot-recall trace | Auditor | Lot affected by vendor recall; introduced by GRN, partially issued via SR, partially written off via stock-out, with credit-note amount adjustment. | Backward trace returns originating GRN. Forward trace returns all consuming movements (SR issues, stock-out write-offs, credit-note quantity rows, transfer-outs). Chain-of-custody report rendered both directions. Read-only; no state change. |
| 22 | Auditor verifies void chains | Auditor | Period contains voided adjustment documents. |
For each voided doc, verify a compensating tb_stock_in or tb_stock_out exists with info.voidsAdjustmentId = <original_id> per ADJ_POST_004. Orphaned voids (no compensating reversal) flagged. |
The inventory-adjustment module is partially exercised by three Playwright spec files; there is no inventory-adjustment.spec.ts covering the full document lifecycle. Coverage is distributed across reason-code admin, stock-issue (outbound), and period-end specs.
| Spec / describe block | Cross-persona scenarios covered (Section 4) |
|---|---|
031-adjustment-type.spec.ts |
19 (Sysadmin reason-code CRUD); also exercises ADJ_VAL_001-equivalent on tb_adjustment_type.code uniqueness and ADJ_AUTH_008 Sysadmin scope. |
720-stock-issue.spec.ts |
2 (above-threshold stock-out — uses the stock-issue surface which mirrors stock-out's posting path), 7 (FIFO outbound spanning lots), 9 (negative-balance rejection), 14 (SoD via the issue path). |
900-period-end.spec.ts |
10 (backdated-post rejection — period-status side), 18 (period-end variance-flagged hold). |
501-grn.spec.ts — Stock Movements describe block |
8 (WA inbound recompute pattern — the recompute logic is shared between GRN inbound and stock-in inbound), 11 (direct-cost location — receipt-side), 12 (consignment location — receipt-side). |
601-cn.spec.ts |
13 (compensating-reversal pattern — credit-note module uses a similar void-via-reversal flow). |
Gaps relative to Section 4:
tb_inventory_transaction write pattern).../carmen-inventory-frontend-e2e/tests/031-adjustment-type.spec.ts — adjustment-type / reason-code admin CRUD spec; the canonical Sysadmin surface.../carmen-inventory-frontend-e2e/tests/720-stock-issue.spec.ts — stock-out / stock-issue path; outbound inventory surface that adjustment stock-out shares.../carmen-inventory-frontend-e2e/tests/900-period-end.spec.ts — period-end orchestration; cross-link for backdated-post and variance-hold scenarios.../carmen-inventory-frontend-e2e/tests/501-grn.spec.ts — GRN commit inventory-side; cross-link for the inbound posting pattern (WA / FIFO) the adjustment stock-in mirrors.../carmen-inventory-frontend-e2e/tests/601-cn.spec.ts — credit-note inventory effects; cross-link for the compensating-reversal pattern adjustment void uses.