Files
njts-accounting-core/backend/app/modules/accounts/router.py
FNOS-WIN11ENT\choshoukaku c845373db8 修正
2025-12-14 00:30:24 +09:00

119 lines
3.8 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
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"
equity = "equity"
revenue = "revenue"
expense = "expense"
# ======================================================
# Model登録入力用
# ======================================================
class AccountCreate(BaseModel):
account_code: str
account_name: str
account_type: AccountType
@field_validator("account_code")
@classmethod
def validate_code(cls, v: str):
if not v.isdigit():
raise BusinessException(
error_code="ACCOUNT_CODE_INVALID",
message="科目コードは数字のみで入力してください"
)
if len(v) > 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 BusinessException(
error_code="ACCOUNT_NAME_EMPTY",
message="科目名を入力してください"
)
if len(v) > 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
""")
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
""", (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:
raise BusinessException(
error_code="ACCOUNT_DUPLICATE",
message="この科目コードは既に登録されています"
)
except StringDataRightTruncation:
raise BusinessException(
error_code="ACCOUNT_VALUE_TOO_LONG",
message="入力文字数が制限を超えています"
)
except CheckViolation:
raise BusinessException(
error_code="ACCOUNT_VALUE_INVALID",
message="入力値が不正です"
)