feat: expand platform APIs, sources, and test coverage
Some checks failed
CI/CD Pipeline / Run Tests (pull_request) Successful in 1m53s
CI/CD Pipeline / Telegram Notify Success (push) Has been cancelled
CI/CD Pipeline / Run Tests (push) Has been cancelled
CI/CD Pipeline / Code Quality Checks (push) Has been cancelled
CI/CD Pipeline / Code Quality Checks (pull_request) Failing after 2m54s
CI/CD Pipeline / Telegram Notify Success (pull_request) Has been skipped

This commit is contained in:
2026-03-17 12:56:48 +01:00
parent b505c67968
commit 3d298ce352
101 changed files with 8387 additions and 292 deletions

View File

@@ -20,11 +20,16 @@ from apps.parsers.clients.minpromtorg.manufactures import (
ManufacturesClient,
ManufacturesClientError,
)
from apps.parsers.clients.minpromtorg.products import (
IndustrialProductsClient,
IndustrialProductsClientError,
)
from apps.parsers.clients.proverki.client import ProverkiClientError
from apps.parsers.clients.zakupki import ZakupkiClientError
from apps.parsers.models import (
FinancialReport,
IndustrialCertificateRecord,
IndustrialProductRecord,
InspectionRecord,
ManufacturerRecord,
ParserLoadLog,
@@ -38,6 +43,7 @@ from apps.parsers.tasks import (
parse_all_minpromtorg,
parse_all_sources,
parse_industrial_production,
parse_industrial_products,
parse_inspections,
parse_manufactures,
parse_procurements,
@@ -58,6 +64,7 @@ from tests.utils import TestHTTPServer
from tests.utils.fixtures import (
build_minpromtorg_certificates_excel,
build_minpromtorg_manufacturers_excel,
build_minpromtorg_products_excel,
build_proverki_xml,
build_zakupki_xml,
build_zip,
@@ -360,12 +367,14 @@ class MinpromtorgTasksTestCase(TestCase):
def _add_minpromtorg_routes(self, server: TestHTTPServer):
certificates_bytes, cert_rows = build_minpromtorg_certificates_excel(count=2)
manufacturers_bytes, manuf_rows = build_minpromtorg_manufacturers_excel(count=2)
products_bytes, product_rows = build_minpromtorg_products_excel(count=2)
date_str = fake.date_between(start_date="-30d", end_date="today").strftime(
"%Y%m%d"
)
cert_file = f"data_resolutions_{date_str}.xlsx"
manuf_file = f"data_orgs_{date_str}.xlsx"
products_file = f"industrial_products_{date_str}.xlsx"
server.add_json(
"/api/kss-document-preview",
@@ -379,6 +388,15 @@ class MinpromtorgTasksTestCase(TestCase):
"name": ManufacturesClient().query,
"files": [{"name": manuf_file, "url": f"/files/{manuf_file}"}],
},
{
"name": IndustrialProductsClient().query,
"files": [
{
"name": products_file,
"url": f"/files/{products_file}",
}
],
},
]
},
)
@@ -396,24 +414,33 @@ class MinpromtorgTasksTestCase(TestCase):
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
),
)
return cert_rows, manuf_rows
server.add_bytes(
f"/files/{products_file}",
products_bytes,
content_type=(
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
),
)
return cert_rows, product_rows, manuf_rows
def test_parse_all_minpromtorg_success(self):
with TestHTTPServer() as server:
cert_rows, manuf_rows = self._add_minpromtorg_routes(server)
cert_rows, product_rows, manuf_rows = self._add_minpromtorg_routes(server)
result = parse_all_minpromtorg(
proxies=[],
client_adapter=server.adapter,
)
self.assertIn("industrial", result)
self.assertIn("industrial_products", result)
self.assertIn("manufactures", result)
self.assertEqual(IndustrialCertificateRecord.objects.count(), len(cert_rows))
self.assertEqual(IndustrialProductRecord.objects.count(), len(product_rows))
self.assertEqual(ManufacturerRecord.objects.count(), len(manuf_rows))
def test_parse_all_sources_success(self):
with TestHTTPServer() as server:
cert_rows, manuf_rows = self._add_minpromtorg_routes(server)
cert_rows, product_rows, manuf_rows = self._add_minpromtorg_routes(server)
result = parse_all_sources(
proxies=[],
client_adapter=server.adapter,
@@ -421,31 +448,43 @@ class MinpromtorgTasksTestCase(TestCase):
)
self.assertIn("industrial", result)
self.assertIn("industrial_products", result)
self.assertIn("manufactures", result)
self.assertIn("inspections", result)
self.assertEqual(IndustrialCertificateRecord.objects.count(), len(cert_rows))
self.assertEqual(IndustrialProductRecord.objects.count(), len(product_rows))
self.assertEqual(ManufacturerRecord.objects.count(), len(manuf_rows))
self.assertEqual(InspectionRecord.objects.count(), 0)
def test_parse_all_minpromtorg_without_adapter(self):
with TestHTTPServer() as server:
cert_rows, manuf_rows = self._add_minpromtorg_routes(server)
cert_rows, product_rows, manuf_rows = self._add_minpromtorg_routes(server)
class _LocalIndustrialClient(IndustrialProductionClient):
def __init__(self, *args, **kwargs):
kwargs.setdefault("http_adapter", server.adapter)
super().__init__(*args, **kwargs)
class _LocalIndustrialProductsClient(IndustrialProductsClient):
def __init__(self, *args, **kwargs):
kwargs.setdefault("http_adapter", server.adapter)
super().__init__(*args, **kwargs)
class _LocalManufacturesClient(ManufacturesClient):
def __init__(self, *args, **kwargs):
kwargs.setdefault("http_adapter", server.adapter)
super().__init__(*args, **kwargs)
original_industrial = parser_tasks.IndustrialProductionClient
original_industrial_products = parser_tasks.IndustrialProductsClient
original_manufactures = parser_tasks.ManufacturesClient
original_industrial_delay = parser_tasks.parse_industrial_production.delay
original_industrial_products_delay = (
parser_tasks.parse_industrial_products.delay
)
original_manufactures_delay = parser_tasks.parse_manufactures.delay
parser_tasks.IndustrialProductionClient = _LocalIndustrialClient
parser_tasks.IndustrialProductsClient = _LocalIndustrialProductsClient
parser_tasks.ManufacturesClient = _LocalManufacturesClient
def _industrial_eager_delay(*args, **kwargs):
@@ -454,6 +493,12 @@ class MinpromtorgTasksTestCase(TestCase):
kwargs=kwargs,
)
def _industrial_products_eager_delay(*args, **kwargs):
return parser_tasks.parse_industrial_products.apply(
args=args,
kwargs=kwargs,
)
def _manufactures_eager_delay(*args, **kwargs):
return parser_tasks.parse_manufactures.apply(
args=args,
@@ -461,42 +506,61 @@ class MinpromtorgTasksTestCase(TestCase):
)
parser_tasks.parse_industrial_production.delay = _industrial_eager_delay
parser_tasks.parse_industrial_products.delay = (
_industrial_products_eager_delay
)
parser_tasks.parse_manufactures.delay = _manufactures_eager_delay
try:
result = parse_all_minpromtorg(proxies=[])
finally:
parser_tasks.IndustrialProductionClient = original_industrial
parser_tasks.IndustrialProductsClient = original_industrial_products
parser_tasks.ManufacturesClient = original_manufactures
parser_tasks.parse_industrial_production.delay = (
original_industrial_delay
)
parser_tasks.parse_industrial_products.delay = (
original_industrial_products_delay
)
parser_tasks.parse_manufactures.delay = original_manufactures_delay
self.assertIn("industrial", result)
self.assertIn("industrial_products", result)
self.assertIn("manufactures", result)
self.assertEqual(IndustrialCertificateRecord.objects.count(), len(cert_rows))
self.assertEqual(IndustrialProductRecord.objects.count(), len(product_rows))
self.assertEqual(ManufacturerRecord.objects.count(), len(manuf_rows))
def test_parse_all_sources_without_adapter(self):
with TestHTTPServer() as server:
cert_rows, manuf_rows = self._add_minpromtorg_routes(server)
cert_rows, product_rows, manuf_rows = self._add_minpromtorg_routes(server)
class _LocalIndustrialClient(IndustrialProductionClient):
def __init__(self, *args, **kwargs):
kwargs.setdefault("http_adapter", server.adapter)
super().__init__(*args, **kwargs)
class _LocalIndustrialProductsClient(IndustrialProductsClient):
def __init__(self, *args, **kwargs):
kwargs.setdefault("http_adapter", server.adapter)
super().__init__(*args, **kwargs)
class _LocalManufacturesClient(ManufacturesClient):
def __init__(self, *args, **kwargs):
kwargs.setdefault("http_adapter", server.adapter)
super().__init__(*args, **kwargs)
original_industrial = parser_tasks.IndustrialProductionClient
original_industrial_products = parser_tasks.IndustrialProductsClient
original_manufactures = parser_tasks.ManufacturesClient
original_industrial_delay = parser_tasks.parse_industrial_production.delay
original_industrial_products_delay = (
parser_tasks.parse_industrial_products.delay
)
original_manufactures_delay = parser_tasks.parse_manufactures.delay
original_inspections_delay = parser_tasks.parse_inspections.delay
parser_tasks.IndustrialProductionClient = _LocalIndustrialClient
parser_tasks.IndustrialProductsClient = _LocalIndustrialProductsClient
parser_tasks.ManufacturesClient = _LocalManufacturesClient
def _industrial_eager_delay(*args, **kwargs):
@@ -505,6 +569,12 @@ class MinpromtorgTasksTestCase(TestCase):
kwargs=kwargs,
)
def _industrial_products_eager_delay(*args, **kwargs):
return parser_tasks.parse_industrial_products.apply(
args=args,
kwargs=kwargs,
)
def _manufactures_eager_delay(*args, **kwargs):
return parser_tasks.parse_manufactures.apply(
args=args,
@@ -515,23 +585,32 @@ class MinpromtorgTasksTestCase(TestCase):
return SimpleNamespace(id="inspections-test-task")
parser_tasks.parse_industrial_production.delay = _industrial_eager_delay
parser_tasks.parse_industrial_products.delay = (
_industrial_products_eager_delay
)
parser_tasks.parse_manufactures.delay = _manufactures_eager_delay
parser_tasks.parse_inspections.delay = _inspections_stub_delay
try:
result = parse_all_sources(proxies=[], inspections_use_playwright=None)
finally:
parser_tasks.IndustrialProductionClient = original_industrial
parser_tasks.IndustrialProductsClient = original_industrial_products
parser_tasks.ManufacturesClient = original_manufactures
parser_tasks.parse_industrial_production.delay = (
original_industrial_delay
)
parser_tasks.parse_industrial_products.delay = (
original_industrial_products_delay
)
parser_tasks.parse_manufactures.delay = original_manufactures_delay
parser_tasks.parse_inspections.delay = original_inspections_delay
self.assertIn("industrial", result)
self.assertIn("industrial_products", result)
self.assertIn("manufactures", result)
self.assertIn("inspections", result)
self.assertEqual(IndustrialCertificateRecord.objects.count(), len(cert_rows))
self.assertEqual(IndustrialProductRecord.objects.count(), len(product_rows))
self.assertEqual(ManufacturerRecord.objects.count(), len(manuf_rows))
def test_parse_industrial_production_failure(self):
@@ -563,12 +642,47 @@ class MinpromtorgTasksTestCase(TestCase):
def test_parse_industrial_production_with_default_proxies(self):
with TestHTTPServer() as server:
cert_rows, _manuf_rows = self._add_minpromtorg_routes(server)
cert_rows, _product_rows, _manuf_rows = self._add_minpromtorg_routes(server)
result = parse_industrial_production(client_adapter=server.adapter)
self.assertEqual(result["status"], "success")
self.assertEqual(IndustrialCertificateRecord.objects.count(), len(cert_rows))
def test_parse_industrial_products_failure(self):
date_str = fake.date_between(start_date="-30d", end_date="today").strftime(
"%Y%m%d"
)
products_file = f"industrial_products_{date_str}.xlsx"
with TestHTTPServer() as server:
server.add_json(
"/api/kss-document-preview",
{
"data": [
{
"name": IndustrialProductsClient().query,
"files": [
{
"name": products_file,
"url": f"/files/{products_file}",
}
],
}
]
},
)
server.add_bytes("/files/" + products_file, b"not-an-excel")
with self.assertRaises(IndustrialProductsClientError):
parse_industrial_products(client_adapter=server.adapter)
def test_parse_industrial_products_with_default_proxies(self):
with TestHTTPServer() as server:
_cert_rows, product_rows, _manuf_rows = self._add_minpromtorg_routes(server)
result = parse_industrial_products(client_adapter=server.adapter)
self.assertEqual(result["status"], "success")
self.assertEqual(IndustrialProductRecord.objects.count(), len(product_rows))
def test_parse_manufactures_failure(self):
date_str = fake.date_between(start_date="-30d", end_date="today").strftime(
"%Y%m%d"