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

UC-WLT-003. ПИН-админ вручную корректирует баланс

Назначение

Описывает сценарий ручной корректировки баланса кошелька администратором платформы: исправление последствий рассинхрона или операционной ошибки (по итогам issue Reconciliation Center) добавлением компенсирующей записи в журнал — с обязательной причиной и аудитом актора. Прямой правки баланса или журнала не существует: корректировка — такая же транзакция двойной записи. Связан с контекстом wallet.

Metadata

ПолеЗначение
IDUC-WLT-003
Контекстwallet (см. docs/06-services/wallet/)
Типисключительный (ручное исправление, не штатный денежный поток)
Статусdraft

Актор

ПолеЗначение
РольАдминистратор платформы (ПИН-админ)
Permissions / scopewallet.adjustments.manage, платформенный scope
Tenantне применяется (платформенная операция над любым счётом)

Предусловие

  • Есть основание для корректировки: issue Reconciliation Center, результат разбора DLQ «дебет без покрытия» либо подтверждённая операционная ошибка (ADR-0021).
  • Целевой счёт существует (wallet-account.md); для компенсации — известна исходная транзакция журнала.

Триггер

ПолеЗначение
ИсточникAPI call
Триггерящий элементadmin-операция create-wallet-adjustment.md (POST /api/v1/platform/wallet/adjustments)

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

  1. Админ находит счёт в admin-реестре (list-wallet-accounts.md, wallet.accounts.view-all) и создаёт корректировку: сумма со знаком (положительная — увеличить баланс, отрицательная — уменьшить), обязательная причина, идемпотентный ключ операции.
  2. Система проверяет вход: счёт существует (иначе WALLET_ACCOUNT_NOT_FOUND — корректировка несуществующего счёта запрещена, счета создаются только кредитами rewards), причина непуста (иначе WALLET_ADJUSTMENT_REASON_REQUIRED), сумма ненулевая, валюта равна валюте счёта (иначе WALLET_CURRENCY_MISMATCH).
  3. Система проводит транзакцию Adjustment (SourceId = идемпотентный ключ операции): увеличение — дебет PlatformSettlement / кредит целевого счёта; уменьшение — зеркально (ledger-transaction.md, карта проводок). Причина — в Comment, актор — в ActorUserId.
  4. Guard no-negative: уменьшение не может увести баланс холдерского счёта ниже нуля — иначе отказ WALLET_BALANCE_NEGATIVE_FORBIDDEN (INV-WLT-3); системные счета могут уходить в минус.
  5. Транзакция, проводки и балансы фиксируются атомарно; публикуется pin.wallet.transaction-recorded.v1 по проводке холдерского счёта.
  6. Холдер получает уведомление «баланс скорректирован»; админ видит транзакцию в журнале счёта.

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

A1. Повтор операции (двойная отправка формы / retry)

  1. Запрос с тем же идемпотентным ключом приходит повторно.
  2. Система обнаруживает существующую транзакцию (Adjustment, SourceId) (INV-WLT-7) и возвращает её же как результат — вторая транзакция не проводится, баланс не меняется дважды.

A2. Компенсация транзакции (Correction) — не через этот сценарий

Зеркальная компенсация со ссылкой на исходную транзакцию (Correction) в v1 проводится только системно — при отмене реферального начисления после Approved (UC-WLT-001, A4). Ручного API-пути компенсации нет: админ выражает исправление обычным Adjustment с причиной-ссылкой на разбор.

Постусловие

  • В журнале появилась ровно одна append-only транзакция Adjustment с причиной и актором; прежние записи журнала не изменены.
  • Баланс целевого счёта изменён на сумму корректировки и (для холдерского) остался >= 0; парная проводка легла на PlatformSettlement.
  • Balance каждого затронутого счёта равен пересчёту из журнала.
  • Событие pin.wallet.transaction-recorded.v1 опубликовано; уведомление холдеру доставлено.

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

КодHTTPУсловиеПоведение клиента
WALLET_ACCOUNT_NOT_FOUND404Целевой счёт не существуетПроверить выбор счёта
WALLET_ADJUSTMENT_REASON_REQUIRED400Причина не указана / пустаяЗаполнить причину
WALLET_CURRENCY_MISMATCH400Валюта суммы ≠ валюте счёта (INV-WLT-4)Исправить валюту (RUB-only, ADR-0048)
WALLET_BALANCE_NEGATIVE_FORBIDDEN409Уменьшение увело бы холдерский баланс ниже нуля (INV-WLT-3)Уменьшить сумму либо решать расхождение на стороне rewards
ValidationError400Нулевая сумма / формат полей / нет идемпотентного ключаИсправить запрос

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

СобытиеTopicКогда публикуетсяConsumers
WalletTransactionRecordedKafkaEventpin.wallet.transaction-recorded.v1Атомарно с проведением корректировки — по проводке холдерского счётаnotifications

Acceptance Criteria

#КритерийПроверка
AC1Given счёт агента с балансом B, When админ проводит увеличение на X с причиной, Then баланс = B + X, в журнале — транзакция Adjustment с причиной и актором, исходные записи не тронутыинтеграционный тест
AC2Given корректировка без причины, When запрос отправлен, Then отказ WALLET_ADJUSTMENT_REASON_REQUIRED и журнал не изменённегативный тест
AC3Given уменьшение на сумму больше баланса холдерского счёта, When запрос отправлен, Then отказ WALLET_BALANCE_NEGATIVE_FORBIDDEN, баланс не изменённегативный тест (INV-WLT-3)
AC4Given повторная отправка той же операции (тот же идемпотентный ключ), When запрос обработан, Then вторая транзакция не проведена, возвращена ранее проведённая, баланс изменён однократнотест идемпотентности (INV-WLT-7)
AC5Given корректировка несуществующего счёта, When запрос отправлен, Then отказ WALLET_ACCOUNT_NOT_FOUND — счёт не создаётсянегативный тест
AC6Given любая корректировка, When она проведена, Then Balance затронутых счетов равен пересчёту из журналасверочный пересчёт (ADR-0021)

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

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

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