Files
zkxw/backend/app/crud/lab_sample_process.py
zlwuandCursor acb81cadd5 feat(qc): 新增实验室样本处理数据台账(4 Tab + 补录 + 导出)
在质检管理下增加按来源×样本类型展示的台账页,聚合接收/生产/质检参数,
补录按实验室入库编码关联,支持 Excel 导出与中文时间格式。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-12 12:11:57 +08:00

754 lines
27 KiB
Python

"""实验室样本处理台账列表与补录 CRUD。"""
from __future__ import annotations
from datetime import datetime
from typing import Any, Dict, List, Optional, Tuple
from sqlalchemy import and_
from sqlalchemy.orm import Session
from app.core.data_scope import apply_data_scope
from app.core.utils import generate_uuid
from app.crud import sample_production_reception as prod_svc
from app.models.models import (
BizCellSampleType,
BizCollectionHospital,
BizCollectionProtocol,
BizLabSampleProcessSupplement,
BizProtocolCollectionInfo,
BizProtocolPartyCustomer,
BizProtocolSample,
BizSampleProductionReception,
BizSampleReception,
BizSampleReceptionCheckResult,
BizStorageReleaseReview,
)
from app.models.research_donation import (
BizResearchDonation,
BizResearchDonationCollection,
BizResearchDonationParty,
BizResearchDonationSample,
)
from app.services import lab_sample_process as ledger
def _fmt_raw(dt: Optional[datetime]) -> str:
return dt.strftime("%Y-%m-%d %H:%M:%S") if dt else ""
def _normalize_bound(value: Optional[str], *, end_of_day: bool = False) -> Optional[datetime]:
text = (value or "").strip()
if not text:
return None
for fmt in ("%Y-%m-%d %H:%M:%S", "%Y-%m-%d"):
try:
dt = datetime.strptime(text[:19] if " " in text else text[:10], fmt)
if end_of_day and fmt == "%Y-%m-%d":
return dt.replace(hour=23, minute=59, second=59)
return dt
except ValueError:
continue
return None
def _type_ids_by_name(db: Session, tenant_no: str, type_name: str) -> List[str]:
rows = (
db.query(BizCellSampleType.id)
.filter(
BizCellSampleType.tenant_no == tenant_no,
BizCellSampleType.del_flag == 0,
BizCellSampleType.type_name == type_name,
)
.all()
)
return [r.id for r in rows if r.id]
def _get_supplement_map(
db: Session, tenant_no: str, codes: List[str]
) -> Dict[str, Dict[str, Any]]:
codes = [c for c in {(x or "").strip() for x in codes} if c]
if not codes:
return {}
rows = (
db.query(BizLabSampleProcessSupplement)
.filter(
BizLabSampleProcessSupplement.tenant_no == tenant_no,
BizLabSampleProcessSupplement.del_flag == 0,
BizLabSampleProcessSupplement.lab_storage_code.in_(codes),
)
.all()
)
out: Dict[str, Dict[str, Any]] = {}
for row in rows:
out[row.lab_storage_code] = {
"id": row.id,
"payload": ledger.parse_payload(row.payload),
"remark": row.remark or "",
"updateTime": _fmt_raw(row.update_time),
}
return out
def get_supplement(
db: Session, *, tenant_no: str, lab_storage_code: str
) -> Optional[Dict[str, Any]]:
code = (lab_storage_code or "").strip()
if not code:
return None
row = (
db.query(BizLabSampleProcessSupplement)
.filter(
BizLabSampleProcessSupplement.tenant_no == tenant_no,
BizLabSampleProcessSupplement.lab_storage_code == code,
BizLabSampleProcessSupplement.del_flag == 0,
)
.first()
)
if not row:
return None
return {
"id": row.id,
"labStorageCode": row.lab_storage_code,
"receptionSource": row.reception_source,
"sampleTypeName": row.sample_type_name or "",
"payload": ledger.parse_payload(row.payload),
"remark": row.remark or "",
"createTime": _fmt_raw(row.create_time),
"updateTime": _fmt_raw(row.update_time),
}
def upsert_supplement(
db: Session,
*,
tenant_no: str,
user_id: str,
dept_id: str,
lab_storage_code: str,
reception_source: str,
sample_type_name: str,
payload: Dict[str, Any],
remark: Optional[str] = None,
) -> Dict[str, Any]:
code = (lab_storage_code or "").strip()
if not code:
raise ValueError("实验室入库编码不能为空")
src = (reception_source or "").strip() or "cell_storage"
if src not in ("cell_storage", "research_donation"):
raise ValueError("来源类型无效")
type_name = (sample_type_name or "").strip()
clean_payload = {
str(k): ("" if v is None else str(v).strip())
for k, v in (payload or {}).items()
if str(k).strip()
}
row = (
db.query(BizLabSampleProcessSupplement)
.filter(
BizLabSampleProcessSupplement.tenant_no == tenant_no,
BizLabSampleProcessSupplement.lab_storage_code == code,
BizLabSampleProcessSupplement.del_flag == 0,
)
.first()
)
now = datetime.now()
if row:
row.reception_source = src
row.sample_type_name = type_name or row.sample_type_name
row.payload = ledger.dumps_payload(clean_payload)
if remark is not None:
row.remark = (remark or "").strip() or None
row.update_by = user_id
row.update_time = now
else:
row = BizLabSampleProcessSupplement(
id=generate_uuid(),
lab_storage_code=code,
reception_source=src,
sample_type_name=type_name or None,
payload=ledger.dumps_payload(clean_payload),
tenant_no=tenant_no,
remark=(remark or "").strip() or None,
create_by=user_id,
create_dept_id=dept_id or "",
create_time=now,
update_by=user_id,
update_time=now,
del_flag=0,
)
db.add(row)
db.commit()
db.refresh(row)
return get_supplement(db, tenant_no=tenant_no, lab_storage_code=code) or {}
def _check_flag_map(db: Session, tenant_no: str, reception_ids: List[str]) -> Dict[str, Dict[str, bool]]:
ids = [i for i in reception_ids if i]
if not ids:
return {}
rows = (
db.query(BizSampleReceptionCheckResult)
.filter(
BizSampleReceptionCheckResult.tenant_no == tenant_no,
BizSampleReceptionCheckResult.del_flag == 0,
BizSampleReceptionCheckResult.reception_id.in_(ids),
)
.all()
)
out: Dict[str, Dict[str, bool]] = {}
for r in rows:
bucket = out.setdefault(r.reception_id, {})
name = (r.item_name or "").strip()
if name:
bucket[name] = bool(r.checked)
return out
def _storage_status_map(db: Session, tenant_no: str, sample_codes: List[str]) -> Dict[str, str]:
codes = [c for c in sample_codes if c]
if not codes:
return {}
rows = (
db.query(BizStorageReleaseReview.sample_code, BizStorageReleaseReview.storage_status)
.filter(
BizStorageReleaseReview.tenant_no == tenant_no,
BizStorageReleaseReview.del_flag == 0,
BizStorageReleaseReview.sample_code.in_(codes),
)
.all()
)
labels = {"drk": "待入库", "yrk": "已入库"}
return {r.sample_code: labels.get(r.storage_status or "", r.storage_status or "") for r in rows}
def _hospital_name_map(db: Session, hospital_ids: List[str]) -> Dict[str, str]:
ids = [i for i in hospital_ids if i]
if not ids:
return {}
rows = (
db.query(BizCollectionHospital.id, BizCollectionHospital.hospital_name)
.filter(BizCollectionHospital.id.in_(ids), BizCollectionHospital.del_flag == 0)
.all()
)
return {r.id: r.hospital_name or "" for r in rows}
def _build_cell_system(
*,
tab_key: str,
rec: BizSampleReception,
sample: BizProtocolSample,
party: Optional[BizProtocolPartyCustomer],
coll: Optional[BizProtocolCollectionInfo],
protocol: Optional[BizCollectionProtocol],
prod: Optional[Dict[str, Any]],
hospital_name: str,
check_flags: Dict[str, bool],
storage_status: str,
qc_mother: Dict[str, str],
qc_process: Dict[str, str],
) -> Dict[str, Any]:
prod = prod or {}
maternal_time = coll.maternal_blood_collect_time if coll else None
clear_flag = None
for name, checked in check_flags.items():
if "标识清晰" in name or "样本信息正确" in name:
clear_flag = checked
break
base: Dict[str, Any] = {
"receptionId": rec.id,
"sampleCode": (rec.sample_code or sample.sample_code or "").strip(),
"labStorageCode": (rec.lab_storage_code or "").strip(),
"motherName": (party.mother_name if party else "") or "",
"collectionTime": ledger.format_cn_datetime(coll.sample_collect_time if coll else None),
"collectionTimeRaw": _fmt_raw(coll.sample_collect_time if coll else None),
"hospitalName": hospital_name,
"receptionTime": ledger.format_cn_datetime(rec.reception_time),
"receptionTimeRaw": _fmt_raw(rec.reception_time),
"receiveTemperature": rec.receive_temperature or "",
"handlerName": rec.handler_name or "",
"remarkReception": rec.remark or "",
"createTime": ledger.format_cn_datetime(rec.create_time),
"createTimeRaw": _fmt_raw(rec.create_time),
"operatorName": prod.get("handlerName") or "",
"remarkProcess": prod.get("remark") or "",
"storageStatus": storage_status,
}
if tab_key == "cell_hsc":
base.update(
{
"cellCode": (rec.lab_storage_code or "").strip(),
"hasMaternalBlood": "是" if maternal_time else "否",
"remeasureMaternalBlood": "",
"consentForm": ledger.yes_no_from_urls(
protocol.consent_form_urls if protocol else None
),
"transportPackingList": "",
"cordBloodReceiveConfirm": "",
"healthSurvey": ledger.yes_no_from_urls(
protocol.health_survey_form_urls if protocol else None
),
"labelClear": ledger.yes_no_from_bool(clear_flag) if clear_flag is not None else "",
"receiveCheckText": "",
"originalBloodWeightG": prod.get("originalBloodWeightG"),
"hesVolumeMl": prod.get("hesVolumeMl"),
"bloodType": prod.get("bloodType") or "",
"infectiousFourTestLabel": prod.get("infectiousFourTestResultLabel")
or ledger.infectious_label(prod.get("infectiousFourTestResult")),
"infectiousFourExternal": "",
"preEnrichNucleatedCount": "",
"enrichedBloodWeightG": prod.get("enrichedBloodWeightG"),
"postEnrichNucleatedCount": "",
"cryopreservationVolumeMl": prod.get("cryopreservationVolumeMl"),
"cd34Count1e4": "",
}
)
else: # cell_msc
base.update(
{
"labFlowCode": (rec.lab_storage_code or "").strip(),
"cordCollectTime": ledger.format_cn_datetime(
coll.sample_collect_time if coll else None
),
"transportTempC": rec.receive_temperature or "",
"cordReceiveTime": ledger.format_cn_datetime(rec.reception_time),
"inoculationAmount": prod.get("inoculationAmount") or "",
"cryopreservationTime": ledger.format_cn_datetime(prod.get("cryopreservationTime")),
"storageTotalTubes": prod.get("storageTotalTubes"),
"availableCellCount1e7": prod.get("availableCellCount1e7"),
"remark": rec.remark or prod.get("remark") or "",
"storageDateP2": "",
}
)
base.update(qc_process)
base.update(qc_mother)
return base
def _build_donation_system(
*,
tab_key: str,
rec: BizSampleReception,
sample: BizResearchDonationSample,
party: Optional[BizResearchDonationParty],
coll: Optional[BizResearchDonationCollection],
prod: Optional[Dict[str, Any]],
storage_status: str,
qc_mother: Dict[str, str],
qc_process: Dict[str, str],
) -> Dict[str, Any]:
prod = prod or {}
base: Dict[str, Any] = {
"receptionId": rec.id,
"sampleCode": (rec.sample_code or sample.sample_code or "").strip(),
"labStorageCode": (rec.lab_storage_code or "").strip(),
"motherName": (party.mother_name if party else "") or "",
"receptionTime": ledger.format_cn_datetime(rec.reception_time),
"receptionTimeRaw": _fmt_raw(rec.reception_time),
"receiveTemperature": rec.receive_temperature or "",
"handlerName": rec.handler_name or "",
"remarkReception": rec.remark or "",
"createTime": ledger.format_cn_datetime(rec.create_time),
"createTimeRaw": _fmt_raw(rec.create_time),
"operatorName": prod.get("handlerName") or "",
"remarkProcess": prod.get("remark") or "",
"storageStatus": storage_status,
}
if tab_key == "donation_hsc":
base.update(
{
"cellCode": (rec.lab_storage_code or "").strip(),
"labMaterialCode": "",
"inboundCode": (rec.lab_storage_code or "").strip(),
"discardReason": "",
"receiveCheckText": "",
"originalBloodVolumeMl": prod.get("originalBloodVolumeMl"),
"nucleatedCellCount1e8": prod.get("nucleatedCellCount1e8"),
"preOpNucleatedCount": "",
"infectiousFourTestLabel": prod.get("infectiousFourTestResultLabel")
or ledger.infectious_label(prod.get("infectiousFourTestResult")),
}
)
# 科研捐赠母血 5 项(不含核酸)
for k in (
"motherHbsag",
"motherAntiHcv",
"motherAntiTp",
"motherAntiHiv",
"motherCmvIgm",
):
if qc_mother.get(k):
base[k] = qc_mother[k]
else:
base.update(
{
"labFlowCode": (rec.lab_storage_code or "").strip(),
"cordCollectTime": ledger.format_cn_datetime(
coll.sample_collect_time if coll else None
),
"transportTempC": rec.receive_temperature or "",
"cordReceiveTime": ledger.format_cn_datetime(rec.reception_time),
"inoculationAmount": prod.get("inoculationAmount") or "",
"cryopreservationTime": ledger.format_cn_datetime(prod.get("cryopreservationTime")),
"storageTotalTubes": prod.get("storageTotalTubes"),
"availableCellCount1e7": prod.get("availableCellCount1e7"),
"remark": rec.remark or prod.get("remark") or "",
"storageDateP2": "",
}
)
base.update(qc_process)
base.update(qc_mother)
return base
def list_ledger(
db: Session,
*,
tab_key: str,
page: int = 1,
page_size: int = 10,
tenant_no: str,
lab_storage_code: Optional[str] = None,
mother_name: Optional[str] = None,
create_time_start: Optional[str] = None,
create_time_end: Optional[str] = None,
user_info=None,
) -> Tuple[List[Dict[str, Any]], int]:
meta = ledger.TAB_META.get(tab_key)
if not meta:
raise ValueError("无效的 Tab")
source = meta["source"]
type_name = meta["sampleTypeName"]
type_ids = _type_ids_by_name(db, tenant_no, type_name)
if not type_ids:
return [], 0
q = db.query(BizSampleReception).filter(
BizSampleReception.tenant_no == tenant_no,
BizSampleReception.del_flag == 0,
BizSampleReception.reception_source == source,
BizSampleReception.lab_storage_code.isnot(None),
BizSampleReception.lab_storage_code != "",
BizSampleReception.accept_conclusion == "js",
)
code_kw = (lab_storage_code or "").strip()
if code_kw:
q = q.filter(BizSampleReception.lab_storage_code.like(f"%{code_kw}%"))
start = _normalize_bound(create_time_start)
end = _normalize_bound(create_time_end, end_of_day=True)
if start:
q = q.filter(BizSampleReception.create_time >= start)
if end:
q = q.filter(BizSampleReception.create_time <= end)
if user_info:
q = apply_data_scope(q, BizSampleReception, user_info, db, tenant_no)
mother_kw = (mother_name or "").strip()
# 按来源限制样本类型,并可选母亲姓名
if source == "cell_storage":
sample_q = (
db.query(BizProtocolSample.id)
.join(
BizCollectionProtocol,
and_(
BizCollectionProtocol.id == BizProtocolSample.collection_protocol_id,
BizCollectionProtocol.del_flag == 0,
BizCollectionProtocol.tenant_no == tenant_no,
),
)
.filter(
BizProtocolSample.tenant_no == tenant_no,
BizProtocolSample.del_flag == 0,
BizProtocolSample.sample_type_id.in_(type_ids),
)
)
if mother_kw:
sample_q = sample_q.join(
BizProtocolPartyCustomer,
and_(
BizProtocolPartyCustomer.collection_protocol_id
== BizProtocolSample.collection_protocol_id,
BizProtocolPartyCustomer.del_flag == 0,
BizProtocolPartyCustomer.tenant_no == tenant_no,
),
).filter(BizProtocolPartyCustomer.mother_name.like(f"%{mother_kw}%"))
sample_ids = [r.id for r in sample_q.all()]
if not sample_ids:
return [], 0
q = q.filter(BizSampleReception.protocol_sample_id.in_(sample_ids))
else:
sample_q = (
db.query(BizResearchDonationSample.id)
.join(
BizResearchDonation,
and_(
BizResearchDonation.id == BizResearchDonationSample.research_donation_id,
BizResearchDonation.del_flag == 0,
BizResearchDonation.tenant_no == tenant_no,
),
)
.filter(
BizResearchDonationSample.tenant_no == tenant_no,
BizResearchDonationSample.del_flag == 0,
BizResearchDonationSample.sample_type_id.in_(type_ids),
)
)
if mother_kw:
sample_q = sample_q.join(
BizResearchDonationParty,
and_(
BizResearchDonationParty.research_donation_id
== BizResearchDonationSample.research_donation_id,
BizResearchDonationParty.del_flag == 0,
BizResearchDonationParty.tenant_no == tenant_no,
),
).filter(BizResearchDonationParty.mother_name.like(f"%{mother_kw}%"))
sample_ids = [r.id for r in sample_q.all()]
if not sample_ids:
return [], 0
q = q.filter(BizSampleReception.donation_sample_id.in_(sample_ids))
total = q.count()
page = max(1, int(page or 1))
page_size = min(max(1, int(page_size or 10)), 200)
receptions = (
q.order_by(BizSampleReception.create_time.desc(), BizSampleReception.id.desc())
.offset((page - 1) * page_size)
.limit(page_size)
.all()
)
if not receptions:
return [], int(total)
reception_ids = [r.id for r in receptions]
codes = [(r.lab_storage_code or "").strip() for r in receptions]
sample_codes = [(r.sample_code or "").strip() for r in receptions]
prod_map = _prod_map(db, tenant_no, reception_ids)
check_map = _check_flag_map(db, tenant_no, reception_ids)
storage_map = _storage_status_map(db, tenant_no, [c for c in sample_codes if c])
sup_map = _get_supplement_map(db, tenant_no, codes)
items: List[Dict[str, Any]] = []
if source == "cell_storage":
items = _assemble_cell_rows(
db,
tenant_no=tenant_no,
tab_key=tab_key,
receptions=receptions,
prod_map=prod_map,
check_map=check_map,
storage_map=storage_map,
sup_map=sup_map,
)
else:
items = _assemble_donation_rows(
db,
tenant_no=tenant_no,
tab_key=tab_key,
receptions=receptions,
prod_map=prod_map,
storage_map=storage_map,
sup_map=sup_map,
)
return items, int(total)
def _prod_map(db: Session, tenant_no: str, reception_ids: List[str]) -> Dict[str, Dict[str, Any]]:
rows = (
db.query(BizSampleProductionReception)
.filter(
BizSampleProductionReception.tenant_no == tenant_no,
BizSampleProductionReception.del_flag == 0,
BizSampleProductionReception.reception_id.in_(reception_ids),
)
.all()
)
return {r.reception_id: prod_svc._row_to_dict(r) for r in rows}
def _assemble_cell_rows(
db: Session,
*,
tenant_no: str,
tab_key: str,
receptions: List[BizSampleReception],
prod_map: Dict[str, Dict[str, Any]],
check_map: Dict[str, Dict[str, bool]],
storage_map: Dict[str, str],
sup_map: Dict[str, Dict[str, Any]],
) -> List[Dict[str, Any]]:
sample_ids = [r.protocol_sample_id for r in receptions if r.protocol_sample_id]
samples = (
db.query(BizProtocolSample)
.filter(
BizProtocolSample.tenant_no == tenant_no,
BizProtocolSample.del_flag == 0,
BizProtocolSample.id.in_(sample_ids),
)
.all()
if sample_ids
else []
)
sample_map = {s.id: s for s in samples}
protocol_ids = list({s.collection_protocol_id for s in samples if s.collection_protocol_id})
parties = (
db.query(BizProtocolPartyCustomer)
.filter(
BizProtocolPartyCustomer.tenant_no == tenant_no,
BizProtocolPartyCustomer.del_flag == 0,
BizProtocolPartyCustomer.collection_protocol_id.in_(protocol_ids),
)
.all()
if protocol_ids
else []
)
party_map = {p.collection_protocol_id: p for p in parties}
colls = (
db.query(BizProtocolCollectionInfo)
.filter(
BizProtocolCollectionInfo.tenant_no == tenant_no,
BizProtocolCollectionInfo.del_flag == 0,
BizProtocolCollectionInfo.collection_protocol_id.in_(protocol_ids),
)
.all()
if protocol_ids
else []
)
coll_map = {c.collection_protocol_id: c for c in colls}
protocols = (
db.query(BizCollectionProtocol)
.filter(
BizCollectionProtocol.tenant_no == tenant_no,
BizCollectionProtocol.del_flag == 0,
BizCollectionProtocol.id.in_(protocol_ids),
)
.all()
if protocol_ids
else []
)
protocol_map = {p.id: p for p in protocols}
hospital_ids = [c.hospital_id for c in colls if c.hospital_id]
hospital_map = _hospital_name_map(db, hospital_ids)
out: List[Dict[str, Any]] = []
for rec in receptions:
sample = sample_map.get(rec.protocol_sample_id or "")
if not sample:
continue
pid = sample.collection_protocol_id
sample_code = (rec.sample_code or sample.sample_code or "").strip()
tasks = ledger.load_qc_tasks_for_sample(db, tenant_no, sample_code)
qc_mother = ledger.extract_mother_blood(tasks, include_nucleic=True)
qc_process = ledger.extract_process_tests(tasks)
system = _build_cell_system(
tab_key=tab_key,
rec=rec,
sample=sample,
party=party_map.get(pid),
coll=coll_map.get(pid),
protocol=protocol_map.get(pid),
prod=prod_map.get(rec.id),
hospital_name=hospital_map.get((coll_map.get(pid).hospital_id if coll_map.get(pid) else "") or "", ""),
check_flags=check_map.get(rec.id, {}),
storage_status=storage_map.get(sample_code, ""),
qc_mother=qc_mother,
qc_process=qc_process,
)
lab_code = system.get("labStorageCode") or ""
merged = ledger.merge_row(
tab_key=tab_key,
system_values=system,
supplement=(sup_map.get(lab_code) or {}).get("payload"),
)
merged["supplementId"] = (sup_map.get(lab_code) or {}).get("id") or ""
merged["hasSupplement"] = bool((sup_map.get(lab_code) or {}).get("payload"))
out.append(merged)
return out
def _assemble_donation_rows(
db: Session,
*,
tenant_no: str,
tab_key: str,
receptions: List[BizSampleReception],
prod_map: Dict[str, Dict[str, Any]],
storage_map: Dict[str, str],
sup_map: Dict[str, Dict[str, Any]],
) -> List[Dict[str, Any]]:
sample_ids = [r.donation_sample_id for r in receptions if r.donation_sample_id]
samples = (
db.query(BizResearchDonationSample)
.filter(
BizResearchDonationSample.tenant_no == tenant_no,
BizResearchDonationSample.del_flag == 0,
BizResearchDonationSample.id.in_(sample_ids),
)
.all()
if sample_ids
else []
)
sample_map = {s.id: s for s in samples}
donation_ids = list({s.research_donation_id for s in samples if s.research_donation_id})
parties = (
db.query(BizResearchDonationParty)
.filter(
BizResearchDonationParty.tenant_no == tenant_no,
BizResearchDonationParty.del_flag == 0,
BizResearchDonationParty.research_donation_id.in_(donation_ids),
)
.all()
if donation_ids
else []
)
party_map = {p.research_donation_id: p for p in parties}
colls = (
db.query(BizResearchDonationCollection)
.filter(
BizResearchDonationCollection.tenant_no == tenant_no,
BizResearchDonationCollection.del_flag == 0,
BizResearchDonationCollection.research_donation_id.in_(donation_ids),
)
.all()
if donation_ids
else []
)
coll_map = {c.research_donation_id: c for c in colls}
out: List[Dict[str, Any]] = []
for rec in receptions:
sample = sample_map.get(rec.donation_sample_id or "")
if not sample:
continue
did = sample.research_donation_id
sample_code = (rec.sample_code or sample.sample_code or "").strip()
tasks = ledger.load_qc_tasks_for_sample(db, tenant_no, sample_code)
qc_mother = ledger.extract_mother_blood(tasks, include_nucleic=True)
qc_process = ledger.extract_process_tests(tasks)
system = _build_donation_system(
tab_key=tab_key,
rec=rec,
sample=sample,
party=party_map.get(did),
coll=coll_map.get(did),
prod=prod_map.get(rec.id),
storage_status=storage_map.get(sample_code, ""),
qc_mother=qc_mother,
qc_process=qc_process,
)
lab_code = system.get("labStorageCode") or ""
merged = ledger.merge_row(
tab_key=tab_key,
system_values=system,
supplement=(sup_map.get(lab_code) or {}).get("payload"),
)
merged["supplementId"] = (sup_map.get(lab_code) or {}).get("id") or ""
merged["hasSupplement"] = bool((sup_map.get(lab_code) or {}).get("payload"))
out.append(merged)
return out