Files
zkxw/backend/app/crud/outbound_handover.py
T
2026-06-03 17:53:48 +08:00

258 lines
8.6 KiB
Python

"""输注计划管理 · 出库交接 CRUD"""
from __future__ import annotations
from datetime import datetime
from typing import Any, Dict, List, Optional
from fastapi import HTTPException
from sqlalchemy.orm import Session
from app.core.utils import generate_uuid
from app.crud import outbound_release_material as orm_material_svc
from app.crud import outbound_handover_inventory as handover_inv_svc
from app.crud import pilot_infusion_schedule_mgmt as schedule_mgmt_svc
from app.models.models import BizOutboundHandover, SysUser
def _fmt_dt(t: Optional[datetime]) -> str:
return t.strftime("%Y-%m-%d %H:%M:%S") if t else ""
def _parse_handover_time(value: str) -> datetime:
raw = (value or "").strip()
if not raw:
raise HTTPException(status_code=400, detail="交接时间不能为空")
for fmt in ("%Y-%m-%d %H:%M:%S", "%Y-%m-%d %H:%M"):
try:
return datetime.strptime(raw, fmt)
except ValueError:
continue
raise HTTPException(status_code=400, detail="交接时间格式无效")
def _handover_row_to_dict(row: Optional[BizOutboundHandover]) -> Dict[str, Any]:
if not row:
return {
"handoverUserId": "",
"handoverPerson": "",
"handoverTime": "",
"handoverLocation": "",
"receiverPerson": "",
"cellPurpose": "",
"attachments": "",
"remark": "",
}
return {
"handoverUserId": row.handover_user_id or "",
"handoverPerson": row.handover_person or "",
"handoverTime": _fmt_dt(row.handover_time),
"handoverLocation": row.handover_location or "",
"receiverPerson": row.receiver_person or "",
"cellPurpose": row.cell_purpose or "",
"attachments": row.attachments or "",
"remark": row.remark or "",
}
def _handover_view_dict(row: Optional[BizOutboundHandover]) -> Dict[str, Any]:
if not row:
return {
"handoverPerson": "",
"handoverTime": "",
"handoverLocation": "",
"receiverPerson": "",
"cellPurpose": "",
"attachments": "",
"remark": "",
}
return {
"handoverPerson": row.handover_person or "",
"handoverTime": _fmt_dt(row.handover_time),
"handoverLocation": row.handover_location or "",
"receiverPerson": row.receiver_person or "",
"cellPurpose": row.cell_purpose or "",
"attachments": row.attachments or "",
"remark": row.remark or "",
}
def get_handover_by_schedule(
db: Session,
schedule_id: str,
tenant_no: str,
) -> Optional[BizOutboundHandover]:
sid = (schedule_id or "").strip()
if not sid:
return None
return (
db.query(BizOutboundHandover)
.filter(
BizOutboundHandover.infusion_schedule_id == sid,
BizOutboundHandover.tenant_no == tenant_no,
BizOutboundHandover.del_flag == 0,
)
.first()
)
def get_outbound_handover_view(
db: Session,
schedule_id: str,
tenant_no: str,
) -> Dict[str, Any]:
"""供输注计划 detail 聚合的交接只读信息。"""
row = get_handover_by_schedule(db, schedule_id, tenant_no)
return _handover_view_dict(row)
def get_outbound_handover(
db: Session,
schedule_id: str,
tenant_no: str,
) -> Dict[str, Any]:
"""获取出库交接编辑数据(物料 + 交接信息 + 摘要)。"""
detail = schedule_mgmt_svc.get_infusion_schedule_detail(db, schedule_id, tenant_no)
if not detail:
raise HTTPException(status_code=404, detail="输注计划不存在")
outbound_material = orm_material_svc.get_outbound_material(db, schedule_id, tenant_no)
handover_row = get_handover_by_schedule(db, schedule_id, tenant_no)
return {
"scheduleSummary": {
"applicationNo": detail.get("applicationNo") or "",
"patientName": detail.get("patientName") or "",
"infusionTime": detail.get("infusionTime") or "",
},
"outboundMaterial": {
"remark": outbound_material.get("remark") or "",
"cells": outbound_material.get("cells") or [],
"qcMaterials": outbound_material.get("qcMaterials") or [],
"paperMaterials": outbound_material.get("paperMaterials") or [],
},
"handover": _handover_row_to_dict(handover_row),
}
def save_outbound_handover(
db: Session,
schedule_id: str,
*,
outbound_material: Dict[str, Any],
handover: Dict[str, Any],
tenant_no: str,
user_id: str,
create_dept_id: str = "",
) -> Dict[str, Any]:
"""保存出库物料台账 + 出库交接(单事务,调用方 commit)。"""
detail = schedule_mgmt_svc.get_infusion_schedule_detail(db, schedule_id, tenant_no)
if not detail:
raise HTTPException(status_code=404, detail="输注计划不存在")
handover_user_id = (handover.get("handoverUserId") or handover.get("handover_user_id") or "").strip()
receiver_person = (handover.get("receiverPerson") or handover.get("receiver_person") or "").strip()
handover_location = (handover.get("handoverLocation") or handover.get("handover_location") or "").strip()
handover_remark = (handover.get("remark") or "").strip()
cell_purpose = (handover.get("cellPurpose") or handover.get("cell_purpose") or "").strip()
attachments = (handover.get("attachments") or "").strip()
handover_time_raw = handover.get("handoverTime") or handover.get("handover_time") or ""
if not handover_user_id:
raise HTTPException(status_code=400, detail="交接人不能为空")
if not receiver_person:
raise HTTPException(status_code=400, detail="接收人不能为空")
sys_user = (
db.query(SysUser)
.filter(
SysUser.id == handover_user_id,
SysUser.del_flag == 0,
)
.first()
)
if not sys_user:
raise HTTPException(status_code=400, detail="交接人用户不存在或已删除")
handover_time = _parse_handover_time(str(handover_time_raw))
handover_person = (sys_user.nick_name or sys_user.user_no or "").strip()
if not handover_person:
handover_person = handover_user_id
om = outbound_material or {}
cells = om.get("cells") or []
qc_materials = om.get("qcMaterials") or om.get("qc_materials") or []
paper_materials = om.get("paperMaterials") or om.get("paper_materials") or []
material_remark = om.get("remark")
# 读取保存前台账,用于回滚上次出库交接的库存/状态变更
previous_material = orm_material_svc.get_outbound_material(db, schedule_id, tenant_no)
previous_cell_ids = [
(c.get("cellProductId") or c.get("cell_product_id") or "").strip()
for c in (previous_material.get("cells") or [])
]
had_previous_handover = get_handover_by_schedule(db, schedule_id, tenant_no) is not None
handover_inv_svc.revert_handover_inventory(
db,
schedule_id,
cell_product_ids=previous_cell_ids if had_previous_handover else [],
tenant_no=tenant_no,
user_id=user_id,
)
orm_material_svc.save_outbound_material(
db,
schedule_id,
paper_attachments=None,
paper_materials=paper_materials,
remark=material_remark,
cells=cells,
qc_materials=qc_materials,
tenant_no=tenant_no,
user_id=user_id,
create_dept_id=create_dept_id,
)
handover_inv_svc.apply_handover_inventory(
db,
schedule_id,
cells=cells,
qc_materials=qc_materials,
tenant_no=tenant_no,
user_id=user_id,
create_dept_id=create_dept_id,
receiver_person=receiver_person,
)
now = datetime.now()
row = get_handover_by_schedule(db, schedule_id, tenant_no)
if not row:
row = BizOutboundHandover(
id=generate_uuid(),
infusion_schedule_id=schedule_id,
tenant_no=tenant_no,
order_num=0,
create_by=user_id,
create_dept_id=create_dept_id or "",
create_time=now,
del_flag=0,
)
db.add(row)
db.flush()
else:
row.update_by = user_id
row.update_time = now
row.handover_user_id = handover_user_id
row.handover_person = handover_person
row.handover_time = handover_time
row.handover_location = handover_location or None
row.receiver_person = receiver_person
row.cell_purpose = cell_purpose or None
row.attachments = attachments or None
row.remark = handover_remark or None
db.add(row)
db.flush()
return get_outbound_handover(db, schedule_id, tenant_no)