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).
| Поле | Значение |
|---|
| Сервис/контекст | wallet |
| API area | platform |
| Feature group | platform-wallet |
| Статус | draft |
| Документ | docs/06-services/wallet/api/platform/create-wallet-adjustment.md |
Актор и доступ
| Проверка | Значение |
|---|
| Actor type | Operator(Admin) (оператор ПИН) |
| Auth policy / Permissions | wallet.adjustments.manage |
| Scope (RBAC) | платформа |
| Audit | create: актор, счёт, сумма, причина — полный аудит-след в самой транзакции журнала |
HTTP-контракт
| Поле | Значение |
|---|
| Method | POST |
| Route | /api/v1/platform/wallet/adjustments |
| Success status | 201 |
| Idempotency header | Idempotency-Key (Guid) — обязателен; становится SourceId транзакции |
| Correlation | сквозной trace через заголовок traceparent |
Входные данные / параметры запроса
| Поле | Источник | Тип | Обязательность | Валидация / Ограничения | Безопасность |
|---|
IdempotencyKey | header | Guid | Да | не пустой; становится SourceId транзакции (уникальность в паре с видом операции, INV-WLT-7) | — |
AccountId | body | Guid | Да | существующий счёт (любого вида, включая системные) | — |
Amount | body | decimal | Да | != 0, scale 2; положительная — увеличить баланс счёта (кредит), отрицательная — уменьшить (дебет) | Sensitive — в логи не пишется |
Reason | body | string | Да | 1..1000 символов — обязательная человекочитаемая причина (ссылка на инцидент/разбор); маппится в Comment транзакции | — |
Модель ответа
WalletTransactionModel проведённой транзакции (дом — ../README.md): OperationKind = Adjustment, Amount со знаком относительно скорректированного счёта, BalanceAfter — новый баланс,
SourceId = Idempotency-Key.
Алгоритм
- Контекст и доступ. Оператор ПИН с permission
wallet.adjustments.manage, платформенный scope —
иначе FORBIDDEN.
- Проверка входа.
Amount != 0; Reason непустой (пустой →
WALLET_ADJUSTMENT_REASON_REQUIRED); счёт существует — иначе WALLET_ACCOUNT_NOT_FOUND (счета
создаются lazy кредитами rewards; корректировка несуществующего счёта запрещена — сначала должен
появиться счёт).
- Идемпотентность. Транзакция (
Adjustment, SourceId = Idempotency-Key) уже проведена →
вернуть ранее проведённую транзакцию (201, вторая проводка не создаётся — INV-WLT-7,
../../domain/ledger-transaction.md).
- Guard no-negative. Итоговый баланс холдерского счёта после корректировки
>= 0 — иначе
WALLET_BALANCE_NEGATIVE_FORBIDDEN (INV-WLT-3,
../../domain/wallet-account.md); системные счета могут уходить в минус.
- Проведение. Одна транзакция
Adjustment двойной записью (Σ дебетов = Σ кредитов, INV-WLT-5):
Amount > 0 — дебет PlatformSettlement, кредит целевого счёта; Amount < 0 — зеркально (дебет
целевого счёта, кредит PlatformSettlement). Актор и Reason (Comment) фиксируются в транзакции.
Балансы затронутых счетов, проводки и публикация события — в одном согласованном изменении.
- Результат.
201 + WalletTransactionModel с фактическим BalanceAfter.
Побочные эффекты
| Тип | Детали |
|---|
| Интеграционные события | pin.wallet.transaction-recorded.v1 (key = AccountId, по одному событию на каждую проводку холдерского счёта) — ../../events/wallet-transaction-recorded.md; потребитель notifications (холдер уведомляется об изменении баланса) |
Ошибки и failure modes
| Код | HTTP status | Условие | Сообщение | Retry |
|---|
WALLET_ACCOUNT_NOT_FOUND | 404 | Счёт AccountId не существует | «Счёт не найден» | no retry |
WALLET_ADJUSTMENT_REASON_REQUIRED | 400 | Reason пустой | «Укажите причину корректировки» | no retry |
WALLET_BALANCE_NEGATIVE_FORBIDDEN | 409 | Холдерский баланс после корректировки < 0 (INV-WLT-3) | «Недостаточный баланс счёта» | no retry (пересмотреть сумму) |
WALLET_CURRENCY_MISMATCH | 400 | Валюта операции не совпадает с валютой счёта (RUB-only, ADR-0048) | «Валюта не поддерживается» | no retry |
ValidationError | 400 | Amount = 0 / формат полей / нет Idempotency-Key | — | no 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.
- Каждая корректировка — потенциальный сигнал процессной проблемы: всплеск метрики — повод для разбора
источника рассинхрона, а не нормальный режим.
Обратные ссылки
Автоссылки: где используется этот документ.
Связанные документы