This commit is contained in:
FNOS-WIN11ENT\choshoukaku
2025-12-14 00:30:24 +09:00
parent 49cf65a5cb
commit c845373db8
619 changed files with 172 additions and 15 deletions

View File

@@ -1,11 +1,18 @@
from fastapi import APIRouter, HTTPException
from fastapi import APIRouter
from pydantic import BaseModel, field_validator
from enum import Enum
from psycopg.errors import UniqueViolation, CheckViolation, StringDataRightTruncation
from app.core.database import get_connection
from app.core.exceptions import BusinessException
import psycopg
router = APIRouter(prefix="/accounts", tags=["科目マスタ"])
# ======================================================
# Enum科目種別
# ======================================================
class AccountType(str, Enum):
asset = "asset"
liability = "liability"
@@ -13,6 +20,10 @@ class AccountType(str, Enum):
revenue = "revenue"
expense = "expense"
# ======================================================
# Model登録入力用
# ======================================================
class AccountCreate(BaseModel):
account_code: str
account_name: str
@@ -22,45 +33,86 @@ class AccountCreate(BaseModel):
@classmethod
def validate_code(cls, v: str):
if not v.isdigit():
raise ValueError("科目コードは数字のみで入力してください")
raise BusinessException(
error_code="ACCOUNT_CODE_INVALID",
message="科目コードは数字のみで入力してください"
)
if len(v) > 20:
raise ValueError("科目コードが長すぎます20文字以内")
raise BusinessException(
error_code="ACCOUNT_CODE_TOO_LONG",
message="科目コードは20文字以内で入力してください"
)
return v
@field_validator("account_name")
@classmethod
def validate_name(cls, v: str):
if not v.strip():
raise ValueError("科目名を入力してください")
raise BusinessException(
error_code="ACCOUNT_NAME_EMPTY",
message="科目名を入力してください"
)
if len(v) > 100:
raise ValueError("科目名が長すぎます100文字以内")
raise BusinessException(
error_code="ACCOUNT_NAME_TOO_LONG",
message="科目名は100文字以内で入力してください"
)
return v
# ======================================================
# GET科目一覧取得
# ======================================================
@router.get("/", summary="科目一覧取得")
def list_accounts():
with get_connection() as conn, conn.cursor() as cur:
cur.execute("""
SELECT account_id, account_code, account_name, account_type, is_active
FROM accounts ORDER BY account_code
FROM accounts
ORDER BY account_code
""")
return cur.fetchall()
rows = cur.fetchall()
if not rows:
raise BusinessException(
error_code="ACCOUNT_NOT_FOUND",
message="科目が登録されていません"
)
return rows
# ======================================================
# POST科目登録
# ======================================================
@router.post("/", summary="科目登録", status_code=201)
def create_account(data: AccountCreate):
try:
with get_connection() as conn, conn.cursor() as cur:
cur.execute("""
INSERT INTO accounts (account_code, account_name, account_type)
VALUES (%s, %s, %s) RETURNING account_id
VALUES (%s, %s, %s)
RETURNING account_id
""", (data.account_code, data.account_name, data.account_type.value))
new_id = cur.fetchone()["account_id"]
conn.commit()
return {"account_id": new_id}
except UniqueViolation:
# 409 也行;这里按你的要求统一 400
raise HTTPException(status_code=400, detail="この科目コードは既に登録されています。")
raise BusinessException(
error_code="ACCOUNT_DUPLICATE",
message="この科目コードは既に登録されています"
)
except StringDataRightTruncation:
raise HTTPException(status_code=400, detail="入力文字数が制限を超えています。")
raise BusinessException(
error_code="ACCOUNT_VALUE_TOO_LONG",
message="入力文字数が制限を超えています"
)
except CheckViolation:
raise HTTPException(status_code=400, detail="入力値が不正です。")
raise BusinessException(
error_code="ACCOUNT_VALUE_INVALID",
message="入力値が不正です"
)