Files
zkxw/backend/app/api/insurance_company.py
T
2026-05-20 14:32:07 +08:00

833 lines
26 KiB
Python

"""保险公司及险种价格管理 API(保险公司 + 开票信息 + 险种价格)"""
import math
import uuid
from datetime import datetime
from typing import Any, List, Optional
from fastapi import APIRouter, Depends, Query
from pydantic import BaseModel, ConfigDict, Field
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.core.menu_guard import require_admin_or_super_admin
from app.core.response import error_response, success_response
from app.models.models import (
BizInsuranceCompany,
BizInsuranceCompanyInvoice,
BizInsuranceProjectPrice,
SysUser,
)
router = APIRouter(prefix="/web/admin", tags=["保险公司及险种价格管理"])
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
def _get_tenant_no(db: Session, user: dict) -> str:
user_id = user.get("user_id")
if not user_id:
raise PermissionError("用户身份信息缺失,无法确定租户")
sys_user = db.query(SysUser).filter(SysUser.id == user_id).first()
if not sys_user or not sys_user.tenant_no:
raise PermissionError("用户租户信息缺失")
return sys_user.tenant_no
def _generate_uuid() -> str:
return str(uuid.uuid4()).replace("-", "")
def _fmt_dt(v) -> Optional[str]:
if v is None:
return None
if isinstance(v, datetime):
return v.strftime("%Y-%m-%d %H:%M:%S")
return str(v)
def _total_pages(total: int, page_size: int) -> int:
return math.ceil(total / page_size) if page_size > 0 else 0
# ---------------------------------------------------------------------------
# Row-to-dict helpers (camelCase JSON)
# ---------------------------------------------------------------------------
def _row_to_dict_company(row: BizInsuranceCompany) -> dict:
return {
"id": row.id,
"companyName": row.company_name,
"companyAddress": row.company_address,
"contactName": row.contact_name,
"contactPhone": row.contact_phone,
"status": row.status,
"tenantNo": row.tenant_no,
"orderNum": row.order_num,
"remark": row.remark,
"createBy": row.create_by,
"createDeptId": row.create_dept_id,
"createTime": _fmt_dt(row.create_time),
"updateBy": row.update_by,
"updateTime": _fmt_dt(row.update_time),
}
def _row_to_dict_invoice(row: BizInsuranceCompanyInvoice) -> dict:
return {
"id": row.id,
"insuranceCompanyId": row.insurance_company_id,
"companyName": row.company_name,
"taxNo": row.tax_no,
"companyAddress": row.company_address,
"companyPhone": row.company_phone,
"bankName": row.bank_name,
"bankAccount": row.bank_account,
"tenantNo": row.tenant_no,
"orderNum": row.order_num,
"remark": row.remark,
"createBy": row.create_by,
"createDeptId": row.create_dept_id,
"createTime": _fmt_dt(row.create_time),
"updateBy": row.update_by,
"updateTime": _fmt_dt(row.update_time),
}
def _row_to_dict_project_price(row: BizInsuranceProjectPrice) -> dict:
return {
"id": row.id,
"insuranceCompanyId": row.insurance_company_id,
"projectName": row.project_name,
"projectFee": float(row.project_fee) if row.project_fee is not None else None,
"status": row.status,
"tenantNo": row.tenant_no,
"orderNum": row.order_num,
"remark": row.remark,
"createBy": row.create_by,
"createDeptId": row.create_dept_id,
"createTime": _fmt_dt(row.create_time),
"updateBy": row.update_by,
"updateTime": _fmt_dt(row.update_time),
}
# ---------------------------------------------------------------------------
# Inline CRUD — 保险公司主表
# ---------------------------------------------------------------------------
def _list_insurance_companies(
db: Session, *, page: int, page_size: int, keyword: Optional[str], tenant_no: str
):
q = db.query(BizInsuranceCompany).filter(
BizInsuranceCompany.tenant_no == tenant_no,
BizInsuranceCompany.del_flag == 0,
)
if keyword:
q = q.filter(BizInsuranceCompany.company_name.like(f"%{keyword}%"))
total = q.count()
rows = (
q.order_by(BizInsuranceCompany.create_time.desc())
.offset((page - 1) * page_size)
.limit(page_size)
.all()
)
return [_row_to_dict_company(r) for r in rows], total
def _create_insurance_company(
db: Session,
*,
company_name: str,
company_address: Optional[str],
contact_name: Optional[str],
contact_phone: Optional[str],
status: Optional[str],
tenant_no: str,
order_num: Optional[int],
remark: Optional[str],
user_id: str,
) -> BizInsuranceCompany:
obj = BizInsuranceCompany(
id=_generate_uuid(),
company_name=company_name,
company_address=company_address,
contact_name=contact_name,
contact_phone=contact_phone,
status=status or "1",
tenant_no=tenant_no,
order_num=order_num or 0,
remark=remark,
create_by=user_id,
create_dept_id="",
create_time=datetime.now(),
update_by=user_id,
update_time=datetime.now(),
del_flag=0,
)
db.add(obj)
db.commit()
db.refresh(obj)
return obj
def _update_insurance_company(
db: Session,
row_id: str,
*,
company_name: Optional[str],
company_address: Optional[str],
contact_name: Optional[str],
contact_phone: Optional[str],
status: Optional[str],
order_num: Optional[int],
remark: Optional[str],
user_id: str,
tenant_no: str,
) -> BizInsuranceCompany:
obj = (
db.query(BizInsuranceCompany)
.filter(
BizInsuranceCompany.id == row_id,
BizInsuranceCompany.tenant_no == tenant_no,
BizInsuranceCompany.del_flag == 0,
)
.first()
)
if not obj:
raise ValueError("记录不存在")
if company_name is not None:
obj.company_name = company_name
if company_address is not None:
obj.company_address = company_address
if contact_name is not None:
obj.contact_name = contact_name
if contact_phone is not None:
obj.contact_phone = contact_phone
if status is not None:
obj.status = status
if order_num is not None:
obj.order_num = order_num
if remark is not None:
obj.remark = remark
obj.update_by = user_id
obj.update_time = datetime.now()
db.commit()
db.refresh(obj)
return obj
def _soft_delete_insurance_company(db: Session, row_id: str, *, tenant_no: str):
obj = (
db.query(BizInsuranceCompany)
.filter(
BizInsuranceCompany.id == row_id,
BizInsuranceCompany.tenant_no == tenant_no,
BizInsuranceCompany.del_flag == 0,
)
.first()
)
if not obj:
raise ValueError("记录不存在")
obj.del_flag = 1
db.commit()
# ---------------------------------------------------------------------------
# Inline CRUD — 险种开票信息
# ---------------------------------------------------------------------------
def _list_insurance_company_invoices(
db: Session, insurance_company_id: str, *, tenant_no: str
):
# Verify parent exists
parent = (
db.query(BizInsuranceCompany)
.filter(
BizInsuranceCompany.id == insurance_company_id,
BizInsuranceCompany.tenant_no == tenant_no,
BizInsuranceCompany.del_flag == 0,
)
.first()
)
if not parent:
raise ValueError("保险公司不存在")
rows = (
db.query(BizInsuranceCompanyInvoice)
.filter(
BizInsuranceCompanyInvoice.insurance_company_id == insurance_company_id,
BizInsuranceCompanyInvoice.tenant_no == tenant_no,
BizInsuranceCompanyInvoice.del_flag == 0,
)
.order_by(BizInsuranceCompanyInvoice.create_time.desc())
.all()
)
return [_row_to_dict_invoice(r) for r in rows]
def _create_insurance_company_invoice(
db: Session,
*,
insurance_company_id: str,
company_name: str,
tax_no: Optional[str],
company_address: Optional[str],
company_phone: Optional[str],
bank_name: Optional[str],
bank_account: Optional[str],
tenant_no: str,
order_num: Optional[int],
remark: Optional[str],
user_id: str,
) -> BizInsuranceCompanyInvoice:
obj = BizInsuranceCompanyInvoice(
id=_generate_uuid(),
insurance_company_id=insurance_company_id,
company_name=company_name,
tax_no=tax_no,
company_address=company_address,
company_phone=company_phone,
bank_name=bank_name,
bank_account=bank_account,
tenant_no=tenant_no,
order_num=order_num or 0,
remark=remark,
create_by=user_id,
create_dept_id="",
create_time=datetime.now(),
update_by=user_id,
update_time=datetime.now(),
del_flag=0,
)
db.add(obj)
db.commit()
db.refresh(obj)
return obj
def _update_insurance_company_invoice(
db: Session,
row_id: str,
*,
company_name: Optional[str],
tax_no: Optional[str],
company_address: Optional[str],
company_phone: Optional[str],
bank_name: Optional[str],
bank_account: Optional[str],
order_num: Optional[int],
remark: Optional[str],
user_id: str,
tenant_no: str,
) -> BizInsuranceCompanyInvoice:
obj = (
db.query(BizInsuranceCompanyInvoice)
.filter(
BizInsuranceCompanyInvoice.id == row_id,
BizInsuranceCompanyInvoice.tenant_no == tenant_no,
BizInsuranceCompanyInvoice.del_flag == 0,
)
.first()
)
if not obj:
raise ValueError("记录不存在")
if company_name is not None:
obj.company_name = company_name
if tax_no is not None:
obj.tax_no = tax_no
if company_address is not None:
obj.company_address = company_address
if company_phone is not None:
obj.company_phone = company_phone
if bank_name is not None:
obj.bank_name = bank_name
if bank_account is not None:
obj.bank_account = bank_account
if order_num is not None:
obj.order_num = order_num
if remark is not None:
obj.remark = remark
obj.update_by = user_id
obj.update_time = datetime.now()
db.commit()
db.refresh(obj)
return obj
def _soft_delete_insurance_company_invoice(db: Session, row_id: str, *, tenant_no: str):
obj = (
db.query(BizInsuranceCompanyInvoice)
.filter(
BizInsuranceCompanyInvoice.id == row_id,
BizInsuranceCompanyInvoice.tenant_no == tenant_no,
BizInsuranceCompanyInvoice.del_flag == 0,
)
.first()
)
if not obj:
raise ValueError("记录不存在")
obj.del_flag = 1
db.commit()
# ---------------------------------------------------------------------------
# Inline CRUD — 险种价格
# ---------------------------------------------------------------------------
def _list_insurance_project_prices(
db: Session, insurance_company_id: str, *, tenant_no: str
):
# Verify parent exists
parent = (
db.query(BizInsuranceCompany)
.filter(
BizInsuranceCompany.id == insurance_company_id,
BizInsuranceCompany.tenant_no == tenant_no,
BizInsuranceCompany.del_flag == 0,
)
.first()
)
if not parent:
raise ValueError("保险公司不存在")
rows = (
db.query(BizInsuranceProjectPrice)
.filter(
BizInsuranceProjectPrice.insurance_company_id == insurance_company_id,
BizInsuranceProjectPrice.tenant_no == tenant_no,
BizInsuranceProjectPrice.del_flag == 0,
)
.order_by(BizInsuranceProjectPrice.create_time.desc())
.all()
)
return [_row_to_dict_project_price(r) for r in rows]
def _create_insurance_project_price(
db: Session,
*,
insurance_company_id: str,
project_name: str,
project_fee: Optional[float],
status: Optional[str],
tenant_no: str,
order_num: Optional[int],
remark: Optional[str],
user_id: str,
) -> BizInsuranceProjectPrice:
obj = BizInsuranceProjectPrice(
id=_generate_uuid(),
insurance_company_id=insurance_company_id,
project_name=project_name,
project_fee=project_fee,
status=status or "1",
tenant_no=tenant_no,
order_num=order_num or 0,
remark=remark,
create_by=user_id,
create_dept_id="",
create_time=datetime.now(),
update_by=user_id,
update_time=datetime.now(),
del_flag=0,
)
db.add(obj)
db.commit()
db.refresh(obj)
return obj
def _update_insurance_project_price(
db: Session,
row_id: str,
*,
project_name: Optional[str],
project_fee: Optional[float],
status: Optional[str],
order_num: Optional[int],
remark: Optional[str],
user_id: str,
tenant_no: str,
) -> BizInsuranceProjectPrice:
obj = (
db.query(BizInsuranceProjectPrice)
.filter(
BizInsuranceProjectPrice.id == row_id,
BizInsuranceProjectPrice.tenant_no == tenant_no,
BizInsuranceProjectPrice.del_flag == 0,
)
.first()
)
if not obj:
raise ValueError("记录不存在")
if project_name is not None:
obj.project_name = project_name
if project_fee is not None:
obj.project_fee = project_fee
if status is not None:
obj.status = status
if order_num is not None:
obj.order_num = order_num
if remark is not None:
obj.remark = remark
obj.update_by = user_id
obj.update_time = datetime.now()
db.commit()
db.refresh(obj)
return obj
def _soft_delete_insurance_project_price(db: Session, row_id: str, *, tenant_no: str):
obj = (
db.query(BizInsuranceProjectPrice)
.filter(
BizInsuranceProjectPrice.id == row_id,
BizInsuranceProjectPrice.tenant_no == tenant_no,
BizInsuranceProjectPrice.del_flag == 0,
)
.first()
)
if not obj:
raise ValueError("记录不存在")
obj.del_flag = 1
db.commit()
# ---------------------------------------------------------------------------
# 1. 保险公司(主表)
# ---------------------------------------------------------------------------
class InsuranceCompanyCreateBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
company_name: str = Field(..., alias="companyName")
company_address: Optional[str] = Field(None, alias="companyAddress")
contact_name: Optional[str] = Field(None, alias="contactName")
contact_phone: Optional[str] = Field(None, alias="contactPhone")
status: Optional[str] = Field("1", alias="status")
order_num: Optional[int] = Field(0, alias="orderNum")
remark: Optional[str] = None
class InsuranceCompanyUpdateBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
company_name: Optional[str] = Field(None, alias="companyName")
company_address: Optional[str] = Field(None, alias="companyAddress")
contact_name: Optional[str] = Field(None, alias="contactName")
contact_phone: Optional[str] = Field(None, alias="contactPhone")
status: Optional[str] = Field(None, alias="status")
order_num: Optional[int] = Field(None, alias="orderNum")
remark: Optional[str] = None
@router.get("/insurance-companies")
async def list_insurance_companies(
page: int = Query(1, ge=1),
pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
keyword: Optional[str] = None,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
tenant_no = _get_tenant_no(db, user)
items, total = _list_insurance_companies(
db, page=page, page_size=pageSize, keyword=keyword, tenant_no=tenant_no
)
tp = _total_pages(total, pageSize)
return success_response(
{"list": items, "total": total, "page": page, "pageSize": pageSize, "totalPages": tp}
)
@router.post("/insurance-companies")
async def create_insurance_company(
body: InsuranceCompanyCreateBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
obj = _create_insurance_company(
db,
company_name=body.company_name,
company_address=body.company_address,
contact_name=body.contact_name,
contact_phone=body.contact_phone,
status=body.status,
tenant_no=tenant_no,
order_num=body.order_num,
remark=body.remark,
user_id=user.get("user_id"),
)
return success_response(_row_to_dict_company(obj), message="创建成功")
except ValueError as e:
return error_response(400, str(e))
@router.put("/insurance-companies/{row_id}")
async def update_insurance_company(
row_id: str,
body: InsuranceCompanyUpdateBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
payload: dict[str, Any] = body.model_dump(exclude_unset=True, by_alias=False)
obj = _update_insurance_company(
db,
row_id,
company_name=payload.get("company_name"),
company_address=payload.get("company_address"),
contact_name=payload.get("contact_name"),
contact_phone=payload.get("contact_phone"),
status=payload.get("status"),
order_num=payload.get("order_num"),
remark=payload.get("remark"),
user_id=user.get("user_id"),
tenant_no=tenant_no,
)
return success_response(_row_to_dict_company(obj), message="更新成功")
except ValueError as e:
return error_response(400, str(e))
@router.delete("/insurance-companies/{row_id}")
async def delete_insurance_company(
row_id: str,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
_soft_delete_insurance_company(db, row_id, tenant_no=tenant_no)
return success_response(None, message="删除成功")
except ValueError as e:
return error_response(400, str(e))
# ---------------------------------------------------------------------------
# 2. 保险公司开票信息(子表)
# ---------------------------------------------------------------------------
class InsuranceCompanyInvoiceCreateBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
company_name: str = Field(..., alias="companyName")
tax_no: Optional[str] = Field(None, alias="taxNo")
company_address: Optional[str] = Field(None, alias="companyAddress")
company_phone: Optional[str] = Field(None, alias="companyPhone")
bank_name: Optional[str] = Field(None, alias="bankName")
bank_account: Optional[str] = Field(None, alias="bankAccount")
order_num: Optional[int] = Field(0, alias="orderNum")
remark: Optional[str] = None
class InsuranceCompanyInvoiceUpdateBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
company_name: Optional[str] = Field(None, alias="companyName")
tax_no: Optional[str] = Field(None, alias="taxNo")
company_address: Optional[str] = Field(None, alias="companyAddress")
company_phone: Optional[str] = Field(None, alias="companyPhone")
bank_name: Optional[str] = Field(None, alias="bankName")
bank_account: Optional[str] = Field(None, alias="bankAccount")
order_num: Optional[int] = Field(None, alias="orderNum")
remark: Optional[str] = None
@router.get("/insurance-companies/{company_id}/invoices")
async def list_insurance_company_invoices(
company_id: str,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
items = _list_insurance_company_invoices(db, company_id, tenant_no=tenant_no)
return success_response(items)
except ValueError as e:
return error_response(400, str(e))
@router.post("/insurance-companies/{company_id}/invoices")
async def create_insurance_company_invoice(
company_id: str,
body: InsuranceCompanyInvoiceCreateBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
obj = _create_insurance_company_invoice(
db,
insurance_company_id=company_id,
company_name=body.company_name,
tax_no=body.tax_no,
company_address=body.company_address,
company_phone=body.company_phone,
bank_name=body.bank_name,
bank_account=body.bank_account,
tenant_no=tenant_no,
order_num=body.order_num,
remark=body.remark,
user_id=user.get("user_id"),
)
return success_response(_row_to_dict_invoice(obj), message="创建成功")
except ValueError as e:
return error_response(400, str(e))
@router.put("/insurance-company-invoices/{invoice_id}")
async def update_insurance_company_invoice(
invoice_id: str,
body: InsuranceCompanyInvoiceUpdateBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
payload: dict[str, Any] = body.model_dump(exclude_unset=True, by_alias=False)
obj = _update_insurance_company_invoice(
db,
invoice_id,
company_name=payload.get("company_name"),
tax_no=payload.get("tax_no"),
company_address=payload.get("company_address"),
company_phone=payload.get("company_phone"),
bank_name=payload.get("bank_name"),
bank_account=payload.get("bank_account"),
order_num=payload.get("order_num"),
remark=payload.get("remark"),
user_id=user.get("user_id"),
tenant_no=tenant_no,
)
return success_response(_row_to_dict_invoice(obj), message="更新成功")
except ValueError as e:
return error_response(400, str(e))
@router.delete("/insurance-company-invoices/{invoice_id}")
async def delete_insurance_company_invoice(
invoice_id: str,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
_soft_delete_insurance_company_invoice(db, invoice_id, tenant_no=tenant_no)
return success_response(None, message="删除成功")
except ValueError as e:
return error_response(400, str(e))
# ---------------------------------------------------------------------------
# 3. 险种价格(子表)
# ---------------------------------------------------------------------------
class InsuranceProjectPriceCreateBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
project_name: str = Field(..., alias="projectName")
project_fee: Optional[float] = Field(None, alias="projectFee")
status: Optional[str] = Field("1", alias="status")
order_num: Optional[int] = Field(0, alias="orderNum")
remark: Optional[str] = None
class InsuranceProjectPriceUpdateBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
project_name: Optional[str] = Field(None, alias="projectName")
project_fee: Optional[float] = Field(None, alias="projectFee")
status: Optional[str] = Field(None, alias="status")
order_num: Optional[int] = Field(None, alias="orderNum")
remark: Optional[str] = None
@router.get("/insurance-companies/{company_id}/project-prices")
async def list_insurance_project_prices(
company_id: str,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
items = _list_insurance_project_prices(db, company_id, tenant_no=tenant_no)
return success_response(items)
except ValueError as e:
return error_response(400, str(e))
@router.post("/insurance-companies/{company_id}/project-prices")
async def create_insurance_project_price(
company_id: str,
body: InsuranceProjectPriceCreateBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
obj = _create_insurance_project_price(
db,
insurance_company_id=company_id,
project_name=body.project_name,
project_fee=body.project_fee,
status=body.status,
tenant_no=tenant_no,
order_num=body.order_num,
remark=body.remark,
user_id=user.get("user_id"),
)
return success_response(_row_to_dict_project_price(obj), message="创建成功")
except ValueError as e:
return error_response(400, str(e))
@router.put("/insurance-project-prices/{price_id}")
async def update_insurance_project_price(
price_id: str,
body: InsuranceProjectPriceUpdateBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
payload: dict[str, Any] = body.model_dump(exclude_unset=True, by_alias=False)
obj = _update_insurance_project_price(
db,
price_id,
project_name=payload.get("project_name"),
project_fee=payload.get("project_fee"),
status=payload.get("status"),
order_num=payload.get("order_num"),
remark=payload.get("remark"),
user_id=user.get("user_id"),
tenant_no=tenant_no,
)
return success_response(_row_to_dict_project_price(obj), message="更新成功")
except ValueError as e:
return error_response(400, str(e))
@router.delete("/insurance-project-prices/{price_id}")
async def delete_insurance_project_price(
price_id: str,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
try:
tenant_no = _get_tenant_no(db, user)
_soft_delete_insurance_project_price(db, price_id, tenant_no=tenant_no)
return success_response(None, message="删除成功")
except ValueError as e:
return error_response(400, str(e))