817 lines
29 KiB
Python
817 lines
29 KiB
Python
"""中试服务申请单管理 API(申请单、患者信息、输注方案、输注计划、出库联动)"""
|
|
from typing import Optional
|
|
|
|
from fastapi import APIRouter, Depends, Query
|
|
from pydantic import BaseModel, ConfigDict, Field
|
|
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):
|
|
model_config = ConfigDict(populate_by_name=True)
|
|
|
|
id: str
|
|
|
|
|
|
class PlanIdBody(BaseModel):
|
|
model_config = ConfigDict(populate_by_name=True)
|
|
|
|
plan_id: str = Field(..., alias="infusionPlanId")
|
|
|
|
|
|
class ApplicationCreateBody(BaseModel):
|
|
model_config = ConfigDict(populate_by_name=True)
|
|
|
|
channel_service_order_id: Optional[str] = Field(None, alias="channelServiceOrderId")
|
|
remark: Optional[str] = None
|
|
biz_type: Optional[str] = Field(None, alias="bizType")
|
|
|
|
|
|
class ApplicationUpdateBody(BaseModel):
|
|
model_config = ConfigDict(populate_by_name=True)
|
|
|
|
id: str
|
|
remark: Optional[str] = None
|
|
|
|
|
|
class PatientSaveBody(BaseModel):
|
|
model_config = ConfigDict(populate_by_name=True)
|
|
|
|
application_id: str = Field(..., alias="pilotApplicationId")
|
|
customer_id: Optional[str] = Field(None, alias="customerId")
|
|
patient_name: str = Field(..., alias="patientName")
|
|
sex: Optional[str] = None
|
|
age: Optional[int] = None
|
|
id_card_no: Optional[str] = Field(None, alias="idCardNo")
|
|
phone_no: Optional[str] = Field(None, alias="phoneNo")
|
|
emergency_contact: Optional[str] = Field(None, alias="emergencyContact")
|
|
emergency_phone: Optional[str] = Field(None, alias="emergencyPhone")
|
|
clinical_diagnosis: Optional[str] = Field(None, alias="clinicalDiagnosis")
|
|
diagnosis_attachments: Optional[str] = Field(None, alias="diagnosisAttachments")
|
|
need_checkup: int = Field(1, alias="needCheckup")
|
|
|
|
|
|
class InfusionPlanCreateBody(BaseModel):
|
|
model_config = ConfigDict(populate_by_name=True)
|
|
|
|
pilot_application_id: str = Field(..., alias="pilotApplicationId")
|
|
cell_type: str = Field(..., alias="cellType")
|
|
spec_text: Optional[str] = Field(None, alias="specText")
|
|
total_course_count: int = Field(..., alias="totalCourseCount")
|
|
course_interval: Optional[str] = Field(None, alias="courseInterval")
|
|
infusion_route: Optional[str] = Field(None, alias="infusionRoute")
|
|
infusion_start_date: Optional[str] = Field(None, alias="infusionStartDate")
|
|
|
|
|
|
class InfusionPlanUpdateBody(BaseModel):
|
|
model_config = ConfigDict(populate_by_name=True)
|
|
|
|
id: str
|
|
cell_type: Optional[str] = Field(None, alias="cellType")
|
|
spec_text: Optional[str] = Field(None, alias="specText")
|
|
total_course_count: Optional[int] = Field(None, alias="totalCourseCount")
|
|
course_interval: Optional[str] = Field(None, alias="courseInterval")
|
|
infusion_route: Optional[str] = Field(None, alias="infusionRoute")
|
|
infusion_start_date: Optional[str] = Field(None, alias="infusionStartDate")
|
|
|
|
|
|
class InfusionScheduleUpdateBody(BaseModel):
|
|
model_config = ConfigDict(populate_by_name=True)
|
|
|
|
id: str
|
|
infusion_time: Optional[str] = Field(None, alias="infusionTime")
|
|
remark: Optional[str] = None
|
|
attachments: Optional[str] = None
|
|
|
|
|
|
class ScheduleCreateBody(BaseModel):
|
|
model_config = ConfigDict(populate_by_name=True)
|
|
|
|
plan_id: str = Field(..., alias="infusionPlanId")
|
|
infusion_time: Optional[str] = Field(None, alias="infusionTime")
|
|
remark: Optional[str] = None
|
|
amount: Optional[float] = None
|
|
|
|
|
|
# --- 复合保存 Schema(参考采集协议单一次性保存模式)---
|
|
|
|
|
|
class PatientNestedBody(BaseModel):
|
|
model_config = ConfigDict(populate_by_name=True)
|
|
|
|
customer_id: Optional[str] = Field(None, alias="customerId")
|
|
patient_name: Optional[str] = Field(None, alias="patientName")
|
|
sex: Optional[str] = None
|
|
age: Optional[int] = None
|
|
id_card_no: Optional[str] = Field(None, alias="idCardNo")
|
|
phone_no: Optional[str] = Field(None, alias="phoneNo")
|
|
emergency_contact: Optional[str] = Field(None, alias="emergencyContact")
|
|
emergency_phone: Optional[str] = Field(None, alias="emergencyPhone")
|
|
clinical_diagnosis: Optional[str] = Field(None, alias="clinicalDiagnosis")
|
|
diagnosis_attachments: Optional[str] = Field(None, alias="diagnosisAttachments")
|
|
need_checkup: int = Field(1, alias="needCheckup")
|
|
|
|
|
|
class ScheduleProductNestedBody(BaseModel):
|
|
model_config = ConfigDict(populate_by_name=True)
|
|
|
|
id: Optional[str] = None
|
|
price_id: Optional[str] = Field(None, alias="priceId")
|
|
project_code: Optional[str] = Field(None, alias="projectCode")
|
|
project_name: Optional[str] = Field(None, alias="projectName")
|
|
cell_type_name: Optional[str] = Field(None, alias="cellTypeName")
|
|
spec_text: Optional[str] = Field(None, alias="specText")
|
|
agreement_price: Optional[float] = Field(None, alias="agreementPrice")
|
|
actual_price: Optional[float] = Field(None, alias="actualPrice")
|
|
quantity: Optional[int] = 1
|
|
status: Optional[str] = None
|
|
remark: Optional[str] = None
|
|
|
|
|
|
class InfusionScheduleNestedBody(BaseModel):
|
|
model_config = ConfigDict(populate_by_name=True)
|
|
|
|
id: Optional[str] = None
|
|
sort_no: Optional[int] = Field(None, alias="sortNo")
|
|
infusion_time: Optional[str] = Field(None, alias="infusionTime")
|
|
infusion_location: Optional[str] = Field(None, alias="infusionLocation")
|
|
infusion_method: Optional[str] = Field(None, alias="infusionMethod")
|
|
amount: Optional[float] = None
|
|
cell_products: Optional[list[ScheduleProductNestedBody]] = Field(None, alias="cellProducts")
|
|
|
|
|
|
class InfusionPlanNestedBody(BaseModel):
|
|
model_config = ConfigDict(populate_by_name=True)
|
|
|
|
id: Optional[str] = None
|
|
cell_type: Optional[str] = Field(None, alias="cellType")
|
|
spec_text: Optional[str] = Field(None, alias="specText")
|
|
total_course_count: Optional[int] = Field(None, alias="totalCourseCount")
|
|
course_interval: Optional[str] = Field(None, alias="courseInterval")
|
|
infusion_route: Optional[str] = Field(None, alias="infusionRoute")
|
|
infusion_start_date: Optional[str] = Field(None, alias="infusionStartDate")
|
|
channel_agreement_id: Optional[str] = Field(None, alias="channelAgreementId")
|
|
|
|
|
|
class ApplicationSaveBody(BaseModel):
|
|
"""一揽子保存:申请单 + 患者信息 + 输注方案 + 输注计划(含细胞产品)"""
|
|
|
|
model_config = ConfigDict(populate_by_name=True)
|
|
|
|
id: Optional[str] = None
|
|
application_name: Optional[str] = Field(None, alias="applicationName")
|
|
channel_service_order_id: Optional[str] = Field(None, alias="channelServiceOrderId")
|
|
channel_id: Optional[str] = Field(None, alias="channelId")
|
|
biz_type: Optional[str] = Field(None, alias="bizType")
|
|
remark: Optional[str] = None
|
|
consent_form_urls: Optional[str] = Field(None, alias="consentFormUrls")
|
|
consent_attachments: Optional[list] = Field(None, alias="consentAttachments")
|
|
attachment_urls: Optional[str] = Field(None, alias="attachmentUrls")
|
|
other_attachments: Optional[list] = Field(None, alias="otherAttachments")
|
|
patient: Optional[PatientNestedBody] = None
|
|
infusion_plan: Optional[InfusionPlanNestedBody] = Field(None, alias="infusionPlan")
|
|
infusion_schedules: Optional[list[InfusionScheduleNestedBody]] = Field(
|
|
None, alias="infusionSchedules"
|
|
)
|
|
infusion_plans: Optional[list[InfusionPlanNestedBody]] = Field(None, alias="infusionPlans")
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# 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"),
|
|
keyword: Optional[str] = Query(None, alias="keyword"),
|
|
channelId: Optional[str] = Query(None, alias="channelId"),
|
|
applicationStatus: Optional[str] = Query(None, alias="applicationStatus"),
|
|
channelServiceOrderId: Optional[str] = Query(None, alias="channelServiceOrderId"),
|
|
bizType: Optional[str] = Query(None, alias="bizType"),
|
|
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,
|
|
keyword=keyword,
|
|
biz_type=bizType,
|
|
)
|
|
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 or "",
|
|
"remark": body.remark,
|
|
"bizType": body.biz_type or "pilot_service",
|
|
}
|
|
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.post("/pilot-application/save")
|
|
async def api_save_application(
|
|
body: ApplicationSaveBody,
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
try:
|
|
tenant_no = _get_tenant_no(db, user)
|
|
user_id = user.get("user_id")
|
|
dept_id = user.get("region_id", "")
|
|
is_edit = bool(body.id)
|
|
|
|
biz_type = body.biz_type or "pilot_service"
|
|
app_data: dict = {
|
|
"channelServiceOrderId": body.channel_service_order_id or "",
|
|
"channelId": body.channel_id or "",
|
|
"bizType": biz_type,
|
|
"remark": body.remark,
|
|
}
|
|
if body.application_name is not None:
|
|
app_data["applicationName"] = body.application_name
|
|
if body.consent_attachments is not None:
|
|
app_data["consentAttachments"] = body.consent_attachments
|
|
elif body.consent_form_urls is not None:
|
|
app_data["consentFormUrls"] = body.consent_form_urls
|
|
if body.other_attachments is not None:
|
|
app_data["otherAttachments"] = body.other_attachments
|
|
elif body.attachment_urls is not None:
|
|
app_data["attachmentUrls"] = body.attachment_urls
|
|
|
|
if not is_edit and biz_type != "clinical_application" and not app_data["channelServiceOrderId"]:
|
|
return error_response(400, "请选择渠道服务订单")
|
|
|
|
if not is_edit and biz_type == "clinical_application" and not app_data["channelId"]:
|
|
return error_response(400, "请选择渠道")
|
|
|
|
if is_edit:
|
|
app_result = pilot_application.update_application(
|
|
db,
|
|
app_id=body.id,
|
|
data=app_data,
|
|
tenant_no=tenant_no,
|
|
)
|
|
app_id = body.id
|
|
else:
|
|
app_result = pilot_application.create_application(
|
|
db,
|
|
data=app_data,
|
|
tenant_no=tenant_no,
|
|
user_id=user_id,
|
|
dept_id=dept_id,
|
|
)
|
|
app_id = app_result.get("id")
|
|
if not app_id:
|
|
return error_response(500, "创建申请单失败,未获取到ID")
|
|
|
|
if body.patient:
|
|
pilot_application.save_patient(
|
|
db,
|
|
app_id=app_id,
|
|
data=body.patient.model_dump(by_alias=True),
|
|
tenant_no=tenant_no,
|
|
user_id=user_id,
|
|
dept_id=dept_id,
|
|
)
|
|
|
|
if body.infusion_plan is not None or body.infusion_schedules:
|
|
plan_dict = (
|
|
body.infusion_plan.model_dump(by_alias=True) if body.infusion_plan else {}
|
|
)
|
|
schedules = [
|
|
s.model_dump(by_alias=True) for s in (body.infusion_schedules or [])
|
|
]
|
|
if is_edit:
|
|
pilot_application.upsert_application_infusion(
|
|
db,
|
|
app_id=app_id,
|
|
plan_data=plan_dict,
|
|
schedules_data=schedules,
|
|
tenant_no=tenant_no,
|
|
user_id=user_id,
|
|
dept_id=dept_id,
|
|
)
|
|
else:
|
|
pilot_application.save_application_infusion(
|
|
db,
|
|
app_id=app_id,
|
|
plan_data=plan_dict,
|
|
schedules_data=schedules,
|
|
tenant_no=tenant_no,
|
|
user_id=user_id,
|
|
dept_id=dept_id,
|
|
replace_existing=False,
|
|
)
|
|
elif body.infusion_plans:
|
|
for plan_data in body.infusion_plans:
|
|
plan_result = pilot_application.create_infusion_plan(
|
|
db,
|
|
app_id=app_id,
|
|
data=plan_data.model_dump(by_alias=True),
|
|
tenant_no=tenant_no,
|
|
user_id=user_id,
|
|
dept_id=dept_id,
|
|
)
|
|
plan_id = plan_result.get("id")
|
|
if plan_id and (plan_data.total_course_count or 0) > 0:
|
|
pilot_application.auto_generate_schedules(
|
|
db,
|
|
plan_id=plan_id,
|
|
tenant_no=tenant_no,
|
|
user_id=user_id,
|
|
dept_id=dept_id,
|
|
)
|
|
|
|
app_result = pilot_application.get_application(db, app_id=app_id, tenant_no=tenant_no)
|
|
|
|
return success_response(app_result, message="保存成功")
|
|
except ValueError as e:
|
|
return error_response(400, str(e))
|
|
except Exception as e:
|
|
return error_response(500, 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(..., alias="pilotApplicationId"),
|
|
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(..., alias="pilotApplicationId"),
|
|
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.get("/pilot-infusion-schedule/list")
|
|
async def api_list_schedules(
|
|
plan_id: str = Query(..., alias="infusionPlanId"),
|
|
user: dict = Depends(require_admin_or_super_admin),
|
|
db: Session = Depends(get_db),
|
|
):
|
|
tenant_no = _get_tenant_no(db, user)
|
|
result = pilot_application.list_schedules_by_plan(
|
|
db, plan_id=plan_id, tenant_no=tenant_no
|
|
)
|
|
return success_response(result)
|
|
|
|
|
|
@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,
|
|
"amount": body.amount,
|
|
}
|
|
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
|
|
|
|
from app.crud.qc_work_order import resolve_outbound_biz_type_for_schedule
|
|
|
|
outbound_biz_type = resolve_outbound_biz_type_for_schedule(
|
|
db, body.scheduleId, tenant_no
|
|
)
|
|
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", ""),
|
|
biz_type=outbound_biz_type,
|
|
)
|
|
db.commit()
|
|
db.refresh(wo)
|
|
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
|
|
|
|
from app.crud.qc_work_order import resolve_outbound_biz_type_for_schedule
|
|
|
|
outbound_biz_type = resolve_outbound_biz_type_for_schedule(
|
|
db, body.scheduleId, tenant_no
|
|
)
|
|
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", ""),
|
|
biz_type=outbound_biz_type,
|
|
)
|
|
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))
|