219 lines
7.6 KiB
Python
219 lines
7.6 KiB
Python
"""Tests for authoritative organization directory import."""
|
||
|
||
from decimal import Decimal
|
||
from tempfile import NamedTemporaryFile
|
||
|
||
from django.test import TestCase
|
||
from openpyxl import Workbook
|
||
from organizations.directory_import import (
|
||
DIRECTORY_SHEET,
|
||
SOURCE_HEADERS,
|
||
OrganizationDirectoryImportError,
|
||
OrganizationDirectoryImportService,
|
||
)
|
||
from organizations.models import Organization
|
||
|
||
|
||
class OrganizationDirectoryImportServiceTest(TestCase):
|
||
"""Checks importing the authoritative XLSX organization directory."""
|
||
|
||
def test_import_xlsx_creates_and_updates_organizations_by_rn(self):
|
||
path = self._workbook_path(
|
||
[
|
||
self._row(
|
||
rn="10",
|
||
full_name='Акционерное общество "Тест"',
|
||
short_name='АО "Тест"',
|
||
inn="7701001001",
|
||
ogrn="1027700100001",
|
||
okpo="00123456",
|
||
filial=".F.",
|
||
kpp="770101001",
|
||
registration_date="01.02.2020",
|
||
authorized_capita=1000,
|
||
business_act_cod="2",
|
||
goz_participation=".T.",
|
||
opk_registry_membership=".F.",
|
||
_gk="1",
|
||
in_korp="1",
|
||
_k="2",
|
||
)
|
||
]
|
||
)
|
||
|
||
first = OrganizationDirectoryImportService.import_xlsx(path)
|
||
second = OrganizationDirectoryImportService.import_xlsx(path)
|
||
|
||
self.assertEqual(first.scanned, 1)
|
||
self.assertEqual(first.created, 1)
|
||
self.assertEqual(second.updated, 1)
|
||
self.assertEqual(Organization.objects.count(), 1)
|
||
|
||
organization = Organization.objects.get(rn=10)
|
||
self.assertEqual(organization.name, 'Акционерное общество "Тест"')
|
||
self.assertEqual(organization.okpo, "00123456")
|
||
self.assertFalse(organization.is_branch)
|
||
self.assertEqual(organization.authorized_capital, Decimal("1000.00"))
|
||
self.assertEqual(organization.business_activity, "Производственная")
|
||
self.assertEqual(organization.gk_name, "Роскосмос")
|
||
self.assertEqual(organization.in_korp_name, "Входит в состав")
|
||
self.assertEqual(organization.state_sector_name, "Головные исполнители")
|
||
self.assertTrue(organization.goz_participation)
|
||
self.assertFalse(organization.opk_registry_membership)
|
||
|
||
def test_import_xlsx_rejects_missing_required_column(self):
|
||
path = self._workbook_path([], headers=SOURCE_HEADERS[:-1])
|
||
|
||
with self.assertRaisesMessage(
|
||
OrganizationDirectoryImportError,
|
||
"Missing required columns",
|
||
):
|
||
OrganizationDirectoryImportService.import_xlsx(path)
|
||
|
||
def test_import_xlsx_treats_spaced_dot_date_marker_as_empty(self):
|
||
path = self._workbook_path(
|
||
[
|
||
self._row(
|
||
rn="11",
|
||
registration_date=". .",
|
||
appointment_date=". .",
|
||
filial=".T.",
|
||
)
|
||
]
|
||
)
|
||
|
||
result = OrganizationDirectoryImportService.import_xlsx(path)
|
||
|
||
self.assertEqual(result.created, 1)
|
||
organization = Organization.objects.get(rn=11)
|
||
self.assertIsNone(organization.registration_date)
|
||
self.assertIsNone(organization.appointment_date)
|
||
self.assertTrue(organization.is_branch)
|
||
|
||
def test_import_xlsx_recovers_embedded_tsv_organization_row(self):
|
||
first_tail = [
|
||
*[
|
||
self._row(
|
||
rn="20",
|
||
pn_name_en="First EN",
|
||
inn="7701001020",
|
||
ogrn="1027700100020",
|
||
okpo="00000020",
|
||
filial=".F.",
|
||
kpp="770101020",
|
||
registration_date="01.01.2020",
|
||
_k="2",
|
||
)[header]
|
||
for header in SOURCE_HEADERS[6:-1]
|
||
],
|
||
"20",
|
||
"2",
|
||
]
|
||
embedded_value = "\t".join(str(value or "") for value in first_tail)
|
||
embedded_value = (
|
||
embedded_value
|
||
+ "_x000D_\n"
|
||
+ "\t".join(["21", "0", "0", 'ООО "Вторая"'])
|
||
)
|
||
|
||
second_row = self._row(
|
||
rn="21",
|
||
full_name='ООО "Вторая"',
|
||
short_name='ООО "Вторая"',
|
||
pn_name='ООО "Вторая"',
|
||
inn="7701001021",
|
||
ogrn="1027700100021",
|
||
okpo="00000021",
|
||
filial=".F.",
|
||
kpp="770101021",
|
||
registration_date="02.01.2020",
|
||
_k="2",
|
||
)
|
||
second_row["is"] = "21"
|
||
path = self._workbook_path(
|
||
[
|
||
{
|
||
"__raw_row__": [
|
||
"20",
|
||
"0",
|
||
"0",
|
||
'ООО "Первая"',
|
||
'ООО "Первая"',
|
||
'ООО "Первая"',
|
||
embedded_value,
|
||
*[second_row[header] for header in SOURCE_HEADERS[4:]],
|
||
]
|
||
}
|
||
]
|
||
)
|
||
|
||
result = OrganizationDirectoryImportService.import_xlsx(path)
|
||
|
||
self.assertEqual(result.scanned, 1)
|
||
self.assertEqual(result.created, 2)
|
||
self.assertEqual(Organization.objects.count(), 2)
|
||
self.assertEqual(Organization.objects.get(rn=20).inn, "7701001020")
|
||
second = Organization.objects.get(rn=21)
|
||
self.assertEqual(second.inn, "7701001021")
|
||
self.assertEqual(second.integrated_structure, "")
|
||
|
||
def _workbook_path(
|
||
self,
|
||
rows: list[dict[str, object]],
|
||
*,
|
||
headers: list[str] | None = None,
|
||
) -> str:
|
||
workbook = Workbook()
|
||
worksheet = workbook.active
|
||
worksheet.title = DIRECTORY_SHEET
|
||
worksheet.append(headers or SOURCE_HEADERS)
|
||
for values in rows:
|
||
raw_row = values.get("__raw_row__")
|
||
if raw_row is not None:
|
||
worksheet.append(raw_row)
|
||
else:
|
||
worksheet.append([values.get(header, "") for header in SOURCE_HEADERS])
|
||
|
||
self._append_reference_sheet(workbook, "_gk", {"1": "Роскосмос"})
|
||
self._append_reference_sheet(workbook, "in_korp", {"1": "Входит в состав"})
|
||
self._append_reference_sheet(
|
||
workbook,
|
||
"business_act_cod",
|
||
{"2": "Производственная"},
|
||
)
|
||
self._append_reference_sheet(
|
||
workbook,
|
||
"_k - Госектор",
|
||
{"2": "Головные исполнители"},
|
||
)
|
||
|
||
temp_file = NamedTemporaryFile(suffix=".xlsx", delete=False)
|
||
temp_file.close()
|
||
workbook.save(temp_file.name)
|
||
return temp_file.name
|
||
|
||
@staticmethod
|
||
def _append_reference_sheet(
|
||
workbook: Workbook,
|
||
title: str,
|
||
values: dict[str, str],
|
||
) -> None:
|
||
worksheet = workbook.create_sheet(title=title)
|
||
worksheet.append(["kod", "value"])
|
||
for key, value in values.items():
|
||
worksheet.append([key, value])
|
||
|
||
@staticmethod
|
||
def _row(**overrides) -> dict[str, object]:
|
||
row = {header: "" for header in SOURCE_HEADERS}
|
||
row.update(
|
||
{
|
||
"rn": "1",
|
||
"full_name": 'ООО "По умолчанию"',
|
||
"inn": "7701001000",
|
||
"ogrn": "1027700100000",
|
||
}
|
||
)
|
||
row.update(overrides)
|
||
return row
|