feat(organizations): migrate source storage to polymorphic records
This commit is contained in:
278
tests/apps/parsers/test_direct_ingestion_services.py
Normal file
278
tests/apps/parsers/test_direct_ingestion_services.py
Normal file
@@ -0,0 +1,278 @@
|
||||
"""Tests for parser services writing directly to organization source storage."""
|
||||
|
||||
from decimal import Decimal
|
||||
|
||||
from apps.parsers.clients.common import GenericParserItem
|
||||
from apps.parsers.clients.fns.schemas import ReportLine
|
||||
from apps.parsers.clients.minpromtorg.schemas import (
|
||||
IndustrialCertificate,
|
||||
IndustrialProduct,
|
||||
Manufacturer,
|
||||
)
|
||||
from apps.parsers.clients.proverki.schemas import Inspection
|
||||
from apps.parsers.clients.zakupki.schemas import Procurement
|
||||
from apps.parsers.models import (
|
||||
FinancialReport,
|
||||
GenericParserRecord,
|
||||
IndustrialCertificateRecord,
|
||||
IndustrialProductRecord,
|
||||
InspectionRecord,
|
||||
ManufacturerRecord,
|
||||
ParserLoadLog,
|
||||
ProcurementRecord,
|
||||
)
|
||||
from apps.parsers.services import (
|
||||
FNSReportService,
|
||||
GenericParserRecordService,
|
||||
IndustrialCertificateService,
|
||||
IndustrialProductService,
|
||||
InspectionService,
|
||||
ManufacturerService,
|
||||
ProcurementService,
|
||||
)
|
||||
from django.test import TestCase
|
||||
from organizations.models import (
|
||||
OrganizationSourceFinancialLine,
|
||||
OrganizationSourceRecord,
|
||||
)
|
||||
|
||||
|
||||
class DirectIngestionParserServicesTest(TestCase):
|
||||
"""Parser save services should not write legacy parser record rows."""
|
||||
|
||||
def test_industrial_certificate_save_records_writes_organization_source_records(self):
|
||||
saved = IndustrialCertificateService.save_certificates(
|
||||
[
|
||||
IndustrialCertificate(
|
||||
issue_date="01.02.2026",
|
||||
certificate_number="CERT-DIRECT-1",
|
||||
expiry_date="2029-02-01",
|
||||
certificate_file_url="https://example.test/cert.pdf",
|
||||
organisation_name='ООО "Сертификат"',
|
||||
inn="7707083801",
|
||||
ogrn="1027700132001",
|
||||
)
|
||||
],
|
||||
batch_id=47,
|
||||
)
|
||||
|
||||
self.assertEqual(saved, 1)
|
||||
self.assertEqual(IndustrialCertificateRecord.objects.count(), 0)
|
||||
record = OrganizationSourceRecord.objects.get(
|
||||
source=ParserLoadLog.Source.INDUSTRIAL,
|
||||
external_id="CERT-DIRECT-1",
|
||||
)
|
||||
self.assertEqual(record.record_type, "industrial_certificate")
|
||||
self.assertEqual(record.payload["issue_date_normalized"], "2026-02-01")
|
||||
self.assertEqual(record.payload["expiry_date_normalized"], "2029-02-01")
|
||||
self.assertEqual(record.url, "https://example.test/cert.pdf")
|
||||
|
||||
def test_manufacturer_save_records_writes_organization_source_records(self):
|
||||
saved = ManufacturerService.save_manufacturers(
|
||||
[
|
||||
Manufacturer(
|
||||
full_legal_name='ООО "Производитель"',
|
||||
inn="7707083802",
|
||||
ogrn="1027700132002",
|
||||
address="Москва",
|
||||
)
|
||||
],
|
||||
batch_id=48,
|
||||
)
|
||||
|
||||
self.assertEqual(saved, 1)
|
||||
self.assertEqual(ManufacturerRecord.objects.count(), 0)
|
||||
record = OrganizationSourceRecord.objects.get(
|
||||
source=ParserLoadLog.Source.MANUFACTURES,
|
||||
external_id="7707083802",
|
||||
)
|
||||
self.assertEqual(record.record_type, "manufacturer")
|
||||
self.assertEqual(record.title, 'ООО "Производитель"')
|
||||
self.assertEqual(record.payload["address"], "Москва")
|
||||
|
||||
def test_industrial_product_save_records_writes_organization_source_records(self):
|
||||
saved = IndustrialProductService.save_products(
|
||||
[
|
||||
IndustrialProduct(
|
||||
full_organisation_name='ООО "Продукция"',
|
||||
inn="7707083809",
|
||||
ogrn="1027700132009",
|
||||
registry_number="PROD-DIRECT-1",
|
||||
product_name="Станок",
|
||||
product_model="MODEL-1",
|
||||
okpd2_code="28.41",
|
||||
tnved_code="8457109000",
|
||||
regulatory_document="ГОСТ",
|
||||
)
|
||||
],
|
||||
batch_id=49,
|
||||
)
|
||||
|
||||
self.assertEqual(saved, 1)
|
||||
self.assertEqual(IndustrialProductRecord.objects.count(), 0)
|
||||
record = OrganizationSourceRecord.objects.get(
|
||||
source=ParserLoadLog.Source.INDUSTRIAL_PRODUCTS,
|
||||
external_id="PROD-DIRECT-1",
|
||||
)
|
||||
self.assertEqual(record.record_type, "industrial_product")
|
||||
self.assertEqual(record.title, "Станок")
|
||||
self.assertEqual(record.payload["okpd2_code"], "28.41")
|
||||
|
||||
def test_procurement_save_records_writes_organization_source_records(self):
|
||||
saved = ProcurementService.save_procurements(
|
||||
[
|
||||
Procurement(
|
||||
purchase_number="PROC-DIRECT-1",
|
||||
purchase_name="Поставка оборудования",
|
||||
customer_inn="7707083810",
|
||||
customer_kpp="770701001",
|
||||
customer_ogrn="1027700132010",
|
||||
customer_name='ООО "Заказчик"',
|
||||
max_price="1 234 567,89",
|
||||
currency_code="RUB",
|
||||
placement_method="Аукцион",
|
||||
publish_date="01.03.2026",
|
||||
end_date="2026-03-15",
|
||||
status="published",
|
||||
law_type="44-FZ",
|
||||
purchase_object_info="Оборудование",
|
||||
href="https://example.test/procurement",
|
||||
)
|
||||
],
|
||||
batch_id=50,
|
||||
region_code="77",
|
||||
data_year=2026,
|
||||
data_month=3,
|
||||
)
|
||||
|
||||
self.assertEqual(saved, 1)
|
||||
self.assertEqual(ProcurementRecord.objects.count(), 0)
|
||||
record = OrganizationSourceRecord.objects.get(
|
||||
source=ParserLoadLog.Source.PROCUREMENTS,
|
||||
external_id="PROC-DIRECT-1",
|
||||
)
|
||||
self.assertEqual(record.record_type, "procurement")
|
||||
self.assertEqual(record.amount, Decimal("1234567.89"))
|
||||
self.assertEqual(record.payload["publish_date_normalized"], "2026-03-01")
|
||||
self.assertEqual(record.payload["region_code"], "77")
|
||||
self.assertEqual(record.payload["data_month"], 3)
|
||||
|
||||
def test_generic_save_records_writes_organization_source_records(self):
|
||||
saved = GenericParserRecordService.save_records(
|
||||
[
|
||||
GenericParserItem(
|
||||
source=ParserLoadLog.Source.FAS_GOZ,
|
||||
external_id="fas-goz-1",
|
||||
inn="7707083803",
|
||||
ogrn="",
|
||||
organisation_name='ООО "ГОЗ"',
|
||||
title="Уклонение от ГОЗ",
|
||||
record_date="2026-05-18",
|
||||
amount=Decimal("12.30"),
|
||||
status="active",
|
||||
url="https://example.test/fas-goz-1",
|
||||
payload={"registry": "fas"},
|
||||
)
|
||||
],
|
||||
batch_id=51,
|
||||
source=ParserLoadLog.Source.FAS_GOZ,
|
||||
)
|
||||
|
||||
self.assertEqual(saved, 1)
|
||||
self.assertEqual(GenericParserRecord.objects.count(), 0)
|
||||
record = OrganizationSourceRecord.objects.get(
|
||||
source=ParserLoadLog.Source.FAS_GOZ,
|
||||
external_id="fas-goz-1",
|
||||
)
|
||||
self.assertEqual(record.title, "Уклонение от ГОЗ")
|
||||
self.assertEqual(record.payload["registry"], "fas")
|
||||
self.assertEqual(record.load_batch, 51)
|
||||
|
||||
def test_inspection_save_records_writes_organization_source_records(self):
|
||||
saved = InspectionService.save_inspections(
|
||||
[
|
||||
Inspection(
|
||||
registration_number="INSP-DIRECT-1",
|
||||
inn="7707083804",
|
||||
ogrn="1027700132004",
|
||||
organisation_name='ООО "Проверка"',
|
||||
control_authority="Контроль",
|
||||
inspection_type="Плановая",
|
||||
inspection_form="Документарная",
|
||||
start_date="01.03.2026",
|
||||
end_date="2026-03-15",
|
||||
status="planned",
|
||||
legal_basis="ФЗ",
|
||||
result="",
|
||||
)
|
||||
],
|
||||
batch_id=52,
|
||||
data_year=2026,
|
||||
data_month=3,
|
||||
)
|
||||
|
||||
self.assertEqual(saved, 1)
|
||||
self.assertEqual(InspectionRecord.objects.count(), 0)
|
||||
record = OrganizationSourceRecord.objects.get(
|
||||
source=ParserLoadLog.Source.INSPECTIONS,
|
||||
external_id="INSP-DIRECT-1",
|
||||
)
|
||||
self.assertEqual(record.record_type, "inspection")
|
||||
self.assertEqual(record.payload["control_authority"], "Контроль")
|
||||
self.assertEqual(record.payload["start_date_normalized"], "2026-03-01")
|
||||
self.assertEqual(record.payload["data_year"], 2026)
|
||||
self.assertEqual(record.payload["data_month"], 3)
|
||||
|
||||
def test_fns_save_report_writes_source_record_and_financial_lines(self):
|
||||
report = FNSReportService.save_report(
|
||||
external_id="fns-direct-1",
|
||||
ogrn="1027700132005",
|
||||
file_name="fin_001_1027700132005.xlsx",
|
||||
file_hash="b" * 64,
|
||||
source="file_watch",
|
||||
batch_id=53,
|
||||
lines_data=[
|
||||
{
|
||||
"form_code": "1",
|
||||
"line_code": "1600",
|
||||
"line_name": "Баланс",
|
||||
"year": 2025,
|
||||
"period_start": 100,
|
||||
"period_end": 200,
|
||||
}
|
||||
],
|
||||
)
|
||||
|
||||
self.assertEqual(FinancialReport.objects.count(), 0)
|
||||
self.assertEqual(str(report.external_id), "fns-direct-1")
|
||||
source_record = OrganizationSourceRecord.objects.get(
|
||||
source=ParserLoadLog.Source.FNS_REPORTS,
|
||||
external_id="fns-direct-1",
|
||||
)
|
||||
self.assertEqual(report.uid, source_record.uid)
|
||||
self.assertEqual(source_record.payload["file_hash"], "b" * 64)
|
||||
line = OrganizationSourceFinancialLine.objects.get(source_record=source_record)
|
||||
self.assertEqual(line.line_code, "1600")
|
||||
self.assertEqual(line.period_end, 200)
|
||||
|
||||
def test_fns_exists_by_hash_reads_source_record_payload(self):
|
||||
FNSReportService.save_report(
|
||||
external_id="fns-direct-2",
|
||||
ogrn="1027700132006",
|
||||
file_name="fin_002_1027700132006.xlsx",
|
||||
file_hash="c" * 64,
|
||||
source="file_watch",
|
||||
batch_id=54,
|
||||
lines_data=[
|
||||
ReportLine(
|
||||
form_code="2",
|
||||
line_code="2110",
|
||||
line_name="Выручка",
|
||||
year=2025,
|
||||
period_end=500,
|
||||
).__dict__
|
||||
],
|
||||
)
|
||||
|
||||
self.assertTrue(FNSReportService.exists_by_hash("c" * 64))
|
||||
self.assertTrue(FNSReportService.exists_by_external_id("fns-direct-2"))
|
||||
Reference in New Issue
Block a user