feat(organization): scalar corporation_scope and scopes dictionary endpoint
This commit is contained in:
14
src/apps/organization/dictionary_urls.py
Normal file
14
src/apps/organization/dictionary_urls.py
Normal file
@@ -0,0 +1,14 @@
|
||||
"""URL-маршруты для справочников организации."""
|
||||
|
||||
from apps.organization.dictionary_views import CorporationScopeDictionaryView
|
||||
from django.urls import path
|
||||
|
||||
app_name = "organization_dictionaries"
|
||||
|
||||
urlpatterns = [
|
||||
path(
|
||||
"corporation-scopes/",
|
||||
CorporationScopeDictionaryView.as_view(),
|
||||
name="corporation-scopes",
|
||||
),
|
||||
]
|
||||
18
src/apps/organization/dictionary_views.py
Normal file
18
src/apps/organization/dictionary_views.py
Normal file
@@ -0,0 +1,18 @@
|
||||
"""Dictionary endpoints for organization domain."""
|
||||
|
||||
from apps.organization.scope_utils import get_corporation_scope_dictionary
|
||||
from apps.organization.serializers import CorporationScopeDictionarySerializer
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
|
||||
class CorporationScopeDictionaryView(APIView):
|
||||
"""Return static dictionary for organization corporation scopes."""
|
||||
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request): # noqa: ARG002
|
||||
items = get_corporation_scope_dictionary()
|
||||
serializer = CorporationScopeDictionarySerializer(items, many=True)
|
||||
return Response({"results": serializer.data})
|
||||
@@ -16,6 +16,21 @@ SCOPE_LABELS: dict[str, str] = {
|
||||
"rosatom": "Госкорпорация «Росатом»",
|
||||
"roscosmos": "Госкорпорация «Роскосмос»",
|
||||
"opk": "Организации ОПК",
|
||||
"other": "Иная корпорация",
|
||||
}
|
||||
|
||||
SCOPE_SHORT_NAMES: dict[str, str] = {
|
||||
"rosatom": "Росатом",
|
||||
"roscosmos": "Роскосмос",
|
||||
"opk": "ОПК",
|
||||
"other": "Иная",
|
||||
}
|
||||
|
||||
SCOPE_SORT_ORDER: dict[str, int] = {
|
||||
"rosatom": 10,
|
||||
"roscosmos": 20,
|
||||
"opk": 30,
|
||||
"other": 90,
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +53,27 @@ def scope_labels(scope_codes: Iterable[str]) -> list[str]:
|
||||
return [SCOPE_LABELS[code] for code in scope_codes if code in SCOPE_LABELS]
|
||||
|
||||
|
||||
def get_corporation_scope_dictionary() -> list[dict[str, str | int]]:
|
||||
"""Возвращает справочник корпусов для API-словаря."""
|
||||
items: list[dict[str, str | int]] = []
|
||||
for code, sort_order in sorted(
|
||||
SCOPE_SORT_ORDER.items(), key=lambda item: item[1]
|
||||
):
|
||||
label = SCOPE_LABELS.get(code)
|
||||
short_name = SCOPE_SHORT_NAMES.get(code)
|
||||
if not label or not short_name:
|
||||
continue
|
||||
items.append(
|
||||
{
|
||||
"code": code,
|
||||
"name": label,
|
||||
"short_name": short_name,
|
||||
"sort_order": sort_order,
|
||||
}
|
||||
)
|
||||
return items
|
||||
|
||||
|
||||
def build_scope_query(scope_codes: Iterable[str]) -> Q:
|
||||
query = Q()
|
||||
for scope_code in scope_codes:
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"""
|
||||
|
||||
from apps.organization.models import Organization
|
||||
from apps.organization.scope_utils import SCOPE_LABELS
|
||||
from apps.registers.models import Register
|
||||
from rest_framework import serializers
|
||||
|
||||
@@ -108,12 +109,25 @@ class OrganizationCatalogBaseSerializer(serializers.ModelSerializer):
|
||||
return obj.get_active_registry_names()
|
||||
|
||||
@staticmethod
|
||||
def get_corporation_scope(obj: Organization) -> list[str]:
|
||||
return obj.get_corporation_scopes()
|
||||
def _primary_scope_or_default(obj: Organization) -> str:
|
||||
scopes = obj.get_corporation_scopes()
|
||||
return scopes[0] if scopes else ""
|
||||
|
||||
@staticmethod
|
||||
def get_corporation_scope_label(obj: Organization) -> list[str]:
|
||||
return obj.get_corporation_scope_labels()
|
||||
def get_corporation_scope(obj: Organization) -> str:
|
||||
return OrganizationCatalogBaseSerializer._primary_scope_or_default(obj)
|
||||
|
||||
@staticmethod
|
||||
def get_corporation_scope_label(obj: Organization) -> str:
|
||||
scope = OrganizationCatalogBaseSerializer._primary_scope_or_default(obj)
|
||||
return OrganizationCatalogBaseSerializer._label_or_empty(scope)
|
||||
|
||||
@staticmethod
|
||||
def _label_or_empty(scope_code: str) -> str:
|
||||
if not scope_code:
|
||||
return ""
|
||||
return SCOPE_LABELS.get(scope_code, "")
|
||||
|
||||
|
||||
|
||||
class OrganizationCatalogListSerializer(OrganizationCatalogBaseSerializer):
|
||||
@@ -193,3 +207,12 @@ class OrganizationCatalogDetailSerializer(OrganizationCatalogBaseSerializer):
|
||||
"created_at",
|
||||
"updated_at",
|
||||
]
|
||||
|
||||
|
||||
class CorporationScopeDictionarySerializer(serializers.Serializer):
|
||||
"""Serializer for corporation scope dictionary entries."""
|
||||
|
||||
code = serializers.CharField()
|
||||
name = serializers.CharField()
|
||||
short_name = serializers.CharField()
|
||||
sort_order = serializers.IntegerField()
|
||||
|
||||
@@ -22,6 +22,7 @@ jobs_urlpatterns = [
|
||||
urlpatterns = [
|
||||
path("analytics/", include("apps.organization.analytics_root_urls")),
|
||||
path("exchange/", include("apps.exchange.urls")),
|
||||
path("dictionaries/", include("apps.organization.dictionary_urls")),
|
||||
path("users/", include("apps.user.urls")),
|
||||
path("jobs/", include((jobs_urlpatterns, "jobs"))),
|
||||
path("organizations/", include("apps.organization.urls")),
|
||||
|
||||
@@ -65,7 +65,11 @@ class OrganizationApiTest(APITestCase):
|
||||
self.assertEqual(
|
||||
response.data["results"][0]["active_registry_names"], ["Реестр ОПК"]
|
||||
)
|
||||
self.assertEqual(response.data["results"][0]["corporation_scope"], ["opk"])
|
||||
self.assertEqual(response.data["results"][0]["corporation_scope"], "opk")
|
||||
self.assertEqual(
|
||||
response.data["results"][0]["corporation_scope_label"],
|
||||
"Организации ОПК",
|
||||
)
|
||||
self.assertEqual(response.data["results"][0]["short_name"], "АО «Альфа»")
|
||||
|
||||
def test_detail_includes_active_registries(self):
|
||||
@@ -102,7 +106,11 @@ class OrganizationApiTest(APITestCase):
|
||||
response.data["active_registries"],
|
||||
[{"id": str(register.id), "name": "Реестр Роскосмос"}],
|
||||
)
|
||||
self.assertEqual(response.data["corporation_scope"], ["roscosmos"])
|
||||
self.assertEqual(response.data["corporation_scope"], "roscosmos")
|
||||
self.assertEqual(
|
||||
response.data["corporation_scope_label"],
|
||||
"Госкорпорация «Роскосмос»",
|
||||
)
|
||||
self.assertEqual(
|
||||
response.data["general_director"]["full_name"],
|
||||
"Иванов Иван Иванович",
|
||||
@@ -180,3 +188,26 @@ class OrganizationApiTest(APITestCase):
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(len(response.data["results"]), 1)
|
||||
self.assertEqual(response.data["results"][0]["id"], str(rosatom_org.id))
|
||||
|
||||
|
||||
class OrganizationDictionaryApiTest(APITestCase):
|
||||
"""Tests for organization dictionaries endpoints."""
|
||||
|
||||
def setUp(self):
|
||||
self.user = UserFactory.create_user()
|
||||
self.client.force_authenticate(self.user)
|
||||
|
||||
def test_corporation_scopes_dictionary_returns_sorted_results(self):
|
||||
response = self.client.get("/api/v1/dictionaries/corporation-scopes/")
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertIn("results", response.data)
|
||||
self.assertGreaterEqual(len(response.data["results"]), 3)
|
||||
sort_orders = [item["sort_order"] for item in response.data["results"]]
|
||||
self.assertEqual(sort_orders, sorted(sort_orders))
|
||||
|
||||
first_item = response.data["results"][0]
|
||||
self.assertEqual(first_item["code"], "rosatom")
|
||||
self.assertIn("short_name", first_item)
|
||||
self.assertIn("name", first_item)
|
||||
self.assertIn("sort_order", first_item)
|
||||
|
||||
Reference in New Issue
Block a user