""" Тесты для Inventory - transfer, write_off и инвентарные номера. """ import pytest from rest_framework import status from procurement.constants import EquipmentStatus from procurement.models import ( Equipment, EquipmentCategory, EquipmentTransferLog, MaintenanceRecord, ) from procurement.services import InventoryNumberGenerator @pytest.mark.django_db class TestInventoryNumberGenerator: """Тесты для генератора инвентарных номеров.""" @pytest.fixture(autouse=True) def setup(self, department_factory, user_factory, link_factory): """Настройка тестовых данных.""" self.department = department_factory(name="IT Inventory Test") self.user = user_factory( staff=True, email="inventory_user@test.com", first_name="Test", last_name="Inventory", ) link_factory(self.user, self.department, is_active=True) self.category = EquipmentCategory.objects.create( name="Computers", description="Компьютеры и ноутбуки", ) def test_generate_first_number(self): """Тест: генерация первого инвентарного номера за год.""" from django.utils import timezone year = timezone.now().year number = InventoryNumberGenerator.generate() assert number == f"INV-{year}-0001" def test_generate_sequential_numbers(self): """Тест: последовательная генерация номеров.""" from django.utils import timezone year = timezone.now().year # Создаём оборудование с первым номером Equipment.objects.create( name="Laptop 1", inventory_number=f"INV-{year}-0005", category=self.category, department=self.department, responsible_person=self.user, status=EquipmentStatus.IN_USE, purchase_date="2025-01-01", purchase_cost="10000.00", ) number = InventoryNumberGenerator.generate() assert number == f"INV-{year}-0006" def test_validate_correct_format(self): """Тест: валидация правильного формата.""" assert InventoryNumberGenerator.validate("INV-2025-0001") is True assert InventoryNumberGenerator.validate("INV-2024-9999") is True def test_validate_incorrect_format(self): """Тест: валидация неправильного формата.""" assert InventoryNumberGenerator.validate("INV-2025") is False assert InventoryNumberGenerator.validate("ABC-2025-0001") is False assert InventoryNumberGenerator.validate("") is False @pytest.mark.django_db class TestEquipmentTransferEndpoint: """Тесты для /equipment/{id}/transfer/ endpoint.""" @pytest.fixture(autouse=True) def setup(self, api_client, department_factory, user_factory, link_factory): """Настройка тестовых данных.""" self.client = api_client self.dept1 = department_factory(name="IT Dept") self.dept2 = department_factory(name="HR Dept") self.user1 = user_factory( staff=True, email="transfer_user1@test.com", first_name="User", last_name="One", ) self.user2 = user_factory( email="transfer_user2@test.com", first_name="User", last_name="Two", ) link_factory(self.user1, self.dept1, is_active=True) link_factory(self.user2, self.dept2, is_active=True) self.category = EquipmentCategory.objects.create( name="Laptops", description="Ноутбуки", ) self.equipment = Equipment.objects.create( name="MacBook Pro", inventory_number="INV-2025-0200", category=self.category, department=self.dept1, responsible_person=self.user1, status=EquipmentStatus.IN_USE, purchase_date="2025-01-01", purchase_cost="10000.00", ) def test_transfer_to_another_department(self): """Тест: перевод оборудования в другой отдел.""" self.client.force_authenticate(user=self.user1) response = self.client.post( f"/api/v1/procurement/equipment/{self.equipment.id}/transfer/", { "to_department": self.dept2.id, "reason": "Переезд сотрудника", }, ) assert response.status_code == status.HTTP_200_OK assert response.data["status"] == "transferred" # Проверяем обновление оборудования self.equipment.refresh_from_db() assert self.equipment.department == self.dept2 # Проверяем лог перевода log = EquipmentTransferLog.objects.filter(equipment=self.equipment).first() assert log is not None assert log.from_department == self.dept1 assert log.to_department == self.dept2 assert log.reason == "Переезд сотрудника" def test_transfer_to_another_person(self): """Тест: перевод оборудования другому пользователю.""" self.client.force_authenticate(user=self.user1) response = self.client.post( f"/api/v1/procurement/equipment/{self.equipment.id}/transfer/", { "to_person": self.user2.id, "reason": "Смена ответственного", }, ) assert response.status_code == status.HTTP_200_OK self.equipment.refresh_from_db() assert self.equipment.responsible_person == self.user2 def test_transfer_requires_target(self): """Тест: нужно указать отдел или пользователя.""" self.client.force_authenticate(user=self.user1) response = self.client.post( f"/api/v1/procurement/equipment/{self.equipment.id}/transfer/", {"reason": "Без цели"}, ) assert response.status_code == status.HTTP_400_BAD_REQUEST @pytest.mark.django_db class TestEquipmentWriteOffEndpoint: """Тесты для /equipment/{id}/write_off/ endpoint.""" @pytest.fixture(autouse=True) def setup(self, api_client, department_factory, user_factory, link_factory): """Настройка тестовых данных.""" self.client = api_client self.department = department_factory(name="IT WriteOff") self.user = user_factory( staff=True, email="writeoff_user@test.com", first_name="Test", last_name="WriteOff", ) link_factory(self.user, self.department, is_active=True) self.category = EquipmentCategory.objects.create( name="Printers", description="Принтеры", ) self.equipment = Equipment.objects.create( name="HP LaserJet", inventory_number="INV-2025-0300", category=self.category, department=self.department, responsible_person=self.user, status=EquipmentStatus.IN_USE, purchase_date="2025-01-01", purchase_cost="10000.00", ) def test_write_off_equipment(self): """Тест: списание оборудования.""" self.client.force_authenticate(user=self.user) response = self.client.post( f"/api/v1/procurement/equipment/{self.equipment.id}/write_off/", {"reason": "Износ"}, ) assert response.status_code == status.HTTP_200_OK assert response.data["status"] == "written_off" self.equipment.refresh_from_db() assert self.equipment.status == EquipmentStatus.RETIRED assert "Износ" in self.equipment.notes def test_cannot_write_off_twice(self): """Тест: нельзя списать уже списанное оборудование.""" self.equipment.status = EquipmentStatus.RETIRED self.equipment.save() self.client.force_authenticate(user=self.user) response = self.client.post( f"/api/v1/procurement/equipment/{self.equipment.id}/write_off/", {"reason": "Повторно"}, ) assert response.status_code == status.HTTP_400_BAD_REQUEST @pytest.mark.django_db class TestEquipmentMaintenanceEndpoint: """Тесты для /equipment/{id}/add_maintenance/ endpoint.""" @pytest.fixture(autouse=True) def setup(self, api_client, department_factory, user_factory, link_factory): """Настройка тестовых данных.""" self.client = api_client self.department = department_factory(name="IT Maintenance") self.user = user_factory( staff=True, email="maintenance_user@test.com", first_name="Test", last_name="Maintenance", ) link_factory(self.user, self.department, is_active=True) self.category = EquipmentCategory.objects.create( name="Servers", description="Серверы", ) self.equipment = Equipment.objects.create( name="Dell PowerEdge", inventory_number="INV-2025-0400", category=self.category, department=self.department, responsible_person=self.user, status=EquipmentStatus.IN_USE, purchase_date="2025-01-01", purchase_cost="10000.00", ) def test_add_maintenance_record(self): """Тест: добавление записи об обслуживании.""" self.client.force_authenticate(user=self.user) response = self.client.post( f"/api/v1/procurement/equipment/{self.equipment.id}/add_maintenance/", { "type": "repair", "description": "Замена блока питания", "cost": "5000.00", }, ) assert response.status_code == status.HTTP_201_CREATED assert "maintenance_id" in response.data # Проверяем создание записи record = MaintenanceRecord.objects.get(id=response.data["maintenance_id"]) assert record.equipment == self.equipment assert record.description == "Замена блока питания" assert record.performed_by == self.user @pytest.mark.django_db class TestEquipmentTransferHistoryEndpoint: """Тесты для /equipment/{id}/transfer_history/ endpoint.""" @pytest.fixture(autouse=True) def setup(self, api_client, department_factory, user_factory, link_factory): """Настройка тестовых данных.""" self.client = api_client self.dept1 = department_factory(name="IT History 1") self.dept2 = department_factory(name="IT History 2") self.user1 = user_factory( staff=True, email="history_user1@test.com", first_name="User", last_name="History1", ) self.user2 = user_factory( email="history_user2@test.com", first_name="User", last_name="History2", ) link_factory(self.user1, self.dept1, is_active=True) self.category = EquipmentCategory.objects.create( name="Phones", description="Телефоны", ) self.equipment = Equipment.objects.create( name="iPhone 15", inventory_number="INV-2025-0600", category=self.category, department=self.dept1, responsible_person=self.user1, status=EquipmentStatus.IN_USE, purchase_date="2025-01-01", purchase_cost="10000.00", ) # Создаём историю переводов EquipmentTransferLog.objects.create( equipment=self.equipment, from_department=self.dept1, to_department=self.dept2, from_person=self.user1, to_person=self.user2, reason="Первый перевод", created_by=self.user1, ) def test_get_transfer_history(self): """Тест: получение истории переводов.""" self.client.force_authenticate(user=self.user1) response = self.client.get( f"/api/v1/procurement/equipment/{self.equipment.id}/transfer_history/" ) assert response.status_code == status.HTTP_200_OK assert len(response.data) == 1 assert response.data[0]["reason"] == "Первый перевод" assert "from_department" in response.data[0] assert "to_department" in response.data[0]