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

UC-RWD-011. Корректировки начисления комиссии

Назначение

Описывает три вида first-class корректировок комиссионного начисления (INV-11, ADR-0067 п.4) — вместо отмены и пересоздания: (1) застройщик корректирует сумму в составе подтверждения; (2) ПИН-админ корректирует gross до получения денег; (3) руководитель агентства перераспределяет пул между Agency и Agent по конкретной сделке. Каждая корректировка обязана иметь причину и оставляет append-only аудит-строку (CommissionAccrualAdjustmentEntity); строка Platform (удержание ПИН) неприкосновенна. Связан с контекстом rewards.

Metadata

ПолеЗначение
IDUC-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 агентствомРуководитель агентствасуммы строк AgencyAgent (пул)Confirmed, MoneyReceivedAgent-строка не в неотменённом поручении; Σ двух строк = пул; строка Platform и CommissionAmount не меняются

Триггер

ПолеЗначение
ИсточникUI button
Триггерящий элементЛК застройщика → «Подтвердить с корректировкой»; админ-панель ПИН → карточка начисления → «Скорректировать сумму»; ЛК агентства → карточка начисления → «Перераспределить доли»

Основной Поток

Вид 1. Корректировка застройщиком в составе подтверждения

  1. Менеджер застройщика при подтверждении (UC-RWD-004) видит расхождение суммы с договором и передаёт в команде confirm adjustedAmount + обязательную adjustmentReason (../api/admin/confirm-commission-accrual.md).
  2. Система в одной операции: фиксирует исходную сумму в OriginalCommissionAmount (однократно, при первой корректировке), заменяет CommissionAmount, создаёт аудит-строку (Kind = GrossAmount, старая/новая сумма, причина, актор) и строит три строки распределения уже от новой суммы: Platform = PlatformFeeAmount (не пересчитывается — удержание считается от базы цены, INV-10), пул = новая сумма − PlatformFeeAmount, деление пула — по политике. Guard: новая сумма > PlatformFeeAmount (иначе REWARDS_ACCRUAL_ADJUSTMENT_FORBIDDEN).

Вид 2. Корректировка gross ПИН-админом

  1. ПИН-админ (расхождение с платёжкой при сверке акта, договорённость с застройщиком, ошибка данных) вызывает POST /api/v1/platform/commission-accruals/{accrualId}/adjust { newAmount, reason, expectedVersion } (../api/platform/adjust-commission-accrual.md).
  2. Система проверяет guard-матрицу (вид 2): статус, свободные строки, отсутствие в не-отменённом акте, пул > 0. В одном согласованном изменении: OriginalCommissionAmount (при первой корректировке), CommissionAmount = newAmount, аудит-строка GrossAmount; в Confirmed — пересборка распределения (строка Platform неизменна, пул пересчитан и переделён по применённой политике, Σ трёх строк = новой сумме, INV-5); в PendingConfirmation строк ещё нет — распределение построится при подтверждении от актуальной суммы. Интеграционные события не публикуются (статус не меняется); расхождение с уже собранным Draft-актом поймает регистрация (REWARDS_RECEIPT_ITEM_STALE, UC-RWD-010 A2).

Вид 3. Перераспределение пула агентством

  1. Руководитель агентства (индивидуальная договорённость, бонус за сложную сделку, исправление ошибки политики) вызывает POST /api/v1/agency/commission-accruals/{accrualId}/adjust-distribution { agentAmount, agencyAmount, reason, expectedVersion } (../api/agency/adjust-accrual-distribution.md).
  2. Система проверяет guard-матрицу (вид 3) и сверку пула: agentAmount + agencyAmount = пул (CommissionAmount − PlatformFeeAmount), иначе REWARDS_ACCRUAL_DISTRIBUTION_SUM_INVALID. В одном согласованном изменении: новые суммы строк Agency/Agent (нулевая доля допустима), аудит-строка (Kind = Distribution, доля агента до/после, причина, актор). Строка Platform, CommissionAmount, PlatformFeeAmount и статус не меняются ни при каких входных данных.
  3. Во всех видах: Version + 1; полная история корректировок начисления видна агентству в проекции (Adjustments[]../api/README.md, AdjustmentModel) и служит основой отчётности по корректировкам.

Альтернативные Потоки

A1. Корректировка после получения денег

  1. Начисление в MoneyReceived/Paid: gross неизменяем (виды 1–2 → REWARDS_ACCRUAL_ADJUSTMENT_FORBIDDEN) — ошибки лечатся только компенсирующим ручным начислением (../api/admin/create-manual-accrual.md, финансовая история неизменяема, ADR-0067).
  2. Перераспределение пула (вид 3) в MoneyReceived допустимо, пока Agent-строка свободна, но кошельки уже кредитованы по прежнему распределению — расхождение выравнивается ручной корректировкой оператора ПИН в wallet (операция Adjustment, ADR-0065); объём таких правок контролирует метрика rewards_distribution_adjust_after_receipt_total. Рекомендованный порядок — править доли до регистрации акта.

A2. Начисление в акте или строки в поручении

  1. Начисление входит в не-отменённый акт (вид 2) → сначала исключить позицию из Draft-акта (UC-RWD-010), затем корректировать. Agent-строка в неотменённом поручении (виды 2–3) → сначала освободить строку (Reject/Cancel поручения или правка состава черновика, UC-RWD-005), затем корректировать. Иначе — REWARDS_ACCRUAL_ADJUSTMENT_FORBIDDEN.

A3. Повторные корректировки

  1. Любое число последовательных корректировок допустимо в рамках guard-ов: OriginalCommissionAmount фиксируется только первой корректировкой gross и далее не перезаписывается; каждая корректировка добавляет свою аудит-строку (OldAmount = значение после предыдущей).

A4. Гонки

  1. Корректировка против включения в акт/поручение, подтверждения или отмены — все мутируют один агрегат: оптимистическая блокировка пропускает одну операцию, проигравший получает 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 FORBIDDEN403Нет permission соответствующего вида (guard-матрица)Скрыть действие
REWARDS_ACCRUAL_NOT_FOUND404Начисление не существует / чужой tenant (вид 3) / чужой застройщик (вид 1)Вернуться к списку
REWARDS_ACCRUAL_ADJUSTMENT_REASON_REQUIRED400Reason пуст/whitespace (INV-11)Подсветить поле причины
REWARDS_ACCRUAL_ADJUSTMENT_FORBIDDEN409Статус вне guard-матрицы; строки в поручении; начисление в акте; пул ≤ 0 (INV-11, A1/A2)Показать пояснение и порядок разблокировки
REWARDS_ACCRUAL_DISTRIBUTION_SUM_INVALID409agentAmount + agencyAmount ≠ пулу (вид 3, INV-5/10)Пересчитать по актуальному пулу
REWARDS_CURRENCY_MISMATCH400Валюта корректировки ≠ валюте начисления (INV-6)Исправить вход
REWARDS_CONCURRENCY_CONFLICT409Параллельная мутация начисления (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[] и упорядочена по временичтение проекции начисления

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

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

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