This commit is contained in:
zlwu committed 2026-05-20 09:28:36 +08:00
1 parent e6072457fd
commit be4fab78e1
578 files changed
+174415 -214

No files matched your search

+260 -2
View File
@@ -1,11 +1,12 @@
"""细胞存储 — 采集协议单 / 审核 / 财务确认 / 分期预警 API"""
from datetime import datetime, timedelta
from typing import Any, Dict, List, Optional
from fastapi import APIRouter, Depends, Query
from pydantic import BaseModel, ConfigDict, Field
from sqlalchemy.orm import Session
from sqlalchemy import and_ as sa_and
from sqlalchemy import and_ as sa_and, func as sa_func, or_ as sa_or
from app.core.database import get_db
from app.core.menu_guard import require_admin_or_super_admin
@@ -13,7 +14,14 @@ from app.core.response import error_response, success_response
from app.core.utils import parse_datetime
from app.crud import collection_protocol as cp_svc
from app.crud import customer as customer_crud
from app.models.models import BizCollectionProtocol, BizCustomer, SysUser
from app.models.models import (
BizCollectionProtocol,
BizCustomer,
BizProtocolPartyCustomer,
BizProtocolSample,
BizProtocolStorageCert,
SysUser,
)
router = APIRouter(prefix="/web/admin", tags=["细胞存储"])
@@ -657,3 +665,253 @@ async def post_refund_confirm(
except ValueError as e:
return error_response(400, str(e))
# ---------------------------------------------------------------------------
# 储存证明管理 / 满月待办
# ---------------------------------------------------------------------------
@router.get("/storage-certs")
async def list_storage_certs(
page: int = Query(1, ge=1),
pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
keyword: Optional[str] = None,
makeStatus: Optional[str] = Query(None, alias="makeStatus"),
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
tenant_no = _get_tenant_no(db, user)
q = (
db.query(BizCollectionProtocol)
.filter(
BizCollectionProtocol.del_flag == 0,
BizCollectionProtocol.tenant_no == tenant_no,
BizCollectionProtocol.protocol_status == "sxz",
)
)
kw = (keyword or "").strip()
if kw:
like = f"%{kw}%"
q = q.filter(BizCollectionProtocol.protocol_no.like(like))
protocol_ids_sub = q.with_entities(BizCollectionProtocol.id).subquery()
sample_exists = (
db.query(BizProtocolSample)
.filter(
BizProtocolSample.collection_protocol_id == protocol_ids_sub.c.id,
BizProtocolSample.del_flag == 0,
BizProtocolSample.sample_status == "yrk",
)
.limit(1)
.exists()
)
q = q.filter(sample_exists)
rows_all = q.order_by(BizCollectionProtocol.create_time.desc()).all()
protocol_ids = [r.id for r in rows_all]
pc_map: Dict[str, Any] = {}
sc_map: Dict[str, Any] = {}
sample_map: Dict[str, List[Dict[str, Any]]] = {}
if protocol_ids:
pc_rows = (
db.query(BizProtocolPartyCustomer)
.filter(
BizProtocolPartyCustomer.collection_protocol_id.in_(protocol_ids),
BizProtocolPartyCustomer.del_flag == 0,
)
.all()
)
for pc in pc_rows:
pc_map[pc.collection_protocol_id] = pc
sc_rows = (
db.query(BizProtocolStorageCert)
.filter(
BizProtocolStorageCert.collection_protocol_id.in_(protocol_ids),
BizProtocolStorageCert.del_flag == 0,
)
.all()
)
for sc in sc_rows:
sc_map[sc.collection_protocol_id] = sc
s_rows = (
db.query(BizProtocolSample)
.filter(
BizProtocolSample.collection_protocol_id.in_(protocol_ids),
BizProtocolSample.del_flag == 0,
BizProtocolSample.sample_status == "yrk",
)
.all()
)
for s in s_rows:
sample_map.setdefault(s.collection_protocol_id, []).append(
cp_svc._sample_to_dict(s)
)
items: List[Dict[str, Any]] = []
for r in rows_all:
sc = sc_map.get(r.id)
ms = (sc.make_status or "0") if sc else "0"
if makeStatus and makeStatus.strip() and ms != makeStatus.strip():
continue
pc = pc_map.get(r.id)
d: Dict[str, Any] = {
"id": r.id,
"protocolNo": r.protocol_no or "",
"protocolStatus": r.protocol_status or "",
"motherName": (pc.mother_name or "") if pc else "",
"newbornDeliveryTime": cp_svc._fmt_dt(pc.newborn_delivery_time) if pc else "",
"samples": sample_map.get(r.id, []),
"makeStatus": ms,
"certImageUrls": (sc.cert_image_urls or "") if sc else "",
"makeDate": ((sc.make_date or "").strip() if sc.make_date else "") if sc else "",
}
items.append(d)
total = len(items)
page_safe = max(1, page)
page_size_safe = min(max(1, pageSize), 100)
start = (page_safe - 1) * page_size_safe
page_items = items[start : start + page_size_safe]
tp = cp_svc.total_pages(total, page_size_safe)
return success_response(
{"list": page_items, "total": total, "page": page_safe, "pageSize": page_size_safe, "totalPages": tp}
)
@router.get("/fullmoon-todos")
async def list_fullmoon_todos(
page: int = Query(1, ge=1),
pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
keyword: Optional[str] = None,
todoStatus: Optional[str] = Query(None, alias="todoStatus"),
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
tenant_no = _get_tenant_no(db, user)
q = (
db.query(BizCollectionProtocol, BizProtocolPartyCustomer)
.join(
BizProtocolPartyCustomer,
sa_and(
BizProtocolPartyCustomer.collection_protocol_id == BizCollectionProtocol.id,
BizProtocolPartyCustomer.del_flag == 0,
),
)
.filter(
BizCollectionProtocol.del_flag == 0,
BizCollectionProtocol.tenant_no == tenant_no,
BizCollectionProtocol.protocol_status == "sxz",
BizProtocolPartyCustomer.tenant_no == tenant_no,
)
)
kw = (keyword or "").strip()
if kw:
like = f"%{kw}%"
q = q.filter(
sa_or(
BizCollectionProtocol.protocol_no.like(like),
BizProtocolPartyCustomer.mother_name.like(like),
)
)
rows = q.order_by(BizCollectionProtocol.create_time.desc()).all()
protocol_ids = [r.id for r, _ in rows]
ft_map: Dict[str, Any] = {}
if protocol_ids:
from app.models.models import BizProtocolFullmoonTodo
ft_rows = (
db.query(BizProtocolFullmoonTodo)
.filter(
BizProtocolFullmoonTodo.collection_protocol_id.in_(protocol_ids),
BizProtocolFullmoonTodo.tenant_no == tenant_no,
BizProtocolFullmoonTodo.del_flag == 0,
)
.all()
)
for ft in ft_rows:
ft_map[ft.collection_protocol_id] = ft
now = datetime.now()
items: List[Dict[str, Any]] = []
for proto, pc in rows:
dt = pc.newborn_delivery_time
if not dt:
continue
fullmoon_date = dt + timedelta(days=30)
if fullmoon_date > now:
continue
ft = ft_map.get(proto.id)
ts = (ft.todo_status or "0") if ft else "0"
if todoStatus and todoStatus.strip() and ts != todoStatus.strip():
continue
d: Dict[str, Any] = {
"id": proto.id,
"protocolNo": proto.protocol_no or "",
"protocolStatus": proto.protocol_status or "",
"motherName": pc.mother_name or "",
"motherPhone": pc.mother_phone or "",
"newbornName": pc.newborn_name or "",
"newbornDeliveryTime": cp_svc._fmt_dt(dt),
"fullmoonDate": fullmoon_date.strftime("%Y-%m-%d"),
}
if ft:
d["fullmoonTodo"] = cp_svc._fullmoon_todo_to_dict(ft)
else:
d["fullmoonTodo"] = None
items.append(d)
total = len(items)
page_safe = max(1, page)
page_size_safe = min(max(1, pageSize), 100)
start = (page_safe - 1) * page_size_safe
page_items = items[start : start + page_size_safe]
tp = cp_svc.total_pages(total, page_size_safe)
return success_response(
{"list": page_items, "total": total, "page": page_safe, "pageSize": page_size_safe, "totalPages": tp}
)
class FullmoonTodoInsuranceBody(BaseModel):
model_config = ConfigDict(populate_by_name=True)
insurance_company_id: Optional[str] = Field(None, alias="insuranceCompanyId")
insurance_company_name: Optional[str] = Field(None, alias="insuranceCompanyName")
insurance_type: Optional[str] = Field(None, alias="insuranceType")
insurance_policy_no: Optional[str] = Field(None, alias="insurancePolicyNo")
insurance_effective_date: Optional[str] = Field(None, alias="insuranceEffectiveDate")
insurance_expiry_date: Optional[str] = Field(None, alias="insuranceExpiryDate")
insurance_subscribed: Optional[str] = Field(None, alias="insuranceSubscribed")
insurance_fee: Optional[float] = Field(None, alias="insuranceFee")
insurance_attachments: Optional[str] = Field(None, alias="insuranceAttachments")
todo_status: Optional[str] = Field(None, alias="todoStatus")
handle_date: Optional[str] = Field(None, alias="handleDate")
handle_remark: Optional[str] = Field(None, alias="handleRemark")
@router.put("/fullmoon-todos/{protocol_id}/insurance")
async def update_fullmoon_todo_insurance(
protocol_id: str,
body: FullmoonTodoInsuranceBody,
user: dict = Depends(require_admin_or_super_admin),
db: Session = Depends(get_db),
):
tenant_no = _get_tenant_no(db, user)
user_id = _get_current_user_id(user)
try:
payload = body.model_dump(exclude_unset=True, by_alias=False)
ft = cp_svc.upsert_fullmoon_todo(
db,
protocol_id,
tenant_no,
user_id,
**payload,
)
return success_response(cp_svc._fullmoon_todo_to_dict(ft), message="更新成功")
except ValueError as e:
return error_response(400, str(e))