Fix/supp ag fb (#1023)
* fix: prevent credit notes from entering payment flow * fix: persist and display customer personal numbers * feat: configure automatic invoice reminder days * fix: issue credit notes through send flow * chore: add repository agent guidance * feat(mcp): route tools across user companies * fix(articles): delete unused register entries * feat(invoices): improve issued invoice actions * feat(supplier-invoices): retain uploaded source documents * docs: record implementation decisions * feat: enhance customer personal number handling and validation - Updated CustomerForm to allow personal numbers in the format of "********-1234" for individual customers. - Added validation to ensure personal numbers are only accepted for individual customers in CreateCustomerSchema. - Implemented masking and encryption for personal numbers to enhance data protection. - Introduced new utility functions for masking and encrypting personal numbers. - Added database migration to enforce unique constraints on credit note relationships and prevent duplicate entries. - Enhanced error handling and logging for credit note issuance and invoice processing. - Updated tests to cover new credit note creation guards and personal number handling. * test: enhance list companies test with supabase query mocks
This commit is contained in:
@@ -571,6 +571,47 @@ describe('POST :id/match-invoice', () => {
|
||||
expect((await res.json()).error.code).toBe('MATCH_INVOICE_TX_ALREADY_LINKED')
|
||||
})
|
||||
|
||||
it('rejects a credit note before creating a payment journal entry', async () => {
|
||||
mockServiceClient.mockReturnValue(
|
||||
makeFlexibleSupabase({
|
||||
company_members: { data: { company_id: COMPANY_ID, role: 'owner' }, error: null },
|
||||
transactions: {
|
||||
data: {
|
||||
id: TX_ID,
|
||||
amount: 12500,
|
||||
date: '2026-05-12',
|
||||
currency: 'SEK',
|
||||
invoice_id: null,
|
||||
},
|
||||
error: null,
|
||||
},
|
||||
invoices: {
|
||||
data: {
|
||||
id: INV_ID,
|
||||
status: 'sent',
|
||||
document_type: 'invoice',
|
||||
total: -12500,
|
||||
credited_invoice_id: 'ffffffff-ffff-4fff-8fff-ffffffffffff',
|
||||
},
|
||||
error: null,
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
const res = await matchInvoicePOST(
|
||||
makeRequest(
|
||||
`https://x.test/api/v1/companies/${COMPANY_ID}/transactions/${TX_ID}/match-invoice`,
|
||||
{ invoice_id: INV_ID },
|
||||
),
|
||||
txParams(TX_ID),
|
||||
)
|
||||
|
||||
expect(res.status).toBe(400)
|
||||
expect((await res.json()).error.code).toBe('MATCH_INVOICE_CREDIT_NOTE')
|
||||
expect(createInvPmtJE).not.toHaveBeenCalled()
|
||||
expect(createInvCashJE).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
// The v1 route threads resolveSettlementAccount(transaction.cash_account_id)
|
||||
// exactly like the dashboard route and the agent/MCP commit path; these
|
||||
// regression tests were missing here (flagged in triage on #987) even
|
||||
|
||||
@@ -180,6 +180,11 @@ export const POST = withApiV1<{ params: Promise<{ companyId: string; id: string
|
||||
details: { documentType: docType },
|
||||
})
|
||||
}
|
||||
if (invoice.credited_invoice_id) {
|
||||
return v1ErrorResponseFromCode('MATCH_INVOICE_CREDIT_NOTE', txLog, {
|
||||
requestId: ctx.requestId,
|
||||
})
|
||||
}
|
||||
if (
|
||||
invoice.status !== 'sent' &&
|
||||
invoice.status !== 'overdue' &&
|
||||
|
||||
Reference in New Issue
Block a user