Files
shoppy/shop/tests/test_redsys.py
T
2025-05-02 08:38:57 +02:00

201 lines
7.9 KiB
Python

import base64
import json
from decimal import Decimal
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 rest_framework import status
from rest_framework.test import APITestCase
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(APITestCase, 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 == status.HTTP_200_OK
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 == status.HTTP_409_CONFLICT
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')