This commit is contained in:
FNOS-WIN11ENT\choshoukaku
2025-12-18 15:30:39 +09:00
parent 88163423e0
commit 87fa1aaa1f
12 changed files with 742 additions and 192 deletions

View File

@@ -19,24 +19,69 @@ class JournalEntryRequest(BaseModel):
description: str
lines: List[JournalLine]
class JournalEntryUpdateRequest(BaseModel):
description: str
lines: List[JournalLine]
updated_reason: str
@router.post("")
class JournalEntryDeleteRequest(BaseModel):
deleted_reason: str
@router.post("", summary="仕訳登録")
def create_journal_entry(req: JournalEntryRequest):
from app.utils.month_lock import is_month_locked
if is_month_locked(req.entry_date):
raise HTTPException(
status_code=400,
detail="该月份已锁定,不能新增仕訳"
)
if not req.lines:
raise HTTPException(status_code=400, detail="仕訳明細不能为空")
# (可选)简单的借贷平衡校验
total_debit = sum(l.debit for l in req.lines)
total_credit = sum(l.credit for l in req.lines)
if total_debit != total_credit:
raise HTTPException(status_code=400, detail="借方和贷方不平衡")
fiscal_year = req.entry_date.year
with get_connection() as conn:
with conn.cursor() as cur:
# 仕訳ヘッダ
cur.execute("""
INSERT INTO journal_entries (entry_date, description)
VALUES (%s, %s)
RETURNING id
""", (req.entry_date, req.description))
entry_id = cur.fetchone()[0]
INSERT INTO journal_entries (
journal_date,
description,
fiscal_year,
version,
is_deleted,
created_by
)
VALUES (%s, %s, %s, 1, false, %s)
RETURNING journal_id
""", (
req.entry_date,
req.description,
fiscal_year,
"system" # 以后可以换成登录用户
))
entry_id = cur.fetchone()["journal_id"]
# 明細
for line in req.lines:
cur.execute("""
INSERT INTO journal_lines
(journal_entry_id, account_id, debit, credit)
INSERT INTO journal_lines (
journal_id,
account_id,
debit,
credit
)
VALUES (%s, %s, %s, %s)
""", (
entry_id,
@@ -47,4 +92,121 @@ def create_journal_entry(req: JournalEntryRequest):
conn.commit()
return {"status": "ok", "journal_entry_id": entry_id}
return {
"status": "ok",
"journal_entry_id": entry_id
}
@router.put("/{journal_id}")
def update_journal_entry(journal_id: int, req: JournalEntryUpdateRequest):
from app.utils.month_lock import is_month_locked
with get_connection() as conn:
with conn.cursor() as cur:
# ① 取得现有仕訳
cur.execute("""
SELECT journal_date, is_deleted, version
FROM journal_entries
WHERE journal_id = %s
""", (journal_id,))
row = cur.fetchone()
if not row:
raise HTTPException(status_code=404, detail="仕訳が存在しません")
if row["is_deleted"]:
raise HTTPException(status_code=400, detail="削除済み仕訳は更新できません")
journal_date = row["journal_date"]
# 借贷平衡校验update
total_debit = sum(l.debit for l in req.lines)
total_credit = sum(l.credit for l in req.lines)
if total_debit != total_credit:
raise HTTPException(status_code=400, detail="借方和贷方不平衡")
# ② 月次锁定检查
if is_month_locked(journal_date):
raise HTTPException(status_code=400, detail="该月份已锁定,不能修改仕訳")
# ③ 更新 header
cur.execute("""
UPDATE journal_entries
SET description = %s,
version = version + 1,
updated_at = NOW(),
updated_reason = %s
WHERE journal_id = %s
""", (
req.description,
req.updated_reason,
journal_id
))
# ④ 删除原有明细物理删除OK
cur.execute("""
DELETE FROM journal_lines
WHERE journal_id = %s
""", (journal_id,))
# ⑤ 插入新明细
for line in req.lines:
cur.execute("""
INSERT INTO journal_lines (
journal_id,
account_id,
debit,
credit
) VALUES (%s, %s, %s, %s)
""", (
journal_id,
line.account_id,
line.debit,
line.credit
))
conn.commit()
return {
"status": "ok",
"journal_id": journal_id,
"message": "仕訳を更新しました"
}
@router.delete("/{journal_id}", summary="仕訳删除(软删除)")
def delete_journal_entry(journal_id: int, req: JournalEntryDeleteRequest):
with get_connection() as conn:
with conn.cursor() as cur:
cur.execute("""
UPDATE journal_entries
SET is_deleted = true,
deleted_at = NOW(),
deleted_reason = %s
WHERE journal_id = %s
AND is_deleted = false
RETURNING journal_id
""", (
req.deleted_reason,
journal_id
))
row = cur.fetchone()
if not row:
raise HTTPException(
status_code=404,
detail="仕訳不存在,或已被删除"
)
conn.commit()
return {
"status": "deleted",
"journal_entry_id": journal_id
}