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')