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

UC-RWD-017. Уволенный агент: судьба заработанных комиссий

Назначение

Описывает поведение вознаграждений при увольнении/исключении агента (ADR-0072): что происходит с его начислениями в rewards и с его доступом к финансовым разделам. Ключевые гарантии: начисления в статусах PendingConfirmation/Confirmed продолжают жизненный цикл (застройщик подтверждает, оператор ПИН регистрирует акт, руководитель агентства выплачивает) и по-прежнему адресованы бывшему агенту — AgentUserId и OriginAgentUserId иммутабельны; заработанное и выплаченное (MoneyReceived/Paid) сохраняется; интерактивный доступ к финансам агентства у уволенного revoke (снятие назначения роли в scope этого агентства), а его личный кабинет вознаграждений становится read-only — право получить уже заработанное не отчуждается. Связан с контекстом rewards.

Metadata

ПолеЗначение
IDUC-RWD-017
Контекстrewards (см. docs/06-services/rewards/)
Типисключительный (реакция на увольнение; смешанный: system-каскад + read-only self-view)
Статусdraft

Актор

ПолеЗначение
РольSystem (consumer события членства agent-membership-changed в rewards) — основной поток; Уволенный агент (read-only self-view) — потоки чтения
Permissions / scopeSystem — m2m-обработка события; агент после увольнения — rewards.commission.view-own (record-level, read-only) сохраняется, интерактивные rewards.commission.adjust-request в scope этого агентства revoke (снятие назначения роли в identity, ADR-0072)
TenantНачисления — в tenant агентства (TenantId = AgencyCompanyId); user-centric проекция AgentPerformance и счета кошелька агента — вне tenant (переживают увольнение, ADR-0061 п.5)
Record-levelАгент видит только свои начисления (AgentUserId из claims) и свою проекцию карьеры

Предусловие

  • identity перевёл членство пары (AgentUserId, CompanyId) Active → Left (terminate-agent-membership.md — исключение руководителем, Reason = ExcludedByAgency; либо self-leave, Reason = SelfLeave) и опубликовал pin.identity.agent-membership-changed.v1 с Reason/EffectiveAt (ADR-0072).
  • Перед снятием членства guard «единственный активный Executor» уже отработал: активные лиды/сделки/ фиксации агента переназначены на преемника (ADR-0071/0072) — новые начисления по ним пойдут преемнику; уже созданные начисления агента остаются за ним.
  • Историческая привязка сделок/фиксаций (OriginAgencyCompanyId/OriginAgentUserId) иммутабельна, back-fill запрещён (ADR-0061 п.4).

Триггер

ПолеЗначение
ИсточникKafka event (основной каскад) / UI (чтение агентом)
Триггерящий элементConsumer rewards топика pin.identity.agent-membership-changed.v1 (Status = Left); ЛК агента → «Мои комиссии»

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

  1. identity публикует agent-membership-changed (Left, Reason, EffectiveAt, key = AgentUserId).
  2. Consumer rewards применяет событие (идемпотентно, monotonic-guard по версии членства строки):
    • Проекция карьеры. Строка AgentPerformanceEntity (AgentUserId, CompanyId) этого агентства переводится в MembershipStatus = Left; накопленные метрики строки не обнуляются (user-centric, UC-RWD-006 A1). Прочие строки (другие агентства) не тронуты.
    • Начисления не пересчитываются. Существующие начисления агента в этом tenant остаются в своих статусах; AgentUserId/OriginAgentUserId/распределения/суммы иммутабельны. Никаких массовых переходов статусов увольнение не запускает — деньги следуют цепочке подтверждений, а не членству.
    • Revoke интерактивного доступа. Снятие назначения роли agent в scope этого агентства (выполняет identity, ADR-0072) убирает у уволенного возможность действий над финансами агентства: подавать заявки на корректировку своей доли, участвовать в согласованиях. Право чтения своих начислений (rewards.commission.view-own, record-level AgentUserId) сохраняется — ЛК становится read-only.
  3. Уволенный агент открывает «Мои комиссии»: видит свои начисления и их статусы (в т.ч. Confirmed «подтверждено, ждём деньги», MoneyReceived, Paid) в режиме только чтение; интерактивные действия (заявка на корректировку доли) недоступны — при попытке 403 FORBIDDEN (право revoke).
  4. Цепочка вознаграждений по начислениям уволенного продолжается независимо от него:
    • PendingConfirmation → застройщик подтверждает (UC-RWD-004/UC-RWD-016): строится распределение, строка Agent ссылается на AgentUserId уволенного — он остаётся получателем;
    • Confirmed → оператор ПИН регистрирует акт поступления средств (UC-RWD-010): начисление → MoneyReceived, кошелёк кредитует user-centric счёт AgentCommission уволенного (счёт переживает утрату агентства, ADR-0061 п.5, UC-WLT-001);
    • MoneyReceived → руководитель агентства/оператор ПИН формирует платёжное поручение; при Paid Agent-строки выплачены, начисление → Paid.
  5. notifications доставляет уволенному агенту уведомления о переходах его начислений («комиссия подтверждена», «деньги получены», «выплачено») — право на заработанное реализуется до конца.

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

