from datetime import date from fastapi import APIRouter, Query from app.analytics import service from app.dependencies import Context, Db router = APIRouter(prefix="/analytics", tags=["analytics"]) @router.get("/category-spend") def category_spend( date_from: date = Query(alias="from"), date_to: date = Query(alias="to"), *, db: Db, context: Context, ) -> list[dict]: rows = service.category_spend( db, space_id=context.space.id, date_from=date_from, date_to=date_to ) return [ { "categoryId": row["category_id"], "name": row["name"], "nameKey": row["name_key"], "amountKopecks": row["amount_kopecks"], } for row in rows ] @router.get("/cash-flow") def cash_flow( date_from: date = Query(alias="from"), date_to: date = Query(alias="to"), *, db: Db, context: Context, ) -> list[dict]: rows = service.cash_flow(db, space_id=context.space.id, date_from=date_from, date_to=date_to) months: dict[str, dict[str, int | str]] = {} for row in rows: month = row["date"].strftime("%Y-%m") bucket = months.setdefault( month, { "month": month, "incomeKopecks": 0, "expenseKopecks": 0, "refundsKopecks": 0, "netKopecks": 0, }, ) amount = int(row["amount_kopecks"]) key = { "income": "incomeKopecks", "expense": "expenseKopecks", "refund": "refundsKopecks", }[row["type"]] bucket[key] = int(bucket[key]) + abs(amount) bucket["netKopecks"] = int(bucket["netKopecks"]) + amount return list(months.values()) @router.get("/plan-fact") def plan_fact(month: str, db: Db, context: Context) -> dict: from app.budgeting.router import parse_month year, month_number = parse_month(month) state = service.plan_fact(db, space_id=context.space.id, year=year, month=month_number) categories = state.get("monthly_categories", []) return { "month": month, "items": [ { "categoryId": row["category_id"], "name": row.get("name"), "nameKey": row.get("name_key"), "plannedKopecks": row["planned"], "actualKopecks": row["spent"], } for row in categories ], } @router.get("/balances") def balances(db: Db, context: Context) -> dict: from datetime import UTC, datetime rows = service.balances(db, space_id=context.space.id) assets = sum(max(row["balance_kopecks"], 0) for row in rows if row["kind"] != "credit") liabilities = sum(row["debt_kopecks"] for row in rows) return { "asOf": datetime.now(UTC).date(), "assetsKopecks": assets, "liabilitiesKopecks": liabilities, "netKopecks": assets - liabilities, "items": [ { "accountId": row["account_id"], "name": row["account"], "type": row["kind"], "balanceKopecks": row["balance_kopecks"], } for row in rows ], }