Add organizations v2 API and registry enrichment
All checks were successful
CI/CD Pipeline / Quality Gate (push) Successful in 26s
CI/CD Pipeline / Build and Push Images (push) Successful in 6s
CI/CD Pipeline / Internal Notify (push) Successful in 0s
CI/CD Pipeline / Deploy Dev in Dokploy (push) Successful in 1s

This commit is contained in:
2026-05-06 19:04:46 +02:00
parent f54aa4cb0b
commit 0f17ff6773
62 changed files with 10311 additions and 430 deletions

View File

@@ -22,6 +22,12 @@ from apps.parsers.models import (
ParsingSettings,
ProcurementRecord,
)
from apps.parsers.organization_enrichment import (
ORGANIZATION_ENRICHMENT_CONTEXT_KEY,
OrganizationFieldSet,
build_canonical_organization_enrichment,
enrich_organization_fields,
)
from rest_framework import serializers
BLOCKED_FILE_HOSTS = {"localhost", "localhost.localdomain"}
@@ -76,15 +82,63 @@ def _validate_public_file_host(host: str) -> None:
# =============================================================================
class IndustrialCertificateSerializer(serializers.ModelSerializer):
class CanonicalOrganizationListSerializer(serializers.ListSerializer):
"""Adds one canonical organization lookup for the current serialized page."""
def to_representation(self, data):
items = list(data.all() if hasattr(data, "all") else data)
field_sets = getattr(self.child, "canonical_organization_fields", ())
self.context[
ORGANIZATION_ENRICHMENT_CONTEXT_KEY
] = build_canonical_organization_enrichment(items, field_sets)
return super().to_representation(items)
class CanonicalOrganizationEnrichmentMixin:
"""Fill blank v1 organization fields while preserving existing contract."""
canonical_organization_fields: tuple[OrganizationFieldSet, ...] = ()
def to_representation(self, instance):
data = super().to_representation(instance)
if not self.canonical_organization_fields:
return data
enrichment = self.context.get(ORGANIZATION_ENRICHMENT_CONTEXT_KEY)
if enrichment is None:
enrichment = build_canonical_organization_enrichment(
[instance],
self.canonical_organization_fields,
)
return enrich_organization_fields(
data,
source=instance,
field_sets=self.canonical_organization_fields,
enrichment=enrichment,
)
class IndustrialCertificateSerializer(
CanonicalOrganizationEnrichmentMixin,
serializers.ModelSerializer,
):
"""
Сертификат промышленного производства РФ.
Данные загружаются из Минпромторга.
"""
canonical_organization_fields = (
OrganizationFieldSet(
name="organisation_name",
inn="inn",
ogrn="ogrn",
),
)
class Meta:
model = IndustrialCertificateRecord
list_serializer_class = CanonicalOrganizationListSerializer
fields = [
"id",
"load_batch",
@@ -109,15 +163,27 @@ class IndustrialCertificateSerializer(serializers.ModelSerializer):
# =============================================================================
class ManufacturerSerializer(serializers.ModelSerializer):
class ManufacturerSerializer(
CanonicalOrganizationEnrichmentMixin,
serializers.ModelSerializer,
):
"""
Производитель из реестра Минпромторга.
Данные загружаются из Минпромторга.
"""
canonical_organization_fields = (
OrganizationFieldSet(
name="full_legal_name",
inn="inn",
ogrn="ogrn",
),
)
class Meta:
model = ManufacturerRecord
list_serializer_class = CanonicalOrganizationListSerializer
fields = [
"id",
"load_batch",
@@ -132,15 +198,27 @@ class ManufacturerSerializer(serializers.ModelSerializer):
read_only_fields = fields
class IndustrialProductSerializer(serializers.ModelSerializer):
class IndustrialProductSerializer(
CanonicalOrganizationEnrichmentMixin,
serializers.ModelSerializer,
):
"""
Промышленная продукция из реестра Минпромторга.
Данные загружаются из Минпромторга.
"""
canonical_organization_fields = (
OrganizationFieldSet(
name="full_organisation_name",
inn="inn",
ogrn="ogrn",
),
)
class Meta:
model = IndustrialProductRecord
list_serializer_class = CanonicalOrganizationListSerializer
fields = [
"id",
"load_batch",
@@ -165,15 +243,27 @@ class IndustrialProductSerializer(serializers.ModelSerializer):
# =============================================================================
class InspectionSerializer(serializers.ModelSerializer):
class InspectionSerializer(
CanonicalOrganizationEnrichmentMixin,
serializers.ModelSerializer,
):
"""
Проверка из Единого реестра проверок.
Поддерживает ФЗ-294 и ФЗ-248.
"""
canonical_organization_fields = (
OrganizationFieldSet(
name="organisation_name",
inn="inn",
ogrn="ogrn",
),
)
class Meta:
model = InspectionRecord
list_serializer_class = CanonicalOrganizationListSerializer
fields = [
"id",
"load_batch",
@@ -206,15 +296,28 @@ class InspectionSerializer(serializers.ModelSerializer):
# =============================================================================
class ProcurementSerializer(serializers.ModelSerializer):
class ProcurementSerializer(
CanonicalOrganizationEnrichmentMixin,
serializers.ModelSerializer,
):
"""
Государственная закупка из ЕИС zakupki.gov.ru.
Поддерживает 44-ФЗ и 223-ФЗ.
"""
canonical_organization_fields = (
OrganizationFieldSet(
name="customer_name",
inn="customer_inn",
kpp="customer_kpp",
ogrn="customer_ogrn",
),
)
class Meta:
model = ProcurementRecord
list_serializer_class = CanonicalOrganizationListSerializer
fields = [
"id",
"load_batch",
@@ -432,6 +535,13 @@ class ParserRunRequestSerializer(serializers.Serializer):
required=False,
allow_empty=True,
)
vacancy_sources = serializers.ListField(
child=serializers.ChoiceField(choices=["trudvsem", "hh", "superjob"]),
required=False,
allow_empty=False,
)
registry_organizations_only = serializers.BooleanField(required=False)
registry_organization_limit = serializers.IntegerField(required=False, min_value=1)
year = serializers.IntegerField(required=False, min_value=2000, max_value=2100)
month = serializers.IntegerField(required=False, min_value=1, max_value=12)
limit = serializers.IntegerField(required=False, min_value=1, max_value=1000)
@@ -695,11 +805,23 @@ class ParserLoadLogSerializer(serializers.ModelSerializer):
return 0
class GenericParserRecordSerializer(serializers.ModelSerializer):
class GenericParserRecordSerializer(
CanonicalOrganizationEnrichmentMixin,
serializers.ModelSerializer,
):
"""Сериализатор универсальных записей новых источников."""
canonical_organization_fields = (
OrganizationFieldSet(
name="organisation_name",
inn="inn",
ogrn="ogrn",
),
)
class Meta:
model = GenericParserRecord
list_serializer_class = CanonicalOrganizationListSerializer
fields = [
"id",
"load_batch",