"""Tests for registers admin configuration.""" import io from unittest.mock import patch from apps.registers.admin import RegisterUploadAdmin from apps.registers.models import Organization, RegisterUpload, RegistryMembershipPeriod from django.contrib.admin.sites import AdminSite from django.contrib.messages.storage.fallback import FallbackStorage from django.core.files.uploadedfile import SimpleUploadedFile from django.test import RequestFactory, TestCase from django.urls import reverse from openpyxl import Workbook from tests.apps.registers.factories import RegisterFactory from tests.apps.user.factories import UserFactory def _build_register_excel_upload(filename: str = "registry.xlsx") -> SimpleUploadedFile: workbook = Workbook() worksheet = workbook.active worksheet.append(["pn_name", "mn_ogrn", "mn_inn", "in_kpp", "mn_okpo"]) worksheet.append( [ 'АО "Тестовая организация"', 1027600980990, 7601000086, 760401001, "07506197", ] ) buffer = io.BytesIO() workbook.save(buffer) workbook.close() return SimpleUploadedFile( filename, buffer.getvalue(), content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", ) class RegistersAdminTest(TestCase): def setUp(self): self.site = AdminSite() self.factory = RequestFactory() self.user = UserFactory.create_superuser() self.client.force_login(self.user) def _request(self, path="/admin/registers/registerupload/upload-excel/"): request = self.factory.get(path) request.user = self.user request.session = {} request._messages = FallbackStorage(request) return request def _post_request(self, data): request = self.factory.post( "/admin/registers/registerupload/upload-excel/", data=data, ) request.user = self.user request.session = {} request._messages = FallbackStorage(request) return request def test_register_upload_admin_has_custom_upload_route(self): admin = RegisterUploadAdmin(RegisterUpload, self.site) route_names = [route.name for route in admin.get_urls()] self.assertIn("registers_registerupload_upload_excel", route_names) def test_register_upload_admin_get_renders_custom_file_picker(self): admin = RegisterUploadAdmin(RegisterUpload, self.site) response = admin.upload_excel_view(self._request()) response.render() content = response.content.decode("utf-8") self.assertEqual(response.status_code, 200) self.assertIn('type="file"', content) self.assertIn("mx-upload-file", content) self.assertIn("multiple", content) def test_register_upload_changelist_renders_toolbar_buttons(self): response = self.client.get(reverse("admin:index")) self.assertEqual(response.status_code, 200) self.assertIn("Загрузить реестр", response.content.decode("utf-8")) self.assertIn("Добавить загрузку реестра", response.content.decode("utf-8")) self.assertIn( reverse("admin:registers_registerupload_upload_excel"), response.content.decode("utf-8"), ) self.assertIn( reverse("admin:registers_registerupload_add"), response.content.decode("utf-8"), ) def test_register_upload_admin_upload_excel_success(self): admin = RegisterUploadAdmin(RegisterUpload, self.site) registry = RegisterFactory() uploaded_file = _build_register_excel_upload() request = self._post_request( { "registry": str(registry.id), "actual_date": "2026-03-20", "file": uploaded_file, } ) response = admin.upload_excel_view(request) self.assertEqual(response.status_code, 302) self.assertEqual(RegisterUpload.objects.count(), 1) self.assertEqual(Organization.objects.count(), 1) self.assertEqual(RegistryMembershipPeriod.objects.count(), 1) upload = RegisterUpload.objects.first() self.assertEqual(upload.registry, registry) self.assertEqual(upload.actual_date.isoformat(), "2026-03-20") def test_register_upload_admin_upload_excel_invalid_extension(self): admin = RegisterUploadAdmin(RegisterUpload, self.site) registry = RegisterFactory() invalid_file = SimpleUploadedFile("registry.txt", b"text/plain") request = self._post_request( { "registry": str(registry.id), "actual_date": "2026-03-20", "file": invalid_file, } ) response = admin.upload_excel_view(request) self.assertEqual(response.status_code, 302) self.assertEqual(RegisterUpload.objects.count(), 0) def test_register_upload_admin_uses_sync_import_service(self): admin = RegisterUploadAdmin(RegisterUpload, self.site) registry = RegisterFactory() uploaded_file = _build_register_excel_upload() request = self._post_request( { "registry": str(registry.id), "actual_date": "2026-03-20", "file": uploaded_file, } ) with patch( "apps.registers.admin.RegisterImportService.sync_registry_memberships", return_value={ "registry_name": registry.name, "rows_in_file": 1, "organizations_created": 1, "organizations_updated": 0, }, ) as sync_mock: response = admin.upload_excel_view(request) self.assertEqual(response.status_code, 302) sync_mock.assert_called_once() def test_register_upload_admin_processes_multiple_files(self): admin = RegisterUploadAdmin(RegisterUpload, self.site) registry = RegisterFactory() first_upload = _build_register_excel_upload("registry_1.xlsx") second_upload = _build_register_excel_upload("registry_2.xlsx") request = self._post_request( { "registry": str(registry.id), "actual_date": "2026-03-20", "files": [first_upload, second_upload], } ) with patch( "apps.registers.admin.RegisterImportService.sync_registry_memberships", side_effect=[ { "registry_name": registry.name, "rows_in_file": 1, "organizations_created": 1, "organizations_updated": 0, }, { "registry_name": registry.name, "rows_in_file": 1, "organizations_created": 0, "organizations_updated": 1, }, ], ) as sync_mock: response = admin.upload_excel_view(request) self.assertEqual(response.status_code, 302) self.assertEqual(sync_mock.call_count, 2)