forked from erp-dev/erp
clean: move docs and remove temp test file
This commit is contained in:
277
docs/REFACTOR_CURRENT_STATE_2025-11-19.md
Normal file
277
docs/REFACTOR_CURRENT_STATE_2025-11-19.md
Normal file
@@ -0,0 +1,277 @@
|
||||
# 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)
|
||||
|
||||
Reference in New Issue
Block a user