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