Fix/multiple domain issue (#401)

* feat: enhance invoice management and immutability checks

- Update InvoiceDetailPage to prevent deletion of drafts with assigned invoice numbers, providing user feedback.
- Modify the invoice conversion API to ensure invoice number allocation occurs only after successful item insertion and proforma cancellation.
- Implement structured error responses for invoice deletion, ensuring only drafts without assigned numbers can be deleted.
- Add comprehensive tests for invoice deletion and conversion scenarios, including edge cases for draft invoices.
- Introduce immutability checks in the document management system to prevent unauthorized changes to linked documents.
- Create SQL migration to enforce document metadata immutability, ensuring compliance with accounting regulations.

* fix(invoice): prevent invoice number consumption on PDF render failure

* feat: add document journal entry immutability enforcement for delete_last_voucher RPC

* fix(invoice): implement rollback for orphan invoices on proforma cancel failure

* fix(document): extend immutability trigger to protect journal entry links
This commit is contained in:
Mattsson
2026-05-06 14:08:38 +02:00
committed by GitHub
parent b9a2ce522b
commit ce3af4d17e
13 changed files with 1159 additions and 61 deletions
+25
View File
@@ -433,6 +433,12 @@ const INVOICE: Record<string, StructuredErrorEntry> = {
message_sv: 'E-postleverantören kunde inte skicka meddelandet.',
message_en: 'The email provider could not deliver the message.',
},
INVOICE_SEND_PDF_RENDER_FAILED: {
httpStatus: 500,
message_sv:
'Fakturans PDF kunde inte skapas. Kontrollera fakturarader och kunduppgifter och försök igen.',
message_en: 'Failed to render invoice PDF before send; no invoice number was consumed.',
},
INVOICE_SEND_PARTIAL: {
httpStatus: 200,
message_sv:
@@ -469,6 +475,25 @@ const INVOICE: Record<string, StructuredErrorEntry> = {
message_sv: 'Kunde inte bokföra betalningen.',
message_en: 'Failed to create payment journal entry.',
},
INVOICE_DELETE_NOT_DRAFT: {
httpStatus: 400,
message_sv: 'Endast utkast kan tas bort. Bokförda fakturor måste krediteras istället.',
message_en: 'Only draft invoices can be deleted; non-drafts must be credited.',
remediation: {
description: 'Issue a credit note instead of deleting a posted invoice.',
},
},
INVOICE_DELETE_NUMBERED: {
httpStatus: 400,
message_sv:
'Det här utkastet har redan tilldelats ett löpnummer och kan inte tas bort. Försök skicka det igen — om sändningen lyckas behövs inget annat steg.',
message_en:
'Draft already has an invoice number assigned; refusing to delete to preserve the number sequence. Retry the send — assignment is idempotent.',
remediation: {
description:
'Retry sending the invoice; ensureInvoiceNumber is idempotent so no new number will be consumed. If sending is no longer desired, contact support to clean up the orphan number.',
},
},
}
const SUPPLIER_INVOICE: Record<string, StructuredErrorEntry> = {