957 lines
31 KiB
Python
957 lines
31 KiB
Python
"""中试申请单-体检 CRUD(体检信息、预约项目、实际项目)"""
|
|
from __future__ import annotations
|
|
|
|
import uuid
|
|
from datetime import datetime
|
|
from typing import Any, Dict, List, Optional
|
|
|
|
from sqlalchemy import func, or_
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.models.models import (
|
|
BizCheckupInstitution,
|
|
BizPilotApplication,
|
|
BizPilotCheckup,
|
|
BizPilotCheckupActualItem,
|
|
BizPilotCheckupReserveItem,
|
|
BizPilotPatient,
|
|
)
|
|
|
|
|
|
# ────────────────────────────────────────────
|
|
# Helpers
|
|
# ────────────────────────────────────────────
|
|
|
|
|
|
def _parse_optional_datetime(val: Any) -> Optional[datetime]:
|
|
if val is None or val == "":
|
|
return None
|
|
if isinstance(val, datetime):
|
|
return val
|
|
if isinstance(val, str):
|
|
text = val.strip()
|
|
for fmt in ("%Y-%m-%d %H:%M:%S", "%Y-%m-%d %H:%M"):
|
|
try:
|
|
return datetime.strptime(text, fmt)
|
|
except ValueError:
|
|
continue
|
|
try:
|
|
return datetime.fromisoformat(text.replace("Z", "+00:00"))
|
|
except ValueError:
|
|
return None
|
|
return None
|
|
|
|
|
|
# ────────────────────────────────────────────
|
|
# Helpers: _row_to_dict
|
|
# ────────────────────────────────────────────
|
|
|
|
|
|
def _generate_checkup_no(db: Session, tenant_no: str) -> str:
|
|
today_str = datetime.now().strftime("%Y%m%d")
|
|
prefix = f"ZSTJ{today_str}"
|
|
existing = (
|
|
db.query(BizPilotCheckup.checkup_status)
|
|
.filter(
|
|
BizPilotCheckup.tenant_no == tenant_no,
|
|
BizPilotCheckup.id.like(f"{prefix}%"),
|
|
BizPilotCheckup.del_flag == 0,
|
|
)
|
|
.order_by(BizPilotCheckup.create_time.desc())
|
|
.first()
|
|
)
|
|
seq = 1
|
|
if existing:
|
|
seq = 1
|
|
return f"{prefix}{seq:04d}"
|
|
|
|
|
|
def _row_to_dict_checkup(row, db=None, tenant_no=None) -> Dict[str, Any]:
|
|
d: Dict[str, Any] = {
|
|
"id": row.id,
|
|
"pilotApplicationId": row.pilot_application_id or "",
|
|
"pilotPatientId": row.pilot_patient_id or "",
|
|
"checkupInstitutionId": row.checkup_institution_id or "",
|
|
"reserveTime": row.reserve_time.strftime("%Y-%m-%d %H:%M:%S") if row.reserve_time else "",
|
|
"reserveFee": float(row.reserve_fee) if row.reserve_fee is not None else None,
|
|
"actualCheckupTime": row.actual_checkup_time.strftime("%Y-%m-%d %H:%M:%S") if row.actual_checkup_time else "",
|
|
"actualCheckupFee": float(row.actual_checkup_fee) if row.actual_checkup_fee is not None else None,
|
|
"feeSettled": row.fee_settled if row.fee_settled is not None else 0,
|
|
"checkupStatus": row.checkup_status or "",
|
|
"feeStatus": row.fee_status or "",
|
|
"checkupRemark": row.checkup_remark or "",
|
|
"reportAttachments": row.report_attachments or "",
|
|
"tenantNo": row.tenant_no or "",
|
|
"remark": row.remark or "",
|
|
"createBy": row.create_by or "",
|
|
"createTime": row.create_time.strftime("%Y-%m-%d %H:%M:%S") if row.create_time else "",
|
|
"updateTime": row.update_time.strftime("%Y-%m-%d %H:%M:%S") if row.update_time else "",
|
|
}
|
|
|
|
if db and tenant_no:
|
|
# institutionName — lookup from BizCheckupInstitution
|
|
if row.checkup_institution_id:
|
|
inst = (
|
|
db.query(BizCheckupInstitution.institution_name)
|
|
.filter(
|
|
BizCheckupInstitution.id == row.checkup_institution_id,
|
|
BizCheckupInstitution.del_flag == 0,
|
|
)
|
|
.first()
|
|
)
|
|
d["institutionName"] = inst.institution_name if inst else ""
|
|
else:
|
|
d["institutionName"] = ""
|
|
|
|
# patientName / sex / age / phoneNo — from BizPilotPatient
|
|
if row.pilot_patient_id:
|
|
patient = (
|
|
db.query(BizPilotPatient)
|
|
.filter(
|
|
BizPilotPatient.id == row.pilot_patient_id,
|
|
BizPilotPatient.del_flag == 0,
|
|
)
|
|
.first()
|
|
)
|
|
if patient:
|
|
d["patientName"] = patient.patient_name or ""
|
|
d["sex"] = patient.sex or ""
|
|
d["age"] = patient.age
|
|
d["phoneNo"] = patient.phone_no or ""
|
|
else:
|
|
d["patientName"] = ""
|
|
d["sex"] = ""
|
|
d["age"] = None
|
|
d["phoneNo"] = ""
|
|
else:
|
|
d["patientName"] = ""
|
|
d["sex"] = ""
|
|
d["age"] = None
|
|
d["phoneNo"] = ""
|
|
|
|
# applicationNo / channelName — from BizPilotApplication
|
|
if row.pilot_application_id:
|
|
app = (
|
|
db.query(BizPilotApplication)
|
|
.filter(
|
|
BizPilotApplication.id == row.pilot_application_id,
|
|
BizPilotApplication.del_flag == 0,
|
|
)
|
|
.first()
|
|
)
|
|
if app:
|
|
d["applicationNo"] = app.application_no or ""
|
|
d["channelName"] = app.channel_name or ""
|
|
else:
|
|
d["applicationNo"] = ""
|
|
d["channelName"] = ""
|
|
else:
|
|
d["applicationNo"] = ""
|
|
d["channelName"] = ""
|
|
|
|
# reserveItemCount
|
|
reserve_count = (
|
|
db.query(func.count(BizPilotCheckupReserveItem.id))
|
|
.filter(
|
|
BizPilotCheckupReserveItem.pilot_checkup_id == row.id,
|
|
BizPilotCheckupReserveItem.tenant_no == tenant_no,
|
|
BizPilotCheckupReserveItem.del_flag == 0,
|
|
)
|
|
.scalar()
|
|
) or 0
|
|
d["reserveItemCount"] = reserve_count
|
|
|
|
# actualItemCount
|
|
actual_count = (
|
|
db.query(func.count(BizPilotCheckupActualItem.id))
|
|
.filter(
|
|
BizPilotCheckupActualItem.pilot_checkup_id == row.id,
|
|
BizPilotCheckupActualItem.tenant_no == tenant_no,
|
|
BizPilotCheckupActualItem.del_flag == 0,
|
|
)
|
|
.scalar()
|
|
) or 0
|
|
d["actualItemCount"] = actual_count
|
|
|
|
return d
|
|
|
|
|
|
def _row_to_dict_reserve_item(row) -> Dict[str, Any]:
|
|
return {
|
|
"id": row.id,
|
|
"pilotCheckupId": row.pilot_checkup_id or "",
|
|
"projectName": row.project_name or "",
|
|
"projectFee": float(row.project_fee) if row.project_fee is not None else None,
|
|
"orderNum": row.order_num if row.order_num is not None else 0,
|
|
"remark": row.remark or "",
|
|
"createTime": row.create_time.strftime("%Y-%m-%d %H:%M:%S") if row.create_time else "",
|
|
"updateTime": row.update_time.strftime("%Y-%m-%d %H:%M:%S") if row.update_time else "",
|
|
}
|
|
|
|
|
|
def _row_to_dict_actual_item(row) -> Dict[str, Any]:
|
|
return {
|
|
"id": row.id,
|
|
"pilotCheckupId": row.pilot_checkup_id or "",
|
|
"projectName": row.project_name or "",
|
|
"projectFee": float(row.project_fee) if row.project_fee is not None else None,
|
|
"orderNum": row.order_num if row.order_num is not None else 0,
|
|
"remark": row.remark or "",
|
|
"createTime": row.create_time.strftime("%Y-%m-%d %H:%M:%S") if row.create_time else "",
|
|
"updateTime": row.update_time.strftime("%Y-%m-%d %H:%M:%S") if row.update_time else "",
|
|
}
|
|
|
|
|
|
# ────────────────────────────────────────────
|
|
# Checkup CRUD
|
|
# ────────────────────────────────────────────
|
|
|
|
|
|
def get_checkup_by_application(
|
|
db: Session, application_id: str, tenant_no: str
|
|
) -> Optional[Dict[str, Any]]:
|
|
row = (
|
|
db.query(BizPilotCheckup)
|
|
.filter(
|
|
BizPilotCheckup.pilot_application_id == application_id,
|
|
BizPilotCheckup.tenant_no == tenant_no,
|
|
BizPilotCheckup.del_flag == 0,
|
|
)
|
|
.first()
|
|
)
|
|
if not row:
|
|
return None
|
|
return _row_to_dict_checkup(row, db, tenant_no)
|
|
|
|
|
|
def get_checkup_by_id(
|
|
db: Session, checkup_id: str, tenant_no: str
|
|
) -> Optional[Dict[str, Any]]:
|
|
row = (
|
|
db.query(BizPilotCheckup)
|
|
.filter(
|
|
BizPilotCheckup.id == checkup_id,
|
|
BizPilotCheckup.tenant_no == tenant_no,
|
|
BizPilotCheckup.del_flag == 0,
|
|
)
|
|
.first()
|
|
)
|
|
if not row:
|
|
return None
|
|
return _row_to_dict_checkup(row, db, tenant_no)
|
|
|
|
|
|
def create_checkup(
|
|
db: Session,
|
|
application_id: str,
|
|
data: dict,
|
|
tenant_no: str,
|
|
user_id: str,
|
|
) -> Dict[str, Any]:
|
|
now = datetime.now()
|
|
|
|
row = BizPilotCheckup(
|
|
id=uuid.uuid4().hex,
|
|
pilot_application_id=application_id,
|
|
pilot_patient_id=data.get("pilotPatientId") or None,
|
|
checkup_institution_id=data.get("checkupInstitutionId") or "",
|
|
reserve_time=_parse_optional_datetime(data.get("reserveTime")),
|
|
reserve_fee=data.get("reserveFee") if data.get("reserveFee") is not None else None,
|
|
actual_checkup_time=data.get("actualCheckupTime") or None,
|
|
actual_checkup_fee=data.get("actualCheckupFee") if data.get("actualCheckupFee") is not None else None,
|
|
fee_settled=0,
|
|
checkup_status="dtj",
|
|
fee_status="wjs",
|
|
checkup_remark=data.get("checkupRemark") or "",
|
|
report_attachments=data.get("reportAttachments") or "",
|
|
tenant_no=tenant_no,
|
|
order_num=0,
|
|
remark=data.get("remark") or "",
|
|
create_by=user_id,
|
|
create_dept_id="",
|
|
create_time=now,
|
|
update_by=user_id,
|
|
update_time=now,
|
|
del_flag=0,
|
|
)
|
|
db.add(row)
|
|
db.commit()
|
|
db.refresh(row)
|
|
return _row_to_dict_checkup(row, db, tenant_no)
|
|
|
|
|
|
def update_checkup(
|
|
db: Session, checkup_id: str, data: dict, tenant_no: str
|
|
) -> Dict[str, Any]:
|
|
row = (
|
|
db.query(BizPilotCheckup)
|
|
.filter(
|
|
BizPilotCheckup.id == checkup_id,
|
|
BizPilotCheckup.tenant_no == tenant_no,
|
|
BizPilotCheckup.del_flag == 0,
|
|
)
|
|
.first()
|
|
)
|
|
if not row:
|
|
raise ValueError("体检信息不存在")
|
|
|
|
fields = {
|
|
"checkupInstitutionId": "checkup_institution_id",
|
|
"reserveTime": "reserve_time",
|
|
"reserveFee": "reserve_fee",
|
|
"actualCheckupTime": "actual_checkup_time",
|
|
"actualCheckupFee": "actual_checkup_fee",
|
|
"checkupRemark": "checkup_remark",
|
|
"reportAttachments": "report_attachments",
|
|
"remark": "remark",
|
|
}
|
|
for camel, snake in fields.items():
|
|
if camel in data and data[camel] is not None:
|
|
val = data[camel]
|
|
if snake in ("reserve_time", "actual_checkup_time"):
|
|
val = _parse_optional_datetime(val)
|
|
setattr(row, snake, val)
|
|
|
|
row.update_time = datetime.now()
|
|
db.commit()
|
|
db.refresh(row)
|
|
return _row_to_dict_checkup(row, db, tenant_no)
|
|
|
|
|
|
def soft_delete_checkup(db: Session, checkup_id: str, tenant_no: str) -> None:
|
|
now = datetime.now()
|
|
row = (
|
|
db.query(BizPilotCheckup)
|
|
.filter(
|
|
BizPilotCheckup.id == checkup_id,
|
|
BizPilotCheckup.tenant_no == tenant_no,
|
|
BizPilotCheckup.del_flag == 0,
|
|
)
|
|
.first()
|
|
)
|
|
if not row:
|
|
raise ValueError("体检信息不存在")
|
|
|
|
row.del_flag = 1
|
|
row.update_time = now
|
|
|
|
# Cascade soft-delete to reserve items
|
|
db.query(BizPilotCheckupReserveItem).filter(
|
|
BizPilotCheckupReserveItem.pilot_checkup_id == checkup_id,
|
|
BizPilotCheckupReserveItem.tenant_no == tenant_no,
|
|
BizPilotCheckupReserveItem.del_flag == 0,
|
|
).update({"del_flag": 1, "update_time": now}, synchronize_session=False)
|
|
|
|
# Cascade soft-delete to actual items
|
|
db.query(BizPilotCheckupActualItem).filter(
|
|
BizPilotCheckupActualItem.pilot_checkup_id == checkup_id,
|
|
BizPilotCheckupActualItem.tenant_no == tenant_no,
|
|
BizPilotCheckupActualItem.del_flag == 0,
|
|
).update({"del_flag": 1, "update_time": now}, synchronize_session=False)
|
|
|
|
db.commit()
|
|
|
|
|
|
def mark_checkup_checked(
|
|
db: Session, checkup_id: str, tenant_no: str, user_id: str
|
|
) -> Dict[str, Any]:
|
|
row = (
|
|
db.query(BizPilotCheckup)
|
|
.filter(
|
|
BizPilotCheckup.id == checkup_id,
|
|
BizPilotCheckup.tenant_no == tenant_no,
|
|
BizPilotCheckup.del_flag == 0,
|
|
)
|
|
.first()
|
|
)
|
|
if not row:
|
|
raise ValueError("体检信息不存在")
|
|
if row.checkup_status != "dtj":
|
|
raise ValueError("当前状态不允许标记已体检")
|
|
|
|
row.checkup_status = "ytj"
|
|
if not row.actual_checkup_time:
|
|
row.actual_checkup_time = datetime.now()
|
|
row.update_by = user_id
|
|
row.update_time = datetime.now()
|
|
db.commit()
|
|
db.refresh(row)
|
|
return _row_to_dict_checkup(row, db, tenant_no)
|
|
|
|
|
|
def settle_checkup_fee(
|
|
db: Session, checkup_id: str, tenant_no: str, user_id: str
|
|
) -> Dict[str, Any]:
|
|
row = (
|
|
db.query(BizPilotCheckup)
|
|
.filter(
|
|
BizPilotCheckup.id == checkup_id,
|
|
BizPilotCheckup.tenant_no == tenant_no,
|
|
BizPilotCheckup.del_flag == 0,
|
|
)
|
|
.first()
|
|
)
|
|
if not row:
|
|
raise ValueError("体检信息不存在")
|
|
if row.fee_status != "wjs":
|
|
raise ValueError("当前状态不允许结算")
|
|
|
|
row.fee_status = "yjs"
|
|
row.fee_settled = 1
|
|
row.update_by = user_id
|
|
row.update_time = datetime.now()
|
|
db.commit()
|
|
db.refresh(row)
|
|
return _row_to_dict_checkup(row, db, tenant_no)
|
|
|
|
|
|
# ────────────────────────────────────────────
|
|
# Reserve Items CRUD
|
|
# ────────────────────────────────────────────
|
|
|
|
|
|
def list_reserve_items(
|
|
db: Session, checkup_id: str, tenant_no: str
|
|
) -> List[Dict[str, Any]]:
|
|
rows = (
|
|
db.query(BizPilotCheckupReserveItem)
|
|
.filter(
|
|
BizPilotCheckupReserveItem.pilot_checkup_id == checkup_id,
|
|
BizPilotCheckupReserveItem.tenant_no == tenant_no,
|
|
BizPilotCheckupReserveItem.del_flag == 0,
|
|
)
|
|
.order_by(
|
|
BizPilotCheckupReserveItem.order_num.asc(),
|
|
BizPilotCheckupReserveItem.create_time.asc(),
|
|
)
|
|
.all()
|
|
)
|
|
return [_row_to_dict_reserve_item(r) for r in rows]
|
|
|
|
|
|
def save_reserve_items(
|
|
db: Session,
|
|
checkup_id: str,
|
|
items_json: list,
|
|
tenant_no: str,
|
|
user_id: str,
|
|
) -> List[Dict[str, Any]]:
|
|
now = datetime.now()
|
|
|
|
# Soft-delete existing items
|
|
db.query(BizPilotCheckupReserveItem).filter(
|
|
BizPilotCheckupReserveItem.pilot_checkup_id == checkup_id,
|
|
BizPilotCheckupReserveItem.tenant_no == tenant_no,
|
|
BizPilotCheckupReserveItem.del_flag == 0,
|
|
).update({"del_flag": 1, "update_time": now}, synchronize_session=False)
|
|
|
|
# Insert new items
|
|
for idx, item in enumerate(items_json):
|
|
row = BizPilotCheckupReserveItem(
|
|
id=uuid.uuid4().hex,
|
|
pilot_checkup_id=checkup_id,
|
|
project_name=item.get("projectName") or item.get("project_name") or "",
|
|
project_fee=item.get("projectFee") if item.get("projectFee") is not None else (
|
|
item.get("project_fee") if item.get("project_fee") is not None else None
|
|
),
|
|
tenant_no=tenant_no,
|
|
order_num=idx + 1,
|
|
remark=item.get("remark") or "",
|
|
create_by=user_id,
|
|
create_dept_id="",
|
|
create_time=now,
|
|
update_by=user_id,
|
|
update_time=now,
|
|
del_flag=0,
|
|
)
|
|
db.add(row)
|
|
|
|
db.commit()
|
|
return list_reserve_items(db, checkup_id, tenant_no)
|
|
|
|
|
|
def delete_reserve_item(db: Session, item_id: str, tenant_no: str) -> None:
|
|
row = (
|
|
db.query(BizPilotCheckupReserveItem)
|
|
.filter(
|
|
BizPilotCheckupReserveItem.id == item_id,
|
|
BizPilotCheckupReserveItem.tenant_no == tenant_no,
|
|
BizPilotCheckupReserveItem.del_flag == 0,
|
|
)
|
|
.first()
|
|
)
|
|
if not row:
|
|
raise ValueError("预约项目不存在")
|
|
|
|
row.del_flag = 1
|
|
row.update_time = datetime.now()
|
|
db.commit()
|
|
|
|
|
|
# ────────────────────────────────────────────
|
|
# Actual Items CRUD
|
|
# ────────────────────────────────────────────
|
|
|
|
|
|
def list_actual_items(
|
|
db: Session, checkup_id: str, tenant_no: str
|
|
) -> List[Dict[str, Any]]:
|
|
rows = (
|
|
db.query(BizPilotCheckupActualItem)
|
|
.filter(
|
|
BizPilotCheckupActualItem.pilot_checkup_id == checkup_id,
|
|
BizPilotCheckupActualItem.tenant_no == tenant_no,
|
|
BizPilotCheckupActualItem.del_flag == 0,
|
|
)
|
|
.order_by(
|
|
BizPilotCheckupActualItem.order_num.asc(),
|
|
BizPilotCheckupActualItem.create_time.asc(),
|
|
)
|
|
.all()
|
|
)
|
|
return [_row_to_dict_actual_item(r) for r in rows]
|
|
|
|
|
|
def save_actual_items(
|
|
db: Session,
|
|
checkup_id: str,
|
|
items_json: list,
|
|
tenant_no: str,
|
|
user_id: str,
|
|
) -> List[Dict[str, Any]]:
|
|
now = datetime.now()
|
|
|
|
# Soft-delete existing items
|
|
db.query(BizPilotCheckupActualItem).filter(
|
|
BizPilotCheckupActualItem.pilot_checkup_id == checkup_id,
|
|
BizPilotCheckupActualItem.tenant_no == tenant_no,
|
|
BizPilotCheckupActualItem.del_flag == 0,
|
|
).update({"del_flag": 1, "update_time": now}, synchronize_session=False)
|
|
|
|
# Insert new items
|
|
for idx, item in enumerate(items_json):
|
|
row = BizPilotCheckupActualItem(
|
|
id=uuid.uuid4().hex,
|
|
pilot_checkup_id=checkup_id,
|
|
project_name=item.get("projectName") or item.get("project_name") or "",
|
|
project_fee=item.get("projectFee") if item.get("projectFee") is not None else (
|
|
item.get("project_fee") if item.get("project_fee") is not None else None
|
|
),
|
|
tenant_no=tenant_no,
|
|
order_num=idx + 1,
|
|
remark=item.get("remark") or "",
|
|
create_by=user_id,
|
|
create_dept_id="",
|
|
create_time=now,
|
|
update_by=user_id,
|
|
update_time=now,
|
|
del_flag=0,
|
|
)
|
|
db.add(row)
|
|
|
|
db.commit()
|
|
return list_actual_items(db, checkup_id, tenant_no)
|
|
|
|
|
|
def delete_actual_item(db: Session, item_id: str, tenant_no: str) -> None:
|
|
row = (
|
|
db.query(BizPilotCheckupActualItem)
|
|
.filter(
|
|
BizPilotCheckupActualItem.id == item_id,
|
|
BizPilotCheckupActualItem.tenant_no == tenant_no,
|
|
BizPilotCheckupActualItem.del_flag == 0,
|
|
)
|
|
.first()
|
|
)
|
|
if not row:
|
|
raise ValueError("实际项目不存在")
|
|
|
|
row.del_flag = 1
|
|
row.update_time = datetime.now()
|
|
db.commit()
|
|
|
|
|
|
# ────────────────────────────────────────────
|
|
# Checkup List (Paginated)
|
|
# ────────────────────────────────────────────
|
|
|
|
|
|
def list_checkups_paginated(
|
|
db: Session,
|
|
tenant_no: str,
|
|
page: int = 1,
|
|
page_size: int = 10,
|
|
checkup_status: Optional[str] = None,
|
|
fee_status: Optional[str] = None,
|
|
checkup_institution_id: Optional[str] = None,
|
|
keyword: Optional[str] = None,
|
|
application_no: Optional[str] = None,
|
|
patient_name: Optional[str] = None,
|
|
channel_id: Optional[str] = None,
|
|
biz_type: Optional[str] = None,
|
|
) -> Dict[str, Any]:
|
|
q = db.query(BizPilotCheckup).filter(
|
|
BizPilotCheckup.tenant_no == tenant_no,
|
|
BizPilotCheckup.del_flag == 0,
|
|
)
|
|
|
|
if biz_type:
|
|
app_subq = (
|
|
db.query(BizPilotApplication.id)
|
|
.filter(
|
|
BizPilotApplication.biz_type == biz_type,
|
|
BizPilotApplication.del_flag == 0,
|
|
)
|
|
.subquery()
|
|
)
|
|
q = q.filter(BizPilotCheckup.pilot_application_id.in_(app_subq))
|
|
|
|
if checkup_status:
|
|
statuses = [s.strip() for s in checkup_status.split(",") if s.strip()]
|
|
if statuses:
|
|
q = q.filter(BizPilotCheckup.checkup_status.in_(statuses))
|
|
|
|
if fee_status:
|
|
statuses = [s.strip() for s in fee_status.split(",") if s.strip()]
|
|
if statuses:
|
|
q = q.filter(BizPilotCheckup.fee_status.in_(statuses))
|
|
|
|
if checkup_institution_id:
|
|
q = q.filter(BizPilotCheckup.checkup_institution_id == checkup_institution_id)
|
|
|
|
# keyword: fuzzy search across application_no, patient_name, channel_name
|
|
if keyword:
|
|
kw = f"%{keyword}%"
|
|
app_ids_by_no = (
|
|
db.query(BizPilotApplication.id)
|
|
.filter(
|
|
BizPilotApplication.application_no.like(kw),
|
|
BizPilotApplication.del_flag == 0,
|
|
)
|
|
.subquery()
|
|
)
|
|
app_ids_by_channel = (
|
|
db.query(BizPilotApplication.id)
|
|
.filter(
|
|
BizPilotApplication.channel_name.like(kw),
|
|
BizPilotApplication.del_flag == 0,
|
|
)
|
|
.subquery()
|
|
)
|
|
patient_ids_by_name = (
|
|
db.query(BizPilotPatient.id)
|
|
.filter(
|
|
BizPilotPatient.patient_name.like(kw),
|
|
BizPilotPatient.del_flag == 0,
|
|
)
|
|
.subquery()
|
|
)
|
|
q = q.filter(
|
|
or_(
|
|
BizPilotCheckup.pilot_application_id.in_(app_ids_by_no),
|
|
BizPilotCheckup.pilot_application_id.in_(app_ids_by_channel),
|
|
BizPilotCheckup.pilot_patient_id.in_(patient_ids_by_name),
|
|
)
|
|
)
|
|
|
|
if application_no:
|
|
app_subq = (
|
|
db.query(BizPilotApplication.id)
|
|
.filter(
|
|
BizPilotApplication.application_no.like(f"%{application_no}%"),
|
|
BizPilotApplication.del_flag == 0,
|
|
)
|
|
.subquery()
|
|
)
|
|
q = q.filter(BizPilotCheckup.pilot_application_id.in_(app_subq))
|
|
|
|
if patient_name:
|
|
patient_subq = (
|
|
db.query(BizPilotPatient.id)
|
|
.filter(
|
|
BizPilotPatient.patient_name.like(f"%{patient_name}%"),
|
|
BizPilotPatient.del_flag == 0,
|
|
)
|
|
.subquery()
|
|
)
|
|
q = q.filter(BizPilotCheckup.pilot_patient_id.in_(patient_subq))
|
|
|
|
if channel_id:
|
|
app_subq = (
|
|
db.query(BizPilotApplication.id)
|
|
.filter(
|
|
BizPilotApplication.channel_id == channel_id,
|
|
BizPilotApplication.del_flag == 0,
|
|
)
|
|
.subquery()
|
|
)
|
|
q = q.filter(BizPilotCheckup.pilot_application_id.in_(app_subq))
|
|
|
|
total = q.order_by(None).with_entities(func.count(BizPilotCheckup.id)).scalar() or 0
|
|
page = max(1, page)
|
|
page_size = min(max(1, page_size), 100)
|
|
rows = (
|
|
q.order_by(BizPilotCheckup.create_time.desc())
|
|
.offset((page - 1) * page_size)
|
|
.limit(page_size)
|
|
.all()
|
|
)
|
|
items = [_row_to_dict_checkup(r, db, tenant_no) for r in rows]
|
|
return {
|
|
"list": items,
|
|
"pagination": {"page": page, "pageSize": page_size, "total": total},
|
|
}
|
|
|
|
|
|
def list_pending_patients(
|
|
db: Session,
|
|
tenant_no: str,
|
|
page: int = 1,
|
|
page_size: int = 10,
|
|
application_no: Optional[str] = None,
|
|
patient_name: Optional[str] = None,
|
|
channel_id: Optional[str] = None,
|
|
) -> Dict[str, Any]:
|
|
"""查询 need_checkup=1 但尚未有 biz_pilot_checkup 记录的患者"""
|
|
checked_patient_ids = (
|
|
db.query(BizPilotCheckup.pilot_patient_id)
|
|
.filter(
|
|
BizPilotCheckup.tenant_no == tenant_no,
|
|
BizPilotCheckup.del_flag == 0,
|
|
BizPilotCheckup.pilot_patient_id.isnot(None),
|
|
BizPilotCheckup.pilot_patient_id != "",
|
|
)
|
|
.subquery()
|
|
)
|
|
|
|
q = db.query(BizPilotPatient).filter(
|
|
BizPilotPatient.need_checkup == 1,
|
|
BizPilotPatient.tenant_no == tenant_no,
|
|
BizPilotPatient.del_flag == 0,
|
|
~BizPilotPatient.id.in_(checked_patient_ids),
|
|
)
|
|
|
|
if patient_name:
|
|
q = q.filter(BizPilotPatient.patient_name.like(f"%{patient_name}%"))
|
|
|
|
if application_no or channel_id:
|
|
app_q = db.query(BizPilotApplication.id).filter(
|
|
BizPilotApplication.tenant_no == tenant_no,
|
|
BizPilotApplication.del_flag == 0,
|
|
)
|
|
if application_no:
|
|
app_q = app_q.filter(
|
|
BizPilotApplication.application_no.like(f"%{application_no}%")
|
|
)
|
|
if channel_id:
|
|
app_q = app_q.filter(BizPilotApplication.channel_id == channel_id)
|
|
app_subq = app_q.subquery()
|
|
q = q.filter(BizPilotPatient.pilot_application_id.in_(app_subq))
|
|
|
|
total = q.order_by(None).with_entities(func.count(BizPilotPatient.id)).scalar() or 0
|
|
page = max(1, page)
|
|
page_size = min(max(1, page_size), 100)
|
|
rows = (
|
|
q.order_by(BizPilotPatient.create_time.desc())
|
|
.offset((page - 1) * page_size)
|
|
.limit(page_size)
|
|
.all()
|
|
)
|
|
|
|
items = []
|
|
for r in rows:
|
|
d = {
|
|
"id": r.id,
|
|
"pilotApplicationId": r.pilot_application_id or "",
|
|
"patientName": r.patient_name or "",
|
|
"sex": r.sex or "",
|
|
"age": r.age,
|
|
"phoneNo": r.phone_no or "",
|
|
}
|
|
app = (
|
|
db.query(BizPilotApplication)
|
|
.filter(
|
|
BizPilotApplication.id == r.pilot_application_id,
|
|
BizPilotApplication.del_flag == 0,
|
|
)
|
|
.first()
|
|
)
|
|
if app:
|
|
d["applicationNo"] = app.application_no or ""
|
|
d["channelName"] = app.channel_name or ""
|
|
d["channelId"] = app.channel_id or ""
|
|
else:
|
|
d["applicationNo"] = ""
|
|
d["channelName"] = ""
|
|
d["channelId"] = ""
|
|
items.append(d)
|
|
|
|
return {
|
|
"list": items,
|
|
"pagination": {"page": page, "pageSize": page_size, "total": total},
|
|
}
|
|
|
|
|
|
def batch_create_checkups(
|
|
db: Session,
|
|
patient_ids: list,
|
|
checkup_institution_id: str,
|
|
reserve_time: Optional[str],
|
|
reserve_items: list,
|
|
tenant_no: str,
|
|
user_id: str,
|
|
) -> list:
|
|
"""为多个患者批量创建体检记录 + 预约项目"""
|
|
results = []
|
|
now = datetime.now()
|
|
|
|
for patient_id in patient_ids:
|
|
patient = (
|
|
db.query(BizPilotPatient)
|
|
.filter(
|
|
BizPilotPatient.id == patient_id,
|
|
BizPilotPatient.tenant_no == tenant_no,
|
|
BizPilotPatient.del_flag == 0,
|
|
)
|
|
.first()
|
|
)
|
|
if not patient:
|
|
continue
|
|
|
|
checkup_row = BizPilotCheckup(
|
|
id=uuid.uuid4().hex,
|
|
pilot_application_id=patient.pilot_application_id,
|
|
pilot_patient_id=patient_id,
|
|
checkup_institution_id=checkup_institution_id or "",
|
|
reserve_time=_parse_optional_datetime(reserve_time),
|
|
reserve_fee=sum(
|
|
float(item.get("projectFee") or 0) for item in reserve_items
|
|
) if reserve_items else None,
|
|
actual_checkup_time=None,
|
|
actual_checkup_fee=None,
|
|
fee_settled=0,
|
|
checkup_status="dtj",
|
|
fee_status="wjs",
|
|
checkup_remark="",
|
|
report_attachments="",
|
|
tenant_no=tenant_no,
|
|
order_num=0,
|
|
remark="",
|
|
create_by=user_id,
|
|
create_dept_id="",
|
|
create_time=now,
|
|
update_by=user_id,
|
|
update_time=now,
|
|
del_flag=0,
|
|
)
|
|
db.add(checkup_row)
|
|
db.flush()
|
|
|
|
for idx, item in enumerate(reserve_items):
|
|
ri = BizPilotCheckupReserveItem(
|
|
id=uuid.uuid4().hex,
|
|
pilot_checkup_id=checkup_row.id,
|
|
project_name=item.get("projectName") or item.get("project_name") or "",
|
|
project_fee=item.get("projectFee") if item.get("projectFee") is not None else (
|
|
item.get("project_fee") if item.get("project_fee") is not None else None
|
|
),
|
|
tenant_no=tenant_no,
|
|
order_num=idx + 1,
|
|
remark="",
|
|
create_by=user_id,
|
|
create_dept_id="",
|
|
create_time=now,
|
|
update_by=user_id,
|
|
update_time=now,
|
|
del_flag=0,
|
|
)
|
|
db.add(ri)
|
|
|
|
results.append(_row_to_dict_checkup(checkup_row, db, tenant_no))
|
|
|
|
db.commit()
|
|
return results
|
|
|
|
|
|
def ensure_checkup_for_patient(
|
|
db: Session,
|
|
patient_id: str,
|
|
application_id: str,
|
|
tenant_no: str,
|
|
user_id: str,
|
|
) -> Optional[str]:
|
|
"""为患者创建体检记录(如不存在)。返回 checkup_id 或 None。"""
|
|
existing = (
|
|
db.query(BizPilotCheckup)
|
|
.filter(
|
|
BizPilotCheckup.pilot_patient_id == patient_id,
|
|
BizPilotCheckup.tenant_no == tenant_no,
|
|
BizPilotCheckup.del_flag == 0,
|
|
)
|
|
.first()
|
|
)
|
|
if existing:
|
|
return existing.id
|
|
|
|
now = datetime.now()
|
|
row = BizPilotCheckup(
|
|
id=uuid.uuid4().hex,
|
|
pilot_application_id=application_id,
|
|
pilot_patient_id=patient_id,
|
|
checkup_institution_id="",
|
|
checkup_status="dtj",
|
|
fee_status="wjs",
|
|
fee_settled=0,
|
|
checkup_remark="",
|
|
report_attachments="",
|
|
tenant_no=tenant_no,
|
|
order_num=0,
|
|
remark="",
|
|
create_by=user_id,
|
|
create_dept_id="",
|
|
create_time=now,
|
|
update_by=user_id,
|
|
update_time=now,
|
|
del_flag=0,
|
|
)
|
|
db.add(row)
|
|
db.flush()
|
|
return row.id
|
|
|
|
|
|
def remove_checkup_for_patient(
|
|
db: Session,
|
|
patient_id: str,
|
|
tenant_no: str,
|
|
) -> None:
|
|
"""软删除患者的体检记录(仅在初始状态,无机构数据时才删除)。"""
|
|
row = (
|
|
db.query(BizPilotCheckup)
|
|
.filter(
|
|
BizPilotCheckup.pilot_patient_id == patient_id,
|
|
BizPilotCheckup.tenant_no == tenant_no,
|
|
BizPilotCheckup.del_flag == 0,
|
|
)
|
|
.first()
|
|
)
|
|
if not row:
|
|
return
|
|
if row.checkup_institution_id:
|
|
return
|
|
|
|
now = datetime.now()
|
|
row.del_flag = 1
|
|
row.update_time = now
|
|
|
|
db.query(BizPilotCheckupReserveItem).filter(
|
|
BizPilotCheckupReserveItem.pilot_checkup_id == row.id,
|
|
BizPilotCheckupReserveItem.tenant_no == tenant_no,
|
|
BizPilotCheckupReserveItem.del_flag == 0,
|
|
).update({"del_flag": 1, "update_time": now}, synchronize_session=False)
|
|
|
|
db.query(BizPilotCheckupActualItem).filter(
|
|
BizPilotCheckupActualItem.pilot_checkup_id == row.id,
|
|
BizPilotCheckupActualItem.tenant_no == tenant_no,
|
|
BizPilotCheckupActualItem.del_flag == 0,
|
|
).update({"del_flag": 1, "update_time": now}, synchronize_session=False)
|