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

POST /api/v1/platform/wallet/adjustments — Ручная корректировка счёта

Назначение

Позволяет оператору ПИН вручную скорректировать баланс счёта кошелька — провести транзакцию Adjustment с обязательной причиной. Штатный инструмент устранения последствий рассинхрона и ошибок по итогам разбора Reconciliation Center (ADR-0021): журнал append-only, прежние транзакции не правятся и не удаляются — исправление всегда отдельная транзакция с аудит-следом. Компенсация Correction в v1 проводится только системно (отмена реферального начисления после Approved, ../../consumers/rewards-referral-accrual-status-changed.md); ручного API-пути компенсации нет — админ пользуется Adjustment (../../domain/ledger-transaction.md).

Metadata

ПолеЗначение
Сервис/контекстwallet
API areaplatform
Feature groupplatform-wallet
Статусdraft
Документdocs/06-services/wallet/api/platform/create-wallet-adjustment.md

Актор и доступ

ПроверкаЗначение
Actor typeOperator(Admin) (оператор ПИН)
Auth policy / Permissionswallet.adjustments.manage
Scope (RBAC)платформа
Auditcreate: актор, счёт, сумма, причина — полный аудит-след в самой транзакции журнала

HTTP-контракт

ПолеЗначение
MethodPOST
Route/api/v1/platform/wallet/adjustments
Success status201
Idempotency headerIdempotency-Key (Guid) — обязателен; становится SourceId транзакции
Correlationсквозной trace через заголовок traceparent

Входные данные / параметры запроса

ПолеИсточникТипОбязательностьВалидация / ОграниченияБезопасность
IdempotencyKeyheaderGuidДане пустой; становится SourceId транзакции (уникальность в паре с видом операции, INV-WLT-7)
AccountIdbodyGuidДасуществующий счёт (любого вида, включая системные)
AmountbodydecimalДа!= 0, scale 2; положительная — увеличить баланс счёта (кредит), отрицательная — уменьшить (дебет)Sensitive — в логи не пишется
ReasonbodystringДа1..1000 символов — обязательная человекочитаемая причина (ссылка на инцидент/разбор); маппится в Comment транзакции

Модель ответа

WalletTransactionModel проведённой транзакции (дом — ../README.md): OperationKind = Adjustment, Amount со знаком относительно скорректированного счёта, BalanceAfter — новый баланс, SourceId = Idempotency-Key.

Алгоритм

  1. Контекст и доступ. Оператор ПИН с permission wallet.adjustments.manage, платформенный scope — иначе FORBIDDEN.
  2. Проверка входа. Amount != 0; Reason непустой (пустой → WALLET_ADJUSTMENT_REASON_REQUIRED); счёт существует — иначе WALLET_ACCOUNT_NOT_FOUND (счета создаются lazy кредитами rewards; корректировка несуществующего счёта запрещена — сначала должен появиться счёт).
  3. Идемпотентность. Транзакция (Adjustment, SourceId = Idempotency-Key) уже проведена → вернуть ранее проведённую транзакцию (201, вторая проводка не создаётся — INV-WLT-7, ../../domain/ledger-transaction.md).
  4. Guard no-negative. Итоговый баланс холдерского счёта после корректировки >= 0 — иначе WALLET_BALANCE_NEGATIVE_FORBIDDEN (INV-WLT-3, ../../domain/wallet-account.md); системные счета могут уходить в минус.
  5. Проведение. Одна транзакция Adjustment двойной записью (Σ дебетов = Σ кредитов, INV-WLT-5): Amount > 0 — дебет PlatformSettlement, кредит целевого счёта; Amount < 0 — зеркально (дебет целевого счёта, кредит PlatformSettlement). Актор и Reason (Comment) фиксируются в транзакции. Балансы затронутых счетов, проводки и публикация события — в одном согласованном изменении.
  6. Результат. 201 + WalletTransactionModel с фактическим BalanceAfter.

Побочные эффекты

ТипДетали
Интеграционные событияpin.wallet.transaction-recorded.v1 (key = AccountId, по одному событию на каждую проводку холдерского счёта) — ../../events/wallet-transaction-recorded.md; потребитель notifications (холдер уведомляется об изменении баланса)

Ошибки и failure modes

КодHTTP statusУсловиеСообщениеRetry
WALLET_ACCOUNT_NOT_FOUND404Счёт AccountId не существует«Счёт не найден»no retry
WALLET_ADJUSTMENT_REASON_REQUIRED400Reason пустой«Укажите причину корректировки»no retry
WALLET_BALANCE_NEGATIVE_FORBIDDEN409Холдерский баланс после корректировки < 0 (INV-WLT-3)«Недостаточный баланс счёта»no retry (пересмотреть сумму)
WALLET_CURRENCY_MISMATCH400Валюта операции не совпадает с валютой счёта (RUB-only, ADR-0048)«Валюта не поддерживается»no retry
ValidationError400Amount = 0 / формат полей / нет Idempotency-Keyno retry

Повтор запроса с тем же Idempotency-Key — не ошибка: возвращается ранее проведённая транзакция (идемпотентность INV-WLT-7, WALLET_DUPLICATE_OPERATION — внутренний признак дубля).

Общие UNAUTHORIZED/FORBIDDEN../README.md.

Совместимость и наблюдаемость

  • Контракт стабилен; новые optional-поля запроса/ответа — additive.
  • Logs: актор, AccountId, SourceId, Reasonбез сумм; metrics: wallet_adjustments_total, wallet_adjustment_rejected_total{reason}; traces — traceparent.
  • Каждая корректировка — потенциальный сигнал процессной проблемы: всплеск метрики — повод для разбора источника рассинхрона, а не нормальный режим.

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

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

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