1
0
forked from erp-dev/erp

feat: new modul (stateflow)

This commit is contained in:
2025-11-11 18:05:10 +08:00
parent 2aafb93aad
commit 9898d71a7e
30 changed files with 3723 additions and 7 deletions

284
stateflow/README.md Normal file
View File

@@ -0,0 +1,284 @@
# 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`(未开始),而不是第一个节点