From 02495e41736726d0f75c45f0a04b90c168b22bd4 Mon Sep 17 00:00:00 2001 From: siddharthd Date: Sun, 26 Jul 2026 10:00:15 +1000 Subject: [PATCH] fix(currency): show and settle foreign transactions in AUD The transactions page rendered the statement's native amount through a formatter hardcoded to AUD, so a USD row displayed its USD figure labelled as dollars while every analytics query counted the converted amount_aud. Same transaction, two different numbers depending on the page. getTransactions now returns the statement currency, the amount column shows amount_aud with the native figure beneath it when the two differ, and the split and duplicate modals seed from the converted amount (a duplicate becomes a manual AUD row, so the native figure would be wrong there). Settlement balances had the same split: getParticipantBalances and the per-participant balance route summed raw amount while trip totals summed amount_aud, so a shared foreign expense would net a USD figure against AUD ones. All three now agree on amount_aud. No change to current balances - every statement in the database is AUD today - but correct once Wise data lands. --- .../api/participants/[id]/balance/route.ts | 2 +- src/app/transactions/page.tsx | 20 ++++++++++++++----- src/lib/queries.ts | 10 ++++++++-- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/app/api/participants/[id]/balance/route.ts b/src/app/api/participants/[id]/balance/route.ts index eae3ae7..111d9b2 100644 --- a/src/app/api/participants/[id]/balance/route.ts +++ b/src/app/api/participants/[id]/balance/route.ts @@ -19,7 +19,7 @@ export async function GET( const rows = await queryRaw( `SELECT ts.participant_id, p.name, - SUM(t.amount * ts.share_percent / 100)::numeric(12,2) as total_owed, + SUM(COALESCE(t.amount_aud, t.amount) * ts.share_percent / 100)::numeric(12,2) as total_owed, COUNT(*)::int as transaction_count FROM transaction_splits ts JOIN transactions t ON t.id = ts.transaction_id diff --git a/src/app/transactions/page.tsx b/src/app/transactions/page.tsx index 93a0f02..3603516 100644 --- a/src/app/transactions/page.tsx +++ b/src/app/transactions/page.tsx @@ -22,10 +22,13 @@ function formatDate(d: string) { const SPEND_TYPES = new Set(["debit", "fee", "interest"]); -function formatAmount(amount: number, type: string) { +// `amount` is in the statement's native currency; pass the currency to label it +// correctly. Callers showing a headline figure should pass amount_aud, which is +// what every analytics query totals. +function formatAmount(amount: number, type: string, currency = "AUD") { const formatted = new Intl.NumberFormat("en-AU", { style: "currency", - currency: "AUD", + currency, }).format(amount); return SPEND_TYPES.has(type) ? formatted : `+${formatted}`; } @@ -947,7 +950,12 @@ function TransactionsContent() { - {formatAmount(t.amount, t.transaction_type)} + {formatAmount(t.amount_aud ?? t.amount, t.transaction_type)} + {t.currency && t.currency !== "AUD" && ( +
+ {formatAmount(t.amount, t.transaction_type, t.currency)} +
+ )} ))}