2026-10-03-cell-storage-protocol-sample-payment-analysis.md 19 KB

细胞存储三模块现状分析(改码参考)

日期:2026-10-03
状态:现状梳理(非改造设计)
用途:后续按新思路改代码前的权威对照基线;描述「当前代码实际如何工作」,而非「应当如何」。

覆盖模块:

菜单 Hash 路由 menuCode
采集协议单 /#/cell-storage/protocol-audit biz:cellStorageProtocolAudit:list
样本信息管理 /#/cell-storage/sample-info cell-storage:sample-info:list
缴退费财务确认及开票 /#/cell-storage/payment-confirm biz:cellStoragePaymentConfirm:list

需求权威:docs/中科兴皖需求V0.3.md §2.2.6~2.2.9

相关设计文档(增量能力):

  • docs/superpowers/specs/2026-05-13-cell-storage-protocol-modules-design.md(早期模块设计)
  • docs/superpowers/specs/2026-05-19-protocol-donation-convert-design.md(转科研)
  • docs/superpowers/specs/2026-06-04-protocol-pay-mode-switch-design.md(缴费模式切换,若存在)
  • docs/superpowers/specs/2026-06-17-protocol-invoice-request-design.md(开票)
  • docs/superpowers/specs/2026-06-01-sample-qc-sms-notification-design.md
  • docs/superpowers/specs/2025-05-23-storage-entry-sms-notification-design.md
  • OpenSpec:openspec/changes/zkxw-engineering-standards/specs/api-conventions/spec.md(细胞存储样本跨表关联键)

1. 总览:双并行业务架构

采集协议单是源头。创建后并行两条线:

┌──────────────────── 细胞存储 ────────────────────┐
│  【采集协议单】  合同 + 客户 + 样本源头 + 缴费配置   │
│         │                                        │
│         ├──────────────┬─────────────────────────┤
│         ▼              ▼                         │
│  【样本信息管理】  【缴退费财务确认及开票】          │
│  只读运营台+短信   财务终审+开票完成                 │
│         │              ▲                         │
│         ▼              │ 业务侧发起                 │
│  接收→质检→生产→入库   缴费信息 Tab / 满月待办      │
└──────────────────────────────────────────────────┘
模块 角色 本质
采集协议单 市场/采集专员 主单据 CRUD、状态变更、缴费发起、开票申请入口
样本信息管理 运营 只读查询台 + 线下短信提取/标记(不登记接收、不做质检入库操作)
缴退费财务确认及开票 财务 收款/退费确认 + 开票完成

菜单演进:样本相关 Tab、缴费确认、开票已从早期「单一协议管理页」拆出;隐藏路由仍保留 protocol(录入表格版)、payment-info 等兼容入口。


2. 数据模型(以协议为中心)

biz_collection_protocol (1)
├── biz_protocol_party_customer (1)      当事人/客户
├── biz_protocol_collection_info (1)     采集信息
├── biz_protocol_sample (N)
│     └── biz_protocol_sample_transport
├── biz_protocol_payment (1)
│     └── biz_protocol_payment_detail (N)
├── biz_protocol_audit (N)               审核记录(不改协议状态)
├── biz_protocol_storage_cert
├── biz_protocol_fullmoon_todo
├── biz_protocol_invoice_request (N)
│     └── biz_protocol_invoice_request_item (N)
└── biz_protocol_donation_convert (0..1) 与科研捐赠互转

2.1 跨表关联硬规则(OpenSpec)

关联键 = tenant_no + sample_code
禁止用 collection_protocol_id / protocol_sample_id 做业务匹配

原因:协议编辑可能重建样本行 id;协议可转科研;样本编码不变。接收防重、详情回显、质检/入库 JOIN 均按此规则。

2.2 协议主表关键字段

字段 含义
protocol_no / protocol_no_id 协议号(可自动分配号池)
protocol_status dsx 待生效 / sxz 生效中 / ygq 已过期 / yzf 已作废 / sdfq 属地废弃 / zky 转科研
protocol_attachments / consent_form_urls / health_survey_form_urls 附件 URL 逗号分隔
void_type 作废类型(字典);作废时必填
collector_user_id 采集专员
effective_* / expire_* / void_* / to_research_* 各状态变更时间与描述

无效态 yzf / sdfq:下游接收、生产列表会过滤。


3. 【采集协议单】模块

3.1 前端结构

