Files
shoppy/shop/tests/test_redsys.py
T
2026-03-20 10:30:52 +01:00

200 lines
7.8 KiB
Python

import base64
import json
from decimal import Decimal
from django.test import TestCase
from unittest.mock import patch
import pytest
from django.contrib.auth import get_user_model
from django.urls import reverse
from django.utils import timezone
from config.tests.mixins import Response
from shop.exceptions import RedsysPaymentException
from shop.models import CustomerAddress, Order, ShopSettings, Tax
from shop.redsys import RedsysClient
from shop.tests.mixins import CreateProductsMixin
from shop.utils import create_order, create_order_line_for_product, validate_expiry_date
User = get_user_model()
def redsys_response_ok(*args, **kwargs):
response = {
'Ds_SignatureVersion': 'HMAC_SHA256_V1',
'Ds_MerchantParameters': 'eyJEc19BbW91bnQiOiIxNDUiLCJEc19DdXJyZW5jeSI6Ijk3OCIsIkRzX09yZGVyIjoiMTQ0NjA2ODU4MSIsIkRzX01lcmNoYW50Q29kZSI6Ijk5OTAwODg4MSIsIkRzX1Rlcm1pbmFsIjoiMSIsIkRzX1Jlc3BvbnNlIjoiMDAwMCIsIkRzX0F1dGhvcmlzYXRpb25Db2RlIjoiNTAxNjAyIiwiRHNfVHJhbnNhY3Rpb25UeXBlIjoiMCIsIkRzX1NlY3VyZVBheW1lbnQiOiIwIiwiRHNfTGFuZ3VhZ2UiOiIxIiwiRHNfQ2FyZE51bWJlciI6IjQ1NDg4MSoqKioqKioqMDQiLCJEc19NZXJjaGFudERhdGEiOiIiLCJEc19DYXJkX0NvdW50cnkiOiI3MjQiLCJEc19DYXJkX0JyYW5kIjoiMSJ9',
'Ds_Signature': 'QVxoXwwp919v7XYjyBjhr1VXozESRosHPb3PDW-rcME=',
}
return Response(response, status_code=200)
def redsys_response_error(*args, **kwargs):
response = {'errorCode': 'SIS00001'}
return Response(response, status_code=200)
class TestRedsysTPV(TestCase, CreateProductsMixin):
def setUp(self):
self.tax = Tax.objects.create(code='IVA', value=21)
self.customer = get_user_model().objects.create_user(
username='11111111H', first_name='Darth', last_name='Maul', email='darth@maul.com', password='dathomir'
)
self.customer_shipping_address = CustomerAddress.objects.create(
user=self.customer,
address='Dathomir',
address_town='Dathomir',
address_zip='00001',
address_state='Dathomir',
address_phone='900000000',
address_type=CustomerAddress.Types.SHIPPING,
)
self.customer_billing_address = CustomerAddress.objects.create(
user=self.customer,
address='Dathomir',
address_town='Dathomir',
address_zip='00001',
address_state='Dathomir',
address_phone='900000000',
address_type=CustomerAddress.Types.BILLING,
)
self.product = self.create_product()
self.order = self.create_order()
self.order.calculate_total_from_lines()
self.settings = ShopSettings.load()
self.settings.merchant_code = '999008881'
self.settings.shared_secret = 'sq7HjrUOBfKmC576ILgskD5srU870gJ7' # Debug secret
self.settings.save()
def create_order(self):
order = create_order(
customer=self.customer,
billing_address=self.customer_billing_address.address,
billing_city=self.customer_billing_address.address_town,
billing_state=self.customer_billing_address.address_state,
billing_zip=self.customer_billing_address.address_zip,
billing_country=self.customer_billing_address.address_country,
)
create_order_line_for_product(self.product, quantity=Decimal('1.0'), order=order)
return order
def test_redsys_client(self):
amount_to_pay = Decimal('12.10')
client = RedsysClient()
merchant_parameters = client._get_merchant_parameters_for_order(self.order)
assert merchant_parameters.get('DS_MERCHANT_ORDER') == self.order.code
assert merchant_parameters.get('DS_MERCHANT_AMOUNT') == str(int(amount_to_pay * 100))
assert merchant_parameters.get('DS_MERCHANT_TERMINAL') == self.settings.terminal
assert merchant_parameters.get('DS_MERCHANT_MERCHANTCODE') == self.settings.merchant_code
client.get_body_for_order(self.order)
def test_redsys_webhook(self):
redsys_response_data = {
'Ds_MerchantCode': '999008881',
'Ds_Terminal': '001',
'Ds_Order': self.order.code,
'Ds_Amount': str(self.order.total * 100),
'Ds_Currency': '978',
'Ds_Date': '01/01/2024',
'Ds_Hour': '00:00',
'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',
}
redsys_response_data_str = json.dumps(redsys_response_data)
b64_merchant_params = base64.b64encode(redsys_response_data_str.encode()).decode()
response = self.client.post(
reverse('shop:webhook', kwargs={'uuid': self.order.uuid}),
data={
'Ds_MerchantParameters': b64_merchant_params,
'Ds_Signature': self.settings.shared_secret,
'Ds_SignatureVersion': 'HMAC_SHA256_V1',
},
)
self.order.refresh_from_db()
assert response.status_code == 200
assert self.order.status == Order.Statuses.STATUS_PAID
def test_redsys_webhook_payment_error(self):
redsys_response_data = {
'Ds_MerchantCode': '999008881',
'Ds_Terminal': '001',
'Ds_Order': self.order.code,
'Ds_Amount': '1000',
'Ds_Currency': '978',
'Ds_Date': '01/01/2024',
'Ds_Hour': '00:00',
'Ds_SecurePayment': '1',
'Ds_Card_Number': '454881******1156',
'Ds_Card_Country': '724',
'Ds_Response': '0184',
'Ds_MerchantData': '',
'Ds_TransactionType': '0',
'Ds_ConsumerLanguage': '1',
'Ds_AuthorisationCode': '182670',
'Ds_Card_Brand': '1',
'Ds_ProcessedPayMethod': '80',
'Ds_ECI': '05',
'Ds_Response_Description': 'ERROR',
}
redsys_response_data_str = json.dumps(redsys_response_data)
b64_merchant_params = base64.b64encode(redsys_response_data_str.encode()).decode()
response = self.client.post(
reverse('shop:webhook', kwargs={'uuid': self.order.uuid}),
data={
'Ds_MerchantParameters': b64_merchant_params,
'Ds_Signature': self.settings.shared_secret,
'Ds_SignatureVersion': 'HMAC_SHA256_V1',
},
)
assert response.status_code == 409
self.order.refresh_from_db()
assert self.order.status == Order.Statuses.STATUS_ERROR
def test_expiry_date(self):
now = timezone.now()
previous_year = str(now.year - 1).rjust(2, '0')
current_month = str(now.month).rjust(2, '0')
current_year = str(now.year)[-2:]
assert not validate_expiry_date('042024')
assert not validate_expiry_date(f'{previous_year}{current_month}')
assert validate_expiry_date(f'{current_year}{current_month}')
@patch('requests.post', redsys_response_ok)
def test_redsys_rest_client(self):
client = RedsysClient()
params = client.pay_order_rest(self.order, pan='4548810000000003', expiry_date='122049', cvv2='285')
assert params.get('Ds_Order') == '1446068581'
assert params.get('Ds_MerchantCode') == self.settings.merchant_code
@patch('requests.post', redsys_response_error)
def test_redsys_rest_client_error(self):
client = RedsysClient()
with pytest.raises(RedsysPaymentException):
client.pay_order_rest(self.order, pan='4548810000000003', expiry_date='122049', cvv2='285')