"""General Ledger & Trial Balance API — Phase 5.3.""" from __future__ import annotations from decimal import Decimal from uuid import UUID from fastapi import APIRouter, Depends from pydantic import BaseModel from sqlalchemy.ext.asyncio import AsyncSession from app.api.deps import get_db, require_tenant from app.core.security import get_current_user from app.repositories.ledger import LedgerBalanceRepository from app.services.balance_engine import BalanceEngine from shared.security import CurrentUser router = APIRouter() class BalanceRead(BaseModel): account_id: UUID fiscal_period_id: UUID opening_balance: Decimal debit_total: Decimal credit_total: Decimal closing_balance: Decimal current_balance: Decimal model_config = {"from_attributes": True} class TrialBalanceRead(BaseModel): fiscal_period_id: UUID total_debit: Decimal total_credit: Decimal difference: Decimal is_balanced: bool @router.get("/balances/{account_id}", response_model=BalanceRead | None) async def get_account_balance( account_id: UUID, fiscal_period_id: UUID, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), _user: CurrentUser = Depends(get_current_user), ): repo = LedgerBalanceRepository(db) balance = await repo.get_by_account_period(tenant_id, account_id, fiscal_period_id) return balance @router.get("/balances", response_model=list[BalanceRead]) async def list_period_balances( fiscal_period_id: UUID, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), _user: CurrentUser = Depends(get_current_user), ): repo = LedgerBalanceRepository(db) return await repo.list_by_period(tenant_id, fiscal_period_id) @router.post("/trial-balance", response_model=TrialBalanceRead) async def generate_trial_balance( fiscal_period_id: UUID, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), _user: CurrentUser = Depends(get_current_user), ): engine = BalanceEngine(db) snapshot = await engine.generate_trial_balance(tenant_id, fiscal_period_id) await db.commit() return TrialBalanceRead( fiscal_period_id=snapshot.fiscal_period_id, total_debit=snapshot.total_debit, total_credit=snapshot.total_credit, difference=snapshot.difference, is_balanced=snapshot.is_balanced, ) @router.post("/recalculate") async def recalculate_balances( fiscal_period_id: UUID, tenant_id: UUID = Depends(require_tenant), db: AsyncSession = Depends(get_db), _user: CurrentUser = Depends(get_current_user), ): engine = BalanceEngine(db) count = await engine.recalculate_period(tenant_id, fiscal_period_id) await db.commit() return {"recalculated_accounts": count}