"""协议/捐赠列表卡片:按样本编码批量取接收结论与门禁质检结论(轻量字段)。""" 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 )