update bank gateway

This commit is contained in:
Parsa Nazer
2026-05-22 20:11:17 +03:30
parent e56df858fd
commit 6ed95784a3
22 changed files with 574 additions and 415 deletions
+7 -2
View File
@@ -1,2 +1,7 @@
__version__ = "v2.0.5" import django
default_app_config = "azbankgateways.apps.AZIranianBankGatewaysConfig"
__version__ = "1.0.0"
if django.VERSION < (3, 2):
default_app_config = "azbankgateways.apps.AZIranianBankGatewaysConfig"
+2 -5
View File
@@ -1,9 +1,9 @@
from django.contrib import admin from django.contrib import admin
from utils.admin import ModelAdmin
from .models import Bank from .models import Bank
class BankAdmin(ModelAdmin): class BankAdmin(admin.ModelAdmin):
fields = [ fields = [
"pk", "pk",
"status", "status",
@@ -17,7 +17,6 @@ class BankAdmin(ModelAdmin):
"bank_choose_identifier", "bank_choose_identifier",
"created_at", "created_at",
"update_at", "update_at",
'order'
] ]
list_display = [ list_display = [
"pk", "pk",
@@ -32,7 +31,6 @@ class BankAdmin(ModelAdmin):
"bank_choose_identifier", "bank_choose_identifier",
"created_at", "created_at",
"update_at", "update_at",
'order'
] ]
list_filter = [ list_filter = [
"status", "status",
@@ -66,7 +64,6 @@ class BankAdmin(ModelAdmin):
"extra_information", "extra_information",
"created_at", "created_at",
"update_at", "update_at",
'order',
] ]
@@ -0,0 +1,60 @@
from django.http import request
from azbankgateways.banks import BaseBank
from azbankgateways.models import BankType
from azbankgateways.bankfactories import BankFactory as BaseBankFactory
class BankFactory(BaseBankFactory):
def create(
self,
request: request,
amount: int,
callback_url : str,
mobile_number: str = None,
bank_type: BankType = None,
identifier: str = "1",
) -> BaseBank:
bank = super().create(bank_type, identifier)
bank = self.set_payment_info(
bank=bank,
request=request,
amount=amount,
callback_url=callback_url,
mobile_number=mobile_number,
)
return bank
def auto_create(
self,
request: request,
amount: int,
callback_url : str,
mobile_number: str = None,
identifier: str = "1",
) -> BaseBank:
bank = super().auto_create(identifier, amount)
bank = self.set_payment_info(
bank=bank,
request=request,
amount=amount,
callback_url=callback_url,
mobile_number=mobile_number,
)
return bank
def set_payment_info(
self,
bank: BaseBank,
request: request,
amount: int,
callback_url : str,
mobile_number: str = None,
):
bank.set_request(request=request)
bank.set_amount(amount=amount)
bank.set_client_callback_url(callback_url=callback_url)
bank.set_mobile_number(mobile_number=mobile_number)
return bank
+31 -8
View File
@@ -1,8 +1,31 @@
from .bahamta import Bahamta # noqa """
from .banks import BaseBank # noqa This package exposes bank gateway classes.
from .bmi import BMI # noqa
from .idpay import IDPay # noqa NOTE:
from .mellat import Mellat # noqa `from .banks import BaseBank` **must appear first** to avoid circular-import
from .sep import SEP # noqa issues. Other classes depend on `BaseBank`, so importing it earlier prevents
from .zarinpal import Zarinpal # noqa initialization-order problems.
from .zibal import Zibal # noqa """
# isort: off
from .banks import BaseBank
from .asanpardakht import AsanPardakht
from .bahamta import Bahamta
from .bmi import BMI
from .mellat import Mellat
from .sep import SEP
from .zarinpal import Zarinpal
from .zibal import Zibal
# isort: on
__all__ = [
"BaseBank",
"AsanPardakht",
"Bahamta",
"BMI",
"Mellat",
"SEP",
"Zarinpal",
"Zibal",
]
+175
View File
@@ -0,0 +1,175 @@
import json
import logging
import requests
from azbankgateways.banks import BaseBank
from azbankgateways.exceptions import (
AZBankGatewaysException,
BankGatewayConnectionError,
BankGatewayRejectPayment,
SettingDoesNotExist,
)
from azbankgateways.models import BankType, CurrencyEnum, PaymentStatus
class AsanPardakht(BaseBank):
_merchant_configuration_id = None
_username = None
_password = None
def __init__(self, **kwargs):
super(AsanPardakht, self).__init__(**kwargs)
self.set_gateway_currency(CurrencyEnum.IRR)
self._token_api_url = "https://ipgrest.asanpardakht.ir/v1/Token"
self._payment_url = "https://asan.shaparak.ir"
self._verify_api_url = "https://ipgrest.asanpardakht.ir/v1/Verify"
self._local_date_api_url = "https://ipgrest.asanpardakht.ir/v1/Time"
self._transaction_result_api_url = "https://ipgrest.asanpardakht.ir/v1/TranResult"
self._settlement_api_url = "https://ipgrest.asanpardakht.ir/v1/Settlement"
def get_bank_type(self):
return BankType.ASANPARDAKHT
def set_default_settings(self):
required_settings = ["MERCHANT_CONFIGURATION_ID", "USERNAME", "PASSWORD"]
for item in required_settings:
if item not in self.default_setting_kwargs:
raise SettingDoesNotExist(f"{item} is not set in settings.")
setattr(self, f"_{item.lower()}", self.default_setting_kwargs[item])
def get_pay_data(self):
data = {
"serviceTypeId": 1, # Service type code. For making a purchase, send code 1.
"merchantConfigurationId": self._merchant_configuration_id,
"localInvoiceId": self.get_tracking_code(),
"amountInRials": self.get_gateway_amount(),
"localDate": self._get_local_date(),
"callbackURL": self._get_gateway_callback_url() + f'&localInvoiceId={self.get_tracking_code()}',
"paymentId": self.get_tracking_code(),
**self.get_custom_data(),
}
return data
def prepare_pay(self):
super(AsanPardakht, self).prepare_pay()
def pay(self):
super(AsanPardakht, self).pay()
data = self.get_pay_data()
token = self._send_request(self._token_api_url, data)
if token:
self._set_reference_number(token)
else:
status_text = "Failed to retrieve token from Asan Pardakht"
self._set_transaction_status_text(status_text)
logging.critical(status_text)
raise BankGatewayRejectPayment(self.get_transaction_status_text())
def _get_gateway_payment_url_parameter(self):
return self._payment_url
def _get_gateway_payment_method_parameter(self):
return "POST"
def _get_gateway_payment_parameter(self):
params = {
"RefId": self.get_reference_number(),
}
return params
def prepare_verify_from_gateway(self):
super(AsanPardakht, self).prepare_verify_from_gateway()
request = self.get_request()
tracking_code = request.GET.get("localInvoiceId")
self._set_tracking_code(tracking_code)
self._set_bank_record()
self._check_transaction_data()
def verify_from_gateway(self, request):
super(AsanPardakht, self).verify_from_gateway(request)
def get_verify_data(self):
data = {
"merchantConfigurationId": self._merchant_configuration_id,
"payGateTranId": self._get_pay_gate_tran_id(),
}
return data
def prepare_verify(self, tracking_code):
super(AsanPardakht, self).prepare_verify(tracking_code)
def verify(self, transaction_code):
super(AsanPardakht, self).verify(transaction_code)
data = self.get_verify_data()
self._send_request(self._verify_api_url, data, is_json=False)
self._set_payment_status(PaymentStatus.COMPLETE)
self._settle_transaction()
def _send_request(self, api_url, data, method='POST', is_json=True):
headers = {
"usr": self._username,
"pwd": self._password,
}
try:
response = requests.request(
method, api_url, json=data, headers=headers, timeout=self.get_timeout()
)
response.raise_for_status()
except requests.Timeout:
logging.exception(f"Asan Pardakht gateway timeout: {data}")
raise BankGatewayConnectionError()
except requests.ConnectionError:
logging.exception(f"Asan Pardakht gateway connection error: {data}")
raise BankGatewayConnectionError()
except requests.HTTPError as e:
logging.exception(f"HTTP error occurred: {e}")
raise BankGatewayConnectionError()
if is_json:
return response.json()
return response.text
def _get_local_date(self):
return self._send_request(self._local_date_api_url, {}, method='GET')
def _get_transaction_data(self):
data = {
'merchantConfigurationId': self._merchant_configuration_id,
'localInvoiceId': self.get_tracking_code(),
}
return self._send_request(self._transaction_result_api_url, data, method='GET')
def _check_transaction_data(self):
transaction_data = self._get_transaction_data()
is_valid = (
transaction_data
and self._bank.reference_number == transaction_data.get('refID')
and transaction_data.get('amount') is not None
and int(self._bank.amount) == transaction_data.get('amount')
)
if not is_valid:
error_message = (
"Transaction data validation failed. The reference number or the amount "
"received from the gateway does not match the internal bank record."
)
raise AZBankGatewaysException(error_message)
self._set_pay_gate_tran_id(transaction_data)
def _settle_transaction(self):
try:
data = {
"merchantConfigurationId": self._merchant_configuration_id,
"payGateTranId": self._get_pay_gate_tran_id(),
}
self._send_request(self._settlement_api_url, data=data, is_json=False)
except Exception:
logging.debug("AsanPardakht gateway did not settle the payment")
def _set_pay_gate_tran_id(self, transaction_data):
self._bank.extra_information = json.dumps({'payGateTranID': transaction_data.get('payGateTranID')})
self._bank.save(update_fields={'extra_information'})
def _get_pay_gate_tran_id(self):
return json.loads(self._bank.extra_information)['payGateTranID']
+7 -4
View File
@@ -58,6 +58,7 @@ class Bahamta(BaseBank):
"payer_mobile": self.get_mobile_number(), "payer_mobile": self.get_mobile_number(),
"callback_url": self._get_gateway_callback_url(), "callback_url": self._get_gateway_callback_url(),
} }
data.update(self.get_custom_data())
return data return data
def prepare_pay(self): def prepare_pay(self):
@@ -70,7 +71,9 @@ class Bahamta(BaseBank):
if response_json["ok"]: if response_json["ok"]:
# در این سیستم رفرنس برای ذخیره سازی بر نمی گردد! # در این سیستم رفرنس برای ذخیره سازی بر نمی گردد!
token = self.get_tracking_code() token = self.get_tracking_code()
self._payment_url, self._params = split_to_dict_querystring(response_json["result"]["payment_url"]) self._payment_url, self._params = split_to_dict_querystring(
response_json["result"]["payment_url"]
)
self._set_reference_number(token) self._set_reference_number(token)
else: else:
logging.critical("Bahamta gateway reject payment") logging.critical("Bahamta gateway reject payment")
@@ -82,7 +85,7 @@ class Bahamta(BaseBank):
def prepare_verify_from_gateway(self): def prepare_verify_from_gateway(self):
super(Bahamta, self).prepare_verify_from_gateway() super(Bahamta, self).prepare_verify_from_gateway()
token = self.get_request().GET.get("reference", None) token = self.get_request().GET.get("reference")
self._set_reference_number(token) self._set_reference_number(token)
self._set_bank_record() self._set_bank_record()
@@ -109,7 +112,7 @@ class Bahamta(BaseBank):
super(Bahamta, self).verify(transaction_code) super(Bahamta, self).verify(transaction_code)
data = self.get_verify_data() data = self.get_verify_data()
response_json = self._send_data(self._verify_api_url, data) response_json = self._send_data(self._verify_api_url, data)
if response_json.get("ok", False) and response_json.get("result", {}).get("state", None) == "paid": if response_json.get("ok", False) and response_json.get("result", {}).get("state") == "paid":
self._set_payment_status(PaymentStatus.COMPLETE) self._set_payment_status(PaymentStatus.COMPLETE)
extra_information = json.dumps(response_json.get("result", {})) extra_information = json.dumps(response_json.get("result", {}))
self._bank.extra_information = extra_information self._bank.extra_information = extra_information
@@ -121,7 +124,7 @@ class Bahamta(BaseBank):
def _send_data(self, api, data): def _send_data(self, api, data):
try: try:
url = append_querystring(api, data) url = append_querystring(api, data)
response = requests.get(url, timeout=5) response = requests.get(url, timeout=self.get_timeout())
except requests.Timeout: except requests.Timeout:
logging.exception("Bahamta time out gateway {}".format(data)) logging.exception("Bahamta time out gateway {}".format(data))
raise BankGatewayConnectionError() raise BankGatewayConnectionError()
+29 -5
View File
@@ -4,11 +4,14 @@ import uuid
from urllib import parse from urllib import parse
import six import six
from django.conf import settings as django_settings
from django.db.models import Q from django.db.models import Q
from django.shortcuts import redirect from django.shortcuts import redirect
from django.urls import reverse from django.urls import reverse
from django.utils import timezone from django.utils import timezone
from azbankgateways.utils import append_querystring, build_full_url
from .. import default_settings as settings from .. import default_settings as settings
from ..exceptions import ( from ..exceptions import (
AmountDoesNotSupport, AmountDoesNotSupport,
@@ -18,7 +21,6 @@ from ..exceptions import (
SafeSettingsEnabled, SafeSettingsEnabled,
) )
from ..models import Bank, CurrencyEnum, PaymentStatus from ..models import Bank, CurrencyEnum, PaymentStatus
from ..utils import append_querystring
# TODO: handle and expire record after 15 minutes # TODO: handle and expire record after 15 minutes
@@ -41,8 +43,12 @@ class BaseBank:
def __init__(self, identifier: str, **kwargs): def __init__(self, identifier: str, **kwargs):
self.identifier = identifier self.identifier = identifier
self.default_setting_kwargs = kwargs self.default_setting_kwargs = kwargs
self._custom_data: dict = {}
self.set_default_settings() self.set_default_settings()
def _is_strict_origin_policy_enabled(self):
return django_settings.SECURE_REFERRER_POLICY == 'strict-origin-when-cross-origin'
@abc.abstractmethod @abc.abstractmethod
def set_default_settings(self): def set_default_settings(self):
"""default setting, like fetch merchant code, terminal id and etc""" """default setting, like fetch merchant code, terminal id and etc"""
@@ -162,6 +168,13 @@ class BaseBank:
def get_mobile_number(self): def get_mobile_number(self):
return self._mobile_number return self._mobile_number
def set_custom_data(self, data: dict):
"""تنظیم قابلیت های سفارشی برای درگاه"""
self._custom_data = data
def get_custom_data(self):
return self._custom_data
def set_client_callback_url(self, callback_url): def set_client_callback_url(self, callback_url):
"""ذخیره کال بک از طریق نرم افزار برای بازگردانی کاربر پس از بازگشت درگاه بانک به پکیج و سپس از پکیج به نرم """ذخیره کال بک از طریق نرم افزار برای بازگردانی کاربر پس از بازگشت درگاه بانک به پکیج و سپس از پکیج به نرم
افزار.""" افزار."""
@@ -187,7 +200,10 @@ class BaseBank:
def _set_bank_record(self): def _set_bank_record(self):
try: try:
self._bank = Bank.objects.get( self._bank = Bank.objects.get(
Q(Q(reference_number=self.get_reference_number()) | Q(tracking_code=self.get_tracking_code())), Q(
Q(reference_number=self.get_reference_number())
| Q(tracking_code=self.get_tracking_code())
),
Q(bank_type=self.get_bank_type()), Q(bank_type=self.get_bank_type()),
) )
logging.debug("Set reference find bank object.") logging.debug("Set reference find bank object.")
@@ -216,7 +232,10 @@ class BaseBank:
return self._transaction_status_text return self._transaction_status_text
def _set_payment_status(self, payment_status): def _set_payment_status(self, payment_status):
if payment_status == PaymentStatus.RETURN_FROM_BANK and self._bank.status != PaymentStatus.REDIRECT_TO_BANK: if (
payment_status == PaymentStatus.RETURN_FROM_BANK
and self._bank.status != PaymentStatus.REDIRECT_TO_BANK
):
logging.debug( logging.debug(
"Payment status is not status suitable.", "Payment status is not status suitable.",
extra={"status": self._bank.status}, extra={"status": self._bank.status},
@@ -247,6 +266,10 @@ class BaseBank:
def get_currency(self): def get_currency(self):
return self._currency return self._currency
@staticmethod
def get_timeout():
return settings.BANK_TIMEOUT
def get_gateway_amount(self): def get_gateway_amount(self):
return self._gateway_amount return self._gateway_amount
@@ -357,8 +380,8 @@ class BaseBank:
return redirect_url return redirect_url
def _get_gateway_callback_url(self): def _get_gateway_callback_url(self):
url = reverse(settings.CALLBACK_NAMESPACE)
if self.get_request(): if self.get_request():
url = reverse(settings.CALLBACK_NAMESPACE)
url_parts = list(parse.urlparse(url)) url_parts = list(parse.urlparse(url))
if not (url_parts[0] and url_parts[1]): if not (url_parts[0] and url_parts[1]):
url = self.get_request().build_absolute_uri(url) url = self.get_request().build_absolute_uri(url)
@@ -366,5 +389,6 @@ class BaseBank:
query.update({"bank_type": self.get_bank_type()}) query.update({"bank_type": self.get_bank_type()})
query.update({"identifier": self.identifier}) query.update({"identifier": self.identifier})
url = append_querystring(url, query) url = append_querystring(url, query)
else:
url = build_full_url(settings.CALLBACK_NAMESPACE)
return url return url
+18 -7
View File
@@ -22,6 +22,12 @@ class BMI(BaseBank):
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(BMI, self).__init__(**kwargs) super(BMI, self).__init__(**kwargs)
if not self._is_strict_origin_policy_enabled():
raise SettingDoesNotExist(
"SECURE_REFERRER_POLICY is not set to 'strict-origin-when-cross-origin'"
" in django setting, it's mandatory for BMI gateway"
)
self.set_gateway_currency(CurrencyEnum.IRR) self.set_gateway_currency(CurrencyEnum.IRR)
self._token_api_url = "https://sadad.shaparak.ir/vpg/api/v0/Request/PaymentRequest" self._token_api_url = "https://sadad.shaparak.ir/vpg/api/v0/Request/PaymentRequest"
self._payment_url = "https://sadad.shaparak.ir/VPG/Purchase" self._payment_url = "https://sadad.shaparak.ir/VPG/Purchase"
@@ -54,6 +60,7 @@ class BMI(BaseBank):
"OrderId": self.get_tracking_code(), "OrderId": self.get_tracking_code(),
"AdditionalData": "oi:%s-ou:%s" % (self.get_tracking_code(), self.get_mobile_number()), "AdditionalData": "oi:%s-ou:%s" % (self.get_tracking_code(), self.get_mobile_number()),
} }
data.update(self.get_custom_data())
return data return data
def prepare_pay(self): def prepare_pay(self):
@@ -63,7 +70,7 @@ class BMI(BaseBank):
super(BMI, self).pay() super(BMI, self).pay()
data = self.get_pay_data() data = self.get_pay_data()
response_json = self._send_data(self._token_api_url, data) response_json = self._send_data(self._token_api_url, data)
if response_json["ResCode"] == "0": if str(response_json["ResCode"]) == "0":
token = response_json["Token"] token = response_json["Token"]
self._set_reference_number(token) self._set_reference_number(token)
else: else:
@@ -99,10 +106,11 @@ class BMI(BaseBank):
super(BMI, self).verify(transaction_code) super(BMI, self).verify(transaction_code)
data = self.get_verify_data() data = self.get_verify_data()
response_json = self._send_data(self._verify_api_url, data) response_json = self._send_data(self._verify_api_url, data)
if response_json["ResCode"] == "0": if str(response_json["ResCode"]) == "0":
self._set_payment_status(PaymentStatus.COMPLETE) self._set_payment_status(PaymentStatus.COMPLETE)
extra_information = ( extra_information = (
f"RetrivalRefNo={response_json['RetrivalRefNo']},SystemTraceNo={response_json['SystemTraceNo']}" f"RetrivalRefNo={response_json['RetrivalRefNo']}"
",SystemTraceNo={response_json['SystemTraceNo']}"
) )
self._bank.extra_information = extra_information self._bank.extra_information = extra_information
self._bank.save() self._bank.save()
@@ -113,10 +121,13 @@ class BMI(BaseBank):
def prepare_verify_from_gateway(self): def prepare_verify_from_gateway(self):
super(BMI, self).prepare_verify_from_gateway() super(BMI, self).prepare_verify_from_gateway()
request = self.get_request() request = self.get_request()
for method in ["POST", "GET", "data", "PUT"]: method_data = getattr(request, "POST", {})
token = getattr(request, method, {}).get("token", None) token = None
if token: for key, value in method_data.items():
if key.lower() == "token":
token = value
break break
if not token: if not token:
raise BankGatewayStateInvalid raise BankGatewayStateInvalid
self._set_reference_number(token) self._set_reference_number(token)
@@ -142,7 +153,7 @@ class BMI(BaseBank):
def _send_data(self, api, data): def _send_data(self, api, data):
try: try:
response = requests.post(api, json=data, timeout=5) response = requests.post(api, json=data, timeout=self.get_timeout())
except requests.Timeout: except requests.Timeout:
logging.exception("BMI time out gateway {}".format(data)) logging.exception("BMI time out gateway {}".format(data))
raise BankGatewayConnectionError() raise BankGatewayConnectionError()
-141
View File
@@ -1,141 +0,0 @@
import json
import logging
import requests
from azbankgateways.banks import BaseBank
from azbankgateways.exceptions import BankGatewayConnectionError, SettingDoesNotExist
from azbankgateways.exceptions.exceptions import BankGatewayRejectPayment
from azbankgateways.models import BankType, CurrencyEnum, PaymentStatus
from azbankgateways.utils import get_json, split_to_dict_querystring
class IDPay(BaseBank):
_merchant_code = None
_method = None
_x_sandbox = None
_payment_url = None
_params = {}
def __init__(self, **kwargs):
super(IDPay, self).__init__(**kwargs)
self.set_gateway_currency(CurrencyEnum.IRR)
self._token_api_url = "https://api.idpay.ir/v1.1/payment"
self._verify_api_url = "https://api.idpay.ir/v1.1/payment/verify"
def get_bank_type(self):
return BankType.IDPAY
def set_default_settings(self):
for item in ["MERCHANT_CODE", "METHOD", "X_SANDBOX"]:
if item not in self.default_setting_kwargs:
raise SettingDoesNotExist()
setattr(self, f"_{item.lower()}", self.default_setting_kwargs[item])
self._x_sandbox = str(self._x_sandbox)
"""
gateway
"""
def _get_gateway_payment_url_parameter(self):
return self._payment_url
def _get_gateway_payment_parameter(self):
params = {}
params.update(self._params)
return params
def _get_gateway_payment_method_parameter(self):
return "GET"
"""
pay
"""
def get_pay_data(self):
data = {
"order_id": self.get_tracking_code(),
"amount": self.get_gateway_amount(),
"phone": self.get_mobile_number(),
"callback": self._get_gateway_callback_url(),
}
return data
def prepare_pay(self):
super(IDPay, self).prepare_pay()
def pay(self):
super(IDPay, self).pay()
data = self.get_pay_data()
response_json = self._send_data(self._token_api_url, data)
if "id" in response_json and "link" in response_json and response_json["link"] and response_json["id"]:
token = response_json["id"]
self._payment_url, self._params = split_to_dict_querystring(response_json["link"])
self._set_reference_number(token)
else:
logging.critical("IDPay gateway reject payment")
raise BankGatewayRejectPayment(self.get_transaction_status_text())
"""
verify gateway
"""
def prepare_verify_from_gateway(self):
super(IDPay, self).prepare_verify_from_gateway()
for method in ["GET", "POST", "data"]:
token = getattr(self.get_request(), method).get("id", None)
if token:
self._set_reference_number(token)
self._set_bank_record()
break
def verify_from_gateway(self, request):
super(IDPay, self).verify_from_gateway(request)
"""
verify
"""
def get_verify_data(self):
super(IDPay, self).get_verify_data()
data = {
"id": self.get_reference_number(),
"order_id": self.get_tracking_code(),
}
return data
def prepare_verify(self, tracking_code):
super(IDPay, self).prepare_verify(tracking_code)
def verify(self, transaction_code):
super(IDPay, self).verify(transaction_code)
data = self.get_verify_data()
response_json = self._send_data(self._verify_api_url, data, timeout=10)
if response_json.get("verify", {}).get("date", None):
self._set_payment_status(PaymentStatus.COMPLETE)
extra_information = json.dumps(response_json)
self._bank.extra_information = extra_information
self._bank.save()
else:
self._set_payment_status(PaymentStatus.CANCEL_BY_USER)
logging.debug("IDPay gateway unapprove payment")
def _send_data(self, api, data, timeout=5):
headers = {
"X-API-KEY": self._merchant_code,
"X-SANDBOX": self._x_sandbox,
}
try:
response = requests.post(api, headers=headers, json=data, timeout=timeout)
except requests.Timeout:
logging.exception("IDPay time out gateway {}".format(data))
raise BankGatewayConnectionError()
except requests.ConnectionError:
logging.exception("IDPay time out gateway {}".format(data))
raise BankGatewayConnectionError()
response_json = get_json(response)
if "error_message" in response_json:
self._set_transaction_status_text(response_json["error_message"])
return response_json
+115
View File
@@ -0,0 +1,115 @@
import logging
import requests
from azbankgateways.banks import BaseBank
from azbankgateways.exceptions import SettingDoesNotExist
from azbankgateways.exceptions.exceptions import (
BankGatewayConnectionError,
BankGatewayRejectPayment,
)
from azbankgateways.models import BankType, CurrencyEnum, PaymentStatus
from azbankgateways.utils import get_json
class IranDargah(BaseBank):
_merchant_code = None
_sandbox = False
def __init__(self, **kwargs):
kwargs.setdefault("SANDBOX", 0)
super().__init__(**kwargs)
self.set_gateway_currency(CurrencyEnum.IRR)
self._sandbox = kwargs.get("SANDBOX", 0) == 1
base_url = "https://dargaah.ir"
if self._sandbox:
base_url += "/sandbox"
self._payment_url = f"{base_url}/payment"
self._startpay_url = f"{base_url}/ird/startpay/"
self._verify_url = f"{base_url}/verification"
def get_bank_type(self):
return BankType.IRANDARGAH
def set_default_settings(self):
for item in ["MERCHANT_CODE"]:
if item not in self.default_setting_kwargs:
raise SettingDoesNotExist(f"{item} not in settings")
setattr(self, f"_{item.lower()}", self.default_setting_kwargs[item])
def _get_gateway_payment_url_parameter(self):
return f"{self._startpay_url}{self.get_reference_number()}"
def _get_gateway_payment_parameter(self):
return {}
def _get_gateway_payment_method_parameter(self):
return "GET"
def get_pay_data(self):
return {
"merchantID": self._merchant_code,
"amount": self.get_gateway_amount(),
"callbackURL": self._get_gateway_callback_url(),
"orderId": str(self.get_tracking_code()),
**self.get_custom_data(),
}
def prepare_pay(self):
super().prepare_pay()
def pay(self):
super().pay()
data = self.get_pay_data()
result = self._send_data(api=self._payment_url, data=data)
if result["status"] == 200:
self._set_reference_number(result["authority"])
else:
logging.critical("IranDargah reject payment: %s", result.get("message"))
raise BankGatewayRejectPayment(self.get_transaction_status_text())
def prepare_verify_from_gateway(self):
super().prepare_verify_from_gateway()
authority = self.get_request().POST.get("authority")
self._set_reference_number(authority)
self._set_bank_record()
def verify_from_gateway(self, request):
super().verify_from_gateway(request)
def get_verify_data(self):
return {
"merchantID": self._merchant_code,
"authority": self.get_reference_number(),
"amount": self.get_gateway_amount(),
"orderId": str(self.get_tracking_code()),
}
def prepare_verify(self, tracking_code):
super().prepare_verify(tracking_code)
def verify(self, transaction_code):
super().verify(transaction_code)
data = self.get_verify_data()
result = self._send_data(api=self._verify_url, data=data)
if result.get("status") in [100, 101]:
self._set_payment_status(PaymentStatus.COMPLETE)
else:
self._set_payment_status(PaymentStatus.CANCEL_BY_USER)
logging.debug("IranDargah verify failed: %s", result.get("message"))
def _send_data(self, api, data):
try:
response = requests.post(api, json=data, timeout=self.get_timeout())
response.raise_for_status()
except requests.RequestException as e:
logging.exception("IranDargah connection error: %s", e)
raise BankGatewayConnectionError()
result = get_json(response)
msg = result.get("message", "no message")
self._set_transaction_status_text(msg)
return result
+5 -6
View File
@@ -68,6 +68,7 @@ class Mellat(BaseBank):
"callBackUrl": self._get_gateway_callback_url(), "callBackUrl": self._get_gateway_callback_url(),
"payerId": 0, "payerId": 0,
} }
data.update(self.get_custom_data())
return data return data
def prepare_pay(self): def prepare_pay(self):
@@ -163,9 +164,7 @@ class Mellat(BaseBank):
status_text = "Payment ID is incorrect" status_text = "Payment ID is incorrect"
elif response == "414": elif response == "414":
status_text = "The organization issuing the bill is invalid" status_text = "The organization issuing the bill is invalid"
elif response == "415": elif response in ["415", "416"]:
status_text = "The working session has ended"
elif response == "416":
status_text = "The working session has ended" status_text = "The working session has ended"
elif response == "417": elif response == "417":
status_text = "Payer ID is invalid" status_text = "Payer ID is invalid"
@@ -187,12 +186,12 @@ class Mellat(BaseBank):
def prepare_verify_from_gateway(self): def prepare_verify_from_gateway(self):
super(Mellat, self).prepare_verify_from_gateway() super(Mellat, self).prepare_verify_from_gateway()
post = self.get_request().POST post = self.get_request().POST
token = post.get("RefId", None) token = post.get("RefId")
if not token: if not token:
return return
self._set_reference_number(token) self._set_reference_number(token)
self._set_bank_record() self._set_bank_record()
self._bank.extra_information = dumps(dict(zip(post.keys(), post.values()))) self._bank.extra_information = dumps(dict(post.items()))
self._bank.save() self._bank.save()
def verify_from_gateway(self, request): def verify_from_gateway(self, request):
@@ -250,7 +249,7 @@ class Mellat(BaseBank):
@staticmethod @staticmethod
def _get_client(): def _get_client():
transport = Transport(timeout=5, operation_timeout=5) transport = Transport(timeout=Mellat.get_timeout(), operation_timeout=Mellat.get_timeout())
client = Client("https://bpm.shaparak.ir/pgwchannel/services/pgw?wsdl", transport=transport) client = Client("https://bpm.shaparak.ir/pgwchannel/services/pgw?wsdl", transport=transport)
return client return client
-152
View File
@@ -1,152 +0,0 @@
import json
import logging
import requests
from azbankgateways.banks import BaseBank
from azbankgateways.default_settings import TRACKING_CODE_QUERY_PARAM
from azbankgateways.exceptions import BankGatewayConnectionError, SettingDoesNotExist
from azbankgateways.exceptions.exceptions import (
BankGatewayRejectPayment,
BankGatewayStateInvalid,
)
from azbankgateways.models import BankType, CurrencyEnum, PaymentStatus
class PayV1(BaseBank):
_merchant_code = None
_x_sandbox = None
def __init__(self, **kwargs):
super(PayV1, self).__init__(**kwargs)
self.set_gateway_currency(CurrencyEnum.IRR)
self._token_api_url = "https://pay.ir/pg/send"
self._payment_url = "https://pay.ir/pg/{}"
self._verify_api_url = "https://pay.ir/pg/verify"
def get_bank_type(self):
return BankType.PAYV1
def set_default_settings(self):
for item in ["MERCHANT_CODE", "X_SANDBOX"]:
if item not in self.default_setting_kwargs:
raise SettingDoesNotExist()
setattr(self, f"_{item.lower()}", self.default_setting_kwargs[item])
self._merchant_code = self._merchant_code if not self._x_sandbox else "test"
"""
gateway
"""
def _get_gateway_payment_url_parameter(self):
return self._payment_url.format(self._reference_number)
def _get_gateway_payment_parameter(self):
return {}
def _get_gateway_payment_method_parameter(self):
return "GET"
"""
pay
"""
def get_pay_data(self):
data = {
"api": self._merchant_code,
"amount": self.get_gateway_amount(),
"redirect": self._get_gateway_callback_url(),
"mobile": self.get_mobile_number(),
"factorNumber": self.get_tracking_code(),
}
return data
def prepare_pay(self):
super(PayV1, self).prepare_pay()
def pay(self):
super(PayV1, self).pay()
data = self.get_pay_data()
response = self._send_data(self._token_api_url, data)
response_json = response.json()
if response.status_code == 200 and int(response_json["status"]) == 1:
token = response_json["token"]
self._set_reference_number(token)
else:
logging.critical(
"PayV1 gateway reject payment with error code {0} and status code {1}".format(
response_json["errorCode"], response.status_code
)
)
raise BankGatewayRejectPayment(self.get_transaction_status_text())
"""
verify gateway
"""
def prepare_verify_from_gateway(self):
super(PayV1, self).prepare_verify_from_gateway()
for method in ["GET", "POST", "data"]:
token = getattr(self.get_request(), method).get(TRACKING_CODE_QUERY_PARAM, None)
if token:
self._set_reference_number(token)
self._set_bank_record()
break
else:
raise BankGatewayStateInvalid
def verify_from_gateway(self, request):
super(PayV1, self).verify_from_gateway(request)
"""
verify
"""
def get_verify_data(self):
super(PayV1, self).get_verify_data()
data = {
"api": self._merchant_code(),
"token": self.get_reference_number(),
}
return data
def prepare_verify(self, tracking_code):
super(PayV1, self).prepare_verify(tracking_code)
def verify(self, tracking_code):
super(PayV1, self).verify(tracking_code)
data = self.get_verify_data()
response = self._send_data(self._verify_api_url, data, timeout=10)
response_json = response.json()
status = PaymentStatus.COMPLETE
if int(response_json["status"]) != 1:
if int(response_json["errorCode"]) == -5:
status = PaymentStatus.ERROR
elif int(response_json["errorCode"]) == -9:
status = PaymentStatus.EXPIRE_VERIFY_PAYMENT
elif int(response_json["errorCode"]) == -15:
status = PaymentStatus.CANCEL_BY_USER
elif int(response_json["errorCode"]) == -27:
status = PaymentStatus.RETURN_FROM_BANK
else:
status = PaymentStatus.ERROR
self._set_payment_status(status)
extra_information = json.dumps(response_json)
self._bank.extra_information = extra_information
self._bank.save()
def _send_data(self, url, data, timeout=5) -> requests.post:
try:
logging.debug("Sending POST request to {} with data {}".format(url, data))
response = requests.post(url, json=data, timeout=timeout)
except requests.Timeout:
logging.exception("PayV1 time out gateway {}".format(data))
raise BankGatewayConnectionError()
except requests.ConnectionError:
logging.exception("PayV1 time out gateway {}".format(data))
raise BankGatewayConnectionError()
return response
+18 -28
View File
@@ -1,7 +1,6 @@
import logging import logging
import requests import requests
from zeep import Client, Transport
from azbankgateways.banks import BaseBank from azbankgateways.banks import BaseBank
from azbankgateways.exceptions import BankGatewayConnectionError, SettingDoesNotExist from azbankgateways.exceptions import BankGatewayConnectionError, SettingDoesNotExist
@@ -16,10 +15,16 @@ class SEP(BaseBank):
def __init__(self, **kwargs): def __init__(self, **kwargs):
super(SEP, self).__init__(**kwargs) super(SEP, self).__init__(**kwargs)
if not self._is_strict_origin_policy_enabled():
raise SettingDoesNotExist(
"SECURE_REFERRER_POLICY is not set to 'strict-origin-when-cross-origin' in django setting,"
" it's mandatory for Saman gateway"
)
self.set_gateway_currency(CurrencyEnum.IRR) self.set_gateway_currency(CurrencyEnum.IRR)
self._token_api_url = "https://sep.shaparak.ir/MobilePG/MobilePayment" self._token_api_url = "https://sep.shaparak.ir/onlinepg/onlinepg"
self._payment_url = "https://sep.shaparak.ir/OnlinePG/OnlinePG" self._payment_url = "https://sep.shaparak.ir/OnlinePG/OnlinePG"
self._verify_api_url = "https://verify.sep.ir/Payments/ReferencePayment.asmx?WSDL" self._verify_api_url = "https://sep.shaparak.ir/verifyTxnRandomSessionkey/ipg/VerifyTransaction"
def get_bank_type(self): def get_bank_type(self):
return BankType.SEP return BankType.SEP
@@ -32,14 +37,14 @@ class SEP(BaseBank):
def get_pay_data(self): def get_pay_data(self):
data = { data = {
"Action": "Token", "action": "Token",
"Amount": self.get_gateway_amount(), "Amount": self.get_gateway_amount(),
"Wage": 0,
"TerminalId": self._merchant_code, "TerminalId": self._merchant_code,
"ResNum": self.get_tracking_code(), "ResNum": self.get_tracking_code(),
"RedirectURL": self._get_gateway_callback_url(), "RedirectURL": self._get_gateway_callback_url(),
"CellNumber": self.get_mobile_number(), "CellNumber": self.get_mobile_number(),
} }
data.update(self.get_custom_data())
return data return data
def prepare_pay(self): def prepare_pay(self):
@@ -80,15 +85,15 @@ class SEP(BaseBank):
def prepare_verify_from_gateway(self): def prepare_verify_from_gateway(self):
super(SEP, self).prepare_verify_from_gateway() super(SEP, self).prepare_verify_from_gateway()
request = self.get_request() request = self.get_request()
tracking_code = request.GET.get("ResNum", None) tracking_code = request.GET.get("ResNum")
token = request.GET.get("Token", None) token = request.GET.get("Token")
self._set_tracking_code(tracking_code) self._set_tracking_code(tracking_code)
self._set_bank_record() self._set_bank_record()
ref_num = request.GET.get("RefNum", None) ref_num = request.GET.get("RefNum")
if request.GET.get("State", "NOK") == "OK" and ref_num: if request.GET.get("State", "NOK") == "OK" and ref_num:
self._set_reference_number(ref_num) self._set_reference_number(ref_num)
self._bank.reference_number = ref_num self._bank.reference_number = ref_num
extra_information = f"TRACENO={request.GET.get('TRACENO', None)}, RefNum={ref_num}, Token={token}" extra_information = f"TRACENO={request.GET.get('TRACENO')}, RefNum={ref_num}, Token={token}"
self._bank.extra_information = extra_information self._bank.extra_information = extra_information
self._bank.save() self._bank.save()
@@ -101,8 +106,7 @@ class SEP(BaseBank):
def get_verify_data(self): def get_verify_data(self):
super(SEP, self).get_verify_data() super(SEP, self).get_verify_data()
data = self.get_reference_number(), self._merchant_code return {"RefNum": self.get_reference_number(), "TerminalNumber": self._merchant_code}
return data
def prepare_verify(self, tracking_code): def prepare_verify(self, tracking_code):
super(SEP, self).prepare_verify(tracking_code) super(SEP, self).prepare_verify(tracking_code)
@@ -110,9 +114,8 @@ class SEP(BaseBank):
def verify(self, transaction_code): def verify(self, transaction_code):
super(SEP, self).verify(transaction_code) super(SEP, self).verify(transaction_code)
data = self.get_verify_data() data = self.get_verify_data()
client = self._get_client(self._verify_api_url) result = self._send_data(api=self._verify_api_url, data=data)
result = client.service.verifyTransaction(*data) if result.get('ResultCode') == 0:
if result == self.get_gateway_amount():
self._set_payment_status(PaymentStatus.COMPLETE) self._set_payment_status(PaymentStatus.COMPLETE)
else: else:
self._set_payment_status(PaymentStatus.CANCEL_BY_USER) self._set_payment_status(PaymentStatus.CANCEL_BY_USER)
@@ -120,7 +123,7 @@ class SEP(BaseBank):
def _send_data(self, api, data): def _send_data(self, api, data):
try: try:
response = requests.post(api, json=data, timeout=5) response = requests.post(api, json=data, timeout=self.get_timeout())
except requests.Timeout: except requests.Timeout:
logging.exception("SEP time out gateway {}".format(data)) logging.exception("SEP time out gateway {}".format(data))
raise BankGatewayConnectionError() raise BankGatewayConnectionError()
@@ -131,16 +134,3 @@ class SEP(BaseBank):
response_json = get_json(response) response_json = get_json(response)
self._set_transaction_status_text(response_json.get("errorDesc")) self._set_transaction_status_text(response_json.get("errorDesc"))
return response_json return response_json
@staticmethod
def _get_client(url):
headers = {
"Accept": "*/*",
"Accept-Encoding": "gzip, deflate, br",
"Connection": "keep-alive",
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0",
}
transport = Transport(timeout=5, operation_timeout=5)
transport.session.headers = headers
client = Client(url, transport=transport)
return client
+51 -42
View File
@@ -1,11 +1,15 @@
import logging import logging
from zeep import Client, Transport import requests
from azbankgateways.banks import BaseBank from azbankgateways.banks import BaseBank
from azbankgateways.exceptions import SettingDoesNotExist from azbankgateways.exceptions import SettingDoesNotExist
from azbankgateways.exceptions.exceptions import BankGatewayRejectPayment from azbankgateways.exceptions.exceptions import (
BankGatewayConnectionError,
BankGatewayRejectPayment,
)
from azbankgateways.models import BankType, CurrencyEnum, PaymentStatus from azbankgateways.models import BankType, CurrencyEnum, PaymentStatus
from azbankgateways.utils import get_json
class Zarinpal(BaseBank): class Zarinpal(BaseBank):
@@ -16,8 +20,12 @@ class Zarinpal(BaseBank):
kwargs.setdefault("SANDBOX", 0) kwargs.setdefault("SANDBOX", 0)
super(Zarinpal, self).__init__(**kwargs) super(Zarinpal, self).__init__(**kwargs)
self.set_gateway_currency(CurrencyEnum.IRT) self.set_gateway_currency(CurrencyEnum.IRT)
self._payment_url = "https://www.zarinpal.com/pg/StartPay/{}/ZarinGate" self._payment_type = 'payment'
self._sandbox_url = "https://sandbox.zarinpal.com/pg/StartPay/{}/ZarinGate" if self._sandbox:
self._payment_type = 'sandbox'
self._payment_url = f"https://{self._payment_type}.zarinpal.com/pg/v4/payment/request.json"
self._startpay_url = f"https://{self._payment_type}.zarinpal.com/pg/StartPay/"
self._verify_url = f"https://{self._payment_type}.zarinpal.com/pg/v4/payment/verify.json"
def get_bank_type(self): def get_bank_type(self):
return BankType.ZARINPAL return BankType.ZARINPAL
@@ -37,9 +45,7 @@ class Zarinpal(BaseBank):
return 1000 return 1000
def _get_gateway_payment_url_parameter(self): def _get_gateway_payment_url_parameter(self):
if self._sandbox: return self._startpay_url + "{}".format(self.get_reference_number())
return self._sandbox_url.format(self.get_reference_number())
return self._payment_url.format(self.get_reference_number())
def _get_gateway_payment_parameter(self): def _get_gateway_payment_parameter(self):
return {} return {}
@@ -54,14 +60,19 @@ class Zarinpal(BaseBank):
def get_pay_data(self): def get_pay_data(self):
description = "خرید با شماره پیگیری - {}".format(self.get_tracking_code()) description = "خرید با شماره پیگیری - {}".format(self.get_tracking_code())
return { data = {
"Description": description, "description": description,
"MerchantID": self._merchant_code, "merchant_id": self._merchant_code,
"Amount": self.get_gateway_amount(), "amount": self.get_gateway_amount(),
"Email": None, "currency": self.get_gateway_currency(),
"Mobile": self.get_mobile_number(), "metadata": {},
"CallbackURL": self._get_gateway_callback_url(), "callback_url": self._get_gateway_callback_url(),
} }
mobile_number = self.get_mobile_number()
if mobile_number:
data["metadata"].update({"mobile": mobile_number})
data.update(self.get_custom_data())
return data
def prepare_pay(self): def prepare_pay(self):
super(Zarinpal, self).prepare_pay() super(Zarinpal, self).prepare_pay()
@@ -69,10 +80,9 @@ class Zarinpal(BaseBank):
def pay(self): def pay(self):
super(Zarinpal, self).pay() super(Zarinpal, self).pay()
data = self.get_pay_data() data = self.get_pay_data()
client = self._get_client() result = self._send_data(api=self._payment_url, data=data)
result = client.service.PaymentRequest(**data) if result['data']:
if result.Status == 100: token = result['data']['authority']
token = result.Authority
self._set_reference_number(token) self._set_reference_number(token)
else: else:
logging.critical("Zarinpal gateway reject payment") logging.critical("Zarinpal gateway reject payment")
@@ -84,7 +94,7 @@ class Zarinpal(BaseBank):
def prepare_verify_from_gateway(self): def prepare_verify_from_gateway(self):
super(Zarinpal, self).prepare_verify_from_gateway() super(Zarinpal, self).prepare_verify_from_gateway()
token = self.get_request().GET.get("Authority", None) token = self.get_request().GET.get("Authority")
self._set_reference_number(token) self._set_reference_number(token)
self._set_bank_record() self._set_bank_record()
@@ -98,9 +108,9 @@ class Zarinpal(BaseBank):
def get_verify_data(self): def get_verify_data(self):
super(Zarinpal, self).get_verify_data() super(Zarinpal, self).get_verify_data()
return { return {
"MerchantID": self._merchant_code, "merchant_id": self._merchant_code,
"Authority": self.get_reference_number(), "authority": self.get_reference_number(),
"Amount": self.get_gateway_amount(), "amount": self.get_gateway_amount(),
} }
def prepare_verify(self, tracking_code): def prepare_verify(self, tracking_code):
@@ -109,27 +119,26 @@ class Zarinpal(BaseBank):
def verify(self, transaction_code): def verify(self, transaction_code):
super(Zarinpal, self).verify(transaction_code) super(Zarinpal, self).verify(transaction_code)
data = self.get_verify_data() data = self.get_verify_data()
client = self._get_client(timeout=10) result = self._send_data(api=self._verify_url, data=data)
try: if result['data'] and result['data']['code'] in [100, 101]:
result = client.service.PaymentVerification(**data) self._set_payment_status(PaymentStatus.COMPLETE)
if result.Status in [100, 101]: else:
self._set_payment_status(PaymentStatus.COMPLETE)
else:
self._set_payment_status(PaymentStatus.CANCEL_BY_USER)
logging.debug("Zarinpal gateway unapprove payment")
except:
self._set_payment_status(PaymentStatus.CANCEL_BY_USER) self._set_payment_status(PaymentStatus.CANCEL_BY_USER)
logging.debug("Zarinpal gateway unapprove payment") logging.debug("Zarinpal gateway unapprove payment")
def _get_client(self, timeout=5): def _send_data(self, api, data):
transport = Transport(timeout=timeout, operation_timeout=timeout) try:
if self._sandbox: response = requests.post(api, json=data, timeout=self.get_timeout())
return Client( except requests.Timeout:
"https://sandbox.zarinpal.com/pg/services/WebGate/wsdl", logging.exception("ZARINPAL time out gateway {}".format(data))
transport=transport, raise BankGatewayConnectionError()
) except requests.ConnectionError:
logging.exception("ZARINPAL time out gateway {}".format(data))
raise BankGatewayConnectionError()
return Client( response_json = get_json(response)
"https://www.zarinpal.com/pg/services/WebGate/wsdl", if response_json['data']:
transport=transport, self._set_transaction_status_text(response_json['data']['message'])
) else:
self._set_transaction_status_text(response_json['errors']['message'])
return response_json
+3 -2
View File
@@ -55,6 +55,7 @@ class Zibal(BaseBank):
"orderId": self.get_tracking_code(), "orderId": self.get_tracking_code(),
"mobile": self.get_mobile_number(), "mobile": self.get_mobile_number(),
} }
data.update(self.get_custom_data())
return data return data
def prepare_pay(self): def prepare_pay(self):
@@ -77,7 +78,7 @@ class Zibal(BaseBank):
def prepare_verify_from_gateway(self): def prepare_verify_from_gateway(self):
super(Zibal, self).prepare_verify_from_gateway() super(Zibal, self).prepare_verify_from_gateway()
token = self.get_request().GET.get("trackId", None) token = self.get_request().GET.get("trackId")
self._set_reference_number(token) self._set_reference_number(token)
self._set_bank_record() self._set_bank_record()
@@ -114,7 +115,7 @@ class Zibal(BaseBank):
def _send_data(self, api, data): def _send_data(self, api, data):
try: try:
response = requests.post(api, json=data, timeout=5) response = requests.post(api, json=data, timeout=self.get_timeout())
except requests.Timeout: except requests.Timeout:
logging.exception("Zibal time out gateway {}".format(data)) logging.exception("Zibal time out gateway {}".format(data))
raise BankGatewayConnectionError() raise BankGatewayConnectionError()
+3 -2
View File
@@ -12,17 +12,18 @@ BANK_CLASS = getattr(
"BMI": "azbankgateways.banks.BMI", "BMI": "azbankgateways.banks.BMI",
"SEP": "azbankgateways.banks.SEP", "SEP": "azbankgateways.banks.SEP",
"ZARINPAL": "azbankgateways.banks.Zarinpal", "ZARINPAL": "azbankgateways.banks.Zarinpal",
"IDPAY": "azbankgateways.banks.IDPay",
"ZIBAL": "azbankgateways.banks.Zibal", "ZIBAL": "azbankgateways.banks.Zibal",
"BAHAMTA": "azbankgateways.banks.Bahamta", "BAHAMTA": "azbankgateways.banks.Bahamta",
"MELLAT": "azbankgateways.banks.Mellat", "MELLAT": "azbankgateways.banks.Mellat",
"PAYV1": "azbankgateways.banks.PayV1", "IRANDARGAH": "azbankgateways.banks.irandargah.IranDargah",
"ASANPARDAKHT": "azbankgateways.banks.asanpardakht.AsanPardakht",
}, },
) )
_AZ_IRANIAN_BANK_GATEWAYS = getattr(settings, "AZ_IRANIAN_BANK_GATEWAYS", {}) _AZ_IRANIAN_BANK_GATEWAYS = getattr(settings, "AZ_IRANIAN_BANK_GATEWAYS", {})
BANK_PRIORITIES = _AZ_IRANIAN_BANK_GATEWAYS.get("BANK_PRIORITIES", []) BANK_PRIORITIES = _AZ_IRANIAN_BANK_GATEWAYS.get("BANK_PRIORITIES", [])
BANK_GATEWAYS = _AZ_IRANIAN_BANK_GATEWAYS.get("GATEWAYS", {}) BANK_GATEWAYS = _AZ_IRANIAN_BANK_GATEWAYS.get("GATEWAYS", {})
BANK_DEFAULT = _AZ_IRANIAN_BANK_GATEWAYS.get("DEFAULT", "BMI") BANK_DEFAULT = _AZ_IRANIAN_BANK_GATEWAYS.get("DEFAULT", "BMI")
BANK_TIMEOUT = _AZ_IRANIAN_BANK_GATEWAYS.get("BANK_TIMEOUT", 5)
SETTING_VALUE_READER_CLASS = _AZ_IRANIAN_BANK_GATEWAYS.get( SETTING_VALUE_READER_CLASS = _AZ_IRANIAN_BANK_GATEWAYS.get(
"SETTING_VALUE_READER_CLASS", "azbankgateways.readers.DefaultReader" "SETTING_VALUE_READER_CLASS", "azbankgateways.readers.DefaultReader"
) )
@@ -2,10 +2,11 @@ from .exceptions import ( # noqa
AmountDoesNotSupport, AmountDoesNotSupport,
AZBankGatewaysException, AZBankGatewaysException,
BankGatewayConnectionError, BankGatewayConnectionError,
BankGatewayRejectPayment,
BankGatewayStateInvalid, BankGatewayStateInvalid,
BankGatewayTokenExpired, BankGatewayTokenExpired,
BankGatewayUnclear, BankGatewayUnclear,
CurrencyDoesNotSupport, CurrencyDoesNotSupport,
SettingDoesNotExist,
SafeSettingsEnabled, SafeSettingsEnabled,
SettingDoesNotExist,
) )
@@ -82,10 +82,6 @@ msgstr ""
msgid "Zarinpal" msgid "Zarinpal"
msgstr "" msgstr ""
#: models/enum.py:10
msgid "IDPay"
msgstr ""
#: models/enum.py:11 #: models/enum.py:11
msgid "Zibal" msgid "Zibal"
msgstr "" msgstr ""
@@ -90,10 +90,6 @@ msgstr "بانک سامان"
msgid "Zarinpal" msgid "Zarinpal"
msgstr "زرین پال" msgstr "زرین پال"
#: models/enum.py:10
msgid "IDPay"
msgstr "آی دی پی"
#: models/enum.py:11 #: models/enum.py:11
msgid "Zibal" msgid "Zibal"
msgstr "زیبال" msgstr "زیبال"
@@ -0,0 +1,18 @@
# Generated by Django 5.2 on 2026-05-22 16:40
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('azbankgateways', '0008_alter_bank_order'),
]
operations = [
migrations.AlterField(
model_name='bank',
name='bank_type',
field=models.CharField(choices=[('BMI', 'BMI'), ('SEP', 'SEP'), ('ZARINPAL', 'Zarinpal'), ('ZIBAL', 'Zibal'), ('BAHAMTA', 'Bahamta'), ('MELLAT', 'Mellat'), ('IRANDARGAH', 'IranDargah'), ('ASANPARDAKHT', 'AsanPardakht')], max_length=50, verbose_name='Bank'),
),
]
+2 -2
View File
@@ -6,11 +6,11 @@ class BankType(models.TextChoices):
BMI = "BMI", _("BMI") BMI = "BMI", _("BMI")
SEP = "SEP", _("SEP") SEP = "SEP", _("SEP")
ZARINPAL = "ZARINPAL", _("Zarinpal") ZARINPAL = "ZARINPAL", _("Zarinpal")
IDPAY = "IDPAY", _("IDPay")
ZIBAL = "ZIBAL", _("Zibal") ZIBAL = "ZIBAL", _("Zibal")
BAHAMTA = "BAHAMTA", _("Bahamta") BAHAMTA = "BAHAMTA", _("Bahamta")
MELLAT = "MELLAT", _("Mellat") MELLAT = "MELLAT", _("Mellat")
PAYV1 = "PAYV1", _("PayV1") IRANDARGAH = "IRANDARGAH", _("IranDargah")
ASANPARDAKHT = "ASANPARDAKHT", _("AsanPardakht")
class CurrencyEnum(models.TextChoices): class CurrencyEnum(models.TextChoices):
+28
View File
@@ -1,6 +1,9 @@
import json import json
from urllib import parse from urllib import parse
from django.conf import settings
from django.urls import reverse
from azbankgateways.types import DictQuerystring from azbankgateways.types import DictQuerystring
@@ -33,3 +36,28 @@ def split_to_dict_querystring(url: str) -> DictQuerystring:
url_parts[5] = "" url_parts[5] = ""
return parse.urlunparse(url_parts), query return parse.urlunparse(url_parts), query
def build_full_url(viewname: str, *args, **kwargs):
"""
Build a full absolute URL including domain if Sites framework is available.
Falls back to relative path if no site is configured.
"""
# Generate the path part
path = reverse(viewname, args=args, kwargs=kwargs)
# Try to use django.contrib.sites if installed
if "django.contrib.sites" in settings.INSTALLED_APPS:
try:
from django.contrib.sites.models import Site
site = Site.objects.get_current()
if site and site.domain:
protocol = getattr(settings, "DEFAULT_PROTOCOL", "https")
return f"{protocol}://{site.domain}{path}"
except Exception:
# Any issue with Sites, just return relative path
pass
# Fallback: return only relative path
return path