Files
shoppy/tpv/utils.py
T
2024-11-22 08:30:26 +01:00

134 lines
3.7 KiB
Python

import base64
import hashlib
import hmac
import json
import re
from decimal import Decimal
import pyDes
from django.utils import timezone
from django.utils.text import gettext_lazy as _
from tpv.exceptions import RedsysPaymentException, RedsysValidationException
from tpv.models import PaymentTransaction
from tpv.settings import ERROR_CODES
from tpv.signals import redsys_payment_accepted
def compute_signature(salt, payload, key):
"""
:param salt: order number (Ds_Order or Ds_Merchant_Order)
:param payload: Ds_MerchantParameters
:param key: shared secret (aka key) from the Redsys Administration Module
:return:
"""
b64_key = base64.b64decode(key)
des3 = pyDes.triple_des(
b64_key, mode=pyDes.CBC, IV="\0" * 8, pad="\0", padmode=pyDes.PAD_NORMAL
)
pepper = des3.encrypt(str(salt))
payload_hash = hmac.new(pepper, payload.encode(), hashlib.sha256).digest()
return base64.b64encode(payload_hash)
def compare_signatures(signature_1, signature_2):
alphanumeric_characters = re.compile("[^a-zA-Z0-9]")
sig1safe = re.sub(alphanumeric_characters, "", signature_1)
sig2safe = re.sub(alphanumeric_characters, "", signature_2)
return sig1safe == sig2safe
def validate_payment_for_transaction(
request, transaction: PaymentTransaction
) -> Decimal:
"""
example_response_data = {
'Ds_MerchantCode': '999008881',
'Ds_Terminal': '001',
'Ds_Order': 'a082bd1cda0b488786f23a62e89107c0',
'Ds_Amount': '13532',
'Ds_Currency': '978',
'Ds_Date': '20/03/2024',
'Ds_Hour': '12:21',
'Ds_SecurePayment': '1',
'Ds_Card_Number': '454881******1156',
'Ds_Card_Country': '724',
'Ds_Response': '0000',
'Ds_MerchantData': '',
'Ds_TransactionType': '0',
'Ds_ConsumerLanguage': '1',
'Ds_AuthorisationCode': '182670',
'Ds_Card_Brand': '1',
'Ds_ProcessedPayMethod': '80',
'Ds_ECI': '05',
'Ds_Response_Description': 'OPERACION AUTORIZADA'
}
"""
data = request.POST
merchant_parameters = data.get("Ds_MerchantParameters")
if not merchant_parameters:
raise RedsysValidationException(
_("No se ha recibido ningún valor para Ds_MerchantParameters")
)
merchant_params = decode_b64_string(merchant_parameters)
result = json.loads(merchant_params)
transaction_hex = result.get("Ds_Order")
assert transaction_hex == transaction.hash.hex
status_code = result.get("Ds_Response")
if int(status_code) > 100:
reason = ERROR_CODES.get(status_code, _("Error no tipificado"))
raise RedsysPaymentException(_(f"No se ha realizado el pago. Motivo: {reason}"))
amount = Decimal(result.get("Ds_Amount")) / 100
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))