|
|
@@ -0,0 +1,209 @@
|
|
|
+"""客户详情:关联协议与同单家庭成员聚合。"""
|
|
|
+from __future__ import annotations
|
|
|
+
|
|
|
+from datetime import datetime
|
|
|
+from typing import Any, Dict, List, Optional, Tuple
|
|
|
+
|
|
|
+from sqlalchemy import or_
|
|
|
+from sqlalchemy.orm import Session
|
|
|
+
|
|
|
+from app.crud import customer as customer_crud
|
|
|
+from app.models.models import BizCollectionProtocol, BizProtocolPartyCustomer
|
|
|
+from app.models.research_donation import BizResearchDonation, BizResearchDonationParty
|
|
|
+
|
|
|
+_ROLE_SPECS = (
|
|
|
+ {
|
|
|
+ "role": "mother",
|
|
|
+ "id_attr": "customer_id",
|
|
|
+ "name_attr": "mother_name",
|
|
|
+ "phone_attr": "mother_phone",
|
|
|
+ "id_card_attr": "mother_id_card",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "role": "father",
|
|
|
+ "id_attr": "father_customer_id",
|
|
|
+ "name_attr": "father_name",
|
|
|
+ "phone_attr": "father_phone",
|
|
|
+ "id_card_attr": "father_id_card",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "role": "newborn",
|
|
|
+ "id_attr": "newborn_customer_id",
|
|
|
+ "name_attr": "newborn_name",
|
|
|
+ "phone_attr": None,
|
|
|
+ "id_card_attr": "newborn_id_card",
|
|
|
+ },
|
|
|
+)
|
|
|
+
|
|
|
+
|
|
|
+def resolve_my_role(party: Any, customer_id: str) -> str:
|
|
|
+ cid = (customer_id or "").strip()
|
|
|
+ if not cid:
|
|
|
+ return ""
|
|
|
+ if (getattr(party, "customer_id", None) or "").strip() == cid:
|
|
|
+ return "mother"
|
|
|
+ if (getattr(party, "father_customer_id", None) or "").strip() == cid:
|
|
|
+ return "father"
|
|
|
+ if (getattr(party, "newborn_customer_id", None) or "").strip() == cid:
|
|
|
+ return "newborn"
|
|
|
+ return ""
|
|
|
+
|
|
|
+
|
|
|
+def party_members(party: Any) -> List[Dict[str, str]]:
|
|
|
+ out: List[Dict[str, str]] = []
|
|
|
+ for spec in _ROLE_SPECS:
|
|
|
+ name = (getattr(party, spec["name_attr"], None) or "").strip()
|
|
|
+ if not name:
|
|
|
+ continue
|
|
|
+ phone_attr = spec["phone_attr"]
|
|
|
+ phone = (getattr(party, phone_attr, None) or "").strip() if phone_attr else ""
|
|
|
+ out.append(
|
|
|
+ {
|
|
|
+ "role": spec["role"],
|
|
|
+ "customerId": (getattr(party, spec["id_attr"], None) or "").strip(),
|
|
|
+ "name": name,
|
|
|
+ "phone": phone,
|
|
|
+ "idCardNo": (getattr(party, spec["id_card_attr"], None) or "").strip(),
|
|
|
+ }
|
|
|
+ )
|
|
|
+ return out
|
|
|
+
|
|
|
+
|
|
|
+def _fmt_date(val: Any) -> str:
|
|
|
+ if val is None:
|
|
|
+ return ""
|
|
|
+ if isinstance(val, datetime):
|
|
|
+ return val.strftime("%Y%m%d")
|
|
|
+ return str(val).strip()
|
|
|
+
|
|
|
+
|
|
|
+def _group_sort_key(group: Dict[str, Any]) -> datetime:
|
|
|
+ ct = group.get("_createTime")
|
|
|
+ if isinstance(ct, datetime):
|
|
|
+ return ct
|
|
|
+ return datetime.min
|
|
|
+
|
|
|
+
|
|
|
+def _storage_group(party: Any, protocol: Any, customer_id: str) -> Dict[str, Any]:
|
|
|
+ return {
|
|
|
+ "bizType": "cell_storage",
|
|
|
+ "protocolId": protocol.id,
|
|
|
+ "protocolNo": (protocol.protocol_no or "").strip(),
|
|
|
+ "protocolStatus": (protocol.protocol_status or "").strip(),
|
|
|
+ "registerDate": _fmt_date(protocol.register_date),
|
|
|
+ "myRole": resolve_my_role(party, customer_id),
|
|
|
+ "members": party_members(party),
|
|
|
+ "_createTime": protocol.create_time,
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+def _donation_group(party: Any, donation: Any, customer_id: str) -> Dict[str, Any]:
|
|
|
+ return {
|
|
|
+ "bizType": "research_donation",
|
|
|
+ "protocolId": donation.id,
|
|
|
+ "protocolNo": (donation.donation_no or "").strip(),
|
|
|
+ "protocolStatus": (donation.donation_status or "").strip(),
|
|
|
+ "registerDate": _fmt_date(donation.donation_date),
|
|
|
+ "myRole": resolve_my_role(party, customer_id),
|
|
|
+ "members": party_members(party),
|
|
|
+ "_createTime": donation.create_time,
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+def _fetch_storage_party_rows(
|
|
|
+ db: Session, customer_id: str, tenant_no: str
|
|
|
+) -> List[Tuple[Any, Any]]:
|
|
|
+ cid = (customer_id or "").strip()
|
|
|
+ rows = (
|
|
|
+ db.query(BizProtocolPartyCustomer, BizCollectionProtocol)
|
|
|
+ .join(
|
|
|
+ BizCollectionProtocol,
|
|
|
+ BizCollectionProtocol.id == BizProtocolPartyCustomer.collection_protocol_id,
|
|
|
+ )
|
|
|
+ .filter(
|
|
|
+ BizProtocolPartyCustomer.tenant_no == tenant_no,
|
|
|
+ BizProtocolPartyCustomer.del_flag == 0,
|
|
|
+ BizCollectionProtocol.tenant_no == tenant_no,
|
|
|
+ BizCollectionProtocol.del_flag == 0,
|
|
|
+ or_(
|
|
|
+ BizProtocolPartyCustomer.customer_id == cid,
|
|
|
+ BizProtocolPartyCustomer.father_customer_id == cid,
|
|
|
+ BizProtocolPartyCustomer.newborn_customer_id == cid,
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ .all()
|
|
|
+ )
|
|
|
+ return list(rows)
|
|
|
+
|
|
|
+
|
|
|
+def _fetch_donation_party_rows(
|
|
|
+ db: Session, customer_id: str, tenant_no: str
|
|
|
+) -> List[Tuple[Any, Any]]:
|
|
|
+ cid = (customer_id or "").strip()
|
|
|
+ rows = (
|
|
|
+ db.query(BizResearchDonationParty, BizResearchDonation)
|
|
|
+ .join(
|
|
|
+ BizResearchDonation,
|
|
|
+ BizResearchDonation.id == BizResearchDonationParty.research_donation_id,
|
|
|
+ )
|
|
|
+ .filter(
|
|
|
+ BizResearchDonationParty.tenant_no == tenant_no,
|
|
|
+ BizResearchDonationParty.del_flag == 0,
|
|
|
+ BizResearchDonation.tenant_no == tenant_no,
|
|
|
+ BizResearchDonation.del_flag == 0,
|
|
|
+ or_(
|
|
|
+ BizResearchDonationParty.customer_id == cid,
|
|
|
+ BizResearchDonationParty.father_customer_id == cid,
|
|
|
+ BizResearchDonationParty.newborn_customer_id == cid,
|
|
|
+ ),
|
|
|
+ )
|
|
|
+ .all()
|
|
|
+ )
|
|
|
+ return list(rows)
|
|
|
+
|
|
|
+
|
|
|
+def build_customer_relations(
|
|
|
+ db: Session, customer_id: str, tenant_no: str
|
|
|
+) -> Optional[Dict[str, Any]]:
|
|
|
+ customer = customer_crud.get_customer(db, customer_id, tenant_no=tenant_no)
|
|
|
+ if not customer:
|
|
|
+ return None
|
|
|
+
|
|
|
+ groups: List[Dict[str, Any]] = []
|
|
|
+ for party, protocol in _fetch_storage_party_rows(db, customer_id, tenant_no):
|
|
|
+ groups.append(_storage_group(party, protocol, customer_id))
|
|
|
+ for party, donation in _fetch_donation_party_rows(db, customer_id, tenant_no):
|
|
|
+ groups.append(_donation_group(party, donation, customer_id))
|
|
|
+
|
|
|
+ groups.sort(key=_group_sort_key, reverse=True)
|
|
|
+
|
|
|
+ related_groups: List[Dict[str, Any]] = []
|
|
|
+ protocols: List[Dict[str, Any]] = []
|
|
|
+ for g in groups:
|
|
|
+ related_groups.append(
|
|
|
+ {
|
|
|
+ "bizType": g["bizType"],
|
|
|
+ "protocolId": g["protocolId"],
|
|
|
+ "protocolNo": g["protocolNo"],
|
|
|
+ "protocolStatus": g["protocolStatus"],
|
|
|
+ "registerDate": g["registerDate"],
|
|
|
+ "myRole": g["myRole"],
|
|
|
+ "members": g["members"],
|
|
|
+ }
|
|
|
+ )
|
|
|
+ protocols.append(
|
|
|
+ {
|
|
|
+ "bizType": g["bizType"],
|
|
|
+ "protocolId": g["protocolId"],
|
|
|
+ "protocolNo": g["protocolNo"],
|
|
|
+ "protocolStatus": g["protocolStatus"],
|
|
|
+ "registerDate": g["registerDate"],
|
|
|
+ "myRole": g["myRole"],
|
|
|
+ }
|
|
|
+ )
|
|
|
+
|
|
|
+ return {
|
|
|
+ "customer": customer_crud._row_to_dict(customer),
|
|
|
+ "relatedGroups": related_groups,
|
|
|
+ "protocols": protocols,
|
|
|
+ }
|