Боты на 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— по нему проверяется повторное уведомление. - Сумму в счёте передавайте в копейках, целым числом.
- Логируйте каждый переход состояния: так проще разбирать жалобы «деньги списались, а заказа нет».