feat: changed TPV behaviour
This commit is contained in:
+125
@@ -1,17 +1,28 @@
|
||||
import base64
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
from decimal import Decimal
|
||||
|
||||
import pyDes
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.db import transaction
|
||||
from django.utils import timezone
|
||||
from django.utils.text import gettext_lazy as _
|
||||
|
||||
from shop.exceptions import RedsysPaymentException, RedsysValidationException
|
||||
from shop.models import (
|
||||
Cart,
|
||||
CustomerAddress,
|
||||
Order,
|
||||
OrderLine,
|
||||
Payment,
|
||||
Product,
|
||||
ProductBatch,
|
||||
ProductPrice,
|
||||
ShippingMethod,
|
||||
)
|
||||
from shop.settings import ERROR_CODES
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
@@ -148,3 +159,117 @@ def add_shipping_order_line(order, shipping_method):
|
||||
total=shipping_total,
|
||||
)
|
||||
order.calculate_total_from_lines()
|
||||
|
||||
|
||||
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 validate_payment_for_order(request, order: Order) -> 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'
|
||||
}
|
||||
|
||||
Raises AssertionError
|
||||
"""
|
||||
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)
|
||||
|
||||
order_code = result.get("Ds_Order")
|
||||
assert order_code == order.code
|
||||
|
||||
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 decode_b64_string(value: str):
|
||||
return base64.b64decode(value).decode()
|
||||
|
||||
|
||||
def decode_b64_dict(value: str):
|
||||
return json.loads(decode_b64_string(value))
|
||||
|
||||
|
||||
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_order(order: Order, amount_paid: Decimal):
|
||||
with transaction.atomic() as tx:
|
||||
payment = Payment.objects.create(
|
||||
amount=amount_paid,
|
||||
order=order,
|
||||
user=order.user,
|
||||
method=Payment.MethodChoices.REDSYS,
|
||||
)
|
||||
|
||||
if amount_paid >= order.total:
|
||||
order.status = Order.Statuses.STATUS_PAID
|
||||
order.save()
|
||||
|
||||
Reference in New Issue
Block a user