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

UC-RWD-005. Агентство настраивает распределение и формирует платёжное поручение

Назначение

Описывает сценарий комиссионной политики агентства (матрица «Агенство» 5.2–5.5): руководитель агентства настраивает правила распределения комиссии (удержание агентства в % или фиксированной суммой, с персональными оверрайдами по агентам; политика делит пул — комиссию за вычетом удержания ПИН, ADR-0066), затем формирует платёжное поручение — собирает свободные доли агентов по начислениям, деньги по которым уже получены от застройщика (Status = MoneyReceived, гейт ADR-0067 пройден — UC-RWD-010), утверждает поручение и после фактической выплаты (вне платформы — исполнение платежей отложено, решение №9 ТЗ) отмечает его выплаченным; по событию выплаты кошельки агентов дебетуются (ADR-0065). Связан с контекстом rewards.

Metadata

ПолеЗначение
IDUC-RWD-005
Контекстrewards (см. docs/06-services/rewards/)
Типосновной
Статусdraft

Актор

ПолеЗначение
РольАгентство (руководитель/администратор агентства; отметка выплаты — руководитель/бухгалтер)
Permissions / scopeПолитика — rewards.commission-policy.manage; создание/состав поручения — rewards.payouts.manage; утверждение/отметка выплаты/отклонение — rewards.payouts.approve. Scope — Organization(CompanyId агентства)
TenantTenantId = CompanyId агентства (Type ∈ {Agency, Broker, Pin}, ADR-0052); политика, поручение и все захватываемые строки распределения — в этом tenant (INV-9 payout)
Record-levelАгент видит только свои позиции поручений (rewards.payouts.view-own, record-level AgentUserId) — читательская проекция, не этот сценарий

Предусловие

  • Компания-агентство Status = Active; актор — руководитель/администратор.
  • Для фазы 2: существуют начисления Status = MoneyReceived (деньги от застройщика получены — зарегистрирован акт поступления средств, UC-RWD-010) со свободными Agent-строками распределения (PayoutOrderItemId is null). Начисления в Confirmed в поручение не попадают — гейт денег не пройден (ADR-0067).
  • Для валидации оверрайдов политики: пользователи-агенты принадлежат компании (identity).

Триггер

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

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

Фаза 1. Настройка комиссионной политики

  1. Руководитель открывает «Политика распределения» (GET /rewards/agency/policies, permission rewards.commission-policy.view) и нажимает «Создать политику».
  2. Фронт вызывает POST /rewards/agency/policies с телом CreateAgencyPolicyForm { name (1..256), description? (<= 2000), rules: { defaultRule: { kind: Percent | FixedAmount, value: decimal (Percent: 0..100; FixedAmount: 0..100000000, scale 2), currency?: string (ISO-4217, обязательна при FixedAmount, null при Percent) }, agentOverrides?: [ { agentUserId: Guid, rule: { kind, value, currency? } } ] (<= 1000, agentUserId уникальны) } }.
  3. Система создаёт политику-черновик:
    • Доступ. rewards.commission-policy.manage в scope Organization(TenantId агентства).
    • Проверка входа. INV-2 (диапазоны value по kind; currency задана ⇔ FixedAmount) → REWARDS_POLICY_RULE_INVALID; уникальность agentUserId в оверрайдах (часть INV-3) → REWARDS_POLICY_OVERRIDE_INVALID. Принадлежность агентов компании проверяется при активации (шаг 5).
    • Создание. Политика создаётся в статусе Draft (Version = 1): Name/Description и Rules { DefaultRule, AgentOverrides } — из формы, TenantId — агентство актора. Поднимается доменное событие AgencyPolicyCreatedEvent; Kafka-событий у политики нет (agency-commission-policy.md).
    • Результат. { policyId, status = Draft }.
  4. Руководитель проверяет черновик и нажимает «Активировать»; фронт вызывает POST /rewards/agency/policies/{policyId}/activate { rowVersion }.
  5. Система активирует политику:
    • Доступ. rewards.commission-policy.manage. Политика существует в tenant агентства; guard Status = Draft.
    • INV-3 (агенты оверрайдов). Все AgentOverrides[].AgentUserId — активные пользователи компании TenantId (проверка состава агентства в identity); иначе — REWARDS_POLICY_OVERRIDE_INVALID (A7).
    • Атомарная смена (INV-1). Текущая активная политика (если есть) переходит Active → Archived (DeletedAt = now); новая переходит Draft → Active (EffectiveFrom = now, Version++). Поднимается доменное событие AgencyPolicyActivatedEvent; Kafka-событий нет. Архив старой и активация новой — в одном согласованном изменении; гонка двух активаций ловится частично-уникальным индексом ux_agency_policies_tenant_activeREWARDS_POLICY_ACTIVE_EXISTS (retry).
    • Результат. { policyId, status = Active, effectiveFrom, previousPolicyId? }.
  6. Со следующего подтверждения начисления (UC-RWD-004) распределение считается по новой политике; уже подтверждённые не пересчитываются (AppliedPolicyId зафиксирован).