web-admin/src/views/cell-storage/
├── protocol/                          # 隐藏录入列表
│   ├── index.vue
│   ├── ProtocolFormDialog.vue         # 新增/编辑大表单(权威录入)
│   ├── ProtocolViewDialog.vue
│   ├── ProtocolAuditDialog.vue
│   └── ProtocolStatusChangeDialog.vue
└── protocol-audit/                    # 主管理页
    ├── index.vue                      # Pill Tab
    ├── ProtocolAuditTab.vue
    ├── PaymentInfoTab.vue             # 业务侧缴费看板
    ├── StorageCertTab.vue
    ├── FullmoonTodoTab.vue            # 满月保险 + 开票申请入口
    └── Sample*InfoTab.vue             # 被 sample-info 复用

API:web-admin/src/api/collection-protocol.ts

3.2 协议状态机

创建 → [dsx] 待生效
         │ 协议生效
         ▼
       [sxz] 生效中 ──┬── 过期 → [ygq]
                      ├── 作废 → [yzf](须 voidType)
                      ├── 属地废弃 → [sdfq]
                      └── 转科研 → [zky](convert API,建捐赠单)
  • 审核独立:只写 biz_protocol_audit(shtg/shth),不驱动 protocol_status。
  • 协议号:空则 allocate_next_biz_no;已存在不可改。
  • 删除:软删主单 + 样本 + 运输,释放样本编码占用。

3.3 表单保存顺序(API 硬约束)

_persist_protocol_sub_resources(backend/app/api/collection_protocol.py):

1. party_customer(可 upsert biz_customer)
2. collection_info
3. payment + payment_details   ← 必须在样本之前
4. samples(含运输)
5. storage_cert

原因:缴费校验失败时不得已占用样本编码。创建失败补偿 soft_delete_collection_protocol。

3.4 ProtocolFormDialog 字段分区

Tab 主要字段 payload 路径
基本信息 协议状态*、登记日、采集专员、备注、三类附件 主表字段 + attachments
采集信息 地区、医院、医护、销售、样本/母血采集时间 collectionInfo
样本及运输 类型、编码、价格、年限、状态、特殊标记、运输 samples[] + transport
客户信息 关联客户、母亲/父亲/新生儿全套 partyCustomer
缴费信息 模式、合同额、分期参数、明细行 payment + paymentDetails
  • formRules 仅强制 protocolStatus。
  • 组件:sample-transport-form-section(样本+运输权威 UI)。
  • 附件:卡片化立即上传(OpenSpec UI 附件约定以本弹窗为样例)。

提交前前端校验顺序:

  1. el-form validate
  2. 缴费模式 ↔ 有效样本数(djfq 仅 2 样本)
  3. 新建时样本编码 usedInProtocol 占用拦截
  4. 趸交应缴合计 ≠ 合同额 → 仅 warning,不阻断
  5. syncFqPaymentDetailRowCount → POST/PUT

3.5 缴费默认定价(样本数 × 模式)

web-admin/src/utils/protocol-payment-presets.ts:

有效样本数(≠ yzf) 可选模式 合同金额示例
1 dj / fq 趸交 22880;分期 25880(6 期)
2 dj / djfq / fq 趸交 37880;趸交+分期 41000;分期 44000

3.6 缴费模式切换矩阵

前端:protocol-pay-mode-switch.ts
后端:protocol_pay_mode_switch.py(LOCKED_STATUSES / BLOCKING_STATUSES)

从 → 到 条件 结果
任意 存在进行中确认(前端还拦 ytf) 阻断
dj → fq/djfq 已有锁定明细 阻断
dj → fq/djfq 全待缴 确认后按期数重建
fq/djfq → dj 已全部缴清 阻断
fq/djfq → dj 有已缴+未缴 保留 yjf,作废 dfj,新增剩余趸交
fq ↔ djfq 已有锁定 阻断;否则重建

后端保存 P0:jfqrz/tfqrz 禁止保存;分期条数=期数;比例合计 100%;期数不少于已缴最大期次。
注意:前端 BLOCKING 含 ytf,后端不含(已退费允许随协议保存只读明细)。

3.7 后端核心文件

路径 角色
backend/app/api/collection_protocol.py 协议/缴费/储存证/满月/开票 API
backend/app/crud/collection_protocol.py 核心 CRUD(约 3900+ 行)
backend/app/services/protocol_pay_mode_switch.py 缴费校验
backend/app/crud/collection_protocol_no.py 协议号池
backend/app/models/models.py ORM

4. 【样本信息管理】模块

4.1 定位

不是样本录入页,不是接收/质检/入库操作台。

是协议样本的 全链路查询 + 客户短信触达台(组件复用自 protocol-audit/):

Tab 职责 短信
样本采集信息 采集进度 无
样本接收信息 接收结论 有
样本质检信息 入库质检结论 有
样本入库信息 入库/拒入库 有

