from datetime import timedelta from decimal import Decimal from sqlalchemy import select from factories import make_account, make_category, make_txn, month_back, refresh from fintracker.db import get_sessionmaker from fintracker.models import MetricSpendingByCategory async def rows() -> list[MetricSpendingByCategory]: async with get_sessionmaker()() as session: return list((await session.execute(select(MetricSpendingByCategory))).scalars().all()) async def test_root_category_rollup_and_uncategorised_row(app): card = await make_account(balance="0") food = await make_category("Еда") groceries = await make_category("Продукты", parent_id=food) cafe = await make_category("Кафе", parent_id=food) m = month_back(1) await make_txn( m + timedelta(days=1), outcome="700", outcome_account_id=card, primary_category_id=groceries ) await make_txn( m + timedelta(days=2), outcome="300", outcome_account_id=card, primary_category_id=cafe ) await make_txn(m + timedelta(days=3), outcome="150", outcome_account_id=card) await refresh() by_category = {r.category_id: r for r in await rows()} assert by_category[groceries].amount_rub == Decimal("700") assert by_category[groceries].root_category_id == food assert by_category[cafe].root_category_id == food assert by_category[None].amount_rub == Decimal("150") assert by_category[None].root_category_id is None assert sum(r.amount_rub for r in await rows()) == Decimal("1150") assert {r.month for r in await rows()} == {m} async def test_only_expenses_are_counted(app): card = await make_account(balance="0") savings = await make_account(name="Вклад", balance="0") m = month_back(1) await make_txn(m + timedelta(days=1), income="1000", income_account_id=card) await make_txn( m + timedelta(days=2), income="500", income_account_id=savings, outcome="500", outcome_account_id=card, ) await refresh() assert await rows() == [] async def test_top_level_category_is_its_own_root(app): card = await make_account(balance="0") transport = await make_category("Транспорт") m = month_back(1) await make_txn( m + timedelta(days=4), outcome="90", outcome_account_id=card, primary_category_id=transport, ) await refresh() (row,) = await rows() assert (row.category_id, row.root_category_id) == (transport, transport)