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

Отчет/Export: Выписка по счёту кошелька (wallet-statement)

XLSX-выписка одного счёта кошелька за период — строка = одна проводка этого счёта: дата операции, тип операции, основание (сделка/поручение/корректировка), причина корректировки, дебет, кредит и сальдо после операции. Над таблицей — сальдо на начало периода и обороты; под таблицей — сальдо на конец. Генерируется асинхронной задачей (../api/user/create-wallet-statement-export.md / ../api/agency/create-wallet-statement-export.md / ../api/platform/create-wallet-statement-export.md) по конвейеру ADR-0041.

Назначение

Даёт холдеру счёта (агенту/партнёру), руководителю агентства и оператору ПИН банковскую выписку по внутреннему счёту: как из отдельных начислений, выплат и корректировок сложился текущий баланс, в хронологическом порядке с нарастающим сальдо. Decision value — сверка с бухгалтерией, разбор «почему такой остаток», подтверждение проведённых выплат, аудит корректировок. Owning service — wallet.

Выписка строится строго по журналу (../domain/ledger-transaction.md): одна строка на проводку выбранного счёта. wallet не расшифровывает основание в термины сделки — SourceId отдаётся как непрозрачная ссылка (расшифровка — в rewards по своим permissions, ../api/README.md «Masking»); банковских реквизитов и PII инвесторов в выписке нет.

Классификация

ПолеЗначение
Тип отчетаXLSX
Аудиторияхолдер счёта (агент/партнёр) · руководитель агентства · оператор ПИН
ЧувствительностьFinancial/Sensitive — суммы и балансы счёта; PII инвесторов и банковские реквизиты в выписку не попадают
Freshness SLAсостояние журнала wallet на момент генерации (согласованный снапшот OLTP); балансы догоняют события rewards асинхронно (../api/README.md «Свежесть данных»)
Retentionфайл — 7 дней в приватном объектном хранилище; данные-источник (журнал) — бессрочно (append-only, финансовая история)

Доступ

ActorPermissionScopeГраницы счётаAudit
холдер счёта (агент/партнёр)wallet.transactions.view-ownплатформа (личные данные)только свой счёт (HolderUserId = актор), вид — AgentCommission/ReferralCommissionExportSensitive
руководитель агентстваwallet.team.viewорганизациясчёт AgencyCommission своей компании либо AgentCommission-счёт агента текущего составаExportSensitive
оператор ПИНwallet.accounts.view-allплатформалюбой счёт по AccountId (включая системные)ExportSensitive (+ read-sensitive)

Выписка всегда охватывает ровно один счёт: нарастающее сальдо определено только в разрезе одного счёта. Выбор счёта — в операциях постановки (per-area), см. «Фильтры».

Исходные Source Data

ИсточникВладелецТипFreshnessJoin key
wallet.ledger_entries (проводки счёта)walletsource of truthстрого согласованоAccountId + CreatedAt (период)
wallet.ledger_transactions (тип операции, OccurredAt, SourceId, Comment)walletsource of truthстрого согласованоLedgerEntryEntity.TransactionId
wallet.wallet_accounts (вид, холдер, валюта счёта)walletsource of truthстрого согласованоAccountId
Пользователь/компания identity (ФИО холдера-агента / название агентства — только в шапке)identityenrichment при генерации (не хранится в wallet)на момент генерацииHolderUserId / HolderCompanyId

ФИО холдера и название компании подставляются только в шапку выписки в момент генерации; при недоступности identity задача ретраится, частичный файл не публикуется; если холдер не найден — в шапку пишется id (fail-open отображения, warn-лог). Строки выписки от identity не зависят — только журнал.

Фильтры

Селектор счёта задаётся per-area (постановка), период — общий. Дом полей селектора — в файлах постановки: user (свой счёт по AccountKind), agency (AgentUserId? → счёт агента или AgencyCommission), platform (явный AccountId).

