1
0
forked from erp-dev/erp
Files
erpnew/docs/business_object_relink_fix.md

68 lines
2.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 背景与问题
系统中 `PlateOrder` / `PrintingJob` 都通过 `business_object``stateflow.BusinessObject`)承载流程推进数据:
- `BusinessObject.process` 决定了流程节点序列
- `BusinessObject.state_logs` 记录了推进轨迹(`StateFlowRecord`,支持撤销)
但在现有 API 中PUT/PATCH 更新):
- `PlateOrder.process`(整型流程 ID允许被更新
- `PrintingOrder.process`(外键流程)允许在“所有 jobs 未开始”时被更新
- `PrintingJob` 允许修改 `printing_order`(从而间接改变其应当使用的流程)
这些更新行为会导致一个严重一致性漏洞:
> 业务对象的“当前流程字段”发生变化,但其已绑定的 `BusinessObject.process` 仍指向旧流程,导致后续状态推进与展示出现错乱。
---
## 修正案(最小改动原则)
目标:
- 只在必要处拦截/修复更新行为
- 将核心逻辑集中到 `stateflow/services.py`(跨模块统一)
- 不删除旧的 BusinessObject后续可通过“无反向引用”识别悬空 BO
核心做法:
- 新增 `stateflow.services.relink_business_object_for_instance(...)`
- 当流程发生变化时,创建并绑定一个新的 BusinessObject新流程
- 若旧 BO 存在“未撤销进度”,则拒绝(返回 None由调用方转 400
- 内部新增 `_can_relink_business_object(...)`
- 判定口径与 `has_started` 保持一致:只要存在 `is_cancelled=False` 的记录即视为已开始
---
## 规则(对外行为)
### PlateOrder更新 process
- **process 未变化**:不触发 relink
- **process 变化**
- 若已存在“未撤销进度”has_started=True返回 400
- 否则:创建新 BO 并绑定;旧 BO 保留
### PrintingOrder更新 process
- **process=None**:非法,返回 400
- **任意 job 已存在未撤销进度**:整笔订单不允许改流程,返回 400
- **所有 jobs 均未开始**:允许改流程,并对订单下所有 jobs 进行 relink创建新 BO 并绑定)
### PrintingJob更新 printing_order
- 不允许通过更新接口修改 `printing_order` 绑定关系:返回 400
- 避免绕过 `PrintingOrder` 的流程一致性约束
---
## 影响与收益
- **收益**:保证 `process``BusinessObject.process` 的一致性,避免状态推进/展示错乱
- **可追溯性**:旧 BO 不删除,未来可实现“悬空 BO 查看/排查”
- **风险控制**:仅在“无有效进度”时允许换流程,避免对已开始流程造成破坏
## 涉及代码文件
- stateflow/services.py
- api_v1/views/printing/serializers.py
- api_v1/views/printing/services.py
- api_v1/views/printing/test_plate_order_api.py
- api_v1/views/printing/test_api.py
- api_v1/views/printing/test_printing_job_api.py