Срез 1: справочники (API), импорт из ЕЦП CRM, policy видимости, администрирование #6

Merged
aep merged 51 commits from feat/5-slice-1-directories into main 2026-10-05 10:00:05 +03:00
5 changed files with 18 additions and 18 deletions
Showing only changes of commit 4dd966b0b7 - Show all commits

View File

@ -9,7 +9,8 @@ from typing import Annotated
from fastapi import APIRouter, Depends
from src.api.dependencies.auth import Principal, current_user
from src.schemas.me import MeResponse, RegionalOfficeOut
from src.schemas.directories import RegionalOfficeBrief
from src.schemas.me import MeResponse
router = APIRouter(tags=["me"])
@ -24,7 +25,7 @@ async def get_me(principal: Annotated[Principal, Depends(current_user)]) -> MeRe
# пользователь найден по email, поэтому он заполнен; пустая строка — лишь для типов (колонка nullable)
email=user.email or "",
full_name=user.full_name,
regional_office=RegionalOfficeOut(id=office.id, name=office.name, is_head_office=office.is_head_office),
regional_office=RegionalOfficeBrief.model_validate(office),
business_segment=user.business_segment,
roles=sorted(principal.roles),
permissions=sorted(principal.permissions),

View File

@ -19,14 +19,19 @@ def _blank_to_none(value: str | None) -> str | None:
return stripped or None
class RegionalOfficeOut(BaseModel):
"""Филиал (`GET /directories/regional-offices`)."""
class RegionalOfficeBrief(BaseModel):
"""Филиал кратко: профиль `GET /me` (форма ответа Среза 0 — без `is_active`)."""
model_config = ConfigDict(from_attributes=True)
id: uuid.UUID
name: str
is_head_office: bool
class RegionalOfficeOut(RegionalOfficeBrief):
"""Филиал целиком (`GET /directories/regional-offices`, пользователи администратора)."""
is_active: bool

View File

@ -5,14 +5,7 @@ import uuid
from pydantic import BaseModel, ConfigDict
from src.models.enums import BusinessSegment
class RegionalOfficeOut(BaseModel):
"""Филиал пользователя."""
id: uuid.UUID
name: str
is_head_office: bool
from src.schemas.directories import RegionalOfficeBrief
class MeResponse(BaseModel):
@ -23,7 +16,7 @@ class MeResponse(BaseModel):
id: uuid.UUID
email: str
full_name: str
regional_office: RegionalOfficeOut
regional_office: RegionalOfficeBrief
business_segment: BusinessSegment | None
roles: list[str]
permissions: list[str]

View File

@ -34,7 +34,8 @@ from src.models.access import AppUser, Role, UserRole
from src.models.directories import RegionalOffice
from src.models.enums import BusinessSegment
from src.repositories.users import AmbiguousUserError, load_principal_data
from src.schemas.me import MeResponse, RegionalOfficeOut
from src.schemas.directories import RegionalOfficeBrief
from src.schemas.me import MeResponse
SECRET = "test-secret-for-auth-deps-0123456789abcdef"
OTHER_SECRET = "foreign-secret-for-auth-deps-0123456789ab"
@ -487,7 +488,7 @@ async def test_repository_raises_on_ambiguity(seeded: AsyncSession) -> None:
def test_me_response_schema_serializes_enum_and_null_segment() -> None:
office = RegionalOfficeOut(id=uuid.uuid4(), name="ГО", is_head_office=True)
office = RegionalOfficeBrief(id=uuid.uuid4(), name="ГО", is_head_office=True)
fields: dict[str, Any] = {
"id": uuid.uuid4(),
"email": "a@b.c",

View File

@ -36,7 +36,7 @@ from src.db.db import get_async_session
from src.models.directories import RegionalOffice
from src.models.enums import AuditAction, AuditSection
from src.schemas.common import ErrorDetail, Page, PageParams
from src.schemas.me import RegionalOfficeOut
from src.schemas.directories import RegionalOfficeBrief
from src.services.audit import AuditService
from tests.pg_helpers import alembic_async
@ -141,8 +141,8 @@ def test_domain_error_extra_cannot_shadow_code_or_message() -> None:
def test_page_serializes() -> None:
office = RegionalOfficeOut(id=CONFLICT_ID, name="ГО", is_head_office=True)
page = Page[RegionalOfficeOut](items=[office], total=7, limit=1, offset=3)
office = RegionalOfficeBrief(id=CONFLICT_ID, name="ГО", is_head_office=True)
page = Page[RegionalOfficeBrief](items=[office], total=7, limit=1, offset=3)
assert page.model_dump(mode="json") == {
"items": [{"id": str(CONFLICT_ID), "name": "ГО", "is_head_office": True}],
"total": 7,