GET /api/agent/crm/fixations/{fixationId} — Карточка фиксации (агент)
Страница фиксации агентской стороны: агент (или руководитель его агентства) открывает поданную заявку на
фиксацию и видит, что именно ушло застройщику и чем решилось. Возвращает snapshot ФИО/телефона клиента,
эффективные хотелки (override заявки либо актуальная «шапка» лида), лид-основание, статус решения застройщика
(DecidedAt/RejectReason) и созданную при одобрении сделку (DealId). Только чтение: домен фиксации —
fixation-request.md.
Назначение
Дать агенту карточку одной фиксации по fixationId — иммутабельный снимок того, что подано застройщику, плюс
исход. Инвестор фиксаций не видит; застройщик работает со своей стороной (.decide).
Metadata
| Поле | Значение |
|---|---|
| Сервис/контекст | crm |
| API area | agent |
| Feature group | fixation |
| Статус | draft |
| Документ | docs/06-services/crm/api/agent/get-fixation.md |
Актор и доступ
| Проверка | Значение |
|---|---|
| Actor type | User (Агент — свои; Руководитель агентства — весь AgencyCompanyId; Менеджер ПИН — platform-scope) |
| Auth policy / Permissions | crm.fixations.view |
| Scope (RBAC) | организация (агентство) — OriginAgencyCompanyId |
| Record-level | Актор — текущий исполнитель заявки (ExecutorAgentUserId = actor.UserId) либо руководитель/админ компании-владельца агентской стороны (FixationRequestEntity.OriginAgencyCompanyId = actor.CompanyId) |
| Tenant isolation | Запрос не tenanted по TenantId фиксации (= DeveloperCompanyId ≠ актор): чтение по явному предикату OriginAgencyCompanyId (ADR-0052) |
| Audit | read (не sensitive); телефон клиента в логи — только маской |
Фиксация принадлежит tenant'у застройщика (TenantId = DeveloperCompanyId), но агентский актор проверяется
не по этому tenant, а record-level предикатом: явным сравнением OriginAgencyCompanyId заявки с агентством
актора (ADR-0052). Доступ имеет текущий исполнитель заявки (ExecutorAgentUserId = actor.UserId) либо
руководитель/админ агентства-владельца (OriginAgencyCompanyId = actor.CompanyId).
HTTP-контракт
| Поле | Значение |
|---|---|
| Method | GET |
| Route | /api/agent/crm/fixations/{fixationId} |
| Success status | 200 |
| Idempotency header | не применяется (GET — безопасный) |
| Correlation | сквозной trace через заголовок traceparent |
Входные данные / параметры запроса
| Поле | Источник | Тип | Обязательность | Валидация / Ограничения | Безопасность |
|---|---|---|---|---|---|
FixationId | route | Guid | Да | != Guid.Empty | — |
ActorUserId | identity claims | Guid | Да | JWT агента | — |
ActorCompanyId | identity claims | Guid | Да | AgencyCompanyId агента — сверяется с OriginAgencyCompanyId заявки (record-level) | — |
Модель ответа FixationCardModel
Проекция агрегата; дом полей — fixation-request.md (VO FullName —
client.md; VO LeadWishes — lead.md). Ниже — только дельта.
| Поле | Тип | Обязательность | Источник | Masking | Описание |
|---|---|---|---|---|---|
FixationId | Guid | Да | Id | — | Идентификатор заявки. |
Status | FixationStatus (enum строкой) | Да | Status | — | Pending/FixedUnique/FixedNonUnique/Rejected/Cancelled. |
DeveloperCompanyId | Guid | Да | TenantId | — | Застройщик-адресат. |
LeadId | Guid | Да | LeadId | — | Лид-основание (переход в карточку лида). |
Client | ClientRefModel ({ ClientId: Guid, ClientName: FullName }) | Да | ClientId + ClientName (snapshot) | — | Клиент фиксации; ФИО — snapshot на момент подачи (иммутабельно), карточка — ClientId. |
ClientPhoneNumber | string | Да | ClientPhoneNumber (snapshot) | телефон — маска в логах | Телефон клиента на момент подачи (E.164). |
Wishes | LeadWishes (owned) | Да | computed: WishesOverride ?? Lead.Wishes | — | Эффективные хотелки для показа. |
WishesSource | WishesSource (enum строкой) | Да | computed | — | Override (снимок заявки) / Lead (актуальная «шапка» лида). |
Uniqueness | FixationUniqueness (enum строкой) | Да | Uniqueness | — | Unknown/NoDuplicates/HasDuplicates (результат авто-проверки застройщика). |
DecidedByUserId | Guid? | Нет | DecidedByUserId | — | Кто одобрил/отклонил; null — решения нет. |
DecidedAt | DateTimeOffset? | Нет | DecidedAt | — | Момент решения застройщика. |
RejectReason | string? | Нет | RejectReason | — | Причина отклонения (при Status = Rejected). |
CancelledAt | DateTimeOffset? | Нет | CancelledAt | — | Момент отмены агентом. |
DealId | Guid? | Нет | DealId | — | Сделка, созданная при одобрении (deal.md); null — до одобрения. |
CreatedAt | DateTimeOffset | Да | CreatedAt | — | Подача заявки. |
Дубль-детект (DuplicateOfFixationId/DuplicateMatchKind) — сторона застройщика (.decide); в агентской
карточке не раскрывается.
Алгоритм
- Контекст и доступ. Операцию выполняет агент (permission
crm.fixations.view) в рамках своего агентства. - Проверка входа.
FixationId != Guid.Empty— иначе ошибка валидации. Существование и доступ проверяются при чтении (шаги 3–4). - Что читаем. Заявку (агентская сторона — по явному предикату, у актора нет tenant застройщика); если нет/
soft-deleted →
CRM_FIXATION_NOT_FOUND. ЕслиWishesOverride == null— лид-основание (для чтения актуальнойLead.Wishes); иначе лид не загружается. - Маппинг и правила доступа. Record-level: актор — текущий исполнитель (
ExecutorAgentUserId = actor.UserId) либо руководитель/админ компании-владельца (OriginAgencyCompanyId = actor.CompanyId) — иначеFORBIDDEN(403, чужая агентская сторона не раскрывается). ВычислитьWishes = WishesOverride ?? Lead.Wishes,WishesSource = WishesOverride != null ? Override : Lead. Остальные поля маппятся 1:1. - Результат. Карточка фиксации → HTTP
200. Ошибки —404/403/400(таблица ниже).
Диаграмма
Побочные эффекты
| Тип | Детали |
|---|---|
| Интеграционные события | none (read-only) |
| Внешние вызовы | none |
| Проекции / поиск | none (прямое чтение агрегата и лида) |
| Уведомления | none |
Ошибки и failure modes
| Код | HTTP status | Условие | Сообщение | Retry |
|---|---|---|---|---|
VALIDATION_FAILED | 400 | FixationId = Guid.Empty | «Некорректный идентификатор фиксации» | no retry |
FORBIDDEN | 403 | актор не исполнитель заявки и не руководитель/админ fixation.OriginAgencyCompanyId | «Нет доступа к фиксации» | no retry |
CRM_FIXATION_NOT_FOUND | 404 | нет фиксации с таким Id (или soft-deleted) | «Фиксация не найдена» | no retry |
Совместимость и наблюдаемость
- Новые optional поля
FixationCardModel— additive (без breaking change); удаление/переименование/смена типа — breaking (migration + rollout). Enum-поля (Status/Uniqueness/WishesSource) сериализуются строкой; клиент обязан толерантно обрабатывать неизвестное значение. - Logs:
fixation-card requested(FixationId,DeveloperCompanyId,OriginAgencyCompanyId; телефон — маской); metrics:crm_fixation_card_requests_total{result}, latency p95; traces — сквозной trace черезtraceparent; dashboardpin-crm; runbook —docs/06-services/crm/runbooks/.
Acceptance Criteria
- Happy path. Given агент своей агентской стороны и существующая фиксация; When
GET; Then200сFixationCardModel: snapshot ФИО/телефона, эффективныеWishes, статус и исход решения,DealIdпри одобрении. - Wishes из override. Given фиксация с заданным
WishesOverride; WhenGET; ThenWishes = WishesOverride,WishesSource = Override; лид-основание не читается. - Wishes из лида. Given
WishesOverride == null; WhenGET; ThenWishes = Lead.Wishes,WishesSource = Lead. - Чужое агентство. Given актор не исполнитель и
OriginAgencyCompanyId != actor.CompanyId; WhenGET; Then403 FORBIDDEN. - Не найдена. Given несуществующая или soft-deleted фиксация; When
GET; Then404 CRM_FIXATION_NOT_FOUND. - Валидация. Given
FixationId = Guid.Empty; WhenGET; Then400 VALIDATION_FAILED. - Одобрена. Given
Status ∈ {FixedUnique, FixedNonUnique}; WhenGET; ThenDealId != null, заданыDecidedAt/DecidedByUserId. - Отклонена. Given
Status = Rejected; WhenGET; Then заданыRejectReasonиDecidedAt,DealId == null.
Обратные ссылки
Автоссылки: где используется этот документ.
- API (4): GET /api/agent/crm/deals/{dealId} — Карточка сделки (агент), GET /api/pin-manager/crm/fixations/{fixationId} — Карточка любой фиксации (Менеджер ПИН), POST /api/developer/crm/fixations/{fixationId}/approve — Одобрить фиксацию (уникальная / не уникальная), POST /api/developer/crm/fixations/{fixationId}/reject — Отклонить фиксацию
- registries (1): Реестр API-методов PIN
Связанные документы
- Сущности: fixation-request.md (дом полей, VO
LeadWishesoverride), lead.md (актуальная «шапка» хотелок), client.md (VOFullName), deal.md (сделка из одобрения). - Создание заявки — create-booking-request.md (соседний flow воронки агента).
- ADR: 0052 tenancy (двухсторонние сущности, record-level).