Files
zkxw/backend/app/crud/protocol_sample_collection.py
T
2026-07-01 16:37:33 +08:00

259 lines
8.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""采集协议样本采集信息列表 CRUD(样本信息管理 · 样本采集信息 Tab)"""
from __future__ import annotations
import math
from datetime import datetime
from typing import Any, Dict, List, Optional, Tuple
from sqlalchemy import and_, or_
from sqlalchemy.orm import Session
from app.core.utils import format_date
from app.utils.sample_special import sample_special_to_dict
from app.models.models import (
BizCellSampleType,
BizCollectionHospital,
BizCollectionProtocol,
BizCollectionRegion,
BizProtocolCollectionInfo,
BizProtocolPartyCustomer,
BizProtocolSample,
)
def total_pages(total: int, page_size: int) -> int:
if total <= 0:
return 0
return int(math.ceil(total / float(page_size)))
def _fmt_dt(t: Optional[datetime]) -> str:
return t.strftime("%Y-%m-%d %H:%M:%S") if t else ""
def _sample_status_label(status: str) -> str:
return {
"ycj": "已采集",
"jcz": "检测中",
"yrk": "已入库",
"yzf": "已作废",
}.get(status, "未采集" if not status else status)
def _row_to_dict(
*,
protocol_sample_id: str,
collection_protocol_id: str,
protocol_no: str,
protocol_status: str,
expected_delivery_date: str,
mother_name: str,
newborn_name: str,
sample_code: str,
sample_type_name: str,
sample_status: str,
sample_status_label: str,
region_name: str,
hospital_name: str,
medical_staff: str,
sample_collect_time: str,
maternal_blood_collect_time: str,
) -> Dict[str, Any]:
return {
"protocolSampleId": protocol_sample_id,
"collectionProtocolId": collection_protocol_id,
"protocolNo": protocol_no,
"protocolStatus": protocol_status,
"expectedDeliveryDate": expected_delivery_date,
"motherName": mother_name,
"newbornName": newborn_name,
"sampleCode": sample_code,
"sampleTypeName": sample_type_name,
"sampleStatus": sample_status,
"sampleStatusLabel": sample_status_label,
"regionName": region_name,
"hospitalName": hospital_name,
"medicalStaff": medical_staff,
"sampleCollectTime": sample_collect_time,
"maternalBloodCollectTime": maternal_blood_collect_time,
}
def _base_query(db: Session, tenant_no: str):
return (
db.query(
BizProtocolSample,
BizCollectionProtocol,
BizProtocolPartyCustomer,
BizProtocolCollectionInfo,
)
.join(
BizCollectionProtocol,
and_(
BizCollectionProtocol.id == BizProtocolSample.collection_protocol_id,
BizCollectionProtocol.del_flag == 0,
),
)
.outerjoin(
BizProtocolPartyCustomer,
and_(
BizProtocolPartyCustomer.collection_protocol_id == BizCollectionProtocol.id,
BizProtocolPartyCustomer.del_flag == 0,
),
)
.outerjoin(
BizProtocolCollectionInfo,
and_(
BizProtocolCollectionInfo.collection_protocol_id == BizCollectionProtocol.id,
BizProtocolCollectionInfo.del_flag == 0,
),
)
.filter(
BizProtocolSample.tenant_no == tenant_no,
BizProtocolSample.del_flag == 0,
)
)
def _apply_sample_status_filter(q, sample_status: Optional[str]):
st = (sample_status or "").strip()
if not st or st == "all":
return q
if st == "uncollected":
return q.filter(
or_(
BizProtocolSample.sample_status.is_(None),
BizProtocolSample.sample_status == "",
)
)
return q.filter(BizProtocolSample.sample_status == st)
def list_protocol_sample_collections(
db: Session,
*,
page: int = 1,
page_size: int = 10,
tenant_no: str,
keyword: Optional[str] = None,
sample_status: Optional[str] = None,
user_info=None,
) -> Tuple[List[Dict[str, Any]], int]:
if not tenant_no:
return [], 0
q = _base_query(db, tenant_no)
q = _apply_sample_status_filter(q, sample_status)
if keyword and keyword.strip():
kw = f"%{keyword.strip()}%"
kw_conds = [
BizProtocolPartyCustomer.mother_name.like(kw),
BizProtocolSample.sample_code.like(kw),
]
from app.crud import sample_reception as reception_svc
lab_codes = reception_svc.sample_codes_matching_lab_storage_keyword(
db, tenant_no, keyword, reception_source="cell_storage"
)
if lab_codes:
kw_conds.append(BizProtocolSample.sample_code.in_(lab_codes))
q = q.filter(or_(*kw_conds))
if user_info:
from app.core.data_scope import apply_data_scope
q = apply_data_scope(q, BizProtocolSample, user_info, db, tenant_no)
total = q.count()
page = max(1, page)
page_size = min(max(1, page_size), 100)
rows = (
q.order_by(
BizProtocolPartyCustomer.expected_delivery_date.is_(None),
BizProtocolPartyCustomer.expected_delivery_date.desc(),
BizCollectionProtocol.create_time.desc(),
BizProtocolSample.id.desc(),
)
.offset((page - 1) * page_size)
.limit(page_size)
.all()
)
sample_type_ids = list({
ps.sample_type_id for ps, _, _, _ in rows if ps and ps.sample_type_id
})
type_map: Dict[str, str] = {}
if sample_type_ids:
for t in (
db.query(BizCellSampleType)
.filter(BizCellSampleType.id.in_(sample_type_ids), BizCellSampleType.del_flag == 0)
.all()
):
type_map[t.id] = t.type_name or ""
region_ids = list({
(ci.region_id or "").strip()
for _, _, _, ci in rows
if ci and (ci.region_id or "").strip()
})
hospital_ids = list({
(ci.hospital_id or "").strip()
for _, _, _, ci in rows
if ci and (ci.hospital_id or "").strip()
})
region_name_map: Dict[str, str] = {}
hospital_name_map: Dict[str, str] = {}
if region_ids:
for r in (
db.query(BizCollectionRegion.id, BizCollectionRegion.region_name)
.filter(BizCollectionRegion.id.in_(region_ids), BizCollectionRegion.del_flag == 0)
.all()
):
region_name_map[r.id] = r.region_name or ""
if hospital_ids:
for h in (
db.query(BizCollectionHospital.id, BizCollectionHospital.hospital_name)
.filter(BizCollectionHospital.id.in_(hospital_ids), BizCollectionHospital.del_flag == 0)
.all()
):
hospital_name_map[h.id] = h.hospital_name or ""
items: List[Dict[str, Any]] = []
for psample, proto, party, ci in rows:
status = (psample.sample_status or "").strip() if psample else ""
region_id = (ci.region_id or "").strip() if ci else ""
hospital_id = (ci.hospital_id or "").strip() if ci else ""
item = _row_to_dict(
protocol_sample_id=psample.id,
collection_protocol_id=proto.id if proto else "",
protocol_no=(proto.protocol_no or "") if proto else "",
protocol_status=(proto.protocol_status or "") if proto else "",
expected_delivery_date=format_date(party.expected_delivery_date) if party else "",
mother_name=(party.mother_name or "") if party else "",
newborn_name=(party.newborn_name or "") if party else "",
sample_code=psample.sample_code or "",
sample_type_name=type_map.get(psample.sample_type_id or "", ""),
sample_status=status,
sample_status_label=_sample_status_label(status),
region_name=region_name_map.get(region_id, ""),
hospital_name=hospital_name_map.get(hospital_id, ""),
medical_staff=(ci.medical_staff or "") if ci else "",
sample_collect_time=_fmt_dt(ci.sample_collect_time) if ci else "",
maternal_blood_collect_time=_fmt_dt(ci.maternal_blood_collect_time) if ci else "",
)
item.update(sample_special_to_dict(psample))
items.append(item)
if items and tenant_no:
from app.crud import sample_reception as reception_svc
codes = [i["sampleCode"] for i in items if i.get("sampleCode")]
code_map = reception_svc.get_lab_storage_code_map_by_sample_codes(
db, tenant_no, codes, reception_source="cell_storage"
)
for item in items:
sc = (item.get("sampleCode") or "").strip()
item["labStorageCode"] = code_map.get(sc, "") if sc else ""
return items, total