A1. Начисление подтверждается уже после увольнения

  1. Застройщик подтверждает PendingConfirmation-начисление уволенного (UC-RWD-004/016): строится распределение, строка AgentAgentUserId уволенного. Увольнение не влияет на получателя. Далее — штатная цепочка. Завершается.

A2. Деньги получены после увольнения (кредит user-centric счёта)

  1. Оператор ПИН регистрирует акт по Confirmed-начислению уволенного → MoneyReceived; событие commission-money-received кредитует счёт AgentCommission бывшего агента (счёт user-centric, создаётся/живёт независимо от членства). Баланс уволенного растёт; он видит его read-only (UC-WLT-004, AC4). Не ошибка.

A3. Заработанное/выплаченное до увольнения

  1. Начисления в MoneyReceived/Paid на момент увольнения не меняются: суммы, распределения и Origin- снапшоты иммутабельны; уволенный видит их и историю выплат read-only. Отмена таких начислений запрещена (INV-8) — только компенсирующие операции (ADR-0067), увольнение их не инициирует.

A4. Попытка интерактивного действия после увольнения

  1. Уволенный пытается подать заявку на корректировку своей доли → отказ: право rewards.commission.adjust-request в scope агентства снято (revoke), 403 FORBIDDEN. Существующие Pending-заявки, поданные до увольнения, разрешает руководитель агентства штатно (UC-RWD-011) — их исход также адресован AgentUserId уволенного.

A5. Мульти-членство: уволен из одного агентства, активен в другом

  1. Увольнение затрагивает только пару (AgentUserId, CompanyId) этого агентства (ADR-0070): строка AgentPerformance этого агентства → Left, интерактивный доступ к финансам этого агентства revoke; членство, доступ и начисления в других агентствах сохранены. Агрегированная карьера (UC-RWD-006) по- прежнему суммирует все строки. Завершается.

A6. Расторжение сделки уволенного агента

  1. По не-получившему деньги начислению уволенного приходит deal-cancelled — consumer отменяет начисление (CancelReason = DealCancelled, INV-8: из PendingConfirmation/Confirmed, если строки свободны и нет не-отменённого акта). Это системная реакция на расторжение сделки, не на увольнение. Завершается.

A7. Повторная/переставленная доставка события членства

  1. Повтор agent-membership-changed — идемпотентный skip; переставленный старый переход отбрасывается monotonic-guard по версии членства строки (UC-RWD-006 AC3). Начисления в любом случае не затрагиваются.