Фаза 2. Платёжное поручение

  1. Руководитель открывает «Выплаты» → «Сформировать поручение», задаёт период; фронт вызывает POST /rewards/agency/payout-orders с телом CreatePayoutOrderForm { periodFrom: DateTimeOffset, periodTo: DateTimeOffset (> periodFrom), title?: string (<= 256) }.
  2. Система формирует черновик поручения:
    • Доступ. rewards.payouts.manage. Проверка периода (periodTo > periodFrom).
    • Автосборка (INV-1 payout). Захватываются свободные Agent-строки распределения агентства: RecipientType = Agent, PayoutOrderItemId is null, Amount.Value > 0, родительское начисление Status = MoneyReceived (гейт получения денег пройден, ADR-0067) и DealCompletedAt ∈ [periodFrom; periodTo). Захват без взаимной блокировки с параллельным поручением — каждая строка достаётся ровно одному поручению (A6).
    • Сборка позиций. Поручение создаётся в статусе Draft: Number = PO-{yyyy}-{seq} (последовательность на tenant-год), Title/PeriodFrom/PeriodTo — из формы. Захваченные строки группируются по AgentUserId → на каждого агента PayoutOrderItemEntity { AgentUserId, Amount = Σ строк, DistributionsCount = count } (INV-2 — один агент = одна позиция; INV-4 — единая валюта, иначе REWARDS_CURRENCY_MISMATCH); каждой захваченной строке проставляется PayoutOrderItemId; корень: TotalAmount = Σ Item.Amount, ItemsCount = count(Items) (INV-3). Поднимается доменное событие PayoutOrderCreatedEvent; Kafka на создании черновика не публикуется. Поручение и привязка строк — в одном согласованном изменении.
    • Результат. { orderId, number, status = Draft, totalAmount, itemsCount, items: [ { agentUserId, amount, distributionsCount } ] }.
  3. Руководитель проверяет состав (при необходимости — A1) и нажимает «Утвердить»; фронт вызывает POST /rewards/agency/payout-orders/{orderId}/approve { rowVersion }.
  4. Система утверждает поручение: доступ rewards.payouts.approve; guard INV-6 (Status = Draft, ItemsCount >= 1); переход Draft → PendingPayment («ожидается», матрица 5.5), состав заморожен (INV-5), ApprovedAt/ApprovedByUserId. Поднимается доменное событие PayoutOrderApprovedEvent; в одном согласованном изменении публикуется PayoutOrderStatusChangedKafkaEvent (topic pin.rewards.payout-order-status-changed.v1, key = Id; payload Id, TenantId, Number, FromStatus = Draft, ToStatus = PendingPayment, TotalAmount, ItemsCount, PaidAt = null, RejectReason = null, Version). Результат — { orderId, status = PendingPayment, approvedAt }.
  5. Бухгалтерия выгружает сводный отчёт (GET /rewards/agency/payout-orders/{orderId} — позиции по агентам, суммы; реквизиты в rewards не хранятся — payout-order.md) и проводит платежи вне платформы (исполнение отложено, решение №9 ТЗ).
  6. После фактической выплаты руководитель/бухгалтер нажимает «Отметить выплату»; фронт вызывает POST /rewards/agency/payout-orders/{orderId}/mark-paid { rowVersion }.
  7. Система отмечает выплату (каскад INV-7): доступ rewards.payouts.approve; guard Status = PendingPayment. Поручение переходит PendingPayment → Paid, PaidAt проставляется поручению, каждой его позиции и каждой привязанной строке распределения; для каждого затронутого начисления, у которого все Agent-строки выплачены (PaidAt != null), начисление переходит MoneyReceived → Paid (INV-7 commission-accrual.md). В одном согласованном изменении публикуются PayoutOrderStatusChangedKafkaEvent (ToStatus = Paid, PaidAt, Items[] { PayoutOrderItemId, RecipientUserId, Amount, PaidAt }) и CommissionAccrualStatusChangedKafkaEvent (MoneyReceived → Paid) на каждое переведённое начисление. Результат — { orderId, status = Paid, paidAt, paidAccrualIds[] }.
  8. notifications уведомляет агентов о выплате их позиций и руководителя о смене статуса; wallet по событию Paid дебетует счета AgentCommission агентов на суммы позиций (Items[], идемпотентность (PayoutDebit, ItemId), ADR-0065 — кредит счетов произошёл раньше, по гейту денег UC-RWD-010); история выплат агентства (GET /rewards/agency/payout-orders — фильтры по статусу/периоду) показывает поручение как «выплачено»; в ЛК агента комиссия переходит в «получили».

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

