fix(pdf): keep the minus sign on losses in standard-font PDFs (#1982) (#1987)

Intl sv-SE formats negatives with U+2212, which the bundled react-pdf Helvetica/Courier fonts cannot render, so a loss printed as a profit. lib/pdf/number-text.ts pdfNumberText maps U+2212 to an ASCII hyphen and prints negative zero unsigned; routed through financial-statement, kassaflodesanalys, reskontra, momsdeklaration, payslip (fmt, the literal Preliminar skatt sign and the calculation formula text) and operational-report templates, with content-stream regression tests. The K2/K3 arsredovisning templates keep main's formatPdfKronor from #2013.

Closes #1982
This commit is contained in:
Jakob Wennberg
2026-08-30 11:22:05 +02:00
committed by GitHub
parent 4b7343d5ec
commit cc7050f6cb
16 changed files with 592 additions and 25 deletions
+44
View File
@@ -0,0 +1,44 @@
import { describe, it, expect } from 'vitest'
import { pdfNumberText, pdfText, UNICODE_MINUS } from '../number-text'
describe('pdfNumberText', () => {
it('maps every U+2212 to the ASCII hyphen-minus', () => {
const formatted = (-4684.24).toLocaleString('sv-SE', { minimumFractionDigits: 2 })
expect(formatted).toContain(UNICODE_MINUS)
const safe = pdfNumberText(formatted)
expect(safe).not.toContain(UNICODE_MINUS)
expect(safe.startsWith('-4')).toBe(true)
expect(pdfNumberText(`${UNICODE_MINUS}1 ${UNICODE_MINUS}2`)).toBe('-1 -2')
})
it('prints a negative zero unsigned', () => {
expect(pdfNumberText((-0).toLocaleString('sv-SE'))).toBe('0')
expect(pdfNumberText(`${UNICODE_MINUS}0,00`)).toBe('0,00')
expect(pdfNumberText('-0.00')).toBe('0.00')
// A real small negative keeps its sign.
expect(pdfNumberText(`${UNICODE_MINUS}0,01`)).toBe('-0,01')
})
it('leaves text without a minus sign untouched', () => {
expect(pdfNumberText('20 316')).toBe('20 316')
expect(pdfNumberText('')).toBe('')
})
})
describe('pdfText', () => {
it('maps every U+2212 in free text to the ASCII hyphen-minus', () => {
expect(pdfText(`bruttolön ${UNICODE_MINUS} skatt ${UNICODE_MINUS} nettoavdrag`)).toBe(
'bruttolön - skatt - nettoavdrag'
)
expect(pdfText(`${UNICODE_MINUS}(full lön ${UNICODE_MINUS} sjuklön + karensavdrag)`)).toBe(
'-(full lön - sjuklön + karensavdrag)'
)
})
it('does not treat the text as a number', () => {
// A formula that happens to start with "-0" keeps its sign.
expect(pdfText(`${UNICODE_MINUS}0,5 × lön`)).toBe('-0,5 × lön')
expect(pdfText('grundlön + tillägg')).toBe('grundlön + tillägg')
expect(pdfText('')).toBe('')
})
})