feat(registry): add new endpoints for registers, exchange, and backups; update routing and configurations
Some checks failed
CI/CD Pipeline / Code Quality Checks (push) Failing after 3m10s
CI/CD Pipeline / Run Tests (push) Successful in 3m35s
CI/CD Pipeline / Telegram Notify Success (push) Has been skipped
CI/CD Pipeline / Code Quality Checks (pull_request) Failing after 2m26s
CI/CD Pipeline / Run Tests (pull_request) Successful in 2m46s
CI/CD Pipeline / Telegram Notify Success (pull_request) Has been skipped

This commit is contained in:
2026-03-04 15:36:57 +01:00
parent 052389d921
commit a91ed1f1ae
90 changed files with 5488 additions and 622 deletions

View File

@@ -0,0 +1,40 @@
# Generated by Django 3.2.25 on 2026-03-04 11:59
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("registers", "0002_auto_20260304_1038"),
("parsers", "0008_add_load_log_unique_constraint"),
]
operations = [
migrations.AddField(
model_name="financialreport",
name="registry_organization",
field=models.ForeignKey(blank=True, help_text="Связь с организацией из приложения реестров", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="financial_reports", to="registers.organization", verbose_name="организация из реестров"),
),
migrations.AddField(
model_name="industrialcertificaterecord",
name="registry_organization",
field=models.ForeignKey(blank=True, help_text="Связь с организацией из приложения реестров", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="industrial_certificate_records", to="registers.organization", verbose_name="организация из реестров"),
),
migrations.AddField(
model_name="inspectionrecord",
name="registry_organization",
field=models.ForeignKey(blank=True, help_text="Связь с организацией из приложения реестров", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="inspection_records", to="registers.organization", verbose_name="организация из реестров"),
),
migrations.AddField(
model_name="manufacturerrecord",
name="registry_organization",
field=models.ForeignKey(blank=True, help_text="Связь с организацией из приложения реестров", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="manufacturer_records", to="registers.organization", verbose_name="организация из реестров"),
),
migrations.AddField(
model_name="procurementrecord",
name="registry_organization",
field=models.ForeignKey(blank=True, help_text="Связь с организацией из приложения реестров", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name="procurement_records", to="registers.organization", verbose_name="организация из реестров"),
),
]

View File

