Просмотр исходного кода

feat(production): extend CRUD for outbound work orders — biz_type, yzf status, list/detail enrichment

zlwu 5 месяцев назад
Родитель
Сommit
d84f5056f2
1 измененных файлов с 110 добавлено и 1 удалено
  1. 110 1
      backend/app/crud/production_work_order.py

+ 110 - 1
backend/app/crud/production_work_order.py

@@ -33,6 +33,7 @@ _WORK_ORDER_STATUS_LABELS = {
     "dpz": "待配置",
     "jxz": "进行中",
     "ywc": "已完成",
+    "yzf": "已作废",
 }
 _RECEPTION_SOURCE_LABELS = {
     "cell_storage": "细胞存储",
@@ -100,6 +101,8 @@ def _wo_to_dict(wo: BizProductionWorkOrder) -> Dict[str, Any]:
             getattr(wo, "reception_source", "cell_storage") or "cell_storage",
         ),
         "infusionScheduleId": getattr(wo, "infusion_schedule_id", None) or None,
+        "bizType": getattr(wo, "biz_type", None) or None,
+        "bizTypeLabel": {"pilot_service": "中试服务", "clinical_application": "临床应用"}.get(getattr(wo, "biz_type", None) or "", ""),
         "workOrderStatus": wo.work_order_status,
         "workOrderStatusLabel": _WORK_ORDER_STATUS_LABELS.get(wo.work_order_status, wo.work_order_status),
         "receptionTime": "",
