docs
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
# `modules/billing` — тарифы, инвойсы, оплата
|
||||
|
||||
## Поток оплаты
|
||||
|
||||
1. **`POST /billing/pay/initiate`** (`initiate_payment`) — сервер сам смотрит цену тарифа
|
||||
в нужной валюте (`plan_prices`, см. [`migrations/0001_init.sql`](../../../migrations/0001_init.sql)),
|
||||
запрашивает текущий курс TON у TonAPI, считает сумму в nanoTON с буфером **+2%**
|
||||
(`calculate_ton_invoice` — компенсация волатильности курса между генерацией инвойса и
|
||||
отправкой транзакции юзером) и создаёт `invoices`-запись со статусом `pending`.
|
||||
Клиент **не может повлиять на сумму** — она целиком считается на сервере.
|
||||
2. Фронтенд получает `{ destination, amount, comment }` и просит кошелёк (TonConnect)
|
||||
отправить транзакцию с этим `comment` (= `invoice_id`) — по нему инвойс потом находится.
|
||||
3. **`POST /billing/pay/confirm`** (`confirm_payment`) — клиент присылает `tx_hash`
|
||||
отправленной транзакции. Сервер:
|
||||
- проверяет, что инвойс принадлежит вызывающему юзеру (иначе можно было бы дёргать
|
||||
чужие `invoice_id` и провоцировать обращения к блокчейну — DoS/перебор);
|
||||
- идемпотентен: повторный вызов на уже `paid` инвойсе — no-op;
|
||||
- просит `TonProvider::verify_payment` сходить в блокчейн и сверить **сумму (>=),
|
||||
адрес назначения и комментарий** транзакции по хешу;
|
||||
- при успехе переводит инвойс в `paid`, активирует подписку (`buy_subscription`,
|
||||
заодно выдаёт один игровой билет, до кэпа в 10) и начисляет рефереру 10% от суммы
|
||||
инвойса (`reward_referrer`).
|
||||
4. **Фоновая сверка** (`reconcile_pending_payments`, гоняется из [`tasks.rs`](../../tasks.rs))
|
||||
находит `pending`-инвойсы младше суток, чьи транзакции уже видны в истории
|
||||
мастер-кошелька (по совпадению `comment == invoice_id`), и доводит их до `paid` — на
|
||||
случай, если клиент не смог/не успел вызвать `/pay/confirm` сам.
|
||||
|
||||
## Провайдеры (`providers/`)
|
||||
|
||||
`PaymentProvider` — трейт, чтобы позже добавить Stripe/YooKassa, не трогая
|
||||
`BillingService`. Сейчас единственная реализация — [`ton::TonProvider`] (HTTP к TonAPI,
|
||||
без собственного состояния кроме адреса мастер-кошелька).
|
||||
|
||||
## Триал
|
||||
|
||||
`activate_trial` доступен только аккаунтам с `tg_id` (см. [`auth/README.md`](../auth/README.md#sybil-защита))
|
||||
и только один раз (`has_used_trial`).
|
||||
|
||||
## Известные ограничения (см. корневой README «Недоделки»)
|
||||
|
||||
Синхронный запрос курса TON на каждый `initiate_payment` и пересборка `providers`
|
||||
(включая повторное чтение env) при каждом `Clone` сервиса — оба помечены `// TODO` прямо
|
||||
в `service.rs`.
|
||||
Reference in New Issue
Block a user