深链:?tab=sample-collection|sample-reception|sample-qc|storage-entry
旧路由 sample-reception-info / storage-entry-info 重定向到本页。

4.2 样本状态 sample_status

(空) 未采集 → ycj 已采集 → jcz 检测中 → yrk 已入库
任意 → yzf 已作废
  • 协议表单录入默认常为 ycj。
  • 接收登记不改 sample_status。
  • 入库:store_sample 按 sample_code 回写 yrk + storage_in_date。
  • 取消入库:若原为 yrk → 回退 jcz,清空 storage_in_date。

4.3 真实写库链路(本页只读展示)

接收结论 = js 时(create_sample_reception):

写 biz_sample_reception + 检查项
  → create_work_order_from_reception      # 入库质检工单 dpz
  → create_production_work_order_from_reception
  → try_auto_dispatch_builtin_tasks…      # 内置任务派发
  → create_review_from_reception          # 入库放行审核 drk

结论 = bj:只写接收,不创建工单/审核。

防重:tenant_no + reception_source + sample_code。
实验室入库编码:结论为 js 时必填且租户唯一。

4.4 质检结论派生

backend/app/services/qc_work_order_conclusion.py:

任一任务 conclusion == btg → 工单 btg
全部任务 conclusion == tg  → 工单 tg
否则 → ""(尚无结论)

工单状态:dpz → ypz →(全部任务 ywc)ywc 并落库 wo.conclusion。
try_reopen_work_order:回退 ypz,清空 conclusion。

质检 Tab 列表派生(_qc_status_label):

条件 码
无工单等 dzj 待质检
ypz zjz 质检中
ywc + tg/btg tg / btg
ywc 结论未齐 zjz
工单 yzf yzf

协议详情回显:get_qc_info_map_for_samples 细胞存储侧必须按 sample_code 关联(trigger_source=reception)。

4.5 入库双审

submit_review(production / qc 两侧):

  • 任一方 btg → 聚合 btg
  • 双方 tg → 聚合 tg → storage_transition = store → store_sample
  • 已入库后结论变 btg → unstore

前置:生产与质检均通过且 storage_status=drk 才能入库。

4.6 短信规则

系统不自动发送。运营:提取文案 → 复制 → 线下发 → 标记已通知。

Tab 模板要点
接收 已于{日期}完成接收,结论:{接收/拒收}
质检 合格 / 未通过;未完成返回「暂无短信内容…」
入库 已入库日期 / 审核未通过;待确认暂无内容

4.7 与缴退费关系

  • 无直接 FK;缴费挂协议不挂样本行。
  • 间接:有效样本数 → 默认定价 / 可选缴费模式。
  • 本页无缴费操作;查看协议弹窗内可见缴费。

4.8 代码锚点

路径 角色
web-admin/.../sample-info/index.vue 壳页
web-admin/.../protocol-audit/Sample*InfoTab.vue 四 Tab
backend/app/api/protocol_sample_collection.py 采集列表
backend/app/api/sample_sms_notification.py 等 三短信 API
backend/app/crud/sample_reception.py 接收写库
backend/app/crud/qc_work_order.py 质检工单
backend/app/crud/storage_release_review.py 入库放行

5. 【缴退费财务确认及开票】模块

5.1 三角色协作

业务(缴费信息 / 满月待办)          财务(本模块)
  提交缴费确认 dfj→jfqrz    →    确认收款 → yjf(或退回→dfj)
  提交退费确认 yjf→tfqrz    →    确认退费 → ytf(或退回→yjf)
  发起开票申请 → dkp        →    完成开票 → ykp(上传发票)

前端:

  • payment-confirm/index.vue(缴费确认)
  • RefundConfirmTab.vue
  • InvoiceRequestTab.vue
  • 上游:PaymentInfoTab.vue、FullmoonTodoTab.vue

5.2 缴费明细状态机(pay_status)

dfj → jfqrz → yjf → tfqrz → ytf
         ↑退回      ↑退回
状态 业务可做 财务可做 关键写入
dfj 编辑草稿、提交确认 — 转账方式/金额/时间/凭证
jfqrz — 确认/退回 finance_* → yjf 或 → dfj
yjf 发起退费 — refund_* → tfqrz
tfqrz — 确认/退回 refundfinance* → ytf 或 → yjf
ytf — — 终态

提交收款强制:转账方式非空 + transfer_amount > 0。
提交退费强制:仅 yjf + refund_amount > 0。

注意:批量提交收款不跑单条草稿完整性校验(假定已是合格 dfj)。

5.3 开票(独立状态机,不改 pay_status)

