desktop修正

This commit is contained in:
admin
2025-12-14 23:54:48 +09:00
parent f9f5eec35e
commit 74dcb88fe6
25 changed files with 1068 additions and 157 deletions

View File

@@ -1,55 +1,108 @@
# backend/app/modules/opening_balances/router.py
from fastapi import APIRouter, HTTPException
from psycopg.errors import ForeignKeyViolation
from fastapi import APIRouter, HTTPException, Query
from pydantic import BaseModel
from typing import List
from decimal import Decimal
from app.core.database import get_connection
from app.modules.opening_balances.schema import OpeningBalanceCreate
router = APIRouter(
prefix="/opening-balances",
tags=["期首残高"]
)
@router.post("/", summary="期首残高 登録/更新")
def upsert_opening_balance(data: OpeningBalanceCreate):
try:
with get_connection() as conn, conn.cursor() as cur:
cur.execute("""
INSERT INTO opening_balances
(fiscal_year, account_id, opening_debit, opening_credit)
VALUES (%s, %s, %s, %s)
ON CONFLICT (fiscal_year, account_id)
DO UPDATE SET
opening_debit = EXCLUDED.opening_debit,
opening_credit = EXCLUDED.opening_credit
""", (
data.fiscal_year,
data.account_id,
data.opening_debit,
data.opening_credit
))
conn.commit()
return {"result": "ok"}
except ForeignKeyViolation:
raise HTTPException(
status_code=400,
detail="存在しない科目が指定されています"
)
router = APIRouter(prefix="/opening-balances", tags=["期首残高"])
@router.get("/{fiscal_year}", summary="期首残高一覧取得")
def list_opening_balances(fiscal_year: int):
# ---------- Models ----------
class OpeningBalanceItem(BaseModel):
account_id: int
debit: Decimal = Decimal("0")
credit: Decimal = Decimal("0")
class OpeningBalanceRequest(BaseModel):
fiscal_year: int
balances: List[OpeningBalanceItem]
# ---------- GET期首残高取得 ----------
@router.get("", summary="期首残高取得")
def get_opening_balances(
fiscal_year: int = Query(..., description="会計年度2025")
):
with get_connection() as conn, conn.cursor() as cur:
cur.execute("""
SELECT
a.account_id,
a.account_code,
a.account_name,
a.account_type,
ob.opening_debit,
ob.opening_credit
FROM opening_balances ob
JOIN accounts a ON a.account_id = ob.account_id
WHERE ob.fiscal_year = %s
COALESCE(o.opening_debit, 0) AS opening_debit,
COALESCE(o.opening_credit, 0) AS opening_credit
FROM accounts a
LEFT JOIN opening_balances o
ON o.account_id = a.account_id
AND o.fiscal_year = %s
WHERE a.is_active = true
ORDER BY a.account_code
""", (fiscal_year,))
return cur.fetchall()
# ---------- POST期首残高保存 ----------
@router.post("", summary="期首残高保存")
def save_opening_balances(req: OpeningBalanceRequest):
# 年度锁定チェック
cur.execute("""
SELECT is_locked
FROM fiscal_year_locks
WHERE fiscal_year = %s
""", (req.fiscal_year,))
row = cur.fetchone()
if row and row["is_locked"]:
raise HTTPException(
status_code=400,
detail="この会計年度の期首残高は既に確定されています。"
)
total_debit = Decimal("0")
total_credit = Decimal("0")
for b in req.balances:
total_debit += b.debit
total_credit += b.credit
if total_debit != total_credit:
raise HTTPException(
status_code=400,
detail="借方合計と貸方合計が一致していません。"
)
with get_connection() as conn, conn.cursor() as cur:
# 既存データ削除(年度単位)
cur.execute("""
DELETE FROM opening_balances
WHERE fiscal_year = %s
""", (req.fiscal_year,))
# 再登録
for b in req.balances:
if b.debit == 0 and b.credit == 0:
continue
cur.execute("""
INSERT INTO opening_balances
(fiscal_year, account_id, opening_debit, opening_credit)
VALUES
(%s, %s, %s, %s)
""", (
req.fiscal_year,
b.account_id,
b.debit,
b.credit
))
conn.commit()
return {"message": "期首残高を保存しました。"}