Initial commit

This commit is contained in:
nabeel
2026-05-27 13:58:05 +10:00
commit c2202ea0bb
89 changed files with 28855 additions and 0 deletions

View File

View File

@@ -0,0 +1,9 @@
from fastapi import APIRouter
from ..clients.firefly_client import firefly_client
router = APIRouter()
@router.get("")
async def list_accounts():
accounts = await firefly_client.get_accounts()
return {"data": accounts}

View File

@@ -0,0 +1,9 @@
from fastapi import APIRouter
from ..clients.firefly_client import firefly_client
router = APIRouter()
@router.get("")
async def list_categories():
categories = await firefly_client.get_categories()
return {"data": categories}

View File

@@ -0,0 +1,44 @@
from fastapi import APIRouter
import logging
from ..clients.firefly_client import firefly_client
logger = logging.getLogger("reports_router")
router = APIRouter()
@router.get("/spending-by-category")
async def spending_by_category():
try:
transactions = await firefly_client.get_transactions()
logger.info("Fetched %d transactions from Firefly for reports", len(transactions))
category_totals = {}
for transaction in transactions:
attrs = transaction.get("attributes", {})
legs = attrs.get("transactions", []) or []
for leg in legs:
try:
leg_amount = float(leg.get("amount", 0))
except Exception:
leg_amount = 0.0
leg_type = (leg.get("type") or "").lower()
# we consider 'withdrawal' legs as spending
if leg_type == "withdrawal" or (leg.get("destination_type") or "").lower().startswith("expense"):
category_name = leg.get("category_name") or leg.get("category") or attrs.get("category_name") or attrs.get("category_id") or "Uncategorized"
category_totals[category_name] = category_totals.get(category_name, 0) + abs(leg_amount)
data = [
{"name": name, "amount": amount}
for name, amount in sorted(category_totals.items(), key=lambda item: item[1], reverse=True)
]
return {"data": data}
except Exception as e:
logger.exception("Error computing spending-by-category: %s", e)
# Return 500 with message for frontend debugging
from fastapi import HTTPException
raise HTTPException(status_code=500, detail="Error fetching report data")

View File

@@ -0,0 +1,49 @@
from fastapi import APIRouter
from ..clients.firefly_client import firefly_client
router = APIRouter()
@router.get("/dashboard")
async def dashboard_summary():
transactions = await firefly_client.get_transactions()
total_transactions = len(transactions)
total_expenses = 0.0
total_income = 0.0
category_totals = {}
for transaction in transactions:
attrs = transaction.get("attributes", {})
legs = attrs.get("transactions", []) or []
# Each transaction may contain one or more legs; sum per-leg amounts
for leg in legs:
# amount is typically a string like "4.870000000000"
try:
leg_amount = float(leg.get("amount", 0))
except Exception:
leg_amount = 0.0
leg_type = (leg.get("type") or "").lower()
# classify by leg type: 'withdrawal' -> expense, 'deposit' -> income
if leg_type == "withdrawal" or (leg.get("destination_type") or "").lower().startswith("expense"):
total_expenses += abs(leg_amount)
category_name = leg.get("category_name") or leg.get("category") or attrs.get("category_name") or attrs.get("category_id") or "Uncategorized"
category_totals[category_name] = category_totals.get(category_name, 0) + abs(leg_amount)
elif leg_type == "deposit" or (leg.get("destination_type") or "").lower().startswith("asset"):
total_income += leg_amount
else:
# fallback: if leg_amount > 0 treat as income
if leg_amount > 0:
total_income += leg_amount
top_categories = [
{"name": name, "amount": amount}
for name, amount in sorted(category_totals.items(), key=lambda item: item[1], reverse=True)
][:5]
return {
"total_transactions": total_transactions,
"total_expenses": total_expenses,
"total_income": total_income,
"top_categories": top_categories,
}

View File

@@ -0,0 +1,17 @@
from fastapi import APIRouter
from ..clients.firefly_client import firefly_client
router = APIRouter()
@router.get("")
async def list_transactions():
transactions = await firefly_client.get_transactions()
return {"data": transactions}
@router.get("/sample")
async def transaction_sample():
transactions = await firefly_client.get_transactions()
if transactions:
return {"sample": transactions[0]}
return {"sample": None}