| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- """中试服务出库生产/质检工单与输注计划生产状态、质检状态双向联动。"""
- from __future__ import annotations
- from datetime import datetime
- from typing import Optional
- from sqlalchemy.orm import Session
- from app.models.models import (
- BizPilotInfusionSchedule,
- BizProductionWorkOrder,
- BizQcWorkOrder,
- )
- _OUTBOUND_BIZ_TYPES = ("pilot_service", "clinical_application", "basic_experiment")
- def _is_pilot_outbound_production(wo: BizProductionWorkOrder) -> bool:
- return (
- (getattr(wo, "work_order_type", None) or "") == "outbound"
- and (getattr(wo, "biz_type", None) or "") in _OUTBOUND_BIZ_TYPES
- and bool(getattr(wo, "infusion_schedule_id", None))
- )
- def _is_pilot_outbound_qc(wo: BizQcWorkOrder) -> bool:
- return (
- (getattr(wo, "work_order_type", None) or "") == "outbound"
- and (getattr(wo, "biz_type", None) or "") in _OUTBOUND_BIZ_TYPES
- and bool(getattr(wo, "infusion_schedule_id", None))
- )
- def _get_schedule(
- db: Session, schedule_id: str, tenant_no: str
- ) -> Optional[BizPilotInfusionSchedule]:
- if not (schedule_id or "").strip():
- return None
- return (
- db.query(BizPilotInfusionSchedule)
- .filter(
- BizPilotInfusionSchedule.id == schedule_id.strip(),
- BizPilotInfusionSchedule.tenant_no == tenant_no,
- BizPilotInfusionSchedule.del_flag == 0,
- )
- .first()
- )
- def _touch(row, user_id: Optional[str]) -> None:
- now = datetime.now()
- if user_id:
- row.update_by = user_id
- row.update_time = now
- def sync_schedule_from_production_work_order(
- db: Session,
- wo: BizProductionWorkOrder,
- *,
- user_id: Optional[str] = None,
- ) -> None:
- """出库生产工单状态 → 输注计划 schedule_status。"""
- if not _is_pilot_outbound_production(wo):
- return
- sched = _get_schedule(db, wo.infusion_schedule_id or "", wo.tenant_no or "")
- if not sched:
- return
- wo_status = (wo.work_order_status or "").strip()
- current = (sched.schedule_status or "").strip()
- new_status: Optional[str] = None
- if wo_status in ("dpz", "jxz"):
- if current not in ("ysc", "yjf", "yqx"):
- new_status = "dsc"
- elif wo_status == "ywc":
- if current not in ("yjf", "yqx"):
- new_status = "ysc"
- elif wo_status == "yzf":
- new_status = "yqx"
- if new_status and new_status != current:
- sched.schedule_status = new_status
- _touch(sched, user_id)
- db.add(sched)
- def sync_schedule_from_qc_work_order(
- db: Session,
- wo: BizQcWorkOrder,
- *,
- user_id: Optional[str] = None,
- ) -> None:
- """出库质检工单状态 → 输注计划 qc_status(仅计划自动质检参与联动)。"""
- if not _is_pilot_outbound_qc(wo):
- return
- trigger = (getattr(wo, "trigger_source", None) or "reception").strip()
- if trigger != "schedule":
- return
- sched = _get_schedule(db, wo.infusion_schedule_id or "", wo.tenant_no or "")
- if not sched:
- return
- wo_status = (wo.work_order_status or "").strip()
- current = (sched.qc_status or "").strip()
- new_status: Optional[str] = None
- if wo_status in ("dpz", "ypz"):
- if current not in ("yzj", "yqx"):
- new_status = "dzc"
- elif wo_status == "ywc":
- if current != "yqx":
- new_status = "yzj"
- elif wo_status == "yzf":
- new_status = "yqx"
- if new_status and new_status != current:
- sched.qc_status = new_status
- _touch(sched, user_id)
- db.add(sched)
- def sync_production_work_order_from_schedule(
- db: Session,
- schedule: BizPilotInfusionSchedule,
- *,
- user_id: Optional[str] = None,
- ) -> None:
- """输注计划 schedule_status → 出库生产工单状态。"""
- schedule_id = schedule.id or ""
- tenant_no = schedule.tenant_no or ""
- if not schedule_id:
- return
- wo = (
- db.query(BizProductionWorkOrder)
- .filter(
- BizProductionWorkOrder.infusion_schedule_id == schedule_id,
- BizProductionWorkOrder.tenant_no == tenant_no,
- BizProductionWorkOrder.del_flag == 0,
- BizProductionWorkOrder.work_order_type == "outbound",
- BizProductionWorkOrder.biz_type.in_(_OUTBOUND_BIZ_TYPES),
- )
- .first()
- )
- if not wo:
- return
- sched_status = (schedule.schedule_status or "").strip()
- current = (wo.work_order_status or "").strip()
- new_status: Optional[str] = None
- if sched_status in ("ysc", "yjf"):
- if current not in ("ywc", "yzf"):
- new_status = "ywc"
- elif sched_status == "yqx":
- if current != "ywc":
- new_status = "yzf"
- if new_status and new_status != current:
- wo.work_order_status = new_status
- _touch(wo, user_id)
- db.add(wo)
- def sync_qc_work_order_from_schedule(
- db: Session,
- schedule: BizPilotInfusionSchedule,
- *,
- user_id: Optional[str] = None,
- ) -> None:
- """输注计划 qc_status → 出库质检工单状态。"""
- schedule_id = schedule.id or ""
- tenant_no = schedule.tenant_no or ""
- if not schedule_id:
- return
- wo = (
- db.query(BizQcWorkOrder)
- .filter(
- BizQcWorkOrder.infusion_schedule_id == schedule_id,
- BizQcWorkOrder.tenant_no == tenant_no,
- BizQcWorkOrder.del_flag == 0,
- BizQcWorkOrder.work_order_type == "outbound",
- BizQcWorkOrder.biz_type.in_(_OUTBOUND_BIZ_TYPES),
- BizQcWorkOrder.trigger_source == "schedule",
- )
- .first()
- )
- if not wo:
- return
- qc_status = (schedule.qc_status or "").strip()
- current = (wo.work_order_status or "").strip()
- new_status: Optional[str] = None
- if qc_status == "yzj":
- if current not in ("ywc", "yzf"):
- new_status = "ywc"
- elif qc_status == "yqx":
- if current != "ywc":
- new_status = "yzf"
- if new_status and new_status != current:
- wo.work_order_status = new_status
- _touch(wo, user_id)
- db.add(wo)
- def sync_pilot_outbound_from_schedule(
- db: Session,
- schedule: BizPilotInfusionSchedule,
- *,
- user_id: Optional[str] = None,
- ) -> None:
- """输注计划状态变更后,回写关联出库工单。"""
- sync_production_work_order_from_schedule(db, schedule, user_id=user_id)
- sync_qc_work_order_from_schedule(db, schedule, user_id=user_id)
|