A1. Правка состава черновика поручения

  1. PUT /rewards/agency/payout-orders/{orderId}/items { addDistributionIds?: Guid[], removeDistributionIds?: Guid[], rowVersion } — guard INV-5 (Status = Draft, иначе REWARDS_PAYOUT_COMPOSITION_LOCKED); добавляемые строки проверяются как при автосборке (свободны, родитель MoneyReceived, тот же tenant — INV-1/9, иначе REWARDS_PAYOUT_DISTRIBUTION_UNAVAILABLE); исключаемые — PayoutOrderItemId → null; пересборка позиций и пересчёт TotalAmount/ItemsCount (INV-3); позиция без строк удаляется. Возвращается к шагу 9.

A2. Пустая выборка за период

  1. Свободных строк за период не нашлось (в т.ч. когда начисления ещё в Confirmed — деньги от застройщика не получены, гейт ADR-0067) → поручение создаётся пустым Draft (ItemsCount = 0, TotalAmount = 0); фронт показывает «нет долей, доступных к выплате, за период». Утверждение заблокировано guard-ом INV-6 (ItemsCount >= 1). Руководитель меняет период (пересоздаёт), ждёт регистрации акта (UC-RWD-010) или добавляет строки позже (A1), либо отменяет черновик (A3).

A3. Отмена черновика

  1. POST /rewards/agency/payout-orders/{orderId}/cancel { rowVersion } — guard Status = Draft; поручение переходит в Cancelled, все привязанные строки освобождаются (PayoutOrderItemId → null, INV-8) и доступны следующему поручению. Kafka-событие не публикуется (черновик никому не анонсировался). Завершается.

A4. Отклонение утверждённого поручения

  1. Бухгалтерия/руководитель отклоняет: POST /rewards/agency/payout-orders/{orderId}/reject { reason: string (1..1000, обязателен — иначе REWARDS_PAYOUT_REJECT_REASON_REQUIRED), rowVersion } — guard Status = PendingPayment; поручение переходит в Rejected («отклонено», матрица 5.5), RejectedAt/RejectReason; строки освобождаются (INV-8); публикуется PayoutOrderStatusChangedKafkaEvent (ToStatus = Rejected, RejectReason). Освобождённые строки можно включить в новое поручение (шаг 7). Завершается.

A5. Начисление выбыло до включения в поручение

  1. Начисление, отменённое из Confirmed (UC-RWD-004 A6 / UC-RWD-003 A4) до регистрации акта, в автосборку не попадает (родитель не MoneyReceived). Начисление в MoneyReceived не отменяется вовсе (INV-8 accrual, ADR-0067) — конфликт «отмена против сборки поручения» после гейта денег исключён; корректировка долей пула возможна, пока Agent-строка свободна (UC-RWD-011, вид 3).

A6. Конкурентное формирование двух поручений

  1. Два менеджера параллельно создают поручения за пересекающиеся периоды: захват при автосборке гарантирует, что каждая свободная строка достаётся ровно одному поручению (INV-1 payout); второе поручение получает оставшиеся строки без ошибки блокировки.

A7. Агент оверрайда не принадлежит компании

  1. На шаге 5 проверка в identity не подтвердила AgentUserIdREWARDS_POLICY_OVERRIDE_INVALID (400 со списком невалидных id). Руководитель исправляет оверрайды черновика и повторяет активацию.

