1
0
forked from erp-dev/erp
Files
erpnew/stateflow/README.md
2025-11-11 18:05:10 +08:00

285 lines
9.1 KiB
Markdown
Raw 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.
# Stateflow 状态流转系统
## 架构概述
Stateflow 是一个基于日志的订单状态流转管理系统,采用服务层模式实现业务逻辑与数据访问的分离。
### 核心概念
- **State (状态)**: 流程中的一个节点,可以附带参数
- **Process (流程模板)**: 由多个有序状态组成的流程定义
- **Order (订单实例)**: 流程的具体执行实例
- **OrderStateLog (完成日志)**: 记录订单完成每个状态的时间点和操作人
## 数据模型
### State
```python
State(name, parameters=[StateParameter(...)])
```
- 状态节点定义
- 支持附加参数(键值对)
### Process
```python
Process(name, state_nodes=ManyToMany[ProcessNode])
```
- 流程模板,定义状态流转顺序
- 通过 `ProcessNode` 中间表关联 `State`,支持排序
### ProcessNode
```python
ProcessNode(process, state, order)
```
- Process 和 State 的多对多关联表
- `order` 字段定义状态在流程中的执行顺序
### Order
```python
Order(process, metadata={})
```
- 流程的具体实例
- **不存储** `current_state` 字段
- 当前状态通过查询 `OrderStateLog` 推导
### OrderStateLog
```python
OrderStateLog(order, state, completed_at, completed_by, is_cancelled, cancelled_at)
```
- 记录订单完成某个状态的日志
- `completed_at`: 完成时间
- `completed_by`: 操作人
- `is_cancelled`: 是否已撤销
- `cancelled_at`: 撤销时间
- 唯一约束: `(order, state)` - 每个状态只能有一条记录
- **不允许删除**,重置进度时只标记为已撤销
## 核心逻辑
### 状态推导规则
当前状态的推导遵循以下规则:
1. **未开始**: 没有任何有效完成日志(或所有记录都被撤销) → 返回 `None`
2. **进行中**: 有部分完成日志 → 返回下一个未完成的状态
3. **已完成**: 所有状态都已完成 → 返回 `None`
**重要**: 初始状态是 `None`(未开始),而不是第一个节点。
示例:
```python
from stateflow.services import get_order_current_state, get_overall_status
# 获取当前状态None = 未开始或已完成)
current_state = get_order_current_state(order)
# 获取整体状态类型
status = get_overall_status(order) # 'not_started', 'in_progress', 'completed'
```
### 状态推进
```python
from stateflow.services import advance_to_next_state
# 推进到下一个状态(需要传入操作人)
success = advance_to_next_state(order, completed_by=request.user)
```
推进规则:
- 如果是初始状态(`None`),推进到第一个节点
- 自动查找当前状态
- 验证是否可以推进(是否已完成)
- 创建 `OrderStateLog` 记录完成时间和操作人
- 返回 `(True, message)` 表示成功,`(False, reason)` 表示失败
### 完整时间线
```python
from stateflow.services import get_order_state_timeline
# 获取完整的状态时间线
timeline = get_order_state_timeline(order)
# [
# {'state': State1, 'completed_at': datetime, 'completed_by': User, 'is_completed': True},
# {'state': State2, 'completed_at': None, 'completed_by': None, 'is_completed': False},
# ...
# ]
```
## 服务层 API
所有业务逻辑封装在 `stateflow/services.py` 中,可在 Admin、API、任务队列等场景复用。
### 主要函数
#### `get_order_current_state(order) -> State | None`
获取订单当前应处理的状态。
#### `get_overall_status(order) -> str`
返回订单整体状态:
- `'not_started'`: 未开始
- `'in_progress'`: 进行中
- `'completed'`: 已完成
#### `get_order_state_status(order, state) -> str`
返回订单中某个状态的状态:
- `'not_started'`: 未开始
- `'in_progress'`: 进行中
- `'completed'`: 已完成
#### `advance_to_next_state(order, completed_by) -> Tuple[bool, str]`
推进到下一个状态,创建完成日志。返回 (是否成功, 消息)。
#### `get_order_state_timeline(order) -> List[dict]`
获取完整时间线,包含所有状态的完成情况(包括已撤销的记录)。
#### `get_progress_percentage(order) -> float`
计算完成进度百分比0.0 - 100.0)。
#### `reset_order_progress(order)`
重置订单进度。注意:**不删除日志记录**,而是标记为已撤销并记录撤销时间,保留完整的操作历史。
#### `can_advance_to_next_state(order) -> Tuple[bool, str]`
检查是否可以继续推进。返回 (是否可以推进, 原因)。
## 使用示例
### 1. 创建流程模板
```python
from stateflow.models import State, Process, ProcessNode
# 创建状态
pending = State.objects.create(name="待审核")
approved = State.objects.create(name="已审核")
shipped = State.objects.create(name="已发货")
# 创建流程
process = Process.objects.create(name="订单流程")
# 关联状态(设置顺序)
ProcessNode.objects.create(process=process, state=pending, order=1)
ProcessNode.objects.create(process=process, state=approved, order=2)
ProcessNode.objects.create(process=process, state=shipped, order=3)
```
### 2. 创建订单并推进
```python
from stateflow.models import Order
from stateflow.services import get_order_current_state, advance_to_next_state, get_overall_status
# 创建订单实例
order = Order.objects.create(process=process, metadata={'order_no': 'SO-001'})
# 查看当前状态(初始状态是 None
current = get_order_current_state(order) # None
status = get_overall_status(order) # 'not_started'
# 推进到第一个状态
success, msg = advance_to_next_state(order, completed_by=request.user)
current = get_order_current_state(order) # approved
# 推进到下一个状态
success, msg = advance_to_next_state(order, completed_by=request.user)
current = get_order_current_state(order) # shipped
```
### 3. 在 API 中使用
```python
from rest_framework.decorators import action
from rest_framework.response import Response
from stateflow.services import advance_to_next_state, get_order_state_timeline
class OrderViewSet(viewsets.ModelViewSet):
@action(detail=True, methods=['post'])
def advance(self, request, pk=None):
order = self.get_object()
success, message = advance_to_next_state(order, completed_by=request.user)
if success:
return Response({'status': 'advanced', 'message': message})
return Response({'status': 'failed', 'message': message}, status=400)
@action(detail=True, methods=['get'])
def timeline(self, request, pk=None):
order = self.get_object()
timeline = get_order_state_timeline(order)
return Response(timeline)
```
## Admin 配置
Admin 界面提供以下功能:
1. **State 管理**: 创建和编辑状态,支持内联编辑参数
2. **Process 管理**: 定义流程,通过内联表添加有序状态节点
3. **Order 管理**:
- 查看完成日志(只读内联)
- 批量操作:推进到下一状态、重置进度
- 显示当前状态、完成百分比
4. **OrderStateLog 管理**: 只读日志查看,用于审计
## 迁移历史
- `0001_initial.py`: 初始模型State, Process with CharField state_nodes
- `0002-0007`: 其他应用迁移
- `0008_process_state_nodes_remove_process_current_state...`: 将 state_nodes 改为 ManyToMany创建 ProcessNode 和 Order
- `0009_remove_order_current_state_orderstatelog`: 移除 Order.current_state创建 OrderStateLog
## 测试
运行测试:
```bash
python manage.py test stateflow
```
测试覆盖:
- ✅ 初始状态推导
- ✅ 状态推进逻辑
- ✅ 状态类型判断
- ✅ 完整时间线生成
- ✅ 进度重置
## 设计优势
1. **审计完整**: 每次状态变更都有时间和操作人记录
2. **数据一致**: 状态从日志推导,无冗余存储
3. **逻辑复用**: 服务层可在 Admin/API/Task 中共享
4. **灵活扩展**: 可轻松添加状态前置条件、权限检查等
5. **可追溯**: 通过 OrderStateLog 实现完整的操作历史
6. **历史保留**: 重置进度时不删除记录,保留完整的操作痕迹
7. **撤销追踪**: 记录撤销时间,方便审计和问题追溯
## ProcessNode vs OrderStateLog
很多人会混淆这两个表,这里做详细说明:
### ProcessNode (流程模板)
- **作用**: 定义流程包含哪些状态,以及执行顺序
- **关系**: Process ↔ State 的多对多关联
- **层级**: 模板层(一对多)
- **类比**: "菜谱",定义做菜的步骤
- **示例**: 订单流程 = [待审核(1) → 已审核(2) → 已发货(3)]
### OrderStateLog (订单实例)
- **作用**: 记录某个订单完成了哪些状态,以及完成时间、操作人
- **关系**: Order → State 的完成记录
- **层级**: 实例层(每个订单独立)
- **类比**: "做菜记录",记录实际做了什么、何时做的
- **示例**: 订单#001 在 2025-01-10 由张三完成了"待审核"状态
## 注意事项
1. **唯一约束**: 每个 `(order, state)` 只能有一条记录
2. **顺序性**: 必须按 ProcessNode.order 顺序完成,不能跳过
3. **操作人必填**: `advance_to_next_state()` 必须传入 `completed_by` 参数
4. **不可删除**: OrderStateLog 不允许删除,只能标记为已撤销
5. **保留历史**: 重置进度时保留所有历史记录,并记录撤销时间
6. **初始状态**: 新订单的初始状态是 `None`(未开始),而不是第一个节点