protocol_sample_list_summary.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. """协议/捐赠列表卡片:按样本编码批量取接收结论与门禁质检结论(轻量字段)。"""
  2. from __future__ import annotations
  3. from collections import defaultdict
  4. from typing import Any, Dict, List, Optional
  5. from sqlalchemy.orm import Session
  6. from app.models.models import BizQcTask, BizQcWorkOrder, BizSampleReception
  7. from app.services.qc_work_order_conclusion import (
  8. build_qc_conclusion_fields,
  9. work_order_qc_conclusion_label,
  10. )
  11. _ACCEPT_CONCLUSION_LABELS = {"js": "接收", "bj": "拒收"}
  12. _VALID_QC_CONCLUSIONS = frozenset({"tg", "btg"})
  13. def build_sample_item_reception_qc_fields(
  14. reception: Optional[Dict[str, Any]],
  15. qc: Optional[Dict[str, Any]],
  16. ) -> Dict[str, Any]:
  17. """合并接收/质检结论摘要为列表 sampleItems 字段。"""
  18. conclusion = ""
  19. remark = ""
  20. if reception:
  21. conclusion = (reception.get("acceptConclusion") or "").strip()
  22. remark = (reception.get("remark") or "").strip()
  23. qc_code = ""
  24. qc_label = ""
  25. if qc:
  26. qc_code = (qc.get("qcConclusion") or "").strip()
  27. qc_label = (qc.get("qcConclusionLabel") or "").strip()
  28. if qc_code and not qc_label:
  29. qc_label = work_order_qc_conclusion_label(qc_code)
  30. return {
  31. "receptionAcceptConclusion": conclusion,
  32. "receptionAcceptConclusionLabel": _ACCEPT_CONCLUSION_LABELS.get(conclusion, ""),
  33. "receptionRemark": remark,
  34. "qcConclusion": qc_code,
  35. "qcConclusionLabel": qc_label,
  36. }
  37. def get_list_reception_summary_map_by_sample_codes(
  38. db: Session,
  39. tenant_no: str,
  40. sample_codes: List[str],
  41. *,
  42. reception_source: str,
  43. ) -> Dict[str, Dict[str, str]]:
  44. """按租户 + 样本编码 + 来源返回接收摘要(acceptConclusion / remark),同码取首条。"""
  45. codes = list({(c or "").strip() for c in sample_codes if (c or "").strip()})
  46. if not tenant_no or not codes or not (reception_source or "").strip():
  47. return {}
  48. rows = (
  49. db.query(BizSampleReception)
  50. .filter(
  51. BizSampleReception.tenant_no == tenant_no,
  52. BizSampleReception.del_flag == 0,
  53. BizSampleReception.reception_source == reception_source,
  54. BizSampleReception.sample_code.in_(codes),
  55. )
  56. .all()
  57. )
  58. out: Dict[str, Dict[str, str]] = {}
  59. for rec in rows:
  60. code = (rec.sample_code or "").strip()
  61. if not code or code in out:
  62. continue
  63. out[code] = {
  64. "acceptConclusion": (rec.accept_conclusion or "").strip(),
  65. "remark": (rec.remark or "").strip(),
  66. }
  67. return out
  68. def get_list_qc_conclusion_map_by_sample_codes(
  69. db: Session,
  70. tenant_no: str,
  71. sample_codes: List[str],
  72. *,
  73. reception_source: str,
  74. ) -> Dict[str, Dict[str, str]]:
  75. """按租户 + 样本编码 + 来源返回门禁质检结论(优先工单落库,否则由任务派生)。"""
  76. codes = list({(c or "").strip() for c in sample_codes if (c or "").strip()})
  77. if not tenant_no or not codes or not (reception_source or "").strip():
  78. return {}
  79. rows = (
  80. db.query(BizQcWorkOrder)
  81. .filter(
  82. BizQcWorkOrder.tenant_no == tenant_no,
  83. BizQcWorkOrder.del_flag == 0,
  84. BizQcWorkOrder.reception_source == reception_source,
  85. BizQcWorkOrder.trigger_source == "reception",
  86. BizQcWorkOrder.sample_code.in_(codes),
  87. )
  88. .all()
  89. )
  90. code_to_wo: Dict[str, BizQcWorkOrder] = {}
  91. for wo in rows:
  92. code = (wo.sample_code or "").strip()
  93. if code and code not in code_to_wo:
  94. code_to_wo[code] = wo
  95. need_derive_ids: List[str] = []
  96. for wo in code_to_wo.values():
  97. stored = (getattr(wo, "conclusion", None) or "").strip()
  98. if stored not in _VALID_QC_CONCLUSIONS:
  99. wid = (wo.id or "").strip()
  100. if wid:
  101. need_derive_ids.append(wid)
  102. conclusions_by_wo: Dict[str, List[Optional[str]]] = defaultdict(list)
  103. if need_derive_ids:
  104. task_rows = (
  105. db.query(BizQcTask.work_order_id, BizQcTask.conclusion)
  106. .filter(
  107. BizQcTask.del_flag == 0,
  108. BizQcTask.work_order_id.in_(need_derive_ids),
  109. )
  110. .all()
  111. )
  112. for wo_id, conc in task_rows:
  113. wid = (wo_id or "").strip()
  114. if wid:
  115. conclusions_by_wo[wid].append(conc)
  116. out: Dict[str, Dict[str, str]] = {}
  117. for code, wo in code_to_wo.items():
  118. stored = (getattr(wo, "conclusion", None) or "").strip()
  119. if stored in _VALID_QC_CONCLUSIONS:
  120. out[code] = {
  121. "qcConclusion": stored,
  122. "qcConclusionLabel": work_order_qc_conclusion_label(stored),
  123. }
  124. continue
  125. wid = (wo.id or "").strip()
  126. fields = build_qc_conclusion_fields(conclusions_by_wo.get(wid, []))
  127. out[code] = {
  128. "qcConclusion": fields["qcConclusion"],
  129. "qcConclusionLabel": fields["qcConclusionLabel"],
  130. }
  131. return out
  132. # 兼容旧调用名
  133. def get_list_qc_status_map_by_sample_codes(
  134. db: Session,
  135. tenant_no: str,
  136. sample_codes: List[str],
  137. *,
  138. reception_source: str,
  139. ) -> Dict[str, Dict[str, str]]:
  140. return get_list_qc_conclusion_map_by_sample_codes(
  141. db, tenant_no, sample_codes, reception_source=reception_source
  142. )