1
0
forked from erp-dev/erp
Files
erpnew/stateflow
2025-11-13 18:22:42 +08:00
..
2025-11-13 18:22:42 +08:00
2025-11-13 18:22:42 +08:00
2025-11-13 18:22:42 +08:00
2025-11-11 18:05:10 +08:00
2025-11-12 17:08:20 +08:00
2025-11-11 18:05:10 +08:00
2025-11-13 18:22:42 +08:00
2025-11-11 18:05:10 +08:00
2025-11-13 18:22:42 +08:00
2025-11-13 18:22:42 +08:00
2025-11-13 18:22:42 +08:00
2025-11-12 17:08:20 +08:00

Stateflow 状态流转系统

架构概述

Stateflow 是一个基于日志的订单状态流转管理系统,采用服务层模式实现业务逻辑与数据访问的分离。

核心概念

  • State (状态): 流程中的一个节点,可以附带参数
  • Process (流程模板): 由多个有序状态组成的流程定义
  • Order (订单实例): 流程的具体执行实例
  • OrderStateLog (完成日志): 记录订单完成每个状态的时间点和操作人

数据模型

State

State(name, parameters=[StateParameter(...)])
  • 状态节点定义
  • 支持附加参数(键值对)

Process

Process(name, state_nodes=ManyToMany[ProcessNode])
  • 流程模板,定义状态流转顺序
  • 通过 ProcessNode 中间表关联 State,支持排序

ProcessNode

ProcessNode(process, state, order)
  • Process 和 State 的多对多关联表
  • order 字段定义状态在流程中的执行顺序

Order

Order(process, metadata={})
  • 流程的具体实例
  • 不存储 current_state 字段
  • 当前状态通过查询 OrderStateLog 推导

OrderStateLog

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

示例:

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'

状态推进

from stateflow.services import advance_to_next_state

# 推进到下一个状态(需要传入操作人)
success = advance_to_next_state(order, completed_by=request.user)

推进规则:

  • 如果是初始状态(None),推进到第一个节点
  • 自动查找当前状态
  • 验证是否可以推进(是否已完成)
  • 创建 OrderStateLog 记录完成时间和操作人
  • 返回 (True, message) 表示成功,(False, reason) 表示失败

完整时间线

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. 创建流程模板

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. 创建订单并推进

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 中使用

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

测试

运行测试:

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