fix(trips): stop reporting a settlement breakdown that cannot be computed
ci / lint-test (push) Successful in 35s
ci / lint-test (push) Successful in 35s
The trip view showed Total Owed / Settled / Unsettled per participant, with the last two derived from transaction_splits.settled. Nothing sets that flag - its only writer was /api/splits/settle, which no UI calls - so it is false on all 673 splits and every trip reported 100% unsettled, including trips already paid in full. Molina has paid $20,782.79 against $19,556.07 of splits and the Europe trip still showed her entire share outstanding. A correct per-trip figure is not computable either: split_payments records only from, to, amount and date, so a payment cannot be attributed to a trip. The trip view now shows each participant's share and points at Shared for what is actually owed, which is where settlement genuinely lives. Also removes /api/splits/settle. It was unreachable from the UI but live on its URL, and a single call with participant_id would mark every one of that person's splits settled - writing a flag nothing reads. Settlement will be reintroduced against settlement contexts (docs/shared-expenses-design.md). getParticipantBalances is deliberately untouched: it computes splits minus payments, which is coherent. Excluding settled splits there while still subtracting the payments that settled them would double-count.
This commit is contained in:
@@ -1,46 +0,0 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { queryRaw } from "@/lib/db";
|
||||
import { getCurrentUser } from "@/lib/auth";
|
||||
|
||||
// A split may be settled by the transaction's effective owner or by the
|
||||
// participant the split belongs to.
|
||||
const SCOPE = `
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM transactions t
|
||||
LEFT JOIN statements s ON s.id = t.statement_id
|
||||
WHERE t.id = transaction_splits.transaction_id
|
||||
AND (COALESCE(t.owner_id, s.owner_id) = $2 OR transaction_splits.participant_id = $2)
|
||||
)`;
|
||||
|
||||
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();
|
||||
const { participant_id, split_ids } = body as {
|
||||
participant_id?: number;
|
||||
split_ids?: number[];
|
||||
};
|
||||
|
||||
if (participant_id) {
|
||||
const rows = await queryRaw<{ id: number }>(
|
||||
`UPDATE transaction_splits SET settled = true, settled_at = NOW()
|
||||
WHERE participant_id = $1 AND settled = false ${SCOPE}
|
||||
RETURNING id`,
|
||||
[participant_id, user.id]
|
||||
);
|
||||
return NextResponse.json({ settled: rows.length });
|
||||
}
|
||||
|
||||
if (split_ids?.length) {
|
||||
const rows = await queryRaw<{ id: number }>(
|
||||
`UPDATE transaction_splits SET settled = true, settled_at = NOW()
|
||||
WHERE id = ANY($1::int[]) AND settled = false ${SCOPE}
|
||||
RETURNING id`,
|
||||
[split_ids, user.id]
|
||||
);
|
||||
return NextResponse.json({ settled: rows.length });
|
||||
}
|
||||
|
||||
return NextResponse.json({ error: "participant_id or split_ids required" }, { status: 400 });
|
||||
}
|
||||
Reference in New Issue
Block a user