Files
zkxw/docs/superpowers/specs/2026-10-07-customer-family-protocol-link-design.md
T
zlwuandCursor e027b5abc4 docs: add customer family protocol link design.
Record agreed model for mother/father/child customer IDs on protocol parties, save-time sync, id-card merge, and customer detail relations.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-07 15:52:29 +08:00

8.9 KiB
Raw Blame History

客户管理 · 协议家庭成员关联设计

日期:2026-10-07
状态:已确认(2026-10-07)
范围:市场基础信息「客户管理」+ 细胞存储采集协议单 + 科研捐赠协议单


1. 背景

biz_customer 是独立客户主数据。采集协议保存时,目前只把母亲同步进客户表,并写到当事人表唯一的 customer_id。父亲、子女姓名等信息只存在当事人子表字段上,没有客户 ID。客户详情只展示本人字段,看不到同协议其他人和关联协议。

产品要求:

  • 母亲、父亲、子女只要有姓名即可写入客户管理(有证、无证均可)。
  • 同一张协议上的三人通过协议当事人上的三个客户 ID 关联。
  • 点开任一客户详情:上方按协议看同单其他人,下方看关联协议摘要;点协议号弹出协议只读详情。
  • 一人可对应多张协议,详情按协议分组列出。
  • 细胞存储与科研捐赠一起做。

2. 目标与非目标

2.1 目标

  • 当事人表增加父亲、子女客户 ID;母亲继续用已有 customer_id。
  • 保存细胞存储 / 科研捐赠协议时,对本单三个角色走同一套 upsert 同步(仅当前协议,不全库)。
  • 上线跑一次幂等迁移,把存量当事人补建客户并回写 ID;之后保存继续同步。
  • 补身份证撞到已有客户时:合并有用字段 → 全部引用改挂 → 软删临时客户。
  • 客户详情提供「关联客户」「关联协议」;点协议号打开对应查看弹窗。

2.2 非目标

  • 不新建「协议–客户–角色」关系表。
  • 不把客户管理改成协议列表的派生视图。
  • 不在客户详情内嵌完整协议表单,只弹现有只读查看。
  • 不自动因协议软删而删除客户。
  • 不把客户管理里的手工改名回写到协议当事人字段。
  • 本期不改中试申请患者 ↔ 客户逻辑。

3. 数据模型

不改 biz_customer 结构。扩展两张当事人表:

3.1 biz_protocol_party_customer

字段 说明
customer_id 已有,母亲客户 ID
father_customer_id 新增 VARCHAR(64) NULL,父亲客户 ID
newborn_customer_id 新增 VARCHAR(64) NULL,子女客户 ID

3.2 biz_research_donation_party

同样增加 father_customer_id、newborn_customer_id;已有 customer_id 仍表示母亲。

不把 customer_id 改名为 mother_customer_id,避免无谓迁移;代码与 API 注释写明「母亲」。

SQL 放在 docs/sql/migrations/(例如 2026-10-07-party-father-newborn-customer-id.sql),并同步 SQLAlchemy 模型。

关联约定:同一行上的三个 ID 即同一协议家庭;查询某客户相关协议时:

customer_id = :id
OR father_customer_id = :id
OR newborn_customer_id = :id

细胞存储与科研捐赠各查一次,按租户、del_flag=0 过滤。


4. 同步规则(保存当前协议)

抽公共函数(建议 backend/app/services/party_customer_sync.py),细胞存储与科研捐赠保存当事人时调用。范围仅当前这一张协议的三个角色。

每个角色(母亲 / 父亲 / 子女)独立处理:

  1. 无姓名:不同步客户;该角色客户 ID 置空(不删已有 biz_customer 记录)。
  2. 有姓名、无身份证:新建客户,回写本单对应客户 ID。不按姓名去重(允许重名)。
  3. 有姓名、有身份证:同租户未删除客户中按身份证查找(排除软删)。
    • 未找到:若本单该角色已有客户 ID,则不换 ID,把身份证等写到该客户;若无客户 ID,则新建并回写。
    • 找到且就是本单已挂的客户:更新该客户可写字段(姓名、电话等按下方合并策略)。
    • 找到且是另一条客户:进入第 5 节合并改挂。

性别默认:母亲 1,父亲 0,子女用当事人 newborn_sex,缺省 2。

年龄:能从身份证推算则写入,否则空。

协议当事人上的母亲/父亲/子女姓名电话等业务字段仍照旧写入子表,客户表只存客户主数据字段。


5. 补身份证撞库:合并后软删

