chore: docs and added new field for tpv domain

This commit is contained in:
2025-01-13 18:08:57 +01:00
parent 475b53a7e3
commit 2ff2d08565
12 changed files with 101 additions and 43 deletions
+25 -5
View File
@@ -95,8 +95,28 @@ Puedes crear un archivo `.env` con las siguientes variables de entorno.
| AWS_SECRET_ACCESS_KEY | | Clave secreta de S3 |
| AWS_STORAGE_BUCKET_NAME | | Nombre del bucket de S3 |
| AWS_S3_ENDPOINT_URL | | Endpoint de S3 |
| REDSYS_SHARED_SECRET | sq7HjrUOBfKmC576ILgskD5srU870gJ7 | Clave privada de Redsys |
| REDSYS_MERCHANT_CODE | 999008881 | Código de negocio de Redsys |
| REDSYS_TERMINAL | 001 | Terminal de Redsys |
| REDSYS_CURRENCY_CODE | 978 | Código de moneda de Redsys |
| REDSYS_TPV_DOMAIN | | Dominio del TPV para redirección de Redsys |
## Depurar pagos TPV con Redsys
Para poder usar el TPV en la máquina local necesitaremos instalar y configurar [`ngrok`](https://ngrok.com/),
siguiendo los pasos que nos indican en la web al crear nuestra cuenta
Arrancaremos ngrok con el siguiente comando:
```bash
ngrok http http://localhost:8000
```
Ngrok nos dará una URL accesible desde fuera, que tendremos que guardar en los `Ajustes de la tienda`
como `Dominio del TPV`
Tendremos que establecer también los siguientes ajustes de la cuenta con estos valores para desarrollo.
| Variable | Valor para desarrollo | Descripción |
|------------------------|----------------------------------|------------------------------------------------------------------------------|
| `redsys_shared_secret` | sq7HjrUOBfKmC576ILgskD5srU870gJ7 | Clave privada de Redsys |
| `merchant_code` | 999008881 | Código de negocio de Redsys |
| `terminal` | 001 | Terminal de Redsys |
| `currency_code` | 978 | Código de moneda de Redsys |
| `tpv_domain` | <variable> | Dominio del TPV para redirección de Redsys (en local lo obtenemos por ngrok) |
@@ -0,0 +1,20 @@
# Generated by Django 5.1.4 on 2025-01-13 08:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("shop", "0003_order_shipping_method_alter_payment_order"),
]
operations = [
migrations.AddField(
model_name="shopsettings",
name="tpv_domain",
field=models.URLField(
blank=True, max_length=128, null=True, verbose_name="dominio del tpv"
),
),
]
+3
View File
@@ -631,6 +631,9 @@ class ShopSettings(SingletonModel):
) # 978 == EURO
terminal = models.CharField(max_length=8, verbose_name=_("Terminal"))
shared_secret = models.CharField(max_length=100, verbose_name=_("Clave de Redsys"))
tpv_domain = models.URLField(
max_length=128, blank=True, null=True, verbose_name=_("dominio del tpv")
)
class Meta:
verbose_name = _("ajustes de la tienda")
+11 -8
View File
@@ -7,7 +7,7 @@ from django.conf import settings
from django.urls import reverse
from shop.exceptions import RedsysPaymentException
from shop.models import Order
from shop.models import Order, ShopSettings
from shop.settings import TransactionTypes
from shop.utils import compute_signature, decode_b64_dict
@@ -21,6 +21,9 @@ class RedsysClient:
)
REST_PROD_ENVIRONMENT_URL = "https://sis.redsys.es/sis/rest/trataPeticionREST"
def __init__(self):
self.settings = ShopSettings.load()
def get_target_url(self):
if settings.DEBUG:
return self.DEBUG_ENVIRONMENT_URL
@@ -32,31 +35,31 @@ class RedsysClient:
return self.REST_PROD_ENVIRONMENT_URL
def get_merchant_code(self) -> str:
return settings.REDSYS_MERCHANT_CODE
return self.settings.merchant_code
def get_terminal(self) -> str:
return settings.REDSYS_TERMINAL
return self.settings.terminal
def get_currency_code(self) -> str:
return settings.REDSYS_CURRENCY_CODE
return self.settings.currency_code
def get_merchant_url_ok_for_order(self, order: Order) -> str:
path = reverse("web:order", kwargs={"uuid": order.uuid})
return f"{settings.REDSYS_TPV_DOMAIN}{path}"
return f"{self.settings.tpv_domain}{path}"
def to_integer(self, value: Decimal):
return int(value * 100)
def get_merchant_url_ko_for_order(self, order: Order) -> str:
path = reverse("web:order", kwargs={"uuid": order.uuid})
return f"{settings.REDSYS_TPV_DOMAIN}{path}"
return f"{self.settings.tpv_domain}{path}"
def get_webhook_url_for_order(self, order: Order) -> str:
path = reverse("shop:webhook", kwargs={"uuid": order.uuid})
return f"{settings.REDSYS_TPV_DOMAIN}{path}"
return f"{self.settings.tpv_domain}{path}"
def get_shared_secret(self) -> str:
return settings.REDSYS_SHARED_SECRET
return self.settings.shared_secret
def get_signature(self, hash, payload: str):
key = self.get_shared_secret()
-1
View File
@@ -1,5 +1,4 @@
from django.core.signals import Signal
clear_cart = Signal()
send_order_email = Signal()
+9 -9
View File
@@ -2,14 +2,13 @@ import base64
import json
from decimal import Decimal
from django.conf import settings
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 shop.models import CustomerAddress, Order, Tax
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
@@ -26,7 +25,7 @@ class TestRedsysTPV(APITestCase, CreateProductsMixin):
self.customer = get_user_model().objects.create_user(
username="11111111H",
first_name="Darth",
last_name="Maull",
last_name="Maul",
email="darth@maul.com",
password="dathomir",
)
@@ -53,6 +52,9 @@ class TestRedsysTPV(APITestCase, CreateProductsMixin):
self.product = self.create_product()
self.order = self.create_order()
self.order.calculate_total_from_lines()
self.settings = ShopSettings.load()
self.settings.shared_secret = "sq7HjrUOBfKmC576ILgskD5srU870gJ7" # Debug secret
self.settings.save()
def create_order(self):
order = create_order(
@@ -83,12 +85,10 @@ class TestRedsysTPV(APITestCase, CreateProductsMixin):
assert merchant_parameters.get("DS_MERCHANT_AMOUNT") == str(
int(amount_to_pay * 100)
)
assert (
merchant_parameters.get("DS_MERCHANT_TERMINAL") == settings.REDSYS_TERMINAL
)
assert merchant_parameters.get("DS_MERCHANT_TERMINAL") == self.settings.terminal
assert (
merchant_parameters.get("DS_MERCHANT_MERCHANTCODE")
== settings.REDSYS_MERCHANT_CODE
== self.settings.merchant_code
)
client.get_body_for_order(self.order)
@@ -124,7 +124,7 @@ class TestRedsysTPV(APITestCase, CreateProductsMixin):
reverse("shop:webhook", kwargs={"uuid": self.order.uuid}),
data={
"Ds_MerchantParameters": b64_merchant_params,
"Ds_Signature": settings.REDSYS_SHARED_SECRET,
"Ds_Signature": self.settings.shared_secret,
"Ds_SignatureVersion": "HMAC_SHA256_V1",
},
)
@@ -164,7 +164,7 @@ class TestRedsysTPV(APITestCase, CreateProductsMixin):
reverse("shop:webhook", kwargs={"uuid": self.order.uuid}),
data={
"Ds_MerchantParameters": b64_merchant_params,
"Ds_Signature": settings.REDSYS_SHARED_SECRET,
"Ds_Signature": self.settings.shared_secret,
"Ds_SignatureVersion": "HMAC_SHA256_V1",
},
)
+1 -1
View File
@@ -3,7 +3,7 @@ from django.shortcuts import get_object_or_404
from django.views.decorators.csrf import csrf_exempt
from shop.models import Order
from shop.utils import validate_payment_for_order, pay_order
from shop.utils import pay_order, validate_payment_for_order
@csrf_exempt
+1 -2
View File
@@ -20,7 +20,6 @@
{% endblock %}
</main>
</body>
<script src="{% static 'theme/js/theme.js' %}"></script>
</body>
</html>
+3 -4
View File
@@ -1,5 +1,4 @@
<svg class="h-4 w-4 text-yellow-400" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
fill="currentColor" viewBox="0 0 24 24">
<path
d="M13.8 4.2a2 2 0 0 0-3.6 0L8.4 8.4l-4.6.3a2 2 0 0 0-1.1 3.5l3.5 3-1 4.4c-.5 1.7 1.4 3 2.9 2.1l3.9-2.3 3.9 2.3c1.5 1 3.4-.4 3-2.1l-1-4.4 3.4-3a2 2 0 0 0-1.1-3.5l-4.6-.3-1.8-4.2Z"/>
<svg class="h-4 w-4" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
fill="#CFCA00" viewBox="0 0 24 24">
<path d="M13.8 4.2a2 2 0 0 0-3.6 0L8.4 8.4l-4.6.3a2 2 0 0 0-1.1 3.5l3.5 3-1 4.4c-.5 1.7 1.4 3 2.9 2.1l3.9-2.3 3.9 2.3c1.5 1 3.4-.4 3-2.1l-1-4.4 3.4-3a2 2 0 0 0-1.1-3.5l-4.6-.3-1.8-4.2Z" />
</svg>