Постусловие

  • AgentUserId/OriginAgentUserId, суммы и распределения начислений уволенного — неизменны; earned (MoneyReceived) и paid (Paid) сохранены; Pending/Confirmed продолжают цикл и остаются адресованы бывшему агенту.
  • Строка AgentPerformance этого агентства — Left (метрики сохранены); интерактивный доступ к финансам агентства у уволенного revoke; ЛК вознаграждений — read-only; право получить заработанное реализуется штатной цепочкой и кредитуется на user-centric счёт кошелька.
  • Историческая привязка сделок/фиксаций не пересчитана (снапшоты иммутабельны).

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

  • Ожидает на входе. Долговечное pin.identity.agent-membership-changed.v1 (Left, Reason, EffectiveAt); reassign активных процессов уже выполнен guard-ом до увольнения — новые начисления по ним адресуются преемнику, а не уволенному.
  • Предоставляет на выходе. Ничего нового rewards по факту увольнения не публикует (обновляет лишь проекцию карьеры). Дальнейшие переходы начислений публикуют штатные commission-accrual-status-changed/commission-money-received независимо от членства.
  • Окно eventual-consistency. Между увольнением в identity и применением события в проекции/доступе — лаг (< 5 мин SLO): короткое время уволенный может ещё видеть интерактивные элементы (действие всё равно отклонит серверная проверка права). Не ошибка.
  • Инвариант права. Финансовое право следует иммутабельному AgentUserId и user-centric счёту, а не активному членству: увольнение снимает доступ к процессам агентства, но не отчуждает заработанное (ADR-0072 п.4, ADR-0061 п.5).

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

КодHTTPУсловиеПоведение клиента
403 FORBIDDEN403Интерактивное действие над финансами агентства после revoke (A4)Скрыть кнопки действий, оставить read-only
— (идемпотентный skip)Повтор события членства (A7)Consumer: skip

Чтение своих начислений уволенным — не ошибка (200, read-only).

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

СобытиеTopicКогдаConsumers
— (потребление)pin.identity.agent-membership-changed.v1 (Left)Наполнение проекции + отражение revokeconsumer rewards (проекция карьеры)
CommissionAccrualStatusChangedKafkaEvent.v1pin.rewards.commission-accrual-status-changed.v1Продолжение цикла начислений уволенного (Confirm/MoneyReceived/Paid/Cancelled)notifications
CommissionMoneyReceivedKafkaEvent.v1pin.rewards.commission-money-received.v1Confirmed → MoneyReceived начисления уволенногоwallet (кредит user-centric счёта), notifications

Acceptance Criteria

#КритерийПроверка
AC1Увольнение не меняет статусы/суммы/получателя существующих начислений (AgentUserId/Origin иммутабельны)тест: terminate → перечитать начисления, всё неизменно
AC2PendingConfirmation-начисление уволенного подтверждается и адресовано ему же (A1)тест Confirm после увольнения → строка Agent на AgentUserId уволенного
AC3Confirmed → MoneyReceived уволенного кредитует его user-centric счёт кошелька (A2)интеграционный тест commission-money-received → баланс уволенного
AC4earned/paid до увольнения сохранены и видны read-only (A3)тест: MoneyReceived/Paid неизменны, отмена запрещена
AC5Интерактивное финансовое действие уволенного отклонено (403), ЛК read-only (A4)негативный тест заявки на корректировку после revoke
AC6Мульти-членство: revoke и Left только для покинутого агентства; другие сохранены (A5)тест terminate из одного из двух агентств
AC7Строка AgentPerformance покинутого агентства → Left, метрики не обнуленытест проекции после увольнения
AC8Повтор/переставленное событие членства не искажает начисления и проекцию (A7)тест идемпотентности/monotonic-guard

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

  • Логи (без секретов/PII). agent-membership-left-applied (agentUserId, companyId, reason, effectiveAt, perfRowStatus = Left); попытки интерактивных действий после revoke логируются как forbidden (без содержимого). Суммы — класс Sensitive, в логи не пишутся.
  • Метрики. rewards_membership_left_applied_total{reason}; rewards_terminated_agent_forbidden_total (интерактивные попытки после revoke); лаг применения membership-события (alert > 5 мин).
  • Доступ/безопасность. rewards.commission.view-own (read-only) сохраняется; интерактивные права в scope покинутого агентства — revoke; получатель финансового права — иммутабельный AgentUserId, не членство.

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

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

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