1
0
forked from erp-dev/erp
Files
erpnew/basic_info/tests.py
2026-04-14 00:03:22 +08:00

419 lines
15 KiB
Python

from io import StringIO
from django.core.management import call_command
from django.test import TestCase
from django.core.exceptions import ValidationError
from .models import (
Merchant, MerchantTypeEnum, WareHouse, WarehouseTypeEnum,
WareHouseModeEnum, EmployeeType, Employee, EmployeeStatusEnum,
FrontendPage, FrontendPageTypeEnum, TransportVehicle, TransportVehicleMaterialCapacity
)
class WarehouseTypeTestCase(TestCase):
"""测试仓库类型字段"""
def setUp(self):
"""设置测试数据"""
self.merchant = Merchant.objects.create(
name='测试商户',
type=MerchantTypeEnum.STORE
)
def test_warehouse_default_type(self):
"""测试仓库类型的默认值"""
warehouse = WareHouse.objects.create(
merchant=self.merchant,
name='默认仓库',
)
self.assertEqual(warehouse.type, WarehouseTypeEnum.WHOLE)
def test_warehouse_type_whole(self):
"""测试创建整仓"""
warehouse = WareHouse.objects.create(
merchant=self.merchant,
name='整仓1',
type=WarehouseTypeEnum.WHOLE
)
self.assertEqual(warehouse.type, WarehouseTypeEnum.WHOLE)
self.assertEqual(warehouse.get_type_display(), '整仓')
def test_warehouse_type_scattered(self):
"""测试创建散仓"""
warehouse = WareHouse.objects.create(
merchant=self.merchant,
name='散仓1',
type=WarehouseTypeEnum.SCATTERED
)
self.assertEqual(warehouse.type, WarehouseTypeEnum.SCATTERED)
self.assertEqual(warehouse.get_type_display(), '散仓')
def test_warehouse_type_enum_values(self):
"""测试仓库类型枚举的所有值"""
self.assertEqual(WarehouseTypeEnum.WHOLE.value, 1)
self.assertEqual(WarehouseTypeEnum.WHOLE.label, '整仓')
self.assertEqual(WarehouseTypeEnum.SCATTERED.value, 2)
self.assertEqual(WarehouseTypeEnum.SCATTERED.label, '散仓')
def test_warehouse_with_all_fields(self):
"""测试带有所有字段的仓库"""
warehouse = WareHouse.objects.create(
merchant=self.merchant,
name='完整仓库',
type=WarehouseTypeEnum.SCATTERED,
mode=WareHouseModeEnum.RESTRICT_IN_OUT,
location='测试地址',
area='测试区域',
contact='张三',
mobile='13800138000',
description='测试描述'
)
self.assertEqual(warehouse.type, WarehouseTypeEnum.SCATTERED)
self.assertEqual(warehouse.mode, WareHouseModeEnum.RESTRICT_IN_OUT)
self.assertEqual(warehouse.name, '完整仓库')
class EmployeeTypeTestCase(TestCase):
"""测试员工职位类型"""
def setUp(self):
"""设置测试数据"""
self.merchant = Merchant.objects.create(
name='测试商户',
type=MerchantTypeEnum.STORE
)
def test_create_employee_type(self):
"""测试创建员工职位类型"""
emp_type = EmployeeType.objects.create(
merchant=self.merchant,
title='测试职位',
description='职位描述'
)
self.assertEqual(emp_type.title, '测试职位')
self.assertEqual(emp_type.description, '职位描述')
self.assertEqual(str(emp_type), '测试职位')
def test_employee_type_unique_together(self):
"""测试商户+职位名称的唯一性约束"""
EmployeeType.objects.create(
merchant=self.merchant,
title='打纸'
)
# 同一商户不能创建重复职位
with self.assertRaises(Exception):
EmployeeType.objects.create(
merchant=self.merchant,
title='打纸'
)
def test_employee_with_position(self):
"""测试员工关联职位"""
emp_type = EmployeeType.objects.create(
merchant=self.merchant,
title='滚筒工'
)
employee = Employee.objects.create(
merchant=self.merchant,
name='张三',
position=emp_type,
status=EmployeeStatusEnum.ACTIVE
)
self.assertEqual(employee.position, emp_type)
self.assertEqual(employee.job_type, '滚筒工') # 测试 job_type 属性
def test_employee_without_position(self):
"""测试员工没有职位时 job_type 返回空字符串"""
employee = Employee.objects.create(
merchant=self.merchant,
name='李四',
status=EmployeeStatusEnum.ACTIVE
)
self.assertIsNone(employee.position)
self.assertEqual(employee.job_type, '')
def test_employee_type_reverse_field(self):
"""测试预留字段"""
emp_type = EmployeeType.objects.create(
merchant=self.merchant,
title='仓库管理员',
reverse='预留数据'
)
self.assertEqual(emp_type.reverse, '预留数据')
def test_multiple_employees_same_position(self):
"""测试多个员工可以有相同职位"""
emp_type = EmployeeType.objects.create(
merchant=self.merchant,
title='打纸工'
)
emp1 = Employee.objects.create(
merchant=self.merchant,
name='员工1',
position=emp_type
)
emp2 = Employee.objects.create(
merchant=self.merchant,
name='员工2',
position=emp_type
)
self.assertEqual(emp1.job_type, '打纸工')
self.assertEqual(emp2.job_type, '打纸工')
self.assertEqual(emp_type.employees.count(), 2)
class TransportVehicleTestCase(TestCase):
def setUp(self):
self.merchant = Merchant.objects.create(
name='运输商户',
type=MerchantTypeEnum.STORE
)
def test_create_transport_vehicle_with_material_capacity(self):
vehicle = TransportVehicle.objects.create(
merchant=self.merchant,
name='9.6米厢车',
license_plate='浙A12345'
)
capacity = TransportVehicleMaterialCapacity.objects.create(
merchant=self.merchant,
transport_vehicle=vehicle,
material_name='棉布',
capacity=120
)
self.assertEqual(vehicle.license_plate, '浙A12345')
self.assertEqual(str(vehicle), '9.6米厢车 (浙A12345)')
self.assertEqual(capacity.capacity, 120)
self.assertEqual(vehicle.material_capacities.count(), 1)
def test_transport_vehicle_license_plate_unique_per_merchant(self):
TransportVehicle.objects.create(
merchant=self.merchant,
name='一号车',
license_plate='浙A99999'
)
with self.assertRaises(Exception):
TransportVehicle.objects.create(
merchant=self.merchant,
name='二号车',
license_plate='浙A99999'
)
class FrontendPageTestCase(TestCase):
"""测试前端页面模型"""
def test_create_main_menu(self):
"""测试创建主菜单"""
page = FrontendPage.objects.create(
key='plate-opening',
label='开版管理',
page_type=FrontendPageTypeEnum.MAIN,
sort_order=0
)
self.assertEqual(page.key, 'plate-opening')
self.assertEqual(page.label, '开版管理')
self.assertEqual(page.page_type, FrontendPageTypeEnum.MAIN)
self.assertIsNone(page.parent)
self.assertTrue(page.is_active)
self.assertEqual(str(page), '开版管理 (plate-opening)')
def test_create_sub_menu_with_parent(self):
"""测试创建子菜单并关联父级"""
parent = FrontendPage.objects.create(
key='plate-opening',
label='开版管理',
page_type=FrontendPageTypeEnum.MAIN
)
child = FrontendPage.objects.create(
key='plate-order',
label='开版订单',
page_type=FrontendPageTypeEnum.SUB,
parent=parent
)
self.assertEqual(child.parent, parent)
self.assertEqual(parent.children.count(), 1)
self.assertEqual(parent.children.first(), child)
def test_key_unique_constraint(self):
"""测试 key 字段唯一性约束"""
FrontendPage.objects.create(key='test-page', label='测试页面')
with self.assertRaises(Exception):
FrontendPage.objects.create(key='test-page', label='重复页面')
def test_cascade_delete(self):
"""测试删除父级时子级也被删除"""
parent = FrontendPage.objects.create(
key='parent',
label='父级',
page_type=FrontendPageTypeEnum.MAIN
)
FrontendPage.objects.create(
key='child1',
label='子级1',
parent=parent
)
FrontendPage.objects.create(
key='child2',
label='子级2',
parent=parent
)
self.assertEqual(FrontendPage.objects.count(), 3)
parent.delete()
self.assertEqual(FrontendPage.objects.count(), 0)
class EmployeeTypeVisiblePagesTestCase(TestCase):
"""测试员工职位类型的可见页面功能"""
def setUp(self):
"""设置测试数据"""
self.merchant = Merchant.objects.create(
name='测试商户',
type=MerchantTypeEnum.STORE
)
# 创建页面
self.main_menu = FrontendPage.objects.create(
key='production',
label='生产管理',
page_type=FrontendPageTypeEnum.MAIN
)
self.sub_menu1 = FrontendPage.objects.create(
key='production-kanban',
label='生产看板',
page_type=FrontendPageTypeEnum.SUB,
parent=self.main_menu
)
self.sub_menu2 = FrontendPage.objects.create(
key='printing-order-list',
label='生产订单',
page_type=FrontendPageTypeEnum.SUB,
parent=self.main_menu
)
# 创建岗位
self.emp_type = EmployeeType.objects.create(
merchant=self.merchant,
title='生产主管'
)
def test_assign_visible_pages(self):
"""测试为岗位分配可见页面"""
self.emp_type.visible_pages.add(self.main_menu)
self.assertEqual(self.emp_type.visible_pages.count(), 1)
self.assertIn(self.main_menu, self.emp_type.visible_pages.all())
def test_get_visible_page_keys_with_main_menu(self):
"""测试授予主菜单时获取所有可见页面(含子菜单)"""
self.emp_type.visible_pages.add(self.main_menu)
# 模拟查询逻辑
visible_keys = set()
for page in self.emp_type.visible_pages.filter(is_active=True):
visible_keys.add(page.key)
if page.page_type == FrontendPageTypeEnum.MAIN:
children_keys = page.children.filter(is_active=True).values_list('key', flat=True)
visible_keys.update(children_keys)
self.assertIn('production', visible_keys)
self.assertIn('production-kanban', visible_keys)
self.assertIn('printing-order-list', visible_keys)
self.assertEqual(len(visible_keys), 3)
def test_get_visible_page_keys_with_sub_menu_only(self):
"""测试仅授予子菜单时只能看到该子菜单"""
self.emp_type.visible_pages.add(self.sub_menu1)
visible_keys = set()
for page in self.emp_type.visible_pages.filter(is_active=True):
visible_keys.add(page.key)
if page.page_type == FrontendPageTypeEnum.MAIN:
children_keys = page.children.filter(is_active=True).values_list('key', flat=True)
visible_keys.update(children_keys)
self.assertIn('production-kanban', visible_keys)
self.assertNotIn('production', visible_keys)
self.assertNotIn('printing-order-list', visible_keys)
self.assertEqual(len(visible_keys), 1)
def test_employee_visible_pages_through_position(self):
"""测试通过员工岗位查询可见页面"""
self.emp_type.visible_pages.add(self.main_menu)
employee = Employee.objects.create(
merchant=self.merchant,
name='测试员工',
position=self.emp_type
)
# 通过员工 -> 岗位 -> 可见页面
visible_pages = employee.position.visible_pages.all()
self.assertEqual(visible_pages.count(), 1)
self.assertIn(self.main_menu, visible_pages)
class SyncFrontendPagesCommandTestCase(TestCase):
"""测试 sync_frontend_pages 管理命令"""
def test_sync_command_dry_run(self):
"""测试 dry-run 模式不写入数据"""
out = StringIO()
call_command('sync_frontend_pages', '--dry-run', stdout=out)
# 验证没有实际写入
self.assertEqual(FrontendPage.objects.count(), 0)
self.assertIn('DRY-RUN', out.getvalue())
def test_sync_command_creates_pages(self):
"""测试命令创建页面数据"""
out = StringIO()
call_command('sync_frontend_pages', stdout=out)
# 验证创建了页面
self.assertGreater(FrontendPage.objects.count(), 0)
# 验证主菜单
main_menus = FrontendPage.objects.filter(page_type=FrontendPageTypeEnum.MAIN)
self.assertEqual(main_menus.count(), 9) # 9 个主菜单
# 验证子菜单
sub_menus = FrontendPage.objects.filter(page_type=FrontendPageTypeEnum.SUB)
self.assertEqual(sub_menus.count(), 43) # 43 个子菜单
# 验证父子关系
plate_opening = FrontendPage.objects.get(key='plate-opening')
self.assertEqual(plate_opening.children.count(), 5)
def test_sync_command_idempotent(self):
"""测试命令幂等性(多次运行结果一致)"""
call_command('sync_frontend_pages', stdout=StringIO())
first_count = FrontendPage.objects.count()
call_command('sync_frontend_pages', stdout=StringIO())
second_count = FrontendPage.objects.count()
self.assertEqual(first_count, second_count)
def test_sync_command_clear_option(self):
"""测试 --clear 选项"""
# 先创建数据
call_command('sync_frontend_pages', stdout=StringIO())
self.assertGreater(FrontendPage.objects.count(), 0)
# 使用 --clear 重新同步
out = StringIO()
call_command('sync_frontend_pages', '--clear', stdout=out)
self.assertIn('已清空', out.getvalue())
# 数据应该重新创建
self.assertEqual(FrontendPage.objects.count(), 52) # 9 主菜单 + 43 子菜单