| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- """协议/捐赠列表卡片:按样本编码批量取接收结论与门禁质检结论(轻量字段)。"""
- from __future__ import annotations
- from collections import defaultdict
- from typing import Any, Dict, List, Optional
- from sqlalchemy.orm import Session
- from app.models.models import BizQcTask, BizQcWorkOrder, BizSampleReception
- from app.services.qc_work_order_conclusion import (
- build_qc_conclusion_fields,
- work_order_qc_conclusion_label,
- )
- _ACCEPT_CONCLUSION_LABELS = {"js": "接收", "bj": "拒收"}
- _VALID_QC_CONCLUSIONS = frozenset({"tg", "btg"})
- _QC_WORK_ORDER_STATUS_LABELS = {
- "dpz": "待配置",
- "ypz": "已配置",
- "ywc": "已完成",
- "yzf": "已作废",
- }
- def empty_gate_qc_summary_fields() -> Dict[str, str]:
- return {
- "qcWorkOrderNo": "",
- "qcWorkOrderStatus": "",
- "qcWorkOrderStatusLabel": "",
- "qcConclusion": "",
- "qcConclusionLabel": "",
- }
- def _empty_gate_qc_summary_fields() -> Dict[str, str]:
- return empty_gate_qc_summary_fields()
- def _load_derived_qc_conclusions_by_work_order_ids(
- db: Session,
- work_order_ids: List[str],
- ) -> Dict[str, List[Optional[str]]]:
- conclusions_by_wo: Dict[str, List[Optional[str]]] = defaultdict(list)
- ids = list({(i or "").strip() for i in work_order_ids if (i or "").strip()})
- if not ids:
- return conclusions_by_wo
- task_rows = (
- db.query(BizQcTask.work_order_id, BizQcTask.conclusion)
- .filter(
- BizQcTask.del_flag == 0,
- BizQcTask.work_order_id.in_(ids),
- )
- .all()
- )
- for wo_id, conc in task_rows:
- wid = (wo_id or "").strip()
- if wid:
- conclusions_by_wo[wid].append(conc)
- return conclusions_by_wo
- def _build_gate_qc_summary_fields(
- wo: BizQcWorkOrder,
- conclusions_by_wo: Dict[str, List[Optional[str]]],
- ) -> Dict[str, str]:
- stored = (getattr(wo, "conclusion", None) or "").strip()
- if stored in _VALID_QC_CONCLUSIONS:
- qc_conclusion = stored
- qc_label = work_order_qc_conclusion_label(stored)
- else:
- wid = (wo.id or "").strip()
- fields = build_qc_conclusion_fields(conclusions_by_wo.get(wid, []))
- qc_conclusion = fields["qcConclusion"]
- qc_label = fields["qcConclusionLabel"]
- status = (wo.work_order_status or "").strip()
- return {
- "qcWorkOrderNo": (wo.work_order_no or "").strip(),
- "qcWorkOrderStatus": status,
- "qcWorkOrderStatusLabel": _QC_WORK_ORDER_STATUS_LABELS.get(status, status),
- "qcConclusion": qc_conclusion,
- "qcConclusionLabel": qc_label,
- }
- def _build_gate_qc_summaries_for_work_orders(
- db: Session,
- work_orders: List[BizQcWorkOrder],
- ) -> Dict[str, Dict[str, str]]:
- if not work_orders:
- return {}
- need_derive_ids: List[str] = []
- for wo in work_orders:
- stored = (getattr(wo, "conclusion", None) or "").strip()
- if stored not in _VALID_QC_CONCLUSIONS:
- wid = (wo.id or "").strip()
- if wid:
- need_derive_ids.append(wid)
- conclusions_by_wo = _load_derived_qc_conclusions_by_work_order_ids(db, need_derive_ids)
- out: Dict[str, Dict[str, str]] = {}
- for wo in work_orders:
- wid = (wo.id or "").strip()
- if wid:
- out[wid] = _build_gate_qc_summary_fields(wo, conclusions_by_wo)
- return out
- def build_sample_item_reception_qc_fields(
- reception: Optional[Dict[str, Any]],
- qc: Optional[Dict[str, Any]],
- ) -> Dict[str, Any]:
- """合并接收/质检结论摘要为列表 sampleItems 字段。"""
- conclusion = ""
- remark = ""
- if reception:
- conclusion = (reception.get("acceptConclusion") or "").strip()
- remark = (reception.get("remark") or "").strip()
- qc_code = ""
- qc_label = ""
- if qc:
- qc_code = (qc.get("qcConclusion") or "").strip()
- qc_label = (qc.get("qcConclusionLabel") or "").strip()
- if qc_code and not qc_label:
- qc_label = work_order_qc_conclusion_label(qc_code)
- return {
- "receptionAcceptConclusion": conclusion,
- "receptionAcceptConclusionLabel": _ACCEPT_CONCLUSION_LABELS.get(conclusion, ""),
- "receptionRemark": remark,
- "qcConclusion": qc_code,
- "qcConclusionLabel": qc_label,
- }
- def get_list_reception_summary_map_by_sample_codes(
- db: Session,
- tenant_no: str,
- sample_codes: List[str],
- *,
- reception_source: str,
- ) -> Dict[str, Dict[str, str]]:
- """按租户 + 样本编码 + 来源返回接收摘要(acceptConclusion / remark),同码取首条。"""
- codes = list({(c or "").strip() for c in sample_codes if (c or "").strip()})
- if not tenant_no or not codes or not (reception_source or "").strip():
- return {}
- rows = (
- db.query(BizSampleReception)
- .filter(
- BizSampleReception.tenant_no == tenant_no,
- BizSampleReception.del_flag == 0,
- BizSampleReception.reception_source == reception_source,
- BizSampleReception.sample_code.in_(codes),
- )
- .all()
- )
- out: Dict[str, Dict[str, str]] = {}
- for rec in rows:
- code = (rec.sample_code or "").strip()
- if not code:
- continue
- prev = out.get(code)
- prev_t = prev.get("_receptionTime") if prev else None
- rec_t = rec.reception_time
- if prev and rec_t and prev_t and rec_t <= prev_t:
- continue
- if prev and rec_t is None and prev_t is not None:
- continue
- out[code] = {
- "acceptConclusion": (rec.accept_conclusion or "").strip(),
- "remark": (rec.remark or "").strip(),
- "receptionTime": rec_t.strftime("%Y-%m-%d %H:%M:%S") if rec_t else "",
- "_receptionTime": rec_t,
- }
- for v in out.values():
- v.pop("_receptionTime", None)
- return out
- def get_list_gate_qc_summary_map_by_reception_ids(
- db: Session,
- tenant_no: str,
- reception_ids: List[str],
- ) -> Dict[str, Dict[str, str]]:
- """按 reception_id 批量返回样本接收触发的门禁质检摘要(工单号、状态、结论)。"""
- ids = list({(i or "").strip() for i in reception_ids if (i or "").strip()})
- if not tenant_no or not ids:
- return {}
- rows = (
- db.query(BizQcWorkOrder)
- .filter(
- BizQcWorkOrder.tenant_no == tenant_no,
- BizQcWorkOrder.del_flag == 0,
- BizQcWorkOrder.trigger_source == "reception",
- BizQcWorkOrder.reception_id.in_(ids),
- )
- .all()
- )
- summaries_by_wo_id = _build_gate_qc_summaries_for_work_orders(db, rows)
- out: Dict[str, Dict[str, str]] = {}
- for wo in rows:
- rid = (wo.reception_id or "").strip()
- wid = (wo.id or "").strip()
- if not rid or rid in out or not wid:
- continue
- out[rid] = summaries_by_wo_id.get(wid) or _empty_gate_qc_summary_fields()
- return out
- def get_list_qc_conclusion_map_by_sample_codes(
- db: Session,
- tenant_no: str,
- sample_codes: List[str],
- *,
- reception_source: str,
- ) -> Dict[str, Dict[str, str]]:
- """按租户 + 样本编码 + 来源返回门禁质检摘要(工单号、状态、结论)。"""
- codes = list({(c or "").strip() for c in sample_codes if (c or "").strip()})
- if not tenant_no or not codes or not (reception_source or "").strip():
- return {}
- rows = (
- db.query(BizQcWorkOrder)
- .filter(
- BizQcWorkOrder.tenant_no == tenant_no,
- BizQcWorkOrder.del_flag == 0,
- BizQcWorkOrder.reception_source == reception_source,
- BizQcWorkOrder.trigger_source == "reception",
- BizQcWorkOrder.sample_code.in_(codes),
- )
- .all()
- )
- code_to_wo: Dict[str, BizQcWorkOrder] = {}
- for wo in rows:
- code = (wo.sample_code or "").strip()
- if code and code not in code_to_wo:
- code_to_wo[code] = wo
- summaries_by_wo_id = _build_gate_qc_summaries_for_work_orders(db, list(code_to_wo.values()))
- out: Dict[str, Dict[str, str]] = {}
- for code, wo in code_to_wo.items():
- wid = (wo.id or "").strip()
- out[code] = summaries_by_wo_id.get(wid) or _empty_gate_qc_summary_fields()
- return out
- # 兼容旧调用名
- def get_list_qc_status_map_by_sample_codes(
- db: Session,
- tenant_no: str,
- sample_codes: List[str],
- *,
- reception_source: str,
- ) -> Dict[str, Dict[str, str]]:
- return get_list_qc_conclusion_map_by_sample_codes(
- db, tenant_no, sample_codes, reception_source=reception_source
- )
|