fix(bookkeeping): let a rättelseverifikation be stornoed; unblock aged supplier-invoice deletion (#1204)

* fix(bookkeeping): let a rättelseverifikation be stornoed; unblock aged supplier-invoice deletion

A user who corrected a booking (storno + rättelse) and then discovered the
affärshändelse was already booked by another verifikat had no sanctioned way
out: reverseEntry refused source_type 'correction' alongside 'storno', and
correctEntry rightly rejects a zeroing rättelse (BFL 5 kap 5 §). The same
guard also broke uncategorize-after-rättelse, since bank transactions are
relinked to the correction entry.

- reverseEntry now blocks only 'storno' (storno-of-a-storno keeps the chain
  ambiguity problem); a correction entry is a regular live verifikat and can
  be stornoed, with correction_of_id keeping the chain traceable.
- CANNOT_REVERSE_STORNO copy narrowed to stornos + remediation hint.
- Supplier-invoice DELETE now allows unbooked, unpaid invoices in
  registered/approved/overdue: the daily overdue cron flipped unbooked
  invoices past due_date into a state where deletion was blocked forever.
  Orphan-safety checks (registration JE, payments, accrual schedule) are what
  actually protect the books. UI shows the delete button accordingly.
- LinkVoucherPicker showed customer-side copy (kundfordran/1510) in
  supplier-invoice mode; supplier mode now explains the 2440-debit
  requirement, including why a direct-cost verifikat cannot be linked.

Support case 2026-07-26 (marcus@).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(supplier-invoices): review fixes: fail-closed orphan lookups, hide delete when payments loaded

- The payment and accrual-schedule lookups in DELETE now fail closed: a
  lookup error returns 500 instead of reading as "nothing linked" and
  letting the delete proceed unverified.
- The delete button also requires the loaded payment list to be empty,
  matching the server predicate.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs: authorize 'approved' in supplier-invoice delete allow-list (compliance-swarm V2.3)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Jakob Wennberg
2026-07-26 12:49:10 +02:00
committed by GitHub
co-authored by Claude Fable 5
parent 968161b42b
commit 1270b6daeb
12 changed files with 291 additions and 68 deletions
+6 -4
View File
@@ -191,8 +191,10 @@ const BOOKKEEPING: Record<string, StructuredErrorEntry> = {
},
CANNOT_REVERSE_STORNO: {
httpStatus: 400,
message_sv: 'En stornering eller rättelse kan inte stornas.',
message_en: 'A storno or correction entry cannot be reversed.',
message_sv:
'En stornering kan inte stornas. Om verifikationen makulerades av misstag, bokför den på nytt (kopiera originalet).',
message_en:
'A storno entry cannot be reversed. If the entry was cancelled by mistake, re-book it (copy the original).',
},
CANNOT_CORRECT_NON_POSTED: {
httpStatus: 400,
@@ -1934,9 +1936,9 @@ const SUPPLIER_INVOICE_WAVE4: Record<string, StructuredErrorEntry> = {
SI_DELETE_HAS_BOOKING: {
httpStatus: 400,
message_sv:
'Leverantörsfakturan är bokförd eller har en periodisering och kan inte tas bort. Skapa en kreditfaktura i stället för att återställa bokföringen.',
'Leverantörsfakturan är bokförd, har registrerade betalningar eller en periodisering och kan inte tas bort. Skapa en kreditfaktura i stället för att återställa bokföringen.',
message_en:
'The supplier invoice has a posted journal entry or an accrual schedule and cannot be deleted. Create a credit note instead to reverse the bookkeeping.',
'The supplier invoice has a posted journal entry, recorded payments, or an accrual schedule and cannot be deleted. Create a credit note instead to reverse the bookkeeping.',
},
SI_PAID_ALREADY: {
httpStatus: 409,