feat(parsers): implement arbitration and upload fixes
This commit is contained in:
@@ -31,6 +31,7 @@ from apps.parsers.clients.proverki.client import ProverkiClientError
|
||||
from apps.parsers.clients.zakupki import ZakupkiClientError
|
||||
from apps.parsers.models import (
|
||||
FinancialReport,
|
||||
GenericParserRecord,
|
||||
IndustrialCertificateRecord,
|
||||
IndustrialProductRecord,
|
||||
InspectionRecord,
|
||||
@@ -66,6 +67,7 @@ from registers.models import Organization
|
||||
|
||||
from tests.apps.parsers.factories import (
|
||||
InspectionRecordFactory,
|
||||
ManufacturerRecordFactory,
|
||||
ParserLoadLogFactory,
|
||||
ProcurementRecordFactory,
|
||||
ProxyFactory,
|
||||
@@ -246,6 +248,124 @@ class GenericSourceFetchTestCase(TestCase):
|
||||
self.assertEqual(records[0].record_date, "2026-04-01")
|
||||
self.assertEqual(records[0].payload["provider"], "checko")
|
||||
|
||||
@override_settings(CHECKO_API_KEY="test-key", ARBITRATION_CHECKO_LIMIT=10)
|
||||
def test_arbitration_fetches_checko_legal_cases_for_registry_organizations(self):
|
||||
organization = Organization.objects.create(
|
||||
pn_name='ООО "Арбитраж"',
|
||||
mn_ogrn=1027700000001,
|
||||
mn_inn=7701000002,
|
||||
in_kpp=770101001,
|
||||
mn_okpo="12345678",
|
||||
)
|
||||
|
||||
class _CheckoClient:
|
||||
instances = []
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.kwargs = kwargs
|
||||
self.requests = []
|
||||
self.instances.append(self)
|
||||
|
||||
def iter_legal_cases(self, request):
|
||||
self.requests.append(request)
|
||||
return iter(
|
||||
[
|
||||
SimpleNamespace(
|
||||
case_number="А40-1/2026",
|
||||
court_name="АС города Москвы",
|
||||
type="civil",
|
||||
category="Взыскание задолженности",
|
||||
status="Рассмотрено",
|
||||
filing_date="2026-04-01",
|
||||
result_date="2026-04-20",
|
||||
claim_amount=150000,
|
||||
awarded_amount=100000,
|
||||
plaintiffs=(
|
||||
SimpleNamespace(
|
||||
name=organization.pn_name,
|
||||
inn=str(organization.mn_inn),
|
||||
ogrn=str(organization.mn_ogrn),
|
||||
role="plaintiff",
|
||||
),
|
||||
),
|
||||
defendants=(),
|
||||
third_parties=(),
|
||||
instances=(),
|
||||
url="https://kad.arbitr.ru/Card/1",
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
with patch.object(parser_tasks, "CheckoClient", _CheckoClient):
|
||||
result = parser_tasks.parse_arbitration_cases(limit=10, proxies=[])
|
||||
|
||||
self.assertEqual(result["status"], "success")
|
||||
self.assertEqual(result["saved"], 1)
|
||||
record = GenericParserRecord.objects.get(
|
||||
source=ParserLoadLog.Source.ARBITRATION
|
||||
)
|
||||
self.assertEqual(record.registry_organization_id, organization.id)
|
||||
self.assertEqual(record.inn, str(organization.mn_inn))
|
||||
self.assertEqual(record.ogrn, str(organization.mn_ogrn))
|
||||
self.assertEqual(record.amount, 150000)
|
||||
self.assertEqual(record.payload["provider"], "checko")
|
||||
self.assertEqual(record.payload["target"]["role"], "plaintiff")
|
||||
self.assertEqual(_CheckoClient.instances[0].requests[0].inn, record.inn)
|
||||
|
||||
@override_settings(CHECKO_API_KEY="test-key")
|
||||
def test_arbitration_uses_loaded_parser_identifiers_when_registry_empty(self):
|
||||
manufacturer = ManufacturerRecordFactory(
|
||||
inn="7701000003",
|
||||
ogrn="1027700000002",
|
||||
full_legal_name='ООО "Источник"',
|
||||
)
|
||||
|
||||
class _CheckoClient:
|
||||
def __init__(self, **_kwargs):
|
||||
return
|
||||
|
||||
def iter_legal_cases(self, request):
|
||||
self.request = request
|
||||
return iter(
|
||||
[
|
||||
SimpleNamespace(
|
||||
case_number="А40-2/2026",
|
||||
court_name="АС города Москвы",
|
||||
type=None,
|
||||
category=None,
|
||||
status="Принято",
|
||||
filing_date="2026-04-02",
|
||||
result_date=None,
|
||||
claim_amount=None,
|
||||
awarded_amount=None,
|
||||
plaintiffs=(),
|
||||
defendants=(
|
||||
SimpleNamespace(
|
||||
name=manufacturer.full_legal_name,
|
||||
inn=manufacturer.inn,
|
||||
ogrn=manufacturer.ogrn,
|
||||
role="defendant",
|
||||
),
|
||||
),
|
||||
third_parties=(),
|
||||
instances=(),
|
||||
url="https://kad.arbitr.ru/Card/2",
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
with patch.object(parser_tasks, "CheckoClient", _CheckoClient):
|
||||
records = parser_tasks._fetch_checko_arbitration_records(
|
||||
limit=1,
|
||||
proxies=[],
|
||||
)
|
||||
|
||||
self.assertEqual(len(records), 1)
|
||||
self.assertEqual(records[0].source, "arbitration")
|
||||
self.assertEqual(records[0].inn, manufacturer.inn)
|
||||
self.assertEqual(records[0].ogrn, manufacturer.ogrn)
|
||||
self.assertEqual(records[0].payload["target"]["role"], "defendant")
|
||||
|
||||
@override_settings(CHECKO_API_KEY="")
|
||||
def test_fedresurs_skips_when_official_blocked_and_fallback_empty(self):
|
||||
with patch.object(
|
||||
|
||||
@@ -5,6 +5,7 @@ from __future__ import annotations
|
||||
import io
|
||||
import os
|
||||
import tempfile
|
||||
import zipfile
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
from apps.parsers.models import (
|
||||
@@ -50,6 +51,14 @@ def _build_fns_excel_bytes() -> bytes:
|
||||
return buf.getvalue()
|
||||
|
||||
|
||||
def _build_fns_zip_bytes(file_map: dict[str, bytes]) -> bytes:
|
||||
buf = io.BytesIO()
|
||||
with zipfile.ZipFile(buf, "w", compression=zipfile.ZIP_DEFLATED) as archive:
|
||||
for file_name, content in file_map.items():
|
||||
archive.writestr(file_name, content)
|
||||
return buf.getvalue()
|
||||
|
||||
|
||||
def _create_procurement_record() -> ProcurementRecord:
|
||||
return ProcurementRecord.objects.create(
|
||||
load_batch=fake.random_int(min=1, max=1000),
|
||||
@@ -411,6 +420,34 @@ class ParsersViewSetTest(APITestCase):
|
||||
self.assertEqual(response.data["success"], True)
|
||||
self.assertIn("message", response.data)
|
||||
|
||||
def test_fns_upload_accepts_zip_payload(self):
|
||||
self.client.force_authenticate(self.admin)
|
||||
external_id = _digits(5)
|
||||
ogrn = _digits(13)
|
||||
filename = f"fin_{external_id}_{ogrn}.xlsx"
|
||||
upload = SimpleUploadedFile(
|
||||
"fns_reports.zip",
|
||||
_build_fns_zip_bytes({filename: _build_fns_excel_bytes()}),
|
||||
content_type="application/zip",
|
||||
)
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
watch_dir = os.path.join(tmpdir, "watch")
|
||||
processed_dir = os.path.join(tmpdir, "processed")
|
||||
failed_dir = os.path.join(tmpdir, "failed")
|
||||
with self.settings(
|
||||
FNS_WATCH_DIRECTORY=watch_dir,
|
||||
FNS_PROCESSED_DIRECTORY=processed_dir,
|
||||
FNS_FAILED_DIRECTORY=failed_dir,
|
||||
):
|
||||
url = reverse("api_v1:fns:fns-upload")
|
||||
response = self.client.post(url, {"file": upload}, format="multipart")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_202_ACCEPTED)
|
||||
self.assertEqual(response.data["queued"], 1)
|
||||
self.assertEqual(response.data["skipped"], 0)
|
||||
self.assertEqual(response.data["invalid"], 0)
|
||||
self.assertEqual(FinancialReport.objects.count(), 1)
|
||||
|
||||
def test_parsing_settings_get_and_patch(self):
|
||||
self.client.force_authenticate(self.admin)
|
||||
url = reverse("api_v1:parsing:parsing-settings")
|
||||
|
||||
Reference in New Issue
Block a user