Перейти к основному содержимому

GET /api/pin-manager/crm/fixations/{fixationId} — Карточка любой фиксации (Менеджер ПИН)

Назначение

Даёт Менеджеру ПИН сквозную (арбитражную) карточку одной заявки на фиксацию: platform-scope актор открывает любую фиксацию любого тенанта по fixationId и видит обе стороны сразу — снимок ФИО/телефона клиента, эффективные хотелки (override заявки либо «шапка» лида), результат авто-проверки дублей у застройщика (DuplicateOfFixationId/DuplicateMatchKind), решение (DecidedAt/RejectReason), созданную сделку (DealId) и того, кто подал заявку (CreatedByUserId — Менеджер ПИН может подать фиксацию от имени агента). Нужна для арбитража спора «агент ↔ застройщик» (US-MGR-01..06). В отличие от агентской (../agent/get-fixation.md) и застройщичьей сторон, карточка Менеджера ПИН не ограничена ни OriginAgencyCompanyId, ни DeveloperCompanyId и раскрывает дубль-ссылку. Инвестор фиксаций не видит. Только чтение; дом полей — fixation-request.md.

Metadata

ПолеЗначение
Сервис/контекстcrm
API areapin-manager
Feature groupfixation
Статусdraft
Документdocs/06-services/crm/api/pin-manager/get-fixation.md

Актор и доступ

ПроверкаЗначение
Actor typeOperator(Admin) — Менеджер ПИН (platform-scope); Служба заботы — read-only арбитраж
Auth policy / Permissionscrm.fixations.view в platform-scope (роль «Менеджер ПИН»); политика проверяется до бизнес-логики
Scope (RBAC)платформа (кросс-tenant; ADR-0052: кросс-tenant — только platform-scope)
Record-levelне применяется (platform-scope видит любую фиксацию любого агентства и застройщика)
Tenant isolationЗапрос не tenanted: TenantId фиксации (= DeveloperCompanyId) не сравнивается с актором; чтение сквозное по platform-scope-политике
Auditread (арбитраж); телефон клиента в логи — только маской; ActorUserId фиксируется

HTTP-контракт

ПолеЗначение
MethodGET
Route/api/pin-manager/crm/fixations/{fixationId}
Success status200
Idempotency headerне применяется (безопасный GET)
Correlationсквозной trace через заголовок traceparent

Входные данные / параметры запроса

ПолеИсточникТипОбязательностьВалидация / ОграниченияБезопасность
FixationIdrouteGuidДа!= Guid.Empty
ActorUserIdidentity claimsGuidДаJWT Менеджера ПИН (platform-scope)audit/логи

Модель ответа FixationCardModel

Проекция агрегата; дом полей — fixation-request.md (VO FullNameclient.md; VO LeadWisheslead.md). Все enum сериализуются строкой.

ПолеТипОбязательностьИсточникMaskingОписание
FixationIdGuidДаIdИдентификатор заявки (fixationId маршрута).
StatusFixationStatusДаStatusPending/FixedUnique/FixedNonUnique/Rejected/Cancelled.
DeveloperCompanyIdGuidДаTenantIdЗастройщик-адресат заявки.
OriginAgencyCompanyIdGuidДаOriginAgencyCompanyIdАгентство агента-инициатора на момент подачи (иммутабельная атрибуция).
OriginAgentUserIdGuidДаOriginAgentUserIdАгент-инициатор на момент подачи: историческая атрибуция и антифрод (иммутабелен).
ExecutorAgentUserIdGuidДаExecutorAgentUserIdТекущий агент-исполнитель фиксации (получатель комиссии при одобрении); мутабелен — переназначается без переписывания Origin.
InvestorUserIdGuidДаInvestorUserIdИнвестор (клиент).
LeadIdGuidДаLeadIdЛид-основание (переход в карточку лида).
ClientClientRefModel ({ ClientId: Guid, ClientName: FullName })ДаClientId + ClientName (snapshot)Клиент фиксации; ФИО — snapshot на момент подачи (иммутабельно), карточка — ClientId.
ClientPhoneNumberstringДаClientPhoneNumber (snapshot)телефон — маска в логахТелефон клиента на момент подачи (E.164).
WishesLeadWishes (owned)Давычисление: WishesOverride ?? Lead.WishesЭффективные хотелки для показа (шаг 3–4).
WishesSourceWishesSource (enum)ДавычислениеOverride (снимок заявки) / Lead (актуальная «шапка» лида).
UniquenessFixationUniquenessДаUniquenessUnknown/NoDuplicates/HasDuplicates (авто-проверка застройщика).
DuplicateOfFixationIdGuid?НетDuplicateOfFixationIdАктивная фиксация-дубль у застройщика (арбитраж); null — совпадений нет.
DuplicateMatchKindDuplicateMatchKind?НетDuplicateMatchKindЧем совпало: Phone/Name/PhoneAndName.
DecidedByUserIdGuid?НетDecidedByUserIdКто одобрил/отклонил (менеджер застройщика); null — решения нет.
DecidedAtDateTimeOffset?НетDecidedAtМомент решения застройщика.
RejectReasonstring?НетRejectReasonПричина отклонения (при Status = Rejected).
CancelledAtDateTimeOffset?НетCancelledAtМомент отмены агентом.
DealIdGuid?НетDealIdСделка, созданная при одобрении (deal.md); null — до одобрения.
CreatedByUserIdGuid?НетCreatedByUserIdКто подал заявку: совпадает с OriginAgentUserId, либо Менеджер ПИН — при подаче от имени агента.
CreatedAtDateTimeOffsetДаCreatedAtПодача заявки.
UpdatedAtDateTimeOffsetДаUpdatedAtПоследнее изменение.

