forked from erp-dev/erp
1061 lines
42 KiB
Python
1061 lines
42 KiB
Python
from django.test import TestCase
|
||
from django.contrib.auth.models import User
|
||
from rest_framework.test import APIClient
|
||
from rest_framework import status
|
||
from basic_info.models import (
|
||
Merchant, MerchantTypeEnum, WareHouse, WarehouseTypeEnum,
|
||
Employee, EmployeeType, EmployeeStatusEnum,
|
||
QuickInput, Product, ProductCategory, Supplier, Customer,
|
||
VehicleType, BankAccount, DeviceInfo, VehicleTransportRecord
|
||
)
|
||
|
||
|
||
class WarehouseAPITestCase(TestCase):
|
||
"""测试仓库 API"""
|
||
|
||
def setUp(self):
|
||
"""设置测试数据"""
|
||
# 创建商户
|
||
self.merchant = Merchant.objects.create(
|
||
name='测试商户',
|
||
type=MerchantTypeEnum.STORE
|
||
)
|
||
|
||
# 创建用户和员工
|
||
self.user = User.objects.create_user(
|
||
username='testuser',
|
||
password='testpass123'
|
||
)
|
||
self.employee = Employee.objects.create(
|
||
merchant=self.merchant,
|
||
sys_user=self.user,
|
||
name='测试员工'
|
||
)
|
||
|
||
# 设置 API 客户端
|
||
self.client = APIClient()
|
||
self.client.force_authenticate(user=self.user)
|
||
|
||
def test_create_warehouse_with_default_type(self):
|
||
"""测试创建仓库时使用默认类型"""
|
||
data = {
|
||
'name': '测试仓库1',
|
||
'location': '测试地址',
|
||
}
|
||
response = self.client.post('/api/backend/warehouses/', data, format='json')
|
||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||
self.assertEqual(response.data['type'], WarehouseTypeEnum.WHOLE.value)
|
||
|
||
# 验证数据库
|
||
warehouse = WareHouse.objects.get(id=response.data['id'])
|
||
self.assertEqual(warehouse.type, WarehouseTypeEnum.WHOLE)
|
||
|
||
def test_create_warehouse_with_whole_type(self):
|
||
"""测试创建整仓"""
|
||
data = {
|
||
'name': '整仓测试',
|
||
'type': WarehouseTypeEnum.WHOLE.value,
|
||
}
|
||
response = self.client.post('/api/backend/warehouses/', data, format='json')
|
||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||
self.assertEqual(response.data['type'], WarehouseTypeEnum.WHOLE.value)
|
||
|
||
def test_create_warehouse_with_scattered_type(self):
|
||
"""测试创建散仓"""
|
||
data = {
|
||
'name': '散仓测试',
|
||
'type': WarehouseTypeEnum.SCATTERED.value,
|
||
}
|
||
response = self.client.post('/api/backend/warehouses/', data, format='json')
|
||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||
self.assertEqual(response.data['type'], WarehouseTypeEnum.SCATTERED.value)
|
||
|
||
def test_list_warehouses_includes_type(self):
|
||
"""测试列表接口返回类型字段"""
|
||
WareHouse.objects.create(
|
||
merchant=self.merchant,
|
||
name='仓库1',
|
||
type=WarehouseTypeEnum.WHOLE
|
||
)
|
||
WareHouse.objects.create(
|
||
merchant=self.merchant,
|
||
name='仓库2',
|
||
type=WarehouseTypeEnum.SCATTERED
|
||
)
|
||
|
||
response = self.client.get('/api/backend/warehouses/')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
self.assertEqual(len(results), 2)
|
||
|
||
# 验证返回的数据包含 type 字段
|
||
for warehouse in results:
|
||
self.assertIn('type', warehouse)
|
||
self.assertIn(warehouse['type'], [WarehouseTypeEnum.WHOLE.value, WarehouseTypeEnum.SCATTERED.value])
|
||
|
||
def test_update_warehouse_type(self):
|
||
"""测试更新仓库类型"""
|
||
warehouse = WareHouse.objects.create(
|
||
merchant=self.merchant,
|
||
name='待更新仓库',
|
||
type=WarehouseTypeEnum.WHOLE
|
||
)
|
||
|
||
data = {'type': WarehouseTypeEnum.SCATTERED.value}
|
||
response = self.client.patch(f'/api/backend/warehouses/{warehouse.id}/', data, format='json')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
self.assertEqual(response.data['type'], WarehouseTypeEnum.SCATTERED.value)
|
||
|
||
# 验证数据库
|
||
warehouse.refresh_from_db()
|
||
self.assertEqual(warehouse.type, WarehouseTypeEnum.SCATTERED)
|
||
|
||
def test_retrieve_warehouse_includes_type(self):
|
||
"""测试检索单个仓库时包含类型字段"""
|
||
warehouse = WareHouse.objects.create(
|
||
merchant=self.merchant,
|
||
name='单个仓库',
|
||
type=WarehouseTypeEnum.SCATTERED
|
||
)
|
||
|
||
response = self.client.get(f'/api/backend/warehouses/{warehouse.id}/')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
self.assertEqual(response.data['type'], WarehouseTypeEnum.SCATTERED.value)
|
||
self.assertEqual(response.data['name'], '单个仓库')
|
||
|
||
def test_filter_warehouses_by_name(self):
|
||
"""测试通过 name 查询参数过滤仓库(icontains 模糊匹配)"""
|
||
WareHouse.objects.create(merchant=self.merchant, name='主仓库')
|
||
WareHouse.objects.create(merchant=self.merchant, name='备用仓库')
|
||
WareHouse.objects.create(merchant=self.merchant, name='临时仓库')
|
||
|
||
# 测试部分匹配
|
||
response = self.client.get('/api/backend/warehouses/?name=主')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
self.assertEqual(len(results), 1)
|
||
self.assertEqual(results[0]['name'], '主仓库')
|
||
|
||
# 测试包含"仓库"的所有记录
|
||
response = self.client.get('/api/backend/warehouses/?name=仓库')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
self.assertEqual(len(results), 3)
|
||
|
||
# 测试不匹配
|
||
response = self.client.get('/api/backend/warehouses/?name=不存在')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
self.assertEqual(len(results), 0)
|
||
|
||
|
||
class EmployeeTypeAPITestCase(TestCase):
|
||
"""测试员工职位类型 API"""
|
||
|
||
def setUp(self):
|
||
"""设置测试数据"""
|
||
# 创建商户
|
||
self.merchant = Merchant.objects.create(
|
||
name='测试商户',
|
||
type=MerchantTypeEnum.STORE
|
||
)
|
||
|
||
# 创建用户和员工
|
||
self.user = User.objects.create_user(
|
||
username='testuser',
|
||
password='testpass123'
|
||
)
|
||
self.employee = Employee.objects.create(
|
||
merchant=self.merchant,
|
||
sys_user=self.user,
|
||
name='测试员工'
|
||
)
|
||
|
||
# 设置 API 客户端
|
||
self.client = APIClient()
|
||
self.client.force_authenticate(user=self.user)
|
||
|
||
def test_create_employee_type(self):
|
||
"""测试创建职位类型"""
|
||
data = {
|
||
'title': '打纸工',
|
||
'description': '负责打纸工作'
|
||
}
|
||
response = self.client.post('/api/backend/employee-types/', data, format='json')
|
||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||
self.assertEqual(response.data['title'], '打纸工')
|
||
self.assertEqual(response.data['description'], '负责打纸工作')
|
||
|
||
def test_list_employee_types(self):
|
||
"""测试列出所有职位类型"""
|
||
EmployeeType.objects.create(merchant=self.merchant, title='打纸工')
|
||
EmployeeType.objects.create(merchant=self.merchant, title='滚筒工')
|
||
|
||
response = self.client.get('/api/backend/employee-types/')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
self.assertEqual(len(results), 2)
|
||
|
||
def test_update_employee_type(self):
|
||
"""测试更新职位类型"""
|
||
emp_type = EmployeeType.objects.create(
|
||
merchant=self.merchant,
|
||
title='仓库管理员'
|
||
)
|
||
|
||
data = {'description': '新的描述'}
|
||
response = self.client.patch(f'/api/backend/employee-types/{emp_type.id}/', data, format='json')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
self.assertEqual(response.data['description'], '新的描述')
|
||
|
||
def test_delete_employee_type(self):
|
||
"""测试删除职位类型"""
|
||
emp_type = EmployeeType.objects.create(
|
||
merchant=self.merchant,
|
||
title='临时工'
|
||
)
|
||
|
||
response = self.client.delete(f'/api/backend/employee-types/{emp_type.id}/')
|
||
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
|
||
self.assertFalse(EmployeeType.objects.filter(id=emp_type.id).exists())
|
||
|
||
def test_filter_employee_types_by_title(self):
|
||
"""测试通过 title 查询参数过滤职位类型(icontains 模糊匹配)"""
|
||
EmployeeType.objects.create(merchant=self.merchant, title='打纸工')
|
||
EmployeeType.objects.create(merchant=self.merchant, title='滚筒工')
|
||
EmployeeType.objects.create(merchant=self.merchant, title='仓库管理员')
|
||
|
||
# 测试部分匹配
|
||
response = self.client.get('/api/backend/employee-types/?title=打纸')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
self.assertEqual(len(results), 1)
|
||
self.assertEqual(results[0]['title'], '打纸工')
|
||
|
||
# 测试包含"工"的所有记录
|
||
response = self.client.get('/api/backend/employee-types/?title=工')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
self.assertEqual(len(results), 2) # 打纸工、滚筒工
|
||
|
||
# 测试不匹配
|
||
response = self.client.get('/api/backend/employee-types/?title=不存在')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
self.assertEqual(len(results), 0)
|
||
|
||
|
||
class EmployeeAPITestCase(TestCase):
|
||
"""测试员工 API(包含 job_type 兼容性)"""
|
||
|
||
def setUp(self):
|
||
"""设置测试数据"""
|
||
# 创建商户
|
||
self.merchant = Merchant.objects.create(
|
||
name='测试商户',
|
||
type=MerchantTypeEnum.STORE
|
||
)
|
||
|
||
# 创建用户和员工
|
||
self.user = User.objects.create_user(
|
||
username='testuser',
|
||
password='testpass123'
|
||
)
|
||
self.employee = Employee.objects.create(
|
||
merchant=self.merchant,
|
||
sys_user=self.user,
|
||
name='测试员工'
|
||
)
|
||
|
||
# 创建职位类型
|
||
self.emp_type = EmployeeType.objects.create(
|
||
merchant=self.merchant,
|
||
title='打纸工'
|
||
)
|
||
|
||
# 设置 API 客户端
|
||
self.client = APIClient()
|
||
self.client.force_authenticate(user=self.user)
|
||
|
||
def test_create_employee_with_position(self):
|
||
"""测试创建带职位的员工"""
|
||
data = {
|
||
'name': '张三',
|
||
'position': self.emp_type.id,
|
||
'mobile': '13800138000'
|
||
}
|
||
response = self.client.post('/api/backend/employees/', data, format='json')
|
||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||
self.assertEqual(response.data['position'], self.emp_type.id)
|
||
self.assertEqual(response.data['job_type'], '打纸工') # 验证兼容性字段
|
||
|
||
def test_create_employee_without_position(self):
|
||
"""测试创建不带职位的员工"""
|
||
data = {
|
||
'name': '李四',
|
||
'mobile': '13900139000'
|
||
}
|
||
response = self.client.post('/api/backend/employees/', data, format='json')
|
||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||
self.assertIsNone(response.data['position'])
|
||
self.assertEqual(response.data['job_type'], '') # 验证返回空字符串
|
||
|
||
def test_list_employees_includes_job_type(self):
|
||
"""测试列表接口包含 job_type 字段"""
|
||
Employee.objects.create(
|
||
merchant=self.merchant,
|
||
name='员工1',
|
||
position=self.emp_type
|
||
)
|
||
Employee.objects.create(
|
||
merchant=self.merchant,
|
||
name='员工2'
|
||
)
|
||
|
||
response = self.client.get('/api/backend/employees/')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
|
||
# 验证 job_type 字段存在
|
||
for emp in results:
|
||
self.assertIn('job_type', emp)
|
||
|
||
def test_update_employee_position(self):
|
||
"""测试更新员工职位"""
|
||
new_type = EmployeeType.objects.create(
|
||
merchant=self.merchant,
|
||
title='滚筒工'
|
||
)
|
||
|
||
employee = Employee.objects.create(
|
||
merchant=self.merchant,
|
||
name='王五',
|
||
position=self.emp_type
|
||
)
|
||
|
||
data = {'position': new_type.id}
|
||
response = self.client.patch(f'/api/backend/employees/{employee.id}/', data, format='json')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
self.assertEqual(response.data['position'], new_type.id)
|
||
self.assertEqual(response.data['job_type'], '滚筒工')
|
||
|
||
def test_job_type_is_read_only(self):
|
||
"""测试 job_type 是只读字段"""
|
||
employee = Employee.objects.create(
|
||
merchant=self.merchant,
|
||
name='赵六',
|
||
position=self.emp_type
|
||
)
|
||
|
||
# 尝试直接更新 job_type(应该被忽略)
|
||
data = {'job_type': '其他职位'}
|
||
response = self.client.patch(f'/api/backend/employees/{employee.id}/', data, format='json')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
self.assertEqual(response.data['job_type'], '打纸工') # 应该保持不变
|
||
|
||
def test_filter_employees_by_name(self):
|
||
"""测试通过 name 查询参数过滤员工(icontains 模糊匹配)"""
|
||
Employee.objects.create(merchant=self.merchant, name='张三')
|
||
Employee.objects.create(merchant=self.merchant, name='李四')
|
||
Employee.objects.create(merchant=self.merchant, name='王五')
|
||
|
||
# 测试部分匹配
|
||
response = self.client.get('/api/backend/employees/?name=三')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
self.assertEqual(len(results), 1)
|
||
self.assertEqual(results[0]['name'], '张三')
|
||
|
||
# 测试不匹配
|
||
response = self.client.get('/api/backend/employees/?name=不存在')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
self.assertEqual(len(results), 0)
|
||
|
||
|
||
class UserProfileAPITestCase(TestCase):
|
||
"""测试用户资料 API"""
|
||
|
||
def setUp(self):
|
||
"""设置测试数据"""
|
||
# 创建商户
|
||
self.merchant = Merchant.objects.create(
|
||
name='测试商户',
|
||
type=MerchantTypeEnum.STORE
|
||
)
|
||
|
||
# 创建用户和员工
|
||
self.user = User.objects.create_user(
|
||
username='testuser',
|
||
password='testpass123',
|
||
email='test@example.com'
|
||
)
|
||
self.employee = Employee.objects.create(
|
||
merchant=self.merchant,
|
||
sys_user=self.user,
|
||
name='测试员工'
|
||
)
|
||
|
||
# 创建另一个用户用于测试
|
||
self.user2 = User.objects.create_user(
|
||
username='testuser2',
|
||
password='testpass123',
|
||
email='test2@example.com'
|
||
)
|
||
|
||
# 设置 API 客户端
|
||
self.client = APIClient()
|
||
self.client.force_authenticate(user=self.user)
|
||
|
||
def test_create_user_profile(self):
|
||
"""测试创建用户资料"""
|
||
data = {
|
||
'user': self.user2.id,
|
||
'description': '测试用户资料描述'
|
||
}
|
||
response = self.client.post('/api/backend/user-profiles/', data, format='json')
|
||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||
self.assertEqual(response.data['user'], self.user2.id)
|
||
self.assertEqual(response.data['merchant'], self.merchant.id) # 应该由BaseViewSet自动设置
|
||
self.assertEqual(response.data['description'], '测试用户资料描述')
|
||
|
||
def test_list_user_profiles(self):
|
||
"""测试列出所有用户资料"""
|
||
from basic_info.models import UserProfile
|
||
UserProfile.objects.create(
|
||
user=self.user,
|
||
merchant=self.merchant,
|
||
description='用户1资料'
|
||
)
|
||
UserProfile.objects.create(
|
||
user=self.user2,
|
||
merchant=self.merchant,
|
||
description='用户2资料'
|
||
)
|
||
|
||
response = self.client.get('/api/backend/user-profiles/')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
self.assertEqual(len(results), 2) # 应该只返回当前商户的用户资料
|
||
|
||
def test_retrieve_user_profile(self):
|
||
"""测试检索单个用户资料"""
|
||
from basic_info.models import UserProfile
|
||
profile = UserProfile.objects.create(
|
||
user=self.user,
|
||
merchant=self.merchant,
|
||
description='测试资料'
|
||
)
|
||
|
||
response = self.client.get(f'/api/backend/user-profiles/{profile.id}/')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
self.assertEqual(response.data['id'], profile.id)
|
||
self.assertEqual(response.data['description'], '测试资料')
|
||
self.assertEqual(response.data['user_detail']['username'], 'testuser') # 检查嵌套用户对象
|
||
|
||
def test_update_user_profile(self):
|
||
"""测试更新用户资料"""
|
||
from basic_info.models import UserProfile
|
||
profile = UserProfile.objects.create(
|
||
user=self.user,
|
||
merchant=self.merchant,
|
||
description='原始描述'
|
||
)
|
||
|
||
data = {'description': '更新后的描述'}
|
||
response = self.client.patch(f'/api/backend/user-profiles/{profile.id}/', data, format='json')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
self.assertEqual(response.data['description'], '更新后的描述')
|
||
|
||
# 验证数据库
|
||
profile.refresh_from_db()
|
||
self.assertEqual(profile.description, '更新后的描述')
|
||
|
||
def test_delete_user_profile(self):
|
||
"""测试删除用户资料"""
|
||
from basic_info.models import UserProfile
|
||
profile = UserProfile.objects.create(
|
||
user=self.user,
|
||
merchant=self.merchant,
|
||
description='待删除资料'
|
||
)
|
||
|
||
response = self.client.delete(f'/api/backend/user-profiles/{profile.id}/')
|
||
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
|
||
self.assertFalse(UserProfile.objects.filter(id=profile.id).exists())
|
||
|
||
def test_user_profile_filter_by_merchant(self):
|
||
"""测试用户资料按商户过滤"""
|
||
# 创建另一个商户
|
||
other_merchant = Merchant.objects.create(
|
||
name='其他商户',
|
||
type=MerchantTypeEnum.FACTORY
|
||
)
|
||
|
||
# 创建另一个商户的员工
|
||
other_user = User.objects.create_user(
|
||
username='otheruser',
|
||
password='testpass123'
|
||
)
|
||
other_employee = Employee.objects.create(
|
||
merchant=other_merchant,
|
||
sys_user=other_user,
|
||
name='其他员工'
|
||
)
|
||
|
||
# 为两个商户分别创建用户资料
|
||
from basic_info.models import UserProfile
|
||
UserProfile.objects.create(
|
||
user=self.user,
|
||
merchant=self.merchant,
|
||
description='本商户用户资料'
|
||
)
|
||
UserProfile.objects.create(
|
||
user=other_user,
|
||
merchant=other_merchant,
|
||
description='其他商户用户资料'
|
||
)
|
||
|
||
# 使用当前用户(属于self.merchant)访问API
|
||
response = self.client.get('/api/backend/user-profiles/')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
self.assertEqual(len(results), 1) # 只应该返回当前商户的用户资料
|
||
self.assertEqual(results[0]['description'], '本商户用户资料')
|
||
|
||
|
||
# ==================== 补充缺失的 ViewSet 测试 ====================
|
||
|
||
class QuickInputAPITestCase(TestCase):
|
||
"""测试快捷输入 API(支持 name 和 group 查询参数)"""
|
||
|
||
def setUp(self):
|
||
self.merchant = Merchant.objects.create(
|
||
name='测试商户',
|
||
type=MerchantTypeEnum.STORE
|
||
)
|
||
self.user = User.objects.create_user(
|
||
username='testuser',
|
||
password='testpass123'
|
||
)
|
||
self.employee = Employee.objects.create(
|
||
merchant=self.merchant,
|
||
sys_user=self.user,
|
||
name='测试员工'
|
||
)
|
||
self.client = APIClient()
|
||
self.client.force_authenticate(user=self.user)
|
||
|
||
def test_create_quick_input(self):
|
||
"""测试创建快捷输入"""
|
||
data = {
|
||
'name': '测试输入',
|
||
'value': '测试值',
|
||
'group': '测试组'
|
||
}
|
||
response = self.client.post('/api/backend/quick-inputs/', data, format='json')
|
||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||
self.assertEqual(response.data['name'], '测试输入')
|
||
self.assertEqual(response.data['group'], '测试组')
|
||
|
||
def test_filter_quick_inputs_by_name(self):
|
||
"""测试通过 name 查询参数过滤快捷输入"""
|
||
QuickInput.objects.create(name='输入1', value='值1', group='组1')
|
||
QuickInput.objects.create(name='输入2', value='值2', group='组1')
|
||
QuickInput.objects.create(name='输入3', value='值3', group='组2')
|
||
|
||
response = self.client.get('/api/backend/quick-inputs/?name=输入1')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
self.assertEqual(len(results), 1)
|
||
self.assertEqual(results[0]['name'], '输入1')
|
||
|
||
def test_filter_quick_inputs_by_group(self):
|
||
"""测试通过 group 查询参数过滤快捷输入"""
|
||
QuickInput.objects.create(name='输入1', value='值1', group='组1')
|
||
QuickInput.objects.create(name='输入2', value='值2', group='组1')
|
||
QuickInput.objects.create(name='输入3', value='值3', group='组2')
|
||
|
||
response = self.client.get('/api/backend/quick-inputs/?group=组1')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
self.assertEqual(len(results), 2)
|
||
for item in results:
|
||
self.assertEqual(item['group'], '组1')
|
||
|
||
def test_quick_input_groups_action(self):
|
||
"""测试获取所有分组"""
|
||
QuickInput.objects.create(name='输入1', value='值1', group='组1')
|
||
QuickInput.objects.create(name='输入2', value='值2', group='组1')
|
||
QuickInput.objects.create(name='输入3', value='值3', group='组2')
|
||
|
||
response = self.client.get('/api/backend/quick-inputs/groups/')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
groups = list(response.data)
|
||
self.assertEqual(len(groups), 2)
|
||
self.assertIn('组1', groups)
|
||
self.assertIn('组2', groups)
|
||
|
||
|
||
class ProductAPITestCase(TestCase):
|
||
"""测试产品 API(支持 name 查询参数)"""
|
||
|
||
def setUp(self):
|
||
self.merchant = Merchant.objects.create(
|
||
name='测试商户',
|
||
type=MerchantTypeEnum.STORE
|
||
)
|
||
self.user = User.objects.create_user(
|
||
username='testuser',
|
||
password='testpass123'
|
||
)
|
||
self.employee = Employee.objects.create(
|
||
merchant=self.merchant,
|
||
sys_user=self.user,
|
||
name='测试员工'
|
||
)
|
||
self.category = ProductCategory.objects.create(
|
||
merchant=self.merchant,
|
||
name='测试类别',
|
||
product_prefix='TEST'
|
||
)
|
||
self.client = APIClient()
|
||
self.client.force_authenticate(user=self.user)
|
||
|
||
def test_create_product(self):
|
||
"""测试创建产品"""
|
||
data = {
|
||
'name': '测试产品',
|
||
'category': self.category.id
|
||
}
|
||
response = self.client.post('/api/backend/products/', data, format='json')
|
||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||
self.assertEqual(response.data['name'], '测试产品')
|
||
|
||
def test_filter_products_by_name(self):
|
||
"""测试通过 name 查询参数过滤产品"""
|
||
Product.objects.create(merchant=self.merchant, category=self.category, name='产品A')
|
||
Product.objects.create(merchant=self.merchant, category=self.category, name='产品B')
|
||
Product.objects.create(merchant=self.merchant, category=self.category, name='产品C')
|
||
|
||
response = self.client.get('/api/backend/products/?name=产品A')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
self.assertEqual(len(results), 1)
|
||
self.assertEqual(results[0]['name'], '产品A')
|
||
|
||
|
||
class ProductCategoryAPITestCase(TestCase):
|
||
"""测试产品类别 API(支持 name 查询参数)"""
|
||
|
||
def setUp(self):
|
||
self.merchant = Merchant.objects.create(
|
||
name='测试商户',
|
||
type=MerchantTypeEnum.STORE
|
||
)
|
||
self.user = User.objects.create_user(
|
||
username='testuser',
|
||
password='testpass123'
|
||
)
|
||
self.employee = Employee.objects.create(
|
||
merchant=self.merchant,
|
||
sys_user=self.user,
|
||
name='测试员工'
|
||
)
|
||
self.client = APIClient()
|
||
self.client.force_authenticate(user=self.user)
|
||
|
||
def test_create_product_category(self):
|
||
"""测试创建产品类别"""
|
||
data = {
|
||
'name': '测试类别',
|
||
'product_prefix': 'TEST'
|
||
}
|
||
response = self.client.post('/api/backend/product-categories/', data, format='json')
|
||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||
self.assertEqual(response.data['name'], '测试类别')
|
||
|
||
def test_filter_product_categories_by_name(self):
|
||
"""测试通过 name 查询参数过滤产品类别"""
|
||
ProductCategory.objects.create(merchant=self.merchant, name='类别A', product_prefix='A')
|
||
ProductCategory.objects.create(merchant=self.merchant, name='类别B', product_prefix='B')
|
||
|
||
response = self.client.get('/api/backend/product-categories/?name=类别A')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
self.assertEqual(len(results), 1)
|
||
self.assertEqual(results[0]['name'], '类别A')
|
||
|
||
|
||
class SupplierAPITestCase(TestCase):
|
||
"""测试供应商 API(支持 name 查询参数)"""
|
||
|
||
def setUp(self):
|
||
self.merchant = Merchant.objects.create(
|
||
name='测试商户',
|
||
type=MerchantTypeEnum.STORE
|
||
)
|
||
self.user = User.objects.create_user(
|
||
username='testuser',
|
||
password='testpass123'
|
||
)
|
||
self.employee = Employee.objects.create(
|
||
merchant=self.merchant,
|
||
sys_user=self.user,
|
||
name='测试员工'
|
||
)
|
||
self.client = APIClient()
|
||
self.client.force_authenticate(user=self.user)
|
||
|
||
def test_create_supplier(self):
|
||
"""测试创建供应商"""
|
||
data = {
|
||
'name': '测试供应商'
|
||
}
|
||
response = self.client.post('/api/backend/suppliers/', data, format='json')
|
||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||
self.assertEqual(response.data['name'], '测试供应商')
|
||
|
||
def test_filter_suppliers_by_name(self):
|
||
"""测试通过 name 查询参数过滤供应商"""
|
||
Supplier.objects.create(merchant=self.merchant, name='供应商A')
|
||
Supplier.objects.create(merchant=self.merchant, name='供应商B')
|
||
|
||
response = self.client.get('/api/backend/suppliers/?name=供应商A')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
self.assertEqual(len(results), 1)
|
||
self.assertEqual(results[0]['name'], '供应商A')
|
||
|
||
|
||
class CustomerAPITestCase(TestCase):
|
||
"""测试客户 API(支持 name 和 visible_employee_name 查询参数)"""
|
||
|
||
def setUp(self):
|
||
self.merchant = Merchant.objects.create(
|
||
name='测试商户',
|
||
type=MerchantTypeEnum.STORE
|
||
)
|
||
self.user = User.objects.create_user(
|
||
username='testuser',
|
||
password='testpass123'
|
||
)
|
||
self.employee = Employee.objects.create(
|
||
merchant=self.merchant,
|
||
sys_user=self.user,
|
||
name='测试员工'
|
||
)
|
||
# CustomerViewSet 使用 DjangoModelPermissions,需要添加权限
|
||
from django.contrib.auth.models import Permission
|
||
from django.contrib.contenttypes.models import ContentType
|
||
content_type = ContentType.objects.get_for_model(Customer)
|
||
permissions = Permission.objects.filter(content_type=content_type)
|
||
self.user.user_permissions.set(permissions)
|
||
self.client = APIClient()
|
||
self.client.force_authenticate(user=self.user)
|
||
|
||
def test_create_customer(self):
|
||
"""测试创建客户"""
|
||
data = {
|
||
'name': '测试客户'
|
||
}
|
||
response = self.client.post('/api/backend/customers/', data, format='json')
|
||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||
self.assertEqual(response.data['name'], '测试客户')
|
||
customer = Customer.objects.get(id=response.data['id'])
|
||
self.assertEqual(customer.merchant, self.merchant)
|
||
self.assertEqual(customer.created_by, self.employee)
|
||
|
||
def test_create_customer_ignores_explicit_merchant_param(self):
|
||
"""测试创建客户时即使前端显式传 merchant,也以当前用户商户为准"""
|
||
other_merchant = Merchant.objects.create(
|
||
name='其他商户',
|
||
type=MerchantTypeEnum.STORE,
|
||
)
|
||
data = {
|
||
'name': '兼容客户',
|
||
'merchant': other_merchant.id,
|
||
}
|
||
|
||
response = self.client.post('/api/backend/customers/', data, format='json')
|
||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||
customer = Customer.objects.get(id=response.data['id'])
|
||
self.assertEqual(customer.merchant, self.merchant)
|
||
self.assertEqual(customer.created_by, self.employee)
|
||
|
||
def test_filter_customers_by_name(self):
|
||
"""测试通过 name 查询参数过滤客户"""
|
||
Customer.objects.create(merchant=self.merchant, name='客户A', created_by=self.employee)
|
||
Customer.objects.create(merchant=self.merchant, name='客户B', created_by=self.employee)
|
||
|
||
response = self.client.get('/api/backend/customers/?name=客户A')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
self.assertEqual(len(results), 1)
|
||
self.assertEqual(results[0]['name'], '客户A')
|
||
|
||
def test_filter_customers_by_visible_employee_name(self):
|
||
"""测试通过 visible_employee_name 查询参数过滤客户"""
|
||
visible_employee = Employee.objects.create(
|
||
merchant=self.merchant,
|
||
name='李四业务',
|
||
)
|
||
other_employee = Employee.objects.create(
|
||
merchant=self.merchant,
|
||
name='王五跟单',
|
||
)
|
||
customer_a = Customer.objects.create(
|
||
merchant=self.merchant,
|
||
name='客户A',
|
||
created_by=self.employee,
|
||
)
|
||
customer_b = Customer.objects.create(
|
||
merchant=self.merchant,
|
||
name='客户B',
|
||
created_by=self.employee,
|
||
)
|
||
customer_a.visible_employees.add(visible_employee)
|
||
customer_b.visible_employees.add(other_employee)
|
||
|
||
response = self.client.get('/api/backend/customers/?visible_employee_name=李四')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
self.assertEqual(len(results), 1)
|
||
self.assertEqual(results[0]['id'], customer_a.id)
|
||
|
||
def test_filter_customers_by_visible_employee_name_excludes_unbound_customers(self):
|
||
"""测试 visible_employee_name 过滤不会返回没有绑定员工的客户"""
|
||
visible_employee = Employee.objects.create(
|
||
merchant=self.merchant,
|
||
name='李四业务',
|
||
)
|
||
unbound_customer = Customer.objects.create(
|
||
merchant=self.merchant,
|
||
name='未绑定客户',
|
||
created_by=self.employee,
|
||
)
|
||
bound_customer = Customer.objects.create(
|
||
merchant=self.merchant,
|
||
name='已绑定客户',
|
||
created_by=self.employee,
|
||
)
|
||
bound_customer.visible_employees.add(visible_employee)
|
||
|
||
response = self.client.get('/api/backend/customers/?visible_employee_name=李四')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
returned_ids = {item['id'] for item in results}
|
||
self.assertIn(bound_customer.id, returned_ids)
|
||
self.assertNotIn(unbound_customer.id, returned_ids)
|
||
|
||
def test_filter_customers_by_visible_employee_name_returns_distinct_results(self):
|
||
"""测试 visible_employee_name 过滤不会因多名匹配员工导致客户重复"""
|
||
customer = Customer.objects.create(
|
||
merchant=self.merchant,
|
||
name='客户A',
|
||
created_by=self.employee,
|
||
)
|
||
customer.visible_employees.add(
|
||
Employee.objects.create(merchant=self.merchant, name='销售张三'),
|
||
Employee.objects.create(merchant=self.merchant, name='客服张三'),
|
||
)
|
||
|
||
response = self.client.get('/api/backend/customers/?visible_employee_name=张三')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
self.assertEqual(len(results), 1)
|
||
self.assertEqual(results[0]['id'], customer.id)
|
||
|
||
|
||
class VehicleTypeAPITestCase(TestCase):
|
||
"""测试车辆类型 API(支持 name 查询参数)"""
|
||
|
||
def setUp(self):
|
||
self.merchant = Merchant.objects.create(
|
||
name='测试商户',
|
||
type=MerchantTypeEnum.STORE
|
||
)
|
||
self.user = User.objects.create_user(
|
||
username='testuser',
|
||
password='testpass123'
|
||
)
|
||
self.employee = Employee.objects.create(
|
||
merchant=self.merchant,
|
||
sys_user=self.user,
|
||
name='测试员工'
|
||
)
|
||
self.client = APIClient()
|
||
self.client.force_authenticate(user=self.user)
|
||
|
||
def test_create_vehicle_type(self):
|
||
"""测试创建车辆类型"""
|
||
data = {
|
||
'name': '测试车辆类型'
|
||
}
|
||
response = self.client.post('/api/backend/vehicle-types/', data, format='json')
|
||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||
self.assertEqual(response.data['name'], '测试车辆类型')
|
||
|
||
def test_filter_vehicle_types_by_name(self):
|
||
"""测试通过 name 查询参数过滤车辆类型"""
|
||
VehicleType.objects.create(merchant=self.merchant, name='类型A')
|
||
VehicleType.objects.create(merchant=self.merchant, name='类型B')
|
||
|
||
response = self.client.get('/api/backend/vehicle-types/?name=类型A')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
self.assertEqual(len(results), 1)
|
||
self.assertEqual(results[0]['name'], '类型A')
|
||
|
||
|
||
class BankAccountAPITestCase(TestCase):
|
||
"""测试银行账户 API(支持 name 查询参数)"""
|
||
|
||
def setUp(self):
|
||
self.merchant = Merchant.objects.create(
|
||
name='测试商户',
|
||
type=MerchantTypeEnum.STORE
|
||
)
|
||
self.user = User.objects.create_user(
|
||
username='testuser',
|
||
password='testpass123'
|
||
)
|
||
self.employee = Employee.objects.create(
|
||
merchant=self.merchant,
|
||
sys_user=self.user,
|
||
name='测试员工'
|
||
)
|
||
self.client = APIClient()
|
||
self.client.force_authenticate(user=self.user)
|
||
|
||
def test_create_bank_account(self):
|
||
"""测试创建银行账户"""
|
||
data = {
|
||
'name': '测试账户',
|
||
'auto_number': 'ACC001'
|
||
}
|
||
response = self.client.post('/api/backend/bank-accounts/', data, format='json')
|
||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||
self.assertEqual(response.data['name'], '测试账户')
|
||
|
||
def test_filter_bank_accounts_by_name(self):
|
||
"""测试通过 name 查询参数过滤银行账户"""
|
||
BankAccount.objects.create(merchant=self.merchant, name='账户A', auto_number='A001')
|
||
BankAccount.objects.create(merchant=self.merchant, name='账户B', auto_number='B001')
|
||
|
||
response = self.client.get('/api/backend/bank-accounts/?name=账户A')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
self.assertEqual(len(results), 1)
|
||
self.assertEqual(results[0]['name'], '账户A')
|
||
|
||
|
||
class DeviceInfoAPITestCase(TestCase):
|
||
"""测试设备信息 API(支持 name 查询参数)"""
|
||
|
||
def setUp(self):
|
||
self.merchant = Merchant.objects.create(
|
||
name='测试商户',
|
||
type=MerchantTypeEnum.STORE
|
||
)
|
||
self.user = User.objects.create_user(
|
||
username='testuser',
|
||
password='testpass123'
|
||
)
|
||
self.employee = Employee.objects.create(
|
||
merchant=self.merchant,
|
||
sys_user=self.user,
|
||
name='测试员工'
|
||
)
|
||
self.client = APIClient()
|
||
self.client.force_authenticate(user=self.user)
|
||
|
||
def test_create_device_info(self):
|
||
"""测试创建设备信息"""
|
||
data = {
|
||
'name': '测试设备'
|
||
}
|
||
response = self.client.post('/api/backend/device-info/', data, format='json')
|
||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||
self.assertEqual(response.data['name'], '测试设备')
|
||
|
||
def test_filter_device_info_by_name(self):
|
||
"""测试通过 name 查询参数过滤设备信息"""
|
||
DeviceInfo.objects.create(merchant=self.merchant, name='设备A')
|
||
DeviceInfo.objects.create(merchant=self.merchant, name='设备B')
|
||
|
||
response = self.client.get('/api/backend/device-info/?name=设备A')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
self.assertEqual(len(results), 1)
|
||
self.assertEqual(results[0]['name'], '设备A')
|
||
|
||
|
||
class VehicleTransportRecordAPITestCase(TestCase):
|
||
"""测试司机车次 API(支持 driver_name 查询参数)"""
|
||
|
||
def setUp(self):
|
||
self.merchant = Merchant.objects.create(
|
||
name='测试商户',
|
||
type=MerchantTypeEnum.STORE
|
||
)
|
||
self.user = User.objects.create_user(
|
||
username='testuser',
|
||
password='testpass123'
|
||
)
|
||
self.employee = Employee.objects.create(
|
||
merchant=self.merchant,
|
||
sys_user=self.user,
|
||
name='测试员工'
|
||
)
|
||
self.vehicle_type = VehicleType.objects.create(
|
||
merchant=self.merchant,
|
||
name='测试车辆类型'
|
||
)
|
||
self.client = APIClient()
|
||
self.client.force_authenticate(user=self.user)
|
||
|
||
def test_create_vehicle_transport_record(self):
|
||
"""测试创建司机车次
|
||
|
||
注意:由于 VehicleTransportRecordSerializer 使用 depth=1 可能影响反序列化,
|
||
如果创建失败,可能是序列化器配置问题,但过滤功能测试仍然有效。
|
||
"""
|
||
from datetime import date
|
||
data = {
|
||
'vehicle_type': self.vehicle_type.id,
|
||
'driver_name': '测试司机',
|
||
'delivery_date': date.today().isoformat()
|
||
}
|
||
response = self.client.post('/api/backend/vehicle-transport-records/', data, format='json')
|
||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||
self.assertEqual(response.data['driver_name'], '测试司机')
|
||
self.assertEqual(response.data['vehicle_type'], self.vehicle_type.id)
|
||
|
||
def test_filter_vehicle_transport_records_by_driver_name(self):
|
||
"""测试通过 driver_name 查询参数过滤司机车次"""
|
||
from datetime import date
|
||
VehicleTransportRecord.objects.create(
|
||
merchant=self.merchant,
|
||
vehicle_type=self.vehicle_type,
|
||
driver_name='司机A',
|
||
delivery_date=date.today()
|
||
)
|
||
VehicleTransportRecord.objects.create(
|
||
merchant=self.merchant,
|
||
vehicle_type=self.vehicle_type,
|
||
driver_name='司机B',
|
||
delivery_date=date.today()
|
||
)
|
||
|
||
response = self.client.get('/api/backend/vehicle-transport-records/?driver_name=司机A')
|
||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||
results = response.data['results'] if isinstance(response.data, dict) else response.data
|
||
self.assertEqual(len(results), 1)
|
||
self.assertEqual(results[0]['driver_name'], '司机A')
|