
Эта заключительная статья смешивает в себе как часть на Kotlin, самого Web приложения, и на Python, собственно реализация оплаты. Для лучшего понимания рекомендуется прочитать предыдущие части.
Навигация по циклу статей:
Часть 1. Пишем веб-приложение кликер на Kotlin
Часть 2. Пишем кликер для Telegram на Kotlin
Часть 2.5. Аутентификация пользователя с DRF
Часть 3. Добавляем оплату через Telegram Mini Apps на Kotlin - текущая статья
Раскрытые темы в цикле
Web приложение на Kotlin – часть 1
Интеграция приложения с Telegram Mini Apps – часть 2
Работа с элементами интерфейса TMA приложения. Тема,
MainButton,BackButton– часть 2Поделиться ссылкой на приложение через Telegram. Передача данных через ссылку – часть 2
Аутентификации через TMA приложение – часть 2 и 2.5
Telegram Payments API– часть 3
Подключение Telegram Payments API
Telegram Payments API самостоятельно не принимает платежи, он лишь может получить данные о доставке и пользователе и отправить их в бот вместе со статусом оплаты.
Для работы с платежами потребуется подключить один из провайдеров:
Возвращаемся в BotFather к нашему боту и настраиваем его
Payments>>Paymaster>>Connect Paymaster Test.Выбираем любой интересующий вас провайдер. Для проверки рекомедуем “Paymaster: тест”
Нас перебрасывает в бот “Paymaster: тест”, который подключит наш бот к своей системе.
Теперь возвращаемся к BotFather, который отправляет нам токен.
Можно выбрать любой другой провайдер, однако именно Paymaster прост для тестового запуска, п��скольку не требует никакой сторонней регистрации.
Теперь мы можем принимать оплату через наш бот, осталось только его настроить на это. Архитектура оплаты из TMA приложения проста:
Приложение отправляет на сервер запрос на сервер.
Сервер генерирует ссылку для оплаты и отправляет её TMA приложение
Клиент открывает экран оплаты
webApp.openInvoice(url)После нажатия «Оплатить» в бот посылается событие
pre_checkout_query, на которое он должен в течение 10 секунд ответитьЕсли бот разрешает оплату, она проходит и в бот приходит новое событие об успешной оплате
successful_payment
Если вы используете другой провайдер, то этапы могут измениться
Отправляем запрос на оплату
Добавим в наш кликер премиум аккаунты, чтобы лучше кликалось. Создаём кнопку, по нажатию на которую будет отправляться запрос на сервер на генерацию ссылки и открываться меню для оплаты после получения ответа. После оплаты будем показывать сообщение со статусом оплаты.
@Composable
fun PayButton() {
val coroutineScope = rememberCoroutineScope()
Button(
attrs = {
classes(ClickerStyles.PayButton)
onClick {
coroutineScope.launch {
val link = TapClient.fetchUpgradeLink()
webApp.openInvoice(link) {
when (it.statusTyped) {
InvoiceStatus.Cancelled -> webApp.showAlert(message = "Оплата отменена")
InvoiceStatus.Failed -> webApp.showAlert(message = "Ошибка оплаты")
InvoiceStatus.Paid -> webApp.showAlert(message = "Оплата принята")
else -> {}
}
}
}
}
}
) {
Text("Upgrade")
}
}
Настройка сервера на генерацию ссылки
Теперь вернёмся к нашему серверу. Именно здесь проходит основная работа по оплате.
Теперь можно установить библиотеку для работы с Telegram Bot API и добавить в настройки наш токен для провайдера оплаты.
pip install pyTelegramBotAPI
Почему именно эта библиотека, а не IOGram или python-telegram-bot? Ответ: она может работать в синхронных функциях. По хорошему пора переходить на async, но пока DRF поддерживает (хотя есть и ADRF), используем что имеем.
Поскольку мы используем ngrok, у нас уже есть https ссылка, следовательно нам доступна возможность использовать WebHooks.
Для начала создадим новое приложение для нашего проекта, ненужные файлы можно удалить.
python manage.py startapp bot

