# Stateflow 修正记录 ## 2025-11-11: 重要架构调整 ### 修正1: 日志不可删除,仅能标记为已撤销 **问题**: 之前重置进度时会删除所有完成记录,导致操作历史丢失。 **解决方案**: - 添加 `OrderStateLog.is_cancelled` 字段(是否已撤销) - 添加 `OrderStateLog.cancelled_at` 字段(撤销时间) - 修改 `reset_order_progress()` 函数,不再删除记录,而是: ```python 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` 字段 - 重置进度时,自动记录撤销时间: ```python order.state_logs.filter(is_cancelled=False).update( is_cancelled=True, cancelled_at=timezone.now() ) ``` **影响**: - ✅ 完整的审计追踪 - ✅ 可以分析订单被重置的频率和原因 - ✅ 便于问题排查和数据分析 ## 数据库迁移 ```bash # 生成迁移文件 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: 1. **备份数据库**(重要!) 2. **应用迁移**: ```bash python manage.py migrate stateflow ``` 3. **更新代码**: - 将 `advance_to_next_state()` 的返回值解包为 `(success, message)` - 使用 `get_overall_status()` 替代直接判断 `current_state is None` 4. **测试验证**: ```bash python manage.py test stateflow ``` ## 向后兼容性 ⚠️ **破坏性变更**: - `get_order_current_state()` 的返回值变化 - `advance_to_next_state()` 的返回值从 `bool` 变为 `Tuple[bool, str]` ✅ **兼容性保持**: - 数据库表结构只增不减 - 现有的 OrderStateLog 记录自动设置 `is_cancelled=False` - API 端点可以平滑升级 ## 最佳实践 1. **永远不要删除 OrderStateLog** - 使用 Admin 界面时,设置 `can_delete=False` - 在 API 中禁用 DELETE 端点 2. **记录所有操作人** - `advance_to_next_state()` 必须传入 `completed_by` - 可以在中间件中自动获取当前用户 3. **定期清理撤销记录** - 建议保留至少 1 年的撤销记录 - 可以归档到历史表而不是直接删除 4. **监控重置频率** - 高频率的重置可能表明流程设计有问题 - 可以添加告警机制 ## 疑问解答 ### Q: ProcessNode 和 OrderStateLog 有什么区别? **A**: - **ProcessNode**: 流程模板(定义流程有哪些步骤) - **OrderStateLog**: 订单实例的执行记录(记录实际完成了什么) 类比: - ProcessNode = 菜谱(定义做菜步骤) - OrderStateLog = 做菜记录(记录实际操作) 详细说明请参考 README.md 的"ProcessNode vs OrderStateLog"章节。