1
0
forked from erp-dev/erp
Files
erpnew/docs/REFACTOR_CURRENT_STATE_2025-11-19.md

278 lines
6.8 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 current_state 重构记录
**日期**: 2025-11-19
**目标**: 消除 `current_state` 语义歧义,使其可配置
---
## 重构目标
### 问题
原有的 `current_state` 始终表示"下一个待执行的节点",但在某些业务场景下,需要显示"最后完成的节点",语义不够清晰,容易混淆。
### 解决方案
1. 添加两个明确语义的方法:
- `get_last_completed_state()` - 返回最后完成的状态
- `get_next_pending_state()` - 返回下一个待执行的状态
2. `current_state` 变为可配置模式:
- 通过 `settings.STATEFLOW_CURRENT_STATE_MODE` 控制行为
- `'NEXT'` (默认): 返回下一个待执行的节点(原有行为)
- `'LAST'`: 返回最后完成的节点(新增模式)
3. 保持所有API接口不变确保向后兼容
---
## 修改文件清单
### 1. `stateflow/services.py`
**新增函数**:
- `get_last_completed_state(business_object)` - 获取最后完成的状态
- `get_next_pending_state_simple(business_object)` - 获取下一个待执行的状态(简化版)
**修改函数**:
- `get_business_object_current_state(business_object)` - 根据配置返回不同结果
```python
def get_business_object_current_state(business_object):
"""根据 settings.STATEFLOW_CURRENT_STATE_MODE 决定返回内容"""
from django.conf import settings
mode = getattr(settings, 'STATEFLOW_CURRENT_STATE_MODE', 'NEXT')
if mode == 'LAST':
return get_last_completed_state(business_object)
else: # 默认 'NEXT'
return get_next_pending_state_simple(business_object)
```
### 2. `stateflow/models.py` (BusinessObject)
**新增方法**:
- `get_last_completed_state()` - 获取最后完成的状态
- `get_next_pending_state()` - 获取下一个待执行的状态
**修改方法**:
- `get_current_state()` - 更新文档说明,明确其行为可配置
### 3. `stateflow/admin.py`
**修改**:
- `current_state_display()` - 根据配置模式显示不同文案
- NEXT模式: "进行中 (下一步: xxx)"
- LAST模式: "进行中 (已完成: xxx)"
- `params()` - 更新文档说明
### 4. `flower/settings.py`
**新增配置**:
```python
# Stateflow 配置
STATEFLOW_CURRENT_STATE_MODE = 'NEXT' # 或 'LAST'
```
添加详细的配置说明文档。
---
## 兼容性保证
### ✅ API层面完全兼容
- 所有API端点无需修改
- 所有序列化器无需修改
- 返回结构保持一致
### ✅ 模型层面保持兼容
- `PlateOrder.status` 属性无需修改
- `PrintingJob.status` 属性无需修改
- 方法签名完全一致
### ✅ 测试验证
- ✅ stateflow.tests.test_services - 10个测试全部通过
- ✅ printing.test_plate_order - 11个测试全部通过
- ✅ printing.test_plate_order_advance - 3个测试全部通过
-**总计95个测试全部通过**
---
## 使用指南
### 默认行为 (NEXT模式)
```python
# settings.py
STATEFLOW_CURRENT_STATE_MODE = 'NEXT' # 默认
# 业务代码
current = business_object.get_current_state()
# 返回:下一个待执行的节点
# 示例:流程 [质检] → [包装] → [发货]
# 完成质检后:
current_state.name # "包装"(下一步要做的)
status # "包装"
progress # 33.3%
```
### LAST模式
```python
# settings.py
STATEFLOW_CURRENT_STATE_MODE = 'LAST'
# 业务代码
current = business_object.get_current_state()
# 返回:最后完成的节点
# 示例:流程 [质检] → [包装] → [发货]
# 完成质检后:
current_state.name # "质检"(刚完成的)
status # "质检"
progress # 33.3%
```
### 推荐做法:使用明确命名的方法
```python
# ✅ 推荐:语义清晰
last_done = business_object.get_last_completed_state()
next_todo = business_object.get_next_pending_state()
# ⚠️ 可用但需注意:语义取决于配置
current = business_object.get_current_state()
```
---
## status 和 current_state 的关系
### status 属性逻辑(不变)
```python
@property
def status(self) -> str:
if not self.business_object:
return '未开始'
current_state = self.business_object.get_current_state()
if current_state is None:
return '已完成'
progress = self.business_object.get_progress_percentage()
if progress == 0:
return '未开始'
return current_state.name
```
### 不同模式下的表现
| 场景 | progress | NEXT模式 | LAST模式 |
|------|----------|----------|----------|
| 未开始 | 0% | `status="未开始"`<br>`current_state="质检"` | `status="未开始"`<br>`current_state=None` |
| 完成质检 | 33% | `status="包装"`<br>`current_state="包装"` | `status="质检"`<br>`current_state="质检"` |
| 全部完成 | 100% | `status="已完成"`<br>`current_state=None` | `status="已完成"`<br>`current_state="发货"` |
---
## Admin 显示变化
### NEXT模式默认
```
当前状态: 进行中 (下一步: 包装)
```
### LAST模式
```
当前状态: 进行中 (已完成: 质检)
```
---
## 注意事项
### ⚠️ 语义变化
- 切换配置会改变 `status``status_id` 的含义
- 前端显示文案可能需要相应调整
### ⚠️ 环境一致性
- 建议在所有环境(开发/测试/生产)使用相同配置
- 避免因配置不同导致行为差异
### ⚠️ 测试注意
- 如需切换模式,确保充分测试
- 可以使用 `@override_settings` 装饰器测试不同模式
```python
from django.test import override_settings
@override_settings(STATEFLOW_CURRENT_STATE_MODE='LAST')
def test_with_last_mode():
# 测试 LAST 模式
pass
```
---
## 设计优势
### ✅ 消除歧义
- 通过命名明确区分"最后完成"和"下一个待执行"
- 减少开发者理解成本
### ✅ 灵活可配置
- 可以根据业务需求选择不同模式
- 无需修改代码即可切换行为
### ✅ 向后兼容
- API完全不变
- 测试全部通过
- 现有集成无影响
### ✅ 代码清晰
- 新增方法语义明确
- 文档完善
- 易于维护
---
## 未来优化建议
### 方案A逐步迁移到明确命名的方法
```python
# 在新代码中推荐使用
business_object.get_last_completed_state()
business_object.get_next_pending_state()
# 而非
business_object.get_current_state()
```
### 方案B考虑废弃 current_state
```python
# 未来可能
@deprecated("请使用 get_last_completed_state() 或 get_next_pending_state()")
def get_current_state(self):
pass
```
---
## 总结
此次重构成功实现了以下目标:
1. ✅ 添加了语义明确的 `get_last_completed_state()``get_next_pending_state()` 方法
2. ✅ 使 `current_state` 可配置,默认保持原有行为
3. ✅ 所有API接口保持不变
4. ✅ Admin仅作轻微文案调整
5. ✅ 95个测试全部通过
**重构风险**: 低
**兼容性**: 完全兼容
**测试覆盖**: 完整
---
**重构完成时间**: 2025-11-19
**测试通过率**: 100% (95/95)