fix csv import for money tracker
All checks were successful
Test and deploy staging / staging (push) Successful in 1m44s

This commit is contained in:
2026-09-23 17:23:14 +00:00
parent 0638ead87f
commit 2466db74cd
4 changed files with 165 additions and 53 deletions

View File

@@ -11,12 +11,12 @@ import {
} from '$lib/server/db/schema';
import { requireAdmin } from '$lib/server/authorization';
import {
type ImportedTransaction,
cadence,
cents,
csvDate,
invalid,
optionalText,
parseCsv,
parseTransactionImport,
positiveId,
textField,
utilityKind,
@@ -371,42 +371,13 @@ export const actions: Actions = {
const form = await event.request.formData();
const file = form.get('file');
if (!(file instanceof File) || !file.size || file.size > 2_000_000)
return invalid('Choose a CSV file under 2 MB.');
let rows: string[][];
return invalid('Choose a CSV or TSV file under 2 MB.');
let parsed: ImportedTransaction[];
try {
rows = parseCsv(await file.text());
parsed = parseTransactionImport(await file.text());
} catch (cause) {
return invalid(cause instanceof Error ? cause.message : 'Invalid CSV.');
}
if (rows.length < 2 || rows.length > 20_001)
return invalid('The CSV must have a header and 1–20,000 rows.');
const header = rows.shift()!.map((value) =>
value
.replace(/^\uFEFF/, '')
.trim()
.toLowerCase()
);
const columns = ['date', 'account', 'description', 'amount'].map((key) => header.indexOf(key));
if (columns.some((index) => index < 0))
return invalid('CSV headers must include date, account, description and amount.');
const parsed: { date: string; account: string; description: string; amountCents: number }[] =
[];
for (const [index, row] of rows.entries()) {
const date = csvDate(row[columns[0]] ?? '');
const account = (row[columns[1]] ?? '').trim();
const description = (row[columns[2]] ?? '').trim();
const amountCents = cents(row[columns[3]]);
if (
!date ||
!account ||
account.length > 80 ||
!description ||
description.length > 500 ||
amountCents == null
)
return invalid(`Invalid data in CSV row ${index + 2}. No rows were imported.`);
parsed.push({ date, account, description, amountCents });
}
await db.transaction(async (tx) => {
const existing = await tx
.select()