sample_info_list_enrich.py 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. """样本信息列表:批量补进度标识(接收/质检/入库/证保险)与客户服务宽表字段。"""
  2. from __future__ import annotations
  3. from datetime import datetime
  4. from typing import Any, Dict, List, Optional
  5. from sqlalchemy.orm import Session
  6. from app.crud import sample_customer_service as sample_cs_crud
  7. from app.crud import sample_insurance as sample_insurance_crud
  8. from app.crud import sample_storage_cert as sample_storage_cert_crud
  9. from app.models.models import BizStorageReleaseReview, SysUser
  10. from app.services.protocol_sample_list_summary import (
  11. get_list_qc_conclusion_map_by_sample_codes,
  12. get_list_reception_summary_map_by_sample_codes,
  13. )
  14. from app.services.sample_info_progress import (
  15. collection_progress,
  16. insurance_handled,
  17. qc_progress,
  18. reception_progress,
  19. storage_cert_handled,
  20. storage_progress,
  21. )
  22. def _fmt_dt(t: Optional[datetime]) -> str:
  23. return t.strftime("%Y-%m-%d %H:%M:%S") if t else ""
  24. def _has_urls(raw: Optional[str]) -> bool:
  25. return bool((raw or "").strip())
  26. def get_storage_review_map_by_sample_codes(
  27. db: Session,
  28. tenant_no: str,
  29. sample_codes: List[str],
  30. *,
  31. reception_source: str,
  32. ) -> Dict[str, Dict[str, str]]:
  33. codes = list({(c or "").strip() for c in sample_codes if (c or "").strip()})
  34. if not tenant_no or not codes or not (reception_source or "").strip():
  35. return {}
  36. rows = (
  37. db.query(BizStorageReleaseReview)
  38. .filter(
  39. BizStorageReleaseReview.tenant_no == tenant_no,
  40. BizStorageReleaseReview.del_flag == 0,
  41. BizStorageReleaseReview.reception_source == reception_source,
  42. BizStorageReleaseReview.sample_code.in_(codes),
  43. )
  44. .all()
  45. )
  46. out: Dict[str, Dict[str, Any]] = {}
  47. for rev in rows:
  48. code = (rev.sample_code or "").strip()
  49. if not code:
  50. continue
  51. prev = out.get(code)
  52. prev_t = prev.get("_t") if prev else None
  53. cur_t = rev.storage_time or rev.update_time or rev.create_time
  54. if prev and cur_t and prev_t and cur_t <= prev_t:
  55. continue
  56. if prev and cur_t is None and prev_t is not None:
  57. continue
  58. out[code] = {
  59. "storageStatus": (rev.storage_status or "").strip(),
  60. "reviewConclusion": (rev.review_conclusion or "").strip(),
  61. "storageTime": _fmt_dt(rev.storage_time),
  62. "storageBy": (rev.storage_by or "").strip(),
  63. "storageByName": (rev.storage_by_name or "").strip(),
  64. "storageAttachments": (rev.review_attachments or "").strip(),
  65. "storageRemark": (rev.remark or "").strip(),
  66. "_t": cur_t,
  67. }
  68. for v in out.values():
  69. v.pop("_t", None)
  70. return out
  71. def _user_name_map(db: Session, user_ids: List[str]) -> Dict[str, str]:
  72. ids = list({(uid or "").strip() for uid in user_ids if (uid or "").strip()})
  73. if not ids:
  74. return {}
  75. rows = (
  76. db.query(SysUser.id, SysUser.nick_name)
  77. .filter(SysUser.id.in_(ids), SysUser.del_flag == 0)
  78. .all()
  79. )
  80. return {str(row[0]): (row[1] or "") for row in rows}
  81. def enrich_sample_info_items(
  82. db: Session,
  83. tenant_no: str,
  84. items: List[Dict[str, Any]],
  85. *,
  86. reception_source: str,
  87. include_handle_flags: bool,
  88. ) -> None:
  89. if not items or not tenant_no:
  90. return
  91. codes = [str(i.get("sampleCode") or "").strip() for i in items]
  92. codes = [c for c in codes if c]
  93. rec_map = get_list_reception_summary_map_by_sample_codes(
  94. db, tenant_no, codes, reception_source=reception_source
  95. )
  96. qc_map = get_list_qc_conclusion_map_by_sample_codes(
  97. db, tenant_no, codes, reception_source=reception_source
  98. )
  99. st_map = get_storage_review_map_by_sample_codes(
  100. db, tenant_no, codes, reception_source=reception_source
  101. )
  102. cert_map: Dict[str, Any] = {}
  103. ins_map: Dict[str, Any] = {}
  104. cs_map: Dict[str, Any] = {}
  105. if include_handle_flags and reception_source == "cell_storage":
  106. cert_map = sample_storage_cert_crud.get_map_by_sample_codes(db, tenant_no, codes)
  107. ins_map = sample_insurance_crud.get_map_by_sample_codes(db, tenant_no, codes)
  108. cs_map = sample_cs_crud.get_map_by_sample_codes(db, tenant_no, codes)
  109. for item in items:
  110. code = str(item.get("sampleCode") or "").strip()
  111. cflag, clabel = collection_progress(str(item.get("sampleStatus") or ""))
  112. item["collectionFlag"] = cflag
  113. item["collectionFlagLabel"] = clabel
  114. rec = rec_map.get(code)
  115. rflag, rlabel = reception_progress(rec)
  116. item["receptionFlag"] = rflag
  117. item["receptionFlagLabel"] = rlabel
  118. item["receptionTime"] = (rec or {}).get("receptionTime") or ""
  119. qc = qc_map.get(code)
  120. qflag, qlabel = qc_progress(qc)
  121. item["qcFlag"] = qflag
  122. item["qcFlagLabel"] = qlabel
  123. item["qcCompleteTime"] = ""
  124. st = st_map.get(code)
  125. sflag, slabel = storage_progress(st)
  126. item["storageFlag"] = sflag
  127. item["storageFlagLabel"] = slabel
  128. item["storageTime"] = (st or {}).get("storageTime") or ""
  129. item["storageBy"] = (st or {}).get("storageBy") or ""
  130. item["storageByName"] = (st or {}).get("storageByName") or ""
  131. item["storageAttachments"] = (st or {}).get("storageAttachments") or ""
  132. item["storageRemark"] = (st or {}).get("storageRemark") or ""
  133. if include_handle_flags:
  134. cert_row = cert_map.get(code)
  135. ins_row = ins_map.get(code)
  136. cert_done = storage_cert_handled(cert_row)
  137. ins_done = insurance_handled(ins_row)
  138. item["storageCertHandled"] = cert_done
  139. item["insuranceHandled"] = ins_done
  140. item["mailCertTime"] = _fmt_dt(getattr(cert_row, "mail_cert_time", None)) if cert_row else ""
  141. item["storageCertHandleTime"] = (
  142. _fmt_dt(getattr(cert_row, "handle_time", None)) if cert_row else ""
  143. )
  144. item["storageCertHandlerUserId"] = (
  145. getattr(cert_row, "handler_user_id", None) or ""
  146. ) if cert_row else ""
  147. item["storageCertAttachments"] = (
  148. getattr(cert_row, "cert_image_urls", None) or ""
  149. ) if cert_row else ""
  150. item["storageCertRemark"] = (getattr(cert_row, "remark", None) or "") if cert_row else ""
  151. item["insuranceHandleTime"] = _fmt_dt(getattr(ins_row, "handle_time", None)) if ins_row else ""
  152. item["insuranceHandlerUserId"] = (
  153. getattr(ins_row, "handler_user_id", None) or ""
  154. ) if ins_row else ""
  155. item["insuranceAttachments"] = (
  156. getattr(ins_row, "insurance_attachments", None) or ""
  157. ) if ins_row else ""
  158. item["insuranceRemark"] = (getattr(ins_row, "handle_remark", None) or "") if ins_row else ""
  159. item["policySendTime"] = _fmt_dt(getattr(ins_row, "policy_send_time", None)) if ins_row else ""
  160. # 购买保险时间 = 保险办理时间
  161. item["purchaseInsuranceTime"] = item["insuranceHandleTime"]
  162. cs_row = cs_map.get(code)
  163. if cs_row:
  164. cs = sample_cs_crud.row_to_dict(cs_row)
  165. item["smsSendDate"] = cs.get("smsSendDate") or ""
  166. item["smsSendStatus"] = cs.get("smsSendStatus") or ""
  167. item["microbeFollowupDate"] = cs.get("microbeFollowupDate") or ""
  168. item["microbeFollowupStatus"] = cs.get("microbeFollowupStatus") or ""
  169. item["fullmoonFollowupDate"] = cs.get("fullmoonFollowupDate") or ""
  170. item["fullmoonFollowupStatus"] = cs.get("fullmoonFollowupStatus") or ""
  171. item["householdRegistered"] = cs.get("householdRegistered") or ""
  172. item["einvoiceSendTime"] = cs.get("einvoiceSendTime") or ""
  173. item["effectiveAddress"] = cs.get("effectiveAddress") or ""
  174. else:
  175. item["smsSendDate"] = ""
  176. item["smsSendStatus"] = ""
  177. item["microbeFollowupDate"] = ""
  178. item["microbeFollowupStatus"] = ""
  179. item["fullmoonFollowupDate"] = ""
  180. item["fullmoonFollowupStatus"] = ""
  181. item["householdRegistered"] = ""
  182. item["einvoiceSendTime"] = ""
  183. item["effectiveAddress"] = ""
  184. item["protocolAttachmentPresent"] = _has_urls(item.get("protocolAttachments"))
  185. item["insuranceDocPresent"] = bool(ins_done)
  186. item["informedConsentPresent"] = _has_urls(item.get("consentFormUrls"))
  187. item["healthSurveyPresent"] = _has_urls(item.get("healthSurveyFormUrls"))
  188. name_ids = [
  189. str(item.get("storageBy") or "")
  190. for item in items
  191. if str(item.get("storageBy") or "").strip()
  192. and not str(item.get("storageByName") or "").strip()
  193. ]
  194. if include_handle_flags:
  195. name_ids.extend(
  196. str(item.get("storageCertHandlerUserId") or "")
  197. for item in items
  198. if str(item.get("storageCertHandlerUserId") or "").strip()
  199. )
  200. name_ids.extend(
  201. str(item.get("insuranceHandlerUserId") or "")
  202. for item in items
  203. if str(item.get("insuranceHandlerUserId") or "").strip()
  204. )
  205. name_map = _user_name_map(db, name_ids)
  206. for item in items:
  207. if not str(item.get("storageByName") or "").strip():
  208. item["storageByName"] = name_map.get(str(item.get("storageBy") or ""), "")
  209. if include_handle_flags:
  210. cert_uid = str(item.get("storageCertHandlerUserId") or "")
  211. ins_uid = str(item.get("insuranceHandlerUserId") or "")
  212. item["storageCertHandlerName"] = name_map.get(cert_uid, "") if cert_uid else ""
  213. item["insuranceHandlerName"] = name_map.get(ins_uid, "") if ins_uid else ""