Для тех, кто не читал предыдущие части:


Зачем нужна оплата?


В жизни каждого разработчика телеграм ботов наступает момент, когда необходимо реализовать оплату в вашем боте. И тут у вас есть два пути. Первый — зарегистрировать ИНН, ИП/Юридическое лицо и подключить официальную оплату от телеграма или просто использовать сторонний сервис по типу Free-Kassa, QIWI и т.д. Думаю выбор очевиден, в этой статье я буду использовать QIWI, потому что так хочу.

Для начала давайте подумаем как бот будет проверять что пришло, от кого и какая сумма. Капитан очевидность подсказывает мне, что необходимо будет получить всю историю переводов на аккаунт, который мы будем использовать в качестве нашего счета для приема платежей. Давайте это сделаем:

import requests
import json

QIWI_TOKEN = ''
QIWI_ACCOUNT = ''

s = requests.Session()
s.headers['authorization'] = 'Bearer ' + QIWI_TOKEN  
parameters = {'rows': '50'}
h = s.get('https://edge.qiwi.com/payment-history/v1/persons/'+ QIWI_ACCOUNT +'/payments', params = parameters)
req = json.loads(h.text)

В константу QIWI_TOKEN мы записываем api ключ для работы с QIWI, получить его можно тут. А в QIWI_ACCOUNT мы записываем номер телефона вашего главного счета. Если вы все сделали правильно, ошибок не будет. Данные находятся в словаре req, включающем в себя списки с данными. А точнее (не читать) переменную req включающую словарь data, в котором находится список из нумерованных словарей включающих в себя списки.



Тут мы должны получить номер телефона, комментарий(позже поймете зачем) и сумму транзакции. Для того, чтобы продолжить писать код, вы должны будете уметь использовать базы данных, если вы не ничего не умеете или даже не знаете, что это такое — вот вам ссылка на статью, в которой достаточно понятно описана работа с Sqlite3. Теперь давайте продумаем алгоритм, который будет использован в нашем боте.

  1. Генерируем рандомное число от 100000 до 999999.
  2. Временно заносим данные в таблицу (id пользователя, номер телефона, сумма, сгенерированное ранее рандомное число)
  3. Проверяем комментарий, аккаунт и сумму в словаре req.
  4. Если сумма, телефон и комментарий сошлись — засчитываем оплату.
  5. Добавляем свой функционал после оплаты...

Сейчас вы наверное задумались, а зачем нужно проверять этот комментарий и генерировать рандомное число? А все гениальное — просто. Дело в том, что если мы просто проверим сумму и телефон, то бот сможет найти ранее отправленную транзакцию и засчитать её. Проще говоря, это сделано для безопасности и минимизации багов. Продолжим писать код:

Создаем таблицу:

import sqlite3

c.execute("CREATE TABLE IF NOT EXISTS payment_query(user_id INTEGER, phone TEXT, sum INTEGER, code INTEGER)")

Заносим данные в таблицу, как только пользователь захочет что-то оплатить в вашем боте.

from random import randint

# создаем иссуственные данные, которые хотим проверить
phone = '+79999999999'
sum = 100
random_code = randint(100000, 999999)

c.execute(f"INSERT INTO payment_query VALUES({message.from_user.id}, {phone}, {sum}, {random_code})")
conn.commit()

Далее необходимо сделать какую-то проверку оплаты, в моем случае — это будет инлайн клавиатура:

Вот пример из моего недавнего бота


Как только пользователь нажмет на кнопку оплаты, бот получит историю переводов с QIWI. Теперь нам нужно сделать самое главное — проверку оплаты.

result = c.execute(f"SELECT * FROM payment_query WHERE user_id = {call.message.chat.id}").fetchone() # достаем данные из таблицы

# не рекомендую так делать, но это просто для теста (простите)
phone = result[1] 
random_code = result[3]
sum = result[2]

# проходимся циклом по словарю
for i in range(len(req['data'])):
    if req['data'][i]['account'] == phone:
        if req['data'][i]['comment'] == random_code:
            if req['data'][i]['sum']['amount'] == sum:
                c.execute(f"DELETE FROM payment_query WHERE user_id = {call.message.chat.id}") # удаляем временные данные из таблицы
               # код, который сработает, если оплата прошла успешно

Вот и все, надеюсь я помог вам решить очередную проблему! Заказчики, вы где? Пишите мне в телеграм: dimagorovtsov, жду всех!

Комментарии (6)


  1. andriymoskal
    03.10.2019 23:38
    +1

    Может все же лучше так

    c.execute(f"INSERT INTO payment_query VALUES(?, ?, ?, ?)", message.from_user.id, phone, sum, random_code)


    1. dimagorovtsov Автор
      03.10.2019 23:38
      -1

      кому как удобнее


      1. Groosha
        04.10.2019 01:23
        +1

        Речь не об удобстве, а о безопасности. Ваш вариант, войдя в привычку, в один прекрасный (нет) день приведёт к возможной SQL-инъекции.


  1. rSedoy
    04.10.2019 06:43

    Плохое качество кода: конкатенация с "+", циклы «range(len(», именование переменных.
    Плюс, когда работаете с платежами, очень желательно хранить всю историю и ничего не удалять по ним из базы.


  1. ar2rsoft
    06.10.2019 00:01

    Рандом с платежами как-то не очень внушает доверие. Вероятность совпадения конечно маленькая, но она все же есть.


    Я бы добавил primary key, делал инсерт и полученный айди использовал.


  1. mishell_trickster
    06.10.2019 00:01

    Ага, только киви блокируют все эти кошельки с подозрительными комментами. По крайней мере имеют манеру так делать. По моему каждый мой киви-бот в последствии был забанен(не сам бот, а кошелек админа). Лучше бы о фри-кассе рассказали больше, что бы без сайта интегрировать оплату в бота. Оно вроде по надёжнее Киви.