233 lines
8.3 KiB
Python
233 lines
8.3 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,
|
|
)
|
|
|
|
l1 = 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",
|
|
)
|