fix(reconcile): prevent split/tag double-counting on reconciled transactions
Move splits, tags and overrides from manual to statement side on reconcile (delete from manual after copying) instead of just copying. Add read-time filter to exclude reconciled manual transactions from balance and shared transaction queries. Also adds participant filter to shared expenses page.
This commit is contained in:
+7
-4
@@ -210,12 +210,15 @@ export function useParticipantBalances(tagIds?: string[]) {
|
||||
});
|
||||
}
|
||||
|
||||
export function useSharedTransactions(tagIds?: string[]) {
|
||||
export function useSharedTransactions(tagIds?: string[], participantId?: number) {
|
||||
return useQuery({
|
||||
queryKey: ["shared-transactions", tagIds],
|
||||
queryKey: ["shared-transactions", tagIds, participantId],
|
||||
queryFn: async () => {
|
||||
const params = tagIds?.length ? `?tag_ids=${tagIds.join(",")}` : "";
|
||||
const res = await fetch(`/api/shared-transactions${params}`);
|
||||
const sp = new URLSearchParams();
|
||||
if (tagIds?.length) sp.set("tag_ids", tagIds.join(","));
|
||||
if (participantId) sp.set("participant_id", String(participantId));
|
||||
const query = sp.toString() ? `?${sp.toString()}` : "";
|
||||
const res = await fetch(`/api/shared-transactions${query}`);
|
||||
return res.json();
|
||||
},
|
||||
});
|
||||
|
||||
+11
-1
@@ -329,6 +329,7 @@ export async function getParticipantBalances(ownerId: number, tagIds?: number[])
|
||||
JOIN transactions t ON t.id = ts.transaction_id
|
||||
LEFT JOIN statements s ON s.id = t.statement_id
|
||||
WHERE COALESCE(t.owner_id, s.owner_id) = $1 AND ts.participant_id != $1
|
||||
AND NOT (t.statement_id IS NULL AND t.reconciled_with_id IS NOT NULL)
|
||||
${tagFilter}
|
||||
|
||||
UNION ALL
|
||||
@@ -341,6 +342,7 @@ export async function getParticipantBalances(ownerId: number, tagIds?: number[])
|
||||
JOIN transactions t ON t.id = ts.transaction_id
|
||||
LEFT JOIN statements s ON s.id = t.statement_id
|
||||
WHERE ts.participant_id = $1 AND COALESCE(t.owner_id, s.owner_id) != $1
|
||||
AND NOT (t.statement_id IS NULL AND t.reconciled_with_id IS NOT NULL)
|
||||
${tagFilter}
|
||||
) splits ON splits.pid = p.id
|
||||
${paymentsJoin}
|
||||
@@ -542,7 +544,7 @@ export async function getTags() {
|
||||
`);
|
||||
}
|
||||
|
||||
export async function getSharedTransactions(ownerId: number, tagIds?: number[], noTags?: boolean) {
|
||||
export async function getSharedTransactions(ownerId: number, tagIds?: number[], noTags?: boolean, participantId?: number) {
|
||||
const params: unknown[] = [ownerId];
|
||||
let tagClause = "";
|
||||
if (noTags) {
|
||||
@@ -552,6 +554,12 @@ export async function getSharedTransactions(ownerId: number, tagIds?: number[],
|
||||
tagClause = `AND EXISTS (SELECT 1 FROM transaction_tags tt WHERE tt.transaction_id = t.id AND tt.tag_id = ANY($2::int[]))`;
|
||||
}
|
||||
|
||||
let participantClause = "";
|
||||
if (participantId) {
|
||||
params.push(participantId);
|
||||
participantClause = `AND EXISTS (SELECT 1 FROM transaction_splits ts_p WHERE ts_p.transaction_id = t.id AND ts_p.participant_id = $${params.length})`;
|
||||
}
|
||||
|
||||
const rows = await queryRaw<TransactionRow & { split_data: string }>(`
|
||||
SELECT t.*,
|
||||
o.category_override, o.merchant_normalized as merchant_override, o.notes,
|
||||
@@ -584,7 +592,9 @@ export async function getSharedTransactions(ownerId: number, tagIds?: number[],
|
||||
AND EXISTS (SELECT 1 FROM transaction_splits ts_me WHERE ts_me.transaction_id = t.id AND ts_me.participant_id = $1)
|
||||
)
|
||||
)
|
||||
AND NOT (t.statement_id IS NULL AND t.reconciled_with_id IS NOT NULL)
|
||||
${tagClause}
|
||||
${participantClause}
|
||||
GROUP BY t.id, o.category_override, o.merchant_normalized, o.notes, s.bank_name, s.owner_id, p_owner.name, src.created_at
|
||||
ORDER BY t.transaction_date DESC
|
||||
`, params);
|
||||
|
||||
Reference in New Issue
Block a user