Интеграция Uzum
Uzum — это быстрорастущая платежная система в Узбекистане. Это руководство показывает, как интегрировать Uzum с PayTechUZ.
Установка
pip install paytechuz
Базовое использование
Создание шлюза
from paytechuz.gateways.uzum.client import UzumGateway
# Инициализация шлюза Uzum (Biller/open-service)
uzum = UzumGateway(
service_id="your_service_id", # ID сервиса Uzum
is_test_mode=True # Установите False в продакшене
)
Создание платежа
# Генерация ссылки для оплаты Uzum Biller
# Формат URL: https://www.uzumbank.uz/open-service?serviceId=...&order_id=...&amount=...&redirectUrl=...
uzum_link = uzum.create_payment(
id="order_123", # ID заказа (параметр order_id)
amount=100000, # сумма в сумах (будет конвертирована в тийины)
return_url="https://example.com/callback" # параметр redirectUrl
)
# Результат: https://www.uzumbank.uz/open-service?serviceId=your_service_id&order_id=order_123&amount=10000000&redirectUrl=https%3A%2F%2Fexample.com%2Fcallback
Интеграция с Django
Settings.py
Добавьте конфигурацию UZUM в настройки PAYTECHUZ:
# settings.py
INSTALLED_APPS = [
# ...
'paytechuz.integrations.django',
]
PAYTECHUZ = {
# ... другие шлюзы
'UZUM': {
'SERVICE_ID': 'your_service_id', # ID сервиса Uzum для Biller URL
'USERNAME': 'your_uzum_username', # Для Basic Auth вебхука
'PASSWORD': 'your_uzum_password', # Для Basic Auth вебхука
'ALLOWED_IPS': ['...'], # адреса Uzum; без него принимается любой
'ACCOUNT_MODEL': 'your_app.models.Order',
'ACCOUNT_FIELD': 'id', # или 'order_id'
'AMOUNT_FIELD': 'amount',
'ONE_TIME_PAYMENT': True, # Set to False if you want to allow multiple payments for the same invoice
}
}
Views.py
Создайте view для вебхука, наследуясь от BaseUzumWebhookView:
# views.py
from paytechuz.integrations.django.views import BaseUzumWebhookView
from .models import Order
class UzumWebhookView(BaseUzumWebhookView):
def successfully_payment(self, params, transaction):
order = Order.objects.get(id=transaction.account_id)
order.status = 'paid'
order.save()
def cancelled_payment(self, params, transaction):
order = Order.objects.get(id=transaction.account_id)
order.status = 'cancelled'
order.save()
URLs.py
Добавьте URL вебхука. Обратите внимание, что вебхуки Uzum используют параметр action в пути URL:
# urls.py
from django.urls import path
from .views import UzumWebhookView
urlpatterns = [
# ...
path('payments/webhook/uzum/<str:action>/', UzumWebhookView.as_view(), name='uzum_webhook'),
]
Что проверяет вебхук
Каждая ошибка возвращается с HTTP 400, status: FAILED и errorCode Uzum:
| Код | Когда |
|---|---|
10001 | неверный логин или пароль либо адрес вне ALLOWED_IPS |
10002 | нечитаемый JSON (только после авторизации вызывающего) |
10003 | неизвестное действие или не POST-запрос |
10005 | нет обязательного параметра |
10006 | serviceId не этой кассы |
10007 | счёт не существует |
10008 | счёт уже оплачен |
10010 | этот transId уже был |
10011 | сумма не равна сумме счёта |
10014 | неизвестный transId |
10015 | транзакция отменена — confirm позже 30 минут после create или для счёта, оплаченного тем временем, тоже отменяет её |
10016 | уже подтверждена |
10017 / 10018 | нельзя вернуть / уже возвращена |
99999 | ваш хук упал; ничего не сохранено |
successfully_payment выполняется в одной транзакции базы данных с confirm.
cancelled_payment вызывается только при возврате подтверждённого платежа;
reverse до confirm никого не уведомляет, и заказ остаётся доступным для
оплаты.
Разрешённые IP-адреса
Uzum обращается с фиксированного набора адресов. Перечислите их для каждой кассы:
PAYTECHUZ = {
'UZUM': {
'KASSAS': {
'shop': {'SERVICE_ID': '...', 'USERNAME': '...', 'PASSWORD': '...',
'ALLOWED_IPS': ['...']},
},
'IP_HEADER': 'HTTP_X_REAL_IP', # куда прокси кладёт адрес вызывающего
'BEHIND_CLOUDFLARE': True, # читать CF-Connecting-IP только от Cloudflare
# ACCOUNT_MODEL и остальное как выше
},
}
По умолчанию IP_HEADER — REMOTE_ADDR. С BEHIND_CLOUDFLARE
CF-Connecting-IP учитывается, только если сам запрос пришёл из
опубликованных диапазонов Cloudflare, поэтому его нельзя подделать.
Sandbox
Касса с IS_SANDBOX: True подтверждает платежи без доставки: вместо
successfully_payment вызывается sandbox_payment(params, transaction), и
заказ остаётся доступным для оплаты тестером Uzum. См.
Несколько касс.