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.
Ten routes accepted requests with no getCurrentUser check (transactions/[id],
bulk, splits, tags-on-tx, splits/settle, statements/[id], tags, tags/[id],
merchants, participants/[id]/balance), and by-id routes did no ownership
check at all — any participant could read or modify another's data.
Adds canAccessTransactions() (owner via statement/direct, or split
participant), applies it to every transaction-scoped route, owner-scopes
statements/[id], and rescopes splits/settle in raw SQL so settlement only
touches splits the caller is party to.
Also: all trip analytics now sum COALESCE(amount_aud, amount) instead of raw
amount, matching every other analytics query — trip totals previously added
foreign-currency amounts to AUD ones unit-less.
And rules apply_split no longer delete+reinserts splits (which reset settled
flags on every run) — it upserts share_percent and removes only participants
no longer in the rule.