当本单某角色「当前挂着的客户 A」与「身份证已存在的客户 B」且 A.id != B.id:

  1. 把 A 的有用信息合并进 B:
    • phone_no、age、sex(仅当目标为空或未知 2 时用源值)、remark:目标为空才补,不覆盖已有。
    • customer_tags:按逗号拆开后做并集再写回 B。
    • customer_name:保留 B(身份证命中的已有客户为准)。
  2. 将细胞存储当事人、科研捐赠当事人中,三个客户 ID 字段里所有等于 A 的值,改为 B(避免 A 仍被其它协议引用)。
  3. 本单该角色 ID 写为 B。
  4. 软删 A(del_flag=1)。
  5. 客户管理列表默认不展示 A。

若身份证不撞库:不换 ID,只更新当前客户。


6. 存量迁移

上线脚本(Python 或 SQL + 服务函数均可,须幂等):

  • 扫描未删除的 biz_protocol_party_customer、biz_research_donation_party。
  • 对已有角色姓名、却缺少对应客户 ID 的记录,调用与保存相同的同步函数。
  • 已有正确客户 ID 的跳过。
  • 可重复执行,结果一致。

之后日常只在保存当前协议时同步,不再全库重跑。


7. 客户详情

7.1 界面

客户管理查看弹窗自上而下:

  1. 基本信息:现有字段不变。
  2. 关联客户:按该客户出现过的协议分组(协议 create_time 倒序)。每组展示:
    • 类型(细胞存储 / 科研捐赠)、协议号、本客户角色(母亲 / 父亲 / 子女)
    • 同单已填角色(含本人,标记「本人」):角色、姓名、电话、身份证;非本人点姓名打开对方客户详情
    • 未填角色不展示
  3. 关联协议:摘要列表字段:协议号、类型、状态、日期、本客户角色。
    日期:细胞存储用 register_date,科研捐赠用 donation_date,接口统一字段名 registerDate。
    点击协议号弹出只读详情:
    • 细胞存储 → ProtocolViewDialog
    • 科研捐赠 → DonationViewDialog

无关联协议时,关联客户、关联协议区块展示空态文案。

7.2 API

GET /api/admin/customers/{id}/relations(需客户查看权限,租户隔离):

{
  customer: { ...与客户详情一致 },
  relatedGroups: [
    {
      bizType,              // cell_storage | research_donation
      protocolId,
      protocolNo,           // 细胞存储 protocol_no;科研捐赠 donation_no
      protocolStatus,       // protocol_status / donation_status
      registerDate,         // register_date / donation_date
      myRole,               // mother | father | newborn
      members: [
        { role, customerId, name, phone, idCardNo }
      ]
    }
  ],
  protocols: [
    { bizType, protocolId, protocolNo, protocolStatus, registerDate, myRole }
  ]
}

relatedGroups 与 protocols 同源:每张相关协议一组;members 含本客户及同单其他人(有客户 ID 或至少有姓名的角色)。protocols 便于下方摘要表直接绑定。

打开协议详情:前端复用现有协议/捐赠详情接口与弹窗。无对应协议查看权限时:协议号不可点或点击后提示无权限(与现有权限码一致,不新造权限)。


8. 列表与其它入口

  • 客户列表仍是 biz_customer 全量未删除记录;父亲、子女会出现为独立行。
  • 协议表单「选择客户」仍选自 biz_customer;保存后按第 4 节回写三个 ID。
  • 客户管理手工新增/编辑/删除行为不变;删除客户不级联改协议(协议上可能留下已删 ID;详情关联客户对该 ID 显示姓名占位或「客户已删除」)。

9. 测试要点

  • 无证三人保存 → 客户表 3 条,当事人三个 ID 均有值。
  • 后补子女身份证撞已有客户 → 字段合并、所有引用改挂、临时户软删、详情指向 B。
  • 后补身份证不撞库 → 客户 ID 不变,身份证写到原客户。
  • 同一母亲两张协议 → 详情两组关联客户 + 两条协议摘要。
  • 点协议号分别打开细胞存储 / 科研捐赠只读弹窗。
  • 仅填母亲 → 只同步母亲;关联客户组内无父/子女行。
  • 迁移脚本跑两遍结果一致。
  • 科研捐赠保存与细胞存储同一套规则。

10. 已确认决策

项 结论
关联落点 当事人表三个客户 ID,不新建关系表
母亲 ID 沿用已有 customer_id
业务范围 细胞存储 + 科研捐赠
无证 有姓名即可建客户
补证撞库 合并后软删临时客户,协议改挂已有客户
存量 上线全量脚本 + 之后仅保存当前单时同步
详情布局 上:按协议分组的关联客户;下:协议摘要;点协议号弹详情
中试 本期不动