Before

Width:  |  Height:  |  Size: 347 B

After

Width:  |  Height:  |  Size: 315 B

@@ -0,0 +1,5 @@
<svg class="h-4 w-4" aria-hidden="true" xmlns="http://www.w3.org/2000/svg"
fill="#101010" viewBox="0 0 24 24">
<path
d="M13.8 4.2a2 2 0 0 0-3.6 0L8.4 8.4l-4.6.3a2 2 0 0 0-1.1 3.5l3.5 3-1 4.4c-.5 1.7 1.4 3 2.9 2.1l3.9-2.3 3.9 2.3c1.5 1 3.4-.4 3-2.1l-1-4.4 3.4-3a2 2 0 0 0-1.1-3.5l-4.6-.3-1.8-4.2Z"/>
</svg>

After

Width:  |  Height:  |  Size: 326 B

+2
View File
@@ -80,7 +80,9 @@ class MyAccountView(TemplateView):
def get_context_data(self, **kwargs):
addresses = CustomerAddress.objects.filter(user=self.request.user)
settings = WebSettings.load()
return {
"web_title": settings.web_title,
"customer_addresses": addresses,
}
+19 -11
View File
@@ -1,3 +1,5 @@
from decimal import Decimal
from django.db.models import Sum
from django.http.response import HttpResponse, JsonResponse
from django.shortcuts import get_object_or_404, redirect, reverse
@@ -79,7 +81,7 @@ class CartDetail(TemplateView, CreateView):
return {
"cart": cart,
"items": cart_items,
"title": web_settings.web_title,
"web_title": web_settings.web_title,
"description": _("resumen del carrito"),
}
@@ -148,15 +150,21 @@ class OrderDetail(TemplateView):
items = OrderLine.objects.select_related("product").filter(
order=order, product__is_shipping_method=False
)
shipping_cost = (
OrderLine.objects.select_related("product")
.filter(
shipping_cost = OrderLine.objects.select_related("product").filter(
order=order,
product__is_shipping_method=True,
)
.aggregate(amount=Sum("total"))
.get("amount")
)
).aggregate(amount=Sum("total")).get("amount") or Decimal("0")
base_total = OrderLine.objects.select_related("product").filter(
order=order,
product__is_shipping_method=False,
).aggregate(amount=Sum("base_total")).get("amount") or Decimal("0")
tax_total = OrderLine.objects.select_related("product").filter(
order=order,
product__is_shipping_method=False,
).aggregate(amount=Sum("taxes")).get("amount") or Decimal("0")
return {
"order": order,
@@ -165,9 +173,9 @@ class OrderDetail(TemplateView):
"merchant_parameters": parameters.get("Ds_MerchantParameters"),
"signature": parameters.get("Ds_Signature"),
"redsys_target_url": redsys_client.get_target_url(),
"total": order.total,
"base_total": order.base_total,
"tax_total": order.total - order.base_total,
"total": round(order.total, 2),
"base_total": round(base_total, 2),
"tax_total": round(tax_total, 2),
"shipping_cost": round(shipping_cost, 2),
}