Далее в bot.py создадим сам объект бота, который будут использовать остальные части приложения.
import telebot
from django.conf import settings
bot = telebot.TeleBot(settings.TELEGRAM_API_TOKEN, parse_mode="HTML")
Теперь мы можем импортировать экземпляр нашего бота из Django приложения и с его помощью создать ссылку на оплату через bot.create_invoice_link
class UpgradeAPIView(APIView):
authentication_classes = [TMAAuthentication]
permission_classes = [IsAuthenticated]
def post(self, request: Request):
if request.user.is_premium:
raise Exception() # Обработать логику, если пользователь уже имеет премиум
return Response(
data={
'invoice_link': bot.create_invoice_link(
title='Оплата премиум статуса',
description='С премиумом тапается лучше! Проложи дорогу к криптоинвестициям',
payload=f'user_{request.user.id}',
provider_token=settings.TELEGRAM_PAYMENTS_PROVIDER_TOKEN,
currency='RUB',
prices=[LabeledPrice(label='Премиум статус', amount=5000)],
need_name=True,
need_email=True,
need_phone_number=False,
need_shipping_address=False,
)
}
)
Теперь по нажатию на кнопку «Upgrade» открывается меню оплаты
Для справки: поскольку используется тестовый провайдер, деньги списываться не будет. Можно использовать тестовые данные карты.
Номер карты: 4242 4242 4242 4242
Дата истечения: любая будущая
CVV: любой

Подробнее о возможностях настройки заказа в документации библиотеки и Telegram.
Обработка подтверждения оплаты.Обработка подтверждения оплаты.
Однако сейчас оплата проходить не может, нужно её подтвердить в течение 10 секунд уже через бот. На протяжении всего цикла мы ни разу не запустили бота, именно в этот момент мы первый раз и его и запустим.
Создадим обработчик post запросов, который будет направлять содержимое запросов в bot
# многое не обработно, не используйте код в таком виде
@require_POST
@csrf_exempt
def tg_webhook(request):
update = telebot.types.Update.de_json(request.body.decode('utf-8'))
bot.process_new_updates([update])
return HttpResponse(status=200)
Осталось подключить этот запрос по какому либо пути в urls.py
urlpatterns = [
path('tg-webhook/', views.tg_webhook)
]
Установим WebHook на старте нашего приложения в apps.py
class BotConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'bot'
def ready(self):
if 'runserver' not in sys.argv:
return True
from bot.bot import bot
bot.set_webhook(settings.WEBHOOK_URL) # WEBHOOK_URL берётся из конфига Django.
Добавим обработчик pre_checout_query в bot.py , который будет проверять, не куплен ли премиум у а��каунта, для которого совершается оплата. get_user_id_from_payload получает user_id, который мы передавали через payload в момент создания ссылки
# ...
# don’t use in real code, it is example
@bot.pre_checkout_query_handler(lambda query: True)
def pre_checkout_query_handler(query: PreCheckoutQuery):
id = get_user_id_from_payload(query.invoice_payload)
if id is None:
return bot.answer_pre_checkout_query(pre_checkout_query_id=int(query.id), ok=False)
user = TelegramUser.objects.get(id=id)
if user.is_premium:
return bot.answer_pre_checkout_query(pre_checkout_query_id=int(query.id), ok=False,
error_message='User already has premium')
return bot.answer_pre_checkout_query(pre_checkout_query_id=int(query.id), ok=True)
# ...
Всё готово, теперь оплата будет проходить или завершаться с ошибкой, если статус уже куплен. Осталось только обработать успешную оплату.
После успешной оплаты бот получает другое событие. Это сообщение типа successful_payment. Мы можем обрабатывать такие сообщения и присваивать пользователю премиум статус.
@bot.message_handler(content_types=['successful_payment'])
def successful_payment_handler(message: Message):
id = get_user_id_from_payload(message.successful_payment.invoice_payload)
if id is None:
return
user = TelegramUser.objects.get(id=id)
user.is_premium = True
user.save()
Итоги
Это завершающая статья из цикла Telegram Mini Apps на Kotlin. В нём мы разобрали все этапы разработки TMA кликера. Однако стоит предупредить, что это лишь код для примера. В реальном приложении нужно использовать более сложную логику как в клиентском приложении, так и в серверной части.
TMA – это способ расширить возможности существующего веб-приложения. Интеграция в нём позволяет получить доступ к большому количеству функций, которые не доступны обычному веб-приложению.
Это не весь список доступного API, однако то, что будет чаще всего использоваться в нашем цикле представлено, и если бизнес поймёт важность приложений на TMA, то это направление начнёт очень сильно развиваться, хотя пока выбран не самый удобный способ взаимодействия – через бот.
