From 4e72abbe9a45cbe8dbf7fc646fa4fbe0c3380273 Mon Sep 17 00:00:00 2001 From: Aleksandr Meshchriakov Date: Tue, 18 Aug 2026 10:59:40 +0200 Subject: [PATCH] fix(source-cards): scope counters to OPK organizations --- src/apps/parsers/source_cards.py | 12 +++++-- .../apps/parsers/test_source_cards_service.py | 34 ++++++++++++++++++- tests/apps/parsers/test_source_cards_views.py | 6 +++- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/apps/parsers/source_cards.py b/src/apps/parsers/source_cards.py index b36f415..903e15a 100644 --- a/src/apps/parsers/source_cards.py +++ b/src/apps/parsers/source_cards.py @@ -34,6 +34,7 @@ ACTIVE_JOB_STATUSES = [JobStatus.PENDING, JobStatus.STARTED, JobStatus.RETRY] STALE_ACTIVE_MAX_AGE_MINUTES = 4 * 60 STALE_PENDING_MAX_AGE_MINUTES = 24 * 60 SOURCE_CARD_STATS_CACHE_TIMEOUT_SECONDS = 7 * 24 * 60 * 60 +SOURCE_CARD_STATS_CACHE_SCHEMA_VERSION = 2 @dataclass(frozen=True) @@ -665,7 +666,10 @@ class SourceCardService: version = get_source_data_cache_version() slugs = ",".join(definition.slug for definition in definitions) slugs_digest = blake2s(slugs.encode(), digest_size=8).hexdigest() - return f"parsers:source_cards:aggregate_stats:{version}:{slugs_digest}" + return ( + "parsers:source_cards:aggregate_stats:" + f"v{SOURCE_CARD_STATS_CACHE_SCHEMA_VERSION}:{version}:{slugs_digest}" + ) @classmethod def _build_item_stats_by_code( @@ -688,7 +692,10 @@ class SourceCardService: return {} rows = ( - OrganizationSourceRecord.objects.filter(source__in=unique_sources) + OrganizationSourceRecord.objects.filter( + source__in=unique_sources, + extension__organization__opk_registry_membership=True, + ) .order_by() .values("source") .annotate( @@ -762,6 +769,7 @@ class SourceCardService: rows = ( OrganizationSourceExtension.objects.filter( + organization__opk_registry_membership=True, source_group__in=source_groups, records_count__gt=0, ) diff --git a/tests/apps/parsers/test_source_cards_service.py b/tests/apps/parsers/test_source_cards_service.py index 3bfdf36..12d9c42 100644 --- a/tests/apps/parsers/test_source_cards_service.py +++ b/tests/apps/parsers/test_source_cards_service.py @@ -39,6 +39,7 @@ def _save_source_record( organization_name: str = "", title: str = "", payload: dict | None = None, + opk_registry_membership: bool = True, ) -> None: payload = dict(payload or {}) if inn: @@ -46,6 +47,7 @@ def _save_source_record( create_directory_organization( name=organization_name or title or external_id, inn=inn, + opk_registry_membership=opk_registry_membership, ) else: rn_key = organization_name or title or external_id @@ -53,7 +55,10 @@ def _save_source_record( payload.setdefault("rn", rn) get_or_create_directory_organization( rn=rn, - defaults={"name": organization_name or title or external_id}, + defaults={ + "name": organization_name or title or external_id, + "opk_registry_membership": opk_registry_membership, + }, ) OrganizationSourceIngestionService.save_records( source=source, @@ -441,6 +446,33 @@ class SourceCardServiceDatabaseTest(TestCase): def setUp(self): SourceCardService.clear_cache() + def test_source_card_counters_include_only_opk_organizations(self): + _save_source_record( + source=ParserLoadLog.Source.PROCUREMENTS_44FZ, + external_id="opk-notice", + inn="7701234567", + organization_name="Организация ОПК", + title="Закупка организации ОПК", + ) + _save_source_record( + source=ParserLoadLog.Source.PROCUREMENTS_44FZ, + external_id="non-opk-notice", + inn="7701234568", + organization_name="Организация вне ОПК", + title="Закупка организации вне ОПК", + opk_registry_membership=False, + ) + + card = SourceCardService.get_card("public-procurements") + + source_item = next( + item for item in card["source_items"] if item["code"] == "procurements_44fz" + ) + self.assertEqual(source_item["records_count"], 1) + self.assertEqual(source_item["organizations_count"], 1) + self.assertEqual(card["records_count"], 1) + self.assertEqual(card["organizations_count"], 1) + def test_enqueue_vacancy_refresh_reuses_fresh_active_job(self): existing = BackgroundJob.objects.create( task_id="active-vacancies", diff --git a/tests/apps/parsers/test_source_cards_views.py b/tests/apps/parsers/test_source_cards_views.py index aa7e966..79369bf 100644 --- a/tests/apps/parsers/test_source_cards_views.py +++ b/tests/apps/parsers/test_source_cards_views.py @@ -53,6 +53,7 @@ def _save_source_record( name=organization_name or title or external_id, inn=inn, ogrn=ogrn, + opk_registry_membership=True, ) else: rn_key = organization_name or title or external_id @@ -60,7 +61,10 @@ def _save_source_record( payload["rn"] = rn get_or_create_directory_organization( rn=rn, - defaults={"name": organization_name or title or external_id}, + defaults={ + "name": organization_name or title or external_id, + "opk_registry_membership": True, + }, ) OrganizationSourceIngestionService.save_records( source=source,