feat: lots of stuff
This commit is contained in:
@@ -0,0 +1,22 @@
|
|||||||
|
name: CI
|
||||||
|
on: [push]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ci:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
python-version: ["3.9", "3.10", "3.11"]
|
||||||
|
os: [ubuntu-20.04]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.python-version }}
|
||||||
|
- name: Setup dependencies
|
||||||
|
run: pip install -r requirements.test.txt
|
||||||
|
- name: Run tests
|
||||||
|
env:
|
||||||
|
DJANGO_SETTINGS_MODULE: config.settings.develop
|
||||||
|
run: pytest --cov && coverage xml
|
||||||
@@ -1,11 +1,69 @@
|
|||||||
# Django Template
|
# Shop
|
||||||
|
|
||||||
## How to use the template?
|
## Desarrollo
|
||||||
|
|
||||||
Just run this, changing the project name:
|
### Establecer variables de entorno
|
||||||
|
|
||||||
|
A partir del archivo `.env.example`, creamos un archivo `.env` en el que podemos establecer las
|
||||||
|
[variables de entorno](#variables-de-entorno).
|
||||||
|
|
||||||
|
### Instalar dependencias
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
django-admin startproject --template=https://github.com/pablo-moreno/django-template/archive/refs/heads/main.zip <project name>
|
pip install -r requirements.test.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
- Django's extensions already installed (such as the beautiful shell plus)
|
### Lanzar migraciones
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python manage.py migrate
|
||||||
|
```
|
||||||
|
|
||||||
|
### Arrancar servidor
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python manage.py runserver
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tareas de Celery
|
||||||
|
|
||||||
|
```bash
|
||||||
|
celery -A config worker -B -l debug
|
||||||
|
```
|
||||||
|
|
||||||
|
### Pruebas con pytest
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pytest --cov
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Variables de entorno
|
||||||
|
|
||||||
|
Puedes crear un archivo `.env` con las siguientes variables de entorno.
|
||||||
|
|
||||||
|
| Variable | Default value | Comments |
|
||||||
|
|-------------------------|----------------------------------|--------------------------------------------|
|
||||||
|
| SECRET_KEY | secret key | Clave de encriptación |
|
||||||
|
| DEBUG | TRUE | Modo de desarrollo activo |
|
||||||
|
| DATABASE_URL | sqlite:///db.sqlite3 | URL de conexión a base de datos |
|
||||||
|
| STATIC_ROOT | static | Carpeta de estáticos |
|
||||||
|
| MEDIA_ROOT | media | Carpeta de archivos media |
|
||||||
|
| REDIS_HOST | redis | Dirección de servidor Redis |
|
||||||
|
| REDIS_PORT | 6379 | Puerto de Redis |
|
||||||
|
| PAGE_SIZE | 20 | Tamaño de paginación |
|
||||||
|
| ALLOWED_HOSTS | * | Hosts permitidos (CORS) |
|
||||||
|
| CELERY_BROKER_URL | redis://172.17.0.1:6379/0 | Url de conexión para celery |
|
||||||
|
| S3_ENABLED | FALSE | Activado protocolo S3 |
|
||||||
|
| S3_HOST | | URL de servidor S3 |
|
||||||
|
| AWS_ACCESS_KEY_ID | | Clave de acceso de S3 |
|
||||||
|
| 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 |
|
||||||
|
|
||||||
|
|||||||
@@ -177,14 +177,3 @@ SPECTACULAR_SETTINGS = {
|
|||||||
CELERY_BROKER_URL = env.str("CELERY_BROKER_URL", default="redis://172.17.0.1:6379/0")
|
CELERY_BROKER_URL = env.str("CELERY_BROKER_URL", default="redis://172.17.0.1:6379/0")
|
||||||
CELERY_TIME_ZONE = TIME_ZONE
|
CELERY_TIME_ZONE = TIME_ZONE
|
||||||
CELERY_ALWAYS_EAGER = DEBUG
|
CELERY_ALWAYS_EAGER = DEBUG
|
||||||
|
|
||||||
# Redsys
|
|
||||||
# https://pagosonline.redsys.es/conexion-redireccion.html
|
|
||||||
|
|
||||||
REDSYS_SHARED_SECRET = env.str(
|
|
||||||
"REDSYS_SHARED_SECRET", "sq7HjrUOBfKmC576ILgskD5srU870gJ7"
|
|
||||||
)
|
|
||||||
REDSYS_MERCHANT_CODE = env.str("REDSYS_MERCHANT_CODE", "999008881")
|
|
||||||
REDSYS_TERMINAL = env.str("REDSYS_TERMINAL", "001")
|
|
||||||
REDSYS_CURRENCY_CODE = env.str("REDSYS_CURRENCY_CODE", "978")
|
|
||||||
REDSYS_TPV_DOMAIN = env.str("REDSYS_TPV_DOMAIN", "")
|
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ REDIS_PORT = env.str("REDIS_PORT", 6379)
|
|||||||
PAGE_SIZE = env.int("PAGE_SIZE", 20)
|
PAGE_SIZE = env.int("PAGE_SIZE", 20)
|
||||||
ALLOWED_HOSTS = env.str("ALLOWED_HOSTS", "*").split(",")
|
ALLOWED_HOSTS = env.str("ALLOWED_HOSTS", "*").split(",")
|
||||||
|
|
||||||
|
CELERY_BROKER_URL = env.str("CELERY_BROKER_URL", default="redis://172.17.0.1:6379/0")
|
||||||
|
|
||||||
S3_ENABLED = env.bool("S3_ENABLED", False)
|
S3_ENABLED = env.bool("S3_ENABLED", False)
|
||||||
|
|
||||||
AWS_S3_HOST = env.str("S3_HOST", "")
|
AWS_S3_HOST = env.str("S3_HOST", "")
|
||||||
@@ -32,3 +34,14 @@ AWS_ACCESS_KEY_ID = env.str("S3_ACCESS_KEY_ID", "")
|
|||||||
AWS_SECRET_ACCESS_KEY = env.str("S3_SECRET_ACCESS_KEY", "")
|
AWS_SECRET_ACCESS_KEY = env.str("S3_SECRET_ACCESS_KEY", "")
|
||||||
AWS_STORAGE_BUCKET_NAME = env.str("S3_STORAGE_BUCKET_NAME", "")
|
AWS_STORAGE_BUCKET_NAME = env.str("S3_STORAGE_BUCKET_NAME", "")
|
||||||
AWS_S3_ENDPOINT_URL = env.str("S3_ENDPOINT_URL", "")
|
AWS_S3_ENDPOINT_URL = env.str("S3_ENDPOINT_URL", "")
|
||||||
|
|
||||||
|
# Redsys
|
||||||
|
# https://pagosonline.redsys.es/conexion-redireccion.html
|
||||||
|
|
||||||
|
REDSYS_SHARED_SECRET = env.str(
|
||||||
|
"REDSYS_SHARED_SECRET", "sq7HjrUOBfKmC576ILgskD5srU870gJ7"
|
||||||
|
)
|
||||||
|
REDSYS_MERCHANT_CODE = env.str("REDSYS_MERCHANT_CODE", "999008881")
|
||||||
|
REDSYS_TERMINAL = env.str("REDSYS_TERMINAL", "001")
|
||||||
|
REDSYS_CURRENCY_CODE = env.str("REDSYS_CURRENCY_CODE", "978")
|
||||||
|
REDSYS_TPV_DOMAIN = env.str("REDSYS_TPV_DOMAIN", "")
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 5.0.3 on 2024-03-24 12:51
|
# Generated by Django 5.0.3 on 2024-03-24 18:23
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
import django.utils.timezone
|
import django.utils.timezone
|
||||||
@@ -13,6 +13,43 @@ class Migration(migrations.Migration):
|
|||||||
dependencies = []
|
dependencies = []
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="Customer",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"vat_id",
|
||||||
|
models.CharField(
|
||||||
|
max_length=32,
|
||||||
|
unique=True,
|
||||||
|
verbose_name="Documento de identidad",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("first_name", models.CharField(max_length=64, verbose_name="Nombre")),
|
||||||
|
(
|
||||||
|
"last_name",
|
||||||
|
models.CharField(max_length=64, verbose_name="Apellidos"),
|
||||||
|
),
|
||||||
|
("email", models.EmailField(max_length=254, verbose_name="E-mail")),
|
||||||
|
("address", models.CharField(max_length=255, verbose_name="Dirección")),
|
||||||
|
("city", models.CharField(max_length=64, verbose_name="Ciudad")),
|
||||||
|
("state", models.CharField(max_length=64, verbose_name="Región")),
|
||||||
|
("country", models.CharField(max_length=64, verbose_name="País")),
|
||||||
|
("zip", models.CharField(max_length=32, verbose_name="Código postal")),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "Cliente",
|
||||||
|
"verbose_name_plural": "Clientes",
|
||||||
|
},
|
||||||
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name="OrderLine",
|
name="OrderLine",
|
||||||
fields=[
|
fields=[
|
||||||
@@ -189,6 +226,68 @@ class Migration(migrations.Migration):
|
|||||||
verbose_name="Total",
|
verbose_name="Total",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
"billing_address",
|
||||||
|
models.CharField(
|
||||||
|
max_length=255, verbose_name="Dirección de facturación"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"billing_city",
|
||||||
|
models.CharField(
|
||||||
|
max_length=64, verbose_name="Ciudad de facturación"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"billing_state",
|
||||||
|
models.CharField(
|
||||||
|
max_length=64, verbose_name="Región de facturación"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"billing_country",
|
||||||
|
models.CharField(max_length=64, verbose_name="País de facturación"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"billing_zip",
|
||||||
|
models.CharField(
|
||||||
|
max_length=32, verbose_name="Código postal de facturación"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"shipping_address",
|
||||||
|
models.CharField(max_length=255, verbose_name="Dirección"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"shipping_city",
|
||||||
|
models.CharField(max_length=64, verbose_name="Ciudad"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"shipping_state",
|
||||||
|
models.CharField(max_length=64, verbose_name="Región"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"shipping_country",
|
||||||
|
models.CharField(max_length=64, verbose_name="País"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"shipping_zip",
|
||||||
|
models.CharField(max_length=32, verbose_name="Código postal"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"contact_phone",
|
||||||
|
models.CharField(
|
||||||
|
blank=True, max_length=32, verbose_name="Teléfono de contacto"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"customer",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.PROTECT,
|
||||||
|
to="shop.customer",
|
||||||
|
verbose_name="Cliente",
|
||||||
|
),
|
||||||
|
),
|
||||||
(
|
(
|
||||||
"lines",
|
"lines",
|
||||||
models.ManyToManyField(to="shop.orderline", verbose_name="Líneas"),
|
models.ManyToManyField(to="shop.orderline", verbose_name="Líneas"),
|
||||||
|
|||||||
@@ -80,6 +80,33 @@ class Tax(models.Model):
|
|||||||
verbose_name_plural = _("Impuestos")
|
verbose_name_plural = _("Impuestos")
|
||||||
|
|
||||||
|
|
||||||
|
class Customer(models.Model):
|
||||||
|
vat_id = models.CharField(
|
||||||
|
max_length=32,
|
||||||
|
blank=False,
|
||||||
|
unique=True,
|
||||||
|
verbose_name=_("Documento de identidad"),
|
||||||
|
)
|
||||||
|
first_name = models.CharField(max_length=64, blank=False, verbose_name=_("Nombre"))
|
||||||
|
last_name = models.CharField(
|
||||||
|
max_length=64, blank=False, verbose_name=_("Apellidos")
|
||||||
|
)
|
||||||
|
email = models.EmailField(blank=False, verbose_name=_("E-mail"))
|
||||||
|
|
||||||
|
address = models.CharField(max_length=255, blank=False, verbose_name=_("Dirección"))
|
||||||
|
city = models.CharField(max_length=64, blank=False, verbose_name=_("Ciudad"))
|
||||||
|
state = models.CharField(max_length=64, blank=False, verbose_name=_("Región"))
|
||||||
|
country = models.CharField(max_length=64, blank=False, verbose_name=_("País"))
|
||||||
|
zip = models.CharField(max_length=32, blank=False, verbose_name=_("Código postal"))
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f"{self.vat_id} - {self.first_name} {self.last_name}"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("Cliente")
|
||||||
|
verbose_name_plural = _("Clientes")
|
||||||
|
|
||||||
|
|
||||||
class OrderLine(models.Model):
|
class OrderLine(models.Model):
|
||||||
product = models.ForeignKey(
|
product = models.ForeignKey(
|
||||||
"shop.Product",
|
"shop.Product",
|
||||||
@@ -154,6 +181,48 @@ class Order(models.Model):
|
|||||||
default=Decimal("0"), max_digits=13, decimal_places=2, verbose_name=_("Total")
|
default=Decimal("0"), max_digits=13, decimal_places=2, verbose_name=_("Total")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Customer reference
|
||||||
|
customer = models.ForeignKey(
|
||||||
|
"shop.Customer", on_delete=models.PROTECT, verbose_name=_("Cliente")
|
||||||
|
)
|
||||||
|
|
||||||
|
# Billing information
|
||||||
|
billing_address = models.CharField(
|
||||||
|
max_length=255, blank=False, verbose_name=_("Dirección de facturación")
|
||||||
|
)
|
||||||
|
billing_city = models.CharField(
|
||||||
|
max_length=64, blank=False, verbose_name=_("Ciudad de facturación")
|
||||||
|
)
|
||||||
|
billing_state = models.CharField(
|
||||||
|
max_length=64, blank=False, verbose_name=_("Región de facturación")
|
||||||
|
)
|
||||||
|
billing_country = models.CharField(
|
||||||
|
max_length=64, blank=False, verbose_name=_("País de facturación")
|
||||||
|
)
|
||||||
|
billing_zip = models.CharField(
|
||||||
|
max_length=32, blank=False, verbose_name=_("Código postal de facturación")
|
||||||
|
)
|
||||||
|
|
||||||
|
# Shipping information
|
||||||
|
shipping_address = models.CharField(
|
||||||
|
max_length=255, blank=False, verbose_name=_("Dirección")
|
||||||
|
)
|
||||||
|
shipping_city = models.CharField(
|
||||||
|
max_length=64, blank=False, verbose_name=_("Ciudad")
|
||||||
|
)
|
||||||
|
shipping_state = models.CharField(
|
||||||
|
max_length=64, blank=False, verbose_name=_("Región")
|
||||||
|
)
|
||||||
|
shipping_country = models.CharField(
|
||||||
|
max_length=64, blank=False, verbose_name=_("País")
|
||||||
|
)
|
||||||
|
shipping_zip = models.CharField(
|
||||||
|
max_length=32, blank=False, verbose_name=_("Código postal")
|
||||||
|
)
|
||||||
|
contact_phone = models.CharField(
|
||||||
|
max_length=32, blank=True, verbose_name=_("Teléfono de contacto")
|
||||||
|
)
|
||||||
|
|
||||||
def calculate_total_from_lines(self):
|
def calculate_total_from_lines(self):
|
||||||
self.base_total = self.lines.aggregate(base_total=models.Sum("base_total")).get(
|
self.base_total = self.lines.aggregate(base_total=models.Sum("base_total")).get(
|
||||||
"base_total"
|
"base_total"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from rest_framework.test import APITestCase as TestCase
|
from rest_framework.test import APITestCase as TestCase
|
||||||
from shop.models import Product, ProductPrice, OrderLine, Tax
|
from shop.models import Product, ProductPrice, OrderLine, Tax, Customer
|
||||||
from shop.utils import create_order_line_for_product, create_order
|
from shop.utils import create_order_line_for_product, create_order
|
||||||
|
|
||||||
|
|
||||||
@@ -34,6 +34,17 @@ class ShopModelsTest(TestCase):
|
|||||||
ProductPrice.objects.create(product=self.usb_c, price=Decimal("9.95"))
|
ProductPrice.objects.create(product=self.usb_c, price=Decimal("9.95"))
|
||||||
|
|
||||||
def test_create_order(self):
|
def test_create_order(self):
|
||||||
|
self.customer = Customer.objects.create(
|
||||||
|
first_name='Luke',
|
||||||
|
last_name='Skywalker',
|
||||||
|
vat_id='11111111H',
|
||||||
|
address='Farm Skywalker',
|
||||||
|
city='Desert',
|
||||||
|
state='Mos-Eisley',
|
||||||
|
zip='00001',
|
||||||
|
country='Tatooine',
|
||||||
|
)
|
||||||
|
|
||||||
l1 = create_order_line_for_product(
|
l1 = create_order_line_for_product(
|
||||||
self.potatoes,
|
self.potatoes,
|
||||||
quantity=Decimal("1.5"),
|
quantity=Decimal("1.5"),
|
||||||
@@ -50,7 +61,15 @@ class ShopModelsTest(TestCase):
|
|||||||
tax=self.tax,
|
tax=self.tax,
|
||||||
)
|
)
|
||||||
|
|
||||||
order = create_order(OrderLine.objects.all())
|
order = create_order(
|
||||||
|
customer=self.customer,
|
||||||
|
lines=OrderLine.objects.all(),
|
||||||
|
billing_address=self.customer.address,
|
||||||
|
billing_city=self.customer.city,
|
||||||
|
billing_state=self.customer.state,
|
||||||
|
billing_zip=self.customer.zip,
|
||||||
|
billing_country=self.customer.country,
|
||||||
|
)
|
||||||
|
|
||||||
assert order.total == l1.total + l2.total + l3.total
|
assert order.total == l1.total + l2.total + l3.total
|
||||||
assert order.base_total == l1.base_total + l2.base_total + l3.base_total
|
assert order.base_total == l1.base_total + l2.base_total + l3.base_total
|
||||||
|
|||||||
+47
-4
@@ -1,5 +1,7 @@
|
|||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from shop.models import OrderLine, Tax, Product, Order
|
from typing import Iterable
|
||||||
|
|
||||||
|
from shop.models import OrderLine, Tax, Product, Order, Customer
|
||||||
from django.db.models import QuerySet
|
from django.db.models import QuerySet
|
||||||
|
|
||||||
|
|
||||||
@@ -19,10 +21,51 @@ def create_order_line_for_product(product: Product, quantity: Decimal, tax: Tax)
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def create_order(lines: QuerySet):
|
def create_order(
|
||||||
order = Order.objects.create()
|
customer: Customer,
|
||||||
|
lines: Iterable,
|
||||||
|
|
||||||
for line in lines.all():
|
billing_address: str,
|
||||||
|
billing_city: str,
|
||||||
|
billing_state: str,
|
||||||
|
billing_country: str,
|
||||||
|
billing_zip: str,
|
||||||
|
|
||||||
|
shipping_address: str = '',
|
||||||
|
shipping_city: str = '',
|
||||||
|
shipping_state: str = '',
|
||||||
|
shipping_country: str = '',
|
||||||
|
shipping_zip: str = '',
|
||||||
|
) -> Order:
|
||||||
|
billing_address = billing_address if billing_address else customer.address
|
||||||
|
billing_city = billing_city if billing_city else customer.city
|
||||||
|
billing_state = billing_state if billing_state else customer.state
|
||||||
|
billing_country = billing_country if billing_country else customer.country
|
||||||
|
billing_zip = billing_zip if billing_zip else customer.zip
|
||||||
|
|
||||||
|
shipping_address = shipping_address if shipping_address else billing_address
|
||||||
|
shipping_city = shipping_city if shipping_city else billing_city
|
||||||
|
shipping_state = shipping_state if shipping_state else billing_state
|
||||||
|
shipping_country = shipping_country if shipping_country else billing_country
|
||||||
|
shipping_zip = shipping_zip if shipping_zip else billing_zip
|
||||||
|
|
||||||
|
order = Order.objects.create(
|
||||||
|
customer=customer,
|
||||||
|
|
||||||
|
billing_address=billing_address,
|
||||||
|
billing_city=billing_city,
|
||||||
|
billing_state=billing_state,
|
||||||
|
billing_country=billing_country,
|
||||||
|
billing_zip=billing_zip,
|
||||||
|
|
||||||
|
shipping_address=shipping_address,
|
||||||
|
shipping_city=shipping_city,
|
||||||
|
shipping_state=shipping_state,
|
||||||
|
shipping_country=shipping_country,
|
||||||
|
shipping_zip=shipping_zip,
|
||||||
|
)
|
||||||
|
|
||||||
|
for line in lines:
|
||||||
order.lines.add(line)
|
order.lines.add(line)
|
||||||
|
|
||||||
order.calculate_total_from_lines()
|
order.calculate_total_from_lines()
|
||||||
|
|||||||
@@ -104,6 +104,11 @@ class TestRedsysTPV(APITestCase):
|
|||||||
|
|
||||||
assert response.status_code == status.HTTP_200_OK
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
|
||||||
|
response = self.client.get(
|
||||||
|
reverse("tpv:ok", kwargs={"order": order.hash})
|
||||||
|
)
|
||||||
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
|
||||||
def test_redsys_webhook_payment_error(self):
|
def test_redsys_webhook_payment_error(self):
|
||||||
amount_to_pay = Decimal("10.00")
|
amount_to_pay = Decimal("10.00")
|
||||||
order = PaymentTPV.objects.create(amount=amount_to_pay)
|
order = PaymentTPV.objects.create(amount=amount_to_pay)
|
||||||
@@ -167,3 +172,8 @@ class TestRedsysTPV(APITestCase):
|
|||||||
order.refresh_from_db()
|
order.refresh_from_db()
|
||||||
assert str(ERROR_CODES.get("0184")) in order.observations
|
assert str(ERROR_CODES.get("0184")) in order.observations
|
||||||
assert order.status == PaymentTPV.StatusChoices.ERROR
|
assert order.status == PaymentTPV.StatusChoices.ERROR
|
||||||
|
|
||||||
|
response = self.client.get(
|
||||||
|
reverse("tpv:ko", kwargs={"order": order.hash})
|
||||||
|
)
|
||||||
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
|||||||
+14
-51
@@ -13,10 +13,6 @@ from tpv.signals import redsys_payment_accepted, redsys_payment_rejected
|
|||||||
def payment_accepted(request, order):
|
def payment_accepted(request, order):
|
||||||
order = get_object_or_404(PaymentTPV, hash=order)
|
order = get_object_or_404(PaymentTPV, hash=order)
|
||||||
|
|
||||||
# Ñapa histórica
|
|
||||||
if request.GET:
|
|
||||||
return redirect(reverse("tpv:ok", kwargs={"order": order.hash}))
|
|
||||||
|
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
template_name="tpv/order_created.html",
|
template_name="tpv/order_created.html",
|
||||||
@@ -29,13 +25,9 @@ def payment_accepted(request, order):
|
|||||||
def payment_rejected(request, order):
|
def payment_rejected(request, order):
|
||||||
order = get_object_or_404(PaymentTPV, hash=order)
|
order = get_object_or_404(PaymentTPV, hash=order)
|
||||||
|
|
||||||
# Ñapa histórica
|
|
||||||
if request.GET:
|
|
||||||
return redirect(reverse("tpv:ko", kwargs={"order": order.hash}))
|
|
||||||
|
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
template_name="tpv/order.html",
|
template_name="tpv/order_created.html",
|
||||||
context={
|
context={
|
||||||
"order": order,
|
"order": order,
|
||||||
},
|
},
|
||||||
@@ -67,45 +59,16 @@ def order_created(request, order):
|
|||||||
client = RedsysClient()
|
client = RedsysClient()
|
||||||
parameters = client.get_body_for_order(order)
|
parameters = client.get_body_for_order(order)
|
||||||
|
|
||||||
if request.method == "GET":
|
return render(
|
||||||
return render(
|
request,
|
||||||
request,
|
template_name="tpv/order_created.html",
|
||||||
template_name="tpv/order_created.html",
|
context={
|
||||||
context={
|
"form": UpdateEmailForm({"contact_email": order.contact_email}),
|
||||||
"form": UpdateEmailForm({"contact_email": order.contact_email}),
|
"action": reverse("tpv:order_created", kwargs={"order": order.hash}),
|
||||||
"action": reverse("tpv:order_created", kwargs={"order": order.hash}),
|
"order": order,
|
||||||
"order": order,
|
"signature_version": parameters.get("Ds_SignatureVersion"),
|
||||||
"signature_version": parameters.get("Ds_SignatureVersion"),
|
"merchant_parameters": parameters.get("Ds_MerchantParameters"),
|
||||||
"merchant_parameters": parameters.get("Ds_MerchantParameters"),
|
"signature": parameters.get("Ds_Signature"),
|
||||||
"signature": parameters.get("Ds_Signature"),
|
"redsys_target_url": client.get_target_url(),
|
||||||
"redsys_target_url": client.get_target_url(),
|
},
|
||||||
},
|
)
|
||||||
)
|
|
||||||
|
|
||||||
elif request.method == "POST":
|
|
||||||
form = UpdateEmailForm(request.POST)
|
|
||||||
|
|
||||||
if form.is_valid():
|
|
||||||
order.contact_email = form.cleaned_data["contact_email"]
|
|
||||||
order.save()
|
|
||||||
|
|
||||||
return redirect(reverse("tpv:order_created", kwargs={"order": order.hash}))
|
|
||||||
else:
|
|
||||||
return render(
|
|
||||||
request,
|
|
||||||
template_name="tpv/order_created.html",
|
|
||||||
context={
|
|
||||||
"form": UpdateEmailForm({"contact_email": ""}),
|
|
||||||
"errors": form.errors,
|
|
||||||
"action": reverse(
|
|
||||||
"tpv:order_created", kwargs={"order": order.hash}
|
|
||||||
),
|
|
||||||
"order": order,
|
|
||||||
"signature_version": parameters.get("Ds_SignatureVersion"),
|
|
||||||
"merchant_parameters": parameters.get("Ds_MerchantParameters"),
|
|
||||||
"signature": parameters.get("Ds_Signature"),
|
|
||||||
"redsys_target_url": client.get_target_url(),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
return HttpResponse(status=405)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user