From 9c264d7942db8ade021aa5434819483c62ba3228 Mon Sep 17 00:00:00 2001 From: zlwu <704541015@qq.com> Date: Tue, 13 Oct 2026 10:57:55 +0800 Subject: [PATCH] feat(backend): enrich cell-storage sample list with customer-service wide columns. Co-authored-by: Cursor --- .../app/crud/protocol_sample_collection.py | 38 +++++++++ .../app/services/sample_info_list_enrich.py | 85 ++++++++++++------- 2 files changed, 91 insertions(+), 32 deletions(-) diff --git a/backend/app/crud/protocol_sample_collection.py b/backend/app/crud/protocol_sample_collection.py index eeeb571c..4ca2b2a3 100644 --- a/backend/app/crud/protocol_sample_collection.py +++ b/backend/app/crud/protocol_sample_collection.py @@ -399,17 +399,55 @@ def list_protocol_sample_collections( maternal_blood_collect_time=_fmt_dt(ci.maternal_blood_collect_time) if ci else "", ) item.update(sample_special_to_dict(psample)) + # 客户服务宽表:当事人 / 协议附件 / 备注 / 市场专员 id + item["motherPhone"] = (party.mother_phone or "") if party else "" + item["motherIdCard"] = (party.mother_id_card or "") if party else "" + item["fatherName"] = (party.father_name or "") if party else "" + item["fatherPhone"] = (party.father_phone or "") if party else "" + item["fatherIdCard"] = (party.father_id_card or "") if party else "" + item["newbornIdCard"] = (party.newborn_id_card or "") if party else "" + item["newbornSex"] = (party.newborn_sex or "") if party else "" + item["newbornDeliveryTime"] = _fmt_dt(party.newborn_delivery_time) if party else "" + item["protocolRemark"] = (proto.remark or "") if proto else "" + item["protocolAttachments"] = (proto.protocol_attachments or "") if proto else "" + item["consentFormUrls"] = (proto.consent_form_urls or "") if proto else "" + item["healthSurveyFormUrls"] = (proto.health_survey_form_urls or "") if proto else "" + item["salesUserId"] = (ci.sales_user_id or "") if ci else "" items.append(item) if items and tenant_no: from app.crud import sample_reception as reception_svc + from app.crud.storage_release_review import _get_user_name + from app.models.models import BizProtocolSamplePayment codes = [i["sampleCode"] for i in items if i.get("sampleCode")] code_map = reception_svc.get_lab_storage_code_map_by_sample_codes( db, tenant_no, codes, reception_source="cell_storage" ) + pay_mode_map: Dict[str, str] = {} + if codes: + for sp in ( + db.query(BizProtocolSamplePayment) + .filter( + BizProtocolSamplePayment.tenant_no == tenant_no, + BizProtocolSamplePayment.del_flag == 0, + BizProtocolSamplePayment.sample_code.in_(codes), + ) + .all() + ): + sc = (sp.sample_code or "").strip() + if sc and sc not in pay_mode_map: + pay_mode_map[sc] = (sp.pay_mode or "").strip() + sales_ids = list({(i.get("salesUserId") or "").strip() for i in items if i.get("salesUserId")}) + sales_name_map = {uid: _get_user_name(db, uid) for uid in sales_ids if uid} + pay_mode_label = {"dj": "趸交", "fq": "分期"} for item in items: sc = (item.get("sampleCode") or "").strip() item["labStorageCode"] = code_map.get(sc, "") if sc else "" + mode = pay_mode_map.get(sc, "") + item["payMode"] = mode + item["payModeLabel"] = pay_mode_label.get(mode, mode or "") + sid = (item.get("salesUserId") or "").strip() + item["marketSpecialistName"] = sales_name_map.get(sid, "") if sid else "" from app.services.sample_info_list_enrich import enrich_sample_info_items enrich_sample_info_items( diff --git a/backend/app/services/sample_info_list_enrich.py b/backend/app/services/sample_info_list_enrich.py index c406631e..4bd1859c 100644 --- a/backend/app/services/sample_info_list_enrich.py +++ b/backend/app/services/sample_info_list_enrich.py @@ -1,4 +1,4 @@ -"""样本信息列表:批量补进度标识(接收/质检/入库/证保险)。""" +"""样本信息列表:批量补进度标识(接收/质检/入库/证保险)与客户服务宽表字段。""" from __future__ import annotations from datetime import datetime @@ -6,11 +6,10 @@ from typing import Any, Dict, List, Optional from sqlalchemy.orm import Session -from app.models.models import ( - BizProtocolFullmoonTodo, - BizProtocolStorageCert, - BizStorageReleaseReview, -) +from app.crud import sample_customer_service as sample_cs_crud +from app.crud import sample_insurance as sample_insurance_crud +from app.crud import sample_storage_cert as sample_storage_cert_crud +from app.models.models import BizStorageReleaseReview from app.services.protocol_sample_list_summary import ( get_list_qc_conclusion_map_by_sample_codes, get_list_reception_summary_map_by_sample_codes, @@ -29,6 +28,10 @@ def _fmt_dt(t: Optional[datetime]) -> str: return t.strftime("%Y-%m-%d %H:%M:%S") if t else "" +def _has_urls(raw: Optional[str]) -> bool: + return bool((raw or "").strip()) + + def get_storage_review_map_by_sample_codes( db: Session, tenant_no: str, @@ -95,29 +98,11 @@ def enrich_sample_info_items( ) cert_map: Dict[str, Any] = {} ins_map: Dict[str, Any] = {} - if include_handle_flags: - pids = list({str(i.get("collectionProtocolId") or "").strip() for i in items if i.get("collectionProtocolId")}) - if pids: - for sc in ( - db.query(BizProtocolStorageCert) - .filter( - BizProtocolStorageCert.collection_protocol_id.in_(pids), - BizProtocolStorageCert.tenant_no == tenant_no, - BizProtocolStorageCert.del_flag == 0, - ) - .all() - ): - cert_map[sc.collection_protocol_id] = sc - for ft in ( - db.query(BizProtocolFullmoonTodo) - .filter( - BizProtocolFullmoonTodo.collection_protocol_id.in_(pids), - BizProtocolFullmoonTodo.tenant_no == tenant_no, - BizProtocolFullmoonTodo.del_flag == 0, - ) - .all() - ): - ins_map[ft.collection_protocol_id] = ft + cs_map: Dict[str, Any] = {} + if include_handle_flags and reception_source == "cell_storage": + cert_map = sample_storage_cert_crud.get_map_by_sample_codes(db, tenant_no, codes) + ins_map = sample_insurance_crud.get_map_by_sample_codes(db, tenant_no, codes) + cs_map = sample_cs_crud.get_map_by_sample_codes(db, tenant_no, codes) for item in items: code = str(item.get("sampleCode") or "").strip() @@ -140,6 +125,42 @@ def enrich_sample_info_items( item["storageFlagLabel"] = slabel item["storageTime"] = (st or {}).get("storageTime") or "" if include_handle_flags: - pid = str(item.get("collectionProtocolId") or "") - item["storageCertHandled"] = storage_cert_handled(cert_map.get(pid)) - item["insuranceHandled"] = insurance_handled(ins_map.get(pid)) + cert_row = cert_map.get(code) + ins_row = ins_map.get(code) + cert_done = storage_cert_handled(cert_row) + ins_done = insurance_handled(ins_row) + item["storageCertHandled"] = cert_done + item["insuranceHandled"] = ins_done + item["mailCertTime"] = _fmt_dt(getattr(cert_row, "mail_cert_time", None)) if cert_row else "" + item["insuranceHandleTime"] = _fmt_dt(getattr(ins_row, "handle_time", None)) if ins_row else "" + item["policySendTime"] = _fmt_dt(getattr(ins_row, "policy_send_time", None)) if ins_row else "" + # 购买保险时间 = 保险办理时间 + item["purchaseInsuranceTime"] = item["insuranceHandleTime"] + + cs_row = cs_map.get(code) + if cs_row: + cs = sample_cs_crud.row_to_dict(cs_row) + item["smsSendDate"] = cs.get("smsSendDate") or "" + item["smsSendStatus"] = cs.get("smsSendStatus") or "" + item["microbeFollowupDate"] = cs.get("microbeFollowupDate") or "" + item["microbeFollowupStatus"] = cs.get("microbeFollowupStatus") or "" + item["fullmoonFollowupDate"] = cs.get("fullmoonFollowupDate") or "" + item["fullmoonFollowupStatus"] = cs.get("fullmoonFollowupStatus") or "" + item["householdRegistered"] = cs.get("householdRegistered") or "" + item["einvoiceSendTime"] = cs.get("einvoiceSendTime") or "" + item["effectiveAddress"] = cs.get("effectiveAddress") or "" + else: + item["smsSendDate"] = "" + item["smsSendStatus"] = "" + item["microbeFollowupDate"] = "" + item["microbeFollowupStatus"] = "" + item["fullmoonFollowupDate"] = "" + item["fullmoonFollowupStatus"] = "" + item["householdRegistered"] = "" + item["einvoiceSendTime"] = "" + item["effectiveAddress"] = "" + + item["protocolAttachmentPresent"] = _has_urls(item.get("protocolAttachments")) + item["insuranceDocPresent"] = bool(ins_done) + item["informedConsentPresent"] = _has_urls(item.get("consentFormUrls")) + item["healthSurveyPresent"] = _has_urls(item.get("healthSurveyFormUrls"))