MBL
Go / Проекты / WebJesus / WebJesus — баланс и платежи
Go средний

WebJesus — баланс и платежи

projectspythonpayments

Разбор на реальном коде google_ai_scrapper/handlers/admin.py — списание баланса, пополнение, два платёжных провайдера.

Архитектурная схема (archify) →

Баланс списывается ДО обработки, за весь батч разом

check_and_deduct_balance(user_id, amount) — атомарная проверка-и-списание: читает user.balance_rub, если хватает — сразу вычитает processing_cost (цена парсера × число строк в файле). Это происходит ДО вызова process_file_with_parser(), то есть до того, как хоть одна строка реально ушла в парсер.

# Deduct balance
success = await check_and_deduct_balance(user_id, processing_cost)
if not success:
    await message.answer(...)  # баланс не хватило — обработка не начинается
    return
# Start processing
await process_file_with_parser(message, state, bot, parser_type)

Ключевой факт, который нашёлся при поиске по коду: возврата средств за отдельные строки, вернувшие "ERROR" внутри батча, в коде НЕТ — ни одного вхождения refund/возврата баланса по всему репозиторию. Пользователь платит за весь батч по факту отправки на обработку, а не по факту успеха каждой строки.

Что стоит сказать на собесе про этот выбор: списание постфактум (по числу реально успешных строк) было бы честнее к пользователю, но сильно усложнило бы модель — пришлось бы держать баланс "замороженным" на время обработки, обрабатывать частичный возврат, защищаться от гонки между несколькими одновременными батчами одного пользователя. Списание авансом — осознанно более простая модель ценой риска для пользователя при нестабильном внешнем API (капча, блокировка) — компромисс, который стоит уметь явно назвать и объяснить, а не выдавать за случайный недосмотр.

Два независимых платёжных провайдера

Пополнение доступно суммами 499/1499/2999/4999₽, выбор провайдера — отдельным шагом ПОСЛЕ выбора суммы: пользователь видит две кнопки, pay_tbank:{amount} или pay_lava:{amount}, оба ведут на разные callback-хендлеры (callback_pay_tbank/аналогичный для Lava). T-Bank и Lava.top работают независимо — это не fallback друг друга, а равноправный выбор пользователя, вероятно продиктованный тем, что у разных провайдеров разные ограничения на юрлицо/сумму/комиссию.

Начисление баланса после оплаты (user.balance_rub += transaction.amount) происходит в обработчике вебхука провайдера, а не сразу при создании счёта — то есть баланс реально приходит только после подтверждения оплаты снаружи, не по факту нажатия кнопки "оплатить" пользователем.

Тарифы одной строкой

Yandex — 5₽/запрос, Google — 3₽/запрос (комментарий в самом коде: "User tops up balance, then pays per query"), бонус за подписку на канал и разовый приветственный бонус — оба защищены флагами welcome_bonus_received/channel_bonus_received в модели User, чтобы не начислялись повторно при повторном вызове того же хендлера.

Самопроверка 0 / 2
Знаю, что баланс списывается ДО обработки файла, за весь батч целиком, без возврата за отдельные неудачные строки
Помню, что T-Bank и Lava.top — два независимых платёжных провайдера, выбор на стороне пользователя
Как усвоено?