forked from erp-dev/erp
feat: new modul (stateflow)
This commit is contained in:
201
stateflow/CHANGELOG.md
Normal file
201
stateflow/CHANGELOG.md
Normal file
@@ -0,0 +1,201 @@
|
||||
# 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"章节。
|
||||
Reference in New Issue
Block a user