Your Company
Боты на aiogram 3: сценарии, состояния и оплата

Боты на aiogram 3: сценарии, состояния и оплата

Автор: Кирилл Сермягин

Платёжный сценарий в Telegram-боте — это машина состояний: пользователь выбирает товары, вводит адрес, получает счёт, оплачивает и ждёт чек. На каждом шаге он может уйти, вернуться через час или нажать «Отмена». aiogram 3 даёт для этого всё необходимое — разберём на примере магазина.

Состояния сценария

Схема: машина состояний бота — приветствие, каталог, корзина, оплата, чек; отмена возвращает в корзину
Состояния магазина. Отмена на любом шаге возвращает в корзину, а не в начало.
from aiogram import F, Router
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.types import Message

router = Router()


class Checkout(StatesGroup):
    cart = State()
    address = State()
    payment = State()


@router.message(Checkout.address, F.text)
async def got_address(message: Message, state: FSMContext):
    await state.update_data(address=message.text)
    await state.set_state(Checkout.payment)
    await message.answer("Адрес сохранён, отправляю счёт.")

Состояние храните в Redis через RedisStorage, а не в памяти: иначе каждый деплой обнуляет корзины всех пользователей.

Счёт и подтверждение оплаты

Перед списанием Telegram присылает pre_checkout_query — последний шанс проверить, что товар есть в наличии. После успешной оплаты приходит сообщение с successful_payment.

@router.pre_checkout_query()
async def pre_checkout(query: PreCheckoutQuery):
    ok = await stock.is_available(query.invoice_payload)
    await query.answer(ok=ok, error_message=None if ok else "Товар закончился")


@router.message(F.successful_payment)
async def paid(message: Message, state: FSMContext):
    await receipts.send(message.from_user.id, message.successful_payment)
    await state.clear()

Чеки по 54-ФЗ

Чек отправляет онлайн-касса, а не бот. Ставьте задачу на отправку в очередь сразу после successful_payment и повторяйте её до успеха: если бот упадёт между оплатой и чеком, задача останется в очереди.

  • Сохраняйте telegram_payment_charge_id — по нему проверяется повторное уведомление.
  • Сумму в счёте передавайте в копейках, целым числом.
  • Логируйте каждый переход состояния: так проще разбирать жалобы «деньги списались, а заказа нет».