Платёжные сценарии¶
Подборка ключевых сюжетов, которые ежедневно проживает кошелёк OneWallet: от перевода другу до пополнения через банк и корректирующих операций администратора. Для каждого сценария — описание участников, ход событий, точки ветвления и диаграмма последовательности. Технические подробности (имена таблиц, протоколы, идентификаторы счетов) намеренно опущены — их место в разделе dev/.
В заголовках в скобках указано техническое имя операции — оно служит точкой связи с разделом для разработчиков. В прозе же мы остаёмся в терминах пользователя: «Клиент», «Магазин», «Банк», «Платёжный менеджер».
1. «Алиса переводит Бобу» (P2P_TRANSFER)¶
Самый частый сценарий: один житель кошелька отправляет деньги другому. Алиса открывает приложение, выбирает Боба из списка контактов, вводит сумму и подтверждает перевод биометрией. Через мгновение Боб получает push-уведомление о зачислении.
Перевод между двумя пользователями кошелька выполняется мгновенно и не требует обращения во внешний банк — деньги уже находятся внутри системы, нужно лишь переписать остатки между внутренними счетами. Поскольку перевод не покидает периметр кошелька, комиссии за него обычно нет (или она минимальна и заранее показывается Алисе на экране подтверждения).
Ключевые моменты:
- Алиса видит итоговую сумму к списанию до подтверждения — не «примерно столько», а ровно столько.
- Если у Алисы не хватает средств, операция отклоняется до того, как Боб что-либо узнает.
- Боб получает уведомление сразу после успешного зачисления и видит перевод в истории операций как доход.
- Алиса видит свой перевод как расход с пометкой получателя.
sequenceDiagram
actor Алиса as Алиса
participant App as Приложение
participant Auth as Auth Center
participant PM as Платёжный менеджер
actor Боб as Боб
Алиса->>App: выбирает Боба, вводит сумму
App->>Auth: запрос на перевод
Auth->>PM: создать платёж (от Алисы к Бобу)
PM->>PM: проверка остатка и лимитов
PM->>PM: списание со счёта Алисы, зачисление Бобу
PM-->>Auth: успех
Auth-->>App: подтверждение перевода
App-->>Алиса: «Перевод выполнен»
PM->>Боб: push-уведомление «Вам поступил перевод»
2. «Магазин выставляет счёт через QR» (MERCHANT_INVOICE / INVOICE_PAYMENT)¶
В кафе кассир пробивает заказ на 320 бат и нажимает «Принять оплату». На экране кассы появляется QR-код. Клиент наводит камеру приложения, видит сумму и название кафе, подтверждает оплату — и кассир сразу слышит писк подтверждения.
Этот сценарий отличается от P2P тем, что он двухфазный: магазин первым формирует приглашение к оплате (инвойс), а клиент — отдельным действием — это приглашение принимает. До момента подтверждения клиентом со счёта никто ничего не списывает, инвойс просто «висит» в системе и ждёт.
Что важно понимать про инвойсы:
- У инвойса есть срок жизни: если клиент не подтвердил за условные 5 минут, QR «протухает» и оплатить по нему уже нельзя — кассиру придётся пробить заказ заново.
- Магазин может отменить инвойс сам — например, если клиент передумал и ушёл.
- В момент создания инвойса плательщик ещё неизвестен — он определяется только когда кто-то сканирует QR.
- Сумма и реквизиты в QR подписаны магазином, чтобы клиент не мог «подменить» сумму в приложении.
- Комиссия эквайринга (если она есть) удерживается с магазина, а не с клиента — клиент видит ровно ту сумму, что на чеке.
sequenceDiagram
actor Магазин as Магазин (касса)
participant PM as Платёжный менеджер
actor Клиент as Клиент
participant App as Приложение
Магазин->>PM: создать инвойс на 320 бат
PM->>PM: сохранить инвойс, выпустить подписанный QR
PM-->>Магазин: QR-код
Магазин-->>Клиент: показывает QR на экране кассы
Клиент->>App: сканирует QR
App->>PM: запрос реквизитов инвойса
PM-->>App: сумма, название магазина, срок
App-->>Клиент: «Оплатить 320 бат в Кафе Лотос?»
Клиент->>App: подтверждает биометрией
App->>PM: подтвердить оплату инвойса
PM->>PM: списание с клиента, зачисление магазину
PM-->>App: успех
PM->>Магазин: уведомление «оплачено»
App-->>Клиент: «Чек на 320 бат»
3. «Клиент тапает NFC-меткой в магазине» (NFC_CHARGE)¶
В небольшой лавке висит наклейка с NFC-меткой. Клиент подносит к ней телефон, в приложении мгновенно появляется экран «Оплатить 80 бат в Лавке у дома?», клиент подтверждает — и продавец получает оповещение об оплате.
В отличие от QR-инвойса, здесь сценарий синхронный и инициируется со стороны магазина по факту касания: NFC-метка передаёт приложению идентификатор магазина и (если задано) фиксированную сумму, после чего платёж проходит за один шаг, без отдельной фазы «создать инвойс — подождать клиента». По сути это «pull-charge»: магазин запрашивает деньги, и при подтверждении клиента они списываются немедленно.
Особенности этого сценария:
- Касание метки не списывает деньги автоматически — клиент обязательно подтверждает оплату в приложении.
- Метка может быть «открытой» (продавец называет сумму голосом, клиент вводит её сам) или «фиксированной» (например, парковка за 50 бат — сумма прошита в метке).
- Сценарий рассчитан на быстрые мелкие платежи — кофе, парковка, проезд, маленькие магазины — и оптимизирован под минимум тапов.
- Если клиент не подтвердил за несколько секунд, операция автоматически отменяется и никакой «висящей» транзакции не остаётся.
sequenceDiagram
actor Клиент as Клиент
participant App as Приложение
participant NFC as NFC-метка магазина
participant PM as Платёжный менеджер
actor Магазин as Магазин
Клиент->>NFC: подносит телефон
NFC-->>App: ID магазина (и сумма, если задана)
App-->>Клиент: «Оплатить 80 бат в Лавке у дома?»
Клиент->>App: подтверждает
App->>PM: запрос на списание в пользу магазина
PM->>PM: проверка лимитов и остатка
PM->>PM: списание с клиента, зачисление магазину
PM-->>App: успех
App-->>Клиент: «Оплачено»
PM->>Магазин: уведомление о новом платеже
4. «Пользователь выводит деньги на банковский счёт» (WITHDRAWAL / IPPS_WITHDRAWAL)¶
Алиса хочет перевести 5 000 бат из кошелька на свой банковский счёт. Она выбирает в приложении «Вывести», указывает счёт получателя (либо номер телефона, привязанный к PromptPay), сумму и подтверждает операцию. Через несколько секунд деньги уходят в банк-получатель.
Это первый сценарий, где появляется внешний участник — банк. Деньги не просто перекладываются внутри кошелька, а физически уходят в банковскую систему. Поэтому здесь:
- Появляется реальная комиссия за межбанковский перевод, которую кошелёк показывает Алисе на экране подтверждения.
- Операция не моментальная: банковский перевод может занять от секунд до минут.
- Пока банк не подтвердил приём, деньги у Алисы уже зарезервированы (нельзя потратить их повторно), но ещё не «ушли окончательно». Это промежуточное состояние видно в истории как «в обработке».
- Если банк отклонил перевод (неверные реквизиты, недоступность), деньги возвращаются на счёт Алисы автоматически — без обращения в поддержку.
sequenceDiagram
actor Алиса as Алиса
participant App as Приложение
participant PM as Платёжный менеджер
participant Банк as Банк-получатель
Алиса->>App: «Вывести 5 000 бат на счёт X»
App->>PM: запрос на вывод
PM->>PM: проверка лимитов, расчёт комиссии
PM-->>App: «к списанию 5 015 бат» (с комиссией)
Алиса->>App: подтверждает
App->>PM: подтверждение вывода
PM->>PM: резервирует деньги, статус «в обработке»
PM->>Банк: отправить перевод
PM-->>App: «Вывод в обработке»
App-->>Алиса: «Перевод отправлен»
Банк-->>PM: подтверждение зачисления
PM->>PM: окончательное списание
PM->>Алиса: push «Вывод выполнен»
5. «Пользователь пополняет кошелёк через банк» (QP_TOPUP)¶
Боб открывает приложение, выбирает «Пополнить», указывает сумму 2 000 бат и видит QR-код для оплаты со своего банковского приложения. Он переходит в банк, оплачивает по QR — и через несколько секунд получает уведомление, что 2 000 бат уже в кошельке.
Пополнение — зеркальный сценарий к выводу. Здесь деньги идут из банка в кошелёк. Особенности:
- Кошелёк сам не инициирует перевод — он лишь выпускает «приглашение» (QR или реквизиты), а клиент оплачивает их со стороны банка.
- До момента, пока банк не подтвердил приход денег, на счёте Бобу ничего не отображается — никаких «висящих» пополнений в истории нет.
- Когда банк передаёт уведомление о поступлении, кошелёк сверяет сумму и реквизиты с приглашением и зачисляет деньги.
- Если клиент случайно перевёл другую сумму или по неверным реквизитам, кошелёк удерживает деньги в служебном статусе и связывается с пользователем для разбора.
- Комиссия за пополнение (если есть) обычно небольшая или отсутствует — это входная воронка, и владелец кошелька заинтересован, чтобы она была дешёвой.
sequenceDiagram
actor Боб as Боб
participant App as Приложение
participant PM as Платёжный менеджер
participant Банк as Банк Боба
Боб->>App: «Пополнить на 2 000 бат»
App->>PM: запрос на пополнение
PM->>PM: выпустить приглашение (QR, реквизиты)
PM-->>App: QR-код пополнения
App-->>Боб: показывает QR
Боб->>Банк: оплачивает QR из банковского приложения
Банк-->>PM: уведомление о поступлении 2 000 бат
PM->>PM: сверка с приглашением, зачисление Бобу
PM->>Боб: push «Кошелёк пополнен на 2 000 бат»
App-->>Боб: новый баланс
6. «Перевод между сервисными счетами» (SERVICE_DEPOSIT)¶
Не все операции инициирует пользователь. Иногда сам кошелёк должен переместить деньги между внутренними «карманами»: например, начислить пользователю кэшбэк, бонус за приглашённого друга или вернуть удержанную комиссию.
Снаружи такая операция выглядит как «деньги внезапно появились на счёте» — с понятной подписью в истории: «Кэшбэк за оплату в Кафе Лотос», «Бонус за регистрацию», «Возврат комиссии». Изнутри это служебный перевод: со специального технического счёта, на котором лежит бюджет программы лояльности, деньги перетекают на счёт пользователя.
Что отличает служебные переводы:
- Их инициирует не пользователь, а другой сервис системы (бонусная программа, программа возвратов, маркетинг).
- Пользователь не подтверждает их вручную — он просто видит уведомление о начислении.
- Каждый такой перевод обязательно имеет читаемое описание — пользователь должен понять, за что ему начислили.
- Источник средств — конкретный технический счёт с прозрачным бюджетом; нельзя «начислить из ниоткуда».
sequenceDiagram
participant Бонус as Бонусная программа
participant Auth as Auth Center
participant PM as Платёжный менеджер
actor Пользователь as Пользователь
participant App as Приложение
Бонус->>Auth: «Начислить 50 бат пользователю X за кэшбэк»
Auth->>PM: запрос на служебное зачисление
PM->>PM: проверка бюджета программы
PM->>PM: списание с бюджета, зачисление пользователю
PM-->>Auth: успех
PM->>Пользователь: push «Вам начислен кэшбэк 50 бат»
App-->>Пользователь: показывает запись в истории с описанием
7. «Корректирующая операция администратора» (ADMIN_TRANSFER)¶
В редких случаях нужно вручную скорректировать остаток: банк ошибочно отправил двойное пополнение, пользователь жалуется на пропавший перевод и проверка подтверждает проблему, или нужно вернуть деньги при разборе спора. Для таких случаев существует отдельный сценарий — административный перевод.
Он намеренно отделён от всех остальных, потому что:
- Каждая такая операция оставляет след. Указывается администратор, причина, ссылка на тикет или решение. Просто «передвинуть деньги» без обоснования нельзя.
- Требуется повышенное подтверждение. Сумма выше порога обычно подтверждается вторым администратором (правило четырёх глаз) — никто в одиночку не может произвольно крупно изменить остаток.
- Пользователь всегда видит, что операцию провёл администратор. В истории такой записи появляется явная пометка с описанием причины, чтобы клиент понимал, что произошло, и не подозревал ошибку.
- Деньги перемещаются между существующими счетами — административный перевод не «печатает» новые деньги, он лишь исправляет, кому они принадлежат.
sequenceDiagram
actor Админ as Администратор
participant Admin as Админ-панель
participant PM as Платёжный менеджер
actor Пользователь as Пользователь
participant App as Приложение
Админ->>Admin: открывает тикет, выбирает «Корректировка»
Admin->>Admin: проверка прав, запрос причины и суммы
Админ->>Admin: указывает: «Возврат двойного списания», 500 бат
Admin->>PM: запрос на админ-перевод с обоснованием
alt Сумма выше порога
PM->>Admin: «Нужно подтверждение второго администратора»
Admin-->>Админ: ждёт согласования
Админ->>Admin: второй администратор подтверждает
end
PM->>PM: выполнить перевод, записать причину и автора
PM-->>Admin: успех
PM->>Пользователь: push «Корректировка: возврат 500 бат»
App-->>Пользователь: запись в истории с пометкой «Операция администратора. Причина: возврат двойного списания»
Что общего у всех сценариев¶
Несмотря на разнообразие, все эти истории следуют одной и той же канве:
- Намерение — кто-то (пользователь, магазин, сервис, администратор) формулирует, что должно произойти.
- Проверка — Платёжный менеджер сверяется с правилами: достаточно ли средств, не превышены ли лимиты, корректны ли реквизиты.
- Исполнение — деньги перемещаются между счетами или уходят/приходят из банка.
- Уведомление — все заинтересованные стороны получают подтверждение (push, запись в истории, ответ в API).
- След — каждая операция оставляет неизменяемую запись с автором, временем и причиной, доступную для разбора.
Эта общая канва — то, что делает кошелёк предсказуемым: какой бы экзотический ни был сценарий, он раскладывается на одни и те же пять шагов.