forked from erp-dev/erp
feat: stateflow v2 (params required)
This commit is contained in:
@@ -17,34 +17,41 @@ class StateAPITestCase(TestCase):
|
||||
"""测试 State API"""
|
||||
|
||||
def setUp(self):
|
||||
"""设置测试数据"""
|
||||
self.client = APIClient()
|
||||
self.user = User.objects.create_user(username='testuser', password='testpass')
|
||||
self.client.force_authenticate(user=self.user)
|
||||
|
||||
# 创建基础参数供测试使用
|
||||
self.param1 = models.StateParameter.objects.create(
|
||||
key='param1', value='value1', description='参数1'
|
||||
)
|
||||
self.param2 = models.StateParameter.objects.create(
|
||||
key='param2', value='value2', description='参数2'
|
||||
)
|
||||
|
||||
# 创建基础状态供测试使用
|
||||
self.state1 = models.State.objects.create(name='状态1', description='描述1')
|
||||
self.state2 = models.State.objects.create(name='状态2', description='描述2')
|
||||
|
||||
def test_create_state(self):
|
||||
"""测试创建状态"""
|
||||
data = {
|
||||
'name': '测试状态',
|
||||
'description': '这是一个测试状态',
|
||||
'parameters': [
|
||||
{'key': 'param1', 'value': 'value1', 'description': '参数1'},
|
||||
{'key': 'param2', 'value': 'value2', 'description': '参数2'},
|
||||
]
|
||||
'parameter_ids': [self.param1.id, self.param2.id]
|
||||
}
|
||||
|
||||
response = self.client.post('/api/v1/stateflow/states/', data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||
self.assertEqual(response.data['name'], '测试状态')
|
||||
|
||||
# 验证参数已创建
|
||||
# 验证参数已关联
|
||||
state = models.State.objects.get(name='测试状态')
|
||||
self.assertEqual(state.parameters.count(), 2)
|
||||
|
||||
def test_list_states(self):
|
||||
"""测试获取状态列表"""
|
||||
models.State.objects.create(name='状态1', description='描述1')
|
||||
models.State.objects.create(name='状态2', description='描述2')
|
||||
|
||||
response = self.client.get('/api/v1/stateflow/states/?limit=10&offset=0')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data['count'], 2)
|
||||
@@ -52,43 +59,37 @@ class StateAPITestCase(TestCase):
|
||||
|
||||
def test_retrieve_state(self):
|
||||
"""测试获取状态详情"""
|
||||
state = models.State.objects.create(name='测试状态', description='描述')
|
||||
models.StateParameter.objects.create(state=state, key='key1', value='value1')
|
||||
self.state1.parameters.add(self.param1)
|
||||
|
||||
response = self.client.get(f'/api/v1/stateflow/states/{state.id}/')
|
||||
response = self.client.get(f'/api/v1/stateflow/states/{self.state1.id}/')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data['name'], '测试状态')
|
||||
self.assertEqual(response.data['name'], '状态1')
|
||||
self.assertEqual(len(response.data['parameters']), 1)
|
||||
|
||||
def test_update_state(self):
|
||||
"""测试更新状态"""
|
||||
state = models.State.objects.create(name='旧名称', description='旧描述')
|
||||
|
||||
data = {
|
||||
'name': '新名称',
|
||||
'description': '新描述',
|
||||
'parameters': [
|
||||
{'key': 'new_param', 'value': 'new_value', 'description': '新参数'},
|
||||
]
|
||||
'parameter_ids': [self.param1.id]
|
||||
}
|
||||
|
||||
response = self.client.put(f'/api/v1/stateflow/states/{state.id}/', data, format='json')
|
||||
response = self.client.put(f'/api/v1/stateflow/states/{self.state1.id}/', data, format='json')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
state.refresh_from_db()
|
||||
self.assertEqual(state.name, '新名称')
|
||||
self.assertEqual(state.parameters.count(), 1)
|
||||
self.state1.refresh_from_db()
|
||||
self.assertEqual(self.state1.name, '新名称')
|
||||
self.assertEqual(self.state1.parameters.count(), 1)
|
||||
|
||||
def test_delete_state(self):
|
||||
"""测试删除状态"""
|
||||
state = models.State.objects.create(name='待删除状态')
|
||||
|
||||
response = self.client.delete(f'/api/v1/stateflow/states/{state.id}/')
|
||||
response = self.client.delete(f'/api/v1/stateflow/states/{self.state2.id}/')
|
||||
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
|
||||
self.assertFalse(models.State.objects.filter(id=state.id).exists())
|
||||
self.assertFalse(models.State.objects.filter(id=self.state2.id).exists())
|
||||
|
||||
def test_search_states(self):
|
||||
"""测试搜索状态"""
|
||||
# 创建特定名称的状态用于搜索测试
|
||||
models.State.objects.create(name='审核状态', description='需要审核')
|
||||
models.State.objects.create(name='发货状态', description='已经发货')
|
||||
|
||||
@@ -105,18 +106,18 @@ class StateAPITestCase(TestCase):
|
||||
content_type="text/plain"
|
||||
)
|
||||
|
||||
# 先创建状态
|
||||
state = models.State.objects.create(name='测试状态', description='带附件')
|
||||
|
||||
# 创建带附件的参数
|
||||
param = models.StateParameter.objects.create(
|
||||
state=state,
|
||||
key='document',
|
||||
value='测试文档',
|
||||
attachment=test_file,
|
||||
description='这是一个测试文档'
|
||||
)
|
||||
|
||||
# 创建状态并关联参数
|
||||
state = models.State.objects.create(name='测试状态', description='带附件')
|
||||
state.parameters.add(param)
|
||||
|
||||
# 验证附件已保存
|
||||
self.assertIsNotNone(param.attachment)
|
||||
self.assertIn('test_doc', param.attachment.name) # 文件名可能有哈希前缀
|
||||
@@ -138,13 +139,13 @@ class StateAPITestCase(TestCase):
|
||||
|
||||
def test_state_parameter_without_attachment(self):
|
||||
"""测试创建不带附件的状态参数"""
|
||||
state = models.State.objects.create(name='测试状态2', description='不带附件')
|
||||
param = models.StateParameter.objects.create(
|
||||
state=state,
|
||||
key='simple_param',
|
||||
value='简单值',
|
||||
description='简单参数'
|
||||
)
|
||||
state = models.State.objects.create(name='测试状态2', description='不带附件')
|
||||
state.parameters.add(param)
|
||||
|
||||
# 验证附件字段为空
|
||||
self.assertFalse(param.attachment)
|
||||
@@ -161,14 +162,14 @@ class StateAPITestCase(TestCase):
|
||||
|
||||
def test_update_state_parameter_with_attachment(self):
|
||||
"""测试更新状态参数时添加附件"""
|
||||
# 创建初始状态和参数(不带附件)
|
||||
state = models.State.objects.create(name='测试状态3', description='更新附件')
|
||||
# 创建初始参数(不带附件)
|
||||
param = models.StateParameter.objects.create(
|
||||
state=state,
|
||||
key='updatable_param',
|
||||
value='初始值',
|
||||
description='可更新参数'
|
||||
)
|
||||
state = models.State.objects.create(name='测试状态3', description='更新附件')
|
||||
state.parameters.add(param)
|
||||
|
||||
# 验证初始无附件
|
||||
self.assertFalse(param.attachment)
|
||||
@@ -206,13 +207,13 @@ class StateAPITestCase(TestCase):
|
||||
content_type="image/jpeg"
|
||||
)
|
||||
|
||||
state = models.State.objects.create(name='图片状态', description='带图片')
|
||||
param = models.StateParameter.objects.create(
|
||||
state=state,
|
||||
key='image',
|
||||
value='测试图片',
|
||||
attachment=test_file
|
||||
)
|
||||
state = models.State.objects.create(name='图片状态', description='带图片')
|
||||
state.parameters.add(param)
|
||||
|
||||
# 通过 API 获取
|
||||
response = self.client.get(f'/api/v1/stateflow/states/{state.id}/')
|
||||
@@ -229,6 +230,129 @@ class StateAPITestCase(TestCase):
|
||||
# 清理
|
||||
if param.attachment:
|
||||
param.attachment.delete()
|
||||
|
||||
def test_state_parameter_is_required(self):
|
||||
"""测试参数必填字段"""
|
||||
# 创建必填参数
|
||||
required_param = models.StateParameter.objects.create(
|
||||
key='required_param',
|
||||
value='必填参数',
|
||||
is_required=True
|
||||
)
|
||||
|
||||
# 创建可选参数
|
||||
optional_param = models.StateParameter.objects.create(
|
||||
key='optional_param',
|
||||
value='可选参数',
|
||||
is_required=False
|
||||
)
|
||||
|
||||
# 创建状态并关联参数
|
||||
state = models.State.objects.create(name='测试状态', description='测试必填参数')
|
||||
state.parameters.add(required_param, optional_param)
|
||||
|
||||
# 通过 API 验证
|
||||
response = self.client.get(f'/api/v1/stateflow/states/{state.id}/')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
parameters = response.data['parameters']
|
||||
self.assertEqual(len(parameters), 2)
|
||||
|
||||
# 验证必填字段正确返回
|
||||
required_params = [p for p in parameters if p['is_required']]
|
||||
optional_params = [p for p in parameters if not p['is_required']]
|
||||
|
||||
self.assertEqual(len(required_params), 1)
|
||||
self.assertEqual(len(optional_params), 1)
|
||||
self.assertEqual(required_params[0]['key'], 'required_param')
|
||||
|
||||
def test_state_get_parameters_method(self):
|
||||
"""测试 State.get_parameters() 方法"""
|
||||
# 创建必填和可选参数
|
||||
required_param = models.StateParameter.objects.create(
|
||||
key='required1',
|
||||
value='必填',
|
||||
is_required=True
|
||||
)
|
||||
optional_param = models.StateParameter.objects.create(
|
||||
key='optional1',
|
||||
value='可选',
|
||||
is_required=False
|
||||
)
|
||||
|
||||
state = models.State.objects.create(name='测试状态')
|
||||
state.parameters.add(required_param, optional_param)
|
||||
|
||||
# 测试获取所有参数
|
||||
all_params = state.get_parameters(required_only=False)
|
||||
self.assertEqual(len(all_params), 2)
|
||||
|
||||
# 测试只获取必填参数
|
||||
required_params = state.get_parameters(required_only=True)
|
||||
self.assertEqual(len(required_params), 1)
|
||||
self.assertEqual(required_params[0].key, 'required1')
|
||||
self.assertTrue(required_params[0].is_required)
|
||||
|
||||
def test_state_parameter_is_image_path(self):
|
||||
"""测试参数图片路径字段"""
|
||||
# 创建普通参数
|
||||
normal_param = models.StateParameter.objects.create(
|
||||
key='normal_param',
|
||||
value='普通文本值',
|
||||
is_image_path=False
|
||||
)
|
||||
|
||||
# 创建图片路径参数
|
||||
image_param = models.StateParameter.objects.create(
|
||||
key='image_param',
|
||||
value='https://example.com/image.jpg',
|
||||
is_image_path=True
|
||||
)
|
||||
|
||||
# 创建状态并关联参数
|
||||
state = models.State.objects.create(name='测试图片参数', description='测试is_image_path字段')
|
||||
state.parameters.add(normal_param, image_param)
|
||||
|
||||
# 通过 API 验证
|
||||
response = self.client.get(f'/api/v1/stateflow/states/{state.id}/')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
|
||||
parameters = response.data['parameters']
|
||||
self.assertEqual(len(parameters), 2)
|
||||
|
||||
# 验证 is_image_path 字段正确返回
|
||||
image_params = [p for p in parameters if p['is_image_path']]
|
||||
normal_params = [p for p in parameters if not p['is_image_path']]
|
||||
|
||||
self.assertEqual(len(image_params), 1)
|
||||
self.assertEqual(len(normal_params), 1)
|
||||
self.assertEqual(image_params[0]['key'], 'image_param')
|
||||
self.assertEqual(image_params[0]['value'], 'https://example.com/image.jpg')
|
||||
|
||||
def test_create_parameter_with_image_path_flag(self):
|
||||
"""测试创建带图片路径标记的参数"""
|
||||
param = models.StateParameter.objects.create(
|
||||
key='product_image',
|
||||
value='https://cdn.example.com/products/abc123.png',
|
||||
is_image_path=True,
|
||||
description='产品图片URL'
|
||||
)
|
||||
|
||||
# 验证字段已保存
|
||||
self.assertTrue(param.is_image_path)
|
||||
self.assertIn('https://', param.value)
|
||||
|
||||
# 创建状态并关联
|
||||
state = models.State.objects.create(name='产品展示')
|
||||
state.parameters.add(param)
|
||||
|
||||
# API 验证
|
||||
response = self.client.get(f'/api/v1/stateflow/states/{state.id}/')
|
||||
params = response.data['parameters']
|
||||
|
||||
self.assertEqual(len(params), 1)
|
||||
self.assertTrue(params[0]['is_image_path'])
|
||||
self.assertEqual(params[0]['key'], 'product_image')
|
||||
|
||||
|
||||
class ProcessAPITestCase(TestCase):
|
||||
@@ -322,3 +446,189 @@ class ProcessAPITestCase(TestCase):
|
||||
response = self.client.get('/api/v1/stateflow/processes/?search=订单&limit=10&offset=0')
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data['count'], 1)
|
||||
|
||||
|
||||
class BusinessObjectNewAPITestCase(TestCase):
|
||||
"""测试 BusinessObject 新增的 API"""
|
||||
|
||||
def setUp(self):
|
||||
self.client = APIClient()
|
||||
self.user = User.objects.create_user(username='testuser', password='testpass')
|
||||
self.client.force_authenticate(user=self.user)
|
||||
|
||||
# 创建状态和参数
|
||||
self.state1 = models.State.objects.create(name='状态1', description='第一个状态')
|
||||
self.state2 = models.State.objects.create(name='状态2', description='第二个状态')
|
||||
self.state3 = models.State.objects.create(name='状态3', description='第三个状态')
|
||||
|
||||
# 为状态1添加参数
|
||||
self.param1 = models.StateParameter.objects.create(
|
||||
key='param1', value='value1', is_required=True, description='必填参数'
|
||||
)
|
||||
self.param2 = models.StateParameter.objects.create(
|
||||
key='param2', value='value2', is_required=False, description='可选参数'
|
||||
)
|
||||
self.state1.parameters.add(self.param1, self.param2)
|
||||
|
||||
# 创建流程
|
||||
self.process = models.Process.objects.create(name='测试流程')
|
||||
models.ProcessNode.objects.create(process=self.process, state=self.state1, order=0)
|
||||
models.ProcessNode.objects.create(process=self.process, state=self.state2, order=1)
|
||||
models.ProcessNode.objects.create(process=self.process, state=self.state3, order=2)
|
||||
|
||||
# 创建业务对象
|
||||
self.business_object = models.BusinessObject.objects.create(
|
||||
name='测试业务对象',
|
||||
process=self.process
|
||||
)
|
||||
|
||||
def test_next_pending_state_api(self):
|
||||
"""测试获取下一个待执行节点 API"""
|
||||
# 未开始时应返回第一个节点
|
||||
response = self.client.get(
|
||||
f'/api/v1/stateflow/business-objects/{self.business_object.id}/next_pending_state/'
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data['state']['id'], self.state1.id)
|
||||
self.assertEqual(response.data['order'], 0)
|
||||
self.assertIn('parameters', response.data)
|
||||
self.assertEqual(len(response.data['parameters']), 2)
|
||||
|
||||
# 测试不包含参数
|
||||
response = self.client.get(
|
||||
f'/api/v1/stateflow/business-objects/{self.business_object.id}/next_pending_state/?include_parameters=false'
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertNotIn('parameters', response.data)
|
||||
|
||||
# 推进一步(提供必填参数)
|
||||
self.client.post(
|
||||
f'/api/v1/stateflow/business-objects/{self.business_object.id}/advance/',
|
||||
{'parameters': {'param1': 'test_value'}},
|
||||
format='json'
|
||||
)
|
||||
|
||||
# 应返回第二个节点
|
||||
response = self.client.get(
|
||||
f'/api/v1/stateflow/business-objects/{self.business_object.id}/next_pending_state/'
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data['state']['id'], self.state2.id)
|
||||
|
||||
# 完成所有节点
|
||||
self.client.post(f'/api/v1/stateflow/business-objects/{self.business_object.id}/advance/')
|
||||
self.client.post(f'/api/v1/stateflow/business-objects/{self.business_object.id}/advance/')
|
||||
|
||||
# 应返回 None
|
||||
response = self.client.get(
|
||||
f'/api/v1/stateflow/business-objects/{self.business_object.id}/next_pending_state/'
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertIsNone(response.data['next_state'])
|
||||
|
||||
def test_pending_states_api(self):
|
||||
"""测试获取所有待执行节点 API"""
|
||||
# 初始状态应返回所有节点
|
||||
response = self.client.get(
|
||||
f'/api/v1/stateflow/business-objects/{self.business_object.id}/pending_states/'
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data['count'], 3)
|
||||
self.assertEqual(len(response.data['pending_states']), 3)
|
||||
|
||||
# 验证不包含 parameters
|
||||
self.assertNotIn('parameters', response.data['pending_states'][0])
|
||||
|
||||
# 推进一步(提供必填参数)
|
||||
self.client.post(
|
||||
f'/api/v1/stateflow/business-objects/{self.business_object.id}/advance/',
|
||||
{'parameters': {'param1': 'test_value'}},
|
||||
format='json'
|
||||
)
|
||||
|
||||
# 应只剩两个待执行节点
|
||||
response = self.client.get(
|
||||
f'/api/v1/stateflow/business-objects/{self.business_object.id}/pending_states/'
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data['count'], 2)
|
||||
|
||||
# 完成所有节点
|
||||
self.client.post(f'/api/v1/stateflow/business-objects/{self.business_object.id}/advance/')
|
||||
self.client.post(f'/api/v1/stateflow/business-objects/{self.business_object.id}/advance/')
|
||||
|
||||
# 应没有待执行节点
|
||||
response = self.client.get(
|
||||
f'/api/v1/stateflow/business-objects/{self.business_object.id}/pending_states/'
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data['count'], 0)
|
||||
|
||||
def test_current_state_parameters_api(self):
|
||||
"""测试获取当前状态(最后完成状态)参数 API"""
|
||||
# 未开始时,current_state 为 None,应返回无参数消息
|
||||
response = self.client.get(
|
||||
f'/api/v1/stateflow/business-objects/{self.business_object.id}/current_state_parameters/'
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(len(response.data['parameters']), 0)
|
||||
self.assertIn('message', response.data)
|
||||
|
||||
# 推进(完成第一个状态),current_state 变为 state1(最后完成的状态)
|
||||
self.client.post(
|
||||
f'/api/v1/stateflow/business-objects/{self.business_object.id}/advance/',
|
||||
{'parameters': {'param1': 'test_value'}},
|
||||
format='json'
|
||||
)
|
||||
|
||||
# 现在 current_state 是 state1(有参数)
|
||||
response = self.client.get(
|
||||
f'/api/v1/stateflow/business-objects/{self.business_object.id}/current_state_parameters/'
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data['state']['id'], self.state1.id)
|
||||
self.assertEqual(response.data['count'], 2)
|
||||
self.assertEqual(len(response.data['parameters']), 2)
|
||||
|
||||
# 测试只获取必填参数
|
||||
response = self.client.get(
|
||||
f'/api/v1/stateflow/business-objects/{self.business_object.id}/current_state_parameters/?required_only=true'
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data['count'], 1)
|
||||
self.assertEqual(response.data['parameters'][0]['key'], 'param1')
|
||||
|
||||
# 推进(完成第二个状态),current_state 变为 state2(无参数)
|
||||
self.client.post(f'/api/v1/stateflow/business-objects/{self.business_object.id}/advance/')
|
||||
|
||||
response = self.client.get(
|
||||
f'/api/v1/stateflow/business-objects/{self.business_object.id}/current_state_parameters/'
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data['state']['id'], self.state2.id)
|
||||
self.assertEqual(response.data['count'], 0)
|
||||
|
||||
def test_state_parameters_api(self):
|
||||
"""测试 State 的参数 API"""
|
||||
# 获取状态1的所有参数
|
||||
response = self.client.get(
|
||||
f'/api/v1/stateflow/states/{self.state1.id}/parameters/'
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data['state_id'], self.state1.id)
|
||||
self.assertEqual(response.data['count'], 2)
|
||||
self.assertEqual(len(response.data['parameters']), 2)
|
||||
|
||||
# 只获取必填参数
|
||||
response = self.client.get(
|
||||
f'/api/v1/stateflow/states/{self.state1.id}/parameters/?required_only=true'
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data['count'], 1)
|
||||
|
||||
# 测试没有参数的状态
|
||||
response = self.client.get(
|
||||
f'/api/v1/stateflow/states/{self.state2.id}/parameters/'
|
||||
)
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(response.data['count'], 0)
|
||||
|
||||
Reference in New Issue
Block a user