feat: import mostovik exchange sections
All checks were successful
CI/CD Pipeline / Run Tests (push) Successful in 6m12s
CI/CD Pipeline / Code Quality Checks (push) Successful in 6m19s
CI/CD Pipeline / Build Docker Images (push) Successful in 2m21s
CI/CD Pipeline / Push to Gitea Registry (push) Successful in 1s
CI/CD Pipeline / Deploy to Server (push) Successful in 1s

This commit is contained in:
2026-05-27 23:13:40 +02:00
parent bd8e1a8400
commit d1b0cd7945
49 changed files with 1831 additions and 319 deletions

View File

@@ -18,9 +18,13 @@ from apps.external_data.models import (
ArbitrationCase,
BankruptcyProcedure,
DefenseUnreliableSupplier,
FinancialReport,
FinancialReportLine,
IndustrialCertificate,
IndustrialProduct,
InformationSecurityRegistryEntry,
LaborVacancy,
ManufacturerRegistryEntry,
ProsecutorCheck,
PublicProcurement,
)
@@ -164,6 +168,26 @@ def build_exchange_payload() -> dict[str, list[dict[str, object]]]:
"registry_number": "prod-001",
}
],
"industrial_certificates": [
{
"organization_inn": "7707083893",
"certificate_number": "CERT-001",
"issue_date": "2026-01-10",
"expiry_date": "2027-01-10",
"certificate_file_url": "https://minpromtorg.gov.ru/cert/001",
"organisation_name": "АО Альфа Обновленная",
"ogrn": "1027700132195",
}
],
"manufacturers": [
{
"organization_inn": "7707083893",
"full_legal_name": "АО Альфа Обновленная",
"inn": "7707083893",
"ogrn": "1027700132195",
"address": "г. Москва, ул. Тверская, д. 1",
}
],
"prosecutor_checks": [
{
"organization_inn": "7707083893",
@@ -188,6 +212,28 @@ def build_exchange_payload() -> dict[str, list[dict[str, object]]]:
"purchase_name": "Поставка специализированного оборудования",
}
],
"financial_reports": [
{
"organization_inn": "7707083893",
"external_id": "fin-001",
"ogrn": "1027700132195",
"file_name": "fin_001_1027700132195.xlsx",
"file_hash": "f" * 64,
"load_batch": 7,
"status": "success",
"source": "api",
"lines": [
{
"form_code": "1",
"line_code": "1600",
"line_name": "Баланс",
"year": 2025,
"period_start": 1000,
"period_end": 1500,
}
],
}
],
"arbitration_cases": [
{
"organization_inn": "7707083893",
@@ -281,9 +327,13 @@ class ExchangePackageApiTest(APITestCase):
self.assertEqual(response.data["result"]["organizations"]["created"], 1)
self.assertEqual(response.data["result"]["organizations"]["updated"], 1)
self.assertEqual(Organization.objects.count(), 2)
self.assertEqual(IndustrialCertificate.objects.count(), 1)
self.assertEqual(ManufacturerRegistryEntry.objects.count(), 1)
self.assertEqual(IndustrialProduct.objects.count(), 1)
self.assertEqual(ProsecutorCheck.objects.count(), 1)
self.assertEqual(PublicProcurement.objects.count(), 1)
self.assertEqual(FinancialReport.objects.count(), 1)
self.assertEqual(FinancialReportLine.objects.count(), 1)
self.assertEqual(ArbitrationCase.objects.count(), 1)
self.assertEqual(BankruptcyProcedure.objects.count(), 1)
self.assertEqual(DefenseUnreliableSupplier.objects.count(), 1)
@@ -293,6 +343,10 @@ class ExchangePackageApiTest(APITestCase):
response.data["result"]["bankruptcy_procedures"]["created"],
1,
)
self.assertEqual(
response.data["result"]["financial_reports"]["created_lines"],
1,
)
self.assertEqual(
response.data["result"]["defense_unreliable_suppliers"]["created"],
1,
@@ -332,6 +386,43 @@ class ExchangePackageApiTest(APITestCase):
self.assertEqual(ExchangePackageImport.objects.count(), 0)
self.assertEqual(Organization.objects.count(), 0)
def test_upload_rejects_external_rows_for_organization_absent_from_package(self):
Organization.objects.create(
inn="7707083893",
name="АО Альфа",
ogrn="1027700132195",
kpp="770701001",
)
archive = build_exchange_archive(
package_id="pkg-missing-package-organization",
data={
"organizations": [],
"industrial_products": [
{
"organization_inn": "7707083893",
"product_name": "Система связи М-1",
"registry_number": "prod-001",
}
],
},
)
response = self.client.post(
self.url,
{"file": archive},
format="multipart",
HTTP_X_EXCHANGE_TOKEN=TEST_TOKEN,
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertIn("отсутствует в разделе organizations", response.data["file"][0])
self.assertEqual(Organization.objects.count(), 1)
self.assertEqual(IndustrialProduct.objects.count(), 0)
package_import = ExchangePackageImport.objects.get(
package_id="pkg-missing-package-organization"
)
self.assertEqual(package_import.status, "failed")
def test_upload_is_idempotent_for_duplicate_package(self):
archive = build_exchange_archive(
package_id="pkg-duplicate-001",