258 lines
8.6 KiB
Python
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)
|