Skip to main content

Интеграция Paynet

Paynet принимает оплату в своём приложении и в терминалах. Он обращается к вашему серверу по JSON-RPC 2.0: находит счёт, проводит платёж и позже проверяет его. Это руководство показывает обе стороны с PayTechUZ.

Установка​

pip install "paytechuz[django]"

Платёжная ссылка​

from paytechuz.gateways.paynet.client import PaynetGateway

paynet = PaynetGateway(merchant_id="your_merchant_id")

# Сумма в тийинах, необязательно
link = paynet.create_payment(id="order_123", amount=15000000)
# https://app.paynet.uz/?m=your_merchant_id&c=order_123&a=15000000

У ссылки нет адреса возврата. На компьютере показывается QR-код, на телефоне открывается приложение Paynet.

Вебхук для Django​

Настройки​

# settings.py
INSTALLED_APPS = [
# ...
'paytechuz.integrations.django',
]

PAYTECHUZ = {
'PAYNET': {
'SERVICE_ID': 'your_service_id',
'USERNAME': 'your_paynet_login',
'PASSWORD': 'your_paynet_password',
'ACCOUNT_MODEL': 'shop.models.Order',
'ACCOUNT_FIELD': 'order_id', # поле, которое Paynet присылает в params.fields
'AMOUNT_FIELD': 'amount', # в модели в сумах; Paynet присылает тийины
'ONE_TIME_PAYMENT': True,
},
}

Выполните python manage.py migrate. Он создаёт таблицу payments и paynet_service_credentials, где хранится пароль, который меняет Paynet.

View​

# views.py
from paytechuz.integrations.django.views import BasePaynetWebhookView

from shop.models import Order


class PaynetWebhookView(BasePaynetWebhookView):
def successfully_payment(self, params, transaction):
Order.objects.filter(id=transaction.account_id).update(status='paid')

def cancelled_payment(self, params, transaction):
Order.objects.filter(id=transaction.account_id).update(status='cancelled')

def get_check_data(self, params, account): # необязательно: GetInformation
return {'fields': {'amount': int(account.amount)}}
# urls.py
path('payments/webhook/paynet/', PaynetWebhookView.as_view(), name='paynet_webhook'),

successfully_payment выполняется в той же транзакции базы данных, что и запись платежа. Если он падает, ничего не сохраняется и Paynet получает 102 — с клиента не списываются деньги за платёж, который вы не приняли.

Что отвечает вебхук​

МетодПоведение
GetInformationвозвращает данные счёта; 302, если счёта нет или он уже оплачен
PerformTransactionоплачивает счёт один раз; 201 на повторный transactionId, 413 на неверную сумму, 411 без transactionId
CheckTransactionсостояние 1 оплачен, 2 отменён, 3 неизвестен
CancelTransaction202, если уже отменён, 203, если неизвестен
GetStatementплатежи за dateFrom…dateTo (YYYY-MM-DD HH:MM:SS), 414 на неверную дату
ChangePasswordсохраняет новый пароль, не короче 8 символов

Неверный логин получает 412 и HTTP 401 ещё до разбора тела запроса. Пустой логин или пароль в настройках отклоняет любой вызов.

Смена пароля​

Paynet меняет пароль вебхука через ChangePassword. PayTechUZ сохраняет его в PaynetCredential (или в модели из CREDENTIAL_MODEL) и дальше проверяет вызовы по нему. Настройка PASSWORD действует только до первой смены, поэтому повторный деплой не вернёт старый пароль.

Sandbox​

Отметьте сервис как sandbox, пока его проверяет тестер Paynet:

PAYTECHUZ = {
'PAYNET': {
'KASSAS': {
'test': {'SERVICE_ID': '1003', 'USERNAME': '...', 'PASSWORD': '...',
'IS_SANDBOX': True},
},
# ACCOUNT_MODEL и остальное как выше
},
}

Каждый вызов пишется в лог; платежи сохраняются, но вместо successfully_payment вызывается sandbox_payment(params, transaction). Оплаченный счёт отвечает 302, как и в боевом режиме, а после перехода сервиса в бой sandbox-записи не попадают в выписку.

Несколько сервисов Paynet на одном URL — на странице Несколько касс.

Дополнительная информация​