ПолеТипОбязательностьDefaultОграничения
AccountIdGuidДарезолвится из селектора areaровно один счёт; должен существовать (иначе WALLET_STATEMENT_ACCOUNT_NOT_FOUND)
PeriodFromDateTimeOffsetДастроки: OccurredAt >= PeriodFrom
PeriodToDateTimeOffsetДа> PeriodFrom (исключительно: OccurredAt < PeriodTo); диапазон ≤ 1 года — иначе WALLET_STATEMENT_PERIOD_TOO_WIDE
OperationKindstring? (enum WalletOperationKind)Нетвсе видыфильтр по виду операции (../domain/ledger-transaction.md); влияет только на строки — сальдо на начало считается по всем проводкам до PeriodFrom

Строка Отчета WalletStatementRowModel

Одна строка = одна проводка (LedgerEntryEntity) выбранного счёта за период, в хронологическом порядке. Все суммы — в валюте счёта (CurrencyId, RUB-only по ADR-0048).

ПолеТипОбязательностьРасчетMasking
OccurredAtDateTimeOffsetДаLedgerTransactionEntity.OccurredAt (момент бизнес-факта: получение денег / выплата / корректировка)
RecordedAtDateTimeOffsetДаLedgerTransactionEntity.RecordedAt (момент проведения)
OperationKindstring (enum WalletOperationKind)ДаOperationKind (CommissionCredit/ReferralCredit/PayoutDebit/Adjustment/Correction)
SourceGuidДаSourceId — непрозрачная ссылка-основание (начисление / реферальное начисление / позиция поручения / исходная транзакция / ключ корректировки); расшифровка в rewards
AdjustmentReasonstring?Нет (null кроме Adjustment/Correction)LedgerTransactionEntity.Comment (причина ручной корректировки / причина отмены источника)
Debitdecimal?Нет (null у кредитовой проводки)Amount.Value, если Direction = Debit (уменьшение баланса)Financial
Creditdecimal?Нет (null у дебетовой проводки)Amount.Value, если Direction = Credit (увеличение баланса)Financial
BalancedecimalДаBalanceAfter.Value проводки — сальдо счёта сразу после операции (зафиксировано при проведении)Financial

В каждой строке заполнена ровно одна из колонок Debit/Credit (сумма проводки всегда положительна, знак задаёт Direction../domain/ledger-transaction.md). Balance у холдерских счетов >= 0; у системных счетов (platform-area) может быть отрицательным (INV-WLT-3).

Модель Totals WalletStatementTotalsModel

Сальдо на начало/конец и обороты за период (шапка и подвал выписки).

ПолеТипОбязательностьРасчетPrecision
OpeningBalancedecimalДасальдо счёта на момент PeriodFrom = Σ Credit − Σ Debit по всем проводкам с OccurredAt < PeriodFrom (при пустой предыстории — 0)scale 2, banker's; CurrencyId счёта
TurnoverDebitdecimalДаΣ Debit строк периодаscale 2
TurnoverCreditdecimalДаΣ Credit строк периодаscale 2
ClosingBalancedecimalДаOpeningBalance + TurnoverCredit − TurnoverDebitscale 2
RowsCountintДаcount строк выборки периодацелое

Контроль сходимости: ClosingBalance должен равняться Balance последней строки выписки (при непустой выборке без фильтра OperationKind); расхождение — дефект целостности журнала (задача → Failed, алерт, ADR-0021). При заданном OperationKind обороты считаются по отфильтрованным строкам, а сальдо на начало/конец — по всем проводкам (сходимость с Balance строки не гарантируется — это штатно).

Формат Export-а

Лист XLSX statement; заголовки русские; суммы — числовой формат scale 2; шапка листа — счёт (вид, холдер, валюта), период, OpeningBalance, применённый фильтр OperationKind, время генерации (UTC); подвал — TurnoverDebit/TurnoverCredit/ClosingBalance.

ColumnЗаголовокТипФорматNullableИсточник
OccurredAtДата операцииDateTimeOffsetdd.MM.yyyyНетWalletStatementRowModel.OccurredAt
OperationKindТип операцииstringтекст (рус. подпись вида)Нет.OperationKind
SourceОснованиеGuidтекстНет.Source
AdjustmentReasonПричина корректировкиstringтекстДа.AdjustmentReason
DebitДебетdecimal# ##0.00Да.Debit
CreditКредитdecimal# ##0.00Да.Credit
BalanceСальдоdecimal# ##0.00Нет.Balance

