fix(invoices): render statutory PDF notices in the document language (#2321)

* fix(invoices): render statutory PDF notices in the document language

An English invoice PDF printed "Omsättning utanför EU, ML 10 kap." and
"Godkänd för F-skatt" in Swedish, and the notice boxes below the totals
(proforma, VAT notice, notes) each had their own colour, border and
spacing, so the stack looked patchy.

The export notice is stamped in Swedish on invoices.reverse_charge_text at
create time and stored as a snapshot; the PDF printed it verbatim. The
template now matches the stored text against the shared EXPORT_NOTICE_SV
constant from vat-rules.ts and renders it from LABELS in the document
language, so already-created invoices are fixed as well. Custom or unknown
text is printed exactly as stored. The English footer reads "Approved for
F-tax (Godkänd för F-skatt)": SFL 10 kap. 12 § requires the approval to be
stated but prescribes no language, and Peppol SE-R-005 is satisfied by the
UBL file, which is unchanged.

All notices share one noticeBox style: same border, radius, padding and
spacing in a neutral palette.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYtWUhYjfQyrEJodjipxW1

* docs(invoices): cite the skill for the F-tax wording and add docstrings

Review pass on PR #2321: the Swedish compliance review flagged that the
F-skatt comment asserted an SFL paragraph without a skill citation, so the
comment and the DECISIONS.md line now rest on what the
swedish-invoice-compliance skill states (no language requirement for
invoice text in ML) and on the literal Swedish phrase staying on the PDF.
CodeRabbit's docstring check wanted JSDoc on localizeVatNotice and the
test helpers.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYtWUhYjfQyrEJodjipxW1

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Mattsson
2026-09-05 16:32:48 +02:00
committed by GitHub
co-authored by Claude Fable 5.1
parent cbe5580886
commit eb2ae1da17
4 changed files with 176 additions and 34 deletions
+12 -2
View File
@@ -176,6 +176,16 @@ export interface VatRule {
reverseChargeText?: string
}
/**
* Statutory notices stamped on an invoice's reverse_charge_text at create
* time. The stored value is a snapshot, so the PDF template matches against
* these exact strings to render the notice in the recipient's language;
* keep them byte-identical to what getVatRules() writes.
*/
export const EU_REVERSE_CHARGE_NOTICE =
'Omvänd skattskyldighet / Reverse charge - VAT to be accounted for by the recipient as per Article 196, Council Directive 2006/112/EC'
export const EXPORT_NOTICE_SV = 'Omsättning utanför EU, ML 10 kap.'
/**
* Determine VAT treatment based on customer type and VAT validation status.
*
@@ -209,7 +219,7 @@ export function getVatRules(
treatment: 'reverse_charge',
rate: 0,
momsRuta: '39',
reverseChargeText: 'Omvänd skattskyldighet / Reverse charge - VAT to be accounted for by the recipient as per Article 196, Council Directive 2006/112/EC',
reverseChargeText: EU_REVERSE_CHARGE_NOTICE,
}
}
// EU business without validated VAT number, or one whose country is
@@ -225,7 +235,7 @@ export function getVatRules(
treatment: 'export',
rate: 0,
momsRuta: '40',
reverseChargeText: 'Omsättning utanför EU, ML 10 kap.',
reverseChargeText: EXPORT_NOTICE_SV,
}
default: