from __future__ import annotations from datetime import date from decimal import Decimal from urllib.parse import parse_qs, urlsplit from apps.parsers.clients.base import HTTPClientError from apps.parsers.clients.common.eis_registry import EisRegistryProcurementClient from apps.parsers.clients.common.schemas import GenericParserItem from django.test import SimpleTestCase def _record(*, external_id: str, inn: str, amount: str = "1") -> GenericParserItem: return GenericParserItem( source="procurements_44fz", external_id=external_id, inn=inn, organisation_name="Наименование из ЕИС", title="Закупка", amount=Decimal(amount), payload={"raw": external_id}, ) class _FakeHttpClient: def __init__(self, pages: dict[int, bytes], *, error_page: int | None = None): self.pages = pages self.error_page = error_page self.urls: list[str] = [] def download_file(self, url: str, **_kwargs) -> bytes: self.urls.append(url) page = int(parse_qs(urlsplit(url).query)["pageNumber"][0]) if page == self.error_page: raise HTTPClientError("page failed") return self.pages[page] class _FakeStructuredClient: def __init__(self, pages: dict[int, bytes], records: dict[bytes, list]): self.http_client = _FakeHttpClient(pages) self.records = records def fetch_records(self, *, content: bytes, file_name: str): assert file_name == "results.html" return self.records[content] class EisRegistryProcurementClientTest(SimpleTestCase): def test_fetches_all_pages_filters_inn_and_deduplicates_external_id(self): page_1 = b'' page_2 = b'' structured = _FakeStructuredClient( {1: page_1, 2: page_2}, { page_1: [ _record(external_id="same", inn="7701000001", amount="1"), _record(external_id="foreign", inn="7701000099"), ], page_2: [ _record(external_id="same", inn="7701000001", amount="2"), _record(external_id="other", inn="7701000001"), ], }, ) client = EisRegistryProcurementClient( source="procurements_44fz", law="44", _structured_client=structured, ) records = client.fetch_for_customer( inn="7701000001", organization_name="ОПК Заказчик", organization_id="org-1", today=date(2026, 7, 19), ) self.assertEqual([row.external_id for row in records], ["same", "other"]) self.assertEqual(records[0].amount, Decimal("2")) self.assertTrue(all(row.inn == "7701000001" for row in records)) self.assertEqual(records[0].payload["organization_id"], "org-1") query = parse_qs(urlsplit(structured.http_client.urls[0]).query) self.assertEqual(query["fz44"], ["on"]) self.assertEqual(query["strictEqual"], ["true"]) self.assertEqual(query["publishDateFrom"], ["19.07.2025"]) self.assertEqual(query["publishDateTo"], ["19.07.2026"]) def test_builds_223fz_query_and_accepts_empty_page(self): empty_page = b"" structured = _FakeStructuredClient({1: empty_page}, {empty_page: []}) client = EisRegistryProcurementClient( source="procurements_223fz", law="223", _structured_client=structured, ) records = client.fetch_for_customer( inn="7701000001", organization_name="ОПК Заказчик", organization_id="org-1", ) self.assertEqual(records, []) query = parse_qs(urlsplit(structured.http_client.urls[0]).query) self.assertEqual(query["fz223"], ["on"]) self.assertNotIn("fz44", query) def test_page_error_is_not_silenced(self): page_1 = b'' structured = _FakeStructuredClient({1: page_1}, {page_1: []}) structured.http_client.error_page = 2 client = EisRegistryProcurementClient( source="procurements_44fz", law="44", _structured_client=structured, ) with self.assertRaises(HTTPClientError): client.fetch_for_customer( inn="7701000001", organization_name="ОПК Заказчик", organization_id="org-1", )