Files
boc/landvex-admin-backend/app/routers/economy.py
T
Bernt aee0f09db8 landvex: Fixar och tester klara för alla komponenter
- Datafabrik: Dockerfile fix, agentorkestrering fungerar
- Vision: Identify-modell, FAISS, OCR alla testade
- API: Alla 7 integrationstester passerade
- Upplösare: Entitetsupplösning verifierad
2026-07-05 06:41:32 +00:00

284 lines
9.9 KiB
Python

"""
Economy/Ledger Management Module
Handles accounts, transactions, bank accounts, and financial reporting
"""
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from typing import List, Optional
from datetime import datetime, date
from decimal import Decimal
from app.database import get_db
from app.models import Account, Transaction, BankAccount, AccountType, User
from app.core.security import get_current_user
router = APIRouter(prefix="/economy", tags=["economy"])
# ─── ACCOUNTS ─────────────────────────────────────────────────────────────────
@router.get("/accounts")
async def list_accounts(
account_type: Optional[AccountType] = None,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""List all accounts with optional filtering."""
query = db.query(Account)
if account_type:
query = query.filter(Account.account_type == account_type)
accounts = query.all()
return {
"accounts": [
{
"id": a.id,
"account_number": a.account_number,
"name": a.name,
"type": a.account_type.value,
"balance": float(a.balance) if a.balance else 0,
"currency": a.currency,
"is_active": a.is_active,
}
for a in accounts
],
"total": query.count(),
}
@router.post("/accounts")
async def create_account(
account_number: str,
name: str,
account_type: AccountType,
parent_id: Optional[int] = None,
description: Optional[str] = None,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Create a new account."""
account = Account(
account_number=account_number,
name=name,
account_type=account_type,
parent_id=parent_id,
description=description,
)
db.add(account)
db.commit()
db.refresh(account)
return {"status": "created", "account_id": account.id}
@router.get("/accounts/{account_id}")
async def get_account(
account_id: int,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Get account details."""
account = db.query(Account).filter(Account.id == account_id).first()
if not account:
raise HTTPException(status_code=404, detail="Account not found")
return {
"id": account.id,
"account_number": account.account_number,
"name": account.name,
"type": account.account_type.value,
"balance": float(account.balance) if account.balance else 0,
"currency": account.currency,
"description": account.description,
"is_active": account.is_active,
}
# ─── TRANSACTIONS ─────────────────────────────────────────────────────────────
@router.get("/transactions")
async def list_transactions(
account_id: Optional[int] = None,
start_date: Optional[date] = None,
end_date: Optional[date] = None,
skip: int = 0,
limit: int = 100,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""List transactions with filtering."""
query = db.query(Transaction)
if account_id:
query = query.filter(
(Transaction.debit_account_id == account_id) |
(Transaction.credit_account_id == account_id)
)
if start_date:
query = query.filter(Transaction.date >= start_date)
if end_date:
query = query.filter(Transaction.date <= end_date)
transactions = query.order_by(Transaction.date.desc()).offset(skip).limit(limit).all()
return {
"transactions": [
{
"id": t.id,
"transaction_id": t.transaction_id,
"date": t.date.isoformat() if t.date else None,
"description": t.description,
"amount": float(t.amount) if t.amount else 0,
"debit_account_id": t.debit_account_id,
"credit_account_id": t.credit_account_id,
"status": t.status,
"reference": t.reference,
}
for t in transactions
],
"total": query.count(),
}
@router.post("/transactions")
async def create_transaction(
transaction_id: str,
date: datetime,
description: str,
amount: float,
debit_account_id: int,
credit_account_id: int,
reference: Optional[str] = None,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Create a new transaction (double-entry bookkeeping)."""
# Verify accounts exist
debit_account = db.query(Account).filter(Account.id == debit_account_id).first()
credit_account = db.query(Account).filter(Account.id == credit_account_id).first()
if not debit_account or not credit_account:
raise HTTPException(status_code=404, detail="One or both accounts not found")
transaction = Transaction(
transaction_id=transaction_id,
date=date,
description=description,
amount=Decimal(str(amount)),
debit_account_id=debit_account_id,
credit_account_id=credit_account_id,
reference=reference,
created_by=current_user.id,
)
# Update account balances
debit_account.balance += Decimal(str(amount))
credit_account.balance -= Decimal(str(amount))
db.add(transaction)
db.commit()
db.refresh(transaction)
return {"status": "created", "transaction_id": transaction.id}
# ─── BANK ACCOUNTS ────────────────────────────────────────────────────────────
@router.get("/bank-accounts")
async def list_bank_accounts(
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""List all bank accounts."""
accounts = db.query(BankAccount).all()
return {
"accounts": [
{
"id": a.id,
"bank_name": a.bank_name,
"account_name": a.account_name,
"account_number": a.account_number,
"iban": a.iban,
"bic": a.bic,
"currency": a.currency,
"current_balance": float(a.current_balance) if a.current_balance else 0,
"account_type": a.account_type,
"is_active": a.is_active,
}
for a in accounts
]
}
@router.post("/bank-accounts")
async def create_bank_account(
bank_name: str,
account_name: str,
account_number: Optional[str] = None,
iban: Optional[str] = None,
bic: Optional[str] = None,
currency: str = "SEK",
account_type: Optional[str] = None,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Create a new bank account."""
account = BankAccount(
bank_name=bank_name,
account_name=account_name,
account_number=account_number,
iban=iban,
bic=bic,
currency=currency,
account_type=account_type,
)
db.add(account)
db.commit()
db.refresh(account)
return {"status": "created", "bank_account_id": account.id}
# ─── REPORTS ──────────────────────────────────────────────────────────────────
@router.get("/reports/balance-sheet")
async def get_balance_sheet(
as_of: Optional[date] = None,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Generate balance sheet report."""
assets = db.query(Account).filter(Account.account_type == AccountType.ASSET).all()
liabilities = db.query(Account).filter(Account.account_type == AccountType.LIABILITY).all()
equity = db.query(Account).filter(Account.account_type == AccountType.EQUITY).all()
return {
"report_type": "Balance Sheet",
"as_of": as_of.isoformat() if as_of else datetime.utcnow().date().isoformat(),
"assets": {
"total": sum(float(a.balance) for a in assets),
"accounts": [{"name": a.name, "balance": float(a.balance)} for a in assets]
},
"liabilities": {
"total": sum(float(l.balance) for l in liabilities),
"accounts": [{"name": l.name, "balance": float(l.balance)} for l in liabilities]
},
"equity": {
"total": sum(float(e.balance) for e in equity),
"accounts": [{"name": e.name, "balance": float(e.balance)} for e in equity]
},
}
@router.get("/reports/income-statement")
async def get_income_statement(
start_date: date,
end_date: date,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user),
):
"""Generate income statement (resultaträkning)."""
revenues = db.query(Account).filter(Account.account_type == AccountType.REVENUE).all()
expenses = db.query(Account).filter(Account.account_type == AccountType.EXPENSE).all()
total_revenue = sum(float(r.balance) for r in revenues)
total_expenses = sum(float(e.balance) for e in expenses)
return {
"report_type": "Income Statement",
"period": {"start": start_date.isoformat(), "end": end_date.isoformat()},
"revenue": {
"total": total_revenue,
"accounts": [{"name": r.name, "balance": float(r.balance)} for r in revenues]
},
"expenses": {
"total": total_expenses,
"accounts": [{"name": e.name, "balance": float(e.balance)} for e in expenses]
},
"net_income": total_revenue - total_expenses,
}