Add organizations v2 API and registry enrichment
All checks were successful
CI/CD Pipeline / Quality Gate (push) Successful in 26s
CI/CD Pipeline / Build and Push Images (push) Successful in 6s
CI/CD Pipeline / Internal Notify (push) Successful in 0s
CI/CD Pipeline / Deploy Dev in Dokploy (push) Successful in 1s

This commit is contained in:
2026-05-06 19:04:46 +02:00
parent f54aa4cb0b
commit 0f17ff6773
62 changed files with 10311 additions and 430 deletions

View File

@@ -0,0 +1,921 @@
"""Tests for organizations API v2."""
from apps.parsers.models import (
FinancialReport,
FinancialReportLine,
GenericParserRecord,
ParserLoadLog,
)
from django.core.cache import cache
from django.db import connection
from django.test import override_settings
from django.test.utils import CaptureQueriesContext
from django.urls import reverse
from organizations.models import Organization
from organizations.services import OrganizationDataSnapshotRefreshService
from rest_framework import status
from rest_framework.test import APITestCase
from tests.apps.parsers.factories import (
IndustrialCertificateRecordFactory,
IndustrialProductRecordFactory,
InspectionRecordFactory,
ManufacturerRecordFactory,
ProcurementRecordFactory,
)
from tests.apps.registers.factories import (
OrganizationFactory as RegistryOrganizationFactory,
)
from tests.apps.registers.factories import (
RegisterFactory,
RegistryMembershipPeriodFactory,
)
from tests.apps.user.factories import UserFactory
class OrganizationsApiV2Test(APITestCase):
"""Checks v2 canonical organizations endpoints."""
def setUp(self):
cache.clear()
self.user = UserFactory.create_user()
self.client.force_authenticate(self.user)
def test_list_is_paginated_and_available_only_under_v2(self):
Organization.objects.create(
name='ООО "Альфа"',
inn="7707083893",
kpp="770701001",
ogrn="1027700132195",
)
Organization.objects.create(
name="ИП Иванов Иван Иванович",
inn="500100732259",
ogrip="304500116000157",
)
response = self.client.get(
reverse("api_v2:organizations:organizations-list"),
{"page_size": 1, "has_registry": "false"},
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["success"], True)
self.assertEqual(len(response.data["data"]), 1)
self.assertEqual(response.data["meta"]["pagination"]["total_count"], 2)
self.assertEqual(response.data["meta"]["pagination"]["page_size"], 1)
v1_response = self.client.get("/api/v1/organizations/")
self.assertEqual(v1_response.status_code, status.HTTP_404_NOT_FOUND)
def test_openapi_documents_v2_organizations_endpoints(self):
response = self.client.get(
reverse("schema-swagger-ui"),
{"format": "openapi"},
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
paths = response.data["paths"]
list_operation = paths["/api/v2/organizations/"]["get"]
detail_operation = paths["/api/v2/organizations/{uid}/"]["get"]
self.assertEqual(list_operation["tags"], ["Организации"])
self.assertEqual(detail_operation["tags"], ["Организации"])
self.assertEqual(
list_operation["operationId"],
"v2_organizations_list",
)
self.assertEqual(
detail_operation["operationId"],
"v2_organizations_retrieve",
)
list_parameters = {
parameter["name"]: parameter for parameter in list_operation["parameters"]
}
for expected_name in (
"page",
"page_size",
"search",
"ordering",
"registry",
"has_registry",
"has_fns_reports",
"data",
"exclude_data",
):
self.assertIn(expected_name, list_parameters)
self.assertIn("по умолчанию true", list_parameters["has_registry"]["description"])
self.assertIn(
"industrial_products",
list_parameters["data"]["description"],
)
detail_parameters = {
parameter["name"]: parameter
for parameter in detail_operation["parameters"]
}
self.assertEqual(detail_parameters["uid"]["type"], "string")
self.assertEqual(detail_parameters["uid"]["format"], "uuid")
self.assertIn("data", detail_parameters)
self.assertIn("exclude_data", detail_parameters)
self.assertIn("Пагинированный", list_operation["responses"]["200"]["description"])
self.assertIn(
"Карточка организации",
detail_operation["responses"]["200"]["description"],
)
def test_retrieve_returns_item_by_uid(self):
organization = Organization.objects.create(
name='ООО "Ромашка"',
inn="7712345678",
kpp="771201001",
ogrn="1027700132196",
)
response = self.client.get(
reverse("api_v2:organizations:organizations-detail", args=[organization.uid])
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["uid"], str(organization.uid))
self.assertEqual(response.data["name"], 'ООО "Ромашка"')
def test_response_includes_normalized_name(self):
organization = Organization.objects.create(
name='АКЦИОНЕРНОЕ ОБЩЕСТВО "СЕВЕРНЫЙ МОСТ"',
inn="7712345679",
kpp="771201002",
ogrn="1027700132197",
)
response = self.client.get(
reverse("api_v2:organizations:organizations-detail", args=[organization.uid])
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["name"], 'АКЦИОНЕРНОЕ ОБЩЕСТВО "СЕВЕРНЫЙ МОСТ"')
self.assertEqual(response.data["normalized_name"], 'АО "Северный Мост"')
def test_list_keeps_data_source_summary_when_data_payload_is_excluded(self):
organization = Organization.objects.create(
name='ООО "Сводка данных"',
inn="7712345681",
kpp="771201004",
ogrn="1027700132199",
)
IndustrialCertificateRecordFactory(
inn=organization.inn,
ogrn=organization.ogrn,
)
OrganizationDataSnapshotRefreshService.refresh(
organization_uids=[str(organization.uid)]
)
response = self.client.get(
reverse("api_v2:organizations:organizations-list"),
{
"inn": organization.inn,
"has_registry": "false",
"exclude_data": (
"industrial,industrial_products,manufactures,inspections,"
"procurements,procurements_44fz,procurements_223fz,contracts,"
"unfair_suppliers,fas_goz,arbitration,fedresurs_bankruptcy,"
"fstec,vacancies,fns_reports"
),
},
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
item = response.data["data"][0]
self.assertEqual(item["data"], {})
self.assertEqual(
item["data_sources"],
[{"source": "industrial", "count": 1}],
)
def test_normalized_name_compacts_scientific_production_forms(self):
organization = Organization.objects.create(
name='Научно-Производственное Предприятие "ИМПУЛЬС"',
inn="7712345680",
kpp="771201003",
ogrn="1027700132198",
)
response = self.client.get(
reverse("api_v2:organizations:organizations-detail", args=[organization.uid])
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["normalized_name"], 'НПП "Импульс"')
def test_list_filters_by_identifiers_and_searches_by_name(self):
target = Organization.objects.create(
name='ООО "Северный мост"',
inn="7711111111",
kpp="771101001",
ogrn="1027700132111",
)
Organization.objects.create(
name='АО "Южный путь"',
inn="7722222222",
kpp="772201001",
ogrn="1027700132222",
)
by_inn = self.client.get(
reverse("api_v2:organizations:organizations-list"),
{"inn": target.inn, "has_registry": "false"},
)
by_search = self.client.get(
reverse("api_v2:organizations:organizations-list"),
{"search": "мост", "has_registry": "false"},
)
self.assertEqual(by_inn.status_code, status.HTTP_200_OK)
self.assertEqual(by_inn.data["meta"]["pagination"]["total_count"], 1)
self.assertEqual(by_inn.data["data"][0]["uid"], str(target.uid))
self.assertEqual(by_search.status_code, status.HTTP_200_OK)
self.assertEqual(by_search.data["meta"]["pagination"]["total_count"], 1)
self.assertEqual(by_search.data["data"][0]["uid"], str(target.uid))
def test_list_searches_by_identifier_fragments_for_dashboard(self):
target = Organization.objects.create(
name='ООО "Поиск по реквизитам"',
inn="7711111122",
kpp="771102222",
ogrn="1027700132122",
)
Organization.objects.create(
name='ООО "Другая организация"',
inn="7722222233",
kpp="772203333",
ogrn="1027700132233",
)
url = reverse("api_v2:organizations:organizations-list")
for search_value in ("111122", "1027700132122", "102222"):
with self.subTest(search_value=search_value):
response = self.client.get(
url,
{"search": search_value, "has_registry": "false"},
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["meta"]["pagination"]["total_count"], 1)
self.assertEqual(response.data["data"][0]["uid"], str(target.uid))
def test_list_response_is_cached_by_query_string(self):
Organization.objects.create(
name='ООО "Кеш"',
inn="7733333333",
kpp="773301001",
ogrn="1027700132333",
)
url = reverse("api_v2:organizations:organizations-list")
first_response = self.client.get(
url,
{"inn": "7733333333", "has_registry": "false"},
)
Organization.objects.create(
name='ООО "После кеша"',
inn="7744444444",
kpp="774401001",
ogrn="1027700132444",
)
second_response = self.client.get(
url,
{"inn": "7733333333", "has_registry": "false"},
)
different_query_response = self.client.get(
url,
{"inn": "7744444444", "has_registry": "false"},
)
self.assertEqual(first_response.status_code, status.HTTP_200_OK)
self.assertEqual(first_response["X-Cache"], "MISS")
self.assertEqual(second_response["X-Cache"], "HIT")
self.assertEqual(second_response.data, first_response.data)
self.assertEqual(different_query_response["X-Cache"], "MISS")
self.assertEqual(different_query_response.data["data"][0]["inn"], "7744444444")
def test_retrieve_response_is_cached(self):
organization = Organization.objects.create(
name='ООО "Деталь"',
inn="7755555555",
kpp="775501001",
ogrn="1027700132555",
)
url = reverse("api_v2:organizations:organizations-detail", args=[organization.uid])
first_response = self.client.get(url)
organization.name = 'ООО "Изменено"'
organization.save(update_fields=["name"])
second_response = self.client.get(url)
self.assertEqual(first_response.status_code, status.HTTP_200_OK)
self.assertEqual(first_response["X-Cache"], "MISS")
self.assertEqual(second_response["X-Cache"], "HIT")
self.assertEqual(second_response.data["name"], 'ООО "Деталь"')
def test_list_includes_parser_presence_and_active_registries(self):
organization = Organization.objects.create(
name='ООО "Данные"',
inn="7777777777",
kpp="777701001",
ogrn="1027700132777",
)
registry = RegisterFactory(name="Росатом ГОЗ")
registry_organization = RegistryOrganizationFactory(
mn_inn=int(organization.inn),
mn_ogrn=int(organization.ogrn),
)
RegistryMembershipPeriodFactory(
registry=registry,
organization=registry_organization,
)
certificate = IndustrialCertificateRecordFactory(
inn=organization.inn,
ogrn=organization.ogrn,
certificate_number="CERT-ORG-V2-1",
)
product = IndustrialProductRecordFactory(
inn=organization.inn,
ogrn=organization.ogrn,
registry_number="PRODUCT-ORG-V2-1",
)
manufacturer = ManufacturerRecordFactory(
inn=organization.inn,
ogrn=organization.ogrn,
full_legal_name='ООО "Данные"',
)
inspection = InspectionRecordFactory(
inn=organization.inn,
ogrn=organization.ogrn,
registration_number="INSPECTION-ORG-V2-1",
)
procurement = ProcurementRecordFactory(
customer_inn=organization.inn,
customer_ogrn=organization.ogrn,
purchase_number="PROCUREMENT-ORG-V2-1",
)
generic_record = GenericParserRecord.objects.create(
load_batch=1,
source=ParserLoadLog.Source.FSTEC,
external_id="fstec-1",
inn=organization.inn,
ogrn=organization.ogrn,
organisation_name=organization.name,
title="FSTEC record",
payload={"source": "fstec"},
)
GenericParserRecord.objects.create(
load_batch=1,
source=ParserLoadLog.Source.PROCUREMENTS_44FZ,
external_id="procurements-44fz-1",
inn=organization.inn,
ogrn=organization.ogrn,
organisation_name=organization.name,
title="44-FZ record",
)
financial_report = FinancialReport.objects.create(
external_id="fin-1",
ogrn=organization.ogrn,
file_name="fin.xlsx",
file_hash="a" * 64,
load_batch=1,
status=FinancialReport.Status.SUCCESS,
source=FinancialReport.SourceType.API,
)
FinancialReportLine.objects.create(
report=financial_report,
form_code="1",
line_code="1100",
line_name="Внеоборотные активы",
year=2021,
period_start=100,
period_end=200,
)
FinancialReportLine.objects.create(
report=financial_report,
form_code="1",
line_code="1300",
line_name="Капитал и резервы",
year=2021,
period_start=300,
period_end=400,
)
FinancialReportLine.objects.create(
report=financial_report,
form_code="2",
line_code="2110",
line_name="Выручка",
year=2022,
period_start=None,
period_end=500,
)
response = self.client.get(
reverse("api_v2:organizations:organizations-list"),
{"inn": organization.inn},
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
item = response.data["data"][0]
self.assertEqual(
item["registries"],
[{"id": str(registry.id), "name": "Росатом ГОЗ"}],
)
self.assertNotIn("data_presence", item)
self.assertIn("data", item)
self.assertEqual(
item["data"]["industrial"],
[
{
"id": certificate.id,
"load_batch": certificate.load_batch,
"issue_date": certificate.issue_date,
"issue_date_normalized": None,
"certificate_number": "CERT-ORG-V2-1",
"expiry_date": certificate.expiry_date,
"expiry_date_normalized": None,
"certificate_file_url": certificate.certificate_file_url,
"organisation_name": certificate.organisation_name,
"inn": organization.inn,
"ogrn": organization.ogrn,
"registry_organization": None,
"created_at": certificate.created_at.isoformat().replace(
"+00:00", "Z"
),
"updated_at": certificate.updated_at.isoformat().replace(
"+00:00", "Z"
),
}
],
)
self.assertEqual(
item["data"]["industrial_products"][0]["registry_number"],
"PRODUCT-ORG-V2-1",
)
self.assertEqual(
item["data"]["industrial_products"][0]["id"],
product.id,
)
self.assertEqual(
item["data"]["manufactures"][0]["id"],
manufacturer.id,
)
self.assertEqual(
item["data"]["inspections"][0]["registration_number"],
"INSPECTION-ORG-V2-1",
)
self.assertEqual(
item["data"]["inspections"][0]["id"],
inspection.id,
)
self.assertEqual(
item["data"]["procurements"][0]["purchase_number"],
"PROCUREMENT-ORG-V2-1",
)
self.assertEqual(
item["data"]["procurements"][0]["id"],
procurement.id,
)
self.assertEqual(
item["data"]["procurements_44fz"][0]["external_id"],
"procurements-44fz-1",
)
self.assertEqual(
item["data"]["fstec"][0]["id"],
generic_record.id,
)
self.assertEqual(
item["data"]["fns_reports"][0]["external_id"],
"fin-1",
)
self.assertEqual(
item["data"]["fns_reports"][0]["id"],
financial_report.id,
)
self.assertEqual(item["data"]["fns_reports"][0]["lines_count"], 3)
self.assertEqual(
item["data"]["fns_reports"][0]["lines"]["2021"]["active"]["1100"],
{
"form_code": "1",
"name": "Внеоборотные активы",
"period_start": 100,
"period_end": 200,
},
)
self.assertEqual(
item["data"]["fns_reports"][0]["lines"]["2021"]["passive"]["1300"],
{
"form_code": "1",
"name": "Капитал и резервы",
"period_start": 300,
"period_end": 400,
},
)
self.assertEqual(
item["data"]["fns_reports"][0]["lines"]["2022"]["form_2"]["2110"],
{
"form_code": "2",
"name": "Выручка",
"period_start": None,
"period_end": 500,
},
)
self.assertTrue(
all(isinstance(value, list) for value in item["data"].values())
)
def test_filters_by_registry_and_has_registry(self):
with_registry = Organization.objects.create(
name='ООО "В реестре"',
inn="7788888888",
kpp="778801001",
ogrn="1027700132888",
)
without_registry = Organization.objects.create(
name='ООО "Без реестра"',
inn="7799999999",
kpp="779901001",
ogrn="1027700132999",
)
registry = RegisterFactory(name="Роскосмос ОПК")
registry_organization = RegistryOrganizationFactory(
mn_inn=int(with_registry.inn),
mn_ogrn=int(with_registry.ogrn),
)
RegistryMembershipPeriodFactory(
registry=registry,
organization=registry_organization,
)
by_registry = self.client.get(
reverse("api_v2:organizations:organizations-list"),
{"registry": str(registry.id)},
)
has_registry = self.client.get(
reverse("api_v2:organizations:organizations-list"),
{"has_registry": "true"},
)
no_registry = self.client.get(
reverse("api_v2:organizations:organizations-list"),
{"has_registry": "false", "ordering": "inn"},
)
self.assertEqual(by_registry.status_code, status.HTTP_200_OK)
self.assertEqual(by_registry.data["meta"]["pagination"]["total_count"], 1)
self.assertEqual(by_registry.data["data"][0]["uid"], str(with_registry.uid))
self.assertEqual(has_registry.data["meta"]["pagination"]["total_count"], 1)
self.assertEqual(has_registry.data["data"][0]["uid"], str(with_registry.uid))
self.assertEqual(no_registry.data["meta"]["pagination"]["total_count"], 1)
self.assertEqual(no_registry.data["data"][0]["uid"], str(without_registry.uid))
def test_list_defaults_to_has_registry_true(self):
with_registry = Organization.objects.create(
name='ООО "Дефолтный реестр"',
inn="7800000101",
kpp="780001101",
ogrn="1027700133101",
)
Organization.objects.create(
name='ООО "Скрыто по дефолту"',
inn="7800000102",
kpp="780001102",
ogrn="1027700133102",
)
registry = RegisterFactory(name="Дефолтный реестр")
registry_organization = RegistryOrganizationFactory(
mn_inn=int(with_registry.inn),
mn_ogrn=int(with_registry.ogrn),
)
RegistryMembershipPeriodFactory(
registry=registry,
organization=registry_organization,
)
default_response = self.client.get(
reverse("api_v2:organizations:organizations-list")
)
explicit_false_response = self.client.get(
reverse("api_v2:organizations:organizations-list"),
{"has_registry": "false"},
)
self.assertEqual(default_response.status_code, status.HTTP_200_OK)
self.assertEqual(default_response.data["meta"]["pagination"]["total_count"], 1)
self.assertEqual(default_response.data["data"][0]["uid"], str(with_registry.uid))
self.assertEqual(
explicit_false_response.data["meta"]["pagination"]["total_count"],
1,
)
self.assertEqual(
explicit_false_response.data["data"][0]["inn"],
"7800000102",
)
def test_filters_by_data_presence(self):
with_industrial = Organization.objects.create(
name='ООО "С промышленностью"',
inn="7800000001",
kpp="780001001",
ogrn="1027700133001",
)
with_fns = Organization.objects.create(
name='ООО "С отчетностью"',
inn="7800000002",
kpp="780001002",
ogrn="1027700133002",
)
without_data = Organization.objects.create(
name='ООО "Без данных"',
inn="7800000003",
kpp="780001003",
ogrn="1027700133003",
)
IndustrialCertificateRecordFactory(
inn=with_industrial.inn,
ogrn=with_industrial.ogrn,
)
FinancialReport.objects.create(
external_id="fin-presence-1",
ogrn=with_fns.ogrn,
file_name="fin_presence.xlsx",
file_hash="b" * 64,
load_batch=1,
status=FinancialReport.Status.SUCCESS,
source=FinancialReport.SourceType.API,
)
has_industrial = self.client.get(
reverse("api_v2:organizations:organizations-list"),
{"has_industrial": "true", "has_registry": "false"},
)
no_industrial = self.client.get(
reverse("api_v2:organizations:organizations-list"),
{
"has_industrial": "false",
"has_registry": "false",
"ordering": "inn",
},
)
has_fns = self.client.get(
reverse("api_v2:organizations:organizations-list"),
{"has_fns_reports": "true", "has_registry": "false"},
)
self.assertEqual(has_industrial.status_code, status.HTTP_200_OK)
self.assertEqual(has_industrial.data["meta"]["pagination"]["total_count"], 1)
self.assertEqual(
has_industrial.data["data"][0]["uid"],
str(with_industrial.uid),
)
self.assertEqual(no_industrial.data["meta"]["pagination"]["total_count"], 2)
self.assertEqual(
[item["uid"] for item in no_industrial.data["data"]],
[str(with_fns.uid), str(without_data.uid)],
)
self.assertEqual(has_fns.data["meta"]["pagination"]["total_count"], 1)
self.assertEqual(has_fns.data["data"][0]["uid"], str(with_fns.uid))
def test_limits_response_data_sources(self):
organization = Organization.objects.create(
name='ООО "Источник"',
inn="7800000201",
kpp="780002101",
ogrn="1027700133201",
)
IndustrialCertificateRecordFactory(
inn=organization.inn,
ogrn=organization.ogrn,
)
GenericParserRecord.objects.create(
load_batch=1,
source=ParserLoadLog.Source.FSTEC,
external_id="fstec-source-limit",
inn=organization.inn,
ogrn=organization.ogrn,
organisation_name=organization.name,
)
FinancialReport.objects.create(
external_id="fin-source-limit",
ogrn=organization.ogrn,
file_name="fin_source_limit.xlsx",
file_hash="c" * 64,
load_batch=1,
status=FinancialReport.Status.SUCCESS,
source=FinancialReport.SourceType.API,
)
detail_url = reverse(
"api_v2:organizations:organizations-detail",
args=[organization.uid],
)
only_response = self.client.get(
detail_url,
{"data": "industrial,fns_reports"},
)
excluded_response = self.client.get(
detail_url,
{"exclude_data": "fns_reports"},
)
repeated_response = self.client.get(
detail_url,
[("data", "industrial"), ("data", "fstec")],
)
empty_response = self.client.get(
detail_url,
{"data": "industrial", "exclude_data": "industrial"},
)
self.assertEqual(only_response.status_code, status.HTTP_200_OK)
self.assertEqual(
set(only_response.data["data"]),
{"industrial", "fns_reports"},
)
self.assertEqual(len(only_response.data["data"]["industrial"]), 1)
self.assertEqual(len(only_response.data["data"]["fns_reports"]), 1)
self.assertEqual(excluded_response.status_code, status.HTTP_200_OK)
self.assertNotIn("fns_reports", excluded_response.data["data"])
self.assertIn("industrial", excluded_response.data["data"])
self.assertEqual(repeated_response.status_code, status.HTTP_200_OK)
self.assertEqual(
set(repeated_response.data["data"]),
{"industrial", "fstec"},
)
self.assertEqual(empty_response.status_code, status.HTTP_200_OK)
self.assertEqual(empty_response.data["data"], {})
def test_rejects_unknown_response_data_source(self):
organization = Organization.objects.create(
name='ООО "Неверный источник"',
inn="7800000202",
kpp="780002102",
ogrn="1027700133202",
)
response = self.client.get(
reverse("api_v2:organizations:organizations-detail", args=[organization.uid]),
{"data": "unknown"},
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertIn("data", response.data)
def test_selected_data_sources_keep_constant_query_count(self):
organization = Organization.objects.create(
name='ООО "Без N+1"',
inn="7800000203",
kpp="780002103",
ogrn="1027700133203",
)
IndustrialCertificateRecordFactory(
inn=organization.inn,
ogrn=organization.ogrn,
)
for index, year in enumerate((2021, 2022, 2023, 2024), start=1):
report = FinancialReport.objects.create(
external_id=f"fin-query-count-{year}",
ogrn=organization.ogrn,
file_name=f"fin_query_count_{year}.xlsx",
file_hash=f"{index}" * 64,
load_batch=1,
status=FinancialReport.Status.SUCCESS,
source=FinancialReport.SourceType.API,
)
FinancialReportLine.objects.bulk_create(
[
FinancialReportLine(
report=report,
form_code="1",
line_code=str(1100 + line_index),
line_name=f"Line {line_index}",
year=year,
period_start=line_index,
period_end=line_index * 2,
)
for line_index in range(1, 101)
]
)
for source in (
ParserLoadLog.Source.FSTEC,
ParserLoadLog.Source.CONTRACTS,
ParserLoadLog.Source.TRUDVSEM,
):
GenericParserRecord.objects.create(
load_batch=1,
source=source,
external_id=f"{source}-query-count",
inn=organization.inn,
ogrn=organization.ogrn,
organisation_name=organization.name,
)
OrganizationDataSnapshotRefreshService.refresh(
organization_uids=[str(organization.uid)],
)
url = reverse("api_v2:organizations:organizations-detail", args=[organization.uid])
with CaptureQueriesContext(connection) as captured:
response = self.client.get(
url,
{"data": "industrial,fns_reports,fstec,contracts,vacancies"},
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(
set(response.data["data"]),
{"industrial", "fns_reports", "fstec", "contracts", "vacancies"},
)
self.assertNotIn("trudvsem", response.data["data"])
self.assertEqual(len(response.data["data"]["fns_reports"]), 4)
self.assertLessEqual(len(captured), 1)
def test_v2_renames_trudvsem_data_source_to_vacancies(self):
organization = Organization.objects.create(
name='ООО "Вакансии"',
inn="7800000204",
kpp="780002104",
ogrn="1027700133204",
)
GenericParserRecord.objects.create(
load_batch=1,
source=ParserLoadLog.Source.TRUDVSEM,
external_id="vacancy-1",
inn=organization.inn,
ogrn=organization.ogrn,
organisation_name=organization.name,
title="Инженер",
)
OrganizationDataSnapshotRefreshService.refresh(
organization_uids=[str(organization.uid)],
)
detail_url = reverse(
"api_v2:organizations:organizations-detail",
args=[organization.uid],
)
vacancies_response = self.client.get(detail_url, {"data": "vacancies"})
internal_source_response = self.client.get(detail_url, {"data": "trudvsem"})
has_vacancies_response = self.client.get(
reverse("api_v2:organizations:organizations-list"),
{
"has_vacancies": "true",
"has_registry": "false",
"data": "vacancies",
},
)
self.assertEqual(vacancies_response.status_code, status.HTTP_200_OK)
self.assertEqual(set(vacancies_response.data["data"]), {"vacancies"})
self.assertEqual(
vacancies_response.data["data"]["vacancies"][0]["external_id"],
"vacancy-1",
)
self.assertNotIn("trudvsem", vacancies_response.data["data"])
self.assertEqual(
internal_source_response.status_code,
status.HTTP_400_BAD_REQUEST,
)
self.assertIn("trudvsem", str(internal_source_response.data))
self.assertEqual(has_vacancies_response.status_code, status.HTTP_200_OK)
self.assertEqual(
has_vacancies_response.data["data"][0]["uid"],
str(organization.uid),
)
@override_settings(ORGANIZATIONS_V2_ALLOW_ANONYMOUS=True)
def test_dev_flag_allows_anonymous_access(self):
self.client.force_authenticate(user=None)
Organization.objects.create(
name='ООО "Без токена"',
inn="7766666666",
kpp="776601001",
ogrn="1027700132666",
)
response = self.client.get(
reverse("api_v2:organizations:organizations-list"),
{"has_registry": "false"},
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["meta"]["pagination"]["total_count"], 1)
@override_settings(ORGANIZATIONS_V2_ALLOW_ANONYMOUS=False)
def test_without_dev_flag_requires_authentication(self):
self.client.force_authenticate(user=None)
response = self.client.get(reverse("api_v2:organizations:organizations-list"))
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)