Skip to main content

pyQiwiP2P

Project description

pyQiwiP2P

CodeFactor

Поддержка прекращена

Есть более качественный инструмент, полностью покрывающий функции pyQiwiP2P: glQiwiApi

Возможно, здесь когда-нибудь будет гайд по миграции на него, но всё в руках сообщества

О библиотеке

Штучка для удобной работы с кивишной апишкой платежей

Есть типа документация, но в ней есть и косячки, поэтому, если найдёте таковой, обязательно сообщите мне. Буду искренне рад. Правда. Спасибо.

Миграция с первой версии:

  1. Свойство Bill.actual было удалено из-за PEP8
  2. QiwiNotify по умолчанию выполняет только функцию по первому подошедшему хендлеру

⚠️ Важное уведомление [2023.04.05]

Выпуск ключей для приёма P2P платежей через сайт официально закрыт, но метод, заявленный в документации QIWI, продолжает работать, хоть и с несколько изменённой авторизацией.

Инструкция:

  1. Переходим на https://qiwi.com/p2p-admin
  2. Авторизуемся в свой Qiwi аккаунт
  3. Открываем консоль браузера. Как?
  4. Вставляем код из первого блока и нажимаем enter
  5. Вставляем код из второго блока и нажимаем enter
  6. Если прошло успешно:
    • появится строка "Private Key: "
    • копируем ключ, и используем по назначению
  7. Если что-то пошло не так:
    • смириться, что накосячили
    • меня не тревожить
    • мне в личку не писать
    • кусаюсь и кидаю в чс
function createKeys(name, notification_url) {
    let p2pApiData = JSON.parse(localStorage.getItem("p2p-admin-checkout-oauth-token-head"))
    let token = btoa(p2pApiData["client_id"] + ":" + p2pApiData["access_token"]).replaceAll("=", "")

    let body = {
        keysPairName: name
    }

    if (notification_url) {
        body.serverNotificationsUrl = notification_url
    }

    fetch('https://edge.qiwi.com/widgets-api/api/p2p/protected/keys/create', {
        method: 'POST',
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
            'Authorization': "TokenHeadV2 " + token
        },
        body: JSON.stringify(body),
        credentials: 'include',
    })
    .then(response => {
        console.log(response.status);
        return response.json();
    })
    .then(data => {
        console.log(data);
        console.log("Private Key: "+ data.result.secretKey)
    })
    .catch(error => console.error(error));
}
createKeys("Tokens by WhiteApfel")
// or
createKeys("Tokens by WhiteApfel", "https://qiwi.example.com/any")

⚠️ Важное уведомление [2021.06.13]

С июня Qiwi начала блокировать кошельки, если пользователь открыл страницу оплаты "напрямую", тем самым не передав заголовок referer.

Это случается при открытии ссылки:

  • из мессенджера
  • из смс
  • из письма
  • из адресной строки
  • из браузера с повышенным режимом приватности или расширениями для приватного просмотра

Для обхода всех проблем, кроме последней (она не решается), к объекту Bill был добавлен атрибут Bill.alt_url, который предоставляет ссылку для перенаправления на страницу оплаты через специальную страницу-прокладу, добавляющую этот самый referer.

Страница предоставлена мною, но её можно поднять на своём сервере с помощью docker-контейнера.

  • Исходники: Github
  • Образ контейнера: ghcr.io/whiteapfel/pyqiwip2p:p2proxy
  • Запуск: docker run -p 3600:3600 -e QP2P_DOMAIN='example.com' -d ghcr.io/whiteapfel/pyqiwip2p:p2proxy
  • Свой домен в клиенте: p2p = AioQiwiP2P(PrivKey, alt="example.com")

А как пользоваться

Что есть?

Есть сам класс QiwiP2P, который обладает тремя инструментами: для выставления, проверки и закрытия платежа (счёта).

Пример использования:

from pyqiwip2p import QiwiP2P
from pyqiwip2p.p2p_types import QiwiCustomer, QiwiDatetime, PaymentMethods

QIWI_PRIV_KEY = "abCdef...xYz"

p2p = QiwiP2P(auth_key=QIWI_PRIV_KEY)

# Выставим счет на сумму 228 рублей который будет работать 45 минут
new_bill = p2p.bill(bill_id=212332030, amount=228, lifetime=45)

print(new_bill.bill_id, new_bill.pay_url)

