feat: lots of changes

This commit is contained in:
2024-05-05 00:04:51 +02:00
parent d5643bbf5f
commit d148cc9c61
32 changed files with 509 additions and 61 deletions
+126 -24
View File
@@ -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
+18
View File
@@ -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",
+1 -1
View File
@@ -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
View File
@@ -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))
-3
View File
@@ -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: