Skip to main content

Интеграция с Django

Полное руководство по интеграции PayTechUZ с Django приложениями.

Готовые примеры проектов

Ищете готовые Django проекты? У нас есть комплексные примеры для различных платёжных сценариев:

  • 🛒 Пример Shop - Полная интеграция электронной коммерции с платежами на основе заказов через Payme, Click. Идеально для интернет-магазинов и маркетплейсов.

  • 🚕 Пример Taxi - Полная реализация пополнения баланса кошелька через Payme, Click, Uzum. Идеально для сервисных приложений, служб такси и систем на основе баланса.

Оба примера включают полную настройку Django, обработчики вебхуков и готовый к продакшену код!

Установка

Установите PayTechUZ с поддержкой Django:

pip install paytechuz[django]

Настройки Django

Добавьте конфигурацию PayTechUZ в настройки Django:

note

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

# settings.py

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

PAYTECHUZ = {
'PAYME': {
'PAYME_ID': 'your_payme_id',
'PAYME_KEY': 'your_payme_key',
'ACCOUNT_MODEL': 'payment.models.Invoice', # Your invoice model
'ACCOUNT_FIELD': 'id',
'AMOUNT_FIELD': 'amount',
'ONE_TIME_PAYMENT': True,
'IS_TEST_MODE': True, # Set to False in production
},
'CLICK': {
'SERVICE_ID': 'your_service_id',
'MERCHANT_ID': 'your_merchant_id',
'MERCHANT_USER_ID': 'your_merchant_user_id',
'SECRET_KEY': 'your_secret_key',
'ACCOUNT_MODEL': 'payment.models.Invoice',
'ACCOUNT_FIELD': 'id',
'COMMISSION_PERCENT': 0.0,
'ONE_TIME_PAYMENT': True,
'IS_TEST_MODE': True, # Set to False in production
},
'UZUM': {
'SERVICE_ID': 'your_service_id', # ID сервиса Uzum для Biller URL
'USERNAME': 'your_uzum_username', # Для Basic Auth вебхука
'PASSWORD': 'your_uzum_password', # Для Basic Auth вебхука
'ACCOUNT_MODEL': 'payment.models.Invoice',
'ACCOUNT_FIELD': 'id', # или 'id'
'AMOUNT_FIELD': 'amount',
'ONE_TIME_PAYMENT': True, # Set to False if you want to allow multiple payments for the same invoice
'IS_TEST_MODE': True, # Установите False в продакшене
},
'PAYNET': {
'MERCHANT_ID': 'your_merchant_id', # Paynet Merchant ID
'SERVICE_ID': 'your_paynet_service_id',
'USERNAME': 'your_paynet_username',
'PASSWORD': 'your_paynet_password',
'ACCOUNT_MODEL': 'payment.models.Invoice',
'ACCOUNT_FIELD': 'id',
'AMOUNT_FIELD': 'amount',
'ONE_TIME_PAYMENT': True,
'IS_TEST_MODE': True,
}
}

Создайте модели для обработки заказов и платежей:

# shop/models.py
from django.db import models
from django.contrib.auth.models import User