# Проверим статус выставленного счета
print(p2p.check(bill_id=new_bill.bill_id).status)

# Потеряли ссылку на оплату счета? Не проблема!
print(p2p.check(bill_id=245532).pay_url)

# Клиент отменил заказ? Тогда и счет надо закрыть
p2p.reject(bill_id=new_bill.bill_id)

# Если планируете выставлять счета с одинаковой суммой,
# можно воспользоваться параметром default_amount
p2p = QiwiP2P(auth_key=QIWI_PRIV_KEY, default_amount=148)

# Теперь, если не указывать в методе p2p.bill() значение суммы заказа,
# будет применяться указанная базовая сумма
new_bill = p2p.bill(bill_id=6627358)

# А ещё можно не указывать bill_id, тогда значение сгенерируется автоматически.
# Его можно будет посмотреть в объекте ответа Bill
# В комбинации со стандартным значением суммы будет вот так
new_bill = p2p.bill()
print(new_bill.bill_id, new_bill.pay_url)

# Чтобы запретить приём платежей через какой-то метод оплаты, например, карты,
# необходимо передать paySourcesFilter в fields. Туда же можно передать themeCode

fields = {
    "paySourcesFilter": "qw,card",
    "themeCode": "MalchikGay",
}
p2p.bill(fields=fields)

# Либо же воспользоваться удобными полями

p2p.bill(pay_sources=[PaymentMethods.qiwi, PaymentMethods.card])
p2p.bill(pay_sources=[PaymentMethods.qiwi], theme_code="MalchikGay")

А асинхронно могёте?

Могём. Причём примерно так же.

from pyqiwip2p import AioQiwiP2P
from pyqiwip2p.p2p_types import QiwiCustomer, QiwiDatetime, PaymentMethods

QIWI_PRIV_KEY = "abCdef...xYz"

p2p = AioQiwiP2P(auth_key=QIWI_PRIV_KEY)

# Если планируете выставлять счета с одинаковой суммой,
# можно воспользоваться параметром default_amount
p2p = AioQiwiP2P(auth_key=QIWI_PRIV_KEY, default_amount=148)

async def main():
    async with p2p:
        # Выставим счет на сумму 228 рублей который будет работать 45 минут
        new_bill = await p2p.bill(bill_id=212332030, amount=228, lifetime=45)
        
        print(new_bill.bill_id, new_bill.pay_url)
        
        # Проверим статус выставленного счета
        print((await p2p.check(bill_id=new_bill.bill_id)).status)
        
        # Потеряли ссылку на оплату счета? Не проблема!
        print((await p2p.check(bill_id=245532)).pay_url)
        
        # Клиент отменил заказ? Тогда и счет надо закрыть
        await p2p.reject(bill_id=new_bill.bill_id)
        
        # Если не указывать в методе p2p.bill() значение суммы заказа,
        # будет применяться указанная базовая сумма, которую вы установили
        new_bill = await p2p.bill(bill_id=6627358)
        
        # А ещё можно не указывать bill_id, тогда значение сгенерируется автоматически.
        # Его можно будет посмотреть в объекте ответа Bill
        # В комбинации со стандартным значением суммы будет вот так
        new_bill = await p2p.bill()
        print(new_bill.bill_id, new_bill.pay_url)
        
        # Чтобы запретить приём платежей через какой-то метод оплаты, например, карты,
        # необходимо передать paySourcesFilter в fields. Туда же можно передать themeCode
        
        fields = {
            "paySourcesFilter": "qw,card",
            "themeCode": "MalchikGay",
        }
        await p2p.bill(fields=fields)
        
        # Либо же воспользоваться удобными полями
        
        await p2p.bill(pay_sources=[PaymentMethods.qiwi, PaymentMethods.card])
        await p2p.bill(pay_sources=[PaymentMethods.qiwi], theme_code="MalchikGay")

p2p.run(main())
# Аналог
# asyncio.run(main())

И всё?

Нет, не всё. Ещё можно настроить кивишные уведомления на свой сервер, для этого придется немного пострадать, но лишь немного.

Внимание! Для работы будет необходим проксирующий сервер (например, Nginx) с доверенным SSL-сертификатом. Да. Подробнее про требования к проксирующему серверу в документации Qiwi

А эта шайтан-машина нужна для захендлирования функций на события. Она не готова самостоятельно контактировать с внешним миром. Пожалей её.

