# 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"章节。
