"""银行账户管理与交易查询后台路由。""" from fastapi import APIRouter, Depends, HTTPException, Path, Query from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.dependencies import get_admin_user, get_db from app.models.bank_account import BankAccount from app.models.user import User from app.services.bank.service import query_transactions_with_log from app.utils.id_gen import generate_id router = APIRouter(prefix="/admin/bank", tags=["admin-bank"]) # ============================================================ # 银行账户 CRUD # ============================================================ @router.get("/accounts") async def list_accounts( admin: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db), ): """列出所有银行账户。""" result = await db.execute(select(BankAccount).order_by(BankAccount.is_default.desc(), BankAccount.created_at.desc())) accounts = result.scalars().all() return {"items": [ { "id": a.id, "account_name": a.account_name, "bank_name": a.bank_name, "account_no": a.account_no, "is_active": a.is_active, "is_default": a.is_default, "description": a.description, "created_at": a.created_at.isoformat() if a.created_at else None, "updated_at": a.updated_at.isoformat() if a.updated_at else None, } for a in accounts ]} @router.post("/accounts") async def create_account( body: dict, admin: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db), ): """新增银行账户。""" account_name = (body.get("account_name") or "").strip() bank_name = (body.get("bank_name") or "").strip() account_no = (body.get("account_no") or "").strip() if not account_name or not bank_name or not account_no: raise HTTPException(status_code=400, detail="账户名称、开户银行、银行账号不能为空") # 检查账号唯一性 existing = await db.execute(select(BankAccount).where(BankAccount.account_no == account_no)) if existing.scalar_one_or_none(): raise HTTPException(status_code=409, detail="该银行账号已存在") is_default = bool(body.get("is_default", False)) # 如果设为默认,取消其他默认 if is_default: await db.execute( BankAccount.__table__.update().where(BankAccount.is_default.is_(True)).values(is_default=False) ) account = BankAccount( id=generate_id(), account_name=account_name, bank_name=bank_name, account_no=account_no, is_active=bool(body.get("is_active", True)), is_default=is_default, description=body.get("description"), ) db.add(account) await db.commit() return {"id": account.id, "message": "创建成功"} @router.put("/accounts/{account_id}") async def update_account( account_id: str = Path(..., description="账户 ID"), body: dict = ..., admin: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db), ): """编辑银行账户。""" result = await db.execute(select(BankAccount).where(BankAccount.id == account_id)) account = result.scalar_one_or_none() if account is None: raise HTTPException(status_code=404, detail="账户不存在") if "account_name" in body: account.account_name = str(body["account_name"]).strip() if "bank_name" in body: account.bank_name = str(body["bank_name"]).strip() if "account_no" in body: new_no = str(body["account_no"]).strip() if new_no != account.account_no: existing = await db.execute(select(BankAccount).where(BankAccount.account_no == new_no)) if existing.scalar_one_or_none(): raise HTTPException(status_code=409, detail="该银行账号已存在") account.account_no = new_no if "is_active" in body: account.is_active = bool(body["is_active"]) if "description" in body: account.description = body.get("description") if body.get("is_default"): await db.execute( BankAccount.__table__.update() .where(BankAccount.is_default.is_(True)) .where(BankAccount.id != account_id) .values(is_default=False) ) account.is_default = True await db.commit() return {"message": "更新成功"} @router.delete("/accounts/{account_id}") async def delete_account( account_id: str = Path(..., description="账户 ID"), admin: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db), ): """删除银行账户。""" result = await db.execute(select(BankAccount).where(BankAccount.id == account_id)) account = result.scalar_one_or_none() if account is None: raise HTTPException(status_code=404, detail="账户不存在") await db.delete(account) await db.commit() return {"message": "删除成功"} # ============================================================ # 银行交易查询 # ============================================================ @router.get("/transactions") async def list_transactions( account_id: str = Query(..., description="银行账户 ID"), start_date: str = Query(..., description="开始日期 (YYYY-MM-DD)"), end_date: str = Query(..., description="结束日期 (YYYY-MM-DD)"), dc_flag: int | None = Query(None, description="借贷方向: 0-借/出金, 1-贷/入金, 不传返回全部"), page: int = Query(1, ge=1, description="页码"), page_size: int = Query(20, ge=1, le=100, description="每页数量"), admin: User = Depends(get_admin_user), db: AsyncSession = Depends(get_db), ): """查询银行交易流水(带接口请求记录到文件日志)。""" result = await db.execute(select(BankAccount).where(BankAccount.id == account_id)) account = result.scalar_one_or_none() if account is None: raise HTTPException(status_code=404, detail="银行账户不存在") data = await query_transactions_with_log( admin.id, acct_no=account.account_no, start_date=start_date, end_date=end_date, dc_flag=dc_flag, page=page, page_size=page_size, ) return data