- 新規モジュール: backend/app/payroll/withholding_slip/ - schemas.py: 源泉徴収票データモデル - service.py: 年間集計・給与所得控除・控除額計算ロジック - router.py: POST /payroll/withholding-slip/generate - frontend/withholding-slip.html: 票面プレビュー・印刷(3部)ページ - frontend/payroll.html: 源泉徴収票メニューカード追加 - backend/app/main.py: ルーター登録
172 lines
5.3 KiB
Python
172 lines
5.3 KiB
Python
from dotenv import load_dotenv
|
||
load_dotenv()
|
||
|
||
from fastapi import FastAPI, Request
|
||
from fastapi.responses import JSONResponse, RedirectResponse
|
||
from pydantic import ValidationError
|
||
from fastapi.middleware.cors import CORSMiddleware
|
||
|
||
# FastAPI アプリケーション作成
|
||
app = FastAPI(
|
||
title="日本小規模企業向け会計システム"
|
||
)
|
||
|
||
|
||
|
||
app.add_middleware(
|
||
CORSMiddleware,
|
||
allow_origins=["*"],
|
||
allow_credentials=False,
|
||
allow_methods=["*"],
|
||
allow_headers=["*"],
|
||
)
|
||
|
||
# ─────────────────────────
|
||
# 自動データベース遷移
|
||
# ─────────────────────────
|
||
@app.on_event("startup")
|
||
async def run_startup_migration():
|
||
"""アプリケーション起動時にデータベス遷移を実行"""
|
||
try:
|
||
from app.db_auto_migration import run_auto_migration
|
||
run_auto_migration()
|
||
except Exception as e:
|
||
print(f"⚠️ 遷移エラー(無視): {e}")
|
||
|
||
@app.exception_handler(ValidationError)
|
||
async def validation_exception_handler(request: Request, exc: ValidationError):
|
||
# ここでは最初のエラーだけ簡潔に返す(必要に応じて整形)
|
||
first = exc.errors()[0]
|
||
msg = first.get("msg", "入力値が不正です。")
|
||
return JSONResponse(status_code=400, content={"detail": msg})
|
||
|
||
# ─────────────────────────
|
||
# ルート(稼働確認)
|
||
# ─────────────────────────
|
||
@app.get("/", include_in_schema=False)
|
||
def root():
|
||
return RedirectResponse("/login.html")
|
||
# ─────────────────────────
|
||
# ルーター登録(※ 必ず app 定義の後)
|
||
# ─────────────────────────
|
||
from app.modules.users.router import router as users_router
|
||
app.include_router(users_router)
|
||
|
||
from app.modules.accounts.router import router as accounts_router
|
||
app.include_router(accounts_router)
|
||
|
||
|
||
from app.modules.journals.router import router as journals_router
|
||
app.include_router(journals_router)
|
||
|
||
|
||
from app.modules.ledger.router import router as ledger_router
|
||
app.include_router(ledger_router)
|
||
|
||
|
||
from app.modules.trial_balance.router import router as trial_balance_router
|
||
app.include_router(trial_balance_router)
|
||
|
||
from app.modules.opening_balances.router import router as opening_router
|
||
app.include_router(opening_router)
|
||
|
||
from app.modules.general_ledger.router import router as general_ledger_router
|
||
app.include_router(general_ledger_router)
|
||
|
||
from app.modules.opening_balances.lock_router import router as opening_balance_lock_router
|
||
app.include_router(opening_balance_lock_router)
|
||
|
||
from app.routers import journal_entries
|
||
from app.routers import cash
|
||
from app.routers import accounts
|
||
|
||
app.include_router(journal_entries.router)
|
||
app.include_router(cash.router)
|
||
app.include_router(accounts.router)
|
||
|
||
|
||
from app.routers import month_locks
|
||
app.include_router(month_locks.router)
|
||
|
||
from app.routers import year_locks
|
||
app.include_router(year_locks.router)
|
||
|
||
from app.routers import cash
|
||
app.include_router(cash.router)
|
||
|
||
from app.routers import file_upload
|
||
app.include_router(file_upload.router)
|
||
|
||
from app.modules.egov.router import router as egov_router
|
||
app.include_router(egov_router)
|
||
|
||
# ─────────────────────────
|
||
# 給与モジュール (Payroll Module)
|
||
# ─────────────────────────
|
||
from app.payroll.employees.router import router as payroll_employees_router
|
||
app.include_router(payroll_employees_router)
|
||
|
||
from app.payroll.settings.router import router as payroll_settings_router
|
||
app.include_router(payroll_settings_router)
|
||
|
||
from app.payroll.settings.standard_remuneration_router import router as standard_remuneration_router
|
||
app.include_router(standard_remuneration_router)
|
||
|
||
from app.payroll.calculation.router import router as payroll_calculation_router
|
||
app.include_router(payroll_calculation_router)
|
||
|
||
from app.payroll.bonus.router import router as payroll_bonus_router
|
||
app.include_router(payroll_bonus_router)
|
||
|
||
from app.payroll.vouchers.router import router as payroll_vouchers_router
|
||
app.include_router(payroll_vouchers_router)
|
||
|
||
from app.payroll.withholding_slip.router import router as withholding_slip_router
|
||
app.include_router(withholding_slip_router)
|
||
|
||
|
||
from fastapi.staticfiles import StaticFiles
|
||
import os
|
||
from pathlib import Path
|
||
|
||
# アップロードファイル用の静的ファイル配信
|
||
uploads_dir = Path("uploads")
|
||
uploads_dir.mkdir(exist_ok=True)
|
||
app.mount(
|
||
"/uploads",
|
||
StaticFiles(directory="uploads"),
|
||
name="uploads",
|
||
)
|
||
|
||
# 静的ファイル配信(コメントアウト - ディレクトリが存在しない)
|
||
# app.mount(
|
||
# "/static",
|
||
# StaticFiles(directory="app/static", html=True),
|
||
# name="static",
|
||
# )
|
||
|
||
# フロントエンドファイル配信
|
||
from fastapi.staticfiles import StaticFiles
|
||
from pathlib import Path
|
||
|
||
# フロントエンド配信(/app/frontend)
|
||
BASE_DIR = Path(__file__).resolve().parent.parent # /app
|
||
frontend_path = BASE_DIR / "frontend"
|
||
|
||
print("Frontend path =", frontend_path)
|
||
|
||
if frontend_path.exists():
|
||
app.mount(
|
||
"/",
|
||
StaticFiles(directory=frontend_path),
|
||
name="frontend",
|
||
)
|
||
else:
|
||
print(f"Frontend path not found: {frontend_path}")
|
||
|
||
|
||
|
||
|
||
|
||
|