Files
accounted/lib/pdf/number-text.ts
T
Jakob Wennberg cc7050f6cb 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
2026-08-30 11:22:05 +02:00

41 lines
1.7 KiB
TypeScript

/**
* Sign guard for numbers rendered with @react-pdf/renderer.
*
* `Intl.NumberFormat('sv-SE')` and `toLocaleString('sv-SE')` write negatives
* with U+2212 MINUS SIGN, not the ASCII hyphen-minus. The bundled standard
* PDF fonts (Helvetica, Courier, Times: WinAnsi encoding) have no glyph for
* U+2212, so react-pdf emits an unmapped byte and the viewer draws nothing:
* a loss prints as a profit, a credit note as a charge (issue #1982, first
* seen on Årets resultat in the årsredovisning PDF).
*
* Run every locale-formatted amount through this before it reaches a <Text>
* that uses a standard font. Embedded TrueType fonts do carry the glyph, but
* the ASCII hyphen renders identically there, so applying it everywhere is
* safe.
*/
/** Built via fromCharCode so no editor or transport can normalise it away. */
export const UNICODE_MINUS = String.fromCharCode(0x2212)
/** "-0", "-0,00", "-0.00": a negated zero or sub-öre rounding noise. */
const NEGATIVE_ZERO = /^-0(?:[.,]0+)?$/
/**
* Locale-formatted number text made safe for a standard PDF font: U+2212
* becomes the ASCII hyphen-minus, and a negative zero (which the dropped
* glyph used to hide) prints unsigned, as it does on screen.
*/
export function pdfNumberText(text: string): string {
const ascii = text.replaceAll(UNICODE_MINUS, '-')
return NEGATIVE_ZERO.test(ascii) ? ascii.slice(1) : ascii
}
/**
* Free text (a formula, a label) made safe for a standard PDF font: U+2212
* becomes the ASCII hyphen-minus. Unlike pdfNumberText it never touches a
* leading "-0", because the text is not a single number.
*/
export function pdfText(text: string): string {
return text.replaceAll(UNICODE_MINUS, '-')
}