Initial commit
This commit is contained in:
0
backend/app/routers/__init__.py
Normal file
0
backend/app/routers/__init__.py
Normal file
BIN
backend/app/routers/__pycache__/accounts.cpython-314.pyc
Normal file
BIN
backend/app/routers/__pycache__/accounts.cpython-314.pyc
Normal file
Binary file not shown.
BIN
backend/app/routers/__pycache__/categories.cpython-314.pyc
Normal file
BIN
backend/app/routers/__pycache__/categories.cpython-314.pyc
Normal file
Binary file not shown.
BIN
backend/app/routers/__pycache__/reports.cpython-314.pyc
Normal file
BIN
backend/app/routers/__pycache__/reports.cpython-314.pyc
Normal file
Binary file not shown.
BIN
backend/app/routers/__pycache__/summary.cpython-314.pyc
Normal file
BIN
backend/app/routers/__pycache__/summary.cpython-314.pyc
Normal file
Binary file not shown.
BIN
backend/app/routers/__pycache__/transactions.cpython-314.pyc
Normal file
BIN
backend/app/routers/__pycache__/transactions.cpython-314.pyc
Normal file
Binary file not shown.
9
backend/app/routers/accounts.py
Normal file
9
backend/app/routers/accounts.py
Normal 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}
|
||||
9
backend/app/routers/categories.py
Normal file
9
backend/app/routers/categories.py
Normal 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}
|
||||
44
backend/app/routers/reports.py
Normal file
44
backend/app/routers/reports.py
Normal 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")
|
||||
49
backend/app/routers/summary.py
Normal file
49
backend/app/routers/summary.py
Normal 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,
|
||||
}
|
||||
17
backend/app/routers/transactions.py
Normal file
17
backend/app/routers/transactions.py
Normal 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}
|
||||
Reference in New Issue
Block a user