Постусловие

  • Фаза 1: у агентства ровно одна Active политика (INV-1 policy); предыдущая — Archived; применённые ранее распределения не пересчитаны.
  • Фаза 2: PayoutOrderEntity (Kind = AgencyCommission, Status = Paid) с позициями по агентам и Number для бухгалтерии; привязанные строки распределения и позиции имеют PaidAt; начисления, у которых все Agent-строки выплачены, — в Status = Paid («получили» в ЛК агента; переход только из MoneyReceived, INV-7).
  • Кошельки агентов дебетованы по позициям (wallet, асинхронно по событию Paid — окно секунды); баланс сходится: кредит по гейту денег (UC-RWD-010) − дебет по выплате.
  • История выплат (матрица 5.5) — список поручений со статусами PendingPayment/Paid/Rejected, датами и суммами; события статусов опубликованы атомарно.

Согласованность и межсервисное взаимодействие

  • Ожидает на входе. Фаза 1 (активация) синхронно обращается в identity за составом пользователей агентства — проверка AgentOverrides[].AgentUserId (INV-3, A7); недоступность identity → активация не проходит (повтор позже), уже активная политика продолжает применяться, начисления не блокируются. Фаза 2 (автосборка) опирается на свободные Agent-строки распределения начислений в MoneyReceived (строки созданы при подтверждении UC-RWD-004, гейт денег пройден регистрацией акта UC-RWD-010): PayoutOrderItemId is null, Amount.Value > 0, родитель Status = MoneyReceived, DealCompletedAt ∈ [PeriodFrom; PeriodTo). Эти строки на момент захвата иммутабельны — суммы зафиксированы при подтверждении (правка долей пула возможна только пока строка свободна, UC-RWD-011). Kafka-входов у сценария нет: политика и поручение управляются командами руководителя.
  • Предоставляет на выходе. PayoutOrderStatusChangedKafkaEvent (topic pin.rewards.payout-order-status-changed.v1, key = Id поручения, ContractVersion = 1) на переходах Approve (шаг 10), MarkPaid (шаг 13, с Items[]), Reject (A4) — ключ = Id гарантирует порядок переходов одного поручения у потребителя. Каскад MarkPaid дополнительно публикует по каждому переведённому начислению CommissionAccrualStatusChangedKafkaEvent (MoneyReceived → Paid) (topic pin.rewards.commission-accrual-status-changed.v1, key = Id начисления). Политика Kafka не публикует (только доменные AgencyPolicyCreated/Activated/Archived in-proc). Потребители: notifications; wallet — по Paid дебетует счета AgentCommission получателей на суммы Items[] (идемпотентность (PayoutDebit, ItemId), недостаток баланса — DLQ + алерт, ADR-0065); self-consume проекцией AgentPerformance — переход начисления → Paid даёт CommissionPaidTotal += CommissionAmount (agent-performance.md). Создание/правка/отмена черновика поручения Kafka не анонсирует (A2/A3 — черновик никому не виден).
  • Окно eventual-consistency. Синхронно руководитель видит смену статуса и полный каскад сразу (одно согласованное изменение). Асинхронно (лаг доставки < 1 мин штатно, alert > 5 мин): агенты получают уведомления о выплате их позиций; сводки ЛК агента (get-my-commission-summary) и проекция AgentPerformance переводят суммы «получим → получили» после применения событий. В промежутке агент видит прежнюю сводку — лаг проекции, не ошибка.
  • Идемпотентность. Отдельные ключи не нужны — идемпотентность естественная через guard-статусы: повтор Activate упирается в guard Draft; повтор Approve — в guard Draft; повтор MarkPaid — в guard PendingPayment; повтор Reject/Cancel — в соответствующий guard (REWARDS_PAYOUT_INVALID_STATUS_TRANSITION). Гонка двух активаций ловится частично-уникальным индексом ux_agency_policies_tenant_active (REWARDS_POLICY_ACTIVE_EXISTS, retry). Автосборка захватывает свободные строки под блокировкой — каждая строка достаётся ровно одному поручению даже при параллельной сборке (A6).
  • Конкурентность (кто побеждает). Все переходы политики и поручения защищены оптимистической блокировкой по rowVersion: побеждает первая зафиксированная мутация, проигравший получает 409 и перечитывает актуальный статус. Две параллельные активации → ровно одна Active (INV-1 policy). Начисление в MoneyReceived не отменяется вовсе (INV-8 accrual, ADR-0067) — конфликт «отмена против сборки» после гейта денег исключён (A5); гонка «корректировка долей ↔ захват строки поручением» разрешается блокировкой начисления (UC-RWD-011 A4).
  • Восстановление. События статусов доставляются at-least-once, потребители идемпотентны; публикация события и мутация неразделимы (одно согласованное изменение) — «выплатили, но не уведомили» невозможно. Ошибочно утверждённое поручение → Reject (освобождает строки, INV-8) и пересборка. Ошибочно выплаченное (Paid) — терминально: компенсация вне rewards (сторнирующее ручное начисление застройщика, UC-RWD-003 A3, и новое поручение на оставшиеся доли). Отклонённое/отменённое поручение возвращает свои строки в пул свободных — они попадут в следующую автосборку (A4/A3).

