feat: lots of changes
This commit is contained in:
+126
-24
@@ -1,39 +1,36 @@
|
||||
import base64
|
||||
import json
|
||||
import requests
|
||||
|
||||
from django.conf import settings
|
||||
from django.urls import reverse
|
||||
|
||||
from tpv.models import PaymentTransaction
|
||||
from tpv.utils import compute_signature
|
||||
from tpv.utils import compute_signature, decode_b64_dict
|
||||
from tpv.settings import TransactionTypes
|
||||
|
||||
|
||||
class TransactionTypes:
|
||||
AUTHORIZATION = 0
|
||||
PREAUTHORIZATION = 1
|
||||
REPLACEMENT_PREAUTHORIZATION = 11
|
||||
CONFIRMATION = 2
|
||||
REFUND = 3
|
||||
SEPARATED_CONFIRMATION = 8
|
||||
CANCELED = 9
|
||||
PAYGOLD = 15
|
||||
PUCE_AUTHENTICATION = 17
|
||||
REFUND_WITHOUT_ORIGINAL = 34
|
||||
BET_PRICE = 37
|
||||
PAYMENT_CANCELED = 45
|
||||
REFUND_CANCELED = 46
|
||||
SEPARATED_CONFIRMATION_CANCELED = 47
|
||||
LINK_EXPIRATION_CHANGED_FOR_PAYGOLD = 51
|
||||
from tpv.exceptions import RedsysPaymentException
|
||||
|
||||
|
||||
class RedsysClient:
|
||||
DEBUG_ENVIRONMENT_URL = "https://sis-t.redsys.es:25443/sis/realizarPago"
|
||||
PROD_ENVIRONMENT_URL = ""
|
||||
|
||||
REST_DEBUG_ENVIRONMENT_URL = (
|
||||
"https://sis-t.redsys.es:25443/sis/rest/trataPeticionREST"
|
||||
)
|
||||
REST_PROD_ENVIRONMENT_URL = ""
|
||||
|
||||
def get_target_url(self):
|
||||
if settings.DEBUG:
|
||||
return self.DEBUG_ENVIRONMENT_URL
|
||||
return self.PROD_ENVIRONMENT_URL
|
||||
|
||||
def get_rest_target_url(self):
|
||||
if settings.DEBUG:
|
||||
return self.REST_DEBUG_ENVIRONMENT_URL
|
||||
return self.REST_PROD_ENVIRONMENT_URL
|
||||
|
||||
def get_merchant_code(self) -> str:
|
||||
return settings.REDSYS_MERCHANT_CODE
|
||||
|
||||
@@ -66,7 +63,7 @@ class RedsysClient:
|
||||
key = self.get_shared_secret()
|
||||
return compute_signature(str(hash), payload, key).decode()
|
||||
|
||||
def get_merchant_parameters_for_transaction(
|
||||
def _get_merchant_parameters_for_transaction(
|
||||
self,
|
||||
transaction: PaymentTransaction,
|
||||
transaction_type: int = TransactionTypes.AUTHORIZATION,
|
||||
@@ -90,23 +87,22 @@ class RedsysClient:
|
||||
"DS_MERCHANT_URLOK": self.get_merchant_url_ok_for_transaction(transaction),
|
||||
}
|
||||
|
||||
def get_encoded_merchant_parameters_for_transaction(
|
||||
def _get_encoded_merchant_parameters_for_transaction(
|
||||
self,
|
||||
transaction: PaymentTransaction,
|
||||
transaction_type: int = TransactionTypes.AUTHORIZATION,
|
||||
) -> str:
|
||||
body = self.get_merchant_parameters_for_transaction(
|
||||
body = self._get_merchant_parameters_for_transaction(
|
||||
transaction, transaction_type
|
||||
)
|
||||
stringified_body = json.dumps(body)
|
||||
return base64.b64encode(stringified_body.encode()).decode("utf-8")
|
||||
return self._encode_body(body)
|
||||
|
||||
def get_body_for_transaction(
|
||||
self,
|
||||
transaction: PaymentTransaction,
|
||||
transaction_type: int = TransactionTypes.AUTHORIZATION,
|
||||
) -> dict:
|
||||
merchant_parameters = self.get_encoded_merchant_parameters_for_transaction(
|
||||
merchant_parameters = self._get_encoded_merchant_parameters_for_transaction(
|
||||
transaction, transaction_type
|
||||
)
|
||||
signature = self.get_signature(transaction.hash.hex, merchant_parameters)
|
||||
@@ -116,3 +112,109 @@ class RedsysClient:
|
||||
"Ds_SignatureVersion": "HMAC_SHA256_V1",
|
||||
"Ds_Signature": signature,
|
||||
}
|
||||
|
||||
def _encode_body(self, value):
|
||||
stringified_body = json.dumps(value)
|
||||
return base64.b64encode(stringified_body.encode()).decode("utf-8")
|
||||
|
||||
def _get_rest_merchant_parameters_for_transaction(
|
||||
self,
|
||||
transaction: PaymentTransaction,
|
||||
pan: str,
|
||||
expiry_date: str,
|
||||
cvv2: str,
|
||||
transaction_type: int = TransactionTypes.AUTHORIZATION,
|
||||
) -> dict:
|
||||
merchant_code = self.get_merchant_code()
|
||||
|
||||
return {
|
||||
"DS_MERCHANT_AMOUNT": str(transaction.amount_integer),
|
||||
"DS_MERCHANT_CURRENCY": self.get_currency_code(),
|
||||
"DS_MERCHANT_CVV2": cvv2,
|
||||
"DS_MERCHANT_EXPIRYDATE": expiry_date,
|
||||
"DS_MERCHANT_MERCHANTCODE": merchant_code,
|
||||
"DS_MERCHANT_ORDER": transaction.hash.hex,
|
||||
"DS_MERCHANT_PAN": pan,
|
||||
"DS_MERCHANT_TERMINAL": "1",
|
||||
"DS_MERCHANT_TRANSACTIONTYPE": transaction_type,
|
||||
}
|
||||
|
||||
def _get_rest_encoded_merchant_parameters_for_transaction(
|
||||
self,
|
||||
transaction: PaymentTransaction,
|
||||
pan: str,
|
||||
expiry_date: str,
|
||||
cvv2: str,
|
||||
transaction_type: int = TransactionTypes.AUTHORIZATION,
|
||||
) -> str:
|
||||
body = self._get_rest_merchant_parameters_for_transaction(
|
||||
transaction,
|
||||
pan=pan,
|
||||
expiry_date=expiry_date,
|
||||
cvv2=cvv2,
|
||||
transaction_type=transaction_type,
|
||||
)
|
||||
return self._encode_body(body)
|
||||
|
||||
def _get_rest_body_for_transaction(
|
||||
self,
|
||||
transaction: PaymentTransaction,
|
||||
pan: str,
|
||||
expiry_date: str,
|
||||
cvv2: str,
|
||||
transaction_type: int = TransactionTypes.AUTHORIZATION,
|
||||
) -> dict:
|
||||
merchant_parameters = (
|
||||
self._get_rest_encoded_merchant_parameters_for_transaction(
|
||||
transaction=transaction,
|
||||
pan=pan,
|
||||
expiry_date=expiry_date,
|
||||
cvv2=cvv2,
|
||||
transaction_type=transaction_type,
|
||||
)
|
||||
)
|
||||
signature = self.get_signature(transaction.hash.hex, merchant_parameters)
|
||||
|
||||
return {
|
||||
"Ds_MerchantParameters": merchant_parameters,
|
||||
"Ds_SignatureVersion": "HMAC_SHA256_V1",
|
||||
"Ds_Signature": signature,
|
||||
}
|
||||
|
||||
def make_request_for_transaction(
|
||||
self,
|
||||
transaction: PaymentTransaction,
|
||||
pan: str,
|
||||
expiry_date: str,
|
||||
cvv2: str,
|
||||
transaction_type: int = TransactionTypes.AUTHORIZATION,
|
||||
):
|
||||
body = self._get_rest_body_for_transaction(
|
||||
transaction=transaction,
|
||||
pan=pan,
|
||||
expiry_date=expiry_date,
|
||||
cvv2=cvv2,
|
||||
transaction_type=transaction_type,
|
||||
)
|
||||
url = self.get_rest_target_url()
|
||||
response = requests.post(url, body)
|
||||
return response
|
||||
|
||||
def pay_transaction_rest(
|
||||
self, transaction: PaymentTransaction, pan: str, expiry_date: str, cvv2: str
|
||||
):
|
||||
response = self.make_request_for_transaction(
|
||||
transaction, pan, expiry_date, cvv2
|
||||
)
|
||||
data = response.json()
|
||||
error_code: str = data.get("errorCode", "")
|
||||
|
||||
if error_code:
|
||||
error_code.replace("SIS0", "0")
|
||||
|
||||
raise RedsysPaymentException(error_code)
|
||||
|
||||
merchant_parameters = data.get("Ds_MerchantParameters")
|
||||
parameters = decode_b64_dict(merchant_parameters)
|
||||
|
||||
return parameters
|
||||
|
||||
@@ -1,6 +1,24 @@
|
||||
from django.utils.text import gettext_lazy as _
|
||||
|
||||
|
||||
class TransactionTypes:
|
||||
AUTHORIZATION = 0
|
||||
PREAUTHORIZATION = 1
|
||||
REPLACEMENT_PREAUTHORIZATION = 11
|
||||
CONFIRMATION = 2
|
||||
REFUND = 3
|
||||
SEPARATED_CONFIRMATION = 8
|
||||
CANCELED = 9
|
||||
PAYGOLD = 15
|
||||
PUCE_AUTHENTICATION = 17
|
||||
REFUND_WITHOUT_ORIGINAL = 34
|
||||
BET_PRICE = 37
|
||||
PAYMENT_CANCELED = 45
|
||||
REFUND_CANCELED = 46
|
||||
SEPARATED_CONFIRMATION_CANCELED = 47
|
||||
LINK_EXPIRATION_CHANGED_FOR_PAYGOLD = 51
|
||||
|
||||
|
||||
CURRENCY_CODES = {
|
||||
8: "LEK ALL",
|
||||
12: "ALGERIAN DINAR DZD",
|
||||
|
||||
@@ -30,7 +30,7 @@ class TestRedsysTPV(APITestCase):
|
||||
transaction.save()
|
||||
|
||||
client = RedsysClient()
|
||||
merchant_parameters = client.get_merchant_parameters_for_transaction(
|
||||
merchant_parameters = client._get_merchant_parameters_for_transaction(
|
||||
transaction
|
||||
)
|
||||
|
||||
|
||||
+38
-5
@@ -8,10 +8,12 @@ import re
|
||||
|
||||
from decimal import Decimal
|
||||
from django.utils.text import gettext_lazy as _
|
||||
from django.utils import timezone
|
||||
|
||||
from tpv.exceptions import RedsysValidationException, RedsysPaymentException
|
||||
from tpv.models import PaymentTransaction
|
||||
from tpv.settings import ERROR_CODES
|
||||
from tpv.signals import redsys_payment_accepted
|
||||
|
||||
|
||||
def compute_signature(salt, payload, key):
|
||||
@@ -64,10 +66,6 @@ def validate_payment_for_transaction(
|
||||
'Ds_ECI': '05',
|
||||
'Ds_Response_Description': 'OPERACION AUTORIZADA'
|
||||
}
|
||||
|
||||
:param request:
|
||||
:param transaction:
|
||||
:return:
|
||||
"""
|
||||
data = request.POST
|
||||
|
||||
@@ -78,7 +76,7 @@ def validate_payment_for_transaction(
|
||||
_("No se ha recibido ningún valor para Ds_MerchantParameters")
|
||||
)
|
||||
|
||||
merchant_params = base64.b64decode(merchant_parameters).decode()
|
||||
merchant_params = decode_b64_string(merchant_parameters)
|
||||
result = json.loads(merchant_params)
|
||||
|
||||
transaction_hex = result.get("Ds_Order")
|
||||
@@ -96,6 +94,41 @@ def validate_payment_for_transaction(
|
||||
return amount
|
||||
|
||||
|
||||
def validate_expiry_date(expiry_date: str):
|
||||
if len(expiry_date) != 4:
|
||||
return False
|
||||
|
||||
month, year = int(expiry_date[2:4]), int(expiry_date[:2])
|
||||
|
||||
if month < 1 or month > 12:
|
||||
return False
|
||||
|
||||
current_year = int(str(timezone.now().year)[2:])
|
||||
current_month = timezone.now().month
|
||||
|
||||
if year < current_year:
|
||||
return False
|
||||
|
||||
if year == current_year and month > current_month:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def pay_transaction(transaction: PaymentTransaction, amount_paid: Decimal):
|
||||
transaction.status = PaymentTransaction.StatusChoices.PAID
|
||||
transaction.save()
|
||||
|
||||
redsys_payment_accepted.send_robust(
|
||||
PaymentTransaction.__class__,
|
||||
hash=transaction.hash,
|
||||
amount=amount_paid,
|
||||
)
|
||||
|
||||
|
||||
def decode_b64_string(value: str):
|
||||
return base64.b64decode(value).decode()
|
||||
|
||||
|
||||
def decode_b64_dict(value: str):
|
||||
return json.loads(decode_b64_string(value))
|
||||
|
||||
@@ -41,9 +41,6 @@ def webhook(request, transaction):
|
||||
try:
|
||||
amount_paid = validate_payment_for_transaction(request, transaction)
|
||||
pay_transaction(transaction, amount_paid)
|
||||
redsys_payment_accepted.send_robust(
|
||||
PaymentTransaction.__class__, hash=transaction.hash
|
||||
)
|
||||
|
||||
return HttpResponse(status=200)
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user