fix(invoices): keep the stored ROT/RUT personnummer when editing a draft (#1186)

Fixes #1175. The stored personnummer exists only as AES-256-GCM
ciphertext (+ last4), so the editor cannot rehydrate it and sent an
empty string; buildInvoiceWriteData then failed ROT/RUT validation and
every edit of a draft deduction invoice was blocked with "Personnummer
krävs för ROT/RUT-avdrag" unless the user re-entered the customer's
personnummer.

buildInvoiceWriteData accepts the stored ciphertext from the update
path: an empty field on an invoice that still has deduction lines
means keep, a typed value replaces, and removing every deduction line
clears as before. The editor hint shows the kept last4 in edit mode
(new i18n key, sv+en).

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Jakob Wennberg
2026-07-25 12:59:50 +02:00
committed by GitHub
co-authored by Claude Fable 5
parent 731a57dd6e
commit 5afd031306
6 changed files with 107 additions and 5 deletions
+10 -1
View File
@@ -148,7 +148,7 @@ export const PATCH = withRouteContext<{ params: Promise<{ id: string }> }>(
// received self-billing document) may be edited.
const { data: existing, error: fetchError } = await supabase
.from('invoices')
.select('id, status, invoice_number, journal_entry_id, is_self_billed, credited_invoice_id')
.select('id, status, invoice_number, journal_entry_id, is_self_billed, credited_invoice_id, deduction_personnummer_encrypted, deduction_personnummer_last4')
.eq('id', id)
.eq('company_id', companyId!)
.single()
@@ -186,6 +186,15 @@ export const PATCH = withRouteContext<{ params: Promise<{ id: string }> }>(
customer,
documentType,
input,
// The stored personnummer exists only as ciphertext (client sees _last4
// at most), so an edit that leaves the field empty keeps it rather than
// failing ROT/RUT validation (issue #1175).
existingPersonnummer: existing.deduction_personnummer_encrypted
? {
encrypted: existing.deduction_personnummer_encrypted,
last4: existing.deduction_personnummer_last4 ?? null,
}
: null,
})
if (!build.ok) {
if ('dbError' in build) {