fix: resolve parser organizations from directory only
Some checks failed
CI/CD Pipeline / Quality Gate (push) Failing after 32s
CI/CD Pipeline / Build and Push Images (push) Has been skipped
CI/CD Pipeline / Internal Notify (push) Successful in 0s
CI/CD Pipeline / Deploy Dev via Compose (push) Has been skipped

This commit is contained in:
2026-06-07 16:28:57 +02:00
parent 6ba8fa8d88
commit 802257a757
19 changed files with 184 additions and 83 deletions

View File

@@ -1,6 +1,7 @@
"""Tests for organization directory resolver."""
from django.test import TestCase
from django.utils import timezone
from organizations.models import Organization
from organizations.resolver import OrganizationDirectoryResolver
@@ -8,15 +9,20 @@ from organizations.resolver import OrganizationDirectoryResolver
class OrganizationDirectoryResolverTest(TestCase):
"""Checks matching parser rows to the organization directory."""
@staticmethod
def _directory_organization(**kwargs) -> Organization:
kwargs.setdefault("directory_imported_at", timezone.now())
return Organization.objects.create(**kwargs)
def test_resolves_by_rn_okpo_and_exact_pairs(self):
by_rn = Organization.objects.create(name="RN", rn=100)
by_okpo = Organization.objects.create(name="OKPO", okpo="001")
by_inn_kpp = Organization.objects.create(
by_rn = self._directory_organization(name="RN", rn=100)
by_okpo = self._directory_organization(name="OKPO", okpo="001")
by_inn_kpp = self._directory_organization(
name="INN KPP",
inn="7701001001",
kpp="770101001",
)
by_ogrn_kpp = Organization.objects.create(
by_ogrn_kpp = self._directory_organization(
name="OGRN KPP",
ogrn="1027700100001",
kpp="770101002",
@@ -54,13 +60,13 @@ class OrganizationDirectoryResolverTest(TestCase):
)
def test_duplicate_inn_ogrn_uses_single_head(self):
head = Organization.objects.create(
head = self._directory_organization(
name="Head",
inn="7701001001",
ogrn="1027700100001",
is_branch=False,
)
Organization.objects.create(
self._directory_organization(
name="Branch",
inn="7701001001",
ogrn="1027700100001",
@@ -78,13 +84,13 @@ class OrganizationDirectoryResolverTest(TestCase):
self.assertEqual(result.organization, head)
def test_duplicate_inn_ogrn_without_single_head_is_ambiguous(self):
Organization.objects.create(
self._directory_organization(
name="Head 1",
inn="7701001001",
ogrn="1027700100001",
is_branch=False,
)
Organization.objects.create(
self._directory_organization(
name="Head 2",
inn="7701001001",
ogrn="1027700100001",
@@ -100,3 +106,20 @@ class OrganizationDirectoryResolverTest(TestCase):
self.assertEqual(result.status, "ambiguous")
self.assertIsNone(result.organization)
def test_ignores_legacy_organization_matches(self):
Organization.objects.create(
name="Legacy",
inn="7701001001",
kpp="770101001",
)
result = OrganizationDirectoryResolver.resolve(
OrganizationDirectoryResolver.identity(
inn="7701001001",
kpp="770101001",
)
)
self.assertEqual(result.status, "unmatched")
self.assertIsNone(result.organization)

View File

@@ -8,6 +8,7 @@ from apps.parsers.models import (
)
from django.core.management import call_command
from django.test import TestCase
from django.utils import timezone
from organizations.models import (
DefenseSupplierExtension,
FinancialIndicatorsExtension,
@@ -28,8 +29,13 @@ from tests.apps.parsers.factories import (
class OrganizationSourceBackfillServiceTest(TestCase):
"""Checks idempotent migration from legacy source records."""
@staticmethod
def _directory_organization(**kwargs) -> Organization:
kwargs.setdefault("directory_imported_at", timezone.now())
return Organization.objects.create(**kwargs)
def test_backfills_inspection_records_into_planned_inspection_extension(self):
organization = Organization.objects.create(
organization = self._directory_organization(
name='ООО "Проверка"',
inn="7707083801",
ogrn="1027700132001",
@@ -71,7 +77,7 @@ class OrganizationSourceBackfillServiceTest(TestCase):
self.assertEqual(OrganizationSourceRecord.objects.count(), 1)
def test_backfill_payload_serializes_registry_organization_fk_as_id(self):
organization = Organization.objects.create(
organization = self._directory_organization(
name='ООО "FK Payload"',
inn="7707083815",
ogrn="1027700132015",
@@ -94,7 +100,7 @@ class OrganizationSourceBackfillServiceTest(TestCase):
self.assertEqual(record.payload["registry_organization"], str(organization.pk))
def test_backfills_financial_report_lines(self):
organization = Organization.objects.create(
organization = self._directory_organization(
name='ООО "Финансы"',
inn="7707083802",
ogrn="1027700132002",
@@ -132,7 +138,7 @@ class OrganizationSourceBackfillServiceTest(TestCase):
self.assertEqual(record.financial_lines.get().period_end, 200)
def test_backfills_generic_defense_supplier_records(self):
organization = Organization.objects.create(
organization = self._directory_organization(
name='ООО "ГОЗ"',
inn="7707083803",
)
@@ -189,7 +195,7 @@ class OrganizationSourceBackfillServiceTest(TestCase):
)
def test_management_command_runs_source_backfill(self):
organization = Organization.objects.create(
organization = self._directory_organization(
name='ООО "Команда"',
inn="7707083804",
ogrn="1027700132004",

View File

@@ -4,6 +4,7 @@ from decimal import Decimal
from apps.parsers.models import FinancialReport, GenericParserRecord, ParserLoadLog
from django.test import TestCase
from django.utils import timezone
from organizations.models import (
DefenseSupplierExtension,
FinancialIndicatorsExtension,
@@ -22,8 +23,13 @@ from organizations.source_ingestion import (
class OrganizationSourceIngestionServiceTest(TestCase):
"""Checks runtime parser writes bypass legacy parser record tables."""
@staticmethod
def _directory_organization(**kwargs) -> Organization:
kwargs.setdefault("directory_imported_at", timezone.now())
return Organization.objects.create(**kwargs)
def test_save_generic_records_writes_source_records_without_legacy_rows(self):
Organization.objects.create(
self._directory_organization(
name='ООО "ГОЗ"',
inn="7707083803",
)
@@ -70,7 +76,7 @@ class OrganizationSourceIngestionServiceTest(TestCase):
self.assertEqual(record.legacy_pk, "")
def test_save_records_is_idempotent_by_source_external_id(self):
Organization.objects.create(
self._directory_organization(
name='ООО "Идемпотентность"',
inn="7707083810",
)
@@ -140,7 +146,7 @@ class OrganizationSourceIngestionServiceTest(TestCase):
self.assertFalse(name_only.source_extensions.exists())
def test_save_records_does_not_fill_missing_identity_on_resolved_organization(self):
partial = Organization.objects.create(
partial = self._directory_organization(
name="Acme Security",
inn="7713497980",
ogrn="1237700253306",
@@ -168,14 +174,14 @@ class OrganizationSourceIngestionServiceTest(TestCase):
self.assertEqual(record.extension.organization, partial)
def test_save_records_uses_single_head_organization_for_duplicate_inn_ogrn(self):
head = Organization.objects.create(
head = self._directory_organization(
name="Head",
inn="7713497980",
ogrn="1237700253306",
filial=".F.",
is_branch=False,
)
Organization.objects.create(
self._directory_organization(
name="Branch",
inn="7713497980",
ogrn="1237700253306",
@@ -202,14 +208,14 @@ class OrganizationSourceIngestionServiceTest(TestCase):
self.assertEqual(record.extension.organization, head)
def test_save_records_skips_ambiguous_duplicate_inn_ogrn(self):
Organization.objects.create(
self._directory_organization(
name="Head 1",
inn="7713497980",
ogrn="1237700253306",
filial=".F.",
is_branch=False,
)
Organization.objects.create(
self._directory_organization(
name="Head 2",
inn="7713497980",
ogrn="1237700253306",
@@ -259,7 +265,7 @@ class OrganizationSourceIngestionServiceTest(TestCase):
self.assertFalse(Organization.objects.filter(inn="7720525156").exists())
def test_save_records_does_not_add_ogrip_to_existing_legal_entity(self):
organization = Organization.objects.create(
organization = self._directory_organization(
name='ООО "Металл-Завод"',
inn="7720525156",
ogrn="1057746645395",
@@ -286,7 +292,7 @@ class OrganizationSourceIngestionServiceTest(TestCase):
self.assertEqual(organization.ogrip, "")
def test_save_financial_report_writes_financial_lines_without_legacy_report(self):
Organization.objects.create(
self._directory_organization(
name='ООО "Финансовый отчет"',
ogrn="1027700132002",
)

View File

@@ -6,6 +6,7 @@ from apps.parsers.models import ParserLoadLog
from django.apps import apps as django_apps
from django.core.cache import cache
from django.test import TestCase
from django.utils import timezone
from django_celery_beat.models import PeriodicTask
from organizations.cache import get_organization_api_cache_version
from organizations.models import (
@@ -24,8 +25,13 @@ from tests.apps.parsers.factories import IndustrialCertificateRecordFactory
class OrganizationSourceBackfillTasksTest(TestCase):
"""Checks Celery tasks that maintain API v2 organization source extensions."""
@staticmethod
def _directory_organization(**kwargs) -> Organization:
kwargs.setdefault("directory_imported_at", timezone.now())
return Organization.objects.create(**kwargs)
def test_backfill_all_task_rebuilds_sources_and_invalidates_api_cache(self):
organization = Organization.objects.create(
organization = self._directory_organization(
name='ООО "Источник"',
inn="7800000401",
ogrn="1027700144401",
@@ -57,7 +63,7 @@ class OrganizationSourceBackfillTasksTest(TestCase):
)
def test_backfill_parser_batch_task_limits_source_and_batch(self):
organization = Organization.objects.create(
organization = self._directory_organization(
name='ООО "Пакет источника"',
inn="7800000402",
ogrn="1027700144402",