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
+12 -4
View File
@@ -84,11 +84,19 @@ export default function LinkVoucherPicker({
const { toast } = useToast()
const t = useTranslations('invoice_link_voucher')
// Kontantmetoden links against a bank/cash debit (19xx), not an AR credit:
// describe that. Only the customer-invoice copy varies by method.
// Supplier mode links against an AP debit (2440), kontantmetoden against a
// bank/cash debit (19xx), and the accrual customer mode against an AR credit
// (1510): the intro + empty copy must describe the right side, otherwise the
// empty state tells the user to look for a verifikat that can never match
// (support case 2026-07-26: supplier dialog spoke of kundfordran/1510).
const isSupplier = mode === 'supplier_invoice'
const isCash = mode === 'customer_invoice' && accountingMethod === 'cash'
const introKey = isCash ? 'intro_cash' : 'intro'
const emptyDescriptionKey = isCash ? 'empty_description_cash' : 'empty_description'
const introKey = isSupplier ? 'intro_supplier' : isCash ? 'intro_cash' : 'intro'
const emptyDescriptionKey = isSupplier
? 'empty_description_supplier'
: isCash
? 'empty_description_cash'
: 'empty_description'
const apiBase =
mode === 'supplier_invoice'