UC-RWD-011. Корректировки начисления комиссии
Назначение
Описывает три вида first-class корректировок комиссионного начисления (INV-11, ADR-0067 п.4) — вместо
отмены и пересоздания: (1) застройщик корректирует сумму в составе подтверждения; (2) ПИН-админ
корректирует gross до получения денег; (3) руководитель агентства перераспределяет пул между Agency и
Agent по конкретной сделке. Каждая корректировка обязана иметь причину и оставляет append-only
аудит-строку (CommissionAccrualAdjustmentEntity); строка Platform (удержание ПИН) неприкосновенна.
Связан с контекстом rewards.
Metadata
| Поле | Значение |
|---|---|
| ID | UC-RWD-011 |
| Контекст | rewards (см. docs/06-services/rewards/) |
| Тип | альтернативный (корректирующие операции финансового контура) |
| Статус | draft |
Актор
| Поле | Значение |
|---|---|
| Роль | Менеджер застройщика (вид 1); ПИН-админ (вид 2); Руководитель/администратор агентства (вид 3) |
| Permissions / scope | Вид 1 — rewards.accruals.confirm (scope — организация застройщика, cross-tenant по DeveloperCompanyId); вид 2 — rewards.accruals.adjust (платформенный scope, cross-tenant); вид 3 — rewards.commission-policy.manage (scope — организация агентства, in-tenant) |
| Tenant | Начисление живёт в tenant агентства (решение №2 README); застройщик и ПИН-админ действуют по cross-tenant путям (ADR-0052) |
| Record-level | Вид 1 — DeveloperCompanyId начисления = компания актора |
Предусловие
- Начисление существует; статус допускает соответствующий вид корректировки (guard-матрица ниже).
- У актора — актуальная
Versionначисления (optimistic concurrency). - Причина корректировки сформулирована — без непустой
Reasonлюбая корректировка отклоняется (REWARDS_ACCRUAL_ADJUSTMENT_REASON_REQUIRED).
Guard-матрица корректировок (INV-11)
| Вид | Актор | Что меняется | Допустимые статусы | Дополнительные guard-ы |
|---|---|---|---|---|
| 1. Gross при подтверждении | Менеджер застройщика | CommissionAmount (в команде confirm) | PendingConfirmation (в момент перехода в Confirmed) | скорректированная сумма > PlatformFeeAmount (пул > 0) |
| 2. Gross ПИН-админом | ПИН-админ | CommissionAmount (+ пересборка трёх строк в Confirmed) | PendingConfirmation, Confirmed | строки не в неотменённом поручении; начисление не в не-отменённом акте; новая сумма > PlatformFeeAmount; после MoneyReceived — запрещено |
| 3. Distribution агентством | Руководитель агентства | суммы строк Agency ↔ Agent (пул) | Confirmed, MoneyReceived | Agent-строка не в неотменённом поручении; Σ двух строк = пул; строка Platform и CommissionAmount не меняются |
Триггер
| Поле | Значение |
|---|---|
| Источник | UI button |
| Триггерящий элемент | ЛК застройщика → «Подтвердить с корректировкой»; админ-панель ПИН → карточка начисления → «Скорректировать сумму»; ЛК агентства → карточка начисления → «Перераспределить доли» |
Основной Поток
Вид 1. Корректировка застройщиком в составе подтверждения
- Менеджер застройщика при подтверждении (UC-RWD-004) видит расхождение суммы с договором и передаёт
в команде confirm
adjustedAmount+ обязательнуюadjustmentReason(../api/admin/confirm-commission-accrual.md). - Система в одной операции: фиксирует исходную сумму в
OriginalCommissionAmount(однократно, при первой корректировке), заменяетCommissionAmount, создаёт аудит-строку (Kind = GrossAmount, старая/новая сумма, причина, актор) и строит три строки распределения уже от новой суммы:Platform=PlatformFeeAmount(не пересчитывается — удержание считается от базы цены, INV-10), пул = новая сумма −PlatformFeeAmount, деление пула — по политике. Guard: новая сумма >PlatformFeeAmount(иначеREWARDS_ACCRUAL_ADJUSTMENT_FORBIDDEN).
Вид 2. Корректировка gross ПИН-админом
- ПИН-админ (расхождение с платёжкой при сверке акта, договорённость с застройщиком, ошибка данных)
вызывает
POST /api/v1/platform/commission-accruals/{accrualId}/adjust { newAmount, reason, expectedVersion }(../api/platform/adjust-commission-accrual.md). - Система проверяет guard-матрицу (вид 2): статус, свободные строки, отсутствие в не-отменённом акте,
пул > 0. В одном согласованном изменении:
OriginalCommissionAmount(при первой корректировке),CommissionAmount = newAmount, аудит-строкаGrossAmount; вConfirmed— пересборка распределения (строкаPlatformнеизменна, пул пересчитан и переделён по применённой политике, Σ трёх строк = новой сумме, INV-5); вPendingConfirmationстрок ещё нет — распределение построится при подтверждении от актуальной суммы. Интеграционные события не публикуются (статус не меняется); расхождение с уже собраннымDraft-актом поймает регистрация (REWARDS_RECEIPT_ITEM_STALE, UC-RWD-010 A2).
Вид 3. Перераспределение пула агентством
- Руководитель агентства (индивидуальная договорённость, бонус за сложную сделку, исправление ошибки
политики) вызывает
POST /api/v1/agency/commission-accruals/{accrualId}/adjust-distribution { agentAmount, agencyAmount, reason, expectedVersion }(../api/agency/adjust-accrual-distribution.md). - Система проверяет guard-матрицу (вид 3) и сверку пула:
agentAmount + agencyAmount= пул (CommissionAmount − PlatformFeeAmount), иначеREWARDS_ACCRUAL_DISTRIBUTION_SUM_INVALID. В одном согласованном изменении: новые суммы строкAgency/Agent(нулевая доля допустима), аудит-строка (Kind = Distribution, доля агента до/после, причина, актор). СтрокаPlatform,CommissionAmount,PlatformFeeAmountи статус не меняются ни при каких входных данных. - Во всех видах:
Version + 1; полная история корректировок начисления видна агентству в проекции (Adjustments[]— ../api/README.md,AdjustmentModel) и служит основой отчётности по корректировкам.
Альтернативные Потоки
A1. Корректировка после получения денег
- Начисление в
MoneyReceived/Paid: gross неизменяем (виды 1–2 →REWARDS_ACCRUAL_ADJUSTMENT_FORBIDDEN) — ошибки лечатся только компенсирующим ручным начислением (../api/admin/create-manual-accrual.md, финансовая история неизменяема, ADR-0067). - Перераспределение пула (вид 3) в
MoneyReceivedдопустимо, покаAgent-строка свободна, но кошельки уже кредитованы по прежнему распределению — расхождение выравнивается ручной корректировкой оператора ПИН вwallet(операцияAdjustment, ADR-0065); объём таких правок контролирует метрикаrewards_distribution_adjust_after_receipt_total. Рекомендованный порядок — править доли до регистрации акта.
A2. Начисление в акте или строки в поручении
- Начисление входит в не-отменённый акт (вид 2) → сначала исключить позицию из
Draft-акта (UC-RWD-010), затем корректировать.Agent-строка в неотменённом поручении (виды 2–3) → сначала освободить строку (Reject/Cancelпоручения или правка состава черновика, UC-RWD-005), затем корректировать. Иначе —REWARDS_ACCRUAL_ADJUSTMENT_FORBIDDEN.
A3. Повторные корректировки
- Любое число последовательных корректировок допустимо в рамках guard-ов:
OriginalCommissionAmountфиксируется только первой корректировкой gross и далее не перезаписывается; каждая корректировка добавляет свою аудит-строку (OldAmount= значение после предыдущей).
A4. Гонки
- Корректировка против включения в акт/поручение, подтверждения или отмены — все мутируют один агрегат:
оптимистическая блокировка пропускает одну операцию, проигравший получает
REWARDS_CONCURRENCY_CONFLICT(или guard-код) и перечитывает состояние. Если корректировка gross успела раньше включения в акт — расхождение поймает регистрация акта (REWARDS_RECEIPT_ITEM_STALE).
Постусловие
- Суммы начисления/долей соответствуют внесённой корректировке; инварианты сохранены: Σ трёх строк =
CommissionAmount(INV-5), строкаPlatform=PlatformFeeAmount(INV-10), пул > 0. - На каждую применённую корректировку — ровно одна append-only аудит-строка с видом
(
GrossAmount/Distribution), старым/новым значением, обязательной причиной и актором; история не редактируется и не удаляется. OriginalCommissionAmountхранит исходную автосчитанную сумму (если gross корректировался) — расчёт воспроизводим и объясним.
Возможные Ошибки
| Код | HTTP | Условие | Поведение клиента |
|---|---|---|---|
403 FORBIDDEN | 403 | Нет permission соответствующего вида (guard-матрица) | Скрыть действие |
REWARDS_ACCRUAL_NOT_FOUND | 404 | Начисление не существует / чужой tenant (вид 3) / чужой застройщик (вид 1) | Вернуться к списку |
REWARDS_ACCRUAL_ADJUSTMENT_REASON_REQUIRED | 400 | Reason пуст/whitespace (INV-11) | Подсветить поле причины |
REWARDS_ACCRUAL_ADJUSTMENT_FORBIDDEN | 409 | Статус вне guard-матрицы; строки в поручении; начисление в акте; пул ≤ 0 (INV-11, A1/A2) | Показать пояснение и порядок разблокировки |
REWARDS_ACCRUAL_DISTRIBUTION_SUM_INVALID | 409 | agentAmount + agencyAmount ≠ пулу (вид 3, INV-5/10) | Пересчитать по актуальному пулу |
REWARDS_CURRENCY_MISMATCH | 400 | Валюта корректировки ≠ валюте начисления (INV-6) | Исправить вход |
REWARDS_CONCURRENCY_CONFLICT | 409 | Параллельная мутация начисления (A4) | Перечитать и повторить |
Acceptance Criteria
| # | Критерий | Проверка |
|---|---|---|
| AC1 | Вид 1: подтверждение с adjustedAmount строит три строки от новой суммы; OriginalCommissionAmount зафиксирован; аудит-строка создана | тест confirm с корректировкой (UC-RWD-004) |
| AC2 | Вид 2 в Confirmed: строка Platform неизменна, пул пересчитан и переделён по применённой политике, Σ = новой сумме | тест adjust 100 000 → 90 000 при PlatformFee = 10 000 |
| AC3 | Вид 3: перераспределяется только пул; вход с Σ ≠ пулу отклоняется; Platform/gross не тронуты никаким входом | тест adjust-distribution + попытка тронуть Platform |
| AC4 | Без причины любая корректировка отклоняется (400), состояние не изменено | пустая/пробельная Reason во всех трёх видах |
| AC5 | После MoneyReceived gross неизменяем (A1); distribution допустим при свободной строке + метрика after-receipt | тесты по статусам guard-матрицы |
| AC6 | Начисление в акте / строка в поручении блокируют корректировку (A2) | включить в Draft-акт → adjust → 409 |
| AC7 | Повторная корректировка не перезаписывает OriginalCommissionAmount; каждая оставляет свою аудит-строку (A3) | две последовательные корректировки → 2 строки аудита |
| AC8 | Пул обязан остаться положительным: newAmount <= PlatformFeeAmount отклоняется (INV-11) | граничный тест суммы |
| AC9 | Корректировка gross между включением в акт и регистрацией ловится REWARDS_RECEIPT_ITEM_STALE (A4) | сквозной тест с UC-RWD-010 |
| AC10 | История корректировок видна агентству в Adjustments[] и упорядочена по времени | чтение проекции начисления |
Обратные ссылки
Автоссылки: где используется этот документ.
- Use Cases (4): UC-RWD-016. Застройщик подтверждает начисление после смены исполнителя, UC-RWD-017. Уволенный агент: судьба заработанных комиссий, US-реестр: Владелец агентства (US-OWN-AG), US-реестр: Финансовый блок ПИН (US-FIN)
- registries (1): Реестр use cases и user stories PIN
Связанные Документы
- Domain entity: ../domain/commission-accrual.md (INV-5/6/10/11,
CommissionAccrualAdjustmentEntity, enumCommissionAdjustmentKind). - API методы: ../api/admin/confirm-commission-accrual.md (вид 1), ../api/platform/adjust-commission-accrual.md (вид 2), ../api/agency/adjust-accrual-distribution.md (вид 3).
- Влияние на акт: ../domain/platform-receipt.md
(
REWARDS_RECEIPT_ITEM_STALE); выравнивание кошелька — ../../wallet/README.md (операцияAdjustment). - Модели проекций (
AdjustmentModel,CommissionAccrualModel): ../api/README.md. - Связанные UC: UC-RWD-004 (подтверждение — вид 1), UC-RWD-010 (гейт денег и сверка сумм), UC-RWD-005 (освобождение строк поручения).
- ADR: 0067 п.4 (first-class
корректировки, аудит), 0066
(неприкосновенность строки
Platform), ADR-0052 (cross-tenant пути доступа).