admin: don't mangle numeric CSV cells with the formula-injection guard

csvCell() prefixed an apostrophe to any cell whose *string* form starts
with =, +, - or @, applied to every column including numeric ones.
transactions.total_cents is legitimately negative for a net-Pfand-refund
transaction (more deposit returned than drinks bought) — a refund
exported as '-600 in that column, which Excel/LibreOffice import as text,
so SUM() over the column silently skips it. Whoever reconciles the till
against the CSV gets a total too high by the sum of all refunds, exactly
the direction that makes a short drawer look correct.

Numbers now bypass both the injection guard and the quote-escaping below
it — the guard exists for free-text columns that could carry a formula
payload, and numbers never contain the characters the escaping handles
anyway.
This commit is contained in:
iris 2026-07-31 09:23:04 +02:00 committed by mara
commit 6d88d34291

View file

@ -569,6 +569,14 @@ export function registerAdminRoutes(app: FastifyInstance, db: DB) {
function csvCell(v: unknown): string {
if (v === null || v === undefined) return '';
// Numbers (e.g. a negative total_cents from a net-Pfand-refund
// transaction) skip both the formula-injection guard and the quote
// escaping below — the guard exists for free-text columns that could
// contain a formula-injection payload; a real negative number should
// stay a real number, not get coerced into text a spreadsheet can no
// longer SUM(). Numbers also never contain `,`/`"`/`\n`, so escaping is
// moot for them anyway.
if (typeof v === 'number') return String(v);
let s = String(v);
// Neutralise spreadsheet formula injection: a cell starting with one of
// these characters is interpreted as a formula by Excel/LibreOffice when