From c6df6a6d38d00eff982e12bf425fe84ca515428e Mon Sep 17 00:00:00 2001 From: Bastian Wagner Date: Mon, 3 Aug 2026 21:12:27 +0200 Subject: [PATCH] fix: handle negative-zero and half-cent rounding in formatGermanAmount --- .../cashbox-export.utils.spec.ts | 22 +++++++++++++++++++ .../cashbox-export/cashbox-export.utils.ts | 4 +++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/myteamwallet_backend/src/cashbox-export/cashbox-export.utils.spec.ts b/myteamwallet_backend/src/cashbox-export/cashbox-export.utils.spec.ts index 8e08973..54d32a0 100644 --- a/myteamwallet_backend/src/cashbox-export/cashbox-export.utils.spec.ts +++ b/myteamwallet_backend/src/cashbox-export/cashbox-export.utils.spec.ts @@ -133,4 +133,26 @@ describe('buildCsv', () => { 'Datum;Typ;Wer;Notiz;Betrag;Periodensaldo\r\nKeine Buchungen im gewählten Zeitraum', ); }); + + it('formats negative-zero as positive zero', () => { + const csv = buildCsv([ + { date: '2026-08-05T00:00:00.000Z', type: 'expense', who: 'Teamkasse', note: 'Test', amount: -0.001, runningTotal: 0 }, + ]); + + expect(csv).toBe( + 'Datum;Typ;Wer;Notiz;Betrag;Periodensaldo\r\n' + + '2026-08-05;Ausgabe;Teamkasse;Test;0,00;0,00', + ); + }); + + it('rounds half-cent boundaries correctly', () => { + const csv = buildCsv([ + { date: '2026-08-05T00:00:00.000Z', type: 'payment', who: 'Alex Muster', note: 'Test', amount: 1.005, runningTotal: 1.005 }, + ]); + + expect(csv).toBe( + 'Datum;Typ;Wer;Notiz;Betrag;Periodensaldo\r\n' + + '2026-08-05;Zahlung;Alex Muster;Test;1,01;1,01', + ); + }); }); diff --git a/myteamwallet_backend/src/cashbox-export/cashbox-export.utils.ts b/myteamwallet_backend/src/cashbox-export/cashbox-export.utils.ts index 54e90b9..f8ef725 100644 --- a/myteamwallet_backend/src/cashbox-export/cashbox-export.utils.ts +++ b/myteamwallet_backend/src/cashbox-export/cashbox-export.utils.ts @@ -68,7 +68,9 @@ const TYPE_LABELS: Record = { }; function formatGermanAmount(value: number): string { - return value.toFixed(2).replace('.', ','); + const rounded = Math.round((value + Number.EPSILON) * 100) / 100; + const normalized = rounded === 0 ? 0 : rounded; + return normalized.toFixed(2).replace('.', ','); } function escapeCsvField(value: string): string {