@@ -0,0 +1,166 @@
# Generated by Django 3.2.25 on 2026-03-04
from collections import defaultdict
from django.db import migrations
def _normalize_identifier(value):
if value is None:
return None
as_str = str(value).strip()
if not as_str or not as_str.isdigit():
return None
return int(as_str)
def _resolve_organization_id(*, inn, ogrn, by_pair, by_inn, by_ogrn):
if inn is not None and ogrn is not None:
by_pair_id = by_pair.get((inn, ogrn))
if by_pair_id is not None:
return by_pair_id
if inn is not None and inn in by_inn:
return by_inn[inn]
if ogrn is not None and ogrn in by_ogrn:
return by_ogrn[ogrn]
return None
def _build_organization_lookup(organization_model):
by_pair = {}
by_inn_candidates = defaultdict(list)
by_ogrn_candidates = defaultdict(list)
organizations = organization_model.objects.all().values("id", "mn_inn", "mn_ogrn")
for organization in organizations:
organization_id = organization["id"]
inn = organization["mn_inn"]
ogrn = organization["mn_ogrn"]
by_pair[(inn, ogrn)] = organization_id
by_inn_candidates[inn].append(organization_id)
by_ogrn_candidates[ogrn].append(organization_id)
by_inn = {
inn: ids[0]
for inn, ids in by_inn_candidates.items()
if len(set(ids)) == 1
}
by_ogrn = {
ogrn: ids[0]
for ogrn, ids in by_ogrn_candidates.items()
if len(set(ids)) == 1
}
return by_pair, by_inn, by_ogrn
def _link_model_records(
*,
model,
inn_field,
ogrn_field,
by_pair,
by_inn,
by_ogrn,
batch_size=1000,
):
field_names = ["id"]
if inn_field:
field_names.append(inn_field)
if ogrn_field:
field_names.append(ogrn_field)
queryset = model.objects.filter(registry_organization__isnull=True).only(*field_names)
updates = []
for record in queryset.iterator(chunk_size=batch_size):
inn = _normalize_identifier(getattr(record, inn_field)) if inn_field else None
ogrn = _normalize_identifier(getattr(record, ogrn_field)) if ogrn_field else None
organization_id = _resolve_organization_id(
inn=inn,
ogrn=ogrn,
by_pair=by_pair,
by_inn=by_inn,
by_ogrn=by_ogrn,
)
if organization_id is None:
continue
record.registry_organization_id = organization_id
updates.append(record)
if len(updates) >= batch_size:
model.objects.bulk_update(updates, ["registry_organization"], batch_size=batch_size)
updates = []
if updates:
model.objects.bulk_update(updates, ["registry_organization"], batch_size=batch_size)
def link_registry_organizations(apps, schema_editor):
organization_model = apps.get_model("registers", "Organization")
industrial_model = apps.get_model("parsers", "IndustrialCertificateRecord")
manufacturer_model = apps.get_model("parsers", "ManufacturerRecord")
inspection_model = apps.get_model("parsers", "InspectionRecord")
procurement_model = apps.get_model("parsers", "ProcurementRecord")
financial_report_model = apps.get_model("parsers", "FinancialReport")
by_pair, by_inn, by_ogrn = _build_organization_lookup(organization_model)
_link_model_records(
model=industrial_model,
inn_field="inn",
ogrn_field="ogrn",
by_pair=by_pair,
by_inn=by_inn,
by_ogrn=by_ogrn,
)
_link_model_records(
model=manufacturer_model,
inn_field="inn",
ogrn_field="ogrn",
by_pair=by_pair,
by_inn=by_inn,
by_ogrn=by_ogrn,
)
_link_model_records(
model=inspection_model,
inn_field="inn",
ogrn_field="ogrn",
by_pair=by_pair,
by_inn=by_inn,
by_ogrn=by_ogrn,
)
_link_model_records(
model=procurement_model,
inn_field="customer_inn",
ogrn_field="customer_ogrn",
by_pair=by_pair,
by_inn=by_inn,
by_ogrn=by_ogrn,
)
_link_model_records(
model=financial_report_model,
inn_field=None,
ogrn_field="ogrn",
by_pair=by_pair,
by_inn=by_inn,
by_ogrn=by_ogrn,
)
class Migration(migrations.Migration):
dependencies = [
("parsers", "0009_auto_20260304_1159"),
]
operations = [
migrations.RunPython(link_registry_organizations, migrations.RunPython.noop),
]

View File

@@ -0,0 +1,91 @@
# Generated by Django 3.2.25 on 2026-03-04
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("parsers", "0010_link_registry_organizations"),
]
operations = [
migrations.AddField(
model_name="industrialcertificaterecord",
name="issue_date_normalized",
field=models.DateField(
blank=True,
db_index=True,
help_text="Нормализованная дата выдачи сертификата",
null=True,
verbose_name="дата выдачи (нормализованная)",
),
),
migrations.AddField(
model_name="industrialcertificaterecord",
name="expiry_date_normalized",
field=models.DateField(
blank=True,
db_index=True,
help_text="Нормализованная дата окончания действия",
null=True,
verbose_name="дата окончания (нормализованная)",
),
),
migrations.AddField(
model_name="inspectionrecord",
name="start_date_normalized",
field=models.DateField(
blank=True,
db_index=True,
help_text="Нормализованная дата начала проверки",
null=True,
verbose_name="дата начала (нормализованная)",
),
),
migrations.AddField(
model_name="inspectionrecord",
name="end_date_normalized",
field=models.DateField(
blank=True,
db_index=True,
help_text="Нормализованная дата окончания проверки",
null=True,
verbose_name="дата окончания (нормализованная)",
),
),
migrations.AddField(
model_name="procurementrecord",
name="max_price_amount",
field=models.DecimalField(
blank=True,
db_index=True,
decimal_places=2,
help_text="Нормализованная числовая НМЦ",
max_digits=20,
null=True,
verbose_name="НМЦ (число)",
),
),
migrations.AddField(
model_name="procurementrecord",
name="publish_date_normalized",
field=models.DateField(
blank=True,
db_index=True,
help_text="Нормализованная дата публикации извещения",
null=True,
verbose_name="дата публикации (нормализованная)",
),
),
migrations.AddField(
model_name="procurementrecord",
name="end_date_normalized",
field=models.DateField(
blank=True,
db_index=True,
help_text="Нормализованная дата окончания подачи заявок",
null=True,
verbose_name="дата окончания (нормализованная)",
),
),
]