class Order(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
product_name = models.CharField(max_length=255)
total_amount = models.DecimalField(max_digits=12, decimal_places=2)
created_at = models.DateTimeField(auto_now_add=True)

def __str__(self):
return f"Order {self.id} - {self.product_name}"

# payment/models.py
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
from shop.models import Order # Import Order from shop app

class Invoice(models.Model):
STATUS_CHOICES = (
('pending', 'Pending'),
('paid', 'Paid'),
('cancelled', 'Cancelled'),
)

user = models.ForeignKey(User, on_delete=models.CASCADE)
order = models.ForeignKey(Order, on_delete=models.CASCADE)
amount = models.DecimalField(max_digits=12, decimal_places=2)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending')
created_at = models.DateTimeField(default=timezone.now)

def __str__(self):
return f"Invoice {self.id} for Order {self.order.id}"

Представления (Views)

Создайте представления для обработки платежей:

note

Вам нужно создавать webhook представления только для тех платёжных провайдеров, которые вы используете. Удалите импорты и классы для ненужных провайдеров.

# payment/views.py
from paytechuz.integrations.django.views import (
BasePaymeWebhookView,
BaseClickWebhookView,
BaseUzumWebhookView,
BasePaynetWebhookView
)

from payment.models import Invoice
from shop.models import Order

class PaymeWebhookView(BasePaymeWebhookView):
def successfully_payment(self, params, transaction):
invoice = Invoice.objects.get(id=transaction.account_id)
invoice.status = 'paid'
invoice.save()

def cancelled_payment(self, params, transaction):
invoice = Invoice.objects.get(id=transaction.account_id)
invoice.status = 'cancelled'
invoice.save()

def get_check_data(self, params, account): # optional
"""
Return additional data for CheckPerformTransaction (fiscal receipt)

You can override this method to return additional data for fiscal receipt
"""
return {
"additional": {"first_name": account.user.first_name}, # optional
"detail": { # optional
"receipt_type": 0,
"shipping": {"title": "Yetkazib berish", "price": 10000},
"items": [
{
"discount": 0,
"title": account.product_name,
"price": account.amount,
"count": 1,
"code": "00001",
"units": 1,
"vat_percent": 0,
"package_code": "123456"
}
]
}
}

class ClickWebhookView(BaseClickWebhookView):
def successfully_payment(self, params, transaction):
invoice = Invoice.objects.get(id=transaction.account_id)
invoice.status = 'paid'
invoice.save()

def cancelled_payment(self, params, transaction):
invoice = Invoice.objects.get(id=transaction.account_id)
invoice.status = 'cancelled'
invoice.save()

def successfully_payment(self, params, transaction):
invoice = Invoice.objects.get(id=transaction.account_id)
invoice.status = 'paid'
invoice.save()

def cancelled_payment(self, params, transaction):
invoice = Invoice.objects.get(id=transaction.account_id)
invoice.status = 'cancelled'
invoice.save()

class UzumWebhookView(BaseUzumWebhookView):
def successfully_payment(self, params, transaction):
invoice = Invoice.objects.get(id=transaction.account_id)
invoice.status = 'paid'
invoice.save()

def cancelled_payment(self, params, transaction):
invoice = Invoice.objects.get(id=transaction.account_id)
invoice.status = 'cancelled'
invoice.save()

class PaynetWebhookView(BasePaynetWebhookView):
def successfully_payment(self, params, transaction):
invoice = Invoice.objects.get(id=transaction.account_id)
invoice.status = 'paid'
invoice.save()

def cancelled_payment(self, params, transaction):
invoice = Invoice.objects.get(id=transaction.account_id)
invoice.status = 'cancelled'
invoice.save()

def get_check_data(self, params, account): # опционально
# Возврат дополнительных данных для GetInformation
# Вы можете использовать любые пары ключ-значение
return {
"fields": {
"first_name": account.user.first_name,
"balance": 0 # account.user.balance
}
}

URL маршруты

Настройте URL маршруты:

note

Добавляйте URL маршруты только для тех платёжных провайдеров, которые вы используете. Удалите импорты и пути для ненужных провайдеров.

# urls.py
from django.urls import path
from payment.views import PaymeWebhookView, ClickWebhookView, UzumWebhookView, PaynetWebhookView
from shop.views import OrderCreateView

urlpatterns = [
# ...
path('webhooks/payme/', PaymeWebhookView.as_view(), name='payme_webhook'),
path('webhooks/click/', ClickWebhookView.as_view(), name='click_webhook'),
path('webhooks/uzum/<str:action>/', UzumWebhookView.as_view(), name='uzum_webhook'),
path('webhooks/paynet/', PaynetWebhookView.as_view(), name='paynet_webhook'),

# Order creation endpoint
path('order/create/', OrderCreateView.as_view(), name='order_create'),
]

Создание платёжных ссылок

Пример представления Django Rest Framework (DRF), которое обрабатывает создание заказа и генерирует платёжную ссылку на основе выбранного платёжного провайдера (без использования сериализаторов):

note

Настройте логику так, чтобы она включала только те платежные системы, которые вы хотите поддерживать. Удалите импорты и блоки elif для неиспользуемых систем.

# shop/views.py
from django.conf import settings
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

from paytechuz.gateways.payme import PaymeGateway
from paytechuz.gateways.click import ClickGateway
from payment.models import Invoice

class OrderCreateView(APIView):
def post(self, request):
data = request.data
product_name = data.get('product_name')
amount = data.get('amount')
payment_type = data.get('payment_type') # 'payme', 'click', 'uzum', 'paynet'

if not all([product_name, amount, payment_type]):
return Response(
{'error': 'product_name, amount, and payment_type are required.'},
status=status.HTTP_400_BAD_REQUEST
)

# 1. Create Order
order = Order.objects.create(
user=request.user,
product_name=product_name,
total_amount=amount
)

# 2. Create Invoice linked to the Order
invoice = Invoice.objects.create(
user=request.user,
order=order,
amount=amount,
status='pending'
)

payment_url = None

# 3. Generate Payment Link based on payment_type
if payment_type == 'payme':
gateway = PaymeGateway(
payme_id=settings.PAYTECHUZ['PAYME']['PAYME_ID'],
payme_key=settings.PAYTECHUZ['PAYME']['PAYME_KEY'],
is_test_mode=settings.PAYTECHUZ['PAYME']['IS_TEST_MODE']
)
payment_url = gateway.create_payment(
id=invoice.id,
amount=invoice.amount,
return_url="https://example.com/success",
account_field_name=settings.PAYTECHUZ['PAYME']['ACCOUNT_FIELD']
)

elif payment_type == 'click':
gateway = ClickGateway(
service_id=settings.PAYTECHUZ['CLICK']['SERVICE_ID'],
merchant_id=settings.PAYTECHUZ['CLICK']['MERCHANT_ID'],
merchant_user_id=settings.PAYTECHUZ['CLICK']['MERCHANT_USER_ID'],
secret_key=settings.PAYTECHUZ['CLICK']['SECRET_KEY'],
is_test_mode=settings.PAYTECHUZ['CLICK']['IS_TEST_MODE']
)
payment_url = gateway.create_payment(
id=invoice.id,
amount=invoice.amount,
return_url="https://example.com/success"
)

payment_url = gateway.create_payment(
account_id=invoice.id,
amount=invoice.amount,
)

elif payment_type == 'uzum':
gateway = UzumGateway(
service_id=settings.PAYTECHUZ['UZUM']['SERVICE_ID'],
is_test_mode=settings.PAYTECHUZ['UZUM']['IS_TEST_MODE']
)
payment_url = gateway.create_payment(
id=invoice.id,
amount=invoice.amount,
return_url="https://example.com/success"
)

elif payment_type == 'paynet':
gateway = PaynetGateway(
merchant_id=settings.PAYTECHUZ['PAYNET']['MERCHANT_ID'],
is_test_mode=settings.PAYTECHUZ['PAYNET']['IS_TEST_MODE']
)
# Генерация URL платежа Paynet
# Формат URL: https://app.paynet.uz/?m={merchant_id}&c={payment_id}&a={amount}
payment_url = gateway.create_payment(
id=invoice.id, # ID платежа (параметр c)
amount=invoice.amount # сумма в тийинах (опционально, параметр a)
)
# Или без суммы (сумма будет настроена на стороне Paynet)
# payment_url = gateway.create_payment(id=invoice.id)

return Response({
'order_id': order.id,
'invoice_id': invoice.id,
'payment_url': payment_url
}, status=status.HTTP_201_CREATED)