Отчет/Export: Вознаграждения агентства по сотрудникам и сделкам (agency-rewards-by-employee-per-deal)
XLSX-выгрузка агентства: строка = одно комиссионное начисление (сделка агента) за период — с
человекочитаемой карточкой объекта (тип/комнаты/площадь) и его конечной ценой, полной финансовой
раскладкой (комиссия gross, удержание ПИН, пул агентства, доля агента, удержание агентства), статусными
датами и номером платёжного поручения. Генерируется асинхронной задачей
(../api/agency/create-rewards-export.md,
ReportType = ByEmployeePerDeal) по конвейеру
ADR-0041.
Назначение
Даёт владельцу/руководителю агентства детальную картину вознаграждений по каждому сотруднику и каждой
сделке: сколько начислено застройщиком, сколько удержал ПИН, как пул поделён между агентом и агентством,
что подтверждено/получено/выплачено и каким поручением. Decision value — сверка с бухгалтерией, контроль
выплат агентам, разбор спорных сделок. Owning service — rewards.
Классификация
| Поле | Значение |
|---|---|
| Тип отчета | XLSX |
| Аудитория | владелец/руководитель агентства |
| Чувствительность | Financial/Sensitive — суммы вознаграждений и персональные доли агентов; PII инвесторов в отчёт не попадает |
| Freshness SLA | состояние rewards на момент генерации (строго согласованный снапшот OLTP; без окна eventual-consistency) |
| Retention | файл — 7 дней в приватном объектном хранилище; данные-источник — бессрочно (финансовая история) |
Доступ
| Actor | Permission | Tenant/Brand scope | Audit |
|---|---|---|---|
| владелец/руководитель агентства | rewards.commission.view-all | TenantId = CompanyId агентства из claims; fail-closed | ExportSensitive — постановка, выдача ссылки, исход генерации |
Агент и застройщик доступа к выгрузке не имеют (агент видит только свои начисления в ../api/agent/list-my-accruals.md; застройщику распределение агентства не раскрывается).
Исходные Source Data
| Источник | Владелец | Тип | Freshness | Join key |
|---|---|---|---|---|
rewards.commission_accruals | rewards | source of truth (в т.ч. FinalPriceAmount и снапшот атрибутов объекта AppliedRuleSnapshot — ../domain/commission-accrual.md) | строго согласовано | TenantId + DealCompletedAt (период) |
rewards.commission_distributions | rewards | source of truth (три строки Platform/Agency/Agent — ../domain/commission-accrual.md) | строго согласовано | AccrualId |
rewards.payout_order_items + rewards.payout_orders | rewards | source of truth (Number поручения — ../domain/payout-order.md) | строго согласовано | Agent-строка → PayoutOrderItemId → поручение |
Пользователи identity (ФИО агентов) | identity | enrichment при генерации (не хранится в rewards) | на момент генерации | AgentUserId |
Компании identity (названия застройщиков) | identity | enrichment при генерации | на момент генерации | DeveloperCompanyId |
ФИО агента и название застройщика подставляются в момент генерации (актуальные значения identity);
при недоступности identity задача ретраится, частичный файл не публикуется. Если пользователь/компания
не найдены (устаревшая ссылка) — в ячейку пишется id (fail-open отображения, warn-лог).
Фильтры AgencyRewardsByDealFilterModel
Снимаются с задачи выгрузки (../api/agency/create-rewards-export.md).
| Поле | Тип | Обязательность | Default | Ограничения |
|---|---|---|---|---|
TenantId | Guid | Да | identity claims | Required; не из UI |
PeriodFrom | DateTimeOffset | Да | — | строки: DealCompletedAt >= PeriodFrom |
PeriodTo | DateTimeOffset | Да | — | > PeriodFrom (исключительно); диапазон ≤ 1 года |
AgentUserId | Guid? | Нет | все агенты | только сделки этого агента |
Status | string? (enum CommissionAccrualStatus) | Нет | все статусы | PendingConfirmation/Confirmed/MoneyReceived/Paid/Cancelled |
Строка Отчета AgencyRewardsByDealRowModel
Одна строка = одно начисление (CommissionAccrualEntity) tenant-а за период. Все суммы — в валюте
начисления (CurrencyId, RUB-only по ADR-0048); валюта выборки едина (INV-6), иначе генерация падает
REWARDS_CURRENCY_MISMATCH (защита целостности, задача → Failed).
| Поле | Тип | Обязательность | Расчет | Masking |
|---|---|---|---|---|
AgentFullName | string | Да | enrichment identity по AgentUserId (ФИО на момент генерации) | — |
DealId | Guid | Да | CommissionAccrualEntity.DealId | — |
PropertyObjectId | Guid | Да | PropertyObjectId | — |
PropertyType | string (enum PropertyType) | Да | AppliedRuleSnapshot.PropertyObjectPropertyType (снапшот на момент сделки) | — |
Rooms | int? | Нет (null — студия/нежилой объект без комнатности) | AppliedRuleSnapshot.PropertyObjectRooms | — |
AreaTotalM2 | decimal | Да | AppliedRuleSnapshot.PropertyObjectAreaTotalM2 (снапшот, м²) | — |
DeveloperName | string | Да | enrichment identity по DeveloperCompanyId | — |
DealCompletedAt | DateTimeOffset | Да | DealCompletedAt | — |
Status | string (enum CommissionAccrualStatus) | Да | Status | — |
FinalPriceAmount | decimal | Да | FinalPriceAmount.Value (конечная цена объекта: базовая + ремонт, на момент сделки) | Financial |
CommissionGross | decimal | Да | CommissionAmount.Value (после корректировок; исходная сумма — не выгружается, аудит корректировок — отдельная сущность) | Financial |
PlatformFee | decimal | Да | PlatformFeeAmount.Value (удержание ПИН, INV-10) | Financial |
AgencyPool | decimal | Да | CommissionGross − PlatformFee | Financial |
AgentShare | decimal? | Нет (null до Confirmed — строк распределения ещё нет) | Amount.Value строки Agent | Financial |
AgencyRetention | decimal? | Нет (null до Confirmed) | Amount.Value строки Agency | Financial |
ConfirmedAt | DateTimeOffset? | Нет | ConfirmedAt | — |
MoneyReceivedAt | DateTimeOffset? | Нет | MoneyReceivedAt (регистрация акта — гейт ADR-0067) | — |
PaidAt | DateTimeOffset? | Нет | PaidAt | — |
PayoutOrderNumber | string? | Нет (null — доля не включена в поручение) | Number поручения через Agent-строку → позицию (PO-{yyyy}-{seq}) | — |
InvestorUserId, ставки правил застройщика и снапшот условий платформы в выгрузку не попадают — только
итоговые суммы. Строка Platform раскрывается единственным числом PlatformFee. Карточка объекта
(PropertyType/Rooms/AreaTotalM2) берётся из снапшота начисления AppliedRuleSnapshot — это
значения на момент сделки (последующие правки объекта в chessboard отчёт не меняют); адрес объекта в
снапшот не входит и в выгрузку не попадает.
Модель Totals AgencyRewardsByDealTotalsModel
Итоги по всей выборке фильтра (строка «Итого» под таблицей).
| Поле | Тип | Обязательность | Расчет | Precision |
|---|---|---|---|---|
RowsCount | int | Да | count строк выборки (все статусы, включая Cancelled) | целое |
CancelledCount | int | Да | count строк со статусом Cancelled в выборке (справочно) | целое |
TotalGross | decimal | Да | Σ CommissionGross по строкам со статусом ≠ Cancelled | scale 2, banker's; CurrencyId выборки |
TotalPlatformFee | decimal | Да | Σ PlatformFee (строки ≠ Cancelled) | scale 2 |
TotalAgencyPool | decimal | Да | Σ AgencyPool (строки ≠ Cancelled) | scale 2 |
TotalAgentShare | decimal | Да | Σ AgentShare (строки ≠ Cancelled; строки без распределения дают 0) | scale 2 |
TotalAgencyRetention | decimal | Да | Σ AgencyRetention (строки ≠ Cancelled; строки без распределения дают 0) | scale 2 |
Денежные totals исключают Cancelled — как в парном сводном отчёте
(agency-rewards-period-summary.md): отменённое начисление в суммы не
входит, но остаётся строкой таблицы и учитывается счётчиками RowsCount/CancelledCount (детальный аудит
показывает и отменённые сделки). FinalPriceAmount — атрибут строки и в totals не суммируется (цены
объектов не складываются).
Контроль сходимости: TotalPlatformFee + TotalAgentShare + TotalAgencyRetention = TotalGross — сходится
по строкам со статусом Confirmed и выше (INV-5 ../domain/commission-accrual.md);
строки PendingConfirmation дают TotalGross, но ещё не имеют распределения, поэтому точное равенство
достигается только когда в выборке нет PendingConfirmation (либо при фильтре Status ≥ Confirmed).
Формат Export-а
Лист XLSX by-deal; заголовки русские; суммы — числовой формат scale 2; шапка листа — период, агентство,
применённые фильтры, время генерации (UTC).
| Column | Заголовок | Тип | Формат | Nullable | Источник |
|---|---|---|---|---|---|
AgentFullName | Агент | string | текст | Нет | AgencyRewardsByDealRowModel.AgentFullName |
DealId | Сделка | Guid | текст | Нет | .DealId |
PropertyObjectId | Объект (id) | Guid | текст | Нет | .PropertyObjectId |
PropertyType | Тип объекта | string | текст (рус. подпись типа) | Нет | .PropertyType |
Rooms | Комнат | int | # ##0 | Да | .Rooms |
AreaTotalM2 | Площадь, м² | decimal | # ##0.00 | Нет | .AreaTotalM2 |
DeveloperName | Застройщик | string | текст | Нет | .DeveloperName |
DealCompletedAt | Дата завершения | DateTimeOffset | dd.MM.yyyy | Нет | .DealCompletedAt |
Status | Статус начисления | string | текст (рус. подпись статуса) | Нет | .Status |
FinalPriceAmount | Конечная цена объекта | decimal | # ##0.00 | Нет | .FinalPriceAmount |
CommissionGross | Комиссия (gross) | decimal | # ##0.00 | Нет | .CommissionGross |
PlatformFee | Удержание ПИН | decimal | # ##0.00 | Нет | .PlatformFee |
AgencyPool | Пул агентства | decimal | # ##0.00 | Нет | .AgencyPool |
AgentShare | Доля агента | decimal | # ##0.00 | Да | .AgentShare |
AgencyRetention | Удержание агентства | decimal | # ##0.00 | Да | .AgencyRetention |
ConfirmedAt | Подтверждено | DateTimeOffset | dd.MM.yyyy | Да | .ConfirmedAt |
MoneyReceivedAt | Получено | DateTimeOffset | dd.MM.yyyy | Да | .MoneyReceivedAt |
PaidAt | Выплачено | DateTimeOffset | dd.MM.yyyy | Да | .PaidAt |
PayoutOrderNumber | № поручения | string | текст | Да | .PayoutOrderNumber |
Сортировка строк: AgentFullName ASC, затем DealCompletedAt DESC.
Процесс Генерации
- Постановка задачи, проверка permission
rewards.commission.view-all, tenant scope, лимитов и audit — ../api/agency/create-rewards-export.md. - Фоновый исполнитель читает начисления tenant-а за период (+ фильтры
AgentUserId/Status) со строками распределения и привязкой к поручениям — согласованный снапшот на момент чтения. - Обогащение: ФИО агентов и названия застройщиков из
identity(batch по уникальным id). - Проверка лимита строк (≤ 100 000, иначе задача →
FailedcREWARDS_EXPORT_ROW_LIMIT_EXCEEDED). - Формирование
AgencyRewardsByDealRowModel[](потоково) иAgencyRewardsByDealTotalsModel(денежные суммы — безCancelled); контроль сходимости totals по подмножествуConfirmed+ (расхождение — дефект целостности, задача →Failed, алерт). - Сериализация XLSX → приватное объектное хранилище (retention 7 дней); задача →
Completed; финальная audit-запись (число строк, исход). Ссылка на скачивание — короткоживущий signed URL (../api/agency/get-rewards-export-job.md).
Лимиты
| Лимит | Значение | Ошибка |
|---|---|---|
| Max rows | 100 000 строк | REWARDS_EXPORT_ROW_LIMIT_EXCEEDED (задача Failed) |
| Max date range | 1 год | REWARDS_EXPORT_PERIOD_TOO_WIDE (400 на постановке) |
| Concurrent exports | 2 активные задачи на агентство | REWARDS_EXPORT_CONCURRENCY_LIMIT (429 на постановке) |
| Форматы | XLSX | — |
Наблюдаемость
| Тип | Правило |
|---|---|
| Metrics | rewards_export_duration_seconds, rewards_export_rows, rewards_export_file_bytes, rewards_export_jobs_total{report_type=by_employee_per_deal,result} |
| Logs | постановка / генерация / выдача ссылки / истечение / отказ — с актором и фильтрами; суммы не логируются (Financial) |
| Traces | traceparent, TenantId, JobId |
| Audit | ExportSensitive на постановку, выдачу ссылки и исход генерации |
Обратные ссылки
Автоссылки: где используется этот документ.
- API (2): GET /api/v1/agency/rewards-exports/{jobId} — Статус выгрузки и ссылка на скачивание, POST /api/v1/agency/rewards-exports — Постановка Excel-выгрузки вознаграждений агентства
- Use Cases (2): UC-RWD-012. Владелец агентства выгружает отчёты по вознаграждениям в Excel, US-реестр: Владелец агентства (US-OWN-AG)
- Отчёты (1): Отчет/Export: Сводка вознаграждений агентства за период (agency-rewards-period-summary)
- index.md (1): Rewards Service
Связанные документы
- Операции конвейера: ../api/agency/create-rewards-export.md, ../api/agency/get-rewards-export-job.md.
- Сводный отчёт за период: agency-rewards-period-summary.md.
- Дома полей: ../domain/commission-accrual.md (строки распределения,
статусы, INV-5/10), ../domain/payout-order.md (
Number). - ADR-0041 (async pipeline,
signed URL), ADR-0066 (три строки распределения), ADR-0067 (гейт
MoneyReceived), ADR-0048 (RUB-only), ADR-0052 (tenancy).