feat(qc): extend outbound work order list API with application/infusion fields and bizType filter

This commit is contained in:
zlwu committed 2026-05-26 18:29:56 +08:00
1 parent fa60330752
commit c9f369a276
2 files changed
+83 -1

No files matched your search

+2
View File
@@ -596,6 +596,7 @@ async def list_qc_work_orders(
keyword: Optional[str] = None,
workOrderStatus: Optional[str] = None,
workOrderType: Optional[str] = None,
bizType: Optional[str] = Query(None, alias="bizType"),
createTimeStart: Optional[str] = Query(None, alias="createTimeStart"),
createTimeEnd: Optional[str] = Query(None, alias="createTimeEnd"),
db: Session = Depends(get_db),
@@ -610,6 +611,7 @@ async def list_qc_work_orders(
keyword=keyword,
work_order_status=workOrderStatus,
work_order_type=workOrderType,
biz_type=bizType,
create_time_start=createTimeStart,
create_time_end=createTimeEnd,
tenant_no=tenant_no,
+81 -1
View File
@@ -21,6 +21,9 @@ from app.models.models import (
BizCellProduct,
BizCellSampleType,
BizCollectionProtocol,
BizPilotApplication,
BizPilotInfusionPlan,
BizPilotInfusionSchedule,
BizProtocolSample,
BizQcLabTestItem,
BizQcTask,
@@ -53,6 +56,7 @@ _DONATION_STATUS_LABELS = {
"dsx": "待生效", "sxz": "生效中", "ygq": "已过期", "yzf": "已作废", "zckc": "转细胞存储"
}
_CONCLUSION_LABELS = {"tg": "通过", "btg": "不通过"}
_OUTBOUND_BIZ_TYPE_LABELS = {"pilot_service": "中试服务", "clinical_application": "临床应用"}
def _dec(v: Any) -> Optional[float]:
@@ -130,6 +134,63 @@ def _enrich_work_order_cell_products(
return items
def _enrich_outbound_work_orders(
db: Session, tenant_no: str, items: List[Dict[str, Any]]
) -> List[Dict[str, Any]]:
"""为 outbound 类型工单批量补充申请单/输注计划信息。"""
outbound = [x for x in items if x.get("workOrderType") == "outbound"]
if not outbound:
return items
schedule_ids = list({x.get("infusionScheduleId") for x in outbound if x.get("infusionScheduleId")})
if not schedule_ids:
return items
# 查输注计划 → 输注方案 → 申请单
schedules = {
s.id: s
for s in db.query(BizPilotInfusionSchedule)
.filter(
BizPilotInfusionSchedule.id.in_(schedule_ids),
BizPilotInfusionSchedule.tenant_no == tenant_no,
BizPilotInfusionSchedule.del_flag == 0,
)
.all()
}
plan_ids = list({s.infusion_plan_id for s in schedules.values() if s.infusion_plan_id})
plans = {
p.id: p
for p in db.query(BizPilotInfusionPlan)
.filter(
BizPilotInfusionPlan.id.in_(plan_ids),
BizPilotInfusionPlan.tenant_no == tenant_no,
BizPilotInfusionPlan.del_flag == 0,
)
.all()
} if plan_ids else {}
app_ids = list({p.pilot_application_id for p in plans.values() if p.pilot_application_id})
apps = {
a.id: a
for a in db.query(BizPilotApplication)
.filter(
BizPilotApplication.id.in_(app_ids),
BizPilotApplication.tenant_no == tenant_no,
BizPilotApplication.del_flag == 0,
)
.all()
} if app_ids else {}
for item in outbound:
sid = item.get("infusionScheduleId") or ""
sched = schedules.get(sid)
if not sched:
continue
plan = plans.get(sched.infusion_plan_id or "")
app = apps.get(plan.pilot_application_id or "") if plan else None
item["applicationNo"] = app.application_no or "" if app else ""
item["applicationName"] = app.application_name or "" if app else ""
item["channelName"] = app.channel_name or "" if app else ""
item["infusionTime"] = _fmt_dt(sched.infusion_time)
return items
def _accept_conclusion_label(v: Optional[str]) -> str:
key = (v or "").strip()
return _ACCEPT_CONCLUSION_LABELS.get(key, key)
@@ -290,13 +351,20 @@ def _gen_daily_no(db: Session, tenant_no: str, prefix: str) -> str:
return f"{prefix}{day}{cnt + 1:04d}"
def _wo_to_dict(wo: BizQcWorkOrder) -> Dict[str, Any]:
def _wo_to_dict(
wo: BizQcWorkOrder,
*,
outbound_info: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
wo_type = getattr(wo, "work_order_type", None) or "inbound"
recv_source_raw = getattr(wo, "reception_source", None)
if wo_type == "temporary":
recv_source = (recv_source_raw or "").strip()
else:
recv_source = (recv_source_raw or "cell_storage").strip() or "cell_storage"
biz_type = getattr(wo, "biz_type", None) or ""
is_outbound = wo_type == "outbound"
ob = outbound_info or {}
return {
"id": wo.id,
"workOrderNo": wo.work_order_no,
@@ -311,6 +379,12 @@ def _wo_to_dict(wo: BizQcWorkOrder) -> Dict[str, Any]:
"qcBizType": _work_order_qc_biz_type(wo),
"qcBizTypeLabel": _qc_biz_type_label(_work_order_qc_biz_type(wo)),
"infusionScheduleId": getattr(wo, "infusion_schedule_id", None) or None,
"bizType": biz_type if is_outbound else "",
"bizTypeLabel": _OUTBOUND_BIZ_TYPE_LABELS.get(biz_type, "") if is_outbound else "",
"applicationNo": ob.get("applicationNo", "") if is_outbound else "",
"applicationName": ob.get("applicationName", "") if is_outbound else "",
"channelName": ob.get("channelName", "") if is_outbound else "",
"infusionTime": ob.get("infusionTime", "") if is_outbound else "",
"cellProductId": getattr(wo, "cell_product_id", None) or "",
"cellProductCode": "",
"cellProductName": "",
@@ -458,6 +532,7 @@ def list_work_orders(
keyword: Optional[str] = None,
work_order_status: Optional[str] = None,
work_order_type: Optional[str] = None,
biz_type: Optional[str] = None,
create_time_start: Optional[str] = None,
create_time_end: Optional[str] = None,
tenant_no: Optional[str] = None,
@@ -470,6 +545,9 @@ def list_work_orders(
wt = (work_order_type or "").strip()
if wt:
q0 = q0.filter(BizQcWorkOrder.work_order_type == wt)
bt = (biz_type or "").strip()
if bt:
q0 = q0.filter(BizQcWorkOrder.biz_type == bt)
kw = (keyword or "").strip()
if kw:
like = f"%{kw}%"
@@ -511,6 +589,7 @@ def list_work_orders(
items = _enrich_work_order_list_items(db, items)
if tenant_no:
items = _enrich_work_order_cell_products(db, tenant_no, items)
items = _enrich_outbound_work_orders(db, tenant_no, items)
return items, int(total)
@@ -1500,6 +1579,7 @@ def create_outbound_qc_work_order(
sample_code=None,
reception_source="outbound",
qc_biz_type="outbound",
biz_type="pilot_service",
infusion_schedule_id=schedule_id,
cell_product_id=cell_product_id or None,
work_order_status="dpz",