from fastapi import APIRouter, HTTPException, Query from decimal import Decimal from typing import Dict, Any, List from app.core.database import get_connection router = APIRouter(prefix="/trial-balance", tags=["試算表"]) def D(x) -> Decimal: return Decimal(str(x or 0)) @router.get("", summary="試算表(全科目)") def get_trial_balance( date_from: str = Query(..., description="YYYY-MM-DD"), date_to: str = Query(..., description="YYYY-MM-DD"), ): if date_from > date_to: raise HTTPException(status_code=400, detail="期間指定が不正です。") with get_connection() as conn, conn.cursor() as cur: # 全科目取得 cur.execute(""" SELECT account_id, account_code, account_name, account_type FROM accounts WHERE is_active = true ORDER BY account_code """) accounts = cur.fetchall() result_accounts: List[Dict[str, Any]] = [] total_opening = Decimal("0") total_debit = Decimal("0") total_credit = Decimal("0") total_closing = Decimal("0") for acc in accounts: aid = acc["account_id"] # 期首残高 cur.execute(""" SELECT COALESCE(SUM(l.debit - l.credit), 0) AS opening FROM journal_lines l JOIN journal_entries j ON j.journal_id = l.journal_id WHERE l.account_id = %s AND j.journal_date < %s """, (aid, date_from)) opening = D(cur.fetchone()["opening"]) # 当期 cur.execute(""" SELECT COALESCE(SUM(l.debit), 0) AS debit, COALESCE(SUM(l.credit), 0) AS credit FROM journal_lines l JOIN journal_entries j ON j.journal_id = l.journal_id WHERE l.account_id = %s AND j.journal_date BETWEEN %s AND %s """, (aid, date_from, date_to)) row = cur.fetchone() debit = D(row["debit"]) credit = D(row["credit"]) closing = opening + debit - credit total_opening += opening total_debit += debit total_credit += credit total_closing += closing result_accounts.append({ "account_id": aid, "account_code": acc["account_code"], "account_name": acc["account_name"], "account_type": acc["account_type"], "opening_balance": str(opening), "debit": str(debit), "credit": str(credit), "closing_balance": str(closing), }) return { "period": { "from": date_from, "to": date_to }, "totals": { "opening_balance": str(total_opening), "debit": str(total_debit), "credit": str(total_credit), "closing_balance": str(total_closing) }, "accounts": result_accounts }