# 细胞产品来源链路 — 回归说明 ## 功能入口 - 页面:`/#/production/cell-product` → 列表「查看」→「来源链路」 - API:`GET /web/admin/cell-products/{product_id}/chain` - 实现:`backend/app/crud/cell_product.py`(`get_product_chain`) ## 何时应显示链路图 前端 `hasChainGraphContent` 要求 **`ancestors` 或 `descendants` 非空**。 | 场景 | 条件 | |------|------| | 向上(祖先) | 产品有 `production_task_id`,且该任务投入物能追到 **样本** 或 **父级细胞产品** | | 向下(后代) | 其它任务 `input_type=cell_product` 引用了本产品,并有产出物 | 仅当前产品、上下游都为空时,显示「该产品暂无来源及衍生链路信息」。 ## 细胞存储 vs 科研捐赠(2026-05-27 修复) ### 修复前 祖先链样本节点 **仅查询** `biz_protocol_sample`。科研捐赠样本在 `biz_research_donation_sample`,工单 `protocol_sample_id` 存的是捐赠样本 ID,导致捐赠路径产品 **ancestors 为空**。 ### 修复后 任务存在 `input_type=sample` 的投入物时: 1. 工单 `reception_source=research_donation` → 优先查 `biz_research_donation_sample`(`input_id` / `input_code` / 工单 `protocol_sample_id`) 2. 否则查 `biz_protocol_sample`(同上,并带 `tenant_no`) 3. 若工单来源未标明捐赠,仍可在协议样本未命中时 **兜底** 查捐赠样本表 捐赠样本节点: - `receptionSource` = `research_donation` - `protocolNo` = 工单上的捐赠单号(`donation_no`) - `collectionProtocolId` = `research_donation_id`(供扩展;客户信息由 `biz_research_donation_party` 填充) - `customer` 来自捐赠当事人表,**不依赖** 采集协议接口 ## 手工回归清单 ### 细胞存储(不应回退) 1. 样本接收(细胞存储)→ 生产工单 → 生产任务:保存原材料「样本」(编码与工单一致)→ 完成任务并产出细胞产品。 2. 细胞产品库打开该产品「查看」→ 来源链路应出现:**样本 →(连线:工单号/任务号)→ 当前产品**。 3. 双击样本卡片可查看客户信息(协议当事人)。 ### 科研捐赠(修复验证) 1. 样本接收(科研捐赠)→ 生产工单 → 生产任务:保存原材料「样本」(编码可与工单 `sample_code` 一致;`input_id` 可为空)。 2. 产出细胞产品后,来源链路应出现:**捐赠样本 → 当前产品**,来源标签为「科研捐赠」。 3. 若任务未填样本编码但工单有关联样本,应能通过工单 `protocol_sample_id` / `sample_code` 兜底解析。 4. 双击样本卡片:若捐赠单有当事人信息,应弹出客户信息;不应因误调采集协议详情而空白。 ### 子代链路(两来源通用) 1. 以某产品为投入物创建下游任务并产出新产品。 2. 查看父产品时,来源链路应向右展示子代产品及连线。 ### 多进一(2026-05-27) 1. 同一生产任务录入 **2 个及以上** `sample` / `cell_product` 投入,产出 1 个细胞产品。 2. 查看产出产品时,来源链路应 **多条边汇聚到当前产品**(含「细胞产品 + 样本」混合投入)。 3. 各边连线标签应显示正确 **工单类型**(入库生产 / 临时生产 / 出库生产),而非 `reception_source`。 4. 双击任一边应打开同一生产任务。 ## 自动化测试 ```bash cd backend && source venv/bin/activate && python -m pytest tests/test_cell_product_chain.py -v ``` 覆盖:捐赠样本按编码解析、工单样本 ID 兜底、捐赠节点字段。 ## 相关设计文档 - `docs/superpowers/specs/2026-05-24-cell-product-source-chain-design.md`