Django integration for the paylinker payment SDK (Click, Payme)
Project description
paylinker-django
Django integration for the paylinker payment SDK.
Provides webhook views, provider transaction tracking, and abstract handler bases for Click and Payme payment providers in Uzbekistan.
Installation
pip install paylinker-django
Quick Start
1. Add to INSTALLED_APPS
INSTALLED_APPS = [
...
"paylinker_django",
]
2. Configure settings
PAYLINKER = {
"PAYME": {
"merchant_id": env("PAYME_MERCHANT_ID"),
"merchant_key": env("PAYME_SECRET_KEY"),
"test_key": env("PAYME_TEST_KEY", default=""),
"is_test": env.bool("PAYME_IS_TEST", default=False),
},
"CLICK": {
"merchant_id": int(env("CLICK_MERCHANT_ID")),
"service_id": int(env("CLICK_SERVICE_ID")),
"secret_key": env("CLICK_SECRET_KEY"),
},
"PAYME_HANDLER": "apps.payments.handlers.MyPaymeHandler",
"CLICK_HANDLER": "apps.payments.handlers.MyClickHandler",
"ACCOUNT_FIELD": "order_id",
}
3. Implement handlers
# apps/payments/handlers.py
from paylinker.providers.click.enums import ClickErrorCode
from paylinker.providers.click.webhook import OrderCheckResult
from paylinker.providers.payme.rpc_handler import PaymeError
from paylinker_django.handlers import DjangoClickOrderValidator, DjangoPaymeTransactionHandler
from .models import Order
class MyPaymeHandler(DjangoPaymeTransactionHandler):
def validate_order(self, order_id, amount_tiyin):
try:
order = Order.objects.get(pk=order_id)
except Order.DoesNotExist:
raise PaymeError(-31050, "Не найден", "Topilmadi", "Not found", "order_id")
if order.is_paid:
raise PaymeError(-31099, "Оплачен", "To'langan", "Already paid")
if int(order.amount * 100) != amount_tiyin:
raise PaymeError(-31001, "Неверная сумма", "Noto'g'ri summa", "Wrong amount")
def on_payment_performed(self, provider_tx):
order = Order.objects.get(pk=provider_tx.order_id)
order.mark_paid()
def on_payment_cancelled(self, provider_tx, reason, was_performed):
if was_performed:
order = Order.objects.get(pk=provider_tx.order_id)
order.refund()
class MyClickValidator(DjangoClickOrderValidator):
def validate_order(self, merchant_trans_id, amount):
try:
order = Order.objects.get(pk=merchant_trans_id)
except Order.DoesNotExist:
return OrderCheckResult.fail(ClickErrorCode.ORDER_NOT_FOUND, "Not found")
if float(order.amount) != amount:
return OrderCheckResult.fail(ClickErrorCode.INCORRECT_AMOUNT, "Bad amount")
return OrderCheckResult.ok()
def on_payment_completed(self, provider_tx):
order = Order.objects.get(pk=provider_tx.order_id)
order.mark_paid()
4. Include URLs
# urls.py
from django.urls import include, path
urlpatterns = [
path("payments/", include("paylinker_django.urls")),
]
This exposes:
POST /payments/webhooks/payme/— Payme JSON-RPC endpointPOST /payments/webhooks/click/— Click SHOP-API endpoint
5. Run migrations
python manage.py migrate paylinker_django
Architecture
paylinker — Core SDK (framework-agnostic)
├── configs, providers, signing, schemas, HTTP clients
└── handler protocols: TransactionHandler (Payme), OrderValidator (Click)
paylinker-django — Django adapter (this package)
├── ProviderTransaction model — tracks provider-specific state
├── DjangoPaymeTransactionHandler — manages Payme lifecycle + model CRUD
├── DjangoClickOrderValidator — manages Click lifecycle + model CRUD
├── Webhook views — parse HTTP → delegate to handlers
└── Settings integration — PAYLINKER dict in Django settings
Your project only implements business-logic hooks:
validate_order()— order existence and amount verificationon_payment_performed()/on_payment_completed()— post-payment actionson_payment_cancelled()— cancellation handling
Generating payment URLs
from paylinker_django.conf import get_payme_config, get_click_config
from paylinker import PaymeProvider, ClickProvider
# Payme
payme = PaymeProvider(get_payme_config())
url = payme.generate_payment_url(
amount=100000, # tiyin
transaction_param=str(order.pk),
account_field="order_id",
)
# Click
click = ClickProvider(get_click_config())
url = click.generate_payment_url(
amount=1000.0, # UZS
transaction_param=str(order.pk),
)
Building & Publishing
This package uses Hatchling with a single source
of truth for the version (src/paylinker_django/__init__.py).
Local build
pip install -e ".[dev]"
python -m build # produces dist/*.whl and dist/*.tar.gz
twine check --strict dist/* # validate PyPI metadata
Release workflow (recommended)
Releases are automated via GitHub Actions using PyPI Trusted Publishing
(no long-lived API tokens). One-time setup on PyPI / TestPyPI:
add this repo as a trusted publisher for the paylinker-django project,
with workflow publish.yml and environments pypi / testpypi.
Then for each release:
# 1. Bump version in src/paylinker_django/__init__.py
# 2. Update CHANGELOG.md
git commit -am "release: v0.2.0"
# 3. Tag & push → triggers TestPyPI publish
git tag v0.2.0
git push origin main --tags
# 4. Create a GitHub Release for the tag → triggers real PyPI publish
gh release create v0.2.0 --notes-from-tag
Manual publish (fallback)
python -m build
twine upload --repository testpypi dist/* # TestPyPI
twine upload dist/* # PyPI
Versioning
Follows SemVer: MAJOR.MINOR.PATCH.
License
MIT
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file paylinker_django-0.1.1.tar.gz.
File metadata
- Download URL: paylinker_django-0.1.1.tar.gz
- Upload date:
- Size: 12.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0ec1150b4bb41572d8d91c896e08b7aef843371598ef7076e8f63a6e0a4a3e74
|
|
| MD5 |
eae8efdb1cee8153b016219bc02d6cc0
|
|
| BLAKE2b-256 |
045482366e488056e88487ee0d3b38707e5dc97cacff5004df5296fa6a38e5e6
|
File details
Details for the file paylinker_django-0.1.1-py3-none-any.whl.
File metadata
- Download URL: paylinker_django-0.1.1-py3-none-any.whl
- Upload date:
- Size: 16.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.19
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d8e1a52f382495803fa6943f68aede6e8cd94e2ad85a5324e8efd5e495fe4b11
|
|
| MD5 |
e01927ddc3e5e283d7ccfb6765550501
|
|
| BLAKE2b-256 |
f41e8ee5f9176fecb61428229b2955da50b6e788e1af3b26ba0466f67581a062
|