@@ -117,6 +120,65 @@ def _enrich_wo_items(db: Session, items: List[Dict[str, Any]]) -> List[Dict[str,
     return qc_wo_svc._enrich_work_order_list_items(db, items)
 
 
+_BIZ_TYPE_LABELS = {"pilot_service": "中试服务", "clinical_application": "临床应用"}
+
+
+def _enrich_outbound_items(db: Session, items: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
+    """为 outbound 类型工单附加申请单号、细胞类型、规格、输注时间等关联数据。"""
+    from app.models.models import (
+        BizPilotApplication,
+        BizPilotInfusionPlan,
+        BizPilotInfusionSchedule,
+    )
+
+    outbound_ids = [
+        it["infusionScheduleId"]
+        for it in items
+        if it.get("workOrderType") == "outbound" and it.get("infusionScheduleId")
+    ]
+    if not outbound_ids:
+        return items
+
+    schedules = (
+        db.query(BizPilotInfusionSchedule)
+        .filter(
+            BizPilotInfusionSchedule.id.in_(outbound_ids),
+            BizPilotInfusionSchedule.del_flag == 0,
+        )
+        .all()
+    )
+    sched_map = {s.id: s for s in schedules}
+
+    plan_ids = list({s.infusion_plan_id for s in schedules if s.infusion_plan_id})
+    plan_map = {}
+    if plan_ids:
+        plans = db.query(BizPilotInfusionPlan).filter(BizPilotInfusionPlan.id.in_(plan_ids)).all()
+        plan_map = {p.id: p for p in plans}
+
+    app_ids = list({p.pilot_application_id for p in plan_map.values() if p.pilot_application_id})
+    app_map = {}
+    if app_ids:
+        apps = db.query(BizPilotApplication).filter(BizPilotApplication.id.in_(app_ids)).all()
+        app_map = {a.id: a for a in apps}
+
+    for it in items:
+        if it.get("workOrderType") != "outbound" or not it.get("infusionScheduleId"):
+            continue
+        sched = sched_map.get(it["infusionScheduleId"])
+        if not sched:
+            continue
+        plan = plan_map.get(sched.infusion_plan_id) if sched.infusion_plan_id else None
+        app = app_map.get(plan.pilot_application_id) if plan and plan.pilot_application_id else None
+
+        it["applicationNo"] = app.application_no if app else ""
+        it["cellType"] = sched.cell_type or ""
+        it["specText"] = sched.spec_text or ""
+        it["infusionTime"] = _fmt_dt(sched.infusion_time) if sched.infusion_time else ""
+        it["infusionLocation"] = sched.infusion_location or ""
+
+    return items
+
+
 def _reception_source_label(source: Optional[str]) -> str:
     key = (source or "").strip() or "cell_storage"
     return _RECEPTION_SOURCE_LABELS.get(key, key)
@@ -157,10 +219,54 @@ def _attach_reception_detail(
     }
 
 
+def _attach_outbound_detail(
+    db: Session, wo: BizProductionWorkOrder, out: Dict[str, Any]
+) -> None:
+    """outbound 工单详情附加申请单 + 输注计划信息。"""
+    from app.models.models import (
+        BizPilotApplication,
+        BizPilotInfusionPlan,
+        BizPilotInfusionSchedule,
+    )
+
+    _APP_STATUS_LABELS = {"dks": "待开始", "jxz": "进行中", "ywc": "已完成", "yzf": "已作废"}
+
+    sched = (
+        db.query(BizPilotInfusionSchedule)
+        .filter(BizPilotInfusionSchedule.id == wo.infusion_schedule_id, BizPilotInfusionSchedule.del_flag == 0)
+        .first()
+    )
+    plan = None
+    app = None
+    if sched and sched.infusion_plan_id:
+        plan = db.query(BizPilotInfusionPlan).filter(BizPilotInfusionPlan.id == sched.infusion_plan_id).first()
+    if plan and plan.pilot_application_id:
+        app = db.query(BizPilotApplication).filter(BizPilotApplication.id == plan.pilot_application_id).first()
+
+    out["reception"] = {}
+    out["pilotApplication"] = {
+        "applicationNo": app.application_no if app else "",
+        "applicationName": app.application_name if app else "",
+        "applicationStatus": app.application_status if app else "",
+        "applicationStatusLabel": _APP_STATUS_LABELS.get(app.application_status, "") if app else "",
+    } if app else {}
+    out["infusionSchedule"] = {
+        "cellType": sched.cell_type if sched else "",
+        "specText": sched.spec_text if sched else "",
+        "infusionTime": _fmt_dt(sched.infusion_time) if sched and sched.infusion_time else "",
+        "infusionLocation": sched.infusion_location if sched else "",
+        "infusionMethod": sched.infusion_method if sched else "",
+        "scheduleStatus": sched.schedule_status if sched else "",
+    } if sched else {}
+
+
 def _wo_to_response_dict(db: Session, wo: BizProductionWorkOrder) -> Dict[str, Any]:
     """工单响应(含接收记录关联的样本类型、接收人、接收时间及 reception 详情)。"""
     out = _enrich_wo_items(db, [_wo_to_dict(wo)])[0]
-    _attach_reception_detail(db, wo, out, wo.tenant_no or "")
+    if wo.work_order_type == "outbound" and wo.infusion_schedule_id:
+        _attach_outbound_detail(db, wo, out)
+    else:
+        _attach_reception_detail(db, wo, out, wo.tenant_no or "")
     return out
 
 
@@ -341,6 +447,7 @@ def list_production_work_orders(
         .all()
     )
     items = _enrich_wo_items(db, [_wo_to_dict(x) for x in rows])
+    items = _enrich_outbound_items(db, items)
     return {"items": items, "total": int(total)}
 
 
@@ -643,6 +750,7 @@ def create_outbound_production_work_order(
     user_id: Optional[str] = None,
     create_dept_id: str = "",
     remark: str = "",
+    biz_type: str = "pilot_service",
 ) -> BizProductionWorkOrder:
     existing = (
         db.query(BizProductionWorkOrder)
@@ -666,6 +774,7 @@ def create_outbound_production_work_order(
         sample_code=None,
         reception_source="outbound",
         infusion_schedule_id=schedule_id,
+        biz_type=biz_type,
         work_order_status="dpz",
         tenant_no=tenant_no,
         remark=remark,