- Add reconciled_with_id column to transactions (links manual → statement tx) - CSV import wizard: 4-step modal (upload → map columns → review → done) - Handles any bank format via column mapping with localStorage presets - Single signed or separate debit/credit column modes - Editable preview table before committing - Auto-tags all imported rows with 'csv-import' - Batch reconcile page: shows all unreconciled manual transactions with potential statement matches (date ±3 days, amount ±1%) pre-fetched - Select matches across multiple rows, apply all at once - Copies overrides/tags/splits from manual → statement tx atomically - Manual tx marked reconciled (linked), hidden from main transactions view - Transactions with no matches shown separately - Import CSV button on transactions page - Reconcile nav item in sidebar
32 lines
1.0 KiB
TypeScript
32 lines
1.0 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import { getCurrentUser } from "@/lib/auth";
|
|
import { ensureTag, batchInsertCSVTransactions } from "@/lib/queries";
|
|
|
|
export async function POST(req: NextRequest) {
|
|
const user = await getCurrentUser(req);
|
|
if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 403 });
|
|
|
|
const body = await req.json() as {
|
|
bank_name: string;
|
|
transactions: {
|
|
date: string;
|
|
description: string;
|
|
amount: number;
|
|
transaction_type: string;
|
|
merchant_name?: string;
|
|
foreign_currency_amount?: number;
|
|
foreign_currency_code?: string;
|
|
category?: string;
|
|
}[];
|
|
};
|
|
|
|
if (!Array.isArray(body.transactions) || body.transactions.length === 0) {
|
|
return NextResponse.json({ error: "No transactions provided" }, { status: 400 });
|
|
}
|
|
|
|
const tagId = await ensureTag("csv-import", "#8b5cf6");
|
|
const inserted = await batchInsertCSVTransactions(user.id, body.transactions, tagId);
|
|
|
|
return NextResponse.json({ inserted }, { status: 201 });
|
|
}
|