Files
shanxia2.0/backend/app/crud/sample_reception.py
T

850 lines
30 KiB
Python

"""样本接收 CRUD(质量检测)"""
from __future__ import annotations
from datetime import datetime
from typing import Any, Dict, List, Optional, Tuple
from sqlalchemy import and_, func, or_
from sqlalchemy.orm import Session
from app.core.utils import generate_uuid
from app.crud.collection_protocol import urls_to_attachment_list
from app.crud import sample_reception_check_result as check_result_svc
from app.models.models import (
BizCellSampleType,
BizCollectionProtocol,
BizExpressCompany,
BizProtocolPartyCustomer,
BizProtocolSample,
BizProtocolSampleTransport,
BizSampleReception,
SysUser,
)
from app.models.research_donation import (
BizResearchDonation,
BizResearchDonationParty,
BizResearchDonationSample,
BizResearchDonationSampleTransport,
)
# 科研捐赠表默认 general_ci,样本接收等为 unicode_ci,跨表比较需统一
_UNICODE_CI = "utf8mb4_unicode_ci"
def _donation_sample_id_col(col):
"""捐赠样本 ID 与 biz_sample_reception.donation_sample_id 比较时统一排序规则。"""
return col.collate(_UNICODE_CI)
def _fmt_dt(t: Optional[datetime]) -> str:
return t.strftime("%Y-%m-%d %H:%M:%S") if t else ""
def _dec(v: Any) -> Optional[float]:
if v is None:
return None
return float(v)
def _reception_to_dict(
r: BizSampleReception,
*,
check_results: Optional[List[Dict[str, Any]]] = None,
) -> Dict[str, Any]:
return {
"id": r.id,
"protocolSampleId": r.protocol_sample_id,
"collectionProtocolId": r.collection_protocol_id,
"receptionTime": _fmt_dt(r.reception_time),
"handlerUserId": r.handler_user_id or "",
"handlerName": r.handler_name or "",
"receiveTemperature": r.receive_temperature or "",
"volumeMl": _dec(r.volume_ml),
"netWeightG": _dec(r.net_weight_g),
"checkResults": check_results or [],
"acceptConclusion": r.accept_conclusion or "",
"receiveAttachments": r.receive_attachments or "",
"remark": r.remark or "",
"createTime": _fmt_dt(r.create_time),
"updateTime": _fmt_dt(r.update_time),
}
def _sample_detail_rows_query(db: Session):
"""协议样本 + 协议单 + 客户 + 运输(显式 select_from 避免多表 join 歧义)。"""
return (
db.query(
BizProtocolSample,
BizCollectionProtocol,
BizProtocolPartyCustomer,
BizProtocolSampleTransport,
)
.select_from(BizProtocolSample)
.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(
BizProtocolSampleTransport,
and_(
BizProtocolSampleTransport.sample_id == BizProtocolSample.id,
BizProtocolSampleTransport.del_flag == 0,
),
)
)
def _donation_sample_detail_rows_query(db: Session):
"""捐赠样本 + 捐赠单 + 当事人 + 运输(四表 JOIN)。"""
return (
db.query(
BizResearchDonationSample,
BizResearchDonation,
BizResearchDonationParty,
BizResearchDonationSampleTransport,
)
.select_from(BizResearchDonationSample)
.join(
BizResearchDonation,
and_(
BizResearchDonation.id == BizResearchDonationSample.research_donation_id,
BizResearchDonation.del_flag == 0,
),
)
.outerjoin(
BizResearchDonationParty,
and_(
BizResearchDonationParty.research_donation_id == BizResearchDonation.id,
BizResearchDonationParty.del_flag == 0,
),
)
.outerjoin(
BizResearchDonationSampleTransport,
and_(
BizResearchDonationSampleTransport.sample_id == BizResearchDonationSample.id,
BizResearchDonationSampleTransport.del_flag == 0,
),
)
)
def _donation_sample_pending_query(db: Session, tenant_no: str, keyword: Optional[str] = None):
"""待接收:捐赠样本且尚无有效接收记录。"""
received_donation_ids = (
db.query(BizSampleReception.donation_sample_id)
.filter(
BizSampleReception.tenant_no == tenant_no,
BizSampleReception.del_flag == 0,
BizSampleReception.reception_source == "research_donation",
)
.subquery()
)
q = _donation_sample_detail_rows_query(db).filter(
BizResearchDonationSample.del_flag == 0,
BizResearchDonationSample.tenant_no == tenant_no,
BizResearchDonation.tenant_no == tenant_no,
BizResearchDonation.donation_status.in_(["sxz", "ygq"]),
~_donation_sample_id_col(BizResearchDonationSample.id).in_(received_donation_ids),
)
if keyword and keyword.strip():
kw = f"%{keyword.strip()}%"
q = q.filter(
or_(
BizResearchDonation.donation_no.like(kw),
BizResearchDonationSample.sample_code.like(kw),
BizResearchDonationParty.mother_name.like(kw),
BizResearchDonationParty.newborn_name.like(kw),
)
)
return q
def _donation_rows_to_sample_list_items(
db: Session,
rows: list,
tenant_no: str,
*,
reception_map: Optional[Dict[str, BizSampleReception]] = None,
) -> List[Dict[str, Any]]:
"""将捐赠样本行转为统一列表项字典(字段名与细胞存储保持一致)。"""
type_ids = list({s.sample_type_id for s, *_ in rows if s.sample_type_id})
type_map: Dict[str, str] = {}
if type_ids:
for t in (
db.query(BizCellSampleType)
.filter(
BizCellSampleType.id.in_(type_ids),
BizCellSampleType.del_flag == 0,
)
.all()
):
type_map[t.id] = t.type_name or ""
express_ids = list(
{tr.express_company_id for *_, tr in rows if tr and tr.express_company_id}
)
express_map: Dict[str, str] = {}
if express_ids:
for e in (
db.query(BizExpressCompany)
.filter(BizExpressCompany.id.in_(express_ids), BizExpressCompany.del_flag == 0)
.all()
):
express_map[e.id] = e.express_name or ""
reception_ids = (
[reception_map[s.id].id for s, *_ in rows if s.id in reception_map]
if reception_map
else []
)
results_map = (
check_result_svc.list_results_by_reception_ids(db, reception_ids, tenant_no)
if reception_ids
else {}
)
items: List[Dict[str, Any]] = []
for sample, donation, party, transport in rows:
item: Dict[str, Any] = {
"protocolSampleId": sample.id,
"collectionProtocolId": donation.id,
"protocolNo": donation.donation_no or "",
"sampleCode": sample.sample_code or "",
"sampleTypeId": sample.sample_type_id or "",
"sampleTypeName": type_map.get(sample.sample_type_id or "", ""),
"collectAmount": _dec(sample.collect_amount),
"motherName": (party.mother_name if party else "") or "",
"newbornName": (party.newborn_name if party else "") or "",
"sourceType": "research_donation",
"sourceTypeLabel": "科研捐赠",
"etaTime": _fmt_dt(transport.eta_time) if transport and transport.eta_time else "",
"transportType": (transport.transport_type if transport else "") or "",
"waybillNo": (transport.waybill_no if transport else "") or "",
"expressCompanyId": (transport.express_company_id if transport else "") or "",
"expressCompanyName": express_map.get(
(transport.express_company_id if transport else "") or "", ""
),
"carrierName": (transport.carrier_name if transport else "") or "",
"carrierPhone": (transport.carrier_phone if transport else "") or "",
}
if reception_map and sample.id in reception_map:
rec = reception_map[sample.id]
cr = results_map.get(rec.id)
if not cr:
cr = check_result_svc.get_check_results_for_reception(db, rec, tenant_no)
item.update(_reception_to_dict(rec, check_results=cr))
item["receiveAttachmentFiles"] = urls_to_attachment_list(
rec.receive_attachments, db, tenant_no
)
items.append(item)
return items
def _sample_pending_query(db: Session, tenant_no: str, keyword: Optional[str] = None):
"""待接收:协议样本且尚无有效接收记录。"""
received_ids = (
db.query(BizSampleReception.protocol_sample_id)
.filter(
BizSampleReception.tenant_no == tenant_no,
BizSampleReception.del_flag == 0,
)
.subquery()
)
q = _sample_detail_rows_query(db).filter(
BizProtocolSample.del_flag == 0,
BizProtocolSample.tenant_no == tenant_no,
BizCollectionProtocol.tenant_no == tenant_no,
~BizProtocolSample.id.in_(received_ids),
)
if keyword and keyword.strip():
kw = f"%{keyword.strip()}%"
q = q.filter(
or_(
BizCollectionProtocol.protocol_no.like(kw),
BizProtocolSample.sample_code.like(kw),
BizProtocolPartyCustomer.mother_name.like(kw),
BizProtocolPartyCustomer.newborn_name.like(kw),
)
)
return q
def _rows_to_sample_list_items(
db: Session,
rows: list,
tenant_no: str,
*,
reception_map: Optional[Dict[str, BizSampleReception]] = None,
) -> List[Dict[str, Any]]:
type_ids = list({s.sample_type_id for s, *_ in rows if s.sample_type_id})
type_map: Dict[str, str] = {}
if type_ids:
for t in (
db.query(BizCellSampleType)
.filter(
BizCellSampleType.id.in_(type_ids),
BizCellSampleType.del_flag == 0,
)
.all()
):
type_map[t.id] = t.type_name or ""
express_ids = list(
{tr.express_company_id for *_, tr in rows if tr and tr.express_company_id}
)
express_map: Dict[str, str] = {}
if express_ids:
for e in (
db.query(BizExpressCompany)
.filter(BizExpressCompany.id.in_(express_ids), BizExpressCompany.del_flag == 0)
.all()
):
express_map[e.id] = e.express_name or ""
reception_ids = (
[reception_map[s.id].id for s, *_ in rows if s.id in reception_map]
if reception_map
else []
)
results_map = (
check_result_svc.list_results_by_reception_ids(db, reception_ids, tenant_no)
if reception_ids
else {}
)
items: List[Dict[str, Any]] = []
for sample, protocol, party, transport in rows:
item: Dict[str, Any] = {
"protocolSampleId": sample.id,
"collectionProtocolId": protocol.id,
"protocolNo": protocol.protocol_no or "",
"protocolStatus": protocol.protocol_status or "",
"sampleCode": sample.sample_code or "",
"sampleTypeId": sample.sample_type_id or "",
"sampleTypeName": type_map.get(sample.sample_type_id or "", ""),
"collectAmount": _dec(sample.collect_amount),
"sampleStatus": sample.sample_status or "",
"motherName": (party.mother_name if party else "") or "",
"newbornName": (party.newborn_name if party else "") or "",
"etaTime": _fmt_dt(transport.eta_time) if transport and transport.eta_time else "",
"transportType": (transport.transport_type if transport else "") or "",
"waybillNo": (transport.waybill_no if transport else "") or "",
"expressCompanyId": (transport.express_company_id if transport else "") or "",
"expressCompanyName": express_map.get(
(transport.express_company_id if transport else "") or "", ""
),
"carrierName": (transport.carrier_name if transport else "") or "",
"carrierPhone": (transport.carrier_phone if transport else "") or "",
"sourceType": "cell_storage",
"sourceTypeLabel": "细胞存储",
}
if reception_map and sample.id in reception_map:
rec = reception_map[sample.id]
cr = results_map.get(rec.id)
if not cr:
cr = check_result_svc.get_check_results_for_reception(db, rec, tenant_no)
item.update(_reception_to_dict(rec, check_results=cr))
item["receiveAttachmentFiles"] = urls_to_attachment_list(
rec.receive_attachments, db, tenant_no
)
items.append(item)
return items
def list_pending_protocol_samples(
db: Session,
*,
page: int = 1,
page_size: int = 10,
tenant_no: Optional[str] = None,
keyword: Optional[str] = None,
source_type: Optional[str] = None,
) -> Tuple[List[Dict[str, Any]], int]:
if not tenant_no:
return [], 0
# 收集两种来源的样本
all_items: List[Dict[str, Any]] = []
if not source_type or source_type == "cell_storage":
q_base = _sample_pending_query(db, tenant_no, keyword)
cell_total = q_base.order_by(None).with_entities(func.count(BizProtocolSample.id)).scalar() or 0
cell_rows = (
q_base.order_by(
BizProtocolSampleTransport.eta_time.is_(None),
BizProtocolSampleTransport.eta_time.asc(),
BizProtocolSample.create_time.asc(),
)
.all()
)
all_items.extend(_rows_to_sample_list_items(db, cell_rows, tenant_no))
else:
cell_total = 0
if not source_type or source_type == "research_donation":
q_donation = _donation_sample_pending_query(db, tenant_no, keyword)
donation_total = q_donation.order_by(None).with_entities(func.count(BizResearchDonationSample.id)).scalar() or 0
donation_rows = (
q_donation.order_by(
BizResearchDonationSampleTransport.eta_time.is_(None),
BizResearchDonationSampleTransport.eta_time.asc(),
BizResearchDonationSample.create_time.asc(),
)
.all()
)
all_items.extend(_donation_rows_to_sample_list_items(db, donation_rows, tenant_no))
else:
donation_total = 0
# 统一按 etaTime 排序(空值排后)
all_items.sort(key=lambda x: (not x.get("etaTime"), x.get("etaTime") or ""))
total = cell_total + donation_total
page = max(1, page)
page_size = min(max(1, page_size), 100)
start = (page - 1) * page_size
page_items = all_items[start:start + page_size]
return page_items, int(total)
def list_received_protocol_samples(
db: Session,
*,
page: int = 1,
page_size: int = 10,
tenant_no: Optional[str] = None,
keyword: Optional[str] = None,
source_type: Optional[str] = None,
) -> Tuple[List[Dict[str, Any]], int]:
if not tenant_no:
return [], 0
# 查询所有接收记录,按 source_type 过滤
q_rec = db.query(BizSampleReception).filter(
BizSampleReception.tenant_no == tenant_no,
BizSampleReception.del_flag == 0,
)
if source_type:
q_rec = q_rec.filter(BizSampleReception.reception_source == source_type)
# 关键词搜索
if keyword and keyword.strip():
kw = f"%{keyword.strip()}%"
# 细胞存储样本关键词
cell_sample_ids_kw = (
_sample_detail_rows_query(db)
.with_entities(BizProtocolSample.id)
.filter(
BizProtocolSample.del_flag == 0,
BizProtocolSample.tenant_no == tenant_no,
BizCollectionProtocol.tenant_no == tenant_no,
or_(
BizCollectionProtocol.protocol_no.like(kw),
BizProtocolSample.sample_code.like(kw),
BizProtocolPartyCustomer.mother_name.like(kw),
BizProtocolPartyCustomer.newborn_name.like(kw),
),
)
.subquery()
)
# 捐赠样本关键词
donation_sample_ids_kw = (
_donation_sample_detail_rows_query(db)
.with_entities(_donation_sample_id_col(BizResearchDonationSample.id))
.filter(
BizResearchDonationSample.del_flag == 0,
BizResearchDonationSample.tenant_no == tenant_no,
BizResearchDonation.tenant_no == tenant_no,
or_(
BizResearchDonation.donation_no.like(kw),
BizResearchDonationSample.sample_code.like(kw),
BizResearchDonationParty.mother_name.like(kw),
BizResearchDonationParty.newborn_name.like(kw),
),
)
.subquery()
)
q_rec = q_rec.filter(
or_(
BizSampleReception.handler_name.like(kw),
BizSampleReception.protocol_sample_id.in_(cell_sample_ids_kw),
BizSampleReception.donation_sample_id.in_(donation_sample_ids_kw),
)
)
total = q_rec.count()
page = max(1, page)
page_size = min(max(1, page_size), 100)
receptions = (
q_rec.order_by(BizSampleReception.reception_time.desc())
.offset((page - 1) * page_size)
.limit(page_size)
.all()
)
if not receptions:
return [], int(total)
# 按 reception_source 分组查询详情
cell_receptions = [r for r in receptions if r.reception_source == "cell_storage"]
donation_receptions = [r for r in receptions if r.reception_source == "research_donation"]
items: List[Dict[str, Any]] = []
if cell_receptions:
cell_sample_ids = [r.protocol_sample_id for r in cell_receptions]
cell_reception_map = {r.protocol_sample_id: r for r in cell_receptions}
cell_rows = (
_sample_detail_rows_query(db)
.filter(BizProtocolSample.id.in_(cell_sample_ids))
.all()
)
cell_row_by_sample = {row[0].id: row for row in cell_rows}
cell_ordered = [cell_row_by_sample[sid] for sid in cell_sample_ids if sid in cell_row_by_sample]
items.extend(_rows_to_sample_list_items(db, cell_ordered, tenant_no, reception_map=cell_reception_map))
if donation_receptions:
donation_sample_ids = [r.donation_sample_id for r in donation_receptions]
donation_reception_map = {r.donation_sample_id: r for r in donation_receptions}
donation_rows = (
_donation_sample_detail_rows_query(db)
.filter(_donation_sample_id_col(BizResearchDonationSample.id).in_(donation_sample_ids))
.all()
)
donation_row_by_sample = {row[0].id: row for row in donation_rows}
donation_ordered = [donation_row_by_sample[sid] for sid in donation_sample_ids if sid in donation_row_by_sample]
items.extend(_donation_rows_to_sample_list_items(db, donation_ordered, tenant_no, reception_map=donation_reception_map))
# 按 reception_time DESC 排序
items.sort(key=lambda x: x.get("receptionTime") or "", reverse=True)
return items, int(total)
def get_reception_by_id(
db: Session, reception_id: str, tenant_no: str
) -> Optional[Dict[str, Any]]:
rec = (
db.query(BizSampleReception)
.filter(
BizSampleReception.id == reception_id,
BizSampleReception.tenant_no == tenant_no,
BizSampleReception.del_flag == 0,
)
.first()
)
if not rec:
return None
if (rec.reception_source or "cell_storage") == "research_donation":
dsid = rec.donation_sample_id or ""
if not dsid:
cr = check_result_svc.get_check_results_for_reception(db, rec, tenant_no)
out = _reception_to_dict(rec, check_results=cr)
out["sourceType"] = "research_donation"
out["sourceTypeLabel"] = "科研捐赠"
out["receiveAttachmentFiles"] = urls_to_attachment_list(
rec.receive_attachments, db, tenant_no
)
return out
rows = (
_donation_sample_detail_rows_query(db)
.filter(_donation_sample_id_col(BizResearchDonationSample.id) == dsid)
.all()
)
if not rows:
cr = check_result_svc.get_check_results_for_reception(db, rec, tenant_no)
out = _reception_to_dict(rec, check_results=cr)
out["sourceType"] = "research_donation"
out["sourceTypeLabel"] = "科研捐赠"
out["receiveAttachmentFiles"] = urls_to_attachment_list(
rec.receive_attachments, db, tenant_no
)
return out
items = _donation_rows_to_sample_list_items(
db, rows, tenant_no, reception_map={dsid: rec}
)
return items[0] if items else None
sample = (
db.query(BizProtocolSample)
.filter(
BizProtocolSample.id == rec.protocol_sample_id,
BizProtocolSample.del_flag == 0,
)
.first()
)
if not sample:
cr = check_result_svc.get_check_results_for_reception(db, rec, tenant_no)
out = _reception_to_dict(rec, check_results=cr)
out["receiveAttachmentFiles"] = urls_to_attachment_list(
rec.receive_attachments, db, tenant_no
)
return out
rows = (
_sample_detail_rows_query(db)
.filter(BizProtocolSample.id == sample.id)
.all()
)
if not rows:
cr = check_result_svc.get_check_results_for_reception(db, rec, tenant_no)
out = _reception_to_dict(rec, check_results=cr)
out["receiveAttachmentFiles"] = urls_to_attachment_list(
rec.receive_attachments, db, tenant_no
)
return out
items = _rows_to_sample_list_items(
db, rows, tenant_no, reception_map={rec.protocol_sample_id: rec}
)
return items[0] if items else _reception_to_dict(rec)
def create_sample_reception(
db: Session,
*,
reception_source: str = "cell_storage",
protocol_sample_id: Optional[str] = None,
donation_sample_id: Optional[str] = None,
research_donation_id: Optional[str] = None,
tenant_no: str,
user_id: Optional[str],
create_dept_id: str = "",
reception_time: datetime,
handler_user_id: Optional[str],
handler_name: Optional[str],
receive_temperature: Optional[str],
volume_ml: Optional[float] = None,
net_weight_g: Optional[float] = None,
checks: List[Dict[str, Any]],
accept_conclusion: str,
receive_attachments: Optional[str],
remark: Optional[str],
) -> BizSampleReception:
source = (reception_source or "").strip()
if source not in ("cell_storage", "research_donation"):
raise ValueError("来源类型无效")
# 按来源校验样本并获取关联 ID
if source == "cell_storage":
if not protocol_sample_id:
raise ValueError("细胞存储来源必须传入 protocolSampleId")
sample = (
db.query(BizProtocolSample)
.filter(
BizProtocolSample.id == protocol_sample_id,
BizProtocolSample.tenant_no == tenant_no,
BizProtocolSample.del_flag == 0,
)
.first()
)
if not sample:
raise ValueError("样本不存在")
exists = (
db.query(BizSampleReception)
.filter(
BizSampleReception.protocol_sample_id == protocol_sample_id,
BizSampleReception.tenant_no == tenant_no,
BizSampleReception.del_flag == 0,
)
.first()
)
if exists:
raise ValueError("该样本已登记接收,请勿重复操作")
collection_protocol_id = sample.collection_protocol_id
_donation_sample_id = None
_research_donation_id = None
_sample_code = sample.sample_code or ""
else:
# research_donation
if not donation_sample_id:
raise ValueError("科研捐赠来源必须传入 donationSampleId")
dsample = (
db.query(BizResearchDonationSample)
.filter(
_donation_sample_id_col(BizResearchDonationSample.id) == donation_sample_id,
BizResearchDonationSample.tenant_no == tenant_no,
BizResearchDonationSample.del_flag == 0,
)
.first()
)
if not dsample:
raise ValueError("捐赠样本不存在")
exists = (
db.query(BizSampleReception)
.filter(
BizSampleReception.donation_sample_id == donation_sample_id,
BizSampleReception.tenant_no == tenant_no,
BizSampleReception.del_flag == 0,
)
.first()
)
if exists:
raise ValueError("该捐赠样本已登记接收,请勿重复操作")
collection_protocol_id = ""
protocol_sample_id = ""
_donation_sample_id = donation_sample_id
_research_donation_id = dsample.research_donation_id
_sample_code = dsample.sample_code or ""
conclusion = (accept_conclusion or "").strip()
if conclusion not in ("js", "bj"):
raise ValueError("接收结论无效")
handler_display = (handler_name or "").strip()
if handler_user_id and not handler_display:
u = db.query(SysUser).filter(SysUser.id == handler_user_id).first()
if u:
handler_display = u.nick_name or ""
obj = BizSampleReception(
id=generate_uuid(),
protocol_sample_id=protocol_sample_id or "",
collection_protocol_id=collection_protocol_id or "",
reception_source=source,
donation_sample_id=_donation_sample_id,
research_donation_id=_research_donation_id,
sample_code=_sample_code or None,
reception_time=reception_time,
handler_user_id=handler_user_id,
handler_name=handler_display or None,
receive_temperature=(receive_temperature or "").strip() or None,
volume_ml=volume_ml,
net_weight_g=net_weight_g,
check_packaging=0,
check_sealing=0,
check_no_damage=0,
check_no_leakage=0,
check_color=0,
check_tying_rope=0,
check_no_stratification=0,
accept_conclusion=conclusion,
receive_attachments=(receive_attachments or "").strip() or None,
tenant_no=tenant_no,
remark=(remark or "").strip() or None,
create_by=user_id,
create_dept_id=create_dept_id or "",
update_by=user_id,
)
db.add(obj)
db.flush()
check_result_svc.save_reception_check_results(
db,
reception_id=obj.id,
tenant_no=tenant_no,
user_id=user_id,
create_dept_id=create_dept_id or "",
checks=checks,
)
from app.models.models import BizSampleReceptionCheckResult
saved_rows = (
db.query(BizSampleReceptionCheckResult)
.filter(
BizSampleReceptionCheckResult.reception_id == obj.id,
BizSampleReceptionCheckResult.del_flag == 0,
)
.all()
)
check_result_svc.sync_legacy_columns_from_results(db, obj, saved_rows)
db.add(obj)
if conclusion == "js":
from app.crud import qc_work_order as qc_wo_svc
qc_wo_svc.create_work_order_from_reception(
db,
reception=obj,
tenant_no=tenant_no,
user_id=user_id,
create_dept_id=create_dept_id or "",
)
from app.crud import production_work_order as prod_wo_svc
prod_wo_svc.create_production_work_order_from_reception(
db,
reception=obj,
tenant_no=tenant_no,
user_id=user_id,
create_dept_id=create_dept_id or "",
)
db.commit()
db.refresh(obj)
return obj
def get_receptions_map_for_samples(
db: Session,
sample_ids: List[str],
tenant_no: str,
) -> Dict[str, Dict[str, Any]]:
"""按协议样本 ID 批量查询接收记录(含检查项明细、附件列表),供协议单查看弹窗使用。"""
if not sample_ids or not tenant_no:
return {}
rows = (
db.query(BizSampleReception)
.filter(
BizSampleReception.protocol_sample_id.in_(sample_ids),
BizSampleReception.tenant_no == tenant_no,
BizSampleReception.del_flag == 0,
)
.all()
)
if not rows:
return {}
reception_ids = [r.id for r in rows]
results_map = check_result_svc.list_results_by_reception_ids(db, reception_ids, tenant_no)
out: Dict[str, Dict[str, Any]] = {}
for rec in rows:
cr = results_map.get(rec.id)
if not cr:
cr = check_result_svc.get_check_results_for_reception(db, rec, tenant_no)
item = _reception_to_dict(rec, check_results=cr)
item["receiveAttachmentFiles"] = urls_to_attachment_list(
rec.receive_attachments, db, tenant_no
)
out[rec.protocol_sample_id] = item
return out
def get_receptions_map_for_donation_samples(
db: Session,
sample_ids: List[str],
tenant_no: str,
) -> Dict[str, Dict[str, Any]]:
"""按捐赠样本 ID 批量查询接收记录,供捐赠协议单查看弹窗使用。"""
if not sample_ids or not tenant_no:
return {}
rows = (
db.query(BizSampleReception)
.filter(
BizSampleReception.donation_sample_id.in_(sample_ids),
BizSampleReception.tenant_no == tenant_no,
BizSampleReception.del_flag == 0,
)
.all()
)
if not rows:
return {}
reception_ids = [r.id for r in rows]
results_map = check_result_svc.list_results_by_reception_ids(db, reception_ids, tenant_no)
out: Dict[str, Dict[str, Any]] = {}
for rec in rows:
sid = rec.donation_sample_id
if not sid:
continue
cr = results_map.get(rec.id)
if not cr:
cr = check_result_svc.get_check_results_for_reception(db, rec, tenant_no)
item = _reception_to_dict(rec, check_results=cr)
item["receiveAttachmentFiles"] = urls_to_attachment_list(
rec.receive_attachments, db, tenant_no
)
out[sid] = item
return out