Files
njts-accounting-core/backend/app/routers/trial_balance.py
2026-06-07 21:58:20 +09:00

150 lines
5.0 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from fastapi import APIRouter, Query
from datetime import date
from typing import Optional
from app.core.database import get_connection
router = APIRouter(prefix="/trial-balance", tags=["试算表"])
@router.get("", summary="试算表(全科目)")
def get_trial_balance(
fiscal_year: Optional[int] = Query(None, description="会计年度(可选)"),
date_from: Optional[date] = Query(None, description="开始日期(可选)"),
date_to: Optional[date] = Query(None, description="结束日期(可选)"),
):
print("### trial-balance OPTIONAL PARAMS ACTIVE ###")
with get_connection() as conn:
# 检查 is_latest 字段是否存在(新的版本追踪系统)
with conn.cursor() as check_cur:
check_cur.execute("""
SELECT COUNT(*) as cnt
FROM information_schema.columns
WHERE table_name = 'journal_entries' AND column_name = 'is_latest'
""")
has_is_latest = check_cur.fetchone()[0] > 0
# 构建查询语句
if has_is_latest:
# 新系统只取最新版本is_latest = true
sql = """
SELECT
a.account_id,
a.account_code,
a.account_name,
a.account_type,
COALESCE(SUM(l.debit), 0) AS debit,
COALESCE(SUM(l.credit), 0) AS credit
FROM journal_lines l
JOIN journal_entries e ON e.journal_entry_id = l.journal_entry_id
JOIN accounts a ON a.account_id = l.account_id
WHERE e.is_deleted = false
AND e.is_latest = true
AND a.account_code NOT IN ('512', '513', '516')
"""
else:
# 旧系统:排除已修正的记录(使用 parent_entry_id
sql = """
SELECT
a.account_id,
a.account_code,
a.account_name,
a.account_type,
COALESCE(SUM(l.debit), 0) AS debit,
COALESCE(SUM(l.credit), 0) AS credit
FROM journal_lines l
JOIN journal_entries e ON e.journal_entry_id = l.journal_entry_id
JOIN accounts a ON a.account_id = l.account_id
WHERE e.is_deleted = false
AND a.account_code NOT IN ('512', '513', '516')
AND e.journal_entry_id NOT IN (
SELECT parent_entry_id
FROM journal_entries
WHERE parent_entry_id IS NOT NULL
)
"""
params = {}
if fiscal_year is not None:
sql += " AND e.fiscal_year = %(fiscal_year)s"
params["fiscal_year"] = fiscal_year
if date_from is not None:
sql += " AND e.entry_date >= %(date_from)s"
params["date_from"] = date_from
if date_to is not None:
sql += " AND e.entry_date <= %(date_to)s"
params["date_to"] = date_to
sql += """
GROUP BY
a.account_id,
a.account_code,
a.account_name,
a.account_type
ORDER BY
CASE
WHEN a.account_code < '509' THEN a.account_code
WHEN a.account_code IN ('510', '511') THEN '508.' || a.account_code
ELSE a.account_code
END
"""
with get_connection() as conn, conn.cursor() as cur:
cur.execute(sql, params)
rows = cur.fetchall()
return rows
@router.get("/fiscal-years", summary="仕訳データから会計年度一覧取得5月期")
def get_fiscal_years():
"""
仕訳の最小・最大日付から5月期の年度リストを生成して返す。
例: 2025-06-01〜2026-05-31 → {"label": "令和8年(2026年)5月期", "date_from": "2025-06-01", "date_to": "2026-05-31"}
"""
REIWA_OFFSET = 2018 # 令和元年 = 2019年
with get_connection() as conn, conn.cursor() as cur:
cur.execute("""
SELECT
MIN(entry_date)::date AS min_date,
MAX(entry_date)::date AS max_date
FROM journal_entries
WHERE is_deleted = false
""")
row = cur.fetchone()
if not row or not row["min_date"]:
return []
min_date = row["min_date"]
max_date = row["max_date"]
# 5月期の年度を計算: 決算年end_yearは entry_date の月が6以上なら翌年、1〜5なら当年
def fiscal_end_year(d):
return d.year + 1 if d.month >= 6 else d.year
start_fy = fiscal_end_year(min_date)
end_fy = fiscal_end_year(max_date)
result = []
for fy in range(start_fy, end_fy + 1): # 小さい順(昇順)
reiwa = fy - REIWA_OFFSET
if reiwa > 0:
wareki = f"令和{reiwa}"
elif reiwa == 0:
wareki = "平成31/令和元年"
else:
wareki = f"平成{fy - 1988}"
label = f"{wareki}({fy}年)5月期"
result.append({
"label": label,
"date_from": f"{fy - 1}-06-01",
"date_to": f"{fy}-05-31",
})
return result