fix(shared): exclude payments from balance when tag filter is active
This commit is contained in:
@@ -299,6 +299,9 @@ export default function SharedPage() {
|
||||
{addingParticipant && <AddParticipantForm onDone={() => setAddingParticipant(false)} />}
|
||||
|
||||
{/* Balance cards */}
|
||||
{realTagIds.length === 0 && tagIds.includes("untagged") ? null : realTagIds.length > 0 && (
|
||||
<p className="text-xs text-zinc-500 mb-2">Showing split totals for selected tag — payments excluded (payments settle overall debt, not per-tag)</p>
|
||||
)}
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{balLoading ? (
|
||||
<p className="text-zinc-500 text-sm col-span-3">Loading balances...</p>
|
||||
|
||||
+18
-12
@@ -287,10 +287,25 @@ export async function getParticipantBalances(ownerId: number, tagIds?: number[])
|
||||
tagFilter = `AND EXISTS (SELECT 1 FROM transaction_tags tt WHERE tt.transaction_id = t.id AND tt.tag_id = ANY($2::int[]))`;
|
||||
}
|
||||
|
||||
// Payments settle the total relationship between two people, not a specific tag.
|
||||
// Only subtract payments when viewing the unfiltered total; with a tag filter
|
||||
// active, show the raw split amount for that tag context only.
|
||||
const paymentsJoin = tagIds?.length ? "" : `
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
CASE WHEN sp.from_participant_id != $1 THEN sp.from_participant_id ELSE sp.to_participant_id END AS pid,
|
||||
SUM(CASE WHEN sp.to_participant_id = $1 THEN sp.amount ELSE -sp.amount END) AS net_paid
|
||||
FROM split_payments sp
|
||||
WHERE sp.from_participant_id = $1 OR sp.to_participant_id = $1
|
||||
GROUP BY pid
|
||||
) payments ON payments.pid = p.id`;
|
||||
const paymentsSelect = tagIds?.length ? "" : "- COALESCE(payments.net_paid, 0)::numeric(12,2)";
|
||||
const paymentsGroup = tagIds?.length ? "" : ", payments.net_paid";
|
||||
|
||||
return queryRaw<ParticipantBalance>(`
|
||||
SELECT p.id, p.name,
|
||||
COALESCE(SUM(splits.signed_amount), 0)::numeric(12,2)
|
||||
- COALESCE(payments.net_paid, 0)::numeric(12,2) AS total_owed,
|
||||
${paymentsSelect} AS total_owed,
|
||||
COALESCE(SUM(splits.split_count), 0)::int AS unsettled_count
|
||||
FROM participants p
|
||||
|
||||
@@ -317,19 +332,10 @@ export async function getParticipantBalances(ownerId: number, tagIds?: number[])
|
||||
WHERE ts.participant_id = $1 AND COALESCE(t.owner_id, s.owner_id) != $1
|
||||
${tagFilter}
|
||||
) splits ON splits.pid = p.id
|
||||
|
||||
-- Net payments always unfiltered (payments are against total debt, not per-tag)
|
||||
LEFT JOIN (
|
||||
SELECT
|
||||
CASE WHEN sp.from_participant_id != $1 THEN sp.from_participant_id ELSE sp.to_participant_id END AS pid,
|
||||
SUM(CASE WHEN sp.to_participant_id = $1 THEN sp.amount ELSE -sp.amount END) AS net_paid
|
||||
FROM split_payments sp
|
||||
WHERE sp.from_participant_id = $1 OR sp.to_participant_id = $1
|
||||
GROUP BY pid
|
||||
) payments ON payments.pid = p.id
|
||||
${paymentsJoin}
|
||||
|
||||
WHERE p.id != $1
|
||||
GROUP BY p.id, p.name, payments.net_paid
|
||||
GROUP BY p.id, p.name ${paymentsGroup}
|
||||
ORDER BY p.name
|
||||
`, params);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user