Iranian payment gateways integration for Django (Zarinpal, Zibal, Mellat, Saman and more)
Project description
django-iranian-payment
درگاههای پرداخت ایرانی برای Django، با معماری دو لایه:
- لایهی ساده (توصیهشده): یک اپ Django اختیاری که خودش رکورد پرداخت، ذخیرهی
authority، تأیید، و مدیریت وضعیت تراکنش را انجام میدهد. کاربر تقریباً هیچ منطقی نمینویسد. - لایهی هسته (پیشرفته): درگاههای بدون state که در هر محیطی (حتی غیر Django یا
async) قابل استفادهاند. کاربر خودش
authorityرا ذخیره و تأیید را مدیریت میکند.
واحد بانک همیشه ریال است، اما میتوانی واحد ورودی خودت را به تومان تغییر
دهی (IRANIAN_PAYMENT["currency"] = "toman")؛ پکیج خودکار به ریال تبدیل میکند.
بخش واحد پول را ببین.
درگاههای آماده و تستشده (registry عمومی)
این درگاهها راستیآزمایی شده و با get_gateway("slug") در دسترساند:
| درگاه | نوع | وضعیت | وابستگی اختیاری |
|---|---|---|---|
| زرینپال | REST/JSON | ✅ sandbox و تراکنش واقعی تستشده | — |
| زیبال | REST/JSON | ✅ sandbox و تراکنش واقعی تستشده | — |
| ملت | SOAP | ✅ تراکنش live واقعی تستشده (sandbox ندارد) | [soap] (zeep) |
| سامان (SEP) | REST/JSON | ✅ تراکنش واقعی با ترمینال واقعی تستشده (sandbox ندارد) | — |
✅ هر چهار درگاه با تراکنش واقعی تأیید شدهاند. زرینپال/زیبال هم در sandbox و هم با تراکنش واقعی تست شدند. ملت روی محیط عملیاتی (bpm.shaparak.ir) تست شد: تراکنش موفق (ResCode=0، SaleReferenceId، CardHolderPan، FinalAmount) و سناریوی کنسل کاربر (ResCode=17) هر دو تأیید شدند. سامان با تراکنش واقعی روی ترمینال واقعی تست و در نسخهی
1.0.0عمومی شد.⛔ سامان و ملت sandbox واقعی ندارند و
sandbox=Trueرا با خطا رد میکنند (جزئیات). فقط liveاند.
⚠️ ملت نیاز به
zeepدارد:pip install "django-iranian-payment[soap]". ملت دومرحلهای است؛ حالت پیشفرضverify_settle(تأیید+واریز اتمیک) توصیه میشود. برای واریز با تأخیر،settle_mode="verify_only"را در config بگذار و خودتsettle()را صدا بزن (وگرنه بانک در ۳ ساعت Autoreversal میزند). هدایت کاربر به ملت با فرم POST است (نه redirect ساده)؛ لایهی Django این فرم auto-submit را در viewgo_to_gatewayخودکار میسازد.
درگاههای تجربی (در core.experimental)
این درگاهها پیادهسازی کامل از مستند رسمی دارند و منطقشان با تست خودکار
(InMemoryTransport) پوشش داده شده، اما هنوز هیچ تست sandbox یا ترمینال واقعی
روی آنها انجام نشده — برخلاف زرینپال/زیبال که حداقل sandbox دارند، این درگاهها
بهدلیل محدودیتهای دسترسی (نیاز به قرارداد پذیرندگی، ثبت IP، کلید واقعی) حتی تست
script سندباکسشان هم انجام نشده است.
طبق قانون طلایی پروژه، تا تست واقعی موفق در registry عمومی قرار نمیگیرند و با
get_gateway در دسترس نیستند؛ فقط با import صریح:
from django_iranian_payment.core.experimental.irankish import IrankishGateway
from django_iranian_payment.core.experimental.nextpay import NextPayGateway
from django_iranian_payment.core.experimental.sadad import SadadGateway
from django_iranian_payment.core.experimental.digipay import DigipayGateway
| درگاه | نوع | رمزنگاری | وابستگی اختیاری |
|---|---|---|---|
| ایرانکیش | REST/JSON | AES + RSA | [irankish] |
| نکستپی | REST/JSON | — | — |
| سداد | REST/JSON (WebApi) | 3DES | [sadad] |
| دیجیپی | REST/JSON (OAuth2) | — | — |
ℹ️ ملت و سامان پیشتر تجربی بودند؛ پس از تست تراکنش واقعی به registry عمومی منتقل شدند (بالاتر را ببین). دیگر از
core.experimentalimport نمیشوند و مستقیم باget_gateway("mellat")/get_gateway("saman")در دسترساند.
ایرانکیش و سداد به وابستگی رمزنگاری نیاز دارند:
pip install "django-iranian-payment[irankish]"(شاملpycryptodomeوrsa) یاpip install "django-iranian-payment[sadad]"(شاملpycryptodome).
⚠️ سداد همان درگاهی است که از سایت بانک ملی به آن هدایت میشوید؛ بانک ملی درگاه مستقل خود را به سداد سپرده است.
⚠️ دیجیپی برخلاف بقیه احراز هویت دومرحلهای OAuth2 دارد: config آن پنج فیلد اجباری میخواهد (
username,password,client_id,client_secret,provider_id). در verify بهtrackingCode(که در نتیجهی پرداخت/callback برمیگردد) از طریقextraنیاز دارد. اگر پرداخت موفق را verify نکنی، پس از مدتی خودکار لغو و وجه مرجوع میشود.
درگاههای از کار افتاده (دیگر سرویس نمیدهند)
❌ پیآیآر (Pay.ir) و آیدیپی (IDPay) کلاً از دسترس خارج شدهاند و دیگر سرویسدهی نمیکنند. کدشان در
core.experimentalبهعنوان آرشیو باقی مانده ولی برای استفاده توصیه نمیشود وget_gateway("pay_ir")/get_gateway("idpay")کار نمیکند. تنها در صورتی که این سرویسها روزی بازگردند، با import صریح در دسترساند:from django_iranian_payment.core.experimental import PayIrGateway, IDPayGateway
نصب
pip install django-iranian-payment
# درگاههای SOAP (ملت و سایر درگاههای SOAP):
pip install "django-iranian-payment[soap]"
# درگاه ایرانکیش (AES+RSA):
pip install "django-iranian-payment[irankish]"
# درگاه سداد (3DES):
pip install "django-iranian-payment[sadad]"
تنظیمات
در settings.py:
IRANIAN_PAYMENT = {
"sandbox": False, # پیشفرض سراسری
"currency": "rial", # واحد ورودی مبلغ: "rial" (پیشفرض) یا "toman"
"gateways": {
"zarinpal": {"merchant_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"sandbox": True}, # sandbox مجزای همین درگاه
"zibal": {"merchant": "zibal"}, # زیبال sandbox را با merchant کنترل میکند
"mellat": {
"terminal_id": "1234567",
"username": "your-username",
"password": "your-password",
"settle_mode": "verify_settle", # یا "verify_only"
# بدون "sandbox" → از پیشفرض سراسری (False = live) پیروی میکند
},
},
}
واحد پول (ریال یا تومان)
بانکهای ایرانی همیشه با ریال کار میکنند؛ این واحد بانکِ پکیج است و
amount_to_send که به درگاه و verify میرود همیشه ریال است. اما میتوانی واحدی که
خودت ورودی میدهی را با IRANIAN_PAYMENT["currency"] بهصورت سراسری انتخاب کنی:
IRANIAN_PAYMENT = {
"currency": "toman", # حالا amount ها را به تومان میدهی
"gateways": {...},
}
# با تنظیم بالا (هر دو مسیر یکسان عمل میکنند):
services.start_payment("zarinpal", amount=15_000, ...) # ۱۵۰۰۰ تومان → بانک ۱۵۰۰۰۰ ریال
# مسیر toolkit هم واحد سراسری را رعایت میکند (get_gateway آن را تزریق میکند):
get_gateway("zarinpal").initiate(PaymentRequest(amount=15_000, ...)) # هم ۱۵۰۰۰۰ ریال
- پیشفرض
"rial"است (سازگار با قبل؛ هیچ تبدیلی انجام نمیشود). - واحد سراسری در هر دو مسیر اعمال میشود: هم
start_payment، همget_gateway(...).initiate(PaymentRequest(...)). در مسیر toolkit،get_gatewayواحد سراسری را در درخواستی کهcurrencyمشخص نکرده تزریق میکند. اگرcurrencyرا روی خودPaymentRequestبدهی، بر تنظیم سراسری اولویت دارد. - تبدیل ۱ تومان = ۱۰ ریال فقط یکبار و در همان ابتدای کار انجام میشود.
- مبالغ ذخیرهشده در مدل
Paymentو مقادیر بازگشتی verify همیشه ریالاند (واحد بانک)؛currencyفقط واحد ورودی را تعیین میکند. برای نمایش به کاربر در تومان، خودت بر ۱۰ تقسیم کن. - کارمزد:
rate_bpsواحدمستقل است؛ ولیfixedوmax_feeدر همان واحد ورودی تفسیر و خودکار به ریال تبدیل میشوند. - در لایهی هستهی خالص (بدون Django و بدون
get_gateway) واحد را روی خود درخواست بده:PaymentRequest(amount=15_000, currency="toman", ...). برای خواندن مقدار سراسری از settings همfrom django_iranian_payment import get_default_currencyهست.
sandbox مجزای هر درگاه
sandbox هر درگاه جداگانه تعیین میشود. کلید "sandbox" داخل config همان درگاه بر
مقدار سراسری اولویت دارد، پس میتوانی یک درگاه را sandbox و درگاه دیگری را live
داشته باشی همزمان. اولویت کامل:
get_gateway(..., sandbox=...) > config درگاه > "sandbox" سراسری > False
فقط درگاههایی که URL سندباکس جدا دارند (زرینپال، دیجیپی) به این فلگ واکنش میدهند. زیبال با مقدار
merchant="zibal"و ایرانکیش/نکستپی/سداد اصلاً URL سندباکس جدا ندارند (فلگsandboxبرایشان بیاثر است).⛔ سامان و ملت sandbox واقعی ندارند و
sandbox=Trueرا رد میکنند (خطایGatewayConfigurationError). اگرsandboxسراسری راTrueگذاشتهای، برای این دو صریحاً"sandbox": Falseبگذار.اگر اپ
django_iranian_payment.contrib.djangoدرINSTALLED_APPSباشد، این تناقض با یک Django system check در startup گرفته میشود:manage.py runserver(و هرmanage.py) با خطایiranian_payment.E001اجرا نمیشود تا اصلاحش کنی — نه اینکه بیصدا به live وصل شوی. در حالت مدیریت دستی DB (بدون این اپ)، همان خطا هنگام اولینget_gateway("saman"/"mellat")رخ میدهد.
راهنمای کامل هر درگاه
برای هر درگاه یک راهنمای گامبهگام و خودکفا (هر دو حالت مدیریت دیتابیس) در
docs/gateways/ هست:
زرینپال ·
زیبال ·
ملت ·
سامان ·
ایرانکیش ·
نکستپی ·
سداد ·
دیجیپی.
توجه: درگاههای تجربی (ایرانکیش، نکستپی، سداد، دیجیپی) در registry عمومی نیستند. برای استفادهشان با
get_gatewayو لایهی Django باید یکبار صریحاً register شوند (روش بالا را ببین). درگاههای registry عمومی (زرینپال، زیبال، ملت، سامان) به این ثبت نیاز ندارند و مستقیم باget_gateway("slug")در دسترساند.
برای استفاده از لایهی ساده (مدل و ردیابی خودکار)، اپ را هم اضافه کن:
INSTALLED_APPS = [
# ...
"django_iranian_payment.contrib.django",
]
سپس migrate:
python manage.py migrate
و مسیرهای داخلی را در urls.py پروژه اضافه کن:
from django.urls import path, include
urlpatterns = [
# ...
path("payment/", include("django_iranian_payment.contrib.django.urls")),
]
روش ۱: لایهی ساده (توصیهشده)
پکیج خودش رکورد میسازد، authority را ذخیره میکند، و تأیید را انجام میدهد.
شروع پرداخت
from django.shortcuts import redirect
from django_iranian_payment.contrib.django import services
def start_payment(request, order):
payment, redirect_url = services.start_payment(
"zarinpal",
amount=order.amount, # ریال
callback_url="https://yoursite.com/payment/callback/zarinpal/",
order_id=str(order.id),
description="پرداخت سفارش",
mobile="09120000000", # اختیاری
)
# نیازی به ذخیرهی authority نیست؛ پکیج خودش نگه میدارد.
return redirect(redirect_url)
بازگشت از بانک (callback)
اگر مسیرهای داخلی را در urls.py اضافه کرده باشی، هیچ view ای لازم نیست.
بانک به /payment/callback/zarinpal/ برمیگردد، پکیج خودش تأیید میکند و کاربر را
به callback_url رکورد با پارامتر payment_status هدایت میکند:
https://yoursite.com/...?payment_status=success&order_id=123
اگر میخواهی منطق خودت را اجرا کنی، بهجای استفاده از callback داخلی، خودت
services.verify_payment(slug, authority) را صدا بزن.
تأیید مجدد تراکنشهای ناتمام (درگاه در دسترس نبود)
گاهی کاربر از بانک برمیگردد ولی درگاه هنگام verify بیپاسخ میدهد یا ۵۰۰ برمیگرداند (بیثباتی زرینپال و ...). پول ممکن است از کاربر کم شده باشد ولی تأیید نشده. این حالت خودکار مدیریت میشود:
- در callback، پیش از تماس با بانک، رکورد به
RETURN_FROM_BANKعلامت میخورد. اگر verify با خطای شبکه شکست بخورد، رکورد در همین حالت میماند (نه گم میشود، نهexpire_staleمنقضیاش میکند) و کاربر باpayment_status=pendingبرمیگردد. - یک job دورهای این رکوردها را دوباره verify میکند. verify دوباره امن است:
زرینپال کد ۱۰۱ (قبلاً تأیید شده) را
DUPLICATE= موفق برمیگرداند.
در cron یا celery اجرا کن:
from django_iranian_payment.contrib.django import services
services.reverify_pending() # رکوردهای returnedِ ناتمام را دوباره verify میزند
services.expire_stale(older_than_minutes=30) # رکوردهای خیلی قدیمیِ نرفته به درگاه
reverify_pendingخودش خطای در دسترس نبودن درگاه را میبلعد (رکورد returned میماند و اجرای بعدی دوباره تلاش میکند)، وextraلازم برای verify درگاههای شاپرکی (ملت و ...) را ازrawرکورد بازمیخواند.older_than_minutesرا روی ۳۰+ بگذار تا رکورد معلق فرصت reverify داشته باشد پیش از انقضا.
حالت مدیریت دستی دیتابیس (روش ۲): همین منطق را باید خودت پیاده کنی — نمونهی کامل
(callback با payment_status=pending + reverify_pending + management command) در
scripts/django_custom_db.py.
وضعیتهای رکورد
WAITING → REDIRECT_TO_BANK → RETURN_FROM_BANK → COMPLETE
و حالتهای پایانی: CANCEL_BY_USER، EXPIRE_GATEWAY_TOKEN، EXPIRE_VERIFY.
روش ۲: لایهی هسته (بدون مدل، پیشرفته)
اگر نمیخواهی مدل و migration داشته باشی (یا خارج از Django کار میکنی)، مستقیم از
هسته استفاده کن. در این حالت خودت باید authority را ذخیره کنی.
from django_iranian_payment import get_gateway, PaymentRequest
def start_payment(request, order):
gw = get_gateway("zarinpal")
result = gw.initiate(PaymentRequest(
amount=order.amount, # ریال
callback_url="https://yoursite.com/verify/",
order_id=str(order.id),
description="پرداخت سفارش",
))
order.authority = result.authority
order.amount_sent = result.amount_to_send # این را برای verify ذخیره کن
order.save()
return redirect(result.redirect_url)
def verify_payment(request):
authority = request.GET.get("Authority")
order = Order.objects.get(authority=authority)
gw = get_gateway("zarinpal")
result = gw.verify(
authority=authority,
amount=order.amount_sent, # همان مبلغی که در initiate رفت (با کارمزد)
order_id=str(order.id),
)
if result.is_success:
order.mark_paid(result.reference_id)
return redirect("/success/")
return redirect("/failure/")
چرا
amount_sentو نهamount؟ بعضی درگاهها (زرینپال، پیپینگ) مبلغ را در callback برنمیگردانند و verify به همان مبلغ ارسالی نیاز دارد. اگر کارمزد روی مشتری اعمال شده باشد، مبلغ ارسالی با مبلغ پایه فرق دارد.
درگاههایی که در verify به دادهی بیشتری نیاز دارند (پارامتر extra)
برخی درگاههای شاپرکی در verify به دادهای فراتر از یک authority نیاز دارند که
در callbackِ POST از بانک برمیگردد. این دادهها از طریق extra پاس داده میشوند.
اگر از لایهی Django استفاده کنی، viewهای پکیج این مقادیر را خودکار از callback
استخراج و پاس میدهند.
# ملت (registry عمومی): به sale_reference_id و sale_order_id نیاز دارد.
# اگر کاربر کنسل کرده باشد، res_code از callback (=17) را هم بده تا بدون
# تماس SOAP وضعیت CANCELLED برگردد.
gw.verify(authority=ref_id, amount=amount, order_id=oid,
extra={"sale_reference_id": "...", "sale_order_id": "...",
"card_number": "...", "res_code": "0"})
# سامان (registry عمومی): به RefNum نیاز دارد
gw.verify(authority=token, amount=amount, order_id=oid,
extra={"ref_num": "...", "state": "OK"})
# ایرانکیش (تجربی): به token و reference_id نیاز دارد
gw.verify(authority=token, amount=amount, order_id=oid,
extra={"token": "...", "reference_id": "...", "result_code": "100"})
# دیجیپی (تجربی): به trackingCode نیاز دارد (providerId همان order_id است)
gw.verify(authority=ticket, amount=amount, order_id=oid,
extra={"tracking_code": "...", "result": "SUCCESS"})
درگاههای ساده (زرینپال، زیبال) پارامتر extra را نادیده میگیرند.
کارمزد
کارمزد بهصورت اختیاری روی هر پرداخت قابل تنظیم است. میتوانی تعیین کنی کارمزد به مبلغ اضافه شود (مشتری بپردازد) یا نشود (پذیرنده بپردازد، مبلغ بانک تغییر نکند).
from django_iranian_payment import FeeConfig, FeePayer
fee = FeeConfig(
rate_bps=200, # ۲٪ (۲۰۰ واحد پایه). ۱٪ = ۱۰۰
fixed=0, # کارمزد ثابت به ریال (اختیاری)
who_pays=FeePayer.CUSTOMER, # CUSTOMER: به مبلغ اضافه میشود | MERCHANT: نمیشود
max_fee=None, # سقف کارمزد به ریال (اختیاری)
)
# لایهی ساده:
services.start_payment("zarinpal", amount=100_000, callback_url="...",
order_id="1", fee=fee)
# لایهی هسته:
PaymentRequest(amount=100_000, callback_url="...", order_id="1", fee=fee)
نکات کارمزد:
- نرخ به bps (واحد پایه) است تا محاسبهی پول با float انجام نشود (۲٪ = ۲۰۰).
- کارمزد همیشه رو به بالا گرد میشود تا پذیرنده کسری ضرر نکند.
- اگر
who_pays=CUSTOMER، مبلغ ارسالی به بانک = مبلغ پایه + کارمزد. همین مبلغ در verify هم استفاده میشود (در لایهی ساده خودکار است). - اگر
who_pays=MERCHANT، مبلغ بانک تغییر نمیکند و کارمزد فقط برای گزارش/حسابداری محاسبه میشود.
افزودن درگاه جدید / عمومیکردن یک درگاه تجربی
درگاههای core.experimental پس از تست با اطلاعات و ترمینال واقعی، با انتقال فایل
به core/gateways/ و افزودن یک خط به core/gateways/__init__.py عمومی میشوند. تا
آن لحظه با get_gateway در دسترس نیستند و فقط با import صریح قابل دسترسیاند:
from django_iranian_payment.core.experimental.sadad import SadadGateway
نمونهی واقعی این ارتقا: ملت و سامان که پس از تست تراکنش واقعی از
core.experimental به core.gateways منتقل شدند و حالا با get_gateway("mellat") /
get_gateway("saman") در دسترساند.
تاریخچهی تغییرات درگاهها
-
نسخهی
0.7.0— انتخاب واحد پول (ریال/تومان). کلید سراسریIRANIAN_PAYMENT["currency"]("rial"پیشفرض یا"toman") اضافه شد. کاربر میتواند مبلغها را به تومان بدهد و پکیج خودکار به ریال (واحد بانک) تبدیل میکند (۱ تومان = ۱۰ ریال). تبدیل درPaymentRequest.resolve_amount()انجام میشود، پس هیچ درگاهی نیاز به تغییر نداشت. در لایهی هستهPaymentRequest(currency=...)و در settings کلیدcurrency. سازگار با قبل (پیشفرض ریال = بدون تبدیل). مبالغ ذخیره/بازگشتی همیشه ریالاند. تست:tests/test_currency.py. -
نسخهی
0.6.0— دو تغییر:- sandbox مجزای هر درگاه: کلید
"sandbox"داخل config هر درگاه بر مقدار سراسری اولویت دارد؛get_gateway(..., sandbox=...)هم اضافه شد. حالا میتوان یک درگاه را live و دیگری را sandbox داشت همزمان (سازگار با قبل: فقطsandboxسراسری مثل قبل کار میکند). - رفع باگ callback لایهی Django برای درگاههای شاپرکی: پیشتر view callback
پکیج رکورد را فقط با چند نام پارامتر محدود پیدا میکرد و برای نکستپی
(
trans_id)، سداد (Token)، سامان (ResNum— توکن در callback نیست) و دیجیپی (providerId— ticket در callback نیست) رکورد را نمییافت و ۴۰۴ میداد. اکنون یک جدول مشخصات (_CALLBACK_SPEC) درcontrib/django/views.pyبرای هر درگاه نام پارامتر درست و کلید پیدا کردن رکورد (authority یا order_id) را تعریف میکند. ملت همچنان باRefId(authority یکتا) پیدا میشود تا رفتار live تستشدهاش دستنخورده بماند. - راهنمای کامل هر درگاه برای هر دو حالت مدیریت دیتابیس در
docs/gateways/افزوده شد.
- sandbox مجزای هر درگاه: کلید
-
۱۴۰۵/۰۴/۰۳ (نسخهی
0.5.0) — درگاه ملت پس از تست تراکنش واقعی روی محیط عملیاتی (bpm.shaparak.ir) ازcore.experimentalبه registry عمومی منتقل شد و حالا باget_gateway("mellat")در دسترس است. در جریان تست live دو باگ کشف و رفع شد (هر دو تست رگرسیون دارند):- کنسل کاربر (
ResCode=17بدونSaleReferenceId) باعث crash میشد؛ حالا verify ابتداres_codeاز callback را بررسی و بدون تماس SOAP،CANCELLED/FAILEDبرمیگرداند. CardHolderPanاز callback ذخیره نمیشد. اکنون شمارهی کارت ماسکشده درcard_numberو مقادیرsale_order_id/sale_reference_id/final_amountدرraw(مدل Payment) ذخیره میشوند تا برایsettle/reverseبعدی در دسترس باشند.
- کنسل کاربر (
-
۱۴۰۵/۰۳/۲۷ — درگاههای مستقل بانک تجارت و بانک ملی حذف شدند. این بانکها درگاه مستقل خود را کنار گذاشتهاند و پرداخت را به PSPهای دیگر سپردهاند:
- بانک تجارت → ایرانکیش: از درگاه بانک تجارت به ایرانکیش هدایت
میشوید. بهجای درگاه تجارت از
IrankishGatewayاستفاده کنید. - بانک ملی → سداد: از سایت بانک ملی به درگاه سداد هدایت میشوید. بهجای
درگاه ملی از
SadadGatewayاستفاده کنید.
اسکلتهای
tejarat.pyوmelli.py(که هرگز پیادهسازی واقعی نداشتند و فقطTODOبودند) از پروژه حذف شدند تا فایل اضافی نماند. اگر روزی این بانکها درگاه مستقل خود را دوباره راهاندازی کنند، در نسخههای بعدی دوباره افزوده خواهند شد. - بانک تجارت → ایرانکیش: از درگاه بانک تجارت به ایرانکیش هدایت
میشوید. بهجای درگاه تجارت از
لایسنس
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 django_iranian_payment-1.2.3.tar.gz.
File metadata
- Download URL: django_iranian_payment-1.2.3.tar.gz
- Upload date:
- Size: 78.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e9a87cca39dde1e11c515304cd0f560fb396886886b193bb9cf61a5d63dd5594
|
|
| MD5 |
4903c0c596c1f6eb3f6da972034a527b
|
|
| BLAKE2b-256 |
3f09c0cb90dfc9b0f281e2dd88fc47a654fdc6b714b21e53cdd5cfe4c9deb3f2
|
File details
Details for the file django_iranian_payment-1.2.3-py3-none-any.whl.
File metadata
- Download URL: django_iranian_payment-1.2.3-py3-none-any.whl
- Upload date:
- Size: 75.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ed40e9275492632537a51c3bb6bfeca5dfc0d174ff16648ab86e30b63370a9a8
|
|
| MD5 |
6fa3884e6c8e14e99eeab69c1d2964be
|
|
| BLAKE2b-256 |
a93eb93dea05c02e068c8582c80e4703304ef852276cc2129d82eef2bdc22c70
|