pyQiwiP2P
Project description
pyQiwiP2P
Поддержка прекращена
Есть более качественный инструмент, полностью покрывающий функции pyQiwiP2P: glQiwiApi
Возможно, здесь когда-нибудь будет гайд по миграции на него, но всё в руках сообщества
О библиотеке
Штучка для удобной работы с кивишной апишкой платежей
Есть типа документация, но в ней есть и косячки, поэтому, если найдёте таковой, обязательно сообщите мне. Буду искренне рад. Правда. Спасибо.
Миграция с первой версии:
- Свойство
Bill.actual
было удалено из-за PEP8 QiwiNotify
по умолчанию выполняет только функцию по первому подошедшему хендлеру
⚠️ Важное уведомление [2023.04.05]
Выпуск ключей для приёма P2P платежей через сайт официально закрыт, но метод, заявленный в документации QIWI, продолжает работать, хоть и с несколько изменённой авторизацией.
Инструкция:
- Переходим на https://qiwi.com/p2p-admin
- Авторизуемся в свой Qiwi аккаунт
- Открываем консоль браузера. Как?
- Вставляем код из первого блока и нажимаем enter
- Вставляем код из второго блока и нажимаем enter
- Если прошло успешно:
- появится строка "Private Key: "
- копируем ключ, и используем по назначению
- Если что-то пошло не так:
- смириться, что накосячили
- меня не тревожить
- мне в личку не писать
- кусаюсь и кидаю в чс
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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
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
Algorithm | Hash digest | |
---|---|---|
SHA256 | 4932f5544a55beff0d0ed306c6b5b095dcbb5a19b35cdc8f9b13ad5caef5d72c |
|
MD5 | 310af9863a831939fb572c814b3de8a4 |
|
BLAKE2b-256 | b6ef17c717b3d1ac7e8ff77a1c0e3e1135df0d2646d62f3fabf6acf0e9e5e810 |
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
Algorithm | Hash digest | |
---|---|---|
SHA256 | 99ffbaee2dc18fbffd2aacc6f2409bcd2438ff0dae9fb7b3ae747346d5634eda |
|
MD5 | 6f201eec9678d5a95bab7fd87cae2b47 |
|
BLAKE2b-256 | 2c86e8f65479a11a1e20664780c4ad340d811f6f82cbaa722b7bd415a600240a |