75 lines
2.4 KiB
TypeScript
75 lines
2.4 KiB
TypeScript
import { NextRequest, NextResponse } from "next/server";
|
|
import { getCurrentUser } from "@/lib/auth";
|
|
import { queryRaw } from "@/lib/db";
|
|
|
|
export async function GET(req: NextRequest) {
|
|
const user = await getCurrentUser(req);
|
|
if (!user) return NextResponse.json({ error: "Unauthorized" }, { status: 403 });
|
|
|
|
// Statement-level fees and interest (aggregated by Gemini from the PDF)
|
|
const stmtRows = await queryRaw<{
|
|
bank_name: string;
|
|
fees: string;
|
|
interest: string;
|
|
}>(
|
|
`SELECT
|
|
bank_name,
|
|
SUM(COALESCE(fees_charged, 0))::numeric(12,2) AS fees,
|
|
SUM(COALESCE(interest_charged, 0))::numeric(12,2) AS interest
|
|
FROM statements
|
|
WHERE owner_id = $1
|
|
GROUP BY bank_name
|
|
HAVING SUM(COALESCE(fees_charged, 0)) + SUM(COALESCE(interest_charged, 0)) > 0
|
|
ORDER BY (SUM(COALESCE(fees_charged, 0)) + SUM(COALESCE(interest_charged, 0))) DESC`,
|
|
[user.id]
|
|
);
|
|
|
|
// Transaction-level fee and interest line items (split-adjusted)
|
|
const txnRows = await queryRaw<{
|
|
id: number;
|
|
transaction_date: string;
|
|
description: string;
|
|
merchant_name: string | null;
|
|
transaction_type: string;
|
|
my_amount: string;
|
|
bank_name: string;
|
|
}>(
|
|
`SELECT
|
|
t.id,
|
|
t.transaction_date,
|
|
t.description,
|
|
t.merchant_name,
|
|
t.transaction_type,
|
|
CASE
|
|
WHEN ts.share_percent IS NOT NULL THEN COALESCE(t.amount_aud, t.amount) * ts.share_percent / 100
|
|
ELSE COALESCE(t.amount_aud, t.amount)
|
|
END::numeric(12,2) AS my_amount,
|
|
s.bank_name
|
|
FROM transactions t
|
|
LEFT JOIN transaction_splits ts ON ts.transaction_id = t.id AND ts.participant_id = $1
|
|
JOIN statements s ON s.id = t.statement_id
|
|
WHERE s.owner_id = $1
|
|
AND t.transaction_type IN ('fee', 'interest')
|
|
ORDER BY t.transaction_date DESC`,
|
|
[user.id]
|
|
);
|
|
|
|
const by_bank = stmtRows.map((r) => ({
|
|
bank_name: r.bank_name,
|
|
fees: Number(r.fees),
|
|
interest: Number(r.interest),
|
|
total: Number(r.fees) + Number(r.interest),
|
|
}));
|
|
|
|
const transactions = txnRows.map((r) => ({
|
|
...r,
|
|
my_amount: Number(r.my_amount),
|
|
}));
|
|
|
|
// Totals from statement-level data (more complete — Gemini reads the statement summary)
|
|
const total_fees = by_bank.reduce((s, r) => s + r.fees, 0);
|
|
const total_interest = by_bank.reduce((s, r) => s + r.interest, 0);
|
|
|
|
return NextResponse.json({ by_bank, transactions, total_fees, total_interest });
|
|
}
|