From ca705701bd892fd99f8b81b28eeb10d3cf1fb2e0 Mon Sep 17 00:00:00 2001 From: Ryan Chen Date: Mon, 12 Oct 2026 18:28:16 -0400 Subject: [PATCH] State spending-report outflows and inflows separately The ynab_spending_report 'total' was a net figure: inflows (deposits into budget accounts) subtracted from the spending total, which the model repeated back as spending. The report now states total outflows and inflows separately, drops net-negative groups from the per-group list, and computes the monthly average from outflows. --- blueprints/ynab/tools.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/blueprints/ynab/tools.py b/blueprints/ynab/tools.py index 86b60ee..c2272bc 100644 --- a/blueprints/ynab/tools.py +++ b/blueprints/ynab/tools.py @@ -381,19 +381,34 @@ async def ynab_spending_report( GROUP BY 1 ORDER BY {order}""", *params, ) + rows = [r for r in rows if r["spent"] > 0] if not rows: return f"No spending found from {start} to {end}." - total = sum((r["spent"] for r in rows), Decimal(0)) + totals = await _query( + f"""{LINES_CTE} + SELECT COALESCE(-SUM(LEAST(l.amount, 0)), 0) AS outflows, + COALESCE(SUM(GREATEST(l.amount, 0)), 0) AS inflows + FROM lines l + JOIN ynab_accounts a ON a.id = l.account_id + LEFT JOIN ynab_categories c ON c.id = l.category_id + WHERE {' AND '.join(conditions)}""", + *params, + ) + outflows, inflows = totals[0]["outflows"], totals[0]["inflows"] top = max(1, top) shown = rows if group_by == "month" else rows[:top] - lines = [f"Spending by {group_by} from {start} to {end}: total {_usd(total)}"] + lines = [ + f"Spending by {group_by} from {start} to {end}:", + f"- Total spending (outflows): {_usd(outflows)}", + f"- Inflows (deposits into budget accounts, not spending): {_usd(inflows)}", + ] lines += [f"- {r['key']}: {_usd(r['spent'])} ({r['n']} txns)" for r in shown] if len(rows) > len(shown): rest = sum((r["spent"] for r in rows[len(shown) :]), Decimal(0)) lines.append(f"- {len(rows) - len(shown)} others: {_usd(rest)}") if group_by == "month" and len(rows) > 1: - lines.append(f"Monthly average: {_usd(total / len(rows))}") + lines.append(f"Monthly average: {_usd(outflows / len(rows))}") return "\n".join(lines) -- 2.52.0