Сортировка строк: OccurredAt ASC, при совпадении — RecordedAt ASC, затем TransactionId (стабильный порядок — нарастающее сальдо читается сверху вниз).

Модель задачи WalletStatementExportJobModel

Единый дом модели задачи для всех трёх area (постановка и опрос статуса ссылаются сюда).

ПолеТипОбязательностьИсточникОписание
JobIdGuidДазадача выгрузкиИдентификатор задачи.
Statusstring (enum WalletExportJobStatus)ДазадачаQueued / Running / Completed / Failed / Expired.
CreatedAtDateTimeOffsetДазадачаМомент постановки.
FileNamestring?Нет (null до Completed)задачаИмя файла: wallet-statement-{accountShort}-{yyyyMMdd}-{yyyyMMdd}.xlsx.
DownloadUrlstring?Нетsigned URLПодписанная ссылка на файл — только при Status = Completed и непросроченном файле (TTL 1 час); иначе null.
ExpiresAtDateTimeOffset?НетзадачаМомент истечения retention файла (7 дней от готовности); null до Completed.
FailureCodestring?НетзадачаКод причины — только при Status = Failed (например, WALLET_STATEMENT_ROW_LIMIT_EXCEEDED).

Enum WalletExportJobStatus

ЗначениеОписание
QueuedЗадача поставлена, ожидает исполнителя.
RunningИдёт формирование файла.
CompletedФайл готов и лежит в хранилище (retention не истёк).
FailedГенерация завершилась ошибкой (FailureCode); частичный файл не публикуется.
ExpiredФайл удалён по retention (7 дней) — требуется новая постановка.

Процесс Генерации

  1. Постановка задачи, проверка permission, границ счёта (per-area), периода, лимитов и audit — файлы постановки (user / agency / platform).
  2. Фоновый исполнитель резолвит счёт по AccountId, считает OpeningBalance (проводки с OccurredAt < PeriodFrom) — согласованный снапшот на момент чтения.
  3. Читает проводки счёта за период (+ фильтр OperationKind) со связанными транзакциями (тип, OccurredAt, SourceId, Comment) в хронологическом порядке.
  4. Обогащение шапки: ФИО холдера / название компании из identity (одиночный lookup).
  5. Проверка лимита строк (≤ 100 000, иначе задача → Failed c WALLET_STATEMENT_ROW_LIMIT_EXCEEDED).
  6. Формирование WalletStatementRowModel[] (потоково) и WalletStatementTotalsModel; контроль сходимости ClosingBalance с Balance последней строки (при непустой выборке без фильтра вида) — расхождение — дефект целостности, задача → Failed, алерт.
  7. Сериализация XLSX → приватное объектное хранилище (retention 7 дней); задача → Completed; финальная audit-запись (число строк, исход). Ссылка на скачивание — короткоживущий signed URL (get-job операция соответствующей area).

Лимиты

ЛимитЗначениеОшибка
Max rows100 000 строкWALLET_STATEMENT_ROW_LIMIT_EXCEEDED (задача Failed)
Max date range1 годWALLET_STATEMENT_PERIOD_TOO_WIDE (400 на постановке)
Concurrent exports2 активные задачи на актораWALLET_STATEMENT_CONCURRENCY_LIMIT (429 на постановке)
ФорматыXLSX

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

ТипПравило
Metricswallet_statement_export_duration_seconds, wallet_statement_export_rows, wallet_statement_export_file_bytes, wallet_statement_export_jobs_total{area,result}
Logsпостановка / генерация / выдача ссылки / истечение / отказ — с актором, AccountId, периодом; суммы и балансы не логируются (Financial)
Tracestraceparent, AccountId, JobId
AuditExportSensitive на постановку, выдачу ссылки и исход генерации

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

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

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