561 lines
18 KiB
Python
561 lines
18 KiB
Python
"""中试服务申请单管理 API(申请单、患者信息、输注方案、输注计划、出库联动)"""
|
|
from typing import Optional
|
|
|
|
from fastapi import APIRouter, Depends, Query
|
|
from pydantic import BaseModel
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.core.database import get_db
|
|
from app.core.menu_guard import require_admin_or_super_admin
|
|
from app.core.response import error_response, success_response
|
|
from app.crud import pilot_application
|
|
from app.models.models import SysUser
|
|
|
|
router = APIRouter(prefix="/web/admin", tags=["中试服务申请单管理"])
|
|
|
|
|
|
def _get_tenant_no(db: Session, user: dict) -> str:
|
|
user_id = user.get("user_id")
|
|
if not user_id:
|
|
raise PermissionError("用户身份信息缺失,无法确定租户")
|
|
sys_user = db.query(SysUser).filter(SysUser.id == user_id).first()
|
|
if not sys_user or not sys_user.tenant_no:
|
|
raise PermissionError("用户租户信息缺失")
|
|
return sys_user.tenant_no
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Pydantic Schemas
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class IdBody(BaseModel):
|
|
id: str
|
|
|
|
|
|
class PlanIdBody(BaseModel):
|
|
plan_id: str
|
|
|
|
|
|
class ApplicationCreateBody(BaseModel):
|
|
channel_service_order_id: str
|
|
remark: Optional[str] = None
|
|
|
|
|
|
class ApplicationUpdateBody(BaseModel):
|
|
id: str
|
|
remark: Optional[str] = None
|
|
|
|
|
|
class PatientSaveBody(BaseModel):
|
|
application_id: str
|
|
customer_id: Optional[str] = None
|
|
patient_name: str
|
|
sex: Optional[str] = None
|
|
age: Optional[int] = None
|
|
id_card_no: Optional[str] = None
|
|
phone_no: Optional[str] = None
|
|
emergency_contact: Optional[str] = None
|
|
emergency_phone: Optional[str] = None
|
|
clinical_diagnosis: Optional[str] = None
|
|
diagnosis_attachments: Optional[str] = None
|
|
need_checkup: int = 1
|
|
|
|
|
|
class InfusionPlanCreateBody(BaseModel):
|
|
pilot_application_id: str
|
|
cell_type: str
|
|
spec_text: Optional[str] = None
|
|
total_course_count: int
|
|
course_interval: Optional[str] = None
|
|
infusion_route: Optional[str] = None
|
|
infusion_start_date: Optional[str] = None
|
|
|
|
|
|
class InfusionPlanUpdateBody(BaseModel):
|
|
id: str
|
|
cell_type: Optional[str] = None
|
|
spec_text: Optional[str] = None
|
|
total_course_count: Optional[int] = None
|
|
course_interval: Optional[str] = None
|
|
infusion_route: Optional[str] = None
|
|
infusion_start_date: Optional[str] = None
|
|
|
|
|
|
class InfusionScheduleUpdateBody(BaseModel):
|
|
id: str
|
|
infusion_time: Optional[str] = None
|
|
remark: Optional[str] = None
|
|
attachments: Optional[str] = None
|
|
|
|
|
|
class ScheduleCreateBody(BaseModel):
|
|
plan_id: str
|
|
infusion_time: Optional[str] = None
|
|
remark: Optional[str] = None
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 1. 申请单 CRUD + 状态变更
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@router.get("/pilot-application/list")
|
|
async def api_list_applications(
|
|
page: int = Query(1, ge=1),
|
|
pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
|
|
channelId: Optional[str] = Query(None, alias="channelId"),
|
|
applicationStatus: Optional[str] = Query(None, alias="applicationStatus"),
|
|
channelServiceOrderId: Optional[str] = Query(None, alias="channelServiceOrderId"),
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
tenant_no = _get_tenant_no(db, user)
|
|
result = pilot_application.list_applications(
|
|
db,
|
|
tenant_no=tenant_no,
|
|
page=page,
|
|
page_size=pageSize,
|
|
channel_id=channelId,
|
|
application_status=applicationStatus,
|
|
channel_service_order_id=channelServiceOrderId,
|
|
)
|
|
return success_response(result)
|
|
|
|
|
|
@router.get("/pilot-application/detail")
|
|
async def api_get_application(
|
|
id: str = Query(...),
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
tenant_no = _get_tenant_no(db, user)
|
|
result = pilot_application.get_application(db, app_id=id, tenant_no=tenant_no)
|
|
if result is None:
|
|
return error_response(404, "申请单不存在")
|
|
return success_response(result)
|
|
|
|
|
|
@router.post("/pilot-application/create")
|
|
async def api_create_application(
|
|
body: ApplicationCreateBody,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
data = {
|
|
"channelServiceOrderId": body.channel_service_order_id,
|
|
"remark": body.remark,
|
|
}
|
|
result = pilot_application.create_application(
|
|
db,
|
|
data=data,
|
|
tenant_no=tenant_no,
|
|
user_id=user.get("user_id"),
|
|
dept_id=user.get("region_id", ""),
|
|
)
|
|
return success_response(result, message="创建成功")
|
|
except ValueError as e:
|
|
return error_response(400, str(e))
|
|
|
|
|
|
@router.put("/pilot-application/update")
|
|
async def api_update_application(
|
|
body: ApplicationUpdateBody,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
data = {}
|
|
if body.remark is not None:
|
|
data["remark"] = body.remark
|
|
result = pilot_application.update_application(
|
|
db, app_id=body.id, data=data, tenant_no=tenant_no
|
|
)
|
|
return success_response(result, message="更新成功")
|
|
except ValueError as e:
|
|
return error_response(400, str(e))
|
|
|
|
|
|
@router.delete("/pilot-application/delete")
|
|
async def api_delete_application(
|
|
body: IdBody,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
pilot_application.soft_delete_application(db, app_id=body.id, tenant_no=tenant_no)
|
|
return success_response(None, message="删除成功")
|
|
except ValueError as e:
|
|
return error_response(400, str(e))
|
|
|
|
|
|
@router.post("/pilot-application/start")
|
|
async def api_start_application(
|
|
body: IdBody,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
result = pilot_application.start_application(
|
|
db, app_id=body.id, tenant_no=tenant_no, user_id=user.get("user_id")
|
|
)
|
|
return success_response(result, message="操作成功")
|
|
except ValueError as e:
|
|
return error_response(400, str(e))
|
|
|
|
|
|
@router.post("/pilot-application/complete")
|
|
async def api_complete_application(
|
|
body: IdBody,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
result = pilot_application.complete_application(
|
|
db, app_id=body.id, tenant_no=tenant_no, user_id=user.get("user_id")
|
|
)
|
|
return success_response(result, message="操作成功")
|
|
except ValueError as e:
|
|
return error_response(400, str(e))
|
|
|
|
|
|
@router.post("/pilot-application/void")
|
|
async def api_void_application(
|
|
body: IdBody,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
result = pilot_application.void_application(
|
|
db, app_id=body.id, tenant_no=tenant_no, user_id=user.get("user_id")
|
|
)
|
|
return success_response(result, message="操作成功")
|
|
except ValueError as e:
|
|
return error_response(400, str(e))
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 2. 患者信息
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@router.get("/pilot-patient/detail")
|
|
async def api_get_patient(
|
|
application_id: str = Query(...),
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
tenant_no = _get_tenant_no(db, user)
|
|
result = pilot_application.get_patient_by_application(
|
|
db, app_id=application_id, tenant_no=tenant_no
|
|
)
|
|
if result is None:
|
|
return success_response(None)
|
|
return success_response(result)
|
|
|
|
|
|
@router.post("/pilot-patient/save")
|
|
async def api_save_patient(
|
|
body: PatientSaveBody,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
data = {
|
|
"customerId": body.customer_id,
|
|
"patientName": body.patient_name,
|
|
"sex": body.sex,
|
|
"age": body.age,
|
|
"idCardNo": body.id_card_no,
|
|
"phoneNo": body.phone_no,
|
|
"emergencyContact": body.emergency_contact,
|
|
"emergencyPhone": body.emergency_phone,
|
|
"clinicalDiagnosis": body.clinical_diagnosis,
|
|
"diagnosisAttachments": body.diagnosis_attachments,
|
|
"needCheckup": body.need_checkup,
|
|
}
|
|
result = pilot_application.save_patient(
|
|
db,
|
|
app_id=body.application_id,
|
|
data=data,
|
|
tenant_no=tenant_no,
|
|
user_id=user.get("user_id"),
|
|
dept_id=user.get("region_id", ""),
|
|
)
|
|
return success_response(result, message="保存成功")
|
|
except ValueError as e:
|
|
return error_response(400, str(e))
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 3. 输注方案
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@router.get("/pilot-infusion-plan/list")
|
|
async def api_list_plans(
|
|
application_id: str = Query(...),
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
tenant_no = _get_tenant_no(db, user)
|
|
result = pilot_application.list_infusion_plans(
|
|
db, app_id=application_id, tenant_no=tenant_no
|
|
)
|
|
return success_response(result)
|
|
|
|
|
|
@router.post("/pilot-infusion-plan/create")
|
|
async def api_create_plan(
|
|
body: InfusionPlanCreateBody,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
data = {
|
|
"cellType": body.cell_type,
|
|
"specText": body.spec_text,
|
|
"totalCourseCount": body.total_course_count,
|
|
"courseInterval": body.course_interval,
|
|
"infusionRoute": body.infusion_route,
|
|
"infusionStartDate": body.infusion_start_date,
|
|
}
|
|
result = pilot_application.create_infusion_plan(
|
|
db,
|
|
app_id=body.pilot_application_id,
|
|
data=data,
|
|
tenant_no=tenant_no,
|
|
user_id=user.get("user_id"),
|
|
dept_id=user.get("region_id", ""),
|
|
)
|
|
return success_response(result, message="创建成功")
|
|
except ValueError as e:
|
|
return error_response(400, str(e))
|
|
|
|
|
|
@router.put("/pilot-infusion-plan/update")
|
|
async def api_update_plan(
|
|
body: InfusionPlanUpdateBody,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
data = {}
|
|
if body.cell_type is not None:
|
|
data["cellType"] = body.cell_type
|
|
if body.spec_text is not None:
|
|
data["specText"] = body.spec_text
|
|
if body.total_course_count is not None:
|
|
data["totalCourseCount"] = body.total_course_count
|
|
if body.course_interval is not None:
|
|
data["courseInterval"] = body.course_interval
|
|
if body.infusion_route is not None:
|
|
data["infusionRoute"] = body.infusion_route
|
|
if body.infusion_start_date is not None:
|
|
data["infusionStartDate"] = body.infusion_start_date
|
|
result = pilot_application.update_infusion_plan(
|
|
db, plan_id=body.id, data=data, tenant_no=tenant_no
|
|
)
|
|
return success_response(result, message="更新成功")
|
|
except ValueError as e:
|
|
return error_response(400, str(e))
|
|
|
|
|
|
@router.delete("/pilot-infusion-plan/delete")
|
|
async def api_delete_plan(
|
|
body: IdBody,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
pilot_application.soft_delete_infusion_plan(
|
|
db, plan_id=body.id, tenant_no=tenant_no
|
|
)
|
|
return success_response(None, message="删除成功")
|
|
except ValueError as e:
|
|
return error_response(400, str(e))
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 4. 输注计划
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
@router.post("/pilot-infusion-schedule/auto-generate")
|
|
async def api_auto_generate(
|
|
body: PlanIdBody,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
result = pilot_application.auto_generate_schedules(
|
|
db,
|
|
plan_id=body.plan_id,
|
|
tenant_no=tenant_no,
|
|
user_id=user.get("user_id"),
|
|
dept_id=user.get("region_id", ""),
|
|
)
|
|
return success_response(result, message="生成成功")
|
|
except ValueError as e:
|
|
return error_response(400, str(e))
|
|
|
|
|
|
@router.post("/pilot-infusion-schedule/create")
|
|
async def api_create_schedule(
|
|
body: ScheduleCreateBody,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
data = {
|
|
"infusionTime": body.infusion_time,
|
|
"remark": body.remark,
|
|
}
|
|
result = pilot_application.create_schedule(
|
|
db,
|
|
plan_id=body.plan_id,
|
|
data=data,
|
|
tenant_no=tenant_no,
|
|
user_id=user.get("user_id"),
|
|
dept_id=user.get("region_id", ""),
|
|
)
|
|
return success_response(result, message="创建成功")
|
|
except ValueError as e:
|
|
return error_response(400, str(e))
|
|
|
|
|
|
@router.put("/pilot-infusion-schedule/update")
|
|
async def api_update_schedule(
|
|
body: InfusionScheduleUpdateBody,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
data = {}
|
|
if body.infusion_time is not None:
|
|
data["infusionTime"] = body.infusion_time
|
|
if body.remark is not None:
|
|
data["remark"] = body.remark
|
|
if body.attachments is not None:
|
|
data["attachments"] = body.attachments
|
|
result = pilot_application.update_schedule(
|
|
db, schedule_id=body.id, data=data, tenant_no=tenant_no
|
|
)
|
|
return success_response(result, message="更新成功")
|
|
except ValueError as e:
|
|
return error_response(400, str(e))
|
|
|
|
|
|
@router.delete("/pilot-infusion-schedule/delete")
|
|
async def api_delete_schedule(
|
|
body: IdBody,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
pilot_application.soft_delete_schedule(
|
|
db, schedule_id=body.id, tenant_no=tenant_no
|
|
)
|
|
return success_response(None, message="删除成功")
|
|
except ValueError as e:
|
|
return error_response(400, str(e))
|
|
|
|
|
|
@router.post("/pilot-infusion-schedule/mark-complete")
|
|
async def api_mark_complete(
|
|
body: IdBody,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
result = pilot_application.mark_schedule_complete(
|
|
db, schedule_id=body.id, tenant_no=tenant_no, user_id=user.get("user_id")
|
|
)
|
|
return success_response(result, message="操作成功")
|
|
except ValueError as e:
|
|
return error_response(400, str(e))
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 出库生产工单 / 出库质检工单 联动
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class ScheduleIdBody(BaseModel):
|
|
scheduleId: str
|
|
|
|
|
|
@router.post("/pilot-infusion-schedule/create-production-work-order")
|
|
async def api_create_outbound_production(
|
|
body: ScheduleIdBody,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
from app.crud import production_work_order as pwo_svc
|
|
|
|
wo = pwo_svc.create_outbound_production_work_order(
|
|
db,
|
|
schedule_id=body.scheduleId,
|
|
tenant_no=tenant_no,
|
|
user_id=user.get("user_id"),
|
|
create_dept_id=user.get("dept_id", ""),
|
|
)
|
|
pilot_application.mark_schedule_complete(
|
|
db, schedule_id=body.scheduleId, tenant_no=tenant_no, user_id=user.get("user_id")
|
|
)
|
|
return success_response(pwo_svc._wo_to_dict(wo), message="创建出库生产工单成功")
|
|
except ValueError as e:
|
|
return error_response(400, str(e))
|
|
except Exception as e:
|
|
db.rollback()
|
|
return error_response(400, str(e))
|
|
|
|
|
|
class OutboundQcBody(BaseModel):
|
|
scheduleId: str
|
|
cellProductId: str = ""
|
|
|
|
|
|
@router.post("/pilot-infusion-schedule/create-qc-work-order")
|
|
async def api_create_outbound_qc(
|
|
body: OutboundQcBody,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
from app.crud import qc_work_order as qc_svc
|
|
|
|
wo = qc_svc.create_outbound_qc_work_order(
|
|
db,
|
|
schedule_id=body.scheduleId,
|
|
cell_product_id=body.cellProductId,
|
|
tenant_no=tenant_no,
|
|
user_id=user.get("user_id"),
|
|
create_dept_id=user.get("dept_id", ""),
|
|
)
|
|
return success_response(qc_svc._wo_to_dict(wo), message="创建出库质检工单成功")
|
|
except ValueError as e:
|
|
return error_response(400, str(e))
|
|
except Exception as e:
|
|
db.rollback()
|
|
return error_response(400, str(e))
|