Алгоритм

  1. Контекст и доступ. Операцию выполняет Менеджер ПИН с permission crm.fixations.view в platform-scope (проверено до бизнес-логики). Доступ сквозной, кросс-tenant.
  2. Проверка входа и предусловий. FixationId != Guid.Empty → иначе VALIDATION_FAILED. Чтение разрешено во всех статусах, включая терминальные Rejected/Cancelled/Fixed*.
  3. Что читаем. Фиксацию по FixationId сквозным доступом (TenantId фиксации не фильтруется по актору); если фиксации нет или она soft-deleted → CRM_FIXATION_NOT_FOUND. Если у заявки нет собственного снимка хотелок (WishesOverride == null), дополнительно читаем лид-основание по LeadId — для актуальной Lead.Wishes. Дубль-фиксация по DuplicateOfFixationId наружу не разворачивается — в ответе только её id и DuplicateMatchKind.
  4. Бизнес-правила и маппинг. Record-level не применяется (platform-scope видит любую сторону — арбитраж). Эффективные хотелки: Wishes = WishesOverride ?? Lead.Wishes, WishesSource = Override, если снимок заявки есть, иначе Lead. Остальные поля FixationCardModel — 1:1 из фиксации (таблица выше), включая дубль-ссылку и CreatedByUserId. Переходов состояний нет (чтение).
  5. Результат. Карточка FixationCardModel → HTTP 200. Данные согласованы на момент запроса; ФИО клиента — иммутабельный snapshot заявки. Решение застройщика, отражённое в карточке, публикуют отдельные операции (fixation-approved, fixation-rejected); эта операция лишь показывает их результат.

Диаграмма

Побочные эффекты

ТипДетали
Внешние вызовыdisplay-ФИО участников/решивших по их id — отдельный запрос к identity

Ошибки и failure modes

КодHTTP statusУсловиеСообщениеRetry
VALIDATION_FAILED400FixationId = Guid.Empty«Некорректный идентификатор фиксации»no retry
CRM_FIXATION_NOT_FOUND404нет фиксации с таким Id (или soft-deleted)«Фиксация не найдена»no retry
Доступ

Отсутствие platform-scope-права (403 FORBIDDEN) отсекается политикой до бизнес-логики метода.

Предусловия и постусловия

Предусловия (истинны до сценария):

  • актор — Менеджер ПИН (или Служба заботы, read-only) с permission crm.fixations.view в platform-scope; кросс-tenant, TenantId фиксации с актором не сравнивается;
  • чтение разрешено во всех статусах, включая терминальные Rejected/Cancelled/FixedUnique/FixedNonUnique.

Постусловия (после запроса):

  • состояние не изменяется (read-only); факт арбитражного чтения PII логируется, телефон — маской;
  • возвращена карточка обеих сторон с раскрытой дубль-ссылкой (DuplicateOfFixationId + DuplicateMatchKind как id/тип, сама дубль-фиксация не разворачивается) и вычисленными эффективными хотелками.

Кросс-сервисные ожидания (eventual-реплики). Display-ФИО участников/решивших по их id резолвятся отдельным запросом к identity (имена могут отставать, идентификаторы присутствуют всегда). Решение застройщика, отражённое в карточке (DecidedAt/Status/DealId), публикуют отдельные операции (fixation-approved/fixation-rejected); эта операция лишь показывает их результат.

Acceptance Criteria

  • Happy path (override-хотелки). Дано: заявка со снимком WishesOverride. Когда: GET …/fixations/{id}. Тогда: 200, Wishes = снимок заявки, WishesSource = Override (лид-основание не читается).
  • Хотелки из лида. Дано: WishesOverride = null. Когда: GET. Тогда: 200, Wishes = актуальные Lead.Wishes, WishesSource = Lead.
  • Есть дубль. Дано: Uniqueness = HasDuplicates. Когда: GET. Тогда: 200, заполнены DuplicateOfFixationId и DuplicateMatchKind (Phone/Name/PhoneAndName); дубль-фиксация не разворачивается.
  • Терминальный статус. Дано: Status = Rejected/Cancelled/Fixed*. Когда: GET. Тогда: 200 (чтение во всех статусах).
  • Кросс-tenant. Дано: фиксация чужого застройщика. Когда: GET. Тогда: 200 (platform-scope не ограничен tenant).
  • Не найдена/soft-deleted. Когда: фиксации с таким Id нет. Тогда: 404 CRM_FIXATION_NOT_FOUND.
  • Пустой идентификатор. Когда: FixationId = Guid.Empty. Тогда: 400 VALIDATION_FAILED.
  • Нет platform-scope-права. Когда: актор без crm.fixations.view @ platform-scope. Тогда: 403 FORBIDDEN (отсекается политикой до бизнес-логики).

Совместимость и наблюдаемость

  • Новые optional поля FixationCardModel — additive (без breaking change); удаление/переименование/смена типа — breaking (migration + rollout). Enum-поля (FixationStatus/FixationUniqueness/DuplicateMatchKind/ WishesSource) сериализуются строкой; клиент обязан толерантно обрабатывать неизвестное значение.
  • Logs: pin-manager fixation-card requested (FixationId, DeveloperCompanyId, OriginAgencyCompanyId, ActorUserId; телефон — маской); metrics: crm_fixation_card_requests_total{area=pin-manager,result}, latency p95 < 1 с (SLO чтений); traces — сквозной trace через traceparent; dashboard pin-crm.

Обратные ссылки

Автоссылки: где используется этот документ.

Связанные документы