fix(transactions): include 'overdue' in match-supplier-invoice CAS guard (#779)

SupplierInvoicePicker shows overdue invoices as payable candidates, but
the CAS update in the match route omitted 'overdue' from its status
whitelist. This caused the update to return 0 rows for any overdue
invoice, committing a journal entry and then orphaning it before
returning MATCH_SI_NOT_OPEN — making the match appear to fail due to a
concurrent request. The v1 route already had this correct.

Signed-off-by: Jonas Flodén <jonas@floden.nu>
This commit is contained in:
Jonas Flodén
2026-06-29 22:13:48 +02:00
committed by GitHub
parent b2aa79d553
commit da692c2898
2 changed files with 15 additions and 2 deletions
@@ -81,6 +81,7 @@ function enqueueHappyPath(opts: {
exchange_rate?: number | null
remaining_amount?: number
paid_amount?: number
status?: string
}
accountingMethod?: string
}) {
@@ -103,7 +104,7 @@ function enqueueHappyPath(opts: {
id: SI_UUID,
currency: opts.invoice.currency,
exchange_rate: opts.invoice.exchange_rate ?? null,
status: 'registered',
status: opts.invoice.status ?? 'registered',
remaining_amount: opts.invoice.remaining_amount ?? 225,
paid_amount: opts.invoice.paid_amount ?? 0,
supplier: { supplier_type: 'eu_business' },
@@ -285,6 +286,18 @@ describe('POST /api/transactions/[id]/match-supplier-invoice — non-FX paths',
expect(details.excess).toBe(1000)
})
it('succeeds for an overdue invoice (status is a valid CAS target)', async () => {
// Regression: CAS guard previously omitted 'overdue', so selecting an overdue
// invoice from SupplierInvoicePicker would commit a JE, fail the update, orphan
// the voucher, and return MATCH_SI_NOT_OPEN.
enqueueHappyPath({
transaction: { amount: -1000, currency: 'SEK' },
invoice: { currency: 'SEK', remaining_amount: 1000, status: 'overdue' },
})
const res = await POST(makeReq(), createMockRouteParams({ id: TX_UUID }))
expect(res.status).toBe(200)
})
it('does NOT trigger overshoot guard on currency mismatch (FX path clamps to remaining)', async () => {
// SEK transaction paying a EUR invoice. The currency-mismatch branch
// collapses paymentAmountInvoiceCurrency to invoice.remaining_amount and
@@ -330,7 +330,7 @@ export const POST = withRouteContext(
transaction_id: transactionId,
})
.eq('id', supplier_invoice_id)
.in('status', ['registered', 'approved', 'partially_paid'])
.in('status', ['registered', 'approved', 'partially_paid', 'overdue'])
.select('id')
if (updateInvError) {