At a Glance
Persona: Finance (Finance Officer / AP + Finance Manager) · Module: vendor-pricelist · Scenarios: ~26
Categories: Happy Path · Permission · Validation · Edge Case
E2E coverage: none — variance dashboard and co-signoff coverage runs at API / integration level pending roadmap item; no dedicated spec in../carmen-inventory-frontend-e2e/
This page captures the test scenarios that the Finance persona (Finance Officer / AP + Finance Manager) directly drives in the vendor-pricelist module. Finance has no write surface on the pricelist itself — VPL_AUTH_009 is read-only across pricelists, campaigns, and invitations. The Finance Manager's contribution to activation of multi-currency / high-value pricelists is captured as a co-signoff system comment in tb_pricelist_comment, not as a direct status change; the VPL_POST_017 flip is recorded against the Purchaser / Purchasing Manager. Finance's primary touch point is post-receipt variance audit — when GRN / invoice posting in the downstream purchase-order chain flags a variance against the active pricelist (per VPL_XMOD_005), Finance investigates, categorises, and either (a) accepts a within-tolerance variance with a PPV entry on the AP side, (b) routes a vendor over-bill or out-of-date pricelist back to the Purchaser for action, or (c) attributes an FX-only variance to the cross-currency posting. Scenarios are grouped into the happy paths described in 03-user-flow-finance.md, the RBAC boundary that separates Finance Officer read-only from Finance Manager co-signoff right (VPL_AUTH_010) and from the no-direct-write-on-pricelist constraint (VPL_AUTH_009), the validation surfaces around FX / currency policy enforcement, and a small set of edge cases around variance race conditions and cross-currency boundary cases. Cross-persona handoffs that pivot off Finance (X-VPL-03 multi-currency co-signoff, X-VPL-06 GRN variance audit) live in the parent overview, not here.
| # | Scenario | Pre-condition | Steps | Expected |
|---|---|---|---|---|
| VPL-FIN-HP-01 | Finance Manager signs off on a multi-currency pricelist | Submitted pricelist PL-V-EUR from vendor V1 at tb_pricelist.status = draft + submitted_at IS NOT NULL; currency_id = EUR, tenant base currency THB; tenant FX policy permits EUR ↔ THB; cross-border-FX threshold exceeded so co-signoff is required; Finance Manager finance.manager@blueledgers.com in the review queue |
1. Open PL-V-EUR from Finance review queue. 2. Verify currency_id = EUR against the vendor's contracted dual-currency setup. 3. Confirm tenant FX rate source can quote EUR → THB for the validity window. 4. Review tax decomposition per VPL_CALC_001–VPL_CALC_002 and projected aggregate financial impact. 5. Click Sign off. |
Finance signoff system comment appended in tb_pricelist_comment with type system, capturing the Finance Manager's identity, the timestamp, and the FX-policy verification reference. If the Purchasing Manager has already signed off (VPL_AUTH_005), VPL_POST_017 fires immediately and the pricelist activates. Otherwise the workflow continues to wait on the Purchaser side. No tb_pricelist row is mutated directly by Finance — the signoff is purely a comment write. |
| VPL-FIN-HP-02 | Finance Officer reads variance dashboard | Several variance events flagged from GRN postings in the past week per VPL_XMOD_005; Finance Officer finance@blueledgers.com logged in |
1. Sidebar → Finance workspace → Pricelist Variance dashboard. 2. Apply filters: period = last 7 days, magnitude > 5 %. 3. Result table renders one row per variance. 4. Sort by magnitude descending. | Variance dashboard renders read-only across tb_pricelist_detail joined to posted tb_good_received_note_detail and AP invoice records. Each row shows vendor, product, pricelist price, GRN / invoice price, variance magnitude (absolute + percentage), the linked PO / GRN / invoice ids, and the current categorisation status. No tb_pricelist row is mutated. |
| VPL-FIN-HP-03 | Categorise variance as within-tolerance (auto-pass on PO side) | Variance row in dashboard: pricelist price ฿50.00, GRN price ฿50.40, magnitude 0.8%; tenant price tolerance 1.5%; PO three-way match already passed per purchase-order/02-business-rules § PO_POST_008; PPV entry already posted on AP |
1. Open variance row. 2. Confirm PO match outcome = success. 3. Set categorisation = within-tolerance. 4. Save. |
Categorisation system comment appended in tb_pricelist_detail_comment referencing the GRN / invoice ids, the variance magnitude, and the within-tolerance outcome. Variance row drops from the open dashboard. No action on the pricelist; tb_pricelist.status unchanged (active). The categorisation feeds the pricelist-deviation analytics rollup. |
| VPL-FIN-HP-04 | Categorise variance as vendor over-bill (route to Purchaser) | Variance row: pricelist price ฿50.00, invoice price ฿55.00, magnitude 10%; tenant tolerance 1.5%; PO three-way match failed per PO_POST_009; invoice held in dispute |
1. Open variance row. 2. Drill into the PO / GRN / invoice chain. 3. Confirm GRN unit price matches pricelist; invoice unit price diverged at vendor billing. 4. Set categorisation = vendor-over-bill. 5. Route to Purchaser via the Notify Purchaser action. 6. Save. |
Variance system comment appended in tb_pricelist_detail_comment + tb_pricelist_comment recording the categorisation and the rationale. Notification fires to the Purchaser to pursue a credit note with the vendor. Variance row stays open until the Purchaser closes the loop (credit note posted, or amendment applied). tb_pricelist.status unchanged. |
| VPL-FIN-HP-05 | Categorise variance as pricelist out-of-date (route for inactivation) | Pattern across multiple vendors / products on PL-V1-Q1: pricelist price systematically below market; invoice prices align with the new market level; Finance Officer detects the pattern |
1. Open the affected variance rows. 2. Confirm the pattern (multiple rows, multiple products, similar magnitude). 3. Set categorisation = pricelist-out-of-date. 4. Open the affected pricelist PL-V1-Q1. 5. Recommend inactivation action — opens a notification to the Purchaser with the variance evidence attached. |
Recommendation system comment appended on tb_pricelist_comment for PL-V1-Q1. Purchaser is notified; Finance does not inactivate directly (per VPL_AUTH_009 no write right). Purchaser executes VPL_POST_019 under their own authority. Pricelist transitions active → inactive only when the Purchaser acts; Finance's comment is preserved on the activity log for audit. |
| VPL-FIN-HP-06 | Categorise variance as FX-only on cross-currency invoice | PO PO-XCC in USD, exchange_rate = 36.50 (vs base THB); invoice in USD with the same unit price as PO; invoice-date USD → THB rate moved to 36.80 (FX shift only) |
1. Open variance row — the pricelist-vs-invoice unit price match exactly in USD. 2. The THB-equivalent on AP side diverges by 0.82 % due to FX move between PO date and invoice date. 3. Set categorisation = FX-only. 4. Confirm AP posting captured the realised FX gain / loss per tenant GL mapping. |
No action on the pricelist; tb_pricelist values in USD are never mutated for FX per VPL_CALC_005. FX-only system comment appended for the audit trail. Variance row drops from the open dashboard. AP side carries the realised FX gain / loss entry. |
| VPL-FIN-HP-07 | Read pricelist for audit reconciliation | Finance Officer reconciling negotiated rates vs realised rates across Q1; needs the active pricelist PL-V1-Q1 snapshot at a specific point in time |
1. Sidebar → Finance workspace → Vendor Pricelists. 2. Search PL-V1-Q1. 3. Open detail view; activity log shows the full lifecycle. 4. Export the pricelist snapshot to PDF for the reconciliation working paper. |
Read-only access succeeds per VPL_AUTH_009. PDF export is permitted; if the export includes sensitive fields (full pricing snapshots, vendor identities), the export-approval flow fires per the tenant data-export policy. No tb_pricelist mutation. |
| # | Scenario | Expected behaviour (allow/deny + reason) |
|---|---|---|
| VPL-FIN-PERM-01 | Finance Officer reads pricelists, campaigns, invitations across all statuses | Allow per VPL_AUTH_009. Finance Officer's UI exposes read views of every tier; edit / approve / reject / inactivate actions are not exposed. Direct API edit calls return "Finance role is read-only on pricelist documents — use the comment surface for variance findings." |
| VPL-FIN-PERM-02 | Finance Manager co-signs on a multi-currency pricelist | Allow per VPL_AUTH_010. The signoff is a system comment write on tb_pricelist_comment, not a direct status change. The VPL_POST_017 flip records against the Purchasing Manager (or Purchaser, where authorised); Finance Manager's signoff is a prerequisite for the flip on multi-currency. |
| VPL-FIN-PERM-03 | Finance Officer attempts to directly modify a pricelist row | Deny. Per VPL_AUTH_009. UI does not expose Edit; direct API edit returns "Finance role is read-only on pricelist documents." Variance findings are recorded via comments on tb_pricelist_comment / tb_pricelist_detail_comment, not on the row data itself. |
| VPL-FIN-PERM-04 | Finance Manager attempts to inactivate an active pricelist directly | Deny. Per VPL_AUTH_009 (Finance has no write right on tb_pricelist.status). The inactivation VPL_POST_019 is reserved to the Purchaser / Sysadmin. Finance Manager's path is to recommend inactivation via comment + notification, per VPL-FIN-HP-05. |
| VPL-FIN-PERM-05 | Finance Manager sends back a submitted multi-currency pricelist | Allow as part of the co-signoff flow per VPL_AUTH_010. The send-back is the negative outcome of the Finance Manager review — pricelist status returns to draft + submitted_at = NULL via VPL_POST_018; Finance Manager's send-back system comment captures the FX-policy or financial-impact rationale; vendor receives rejection email. Distinct from VPL-FIN-PERM-04: the send-back operates during the pre-activation review window, not on an already-active pricelist. |
| VPL-FIN-PERM-06 | Finance Officer attempts to override a failed three-way match on the AP side (force-post AP despite price discrepancy beyond tolerance) | Deny — Finance Manager only. Override of a failed three-way match requires the Finance Manager role per purchase-order/02-business-rules § PO_AUTH_009 and AP-side configuration. From the pricelist module's perspective, this is documented for cross-module alignment; the actual override is exercised in the AP module surface, not on tb_pricelist. |
| VPL-FIN-PERM-07 | Finance Officer reads the validation engine output stored in tb_pricelist.info (validation_results + quality_score) |
Allow per VPL_AUTH_009. The validation panel renders the stored output read-only; Finance Officer's role is to verify whether quality concerns correlate with downstream variance findings. No info JSON is mutated by Finance. |
| # | Scenario | Trigger | Expected error |
|---|---|---|---|
| VPL-FIN-VAL-01 | Finance Manager veto on a pricelist whose currency is not permitted | Multi-currency pricelist PL-V-BTC submitted with currency_id = BTC (vendor's typo; or a hostile vendor proposal); tenant's permitted-currency list does not include BTC |
Finance Manager rejects per VPL_POST_018 with reason "Currency BTC not in tenant permitted-currency list." tb_pricelist.submitted_at reset; rejection system comment captures the policy citation. Distinct from VPL-VND-VAL-07 which catches the picker at portal time — this scenario covers a slipped-through case at Finance Manager review. |
| VPL-FIN-VAL-02 | Finance Manager veto on a pricelist whose currency lacks an FX quote for the validity window | Pricelist PL-V-MYR submitted with currency_id = MYR; tenant FX rate source cannot quote MYR → THB for the validity window (e.g., FX source feed limitation) |
Finance Manager rejects per VPL_POST_018 with reason "MYR → THB FX rate not available for the validity window from the configured FX source." Vendor receives rejection email. The Purchaser can either pre-arrange an alternative FX source (Sysadmin configuration) or invite the vendor in an alternative currency. |
| VPL-FIN-VAL-03 | Variance categorisation attempted on a closed (already-resolved) variance row | Variance row previously categorised as within-tolerance and dropped from the open dashboard; Finance Officer re-opens the case from history; attempts to re-categorise |
Reject — the variance row is read-only once categorised and closed. Server returns "Variance has already been categorised and closed. Re-open via the audit case-file workflow if a re-categorisation is needed." The audit case file mechanism is the only path to revisit a closed variance; this preserves the integrity of the historical record. |
| VPL-FIN-VAL-04 | Finance Manager attempts to co-sign on a pricelist that has not yet been submitted by the vendor | Submitted pricelist must have submitted_at IS NOT NULL for the co-signoff stage to be available; Finance Manager tries to sign off via direct API on a draft + submitted_at IS NULL pricelist |
Reject. Server returns "Pricelist must be submitted by the vendor before Finance Manager co-signoff. submitted_at is NULL." UI does not expose Sign Off until the submission is in the review queue; the API guard is the fallback. |
| VPL-FIN-VAL-05 | Finance Officer attempts to bypass export approval for a sensitive-field PDF | Finance Officer exports a pricelist snapshot PDF that includes vendor identities + pricing detail + portal-token telemetry | Reject the immediate download — exports including sensitive fields enter pending per the tenant data-export policy. Server returns "Export requires approval — sensitive fields detected (vendor identity, pricing snapshot, portal telemetry). Export is in pending state until release by an export approver." This mirrors the Auditor's export-approval gate (AUD-VAL-02 pattern in the PO module). |
| VPL-FIN-VAL-06 | Variance row is opened against a soft-deleted pricelist | Variance row references tb_pricelist_detail row whose parent tb_pricelist was soft-deleted (administrative cleanup); Finance Officer tries to open the variance |
Allow read of historical data (Finance can audit historical pricelists per VPL_AUTH_009 regardless of soft-delete state). The variance view renders with a banner: "This variance references a soft-deleted pricelist (deleted_at = <date>)." Categorisation is allowed but routes back to the audit case file rather than to the standard variance dashboard (which excludes soft-deleted records). |
| # | Scenario | Condition | Expected |
|---|---|---|---|
| VPL-FIN-EDGE-01 | Concurrent variance categorisation on the same row from two Finance Officer sessions | Officer A and B both open variance row VAR-001 for (PL-V1, P1); A categorises as within-tolerance at T; B categorises as vendor-over-bill at T + 1s using a stale read |
First categorisation wins atomically — A's within-tolerance is persisted. B's categorisation is rejected with "This variance was categorised by another user. Please refresh and re-review." B's UI prompts a refresh. No double-categorisation; activity log is preserved in time order. |
| VPL-FIN-EDGE-02 | Variance straddles the tolerance boundary exactly | Pricelist price ฿50.00; invoice price ฿50.75; tenant tolerance exactly 1.5%; variance is 1.5% exactly |
Boundary handling per tenant configuration: inclusive (variance = tolerance is within) or exclusive (variance = tolerance is outside). Default inclusive — the variance is categorised within-tolerance automatically on the PO side per PO_POST_008; Finance Officer's dashboard shows the row with the boundary indicator but no action required. Tenant can flip to exclusive in VPL_XMOD_009 validation-rule registry configured by the Sysadmin. |
| VPL-FIN-EDGE-03 | Multi-currency co-signoff race — Finance Manager and Purchasing Manager save at the same instant | Multi-currency pricelist PL-V-EUR ready for activation; both Finance Manager and Purchasing Manager click Sign Off / Approve simultaneously within 500 ms |
Backend serialises both signoff writes by timestamp. The second signoff to land is the one that triggers VPL_POST_017 — at that point both signoffs are present in tb_pricelist_comment (in some order), the activation fires, and the pricelist transitions to active. No double-activation; the activation system comment fires exactly once with the actor being whichever signoff landed second. |
| VPL-FIN-EDGE-04 | FX-only variance that crosses cumulative-exposure threshold | Multiple FX-only variances over 30 days against the same vendor; cumulative THB-equivalent FX exposure exceeds tenant threshold (e.g., ฿1,000,000 cumulative realised FX losses) |
Finance Officer's dashboard surfaces the cumulative exposure indicator; recommends escalation to Finance Manager for hedging-policy review out-of-band. No action on individual pricelists; the cumulative finding is logged at the vendor / period level as an audit object. Finance Manager reviews and may recommend currency-hedging policy changes to the Sysadmin (a separate flow outside this module). |
| VPL-FIN-EDGE-05 | Pricelist has no coverage for a product on PR | PR-line creation found no active pricelist for (V1, P1, THB) and was created with pricelist_type = manual_input per VPL_XMOD_002; later, GRN posts at that line's price; Finance Officer's variance dashboard cannot compute a variance because there is no pricelist anchor |
Variance dashboard surfaces a special row: "Pricelist coverage gap — no anchor for variance comparison." Finance Officer routes the case to the Purchasing Manager with a recommendation to launch a campaign for (V1, P1) coverage. No tb_pricelist row exists to comment on; the comment lives on the vendor / product registry instead, ensuring the gap is surfaced in the next campaign-planning cycle. |
| VPL-FIN-EDGE-06 | Decimal precision on FX-converted variance amount | PO currency_id = USD, line value = $10,000.00; invoice $10,005.00 (variance 0.05 %); PO date FX 36.50; invoice date FX 36.55; tenant tolerance 0.1% |
Variance computed on the invoice-currency side first ($5.00 ÷ $10,000.00 = 0.05%); within tolerance — within-tolerance categorisation. The THB-equivalent FX delta is 0.13% ((36.55 − 36.50) ÷ 36.50), categorised separately as FX-only. The two facets are tracked separately; no double-counting. AP posts the realised FX gain / loss; PPV is $5.00 × 36.55 = ฿182.75. |
X-VPL-03 (multi-currency co-signoff with Purchasing Manager), X-VPL-06 (GRN variance audit feeding back to the Purchaser).VPL_AUTH_009 (Finance Officer read-only), VPL_AUTH_010 (Finance Manager co-signoff right), VPL_AUTH_014 (segregation of duties — Finance Manager co-signs but does not flip status alone). § 5 — VPL_POST_017 (activation, conditional on Finance Manager signoff for multi-currency), VPL_POST_018 (Finance veto path), VPL_POST_019 (inactivation, recommended by Finance, executed by Purchaser). § 3 — VPL_CALC_001–VPL_CALC_002 (tax decomposition Finance verifies), VPL_CALC_005 (multi-currency display — pricelist never FX-mutated), VPL_CALC_006 (quality score Finance reviews). § 6 — VPL_XMOD_005 (GRN price-variance check; Finance's primary entry point), VPL_XMOD_002 (PR manual_input coverage gap), VPL_XMOD_008 (currency master integrity), VPL_XMOD_009 (validation engine — Finance reads but does not configure).PO_POST_008 (three-way-match success → AP posting; pricelist-side categorisation = within-tolerance or PPV), PO_POST_009 (three-way-match failure → invoice held in dispute; pricelist-side categorisation = vendor over-bill or pricelist out-of-date). § 6 — PO_XMOD_007 (AP / three-way-match interaction).tb_pricelist.info.validation_results / quality_score shape consumed by Finance read; the comment tables Finance writes to (tb_pricelist_comment for header-level findings, tb_pricelist_detail_comment for per-row variance categorisation).pricelist_type = manual_input coverage-gap origin (VPL-FIN-EDGE-05).../carmen/docs/vendor-pricelist-management/tasks.md. Cross-module integration tests exercise the PO three-way-match boundary that feeds into the pricelist-side variance categorisation.