"""Analytics endpoints: category aggregation (Decimal regression) and the arbitrary date-range filters added for the Analytics range picker.""" from datetime import datetime from decimal import Decimal from app.api.v1.endpoints.analytics import daily_spending, spending_by_category from app.models.models import Category, Transaction from tests.test_installments import make_cc_tx def seed(session): cat = Category(name="Groceries") session.add(cat) session.commit() make_cc_tx(session, merchant="A", amount="1000.50", reference="a1", date=datetime(2026, 6, 2), category_id=cat.id) make_cc_tx(session, merchant="B", amount="2000.00", reference="b1", date=datetime(2026, 6, 20)) return cat class TestSpendingByCategory: def test_decimal_sum_does_not_crash_and_percentages_add_up(self, session): """Regression: Decimal grand total vs float row total raised TypeError, 500ing the endpoint whenever it had data.""" seed(session) rows = spending_by_category(session=session, _user="t") assert {r.category_name for r in rows} == {"Groceries", "Uncategorized"} assert sum(r.percentage for r in rows) == 100.0 def test_date_range_overrides_cycle(self, session): seed(session) rows = spending_by_category( start_date="2026-06-01", end_date="2026-06-10", cycle_year=2026, cycle_month=1, # would match nothing; range must win session=session, _user="t", ) assert len(rows) == 1 assert rows[0].category_name == "Groceries" assert rows[0].total == 1000.50 class TestDailySpending: def test_date_range_filter(self, session): seed(session) rows = daily_spending( start_date="2026-06-15", end_date="2026-07-01", session=session, _user="t", ) assert [r.date for r in rows] == ["2026-06-20"] assert rows[0].total == 2000.00 def test_future_cuotas_excluded(self, session): make_cc_tx(session, merchant="FUTURE", amount="500.00", reference="f1", date=datetime(2030, 1, 19)) rows = daily_spending(session=session, _user="t") assert rows == []