可开票 = pay_status=yjf AND 明细未在有效申请子表(dkp|ykp)
金额   = Σ transfer_amount(快照 line_amount / invoice_amount)
完成   = 仅 dkp + 发票附件必填 → ykp
不做   = 驳回、冲红、改缴费状态、结构化发票号/日期
  • 多期可合并一张发票(1 主表 + N 子表)。
  • 已占用期不可再选;剩余期可另起申请。
  • 抬头六字段申请时 选填。

函数:create_invoice_request / complete_invoice_request / list_invoice_eligible_payment_details。

5.4 平行模块(勿混淆)

模块 差异
临床缴退费财务确认 biz_pilot_payment;无开票 Tab
渠道服务订单财务确认 另一套流水状态机

6. 协议转科研(zky)边界

入口:research_donation.convert_from_storage。

6.1 前置

  • 源协议 sxz
  • 无有效 biz_protocol_donation_convert
  • 协议号非空

6.2 事务内拷贝

拷贝 不拷贝
捐赠主单(同号 donation_no) 缴费主表/明细
party / collection 审核 / 开票 / 储存证 / 满月
samples(同 sample_code)+ transports 接收/质检/入库审核记录

源协议 → zky + to_research_*;写关联表 convert_type=storage_to_research。

6.3 同码共存

配对后两边可暂共用 sample_code;保存唯一性对配对 ID 豁免(get_partner_sample_codes)。
之后两边可各自改号,不自动同步;关联表 biz_no 只留转移快照。

产品含义:转科研是合同形态切换,不是财务结算迁移;退费/开票仍对原协议缴费明细。


7. 端到端写库总图

协议保存
  客户 → 采集 →【缴费校验+明细】→ 样本编码占用 → 储存证
         │                              │
         ▼                              ▼
   缴费明细状态机                    sample_code
   dfj→jfqrz→yjf→…                 │
         │                         ▼
         │              接收(js) → QC + 生产 + 入库审核(drk)
         │                         │
         ▼                         ▼ 双审 tg
   财务确认 / 开票(dkp→ykp)    store → sample_status=yrk

转科研(sxz→zky):新捐赠同号同码;缴费不跟走

8. 实现时注意点(改码易踩坑)

  1. 跨表只认 tenant_no + sample_code,勿用样本行 id 做业务匹配。
  2. 缴费先于样本保存;创建失败要补偿软删。
  3. 审核不改协议状态;财务确认不改协议状态;开票不改 pay_status。
  4. 前端/后端缴费阻断集合不完全一致(ytf)。
  5. 批量提交收款校验弱于单条。
  6. 转科研不迁缴费;样本下游历史仍按编码可查。
  7. 管理端色值用 Fresh Mint(#10b981),勿混小程序三墙绿。
  8. 平行「缴退费财务确认」菜单(临床/渠道)表模型不同。

9. 关键代码地图(速查)

前端

模块 路径
协议主页 web-admin/src/views/cell-storage/protocol-audit/
协议表单 web-admin/src/views/cell-storage/protocol/ProtocolFormDialog.vue
样本信息 web-admin/src/views/cell-storage/sample-info/index.vue
财务确认 web-admin/src/views/cell-storage/payment-confirm/
API web-admin/src/api/collection-protocol.ts 等
缴费工具 web-admin/src/utils/protocol-payment-*.ts、protocol-pay-mode-switch.ts
路由 web-admin/src/router/modules/sqxp.ts

后端

模块 路径
协议 API/CRUD backend/app/api/collection_protocol.py、crud/collection_protocol.py
样本采集列表 api/protocol_sample_collection.py、crud/protocol_sample_collection.py
接收 crud/sample_reception.py
质检 crud/qc_work_order.py、services/qc_work_order_conclusion.py
入库 crud/storage_release_review.py
短信 crud/sample_sms_notification.py、qc_sms_notification.py、storage_entry_sms_notification.py
转科研 crud/research_donation.py(convert_from_storage)、crud/protocol_donation_convert.py
缴费模式 services/protocol_pay_mode_switch.py

10. 后续改码建议用法

  1. 先在本文确认「现状行为」与「要改的边界」。
  2. 若行为变更跨状态机/表结构,另开 OpenSpec change 或 docs/superpowers/specs/YYYY-MM-DD-*-design.md。
  3. 改样本下游关联时,对照 §2.1 与 OpenSpec api-conventions。
  4. 改缴费/开票时,对照 §5 状态矩阵与「明确不做」列表,避免无意引入驳回/冲红等本期未实现能力。
  5. 改协议表单字段时,同步检查:Create/Update Body、_row_to_dict、前端 formData(见 docs/dev-field-consistency.md)。

文档维护:若实现偏离本文描述,请同步更新本节或标注「已失效段落」,避免后续改码基于过时基线。