UC-RWD-007. Платформа настраивает условия удержания ПИН
Назначение
Описывает сценарий управления условиями платформенной комиссии: Менеджер ПИН задаёт, сколько
процентных пунктов ставки застройщика платформа удерживает в свою пользу с каждой подтверждённой
комиссии (0.25–1.50 п.п., ADR-0066) — персонально для агентства или глобальным дефолтом, — активирует
условия и получает их автоматическое применение к новым начислениям: при завершении сделки consumer
снимает снапшот условий на момент CompletedAt, а при подтверждении застройщиком строится строка
распределения Platform. Связан с контекстом rewards.
Metadata
| Поле | Значение |
|---|---|
| ID | UC-RWD-007 |
| Контекст | rewards (см. docs/06-services/rewards/) |
| Тип | основной |
| Статус | draft |
Актор
| Поле | Значение |
|---|---|
| Роль | Менеджер ПИН |
| Permissions / scope | Управление — rewards.platform-terms.manage, чтение реестра — rewards.platform-terms.view; scope — платформа |
| Tenant | вне tenant-модели — платформенная сущность (владелец процесса — ПИН, ADR-0052) |
| Record-level | не применяется |
Предусловие
- Актор аутентифицирован, права платформенного scope.
- Для per-agency условий: компания-агентство существует в
identity(Type ∈ {Agency, Broker}). - Ставки застройщиков (правила вознаграждений, UC-RWD-001) настроены независимо — удержание применяется к любой ставке; конфликт «удержание ≥ ставки» ловится при начислении (A5, INV-PT-4).
Триггер
| Поле | Значение |
|---|---|
| Источник | UI button |
| Триггерящий элемент | Админ-панель ПИН → «Финансы» → «Условия платформенной комиссии» → «Создать» / «Активировать» / «Архивировать» |
Основной Поток
Фаза 1. Создание и активация условий
- Менеджер ПИН открывает реестр условий (
GET /api/v1/platform/commission-terms, permissionrewards.platform-terms.view, фильтры по агентству/статусу) и нажимает «Создать». - Фронт вызывает
POST /api/v1/platform/commission-termsс телом{ agencyCompanyId?: Guid (null = глобальный дефолт), retentionPercentagePoints: decimal (0.25..1.50, scale 2), comment?: string (<= 2000) }(../api/platform/create-platform-terms.md). - Система создаёт условия-черновик: проверка диапазона пунктов (INV-PT-1, иначе
REWARDS_PLATFORM_TERMS_RETENTION_OUT_OF_RANGE); запись вStatus = Draft(Version = 1) — в резолюции удержания черновик не участвует. Результат —{ termsId, status = Draft }. - Менеджер проверяет черновик и нажимает «Активировать»; фронт вызывает
POST /api/v1/platform/commission-terms/{termsId}/activate { expectedVersion }(../api/platform/activate-platform-terms.md). - Система активирует условия (INV-PT-2): guard
Status = Draft; предыдущиеActive-условия той же области (то же агентство либо глобальные) атомарно архивируются (ArchivedAt = now— конец их интервала действия); новые переходятDraft → Active(ActivatedAt = now— начало интервала). Единственность активных на область страхуют partial-unique индексы — гонка двух активаций даётREWARDS_PLATFORM_TERMS_ACTIVE_EXISTS(retry). Результат —{ termsId, status = Active, activatedAt, previousTermsId? }.
Фаза 2. Применение к начислению (автоматически, system)
crmзавершает сделку → consumerrewards(../consumers/crm-deal-completed.md) резолвит условия на моментasOf = CompletedAtсделки: область «агентство» (AgencyCompanyIdсделки, интервал[ActivatedAt, ArchivedAt)покрываетasOf) → область «глобально» → fallback 0 п.п. (A2). Алгоритм — ../domain/platform-commission-terms.md.- Guard конфигурации (INV-PT-4): если пункты удержания ≥
CommissionPercentприменённого правила застройщика (пул агентства ≤ 0) — начисление не создаётся, событие уходит в DLQ (A5). - В начисление снимается снапшот условий:
PlatformRetentionPercentagePoints,PlatformFeeAmount = база × п.п. / 100(banker's, 2 знака; база — поCalculationBaseправила, INV-10) иAppliedPlatformTermsId— последующая смена условий существующие начисления не пересчитывает (UC-RWD-003). - При подтверждении начисления застройщиком (UC-RWD-004) строится строка распределения
Platform=PlatformFeeAmount— первая из трёх строк (INV-4/5/9); политика агентства делит только пул (CommissionAmount − PlatformFeeAmount). Те же цифры агент видит заранее в витрине — расчёт дляcatalogиспользует ту же резолюцию условий (../api/internal/calculate-property-object-commission.md, UC-RWD-002).
Альтернативные Потоки
A1. Правка черновика
PUT /api/v1/platform/commission-terms/{termsId}(agencyCompanyId?,retentionPercentagePoints,comment?,expectedVersion) — только вDraft(../api/platform/update-platform-terms.md). Возвращается к шагу 4.
A2. Условий нет — fallback 0 п.п.
- На момент
CompletedAtнет ни агентских, ни глобальных действующих условий → начисление создаётся без удержания:PlatformRetentionPercentagePoints = 0,PlatformFeeAmount = 0,AppliedPlatformTermsId = null; строкаPlatformпри подтверждении строится с нулевой суммой. Инкрементируется warn-метрикаrewards_platform_terms_missing_total+ алерт (платформа теряет доход, пока условия не заведены). Не ошибка. Возвращается к шагу 8.
A3. Изменение действующих условий
- Поля
Active-условий иммутабельны (INV-PT-3,REWARDS_PLATFORM_TERMS_ACTIVE_IMMUTABLE) — воспроизводимость снапшотов начислений. Менеджер создаёт новыйDraftс новыми пунктами (шаги 2–3) и активирует его (шаг 5) — прежние условия архивируются автоматически, их интервал[ActivatedAt, ArchivedAt)остаётся источником asOf-резолюции для исторических сделок.
A4. Архив условий без замены
POST /api/v1/platform/commission-terms/{termsId}/archive { expectedVersion }(../api/platform/archive-platform-terms.md) — область остаётся без условий: новые начисления агентства пойдут по глобальному дефолту (если он активен) либо по fallback 0 п.п. (A2). СсылкиAppliedPlatformTermsIdиз существующих начислений живы (архив, не удаление). Завершается.
A5. Удержание съедает ставку правила (INV-PT-4)
- При создании начисления пункты удержания применимых условий ≥
CommissionPercentприменённого правила застройщика (пул агентства ≤ 0) → ни одно начисление по сделке (включая реферальное) не создаётся; событие завершения сделки уходит в DLQ с кодомREWARDS_PLATFORM_RETENTION_EXCEEDS_RULE- алерт.
- Менеджер ПИН разбирает конфликт: правит условия платформы (новый
Draft+Activate, A3) либо договаривается с застройщиком о правке правила; после исправления событие переигрывается из DLQ — начисления создаются по условиям, действующим наasOf = CompletedAt(ретроактивное исправление требует интервала действия, покрывающего прошлое). Завершается.
A6. Гонка двух активаций
- Два менеджера параллельно активируют условия одной области → побеждает первая зафиксированная
активация; проигравший получает
REWARDS_PLATFORM_TERMS_ACTIVE_EXISTS(409), перечитывает реестр (его черновик остаётсяDraft) и решает, актуальна ли его версия.
Постусловие
- В области (агентство / глобально) не более одних
Active-условий (INV-PT-2); история условий — цепочка архивных записей с непрерывными интервалами[ActivatedAt, ArchivedAt)для asOf-резолюции. - Новые начисления по сделкам с
CompletedAtв интервале действия получают снапшот условий (PlatformRetentionPercentagePoints,PlatformFeeAmount,AppliedPlatformTermsId); уже созданные начисления не пересчитаны. - Строка
Platformкаждого подтверждаемого начисления равнаPlatformFeeAmountснапшота; по гейту получения денег (UC-RWD-010) счётPlatformRevenueкошелька кредитуется этой суммой (ADR-0065).
Возможные Ошибки
| Код | HTTP | Условие | Поведение клиента |
|---|---|---|---|
403 FORBIDDEN | 403 | Нет rewards.platform-terms.manage | Скрыть управление условиями |
REWARDS_PLATFORM_TERMS_RETENTION_OUT_OF_RANGE | 400 | Пункты вне диапазона 0.25–1.50 (INV-PT-1) | Подсветить поле пунктов |
REWARDS_PLATFORM_TERMS_ACTIVE_EXISTS | 409 | Гонка активаций одной области (INV-PT-2, A6) | Перечитать реестр, повторить при необходимости |
REWARDS_PLATFORM_TERMS_ACTIVE_IMMUTABLE | 409 | Правка Active-условий (INV-PT-3, A3) | Создать новый черновик |
REWARDS_PLATFORM_TERMS_INVALID_STATUS_TRANSITION | 409 | Активация не из Draft / повторная активация | Обновить карточку условий |
REWARDS_PLATFORM_TERMS_NOT_FOUND | 404 | Условия не существуют | Вернуться к реестру |
REWARDS_PLATFORM_RETENTION_EXCEEDS_RULE | — (DLQ) | Удержание ≥ ставки применённого правила при начислении (INV-PT-4, A5) | Разбор Менеджером ПИН + replay из DLQ |
REWARDS_CONCURRENCY_CONFLICT | 409 | expectedVersion не совпал (параллельная мутация) | Перечитать и повторить |
Доменные События
| Событие | Когда поднимается | Subscribers |
|---|---|---|
PlatformTermsCreatedEvent | Успешное создание черновика (шаг 3) | in-proc аудит |
PlatformTermsActivatedEvent | Draft → Active (шаг 5) | in-proc аудит |
PlatformTermsArchivedEvent | * → Archived (шаг 5 автоархив, A4) | in-proc аудит |
Kafka-события условия не публикуют — применяются только внутри rewards при создании начисления
(../domain/platform-commission-terms.md).
Acceptance Criteria
| # | Критерий | Проверка |
|---|---|---|
| AC1 | Активация новых условий атомарно архивирует предыдущие активные той же области; активные всегда единственны (INV-PT-2) | параллельные активации → одна Active; partial-unique index |
| AC2 | Агентские условия побеждают глобальные при резолюции; глобальные применяются к агентствам без персональных условий | начисления двух агентств (с условиями / без) → разные AppliedPlatformTermsId |
| AC3 | Резолюция идёт на момент CompletedAt, а не обработки: сделка, завершённая до активации новых условий, получает старые | сделка с CompletedAt в интервале архивных условий → снапшот старых пунктов |
| AC4 | Смена условий не пересчитывает существующие начисления (снапшот) | активировать новые условия → перечитать начисление: PlatformFeeAmount прежний |
| AC5 | Без условий — fallback 0 п.п. (PlatformFeeAmount = 0, AppliedPlatformTermsId = null) + метрика rewards_platform_terms_missing_total (A2) | тест без активных условий |
| AC6 | Удержание ≥ ставки правила → событие в DLQ, начисления (оба) не созданы (INV-PT-4, A5); после исправления replay создаёт начисления | тест условий 1.50 п.п. при правиле 1% |
| AC7 | Пункты вне 0.25–1.50 отклоняются на создании/правке (INV-PT-1) | границы 0.24 / 1.51 → 400 |
| AC8 | Агентству условия не отдаются — виден только применённый снапшот в начислении | запрос реестра условий актором агентства → 403 |
Обратные ссылки
Автоссылки: где используется этот документ.
- Use Cases (1): US-реестр: Финансовый блок ПИН (US-FIN)
- scenarios (1): UC-OVR-010. От завершённой сделки до выплаты комиссии и реферального вознаграждения
- registries (1): Реестр use cases и user stories PIN
Связанные Документы
- Domain entity: ../domain/platform-commission-terms.md (поля, INV-PT-1..4, резолюция, stateDiagram).
- API методы: ../api/platform/create-platform-terms.md, ../api/platform/update-platform-terms.md, ../api/platform/activate-platform-terms.md, ../api/platform/archive-platform-terms.md, ../api/platform/list-platform-terms.md.
- Точка применения: ../consumers/crm-deal-completed.md (резолюция
и снапшот), ../domain/commission-accrual.md (снапшот-поля, строка
Platform, INV-10). - Превью для витрины: ../api/internal/calculate-property-object-commission.md (та же резолюция — net-цифры каталога, UC-RWD-002).
- Связанные UC: UC-RWD-003 (снапшот при начислении), UC-RWD-004 (строка
Platformпри подтверждении), UC-RWD-010 (кредитPlatformRevenueпо гейту денег). - ADR: 0066 (модель удержания — только процентные пункты), ADR-0052 (платформенная сущность).