Files
zkxw/backend/app/crud/sample_storage_cert_qc.py
T
zlwuandCursor 5e563a6669 fix: 子表保存改为就地同步,避免整批换 id 打断外键。
协议样本、生产产出和盘点明细按行更新并保留原 id;补齐存储证明质检预填、离职人员显示名,以及样本采集通知模板字段。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-28 10:51:53 +08:00

223 lines
7.0 KiB
Python

"""样本储存证质检信息 CRUD。"""
from __future__ import annotations
from datetime import datetime
from typing import Any, Dict, Optional
from sqlalchemy.orm import Session
from app.core.utils import generate_uuid
from app.crud import sample_reception as reception_svc
from app.models.models import (
BizCellSampleType,
BizCollectionProtocol,
BizProtocolPartyCustomer,
BizProtocolSample,
BizSampleStorageCertQc,
)
from app.services.sample_storage_cert_qc import (
dumps_payload,
empty_detail,
loads_payload,
normalize_payload,
resolve_sample_type_key,
)
from app.services.sample_storage_cert_qc_prefill import collect_prefill
def _row_to_dict(
row: BizSampleStorageCertQc,
*,
lab_flow_code: str = "",
protocol_code: str = "",
mother_name: str = "",
sample_type_name: str = "",
) -> Dict[str, Any]:
return {
"id": row.id,
"sampleCode": row.sample_code or "",
"labFlowCode": lab_flow_code or "",
"protocolCode": protocol_code or "",
"motherName": mother_name or "",
"sampleTypeName": sample_type_name or "",
"sampleTypeKey": row.sample_type_key,
"collectionProtocolId": row.collection_protocol_id or "",
"qcWorkOrderId": row.qc_work_order_id or "",
"filledFlag": str(row.filled_flag or "0") == "1",
"payload": loads_payload(row.payload),
"createTime": row.create_time.isoformat(sep=" ", timespec="seconds") if row.create_time else "",
"updateTime": row.update_time.isoformat(sep=" ", timespec="seconds") if row.update_time else "",
}
def _load_sample_context(db: Session, tenant_no: str, sample_code: str):
code = (sample_code or "").strip()
if not code:
return None
sample = (
db.query(BizProtocolSample)
.filter(
BizProtocolSample.tenant_no == tenant_no,
BizProtocolSample.sample_code == code,
BizProtocolSample.del_flag == 0,
)
.first()
)
if not sample:
return None
type_name = ""
if sample.sample_type_id:
st = (
db.query(BizCellSampleType)
.filter(
BizCellSampleType.id == sample.sample_type_id,
BizCellSampleType.del_flag == 0,
)
.first()
)
if st:
type_name = st.type_name or ""
protocol_code = ""
mother_name = ""
if sample.collection_protocol_id:
proto = (
db.query(BizCollectionProtocol)
.filter(
BizCollectionProtocol.id == sample.collection_protocol_id,
BizCollectionProtocol.tenant_no == tenant_no,
BizCollectionProtocol.del_flag == 0,
)
.first()
)
if proto:
protocol_code = proto.protocol_no or ""
pc = (
db.query(BizProtocolPartyCustomer)
.filter(
BizProtocolPartyCustomer.collection_protocol_id == sample.collection_protocol_id,
BizProtocolPartyCustomer.tenant_no == tenant_no,
BizProtocolPartyCustomer.del_flag == 0,
)
.first()
)
if pc:
mother_name = pc.mother_name or ""
lab_flow_code = ""
sc = (sample.sample_code or "").strip()
if sc:
code_map = reception_svc.get_lab_storage_code_map_by_sample_codes(db, tenant_no, [sc])
lab_flow_code = code_map.get(sc, "") or ""
return sample, type_name, protocol_code, mother_name, lab_flow_code
def _with_prefill(db: Session, tenant_no: str, detail: Dict[str, Any]) -> Dict[str, Any]:
detail["prefill"] = collect_prefill(
db,
tenant_no,
detail.get("sampleCode") or "",
detail.get("sampleTypeKey"),
)
return detail
def get_detail(db: Session, tenant_no: str, sample_code: str) -> Optional[Dict[str, Any]]:
"""样本不存在返回 None;存在但未填返回 empty_detail。prefill 只补空,不写入已存档 payload。"""
ctx = _load_sample_context(db, tenant_no, sample_code)
if not ctx:
return None
sample, type_name, protocol_code, mother_name, lab_flow_code = ctx
key = resolve_sample_type_key(type_name)
row = (
db.query(BizSampleStorageCertQc)
.filter(
BizSampleStorageCertQc.tenant_no == tenant_no,
BizSampleStorageCertQc.sample_code == sample.sample_code,
BizSampleStorageCertQc.del_flag == 0,
)
.first()
)
if not row:
detail = empty_detail(
sample_code=sample.sample_code or "",
lab_flow_code=lab_flow_code,
protocol_code=protocol_code,
mother_name=mother_name,
sample_type_name=type_name,
sample_type_key=key,
collection_protocol_id=sample.collection_protocol_id or "",
)
return _with_prefill(db, tenant_no, detail)
detail = _row_to_dict(
row,
lab_flow_code=lab_flow_code,
protocol_code=protocol_code,
mother_name=mother_name,
sample_type_name=type_name,
)
return _with_prefill(db, tenant_no, detail)
def upsert(
db: Session,
*,
tenant_no: str,
user_id: str,
sample_code: str,
payload: Any,
qc_work_order_id: Optional[str] = None,
) -> Dict[str, Any]:
ctx = _load_sample_context(db, tenant_no, sample_code)
if not ctx:
raise ValueError("样本不存在")
sample, type_name, protocol_code, mother_name, lab_flow_code = ctx
key = resolve_sample_type_key(type_name)
if not key:
raise ValueError("该样本类型不支持填写储存证质检信息")
clean = normalize_payload(payload)
now = datetime.now()
row = (
db.query(BizSampleStorageCertQc)
.filter(
BizSampleStorageCertQc.tenant_no == tenant_no,
BizSampleStorageCertQc.sample_code == sample.sample_code,
BizSampleStorageCertQc.del_flag == 0,
)
.first()
)
if not row:
row = BizSampleStorageCertQc(
id=generate_uuid(),
sample_code=sample.sample_code,
collection_protocol_id=sample.collection_protocol_id,
qc_work_order_id=(qc_work_order_id or None),
sample_type_key=key,
payload=dumps_payload(clean),
filled_flag="1",
tenant_no=tenant_no,
create_by=user_id,
create_dept_id="",
create_time=now,
update_by=user_id,
update_time=now,
del_flag=0,
)
db.add(row)
else:
row.collection_protocol_id = sample.collection_protocol_id
row.sample_type_key = key
row.payload = dumps_payload(clean)
row.filled_flag = "1"
if qc_work_order_id:
row.qc_work_order_id = qc_work_order_id
row.update_by = user_id
row.update_time = now
db.commit()
db.refresh(row)
return _row_to_dict(
row,
lab_flow_code=lab_flow_code,
protocol_code=protocol_code,
mother_name=mother_name,
sample_type_name=type_name,
)