Запросы сервер по умолчанию принимает на 8099 порту, его можно изменить, и только на /qiwi_notify - изменить нельзя.

from pyqiwip2p.notify import QiwiNotify
from pyqiwip2p.p2p_types import Bill

QIWI_PRIV_KEY = "abCdef...xYz"

qiwi_notify = QiwiNotify(QIWI_PRIV_KEY)

#
# Хэндлер принимает в себя аргументом функцию,
# в которую передаст объект счёта - Bill
#

# Добавим хэндлер, который будет печатать billID для всех счетов
@qiwi_notify.handler(lambda bill: True)
def print_bill(bill: Bill):
	print(bill.bill_id)


# Создадим хэндлер, который будет печатать сумму оплаченных счетов
@qiwi_notify.handler(lambda bill: bill.status == "PAID")
def print_bill(bill: Bill):
	print(bill.amount)


# Теперь запустим сервер на 12345'ом порту
qiwi_notify.start(port=12345)

И асинхронный сервер, наверное, у вас есть?

Да есть. Причём хендлить функции можно и асинхронные, и синхронные.

from pyqiwip2p import QiwiP2P, AioQiwiP2P
from pyqiwip2p.p2p_types import Bill
from pyqiwip2p.notify import AioQiwiNotify
import asyncio

QIWI_PRIV_KEY = "abCdef...xYz"

qiwi_notify = AioQiwiNotify(QIWI_PRIV_KEY)
p2p = AioQiwiP2P(auth_key=QIWI_PRIV_KEY)


@qiwi_notify.handler(lambda bill: bill.status == "EXPIRED")
async def on_expired(bill: Bill):
	new_bill = await p2p.bill(amount=bill.amount, comment=bill.comment)
	print(new_bill.pay_url)


@qiwi_notify.handler(lambda bill: True)
def on_all(bill: Bill):
	print(bill.status)


async def main():
	p = asyncio.get_event_loop()
	server = p.create_task(qiwi_notify.a_start(port=12345))
	await server


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

Настройка проксирующего Nginx

Для порта 12345 (как в примерах выше) будет:

server {
    listen 443;
    server_name qiwinotify.domain.com;
    ssl_certificate      cert.crt;
    ssl_certificate_key  pkey.key;
    location /superSecretQiwiURI {
        proxy_pass http://0.0.0.0:12345/qiwi_notify;
    }
}

В таком случае при генерации ключей API на https://qiwi.com/p2p-admin/transfers/api нужно будет указать https://qiwinotify.domain.com/superSecretQiwiURI в качестве URL для уведомлений

P.S. за неприходящие от Qiwi запросы ответственность не несу, как и за приходящие, кстати, тоже. Если запроса от Qiwi не было, то пишите им в поддержку @qiwi_api_help_bot

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyQiwiP2P-2.0.7.tar.gz (22.1 kB view details)

Uploaded Source

Built Distribution

pyQiwiP2P-2.0.7-py3-none-any.whl (28.7 kB view details)

Uploaded Python 3

File details

Details for the file pyQiwiP2P-2.0.7.tar.gz.

File metadata

  • Download URL: pyQiwiP2P-2.0.7.tar.gz
  • Upload date:
  • Size: 22.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.9.17

File hashes

Hashes for pyQiwiP2P-2.0.7.tar.gz
Algorithm Hash digest
SHA256 4932f5544a55beff0d0ed306c6b5b095dcbb5a19b35cdc8f9b13ad5caef5d72c
MD5 310af9863a831939fb572c814b3de8a4
BLAKE2b-256 b6ef17c717b3d1ac7e8ff77a1c0e3e1135df0d2646d62f3fabf6acf0e9e5e810

See more details on using hashes here.

File details

Details for the file pyQiwiP2P-2.0.7-py3-none-any.whl.

File metadata

  • Download URL: pyQiwiP2P-2.0.7-py3-none-any.whl
  • Upload date:
  • Size: 28.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.9.17

File hashes

Hashes for pyQiwiP2P-2.0.7-py3-none-any.whl
Algorithm Hash digest
SHA256 99ffbaee2dc18fbffd2aacc6f2409bcd2438ff0dae9fb7b3ae747346d5634eda
MD5 6f201eec9678d5a95bab7fd87cae2b47
BLAKE2b-256 2c86e8f65479a11a1e20664780c4ad340d811f6f82cbaa722b7bd415a600240a

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page