update bank gateway
This commit is contained in:
@@ -1,2 +1,7 @@
|
||||
__version__ = "v2.0.5"
|
||||
import django
|
||||
|
||||
|
||||
__version__ = "1.0.0"
|
||||
|
||||
if django.VERSION < (3, 2):
|
||||
default_app_config = "azbankgateways.apps.AZIranianBankGatewaysConfig"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from django.contrib import admin
|
||||
from utils.admin import ModelAdmin
|
||||
|
||||
from .models import Bank
|
||||
|
||||
|
||||
class BankAdmin(ModelAdmin):
|
||||
class BankAdmin(admin.ModelAdmin):
|
||||
fields = [
|
||||
"pk",
|
||||
"status",
|
||||
@@ -17,7 +17,6 @@ class BankAdmin(ModelAdmin):
|
||||
"bank_choose_identifier",
|
||||
"created_at",
|
||||
"update_at",
|
||||
'order'
|
||||
]
|
||||
list_display = [
|
||||
"pk",
|
||||
@@ -32,7 +31,6 @@ class BankAdmin(ModelAdmin):
|
||||
"bank_choose_identifier",
|
||||
"created_at",
|
||||
"update_at",
|
||||
'order'
|
||||
]
|
||||
list_filter = [
|
||||
"status",
|
||||
@@ -66,7 +64,6 @@ class BankAdmin(ModelAdmin):
|
||||
"extra_information",
|
||||
"created_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
|
||||
@@ -1,8 +1,31 @@
|
||||
from .bahamta import Bahamta # noqa
|
||||
from .banks import BaseBank # noqa
|
||||
from .bmi import BMI # noqa
|
||||
from .idpay import IDPay # noqa
|
||||
from .mellat import Mellat # noqa
|
||||
from .sep import SEP # noqa
|
||||
from .zarinpal import Zarinpal # noqa
|
||||
from .zibal import Zibal # noqa
|
||||
"""
|
||||
This package exposes bank gateway classes.
|
||||
|
||||
NOTE:
|
||||
`from .banks import BaseBank` **must appear first** to avoid circular-import
|
||||
issues. Other classes depend on `BaseBank`, so importing it earlier prevents
|
||||
initialization-order problems.
|
||||
"""
|
||||
|
||||
# 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",
|
||||
]
|
||||
|
||||
Executable
+175
@@ -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']
|
||||
@@ -58,6 +58,7 @@ class Bahamta(BaseBank):
|
||||
"payer_mobile": self.get_mobile_number(),
|
||||
"callback_url": self._get_gateway_callback_url(),
|
||||
}
|
||||
data.update(self.get_custom_data())
|
||||
return data
|
||||
|
||||
def prepare_pay(self):
|
||||
@@ -70,7 +71,9 @@ class Bahamta(BaseBank):
|
||||
if response_json["ok"]:
|
||||
# در این سیستم رفرنس برای ذخیره سازی بر نمی گردد!
|
||||
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)
|
||||
else:
|
||||
logging.critical("Bahamta gateway reject payment")
|
||||
@@ -82,7 +85,7 @@ class Bahamta(BaseBank):
|
||||
|
||||
def prepare_verify_from_gateway(self):
|
||||
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_bank_record()
|
||||
|
||||
@@ -109,7 +112,7 @@ class Bahamta(BaseBank):
|
||||
super(Bahamta, self).verify(transaction_code)
|
||||
data = self.get_verify_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)
|
||||
extra_information = json.dumps(response_json.get("result", {}))
|
||||
self._bank.extra_information = extra_information
|
||||
@@ -121,7 +124,7 @@ class Bahamta(BaseBank):
|
||||
def _send_data(self, api, data):
|
||||
try:
|
||||
url = append_querystring(api, data)
|
||||
response = requests.get(url, timeout=5)
|
||||
response = requests.get(url, timeout=self.get_timeout())
|
||||
except requests.Timeout:
|
||||
logging.exception("Bahamta time out gateway {}".format(data))
|
||||
raise BankGatewayConnectionError()
|
||||
|
||||
@@ -4,11 +4,14 @@ import uuid
|
||||
from urllib import parse
|
||||
|
||||
import six
|
||||
from django.conf import settings as django_settings
|
||||
from django.db.models import Q
|
||||
from django.shortcuts import redirect
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
|
||||
from azbankgateways.utils import append_querystring, build_full_url
|
||||
|
||||
from .. import default_settings as settings
|
||||
from ..exceptions import (
|
||||
AmountDoesNotSupport,
|
||||
@@ -18,7 +21,6 @@ from ..exceptions import (
|
||||
SafeSettingsEnabled,
|
||||
)
|
||||
from ..models import Bank, CurrencyEnum, PaymentStatus
|
||||
from ..utils import append_querystring
|
||||
|
||||
|
||||
# TODO: handle and expire record after 15 minutes
|
||||
@@ -41,8 +43,12 @@ class BaseBank:
|
||||
def __init__(self, identifier: str, **kwargs):
|
||||
self.identifier = identifier
|
||||
self.default_setting_kwargs = kwargs
|
||||
self._custom_data: dict = {}
|
||||
self.set_default_settings()
|
||||
|
||||
def _is_strict_origin_policy_enabled(self):
|
||||
return django_settings.SECURE_REFERRER_POLICY == 'strict-origin-when-cross-origin'
|
||||
|
||||
@abc.abstractmethod
|
||||
def set_default_settings(self):
|
||||
"""default setting, like fetch merchant code, terminal id and etc"""
|
||||
@@ -162,6 +168,13 @@ class BaseBank:
|
||||
def get_mobile_number(self):
|
||||
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):
|
||||
"""ذخیره کال بک از طریق نرم افزار برای بازگردانی کاربر پس از بازگشت درگاه بانک به پکیج و سپس از پکیج به نرم
|
||||
افزار."""
|
||||
@@ -187,7 +200,10 @@ class BaseBank:
|
||||
def _set_bank_record(self):
|
||||
try:
|
||||
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()),
|
||||
)
|
||||
logging.debug("Set reference find bank object.")
|
||||
@@ -216,7 +232,10 @@ class BaseBank:
|
||||
return self._transaction_status_text
|
||||
|
||||
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(
|
||||
"Payment status is not status suitable.",
|
||||
extra={"status": self._bank.status},
|
||||
@@ -247,6 +266,10 @@ class BaseBank:
|
||||
def get_currency(self):
|
||||
return self._currency
|
||||
|
||||
@staticmethod
|
||||
def get_timeout():
|
||||
return settings.BANK_TIMEOUT
|
||||
|
||||
def get_gateway_amount(self):
|
||||
return self._gateway_amount
|
||||
|
||||
@@ -357,8 +380,8 @@ class BaseBank:
|
||||
return redirect_url
|
||||
|
||||
def _get_gateway_callback_url(self):
|
||||
url = reverse(settings.CALLBACK_NAMESPACE)
|
||||
if self.get_request():
|
||||
url = reverse(settings.CALLBACK_NAMESPACE)
|
||||
url_parts = list(parse.urlparse(url))
|
||||
if not (url_parts[0] and url_parts[1]):
|
||||
url = self.get_request().build_absolute_uri(url)
|
||||
@@ -366,5 +389,6 @@ class BaseBank:
|
||||
query.update({"bank_type": self.get_bank_type()})
|
||||
query.update({"identifier": self.identifier})
|
||||
url = append_querystring(url, query)
|
||||
|
||||
else:
|
||||
url = build_full_url(settings.CALLBACK_NAMESPACE)
|
||||
return url
|
||||
|
||||
@@ -22,6 +22,12 @@ class BMI(BaseBank):
|
||||
|
||||
def __init__(self, **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._token_api_url = "https://sadad.shaparak.ir/vpg/api/v0/Request/PaymentRequest"
|
||||
self._payment_url = "https://sadad.shaparak.ir/VPG/Purchase"
|
||||
@@ -54,6 +60,7 @@ class BMI(BaseBank):
|
||||
"OrderId": self.get_tracking_code(),
|
||||
"AdditionalData": "oi:%s-ou:%s" % (self.get_tracking_code(), self.get_mobile_number()),
|
||||
}
|
||||
data.update(self.get_custom_data())
|
||||
return data
|
||||
|
||||
def prepare_pay(self):
|
||||
@@ -63,7 +70,7 @@ class BMI(BaseBank):
|
||||
super(BMI, self).pay()
|
||||
data = self.get_pay_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"]
|
||||
self._set_reference_number(token)
|
||||
else:
|
||||
@@ -99,10 +106,11 @@ class BMI(BaseBank):
|
||||
super(BMI, self).verify(transaction_code)
|
||||
data = self.get_verify_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)
|
||||
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.save()
|
||||
@@ -113,10 +121,13 @@ class BMI(BaseBank):
|
||||
def prepare_verify_from_gateway(self):
|
||||
super(BMI, self).prepare_verify_from_gateway()
|
||||
request = self.get_request()
|
||||
for method in ["POST", "GET", "data", "PUT"]:
|
||||
token = getattr(request, method, {}).get("token", None)
|
||||
if token:
|
||||
method_data = getattr(request, "POST", {})
|
||||
token = None
|
||||
for key, value in method_data.items():
|
||||
if key.lower() == "token":
|
||||
token = value
|
||||
break
|
||||
|
||||
if not token:
|
||||
raise BankGatewayStateInvalid
|
||||
self._set_reference_number(token)
|
||||
@@ -142,7 +153,7 @@ class BMI(BaseBank):
|
||||
|
||||
def _send_data(self, api, data):
|
||||
try:
|
||||
response = requests.post(api, json=data, timeout=5)
|
||||
response = requests.post(api, json=data, timeout=self.get_timeout())
|
||||
except requests.Timeout:
|
||||
logging.exception("BMI time out gateway {}".format(data))
|
||||
raise BankGatewayConnectionError()
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -68,6 +68,7 @@ class Mellat(BaseBank):
|
||||
"callBackUrl": self._get_gateway_callback_url(),
|
||||
"payerId": 0,
|
||||
}
|
||||
data.update(self.get_custom_data())
|
||||
return data
|
||||
|
||||
def prepare_pay(self):
|
||||
@@ -163,9 +164,7 @@ class Mellat(BaseBank):
|
||||
status_text = "Payment ID is incorrect"
|
||||
elif response == "414":
|
||||
status_text = "The organization issuing the bill is invalid"
|
||||
elif response == "415":
|
||||
status_text = "The working session has ended"
|
||||
elif response == "416":
|
||||
elif response in ["415", "416"]:
|
||||
status_text = "The working session has ended"
|
||||
elif response == "417":
|
||||
status_text = "Payer ID is invalid"
|
||||
@@ -187,12 +186,12 @@ class Mellat(BaseBank):
|
||||
def prepare_verify_from_gateway(self):
|
||||
super(Mellat, self).prepare_verify_from_gateway()
|
||||
post = self.get_request().POST
|
||||
token = post.get("RefId", None)
|
||||
token = post.get("RefId")
|
||||
if not token:
|
||||
return
|
||||
self._set_reference_number(token)
|
||||
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()
|
||||
|
||||
def verify_from_gateway(self, request):
|
||||
@@ -250,7 +249,7 @@ class Mellat(BaseBank):
|
||||
|
||||
@staticmethod
|
||||
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)
|
||||
return client
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -1,7 +1,6 @@
|
||||
import logging
|
||||
|
||||
import requests
|
||||
from zeep import Client, Transport
|
||||
|
||||
from azbankgateways.banks import BaseBank
|
||||
from azbankgateways.exceptions import BankGatewayConnectionError, SettingDoesNotExist
|
||||
@@ -16,10 +15,16 @@ class SEP(BaseBank):
|
||||
|
||||
def __init__(self, **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._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._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):
|
||||
return BankType.SEP
|
||||
@@ -32,14 +37,14 @@ class SEP(BaseBank):
|
||||
|
||||
def get_pay_data(self):
|
||||
data = {
|
||||
"Action": "Token",
|
||||
"action": "Token",
|
||||
"Amount": self.get_gateway_amount(),
|
||||
"Wage": 0,
|
||||
"TerminalId": self._merchant_code,
|
||||
"ResNum": self.get_tracking_code(),
|
||||
"RedirectURL": self._get_gateway_callback_url(),
|
||||
"CellNumber": self.get_mobile_number(),
|
||||
}
|
||||
data.update(self.get_custom_data())
|
||||
return data
|
||||
|
||||
def prepare_pay(self):
|
||||
@@ -80,15 +85,15 @@ class SEP(BaseBank):
|
||||
def prepare_verify_from_gateway(self):
|
||||
super(SEP, self).prepare_verify_from_gateway()
|
||||
request = self.get_request()
|
||||
tracking_code = request.GET.get("ResNum", None)
|
||||
token = request.GET.get("Token", None)
|
||||
tracking_code = request.GET.get("ResNum")
|
||||
token = request.GET.get("Token")
|
||||
self._set_tracking_code(tracking_code)
|
||||
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:
|
||||
self._set_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.save()
|
||||
|
||||
@@ -101,8 +106,7 @@ class SEP(BaseBank):
|
||||
|
||||
def get_verify_data(self):
|
||||
super(SEP, self).get_verify_data()
|
||||
data = self.get_reference_number(), self._merchant_code
|
||||
return data
|
||||
return {"RefNum": self.get_reference_number(), "TerminalNumber": self._merchant_code}
|
||||
|
||||
def prepare_verify(self, tracking_code):
|
||||
super(SEP, self).prepare_verify(tracking_code)
|
||||
@@ -110,9 +114,8 @@ class SEP(BaseBank):
|
||||
def verify(self, transaction_code):
|
||||
super(SEP, self).verify(transaction_code)
|
||||
data = self.get_verify_data()
|
||||
client = self._get_client(self._verify_api_url)
|
||||
result = client.service.verifyTransaction(*data)
|
||||
if result == self.get_gateway_amount():
|
||||
result = self._send_data(api=self._verify_api_url, data=data)
|
||||
if result.get('ResultCode') == 0:
|
||||
self._set_payment_status(PaymentStatus.COMPLETE)
|
||||
else:
|
||||
self._set_payment_status(PaymentStatus.CANCEL_BY_USER)
|
||||
@@ -120,7 +123,7 @@ class SEP(BaseBank):
|
||||
|
||||
def _send_data(self, api, data):
|
||||
try:
|
||||
response = requests.post(api, json=data, timeout=5)
|
||||
response = requests.post(api, json=data, timeout=self.get_timeout())
|
||||
except requests.Timeout:
|
||||
logging.exception("SEP time out gateway {}".format(data))
|
||||
raise BankGatewayConnectionError()
|
||||
@@ -131,16 +134,3 @@ class SEP(BaseBank):
|
||||
response_json = get_json(response)
|
||||
self._set_transaction_status_text(response_json.get("errorDesc"))
|
||||
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
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
import logging
|
||||
|
||||
from zeep import Client, Transport
|
||||
import requests
|
||||
|
||||
from azbankgateways.banks import BaseBank
|
||||
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.utils import get_json
|
||||
|
||||
|
||||
class Zarinpal(BaseBank):
|
||||
@@ -16,8 +20,12 @@ class Zarinpal(BaseBank):
|
||||
kwargs.setdefault("SANDBOX", 0)
|
||||
super(Zarinpal, self).__init__(**kwargs)
|
||||
self.set_gateway_currency(CurrencyEnum.IRT)
|
||||
self._payment_url = "https://www.zarinpal.com/pg/StartPay/{}/ZarinGate"
|
||||
self._sandbox_url = "https://sandbox.zarinpal.com/pg/StartPay/{}/ZarinGate"
|
||||
self._payment_type = 'payment'
|
||||
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):
|
||||
return BankType.ZARINPAL
|
||||
@@ -37,9 +45,7 @@ class Zarinpal(BaseBank):
|
||||
return 1000
|
||||
|
||||
def _get_gateway_payment_url_parameter(self):
|
||||
if self._sandbox:
|
||||
return self._sandbox_url.format(self.get_reference_number())
|
||||
return self._payment_url.format(self.get_reference_number())
|
||||
return self._startpay_url + "{}".format(self.get_reference_number())
|
||||
|
||||
def _get_gateway_payment_parameter(self):
|
||||
return {}
|
||||
@@ -54,14 +60,19 @@ class Zarinpal(BaseBank):
|
||||
def get_pay_data(self):
|
||||
description = "خرید با شماره پیگیری - {}".format(self.get_tracking_code())
|
||||
|
||||
return {
|
||||
"Description": description,
|
||||
"MerchantID": self._merchant_code,
|
||||
"Amount": self.get_gateway_amount(),
|
||||
"Email": None,
|
||||
"Mobile": self.get_mobile_number(),
|
||||
"CallbackURL": self._get_gateway_callback_url(),
|
||||
data = {
|
||||
"description": description,
|
||||
"merchant_id": self._merchant_code,
|
||||
"amount": self.get_gateway_amount(),
|
||||
"currency": self.get_gateway_currency(),
|
||||
"metadata": {},
|
||||
"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):
|
||||
super(Zarinpal, self).prepare_pay()
|
||||
@@ -69,10 +80,9 @@ class Zarinpal(BaseBank):
|
||||
def pay(self):
|
||||
super(Zarinpal, self).pay()
|
||||
data = self.get_pay_data()
|
||||
client = self._get_client()
|
||||
result = client.service.PaymentRequest(**data)
|
||||
if result.Status == 100:
|
||||
token = result.Authority
|
||||
result = self._send_data(api=self._payment_url, data=data)
|
||||
if result['data']:
|
||||
token = result['data']['authority']
|
||||
self._set_reference_number(token)
|
||||
else:
|
||||
logging.critical("Zarinpal gateway reject payment")
|
||||
@@ -84,7 +94,7 @@ class Zarinpal(BaseBank):
|
||||
|
||||
def prepare_verify_from_gateway(self):
|
||||
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_bank_record()
|
||||
|
||||
@@ -98,9 +108,9 @@ class Zarinpal(BaseBank):
|
||||
def get_verify_data(self):
|
||||
super(Zarinpal, self).get_verify_data()
|
||||
return {
|
||||
"MerchantID": self._merchant_code,
|
||||
"Authority": self.get_reference_number(),
|
||||
"Amount": self.get_gateway_amount(),
|
||||
"merchant_id": self._merchant_code,
|
||||
"authority": self.get_reference_number(),
|
||||
"amount": self.get_gateway_amount(),
|
||||
}
|
||||
|
||||
def prepare_verify(self, tracking_code):
|
||||
@@ -109,27 +119,26 @@ class Zarinpal(BaseBank):
|
||||
def verify(self, transaction_code):
|
||||
super(Zarinpal, self).verify(transaction_code)
|
||||
data = self.get_verify_data()
|
||||
client = self._get_client(timeout=10)
|
||||
try:
|
||||
result = client.service.PaymentVerification(**data)
|
||||
if result.Status in [100, 101]:
|
||||
result = self._send_data(api=self._verify_url, data=data)
|
||||
if result['data'] and result['data']['code'] in [100, 101]:
|
||||
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)
|
||||
logging.debug("Zarinpal gateway unapprove payment")
|
||||
|
||||
def _get_client(self, timeout=5):
|
||||
transport = Transport(timeout=timeout, operation_timeout=timeout)
|
||||
if self._sandbox:
|
||||
return Client(
|
||||
"https://sandbox.zarinpal.com/pg/services/WebGate/wsdl",
|
||||
transport=transport,
|
||||
)
|
||||
def _send_data(self, api, data):
|
||||
try:
|
||||
response = requests.post(api, json=data, timeout=self.get_timeout())
|
||||
except requests.Timeout:
|
||||
logging.exception("ZARINPAL time out gateway {}".format(data))
|
||||
raise BankGatewayConnectionError()
|
||||
except requests.ConnectionError:
|
||||
logging.exception("ZARINPAL time out gateway {}".format(data))
|
||||
raise BankGatewayConnectionError()
|
||||
|
||||
return Client(
|
||||
"https://www.zarinpal.com/pg/services/WebGate/wsdl",
|
||||
transport=transport,
|
||||
)
|
||||
response_json = get_json(response)
|
||||
if response_json['data']:
|
||||
self._set_transaction_status_text(response_json['data']['message'])
|
||||
else:
|
||||
self._set_transaction_status_text(response_json['errors']['message'])
|
||||
return response_json
|
||||
|
||||
@@ -55,6 +55,7 @@ class Zibal(BaseBank):
|
||||
"orderId": self.get_tracking_code(),
|
||||
"mobile": self.get_mobile_number(),
|
||||
}
|
||||
data.update(self.get_custom_data())
|
||||
return data
|
||||
|
||||
def prepare_pay(self):
|
||||
@@ -77,7 +78,7 @@ class Zibal(BaseBank):
|
||||
|
||||
def prepare_verify_from_gateway(self):
|
||||
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_bank_record()
|
||||
|
||||
@@ -114,7 +115,7 @@ class Zibal(BaseBank):
|
||||
|
||||
def _send_data(self, api, data):
|
||||
try:
|
||||
response = requests.post(api, json=data, timeout=5)
|
||||
response = requests.post(api, json=data, timeout=self.get_timeout())
|
||||
except requests.Timeout:
|
||||
logging.exception("Zibal time out gateway {}".format(data))
|
||||
raise BankGatewayConnectionError()
|
||||
|
||||
Regular → Executable
+3
-2
@@ -12,17 +12,18 @@ BANK_CLASS = getattr(
|
||||
"BMI": "azbankgateways.banks.BMI",
|
||||
"SEP": "azbankgateways.banks.SEP",
|
||||
"ZARINPAL": "azbankgateways.banks.Zarinpal",
|
||||
"IDPAY": "azbankgateways.banks.IDPay",
|
||||
"ZIBAL": "azbankgateways.banks.Zibal",
|
||||
"BAHAMTA": "azbankgateways.banks.Bahamta",
|
||||
"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", {})
|
||||
BANK_PRIORITIES = _AZ_IRANIAN_BANK_GATEWAYS.get("BANK_PRIORITIES", [])
|
||||
BANK_GATEWAYS = _AZ_IRANIAN_BANK_GATEWAYS.get("GATEWAYS", {})
|
||||
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", "azbankgateways.readers.DefaultReader"
|
||||
)
|
||||
|
||||
@@ -2,10 +2,11 @@ from .exceptions import ( # noqa
|
||||
AmountDoesNotSupport,
|
||||
AZBankGatewaysException,
|
||||
BankGatewayConnectionError,
|
||||
BankGatewayRejectPayment,
|
||||
BankGatewayStateInvalid,
|
||||
BankGatewayTokenExpired,
|
||||
BankGatewayUnclear,
|
||||
CurrencyDoesNotSupport,
|
||||
SettingDoesNotExist,
|
||||
SafeSettingsEnabled,
|
||||
SettingDoesNotExist,
|
||||
)
|
||||
|
||||
@@ -82,10 +82,6 @@ msgstr ""
|
||||
msgid "Zarinpal"
|
||||
msgstr ""
|
||||
|
||||
#: models/enum.py:10
|
||||
msgid "IDPay"
|
||||
msgstr ""
|
||||
|
||||
#: models/enum.py:11
|
||||
msgid "Zibal"
|
||||
msgstr ""
|
||||
|
||||
@@ -90,10 +90,6 @@ msgstr "بانک سامان"
|
||||
msgid "Zarinpal"
|
||||
msgstr "زرین پال"
|
||||
|
||||
#: models/enum.py:10
|
||||
msgid "IDPay"
|
||||
msgstr "آی دی پی"
|
||||
|
||||
#: models/enum.py:11
|
||||
msgid "Zibal"
|
||||
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'),
|
||||
),
|
||||
]
|
||||
Regular → Executable
+2
-2
@@ -6,11 +6,11 @@ class BankType(models.TextChoices):
|
||||
BMI = "BMI", _("BMI")
|
||||
SEP = "SEP", _("SEP")
|
||||
ZARINPAL = "ZARINPAL", _("Zarinpal")
|
||||
IDPAY = "IDPAY", _("IDPay")
|
||||
ZIBAL = "ZIBAL", _("Zibal")
|
||||
BAHAMTA = "BAHAMTA", _("Bahamta")
|
||||
MELLAT = "MELLAT", _("Mellat")
|
||||
PAYV1 = "PAYV1", _("PayV1")
|
||||
IRANDARGAH = "IRANDARGAH", _("IranDargah")
|
||||
ASANPARDAKHT = "ASANPARDAKHT", _("AsanPardakht")
|
||||
|
||||
|
||||
class CurrencyEnum(models.TextChoices):
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import json
|
||||
from urllib import parse
|
||||
|
||||
from django.conf import settings
|
||||
from django.urls import reverse
|
||||
|
||||
from azbankgateways.types import DictQuerystring
|
||||
|
||||
|
||||
@@ -33,3 +36,28 @@ def split_to_dict_querystring(url: str) -> DictQuerystring:
|
||||
url_parts[5] = ""
|
||||
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user