forked from erp-dev/erp
5.5 KiB
5.5 KiB
Stateflow 修正记录
2025-11-11: 重要架构调整
修正1: 日志不可删除,仅能标记为已撤销
问题: 之前重置进度时会删除所有完成记录,导致操作历史丢失。
解决方案:
- 添加
OrderStateLog.is_cancelled字段(是否已撤销) - 添加
OrderStateLog.cancelled_at字段(撤销时间) - 修改
reset_order_progress()函数,不再删除记录,而是:order.state_logs.filter(is_cancelled=False).update( is_cancelled=True, cancelled_at=timezone.now() )
影响:
- ✅ 保留完整的操作历史
- ✅ 可以审计谁在什么时候撤销了进度
- ✅ 支持未来可能的"恢复"功能
修正2: 初始状态改为 None(未开始)
问题: 之前订单创建后,初始状态就是第一个节点,无法区分"未开始"和"进行中"。
解决方案:
- 修改
get_order_current_state()函数:- 没有任何有效完成记录时返回
None(而不是第一个节点) - 所有状态都完成后也返回
None
- 没有任何有效完成记录时返回
- 新增
get_overall_status()函数:- 用于区分
'not_started'(未开始)和'completed'(已完成)
- 用于区分
- 修改
advance_to_next_state()函数:- 当当前状态为
None且没有完成记录时,自动推进到第一个节点
- 当当前状态为
状态转换流程:
创建订单 → None (not_started)
↓ 第一次推进
状态1 完成 → 状态2 (in_progress)
↓ 第二次推进
状态2 完成 → 状态3 (in_progress)
↓ 第三次推进
状态3 完成 → None (completed)
影响:
- ✅ 可以区分"未开始处理"和"正在处理"
- ✅ 可以区分"正在处理"和"已完成"
- ✅ API 可以根据状态显示不同的操作按钮
修正3: 撤销记录保存撤销时间
问题: 重置进度时,无法知道具体在什么时候撤销的。
解决方案:
- 在
OrderStateLog模型中添加cancelled_at字段 - 重置进度时,自动记录撤销时间:
order.state_logs.filter(is_cancelled=False).update( is_cancelled=True, cancelled_at=timezone.now() )
影响:
- ✅ 完整的审计追踪
- ✅ 可以分析订单被重置的频率和原因
- ✅ 便于问题排查和数据分析
数据库迁移
# 生成迁移文件
python manage.py makemigrations stateflow
# 应用迁移
python manage.py migrate
迁移文件: 0010_remove_orderstatelog_notes_and_more.py
变更内容:
- 添加
cancelled_at字段(DateTimeField, nullable) - 添加
is_cancelled字段(BooleanField, default=False)
测试验证
所有测试通过 ✅ (6 tests in 0.598s)
新增测试:
test_reset_progress: 验证重置进度不删除记录test_timeline_with_cancelled: 验证时间线包含撤销记录test_initial_state: 验证初始状态为 None
API 变更
返回值变更
advance_to_next_state(order, user):
- 之前:
bool - 现在:
Tuple[bool, str](是否成功, 消息)
can_advance_to_next_state(order):
- 之前:
Tuple[bool, str] - 现在:
Tuple[bool, str](是否可以推进, 原因)
新增函数
get_overall_status(order) -> str:
- 返回:
'not_started'|'in_progress'|'completed' - 用途: 区分未开始和已完成(两者的 current_state 都是 None)
行为变更
reset_order_progress(order):
- 之前: 删除所有完成记录
- 现在: 标记所有记录为已撤销,记录撤销时间
get_order_current_state(order):
- 之前: 无记录时返回第一个节点
- 现在: 无记录时返回
None
Admin 界面更新
OrderStateLog 内联
新增字段显示:
is_cancelled: 是否已撤销cancelled_at: 撤销时间
OrderAdmin
显示逻辑更新:
current_state_display: 显示"未开始"、"已完成"或具体状态名- 重置进度操作提示: "已标记为撤销"而非"已删除"
升级指南
如果你已经在使用旧版本的 stateflow:
-
备份数据库(重要!)
-
应用迁移:
python manage.py migrate stateflow -
更新代码:
- 将
advance_to_next_state()的返回值解包为(success, message) - 使用
get_overall_status()替代直接判断current_state is None
- 将
-
测试验证:
python manage.py test stateflow
向后兼容性
⚠️ 破坏性变更:
get_order_current_state()的返回值变化advance_to_next_state()的返回值从bool变为Tuple[bool, str]
✅ 兼容性保持:
- 数据库表结构只增不减
- 现有的 OrderStateLog 记录自动设置
is_cancelled=False - API 端点可以平滑升级
最佳实践
-
永远不要删除 OrderStateLog
- 使用 Admin 界面时,设置
can_delete=False - 在 API 中禁用 DELETE 端点
- 使用 Admin 界面时,设置
-
记录所有操作人
advance_to_next_state()必须传入completed_by- 可以在中间件中自动获取当前用户
-
定期清理撤销记录
- 建议保留至少 1 年的撤销记录
- 可以归档到历史表而不是直接删除
-
监控重置频率
- 高频率的重置可能表明流程设计有问题
- 可以添加告警机制
疑问解答
Q: ProcessNode 和 OrderStateLog 有什么区别?
A:
- ProcessNode: 流程模板(定义流程有哪些步骤)
- OrderStateLog: 订单实例的执行记录(记录实际完成了什么)
类比:
- ProcessNode = 菜谱(定义做菜步骤)
- OrderStateLog = 做菜记录(记录实际操作)
详细说明请参考 README.md 的"ProcessNode vs OrderStateLog"章节。