Возможные Ошибки

КодHTTPУсловиеПоведение клиента
403 FORBIDDEN403Нет rewards.commission-policy.manage / rewards.payouts.manage / rewards.payouts.approveСкрыть соответствующие действия
ValidationError400Формат формы / periodTo <= periodFrom / пустая причина отклоненияПодсветить поля
REWARDS_POLICY_RULE_INVALID400value вне диапазона по kind; currency не согласована с FixedAmount (INV-2)Подсветить правило
REWARDS_POLICY_OVERRIDE_INVALID400Дубль agentUserId / агент не из компании (INV-3, A7)Показать невалидные оверрайды
REWARDS_POLICY_ACTIVE_EXISTS409Гонка активаций политики (INV-1, unique index)Повторить (retry)
REWARDS_POLICY_ACTIVE_IMMUTABLE409Правка Rules/Name активной политики (INV-4)Создать новый черновик
REWARDS_PAYOUT_DISTRIBUTION_UNAVAILABLE409Добавляемая строка занята / родитель не MoneyReceived / чужой tenant (INV-1/9, A1)Обновить список доступных строк
REWARDS_PAYOUT_DUPLICATE_RECIPIENT500Нарушение «один получатель = одна позиция» (INV-2, guard)Алерт разработке
REWARDS_PAYOUT_SUM_MISMATCH500Расхождение сумм позиций/итога (INV-3, guard)Алерт разработке
REWARDS_CURRENCY_MISMATCH409Разные валюты строк в поручении (INV-4)Показать конфликтные строки
REWARDS_PAYOUT_COMPOSITION_LOCKED409Правка состава не в Draft (INV-5, A1)Перечитать поручение
REWARDS_PAYOUT_INVALID_STATUS_TRANSITION409Approve не из Draft / ItemsCount = 0 (INV-6, A2); MarkPaid/Reject не из PendingPayment (INV-7)Перечитать статус
REWARDS_PAYOUT_REJECT_REASON_REQUIRED400Отклонение без причины (INV-8, A4)Подсветить поле причины
409 CONFLICT (RowVersion)409Конкурентные approve/reject/mark-paid (оптимистическая блокировка)Перечитать и повторить
404 NOT FOUND404Политика/поручение не существует или чужой tenantВернуться к списку

Доменные События

СобытиеКогда поднимаетсяSubscribers
AgencyPolicyCreatedEvent / AgencyPolicyActivatedEvent / AgencyPolicyArchivedEventФаза 1: создание/активация (+автоархив предыдущей)in-proc аудит
PayoutOrderCreatedEventСоздание поручения (шаг 8)in-proc аудит
PayoutOrderApprovedEventDraft → PendingPayment (шаг 10)in-proc аудит

Kafka Интеграционные События

СобытиеTopicКогда публикуетсяConsumers
PayoutOrderStatusChangedKafkaEvent.v1pin.rewards.payout-order-status-changed.v1Утверждение (шаг 10), отметка выплаты (шаг 13, с Items[]), отклонение (A4)notifications — агентам о выплате, руководителю о статусах; wallet — дебет счетов по Paid (Items[], ADR-0065)
CommissionAccrualStatusChangedKafkaEvent.v1pin.rewards.commission-accrual-status-changed.v1Каскад выплаты: каждое начисление MoneyReceived → Paid (шаг 13, INV-7)notifications

Политика Kafka-событий не публикует (agency-commission-policy.md).

Acceptance Criteria

#КритерийПроверка
AC1Активация новой политики атомарно архивирует предыдущую; активная всегда одна (INV-1 policy)параллельные активации → одна Active; unique index
AC2Оверрайд с чужим/несуществующим агентом отклоняется при активации (INV-3, A7)тест с посторонним agentUserId → 400
AC3Автосборка включает только свободные Agent-строки начислений в MoneyReceived (INV-1 payout, гейт ADR-0067)тест: PendingConfirmation/Confirmed/занятые/Agency- и Platform-строки не попадают
AC4Каждая строка — ровно в одном поручении даже при конкурентной сборке (A6)параллельное создание двух поручений → строки не пересекаются
AC5Item.Amount = Σ строк агента, TotalAmount = Σ Items, ItemsCount корректен (INV-3)unit-тест сборки + db check
AC6Approve пустого поручения невозможен (INV-6, A2)ItemsCount = 0 → 409
AC7Reject/Cancel освобождают строки для следующего поручения (INV-8); начисления остаются MoneyReceived, кошельки не затронутыreject → строки с PayoutOrderItemId = null, включаются в новое поручение
AC8Отметка выплаты каскадно: PaidAt на поручении/позициях/строках; начисления со всеми выплаченными Agent-строками → MoneyReceived → Paid (INV-7) — в одном согласованном измененииинтеграционный тест каскада + проверка атомарности
AC13По событию Paid кошельки агентов дебетуются на суммы Items[]; повтор доставки не двоит дебет ((PayoutDebit, ItemId))replay события → один дебет на позицию
AC9После отметки выплаты в ЛК агента комиссия — «получили», в истории выплат поручение — «выплачено» (матрица 5.5)интеграционный тест сводок
AC10События статусов поручения публикуются атомарноконтракт-тест события + проверка атомарности
AC11Number уникален в tenant и следует формату PO-{yyyy}-{seq}тест генерации на смене года
AC12Повтор Approve/MarkPaid/Reject идемпотентен через guard статуса (не двоит событий/каскада)второй вызов → 409; событие и каскад — однократны

Наблюдаемость и НФТ

  • Логи (без секретов/PII). agency-policy-activated (policyId, tenantId, previousPolicyId?, overridesCount, version); payout-order-created (orderId, number, tenantId, itemsCount, distributionsCaptured, periodFrom/periodTo); payout-order-approved / payout-order-paid / payout-order-rejected (orderId, number, fromStatus, toStatus, itemsCount, paidAccrualsCount? для каскада, длина rejectReason — не текст). Суммы (TotalAmount, Item.Amount, доли) — класс Sensitive, в логи не пишутся; реквизиты и ФИО в сервисе отсутствуют.
  • Метрики. rewards_policy_activate_total{result}; rewards_payout_order_total{status}; rewards_payout_mark_paid_duration (p95 каскада — растёт с числом позиций/начислений); rewards_payout_sum_mismatch_total (guard INV-3, в норме 0); rewards_currency_mismatch_total (INV-4); rewards_payout_distribution_unavailable_total (гонки захвата строк, A6).
  • Трейсы. Span команды → (Фаза 2) захват свободных строк и сборка позиций → публикация события; каскад MarkPaid — вложенные span по каждому переводимому начислению MoneyReceived → Paid; сквозной traceparent, синхронный s2s-span в identity при активации (валидация оверрайдов).
  • НФТ (нагрузка/латентность). API p95 < 300 мс (SLO сервиса); автосборка и каскад ограничены числом строк периода (десятки-сотни, ADR-0056); поручений — единицы на агентство в месяц; лаг события статуса < 1 мин (alert > 5 мин); Number — PostgreSQL sequence per tenant-year, монотонный формат PO-{yyyy}-{seq}.
  • Доступ/безопасность. Три разграниченных permission — rewards.commission-policy.manage (политика), rewards.payouts.manage (состав поручения), rewards.payouts.approve (утверждение/выплата/отклонение) — в scope Organization(CompanyId агентства); агент видит только свои позиции (record-level AgentUserId, rewards.payouts.view-own); суммы Sensitive не логируются; банковские реквизиты не хранятся.

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

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

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