feat: reset migrations and created customer address model

This commit is contained in:
2024-12-07 10:10:14 +01:00
parent 1ffa5b117f
commit 48d39f55ba
18 changed files with 863 additions and 908 deletions
+1
View File
@@ -55,3 +55,4 @@ REDSYS_CURRENCY_CODE = env.str("REDSYS_CURRENCY_CODE", "978")
REDSYS_TPV_DOMAIN = env.str("REDSYS_TPV_DOMAIN", "") REDSYS_TPV_DOMAIN = env.str("REDSYS_TPV_DOMAIN", "")
ITEMS_PER_PAGE = env.int("ITEMS_PER_PAGE", 20) ITEMS_PER_PAGE = env.int("ITEMS_PER_PAGE", 20)
SHOP_COUNTRY = env.str("SHOP_COUNTRY", "ESPAÑA")
+1 -1
View File
@@ -228,7 +228,7 @@ class OrderSerializer(serializers.ModelSerializer):
"last_modification_date", "last_modification_date",
"base_total", "base_total",
"total", "total",
"customer", "user",
"billing_address", "billing_address",
"billing_city", "billing_city",
"billing_state", "billing_state",
+263 -90
View File
@@ -1,10 +1,10 @@
# Generated by Django 5.0.6 on 2024-05-21 17:19 # Generated by Django 5.1.3 on 2024-12-07 08:59
import uuid
from decimal import Decimal
import django.db.models.deletion import django.db.models.deletion
import django.utils.timezone import django.utils.timezone
import uuid
from decimal import Decimal
from django.conf import settings
from django.db import migrations, models from django.db import migrations, models
@@ -14,6 +14,7 @@ class Migration(migrations.Migration):
dependencies = [ dependencies = [
("files", "0001_initial"), ("files", "0001_initial"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
] ]
operations = [ operations = [
@@ -32,19 +33,19 @@ class Migration(migrations.Migration):
( (
"creation_date", "creation_date",
models.DateTimeField( models.DateTimeField(
auto_now_add=True, verbose_name="Fecha de creación" auto_now_add=True, verbose_name="fecha de creación"
), ),
), ),
( (
"last_modification_date", "last_modification_date",
models.DateTimeField( models.DateTimeField(
auto_now=True, verbose_name="Fecha de última modificación" auto_now=True, verbose_name="fecha de última modificación"
), ),
), ),
( (
"name", "name",
models.CharField( models.CharField(
max_length=100, unique=True, verbose_name="Nombre" max_length=100, unique=True, verbose_name="nombre"
), ),
), ),
], ],
@@ -68,13 +69,13 @@ class Migration(migrations.Migration):
( (
"creation_date", "creation_date",
models.DateTimeField( models.DateTimeField(
auto_now_add=True, verbose_name="Fecha de creación" auto_now_add=True, verbose_name="fecha de creación"
), ),
), ),
( (
"last_modification_date", "last_modification_date",
models.DateTimeField( models.DateTimeField(
auto_now=True, verbose_name="Fecha de última modificación" auto_now=True, verbose_name="fecha de última modificación"
), ),
), ),
( (
@@ -82,20 +83,20 @@ class Migration(migrations.Migration):
models.CharField( models.CharField(
max_length=32, max_length=32,
unique=True, unique=True,
verbose_name="Documento de identidad", verbose_name="documento de identidad",
), ),
), ),
("first_name", models.CharField(max_length=64, verbose_name="Nombre")), ("first_name", models.CharField(max_length=64, verbose_name="nombre")),
( (
"last_name", "last_name",
models.CharField(max_length=64, verbose_name="Apellidos"), models.CharField(max_length=64, verbose_name="apellidos"),
), ),
("email", models.EmailField(max_length=254, verbose_name="E-mail")), ("email", models.EmailField(max_length=254, verbose_name="e-mail")),
("address", models.CharField(max_length=255, verbose_name="Dirección")), ("address", models.CharField(max_length=255, verbose_name="dirección")),
("city", models.CharField(max_length=64, verbose_name="Ciudad")), ("city", models.CharField(max_length=64, verbose_name="ciudad")),
("state", models.CharField(max_length=64, verbose_name="Región")), ("state", models.CharField(max_length=64, verbose_name="región")),
("country", models.CharField(max_length=64, verbose_name="País")), ("country", models.CharField(max_length=64, verbose_name="país")),
("zip", models.CharField(max_length=32, verbose_name="Código postal")), ("zip", models.CharField(max_length=32, verbose_name="código postal")),
], ],
options={ options={
"verbose_name": "cliente", "verbose_name": "cliente",
@@ -117,13 +118,13 @@ class Migration(migrations.Migration):
( (
"creation_date", "creation_date",
models.DateTimeField( models.DateTimeField(
auto_now_add=True, verbose_name="Fecha de creación" auto_now_add=True, verbose_name="fecha de creación"
), ),
), ),
( (
"last_modification_date", "last_modification_date",
models.DateTimeField( models.DateTimeField(
auto_now=True, verbose_name="Fecha de última modificación" auto_now=True, verbose_name="fecha de última modificación"
), ),
), ),
( (
@@ -131,14 +132,14 @@ class Migration(migrations.Migration):
models.CharField( models.CharField(
max_length=32, max_length=32,
unique=True, unique=True,
verbose_name="Documento de identidad", verbose_name="documento de identidad",
), ),
), ),
("name", models.CharField(max_length=64, verbose_name="Nombre")), ("name", models.CharField(max_length=64, verbose_name="nombre")),
( (
"email", "email",
models.EmailField( models.EmailField(
max_length=254, verbose_name="E-mail de contacto" max_length=254, verbose_name="e-mail de contacto"
), ),
), ),
( (
@@ -151,11 +152,11 @@ class Migration(migrations.Migration):
verbose_name="Teléfono de contacto", verbose_name="Teléfono de contacto",
), ),
), ),
("address", models.CharField(max_length=255, verbose_name="Dirección")), ("address", models.CharField(max_length=255, verbose_name="dirección")),
("city", models.CharField(max_length=64, verbose_name="Ciudad")), ("city", models.CharField(max_length=64, verbose_name="ciudad")),
("state", models.CharField(max_length=64, verbose_name="Región")), ("state", models.CharField(max_length=64, verbose_name="región")),
("country", models.CharField(max_length=64, verbose_name="País")), ("country", models.CharField(max_length=64, verbose_name="país")),
("zip", models.CharField(max_length=32, verbose_name="Código postal")), ("zip", models.CharField(max_length=32, verbose_name="código postal")),
], ],
options={ options={
"verbose_name": "proveedor", "verbose_name": "proveedor",
@@ -197,31 +198,141 @@ class Migration(migrations.Migration):
( (
"creation_date", "creation_date",
models.DateTimeField( models.DateTimeField(
auto_now_add=True, verbose_name="Fecha de creación" auto_now_add=True, verbose_name="fecha de creación"
), ),
), ),
( (
"last_modification_date", "last_modification_date",
models.DateTimeField( models.DateTimeField(
auto_now=True, verbose_name="Fecha de última modificación" auto_now=True, verbose_name="fecha de última modificación"
), ),
), ),
( (
"code", "code",
models.CharField( models.CharField(
max_length=8, unique=True, verbose_name="Código de impuesto" max_length=8, unique=True, verbose_name="código de impuesto"
), ),
), ),
( (
"value", "value",
models.PositiveIntegerField( models.PositiveIntegerField(
verbose_name="Valor entero (porcentaje)" verbose_name="valor entero (porcentaje)"
), ),
), ),
], ],
options={ options={
"verbose_name": "impuesto", "verbose_name": "impuesto",
"verbose_name_plural": "impuestos", "verbose_name_plural": "impuestos",
"ordering": ("id",),
},
),
migrations.CreateModel(
name="Cart",
fields=[
(
"uuid",
models.UUIDField(
default=uuid.uuid4,
primary_key=True,
serialize=False,
verbose_name="uuid",
),
),
(
"creation_date",
models.DateTimeField(
auto_now_add=True, verbose_name="fecha de creación"
),
),
(
"user",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
verbose_name="usuario",
),
),
],
options={
"verbose_name": "carrito",
"verbose_name_plural": "carritos",
},
),
migrations.CreateModel(
name="CustomerAddress",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"vat_id",
models.CharField(
blank=True,
default="",
max_length=16,
null=True,
verbose_name="número de identificación fiscal",
),
),
("address", models.CharField(max_length=128, verbose_name="dirección")),
(
"address_town",
models.CharField(max_length=64, verbose_name="localidad"),
),
(
"address_zip",
models.CharField(max_length=16, verbose_name="código postal"),
),
(
"address_state",
models.CharField(max_length=64, verbose_name="provincia"),
),
(
"address_country",
models.CharField(
default="ESPAÑA", max_length=64, verbose_name="país"
),
),
(
"address_phone",
models.CharField(
blank=True,
default="",
max_length=16,
null=True,
verbose_name="teléfono",
),
),
(
"address_type",
models.CharField(
choices=[("BILL", "facturación"), ("SHIP", "envío")],
default="SHIP",
max_length=4,
verbose_name="tipo de dirección",
),
),
("default", models.BooleanField(default=True)),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
verbose_name="usuario",
),
),
],
options={
"verbose_name": "dirección de cliente",
"verbose_name_plural": "direcciones de cliente",
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
@@ -239,13 +350,13 @@ class Migration(migrations.Migration):
( (
"creation_date", "creation_date",
models.DateTimeField( models.DateTimeField(
auto_now_add=True, verbose_name="Fecha de creación" auto_now_add=True, verbose_name="fecha de creación"
), ),
), ),
( (
"last_modification_date", "last_modification_date",
models.DateTimeField( models.DateTimeField(
auto_now=True, verbose_name="Fecha de última modificación" auto_now=True, verbose_name="fecha de última modificación"
), ),
), ),
( (
@@ -257,7 +368,7 @@ class Migration(migrations.Migration):
( (
"status", "status",
models.CharField( models.CharField(
default="PEN", max_length=3, verbose_name="Estado" default="PEN", max_length=3, verbose_name="estado"
), ),
), ),
( (
@@ -266,7 +377,7 @@ class Migration(migrations.Migration):
decimal_places=2, decimal_places=2,
default=Decimal("0"), default=Decimal("0"),
max_digits=13, max_digits=13,
verbose_name="Base imponible", verbose_name="base imponible",
), ),
), ),
( (
@@ -275,69 +386,69 @@ class Migration(migrations.Migration):
decimal_places=2, decimal_places=2,
default=Decimal("0"), default=Decimal("0"),
max_digits=13, max_digits=13,
verbose_name="Total", verbose_name="total",
), ),
), ),
( (
"billing_address", "billing_address",
models.CharField( models.CharField(
max_length=255, verbose_name="Dirección de facturación" max_length=255, verbose_name="dirección de facturación"
), ),
), ),
( (
"billing_city", "billing_city",
models.CharField( models.CharField(
max_length=64, verbose_name="Ciudad de facturación" max_length=64, verbose_name="ciudad de facturación"
), ),
), ),
( (
"billing_state", "billing_state",
models.CharField( models.CharField(
max_length=64, verbose_name="Región de facturación" max_length=64, verbose_name="región de facturación"
), ),
), ),
( (
"billing_country", "billing_country",
models.CharField(max_length=64, verbose_name="País de facturación"), models.CharField(max_length=64, verbose_name="país de facturación"),
), ),
( (
"billing_zip", "billing_zip",
models.CharField( models.CharField(
max_length=32, verbose_name="Código postal de facturación" max_length=32, verbose_name="código postal de facturación"
), ),
), ),
( (
"shipping_address", "shipping_address",
models.CharField(max_length=255, verbose_name="Dirección"), models.CharField(max_length=255, verbose_name="dirección"),
), ),
( (
"shipping_city", "shipping_city",
models.CharField(max_length=64, verbose_name="Ciudad"), models.CharField(max_length=64, verbose_name="ciudad"),
), ),
( (
"shipping_state", "shipping_state",
models.CharField(max_length=64, verbose_name="Región"), models.CharField(max_length=64, verbose_name="región"),
), ),
( (
"shipping_country", "shipping_country",
models.CharField(max_length=64, verbose_name="País"), models.CharField(max_length=64, verbose_name="país"),
), ),
( (
"shipping_zip", "shipping_zip",
models.CharField(max_length=32, verbose_name="Código postal"), models.CharField(max_length=32, verbose_name="código postal"),
), ),
( (
"contact_phone", "contact_phone",
models.CharField( models.CharField(
blank=True, max_length=32, verbose_name="Teléfono de contacto" blank=True, max_length=32, verbose_name="teléfono de contacto"
), ),
), ),
( (
"customer", "user",
models.ForeignKey( models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT, on_delete=django.db.models.deletion.PROTECT,
to="shop.customer", to=settings.AUTH_USER_MODEL,
verbose_name="Cliente", verbose_name="cliente",
), ),
), ),
], ],
@@ -361,29 +472,26 @@ class Migration(migrations.Migration):
( (
"creation_date", "creation_date",
models.DateTimeField( models.DateTimeField(
auto_now_add=True, verbose_name="Fecha de creación" auto_now_add=True, verbose_name="fecha de creación"
), ),
), ),
( (
"last_modification_date", "last_modification_date",
models.DateTimeField( models.DateTimeField(
auto_now=True, verbose_name="Fecha de última modificación" auto_now=True, verbose_name="fecha de última modificación"
), ),
), ),
( (
"sku", "sku",
models.CharField( models.CharField(
max_length=64, unique=True, verbose_name="Código de referencia" max_length=64, unique=True, verbose_name="código de referencia"
), ),
), ),
("name", models.CharField(max_length=96, verbose_name="Nombre")), ("name", models.CharField(max_length=96, verbose_name="nombre")),
( (
"description", "description",
models.CharField( models.TextField(
blank=True, blank=True, default="", verbose_name="descripción"
default="",
max_length=1000,
verbose_name="Descripción",
), ),
), ),
( (
@@ -392,11 +500,26 @@ class Migration(migrations.Migration):
decimal_places=4, decimal_places=4,
default=Decimal("0"), default=Decimal("0"),
max_digits=13, max_digits=13,
verbose_name="Stock", verbose_name="stock",
),
),
(
"is_digital_asset",
models.BooleanField(
default=False, verbose_name="es un activo digital"
), ),
), ),
("is_digital_asset", models.BooleanField(default=False)),
("url", models.URLField(blank=True, verbose_name="URL de descarga")), ("url", models.URLField(blank=True, verbose_name="URL de descarga")),
(
"slug",
models.SlugField(
blank=True,
default="",
max_length=128,
null=True,
verbose_name="Slug",
),
),
( (
"brand", "brand",
models.ForeignKey( models.ForeignKey(
@@ -404,26 +527,26 @@ class Migration(migrations.Migration):
null=True, null=True,
on_delete=django.db.models.deletion.SET_NULL, on_delete=django.db.models.deletion.SET_NULL,
to="shop.brand", to="shop.brand",
verbose_name="Marca", verbose_name="marca",
), ),
), ),
( (
"images", "images",
models.ManyToManyField( models.ManyToManyField(
blank=True, to="files.fileupload", verbose_name="Imágenes" blank=True, to="files.fileupload", verbose_name="imágenes"
), ),
), ),
( (
"tags", "tags",
models.ManyToManyField( models.ManyToManyField(
blank=True, to="shop.tag", verbose_name="Etiquetas" blank=True, to="shop.tag", verbose_name="etiquetas"
), ),
), ),
], ],
options={ options={
"verbose_name": "producto", "verbose_name": "producto",
"verbose_name_plural": "productos", "verbose_name_plural": "productos",
"ordering": ("-id",), "ordering": ("id",),
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
@@ -441,13 +564,13 @@ class Migration(migrations.Migration):
( (
"creation_date", "creation_date",
models.DateTimeField( models.DateTimeField(
auto_now_add=True, verbose_name="Fecha de creación" auto_now_add=True, verbose_name="fecha de creación"
), ),
), ),
( (
"last_modification_date", "last_modification_date",
models.DateTimeField( models.DateTimeField(
auto_now=True, verbose_name="Fecha de última modificación" auto_now=True, verbose_name="fecha de última modificación"
), ),
), ),
( (
@@ -456,13 +579,13 @@ class Migration(migrations.Migration):
decimal_places=4, decimal_places=4,
default=Decimal("1"), default=Decimal("1"),
max_digits=13, max_digits=13,
verbose_name="Cantidad", verbose_name="cantidad",
), ),
), ),
( (
"price", "price",
models.DecimalField( models.DecimalField(
decimal_places=4, max_digits=13, verbose_name="Precio" decimal_places=4, max_digits=13, verbose_name="precio"
), ),
), ),
( (
@@ -471,23 +594,23 @@ class Migration(migrations.Migration):
decimal_places=4, decimal_places=4,
default=Decimal("0"), default=Decimal("0"),
max_digits=13, max_digits=13,
verbose_name="Total sin impuestos", verbose_name="total sin impuestos",
), ),
), ),
( (
"tax_value", "tax_value",
models.PositiveIntegerField(verbose_name="Valor de impuestos"), models.PositiveIntegerField(verbose_name="valor de impuestos"),
), ),
( (
"taxes", "taxes",
models.DecimalField( models.DecimalField(
decimal_places=4, max_digits=13, verbose_name="Impuestos" decimal_places=4, max_digits=13, verbose_name="impuestos"
), ),
), ),
( (
"total", "total",
models.DecimalField( models.DecimalField(
decimal_places=4, max_digits=13, verbose_name="Total" decimal_places=4, max_digits=13, verbose_name="total"
), ),
), ),
( (
@@ -496,7 +619,7 @@ class Migration(migrations.Migration):
on_delete=django.db.models.deletion.CASCADE, on_delete=django.db.models.deletion.CASCADE,
related_name="lines", related_name="lines",
to="shop.order", to="shop.order",
verbose_name="Pedido", verbose_name="pedido",
), ),
), ),
( (
@@ -504,7 +627,7 @@ class Migration(migrations.Migration):
models.ForeignKey( models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, on_delete=django.db.models.deletion.CASCADE,
to="shop.product", to="shop.product",
verbose_name="Producto", verbose_name="producto",
), ),
), ),
], ],
@@ -513,6 +636,45 @@ class Migration(migrations.Migration):
"verbose_name_plural": "líneas de pedido", "verbose_name_plural": "líneas de pedido",
}, },
), ),
migrations.CreateModel(
name="CartItem",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"quantity",
models.PositiveIntegerField(default=1, verbose_name="cantidad"),
),
(
"cart",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="items",
to="shop.cart",
verbose_name="carrito",
),
),
(
"product",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="shop.product",
verbose_name="producto",
),
),
],
options={
"verbose_name": "línea de carrito",
"verbose_name_plural": "líneas de carrito",
},
),
migrations.CreateModel( migrations.CreateModel(
name="ProductBatch", name="ProductBatch",
fields=[ fields=[
@@ -528,19 +690,19 @@ class Migration(migrations.Migration):
( (
"creation_date", "creation_date",
models.DateTimeField( models.DateTimeField(
auto_now_add=True, verbose_name="Fecha de creación" auto_now_add=True, verbose_name="fecha de creación"
), ),
), ),
( (
"last_modification_date", "last_modification_date",
models.DateTimeField( models.DateTimeField(
auto_now=True, verbose_name="Fecha de última modificación" auto_now=True, verbose_name="fecha de última modificación"
), ),
), ),
( (
"code", "code",
models.CharField( models.CharField(
db_index=True, max_length=32, unique=True, verbose_name="Código" db_index=True, max_length=32, unique=True, verbose_name="código"
), ),
), ),
( (
@@ -549,7 +711,7 @@ class Migration(migrations.Migration):
decimal_places=4, decimal_places=4,
default=Decimal("1"), default=Decimal("1"),
max_digits=13, max_digits=13,
verbose_name="Cantidad", verbose_name="cantidad",
), ),
), ),
( (
@@ -557,7 +719,7 @@ class Migration(migrations.Migration):
models.DateField( models.DateField(
blank=True, blank=True,
null=True, null=True,
verbose_name="Fecha de caducidad / consumo preferente", verbose_name="fecha de caducidad / consumo preferente",
), ),
), ),
( (
@@ -565,7 +727,7 @@ class Migration(migrations.Migration):
models.ForeignKey( models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT, on_delete=django.db.models.deletion.PROTECT,
to="shop.product", to="shop.product",
verbose_name="Producto", verbose_name="producto",
), ),
), ),
( (
@@ -575,7 +737,7 @@ class Migration(migrations.Migration):
null=True, null=True,
on_delete=django.db.models.deletion.SET_NULL, on_delete=django.db.models.deletion.SET_NULL,
to="shop.provider", to="shop.provider",
verbose_name="Proveedor", verbose_name="proveedor",
), ),
), ),
], ],
@@ -599,31 +761,41 @@ class Migration(migrations.Migration):
( (
"creation_date", "creation_date",
models.DateTimeField( models.DateTimeField(
auto_now_add=True, verbose_name="Fecha de creación" auto_now_add=True, verbose_name="fecha de creación"
), ),
), ),
( (
"last_modification_date", "last_modification_date",
models.DateTimeField( models.DateTimeField(
auto_now=True, verbose_name="Fecha de última modificación" auto_now=True, verbose_name="fecha de última modificación"
), ),
), ),
( (
"price", "price",
models.DecimalField( models.DecimalField(
decimal_places=2, max_digits=11, verbose_name="Precio" decimal_places=2, max_digits=11, verbose_name="precio"
), ),
), ),
( (
"date", "date",
models.DateTimeField( models.DateTimeField(
default=django.utils.timezone.now, verbose_name="Fecha" default=django.utils.timezone.now, verbose_name="fecha"
),
),
(
"price_with_tax",
models.DecimalField(
blank=True,
decimal_places=2,
max_digits=11,
null=True,
verbose_name="precio con impuestos",
), ),
), ),
( (
"current", "current",
models.BooleanField( models.BooleanField(
default=False, verbose_name="Es el precio actual" default=False, verbose_name="es el precio actual"
), ),
), ),
( (
@@ -632,7 +804,7 @@ class Migration(migrations.Migration):
on_delete=django.db.models.deletion.CASCADE, on_delete=django.db.models.deletion.CASCADE,
related_name="prices", related_name="prices",
to="shop.product", to="shop.product",
verbose_name="Producto", verbose_name="producto",
), ),
), ),
( (
@@ -640,13 +812,14 @@ class Migration(migrations.Migration):
models.ForeignKey( models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT, on_delete=django.db.models.deletion.PROTECT,
to="shop.tax", to="shop.tax",
verbose_name="Impuesto aplicable", verbose_name="impuesto aplicable",
), ),
), ),
], ],
options={ options={
"verbose_name": "precio de producto", "verbose_name": "precio de producto",
"verbose_name_plural": "precio de producto", "verbose_name_plural": "precio de producto",
"ordering": ("-date",),
}, },
), ),
] ]
@@ -1,34 +0,0 @@
# Generated by Django 5.0.6 on 2024-05-26 11:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("shop", "0001_initial"),
]
operations = [
migrations.AlterModelOptions(
name="productprice",
options={
"ordering": ("-date",),
"verbose_name": "precio de producto",
"verbose_name_plural": "precio de producto",
},
),
migrations.AlterModelOptions(
name="tax",
options={
"ordering": ("id",),
"verbose_name": "impuesto",
"verbose_name_plural": "impuestos",
},
),
migrations.AlterField(
model_name="product",
name="description",
field=models.TextField(blank=True, default="", verbose_name="Descripción"),
),
]
@@ -1,555 +0,0 @@
# Generated by Django 5.0.6 on 2024-06-02 19:47
from decimal import Decimal
import django.db.models.deletion
import django.utils.timezone
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("files", "0001_initial"),
("shop", "0002_alter_productprice_options_alter_tax_options_and_more"),
]
operations = [
migrations.AlterField(
model_name="brand",
name="creation_date",
field=models.DateTimeField(
auto_now_add=True, verbose_name="fecha de creación"
),
),
migrations.AlterField(
model_name="brand",
name="last_modification_date",
field=models.DateTimeField(
auto_now=True, verbose_name="fecha de última modificación"
),
),
migrations.AlterField(
model_name="brand",
name="name",
field=models.CharField(max_length=100, unique=True, verbose_name="nombre"),
),
migrations.AlterField(
model_name="customer",
name="address",
field=models.CharField(max_length=255, verbose_name="dirección"),
),
migrations.AlterField(
model_name="customer",
name="city",
field=models.CharField(max_length=64, verbose_name="ciudad"),
),
migrations.AlterField(
model_name="customer",
name="country",
field=models.CharField(max_length=64, verbose_name="país"),
),
migrations.AlterField(
model_name="customer",
name="creation_date",
field=models.DateTimeField(
auto_now_add=True, verbose_name="fecha de creación"
),
),
migrations.AlterField(
model_name="customer",
name="email",
field=models.EmailField(max_length=254, verbose_name="e-mail"),
),
migrations.AlterField(
model_name="customer",
name="first_name",
field=models.CharField(max_length=64, verbose_name="nombre"),
),
migrations.AlterField(
model_name="customer",
name="last_modification_date",
field=models.DateTimeField(
auto_now=True, verbose_name="fecha de última modificación"
),
),
migrations.AlterField(
model_name="customer",
name="last_name",
field=models.CharField(max_length=64, verbose_name="apellidos"),
),
migrations.AlterField(
model_name="customer",
name="state",
field=models.CharField(max_length=64, verbose_name="región"),
),
migrations.AlterField(
model_name="customer",
name="vat_id",
field=models.CharField(
max_length=32, unique=True, verbose_name="documento de identidad"
),
),
migrations.AlterField(
model_name="customer",
name="zip",
field=models.CharField(max_length=32, verbose_name="código postal"),
),
migrations.AlterField(
model_name="order",
name="base_total",
field=models.DecimalField(
decimal_places=2,
default=Decimal("0"),
max_digits=13,
verbose_name="base imponible",
),
),
migrations.AlterField(
model_name="order",
name="billing_address",
field=models.CharField(
max_length=255, verbose_name="dirección de facturación"
),
),
migrations.AlterField(
model_name="order",
name="billing_city",
field=models.CharField(max_length=64, verbose_name="ciudad de facturación"),
),
migrations.AlterField(
model_name="order",
name="billing_country",
field=models.CharField(max_length=64, verbose_name="país de facturación"),
),
migrations.AlterField(
model_name="order",
name="billing_state",
field=models.CharField(max_length=64, verbose_name="región de facturación"),
),
migrations.AlterField(
model_name="order",
name="billing_zip",
field=models.CharField(
max_length=32, verbose_name="código postal de facturación"
),
),
migrations.AlterField(
model_name="order",
name="contact_phone",
field=models.CharField(
blank=True, max_length=32, verbose_name="teléfono de contacto"
),
),
migrations.AlterField(
model_name="order",
name="creation_date",
field=models.DateTimeField(
auto_now_add=True, verbose_name="fecha de creación"
),
),
migrations.AlterField(
model_name="order",
name="customer",
field=models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
to="shop.customer",
verbose_name="cliente",
),
),
migrations.AlterField(
model_name="order",
name="last_modification_date",
field=models.DateTimeField(
auto_now=True, verbose_name="fecha de última modificación"
),
),
migrations.AlterField(
model_name="order",
name="shipping_address",
field=models.CharField(max_length=255, verbose_name="dirección"),
),
migrations.AlterField(
model_name="order",
name="shipping_city",
field=models.CharField(max_length=64, verbose_name="ciudad"),
),
migrations.AlterField(
model_name="order",
name="shipping_country",
field=models.CharField(max_length=64, verbose_name="país"),
),
migrations.AlterField(
model_name="order",
name="shipping_state",
field=models.CharField(max_length=64, verbose_name="región"),
),
migrations.AlterField(
model_name="order",
name="shipping_zip",
field=models.CharField(max_length=32, verbose_name="código postal"),
),
migrations.AlterField(
model_name="order",
name="status",
field=models.CharField(default="PEN", max_length=3, verbose_name="estado"),
),
migrations.AlterField(
model_name="order",
name="total",
field=models.DecimalField(
decimal_places=2,
default=Decimal("0"),
max_digits=13,
verbose_name="total",
),
),
migrations.AlterField(
model_name="orderline",
name="base_total",
field=models.DecimalField(
decimal_places=4,
default=Decimal("0"),
max_digits=13,
verbose_name="total sin impuestos",
),
),
migrations.AlterField(
model_name="orderline",
name="creation_date",
field=models.DateTimeField(
auto_now_add=True, verbose_name="fecha de creación"
),
),
migrations.AlterField(
model_name="orderline",
name="last_modification_date",
field=models.DateTimeField(
auto_now=True, verbose_name="fecha de última modificación"
),
),
migrations.AlterField(
model_name="orderline",
name="order",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="lines",
to="shop.order",
verbose_name="pedido",
),
),
migrations.AlterField(
model_name="orderline",
name="price",
field=models.DecimalField(
decimal_places=4, max_digits=13, verbose_name="precio"
),
),
migrations.AlterField(
model_name="orderline",
name="product",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="shop.product",
verbose_name="producto",
),
),
migrations.AlterField(
model_name="orderline",
name="quantity",
field=models.DecimalField(
decimal_places=4,
default=Decimal("1"),
max_digits=13,
verbose_name="cantidad",
),
),
migrations.AlterField(
model_name="orderline",
name="tax_value",
field=models.PositiveIntegerField(verbose_name="valor de impuestos"),
),
migrations.AlterField(
model_name="orderline",
name="taxes",
field=models.DecimalField(
decimal_places=4, max_digits=13, verbose_name="impuestos"
),
),
migrations.AlterField(
model_name="orderline",
name="total",
field=models.DecimalField(
decimal_places=4, max_digits=13, verbose_name="total"
),
),
migrations.AlterField(
model_name="product",
name="brand",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="shop.brand",
verbose_name="marca",
),
),
migrations.AlterField(
model_name="product",
name="creation_date",
field=models.DateTimeField(
auto_now_add=True, verbose_name="fecha de creación"
),
),
migrations.AlterField(
model_name="product",
name="description",
field=models.TextField(blank=True, default="", verbose_name="descripción"),
),
migrations.AlterField(
model_name="product",
name="images",
field=models.ManyToManyField(
blank=True, to="files.fileupload", verbose_name="imágenes"
),
),
migrations.AlterField(
model_name="product",
name="is_digital_asset",
field=models.BooleanField(
default=False, verbose_name="es un activo digital"
),
),
migrations.AlterField(
model_name="product",
name="last_modification_date",
field=models.DateTimeField(
auto_now=True, verbose_name="fecha de última modificación"
),
),
migrations.AlterField(
model_name="product",
name="name",
field=models.CharField(max_length=96, verbose_name="nombre"),
),
migrations.AlterField(
model_name="product",
name="sku",
field=models.CharField(
max_length=64, unique=True, verbose_name="código de referencia"
),
),
migrations.AlterField(
model_name="product",
name="stock",
field=models.DecimalField(
decimal_places=4,
default=Decimal("0"),
max_digits=13,
verbose_name="stock",
),
),
migrations.AlterField(
model_name="product",
name="tags",
field=models.ManyToManyField(
blank=True, to="shop.tag", verbose_name="etiquetas"
),
),
migrations.AlterField(
model_name="productbatch",
name="code",
field=models.CharField(
db_index=True, max_length=32, unique=True, verbose_name="código"
),
),
migrations.AlterField(
model_name="productbatch",
name="creation_date",
field=models.DateTimeField(
auto_now_add=True, verbose_name="fecha de creación"
),
),
migrations.AlterField(
model_name="productbatch",
name="expiration_date",
field=models.DateField(
blank=True,
null=True,
verbose_name="fecha de caducidad / consumo preferente",
),
),
migrations.AlterField(
model_name="productbatch",
name="last_modification_date",
field=models.DateTimeField(
auto_now=True, verbose_name="fecha de última modificación"
),
),
migrations.AlterField(
model_name="productbatch",
name="product",
field=models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
to="shop.product",
verbose_name="producto",
),
),
migrations.AlterField(
model_name="productbatch",
name="provider",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="shop.provider",
verbose_name="proveedor",
),
),
migrations.AlterField(
model_name="productbatch",
name="quantity",
field=models.DecimalField(
decimal_places=4,
default=Decimal("1"),
max_digits=13,
verbose_name="cantidad",
),
),
migrations.AlterField(
model_name="productprice",
name="creation_date",
field=models.DateTimeField(
auto_now_add=True, verbose_name="fecha de creación"
),
),
migrations.AlterField(
model_name="productprice",
name="current",
field=models.BooleanField(
default=False, verbose_name="es el precio actual"
),
),
migrations.AlterField(
model_name="productprice",
name="date",
field=models.DateTimeField(
default=django.utils.timezone.now, verbose_name="fecha"
),
),
migrations.AlterField(
model_name="productprice",
name="last_modification_date",
field=models.DateTimeField(
auto_now=True, verbose_name="fecha de última modificación"
),
),
migrations.AlterField(
model_name="productprice",
name="price",
field=models.DecimalField(
decimal_places=2, max_digits=11, verbose_name="precio"
),
),
migrations.AlterField(
model_name="productprice",
name="product",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="prices",
to="shop.product",
verbose_name="producto",
),
),
migrations.AlterField(
model_name="productprice",
name="tax",
field=models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
to="shop.tax",
verbose_name="impuesto aplicable",
),
),
migrations.AlterField(
model_name="provider",
name="address",
field=models.CharField(max_length=255, verbose_name="dirección"),
),
migrations.AlterField(
model_name="provider",
name="city",
field=models.CharField(max_length=64, verbose_name="ciudad"),
),
migrations.AlterField(
model_name="provider",
name="country",
field=models.CharField(max_length=64, verbose_name="país"),
),
migrations.AlterField(
model_name="provider",
name="creation_date",
field=models.DateTimeField(
auto_now_add=True, verbose_name="fecha de creación"
),
),
migrations.AlterField(
model_name="provider",
name="email",
field=models.EmailField(max_length=254, verbose_name="e-mail de contacto"),
),
migrations.AlterField(
model_name="provider",
name="last_modification_date",
field=models.DateTimeField(
auto_now=True, verbose_name="fecha de última modificación"
),
),
migrations.AlterField(
model_name="provider",
name="name",
field=models.CharField(max_length=64, verbose_name="nombre"),
),
migrations.AlterField(
model_name="provider",
name="state",
field=models.CharField(max_length=64, verbose_name="región"),
),
migrations.AlterField(
model_name="provider",
name="vat_id",
field=models.CharField(
max_length=32, unique=True, verbose_name="documento de identidad"
),
),
migrations.AlterField(
model_name="provider",
name="zip",
field=models.CharField(max_length=32, verbose_name="código postal"),
),
migrations.AlterField(
model_name="tax",
name="code",
field=models.CharField(
max_length=8, unique=True, verbose_name="código de impuesto"
),
),
migrations.AlterField(
model_name="tax",
name="creation_date",
field=models.DateTimeField(
auto_now_add=True, verbose_name="fecha de creación"
),
),
migrations.AlterField(
model_name="tax",
name="last_modification_date",
field=models.DateTimeField(
auto_now=True, verbose_name="fecha de última modificación"
),
),
migrations.AlterField(
model_name="tax",
name="value",
field=models.PositiveIntegerField(verbose_name="valor entero (porcentaje)"),
),
]
@@ -1,40 +0,0 @@
# Generated by Django 5.1.3 on 2024-11-22 19:53
from django.db import migrations, models
from django.utils.text import slugify
def add_product_slug(apps, schema_editor):
Product = apps.get_model("shop", "Product")
for product in Product.objects.all():
product.slug = slugify(product.name)[:128]
product.save()
class Migration(migrations.Migration):
dependencies = [
("shop", "0003_alter_brand_creation_date_and_more"),
]
operations = [
migrations.AlterModelOptions(
name="product",
options={
"ordering": ("id",),
"verbose_name": "producto",
"verbose_name_plural": "productos",
},
),
migrations.AddField(
model_name="product",
name="slug",
field=models.SlugField(
blank=True, default="", max_length=128, null=True, verbose_name="Slug"
),
),
migrations.RunPython(
add_product_slug,
),
]
@@ -1,24 +0,0 @@
# Generated by Django 5.1.3 on 2024-11-24 12:26
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("shop", "0004_alter_product_options_product_slug"),
]
operations = [
migrations.AddField(
model_name="productprice",
name="price_with_tax",
field=models.DecimalField(
blank=True,
decimal_places=2,
max_digits=11,
null=True,
verbose_name="precio con impuestos",
),
),
]
-91
View File
@@ -1,91 +0,0 @@
# Generated by Django 5.1.3 on 2024-11-27 12:10
import uuid
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("shop", "0005_productprice_price_with_tax"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name="Cart",
fields=[
(
"uuid",
models.UUIDField(
default=uuid.uuid4,
primary_key=True,
serialize=False,
verbose_name="uuid",
),
),
(
"creation_date",
models.DateTimeField(
auto_now_add=True, verbose_name="fecha de creación"
),
),
(
"user",
models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
verbose_name="usuario",
),
),
],
options={
"verbose_name": "carrito",
"verbose_name_plural": "carritos",
},
),
migrations.CreateModel(
name="CartItem",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"quantity",
models.PositiveIntegerField(default=1, verbose_name="cantidad"),
),
(
"cart",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="items",
to="shop.cart",
verbose_name="carrito",
),
),
(
"product",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="shop.product",
verbose_name="producto",
),
),
],
options={
"verbose_name": "línea de carrito",
"verbose_name_plural": "líneas de carrito",
},
),
]
+45 -3
View File
@@ -1,6 +1,7 @@
from decimal import Decimal from decimal import Decimal
from uuid import uuid4 from uuid import uuid4
from django.conf import settings
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
@@ -346,9 +347,8 @@ class Order(TimestampedModel):
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 user = models.ForeignKey(
customer = models.ForeignKey( User, on_delete=models.PROTECT, verbose_name=_("cliente")
"shop.Customer", on_delete=models.PROTECT, verbose_name=_("cliente")
) )
# Billing information # Billing information
@@ -436,3 +436,45 @@ class CartItem(models.Model):
class Meta: class Meta:
verbose_name = _("línea de carrito") verbose_name = _("línea de carrito")
verbose_name_plural = _("líneas de carrito") verbose_name_plural = _("líneas de carrito")
class CustomerAddress(models.Model):
class Types(models.TextChoices):
BILLING = "BILL", _("facturación")
SHIPPING = "SHIP", _("envío")
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name=_("usuario"))
vat_id = models.CharField(
max_length=16,
blank=True,
null=True,
default="",
verbose_name=_("número de identificación fiscal"),
)
address = models.CharField(
max_length=128, blank=False, null=False, verbose_name=_("dirección")
)
address_town = models.CharField(
max_length=64, blank=False, null=False, verbose_name=_("localidad")
)
address_zip = models.CharField(
max_length=16, blank=False, null=False, verbose_name=_("código postal")
)
address_state = models.CharField(
max_length=64, blank=False, null=False, verbose_name=_("provincia")
)
address_country = models.CharField(
max_length=64, default=settings.SHOP_COUNTRY, blank=False, null=False, verbose_name=_("país")
)
address_phone = models.CharField(
max_length=16, blank=True, null=True, default="", verbose_name=_("teléfono")
)
address_type = models.CharField(
max_length=4, choices=Types.choices, default=Types.SHIPPING, verbose_name=_("tipo de dirección")
)
default = models.BooleanField(default=True)
class Meta:
verbose_name = _("dirección de cliente")
verbose_name_plural = _("direcciones de cliente")
+62 -43
View File
@@ -1,10 +1,13 @@
from decimal import Decimal from decimal import Decimal
from django.contrib.auth import get_user_model
from rest_framework import status from rest_framework import status
from rest_framework.test import APITestCase from rest_framework.test import APITestCase
from config.tests.mixins import TestUserAuthenticationMixin from config.tests.mixins import TestUserAuthenticationMixin
from shop.models import Customer, Product, ProductPrice, Tax from shop.models import Product, ProductPrice, Tax, Customer, CustomerAddress
User = get_user_model()
class TestOrdersAPI(APITestCase, TestUserAuthenticationMixin): class TestOrdersAPI(APITestCase, TestUserAuthenticationMixin):
@@ -16,16 +19,32 @@ class TestOrdersAPI(APITestCase, TestUserAuthenticationMixin):
code="IVA", code="IVA",
value=21, value=21,
) )
self.customer = Customer.objects.create( self.customer = get_user_model().objects.create_user(
vat_id="11111111H", username="11111111H",
first_name="Darth", first_name="Darth",
last_name="Maull", last_name="Maull",
email="darth@maul.com", email="darth@maul.com",
password="dathomir",
)
self.customer_shipping_address = CustomerAddress.objects.create(
user=self.customer,
address="Dathomir", address="Dathomir",
city="Dathomir", address_town="Dathomir",
state="Dathomir", address_zip="00001",
country="Dathomir", address_state="Dathomir",
zip="00001", 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.create_products() self.create_products()
@@ -49,18 +68,18 @@ class TestOrdersAPI(APITestCase, TestUserAuthenticationMixin):
response = self.client.post( response = self.client.post(
f"/api/v1/shop/orders/", f"/api/v1/shop/orders/",
{ {
"customer": self.customer.pk, "user": self.user.pk,
"billing_address": self.customer.address, "billing_address": self.customer_billing_address.address,
"billing_city": self.customer.city, "billing_city": self.customer_billing_address.address_town,
"billing_state": self.customer.state, "billing_state": self.customer_billing_address.address_state,
"billing_country": self.customer.country, "billing_country": self.customer_billing_address.address_country,
"billing_zip": self.customer.zip, "billing_zip": self.customer_billing_address.address_zip,
"shipping_address": self.customer.address, "shipping_address": self.customer_shipping_address.address,
"shipping_city": self.customer.city, "shipping_city": self.customer_shipping_address.address_town,
"shipping_state": self.customer.state, "shipping_state": self.customer_shipping_address.address_state,
"shipping_country": self.customer.country, "shipping_country": self.customer_shipping_address.address_country,
"shipping_zip": self.customer.zip, "shipping_zip": self.customer_shipping_address.address_zip,
"contact_phone": "612345678", "contact_phone": self.customer_shipping_address.address_phone,
}, },
) )
@@ -76,18 +95,18 @@ class TestOrdersAPI(APITestCase, TestUserAuthenticationMixin):
response = self.client.post( response = self.client.post(
f"/api/v1/shop/orders/", f"/api/v1/shop/orders/",
{ {
"customer": self.customer.pk, "user": self.user.pk,
"billing_address": self.customer.address, "billing_address": self.customer_billing_address.address,
"billing_city": self.customer.city, "billing_city": self.customer_billing_address.address_town,
"billing_state": self.customer.state, "billing_state": self.customer_billing_address.address_state,
"billing_country": self.customer.country, "billing_country": self.customer_billing_address.address_country,
"billing_zip": self.customer.zip, "billing_zip": self.customer_billing_address.address_zip,
"shipping_address": self.customer.address, "shipping_address": self.customer_shipping_address.address,
"shipping_city": self.customer.city, "shipping_city": self.customer_shipping_address.address_town,
"shipping_state": self.customer.state, "shipping_state": self.customer_shipping_address.address_state,
"shipping_country": self.customer.country, "shipping_country": self.customer_shipping_address.address_country,
"shipping_zip": self.customer.zip, "shipping_zip": self.customer_shipping_address.address_zip,
"contact_phone": "612345678", "contact_phone": self.customer_shipping_address.address_phone,
}, },
) )
@@ -126,18 +145,18 @@ class TestOrdersAPI(APITestCase, TestUserAuthenticationMixin):
response = self.client.post( response = self.client.post(
f"/api/v1/shop/orders/", f"/api/v1/shop/orders/",
{ {
"customer": self.customer.pk, "user": self.user.pk,
"billing_address": self.customer.address, "billing_address": self.customer_billing_address.address,
"billing_city": self.customer.city, "billing_city": self.customer_billing_address.address_town,
"billing_state": self.customer.state, "billing_state": self.customer_billing_address.address_state,
"billing_country": self.customer.country, "billing_country": self.customer_billing_address.address_country,
"billing_zip": self.customer.zip, "billing_zip": self.customer_billing_address.address_zip,
"shipping_address": self.customer.address, "shipping_address": self.customer_shipping_address.address,
"shipping_city": self.customer.city, "shipping_city": self.customer_shipping_address.address_town,
"shipping_state": self.customer.state, "shipping_state": self.customer_shipping_address.address_state,
"shipping_country": self.customer.country, "shipping_country": self.customer_shipping_address.address_country,
"shipping_zip": self.customer.zip, "shipping_zip": self.customer_shipping_address.address_zip,
"contact_phone": "612345678", "contact_phone": self.customer_shipping_address.address_phone,
}, },
) )
+36 -17
View File
@@ -1,10 +1,13 @@
from decimal import Decimal from decimal import Decimal
from django.contrib.auth import get_user_model
from rest_framework.test import APITestCase as TestCase from rest_framework.test import APITestCase as TestCase
from shop.models import Customer, Product, ProductPrice, Tax from shop.models import Customer, Product, ProductPrice, Tax, CustomerAddress
from shop.utils import create_order, create_order_line_for_product from shop.utils import create_order, create_order_line_for_product
User = get_user_model()
class ShopModelsTest(TestCase): class ShopModelsTest(TestCase):
def setUp(self) -> None: def setUp(self) -> None:
@@ -12,6 +15,33 @@ class ShopModelsTest(TestCase):
code="IVA", code="IVA",
value=21, value=21,
) )
self.customer = User.objects.create_user(
username="11111111H",
first_name="Darth",
last_name="Maull",
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.create_products() self.create_products()
def create_products(self): def create_products(self):
@@ -42,24 +72,13 @@ class ShopModelsTest(TestCase):
) )
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",
)
order = create_order( order = create_order(
customer=self.customer, customer=self.customer,
billing_address=self.customer.address, billing_address=self.customer_billing_address.address,
billing_city=self.customer.city, billing_city=self.customer_billing_address.address_town,
billing_state=self.customer.state, billing_state=self.customer_billing_address.address_state,
billing_zip=self.customer.zip, billing_zip=self.customer_billing_address.address_zip,
billing_country=self.customer.country, billing_country=self.customer_billing_address.address_country,
) )
l1 = create_order_line_for_product( l1 = create_order_line_for_product(
+5 -2
View File
@@ -1,6 +1,9 @@
from decimal import Decimal from decimal import Decimal
from shop.models import Customer, Order, OrderLine, Product, ProductBatch from shop.models import Customer, Order, OrderLine, Product, ProductBatch
from django.contrib.auth import get_user_model
User = get_user_model()
def create_order_line_for_product(product: Product, quantity: Decimal, order: Order): def create_order_line_for_product(product: Product, quantity: Decimal, order: Order):
@@ -22,7 +25,7 @@ def create_order_line_for_product(product: Product, quantity: Decimal, order: Or
def create_order( def create_order(
customer: Customer, customer: User,
billing_address: str, billing_address: str,
billing_city: str, billing_city: str,
billing_state: str, billing_state: str,
@@ -47,7 +50,7 @@ def create_order(
shipping_zip = shipping_zip if shipping_zip else billing_zip shipping_zip = shipping_zip if shipping_zip else billing_zip
order = Order.objects.create( order = Order.objects.create(
customer=customer, user=customer,
billing_address=billing_address, billing_address=billing_address,
billing_city=billing_city, billing_city=billing_city,
billing_state=billing_state, billing_state=billing_state,
+5 -5
View File
@@ -1,5 +1,5 @@
{% load i18n %} {% load i18n %}
<section class="bg-white py-4 antialiased dark:bg-gray-900 md:py-16"> <section class="bg-white py-2 antialiased dark:bg-gray-900 md:py-8">
<div class="mx-auto max-w-screen-xl px-4 2xl:px-0"> <div class="mx-auto max-w-screen-xl px-4 2xl:px-0">
<h2 class="text-xl font-semibold text-gray-900 dark:text-white sm:text-2xl">{% translate 'Carrito' %}</h2> <h2 class="text-xl font-semibold text-gray-900 dark:text-white sm:text-2xl">{% translate 'Carrito' %}</h2>
@@ -75,12 +75,12 @@
<div class="space-y-2"> <div class="space-y-2">
<dl class="flex items-center justify-between gap-4"> <dl class="flex items-center justify-between gap-4">
<dt class="text-base font-normal text-gray-500 dark:text-gray-400">{% translate 'Base imponible' %}</dt> <dt class="text-base font-normal text-gray-500 dark:text-gray-400">{% translate 'Base imponible' %}</dt>
<dd class="text-base font-medium text-gray-900 dark:text-white">{{ base_total }}</dd> <dd class="text-base font-medium text-gray-900 dark:text-white">{{ base_total }}</dd>
</dl> </dl>
<dl class="flex items-center justify-between gap-4"> <dl class="flex items-center justify-between gap-4">
<dt class="text-base font-normal text-gray-500 dark:text-gray-400">{% translate 'Descuentos' %}</dt> <dt class="text-base font-normal text-gray-500 dark:text-gray-400">{% translate 'Descuentos' %}</dt>
<dd class="text-base font-medium text-green-600">-{{ savings }}</dd> <dd class="text-base font-medium text-green-600">-{{ savings }}</dd>
</dl> </dl>
<dl class="flex items-center justify-between gap-4"> <dl class="flex items-center justify-between gap-4">
@@ -91,13 +91,13 @@
<dl class="flex items-center justify-between gap-4"> <dl class="flex items-center justify-between gap-4">
<dt class="text-base font-normal text-gray-500 dark:text-gray-400">{% translate 'Impuestos' %}</dt> <dt class="text-base font-normal text-gray-500 dark:text-gray-400">{% translate 'Impuestos' %}</dt>
<dd class="text-base font-medium text-gray-900 dark:text-white">{{ tax_total }}</dd> <dd class="text-base font-medium text-gray-900 dark:text-white">{{ tax_total }}</dd>
</dl> </dl>
</div> </div>
<dl class="flex items-center justify-between gap-4 border-t border-gray-200 pt-2 dark:border-gray-700"> <dl class="flex items-center justify-between gap-4 border-t border-gray-200 pt-2 dark:border-gray-700">
<dt class="text-base font-bold text-gray-900 dark:text-white">{% translate 'Total' %}</dt> <dt class="text-base font-bold text-gray-900 dark:text-white">{% translate 'Total' %}</dt>
<dd class="text-base font-bold text-gray-900 dark:text-white">{{ total }}</dd> <dd class="text-base font-bold text-gray-900 dark:text-white">{{ total }}</dd>
</dl> </dl>
</div> </div>
@@ -34,7 +34,6 @@
{{ cart_item.product.price.price_with_tax }}€ {{ cart_item.product.price.price_with_tax }}€
</p> </p>
<form hx-post="{% url 'web:delete_cart_item' pk=cart_item.pk %}" <form hx-post="{% url 'web:delete_cart_item' pk=cart_item.pk %}"
hx-swap="none"> hx-swap="none">
<span class="mt-0.5 truncate text-sm font-normal text-gray-500 dark:text-gray-400 mr-2"> <span class="mt-0.5 truncate text-sm font-normal text-gray-500 dark:text-gray-400 mr-2">
@@ -1,7 +1,7 @@
{% load i18n %} {% load i18n %}
<ul class="p-2 text-start text-sm font-medium text-gray-900 dark:text-white"> <ul class="p-2 text-start text-sm font-medium text-gray-900 dark:text-white">
<li> <li>
<a href="#" title="" <a href="{% url 'web:my_account' %}" title=""
class="inline-flex w-full items-center gap-2 rounded-md px-3 py-2 text-sm hover:bg-gray-100 dark:hover:bg-gray-600"> class="inline-flex w-full items-center gap-2 rounded-md px-3 py-2 text-sm hover:bg-gray-100 dark:hover:bg-gray-600">
{% translate 'Mi cuenta' %} {% translate 'Mi cuenta' %}
</a> </a>
+436
View File
@@ -0,0 +1,436 @@
{% extends 'theme/base.html' %}
{% load i18n %}
{% block main %}
{% include 'components/generic/navbar.html' %}
<section class="bg-white py-8 antialiased dark:bg-gray-900 md:py-8">
<div class="mx-auto max-w-screen-lg px-4 2xl:px-0">
<h2 class="mb-4 text-xl font-semibold text-gray-900 dark:text-white sm:text-2xl md:mb-6">{% translate 'Mi cuenta' %}</h2>
<div class="py-4 md:py-8">
<div class="mb-4 grid gap-4 sm:grid-cols-2 sm:gap-8 lg:gap-16">
<div class="space-y-4">
<div class="flex space-x-4">
<div>
<h2 class="flex items-center text-xl font-bold leading-none text-gray-900 dark:text-white sm:text-2xl">Helene Engels</h2>
</div>
</div>
<dl class="">
<dt class="font-semibold text-gray-900 dark:text-white">Email Address</dt>
<dd class="text-gray-500 dark:text-gray-400">helene@example.com</dd>
</dl>
<dl>
<dt class="font-semibold text-gray-900 dark:text-white">Home Address</dt>
<dd class="flex items-center gap-1 text-gray-500 dark:text-gray-400">
<svg class="hidden h-5 w-5 shrink-0 text-gray-400 dark:text-gray-500 lg:inline" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m4 12 8-8 8 8M6 10.5V19a1 1 0 0 0 1 1h3v-3a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v3h3a1 1 0 0 0 1-1v-8.5" />
</svg>
2 Miles Drive, NJ 071, New York, United States of America
</dd>
</dl>
<dl>
<dt class="font-semibold text-gray-900 dark:text-white">Delivery Address</dt>
<dd class="flex items-center gap-1 text-gray-500 dark:text-gray-400">
<svg class="hidden h-5 w-5 shrink-0 text-gray-400 dark:text-gray-500 lg:inline" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7h6l2 4m-8-4v8m0-8V6a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v9h2m8 0H9m4 0h2m4 0h2v-4m0 0h-5m3.5 5.5a2.5 2.5 0 1 1-5 0 2.5 2.5 0 0 1 5 0Zm-10 0a2.5 2.5 0 1 1-5 0 2.5 2.5 0 0 1 5 0Z" />
</svg>
9th St. PATH Station, New York, United States of America
</dd>
</dl>
</div>
<div class="space-y-4">
<dl>
<dt class="font-semibold text-gray-900 dark:text-white">Phone Number</dt>
<dd class="text-gray-500 dark:text-gray-400">+1234 567 890 / +12 345 678</dd>
</dl>
<dl>
<dt class="font-semibold text-gray-900 dark:text-white">Favorite pick-up point</dt>
<dd class="flex items-center gap-1 text-gray-500 dark:text-gray-400">
<svg class="hidden h-5 w-5 shrink-0 text-gray-400 dark:text-gray-500 lg:inline" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 12c.263 0 .524-.06.767-.175a2 2 0 0 0 .65-.491c.186-.21.333-.46.433-.734.1-.274.15-.568.15-.864a2.4 2.4 0 0 0 .586 1.591c.375.422.884.659 1.414.659.53 0 1.04-.237 1.414-.659A2.4 2.4 0 0 0 12 9.736a2.4 2.4 0 0 0 .586 1.591c.375.422.884.659 1.414.659.53 0 1.04-.237 1.414-.659A2.4 2.4 0 0 0 16 9.736c0 .295.052.588.152.861s.248.521.434.73a2 2 0 0 0 .649.488 1.809 1.809 0 0 0 1.53 0 2.03 2.03 0 0 0 .65-.488c.185-.209.332-.457.433-.73.1-.273.152-.566.152-.861 0-.974-1.108-3.85-1.618-5.121A.983.983 0 0 0 17.466 4H6.456a.986.986 0 0 0-.93.645C5.045 5.962 4 8.905 4 9.736c.023.59.241 1.148.611 1.567.37.418.865.667 1.389.697Zm0 0c.328 0 .651-.091.94-.266A2.1 2.1 0 0 0 7.66 11h.681a2.1 2.1 0 0 0 .718.734c.29.175.613.266.942.266.328 0 .651-.091.94-.266.29-.174.537-.427.719-.734h.681a2.1 2.1 0 0 0 .719.734c.289.175.612.266.94.266.329 0 .652-.091.942-.266.29-.174.536-.427.718-.734h.681c.183.307.43.56.719.734.29.174.613.266.941.266a1.819 1.819 0 0 0 1.06-.351M6 12a1.766 1.766 0 0 1-1.163-.476M5 12v7a1 1 0 0 0 1 1h2v-5h3v5h7a1 1 0 0 0 1-1v-7m-5 3v2h2v-2h-2Z"
/>
</svg>
Herald Square, 2, New York, United States of America
</dd>
</dl>
<dl>
<dt class="font-semibold text-gray-900 dark:text-white">My Companies</dt>
<dd class="text-gray-500 dark:text-gray-400">FLOWBITE LLC, Fiscal code: 18673557</dd>
</dl>
<dl>
<dt class="mb-1 font-semibold text-gray-900 dark:text-white">Payment Methods</dt>
<dd class="flex items-center space-x-4 text-gray-500 dark:text-gray-400">
<div class="flex h-12 w-12 shrink-0 items-center justify-center rounded-lg bg-gray-100 dark:bg-gray-700">
<img class="h-4 w-auto dark:hidden" src="https://flowbite.s3.amazonaws.com/blocks/e-commerce/brand-logos/visa.svg" alt="" />
<img class="hidden h-4 w-auto dark:flex" src="https://flowbite.s3.amazonaws.com/blocks/e-commerce/brand-logos/visa-dark.svg" alt="" />
</div>
<div>
<div class="text-sm">
<p class="mb-0.5 font-medium text-gray-900 dark:text-white">Visa ending in 7658</p>
<p class="font-normal text-gray-500 dark:text-gray-400">Expiry 10/2024</p>
</div>
</div>
</dd>
</dl>
</div>
</div>
<button hx-on:click="htmx.toggleClass(htmx.find('#accountInformationModal2'), 'hidden')" type="button" data-modal-target="accountInformationModal2" data-modal-toggle="accountInformationModal2" class="inline-flex w-full items-center justify-center rounded-lg bg-primary-700 px-5 py-2.5 text-sm font-medium text-white hover:bg-primary-800 focus:outline-none focus:ring-4 focus:ring-primary-300 dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800 sm:w-auto">
<svg class="-ms-0.5 me-1.5 h-4 w-4" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m14.304 4.844 2.852 2.852M7 7H4a1 1 0 0 0-1 1v10a1 1 0 0 0 1 1h11a1 1 0 0 0 1-1v-4.5m2.409-9.91a2.017 2.017 0 0 1 0 2.853l-6.844 6.844L8 14l.713-3.565 6.844-6.844a2.015 2.015 0 0 1 2.852 0Z"></path>
</svg>
{% translate 'Editar datos' %}
</button>
</div>
</div>
<!-- Account Information Modal -->
<div id="accountInformationModal2" tabindex="-1" aria-hidden="true" class="max-h-auto fixed left-0 right-0 top-0 z-50 hidden h-[calc(100%-1rem)] max-h-full w-full items-center justify-center overflow-y-auto overflow-x-hidden antialiased md:inset-0">
<div class="max-h-auto relative max-h-full w-full max-w-lg p-4">
<!-- Modal content -->
<div class="relative rounded-lg bg-white shadow dark:bg-gray-800">
<!-- Modal header -->
<div class="flex items-center justify-between rounded-t border-b border-gray-200 p-4 dark:border-gray-700 md:p-5">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">Account Information</h3>
<button hx-on:click="htmx.toggleClass(htmx.find('#accountInformationModal2'), 'hidden')" type="button" class="ms-auto inline-flex h-8 w-8 items-center justify-center rounded-lg bg-transparent text-sm text-gray-400 hover:bg-gray-200 hover:text-gray-900 dark:hover:bg-gray-600 dark:hover:text-white" data-modal-toggle="accountInformationModal2">
<svg class="h-3 w-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 14 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 6 6m0 0 6 6M7 7l6-6M7 7l-6 6" />
</svg>
<span class="sr-only">Close modal</span>
</button>
</div>
<!-- Modal body -->
<form class="p-4 md:p-5">
<div class="mb-5 grid grid-cols-1 gap-4 sm:grid-cols-2">
<div class="col-span-2">
<label for="pick-up-point-input" class="mb-2 block text-sm font-medium text-gray-900 dark:text-white"> Pick-up point* </label>
<input type="text" id="pick-up-point-input" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-primary-500 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder:text-gray-400 dark:focus:border-primary-500 dark:focus:ring-primary-500" placeholder="Enter the pick-up point name" required />
</div>
<div class="col-span-2 sm:col-span-1">
<label for="full_name_info_modal" class="mb-2 block text-sm font-medium text-gray-900 dark:text-white"> Your Full Name* </label>
<input type="text" id="full_name_info_modal" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-primary-500 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder:text-gray-400 dark:focus:border-primary-500 dark:focus:ring-primary-500" placeholder="Enter your first name" required />
</div>
<div class="col-span-2 sm:col-span-1">
<label for="email_info_modal" class="mb-2 block text-sm font-medium text-gray-900 dark:text-white"> Your Email* </label>
<input type="text" id="email_info_modal" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-primary-500 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder:text-gray-400 dark:focus:border-primary-500 dark:focus:ring-primary-500" placeholder="Enter your email here" required />
</div>
<div class="col-span-2">
<label for="phone-input_billing_modal" class="mb-2 block text-sm font-medium text-gray-900 dark:text-white"> Phone Number* </label>
<div class="flex items-center">
<button id="dropdown_phone_input__button_billing_modal" data-dropdown-toggle="dropdown_phone_input_billing_modal" class="z-10 inline-flex shrink-0 items-center rounded-s-lg border border-gray-300 bg-gray-100 px-4 py-2.5 text-center text-sm font-medium text-gray-900 hover:bg-gray-200 focus:outline-none focus:ring-4 focus:ring-gray-100 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-600 dark:focus:ring-gray-700" type="button">
<svg fill="none" aria-hidden="true" class="me-2 h-4 w-4" viewBox="0 0 20 15">
<rect width="19.6" height="14" y=".5" fill="#fff" rx="2" />
<mask id="a" style="mask-type:luminance" width="20" height="15" x="0" y="0" maskUnits="userSpaceOnUse">
<rect width="19.6" height="14" y=".5" fill="#fff" rx="2" />
</mask>
<g mask="url(#a)">
<path fill="#D02F44" fill-rule="evenodd" d="M19.6.5H0v.933h19.6V.5zm0 1.867H0V3.3h19.6v-.933zM0 4.233h19.6v.934H0v-.934zM19.6 6.1H0v.933h19.6V6.1zM0 7.967h19.6V8.9H0v-.933zm19.6 1.866H0v.934h19.6v-.934zM0 11.7h19.6v.933H0V11.7zm19.6 1.867H0v.933h19.6v-.933z" clip-rule="evenodd" />
<path fill="#46467F" d="M0 .5h8.4v6.533H0z" />
<g filter="url(#filter0_d_343_121520)">
<path
fill="url(#paint0_linear_343_121520)"
fill-rule="evenodd"
d="M1.867 1.9a.467.467 0 11-.934 0 .467.467 0 01.934 0zm1.866 0a.467.467 0 11-.933 0 .467.467 0 01.933 0zm1.4.467a.467.467 0 100-.934.467.467 0 000 .934zM7.467 1.9a.467.467 0 11-.934 0 .467.467 0 01.934 0zM2.333 3.3a.467.467 0 100-.933.467.467 0 000 .933zm2.334-.467a.467.467 0 11-.934 0 .467.467 0 01.934 0zm1.4.467a.467.467 0 100-.933.467.467 0 000 .933zm1.4.467a.467.467 0 11-.934 0 .467.467 0 01.934 0zm-2.334.466a.467.467 0 100-.933.467.467 0 000 .933zm-1.4-.466a.467.467 0 11-.933 0 .467.467 0 01.933 0zM1.4 4.233a.467.467 0 100-.933.467.467 0 000 .933zm1.4.467a.467.467 0 11-.933 0 .467.467 0 01.933 0zm1.4.467a.467.467 0 100-.934.467.467 0 000 .934zM6.533 4.7a.467.467 0 11-.933 0 .467.467 0 01.933 0zM7 6.1a.467.467 0 100-.933.467.467 0 000 .933zm-1.4-.467a.467.467 0 11-.933 0 .467.467 0 01.933 0zM3.267 6.1a.467.467 0 100-.933.467.467 0 000 .933zm-1.4-.467a.467.467 0 11-.934 0 .467.467 0 01.934 0z"
clip-rule="evenodd"
/>
</g>
</g>
<defs>
<linearGradient id="paint0_linear_343_121520" x1=".933" x2=".933" y1="1.433" y2="6.1" gradientUnits="userSpaceOnUse">
<stop stop-color="#fff" />
<stop offset="1" stop-color="#F0F0F0" />
</linearGradient>
<filter id="filter0_d_343_121520" width="6.533" height="5.667" x=".933" y="1.433" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feColorMatrix in="SourceAlpha" result="hardAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" />
<feOffset dy="1" />
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.06 0" />
<feBlend in2="BackgroundImageFix" result="effect1_dropShadow_343_121520" />
<feBlend in="SourceGraphic" in2="effect1_dropShadow_343_121520" result="shape" />
</filter>
</defs>
</svg>
+1
<svg class="-me-0.5 ms-2 h-4 w-4" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m19 9-7 7-7-7" />
</svg>
</button>
<div id="dropdown_phone_input_billing_modal" class="z-10 hidden w-56 divide-y divide-gray-100 rounded-lg bg-white shadow dark:bg-gray-700">
<ul class="p-2 text-sm font-medium text-gray-700 dark:text-gray-200" aria-labelledby="dropdown_phone_input__button_billing_modal">
<li>
<button type="button" class="inline-flex w-full rounded-md px-3 py-2 text-sm text-gray-500 hover:bg-gray-100 hover:text-gray-900 dark:text-gray-400 dark:hover:bg-gray-600 dark:hover:text-white" role="menuitem">
<span class="inline-flex items-center">
<svg fill="none" aria-hidden="true" class="me-2 h-4 w-4" viewBox="0 0 20 15">
<rect width="19.6" height="14" y=".5" fill="#fff" rx="2" />
<mask id="a" style="mask-type:luminance" width="20" height="15" x="0" y="0" maskUnits="userSpaceOnUse">
<rect width="19.6" height="14" y=".5" fill="#fff" rx="2" />
</mask>
<g mask="url(#a)">
<path fill="#D02F44" fill-rule="evenodd" d="M19.6.5H0v.933h19.6V.5zm0 1.867H0V3.3h19.6v-.933zM0 4.233h19.6v.934H0v-.934zM19.6 6.1H0v.933h19.6V6.1zM0 7.967h19.6V8.9H0v-.933zm19.6 1.866H0v.934h19.6v-.934zM0 11.7h19.6v.933H0V11.7zm19.6 1.867H0v.933h19.6v-.933z" clip-rule="evenodd" />
<path fill="#46467F" d="M0 .5h8.4v6.533H0z" />
<g filter="url(#filter0_d_343_121520)">
<path
fill="url(#paint0_linear_343_121520)"
fill-rule="evenodd"
d="M1.867 1.9a.467.467 0 11-.934 0 .467.467 0 01.934 0zm1.866 0a.467.467 0 11-.933 0 .467.467 0 01.933 0zm1.4.467a.467.467 0 100-.934.467.467 0 000 .934zM7.467 1.9a.467.467 0 11-.934 0 .467.467 0 01.934 0zM2.333 3.3a.467.467 0 100-.933.467.467 0 000 .933zm2.334-.467a.467.467 0 11-.934 0 .467.467 0 01.934 0zm1.4.467a.467.467 0 100-.933.467.467 0 000 .933zm1.4.467a.467.467 0 11-.934 0 .467.467 0 01.934 0zm-2.334.466a.467.467 0 100-.933.467.467 0 000 .933zm-1.4-.466a.467.467 0 11-.933 0 .467.467 0 01.933 0zM1.4 4.233a.467.467 0 100-.933.467.467 0 000 .933zm1.4.467a.467.467 0 11-.933 0 .467.467 0 01.933 0zm1.4.467a.467.467 0 100-.934.467.467 0 000 .934zM6.533 4.7a.467.467 0 11-.933 0 .467.467 0 01.933 0zM7 6.1a.467.467 0 100-.933.467.467 0 000 .933zm-1.4-.467a.467.467 0 11-.933 0 .467.467 0 01.933 0zM3.267 6.1a.467.467 0 100-.933.467.467 0 000 .933zm-1.4-.467a.467.467 0 11-.934 0 .467.467 0 01.934 0z"
clip-rule="evenodd"
/>
</g>
</g>
<defs>
<linearGradient id="paint0_linear_343_121520" x1=".933" x2=".933" y1="1.433" y2="6.1" gradientUnits="userSpaceOnUse">
<stop stop-color="#fff" />
<stop offset="1" stop-color="#F0F0F0" />
</linearGradient>
<filter id="filter0_d_343_121520" width="6.533" height="5.667" x=".933" y="1.433" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feColorMatrix in="SourceAlpha" result="hardAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" />
<feOffset dy="1" />
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.06 0" />
<feBlend in2="BackgroundImageFix" result="effect1_dropShadow_343_121520" />
<feBlend in="SourceGraphic" in2="effect1_dropShadow_343_121520" result="shape" />
</filter>
</defs>
</svg>
United States (+1)
</span>
</button>
</li>
<li>
<button type="button" class="inline-flex w-full rounded-md px-3 py-2 text-sm text-gray-500 hover:bg-gray-100 hover:text-gray-900 dark:text-gray-400 dark:hover:bg-gray-600 dark:hover:text-white" role="menuitem">
<span class="inline-flex items-center">
<svg class="me-2 h-4 w-4" fill="none" viewBox="0 0 20 15">
<rect width="19.6" height="14" y=".5" fill="#fff" rx="2" />
<mask id="a" style="mask-type:luminance" width="20" height="15" x="0" y="0" maskUnits="userSpaceOnUse">
<rect width="19.6" height="14" y=".5" fill="#fff" rx="2" />
</mask>
<g mask="url(#a)">
<path fill="#0A17A7" d="M0 .5h19.6v14H0z" />
<path fill="#fff" fill-rule="evenodd" d="M-.898-.842L7.467 4.8V-.433h4.667V4.8l8.364-5.642L21.542.706l-6.614 4.46H19.6v4.667h-4.672l6.614 4.46-1.044 1.549-8.365-5.642v5.233H7.467V10.2l-8.365 5.642-1.043-1.548 6.613-4.46H0V5.166h4.672L-1.941.706-.898-.842z" clip-rule="evenodd" />
<path stroke="#DB1F35" stroke-linecap="round" stroke-width=".667" d="M13.067 4.933L21.933-.9M14.009 10.088l7.947 5.357M5.604 4.917L-2.686-.67M6.503 10.024l-9.189 6.093" />
<path fill="#E6273E" fill-rule="evenodd" d="M0 8.9h8.4v5.6h2.8V8.9h8.4V6.1h-8.4V.5H8.4v5.6H0v2.8z" clip-rule="evenodd" />
</g>
</svg>
United Kingdom (+44)
</span>
</button>
</li>
<li>
<button type="button" class="inline-flex w-full rounded-md px-3 py-2 text-sm text-gray-500 hover:bg-gray-100 hover:text-gray-900 dark:text-gray-400 dark:hover:bg-gray-600 dark:hover:text-white" role="menuitem">
<span class="inline-flex items-center">
<svg class="me-2 h-4 w-4" fill="none" viewBox="0 0 20 15" xmlns="http://www.w3.org/2000/svg">
<rect width="19.6" height="14" y=".5" fill="#fff" rx="2" />
<mask id="a" style="mask-type:luminance" width="20" height="15" x="0" y="0" maskUnits="userSpaceOnUse">
<rect width="19.6" height="14" y=".5" fill="#fff" rx="2" />
</mask>
<g mask="url(#a)">
<path fill="#0A17A7" d="M0 .5h19.6v14H0z" />
<path fill="#fff" stroke="#fff" stroke-width=".667" d="M0 .167h-.901l.684.586 3.15 2.7v.609L-.194 6.295l-.14.1v1.24l.51-.319L3.83 5.033h.73L7.7 7.276a.488.488 0 00.601-.767L5.467 4.08v-.608l2.987-2.134a.667.667 0 00.28-.543V-.1l-.51.318L4.57 2.5h-.73L.66.229.572.167H0z" />
<path fill="url(#paint0_linear_374_135177)" fill-rule="evenodd" d="M0 2.833V4.7h3.267v2.133c0 .369.298.667.666.667h.534a.667.667 0 00.666-.667V4.7H8.2a.667.667 0 00.667-.667V3.5a.667.667 0 00-.667-.667H5.133V.5H3.267v2.333H0z" clip-rule="evenodd" />
<path fill="url(#paint1_linear_374_135177)" fill-rule="evenodd" d="M0 3.3h3.733V.5h.934v2.8H8.4v.933H4.667v2.8h-.934v-2.8H0V3.3z" clip-rule="evenodd" />
<path
fill="#fff"
fill-rule="evenodd"
d="M4.2 11.933l-.823.433.157-.916-.666-.65.92-.133.412-.834.411.834.92.134-.665.649.157.916-.823-.433zm9.8.7l-.66.194.194-.66-.194-.66.66.193.66-.193-.193.66.193.66-.66-.194zm0-8.866l-.66.193.194-.66-.194-.66.66.193.66-.193-.193.66.193.66-.66-.193zm2.8 2.8l-.66.193.193-.66-.193-.66.66.193.66-.193-.193.66.193.66-.66-.193zm-5.6.933l-.66.193.193-.66-.193-.66.66.194.66-.194-.193.66.193.66-.66-.193zm4.2 1.167l-.33.096.096-.33-.096-.33.33.097.33-.097-.097.33.097.33-.33-.096z"
clip-rule="evenodd"
/>
</g>
<defs>
<linearGradient id="paint0_linear_374_135177" x1="0" x2="0" y1=".5" y2="7.5" gradientUnits="userSpaceOnUse">
<stop stop-color="#fff" />
<stop offset="1" stop-color="#F0F0F0" />
</linearGradient>
<linearGradient id="paint1_linear_374_135177" x1="0" x2="0" y1=".5" y2="7.033" gradientUnits="userSpaceOnUse">
<stop stop-color="#FF2E3B" />
<stop offset="1" stop-color="#FC0D1B" />
</linearGradient>
</defs>
</svg>
Australia (+61)
</span>
</button>
</li>
<li>
<button type="button" class="inline-flex w-full rounded-md px-3 py-2 text-sm text-gray-500 hover:bg-gray-100 hover:text-gray-900 dark:text-gray-400 dark:hover:bg-gray-600 dark:hover:text-white" role="menuitem">
<span class="inline-flex items-center">
<svg class="me-2 h-4 w-4" fill="none" viewBox="0 0 20 15">
<rect width="19.6" height="14" y=".5" fill="#fff" rx="2" />
<mask id="a" style="mask-type:luminance" width="20" height="15" x="0" y="0" maskUnits="userSpaceOnUse">
<rect width="19.6" height="14" y=".5" fill="#fff" rx="2" />
</mask>
<g mask="url(#a)">
<path fill="#262626" fill-rule="evenodd" d="M0 5.167h19.6V.5H0v4.667z" clip-rule="evenodd" />
<g filter="url(#filter0_d_374_135180)">
<path fill="#F01515" fill-rule="evenodd" d="M0 9.833h19.6V5.167H0v4.666z" clip-rule="evenodd" />
</g>
<g filter="url(#filter1_d_374_135180)">
<path fill="#FFD521" fill-rule="evenodd" d="M0 14.5h19.6V9.833H0V14.5z" clip-rule="evenodd" />
</g>
</g>
<defs>
<filter id="filter0_d_374_135180" width="19.6" height="4.667" x="0" y="5.167" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feColorMatrix in="SourceAlpha" result="hardAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" />
<feOffset />
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.06 0" />
<feBlend in2="BackgroundImageFix" result="effect1_dropShadow_374_135180" />
<feBlend in="SourceGraphic" in2="effect1_dropShadow_374_135180" result="shape" />
</filter>
<filter id="filter1_d_374_135180" width="19.6" height="4.667" x="0" y="9.833" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feColorMatrix in="SourceAlpha" result="hardAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" />
<feOffset />
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.06 0" />
<feBlend in2="BackgroundImageFix" result="effect1_dropShadow_374_135180" />
<feBlend in="SourceGraphic" in2="effect1_dropShadow_374_135180" result="shape" />
</filter>
</defs>
</svg>
Germany (+49)
</span>
</button>
</li>
<li>
<button type="button" class="inline-flex w-full rounded-md px-3 py-2 text-sm text-gray-500 hover:bg-gray-100 hover:text-gray-900 dark:text-gray-400 dark:hover:bg-gray-600 dark:hover:text-white" role="menuitem">
<span class="inline-flex items-center">
<svg class="me-2 h-4 w-4" fill="none" viewBox="0 0 20 15">
<rect width="19.1" height="13.5" x=".25" y=".75" fill="#fff" stroke="#F5F5F5" stroke-width=".5" rx="1.75" />
<mask id="a" style="mask-type:luminance" width="20" height="15" x="0" y="0" maskUnits="userSpaceOnUse">
<rect width="19.1" height="13.5" x=".25" y=".75" fill="#fff" stroke="#fff" stroke-width=".5" rx="1.75" />
</mask>
<g mask="url(#a)">
<path fill="#F44653" d="M13.067.5H19.6v14h-6.533z" />
<path fill="#1035BB" fill-rule="evenodd" d="M0 14.5h6.533V.5H0v14z" clip-rule="evenodd" />
</g>
</svg>
France (+33)
</span>
</button>
</li>
<li>
<button type="button" class="inline-flex w-full rounded-md px-3 py-2 text-sm text-gray-500 hover:bg-gray-100 hover:text-gray-900 dark:text-gray-400 dark:hover:bg-gray-600 dark:hover:text-white" role="menuitem">
<span class="inline-flex items-center">
<svg class="me-2 h-4 w-4" fill="none" viewBox="0 0 20 15">
<rect width="19.6" height="14" y=".5" fill="#fff" rx="2" />
<mask id="a" style="mask-type:luminance" width="20" height="15" x="0" y="0" maskUnits="userSpaceOnUse">
<rect width="19.6" height="14" y=".5" fill="#fff" rx="2" />
</mask>
<g mask="url(#a)">
<path fill="#262626" fill-rule="evenodd" d="M0 5.167h19.6V.5H0v4.667z" clip-rule="evenodd" />
<g filter="url(#filter0_d_374_135180)">
<path fill="#F01515" fill-rule="evenodd" d="M0 9.833h19.6V5.167H0v4.666z" clip-rule="evenodd" />
</g>
<g filter="url(#filter1_d_374_135180)">
<path fill="#FFD521" fill-rule="evenodd" d="M0 14.5h19.6V9.833H0V14.5z" clip-rule="evenodd" />
</g>
</g>
<defs>
<filter id="filter0_d_374_135180" width="19.6" height="4.667" x="0" y="5.167" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feColorMatrix in="SourceAlpha" result="hardAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" />
<feOffset />
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.06 0" />
<feBlend in2="BackgroundImageFix" result="effect1_dropShadow_374_135180" />
<feBlend in="SourceGraphic" in2="effect1_dropShadow_374_135180" result="shape" />
</filter>
<filter id="filter1_d_374_135180" width="19.6" height="4.667" x="0" y="9.833" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse">
<feFlood flood-opacity="0" result="BackgroundImageFix" />
<feColorMatrix in="SourceAlpha" result="hardAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" />
<feOffset />
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.06 0" />
<feBlend in2="BackgroundImageFix" result="effect1_dropShadow_374_135180" />
<feBlend in="SourceGraphic" in2="effect1_dropShadow_374_135180" result="shape" />
</filter>
</defs>
</svg>
Germany (+49)
</span>
</button>
</li>
</ul>
</div>
<div class="relative w-full">
<input type="text" id="phone-input" class="z-20 block w-full rounded-e-lg border border-s-0 border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-primary-500 focus:ring-primary-500 dark:border-gray-600 dark:border-s-gray-700 dark:bg-gray-700 dark:text-white dark:placeholder:text-gray-400 dark:focus:border-primary-500" pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}" placeholder="123-456-7890" required />
</div>
</div>
</div>
<div class="col-span-2 sm:col-span-1">
<div class="mb-2 flex items-center gap-2">
<label for="select_country_input_billing_modal" class="block text-sm font-medium text-gray-900 dark:text-white"> Country* </label>
</div>
<select id="select_country_input_billing_modal" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-primary-500 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder:text-gray-400 dark:focus:border-primary-500 dark:focus:ring-primary-500">
<option selected>United States</option>
<option value="AS">Australia</option>
<option value="FR">France</option>
<option value="ES">Spain</option>
<option value="UK">United Kingdom</option>
</select>
</div>
<div class="col-span-2 sm:col-span-1">
<div class="mb-2 flex items-center gap-2">
<label for="select_city_input_billing_modal" class="block text-sm font-medium text-gray-900 dark:text-white"> City* </label>
</div>
<select id="select_city_input_billing_modal" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-primary-500 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder:text-gray-400 dark:focus:border-primary-500 dark:focus:ring-primary-500">
<option selected>San Francisco</option>
<option value="NY">New York</option>
<option value="LA">Los Angeles</option>
<option value="CH">Chicago</option>
<option value="HU">Houston</option>
</select>
</div>
<div class="col-span-2">
<label for="address_billing_modal" class="mb-2 block text-sm font-medium text-gray-900 dark:text-white"> Delivery Address* </label>
<textarea id="address_billing_modal" rows="4" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-primary-500 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder:text-gray-400 dark:focus:border-primary-500 dark:focus:ring-primary-500" placeholder="Enter here your address"></textarea>
</div>
<div class="col-span-2 sm:col-span-1">
<label for="company_name" class="mb-2 block text-sm font-medium text-gray-900 dark:text-white"> Company name </label>
<input type="text" id="company_name" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-primary-500 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder:text-gray-400 dark:focus:border-primary-500 dark:focus:ring-primary-500" placeholder="Flowbite LLC" />
</div>
<div class="col-span-2 sm:col-span-1">
<label for="vat_number" class="mb-2 block text-sm font-medium text-gray-900 dark:text-white"> VAT number </label>
<input type="text" id="vat_number" class="block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 focus:border-primary-500 focus:ring-primary-500 dark:border-gray-600 dark:bg-gray-700 dark:text-white dark:placeholder:text-gray-400 dark:focus:border-primary-500 dark:focus:ring-primary-500" placeholder="DE42313253" />
</div>
</div>
<div class="border-t border-gray-200 pt-4 dark:border-gray-700 md:pt-5">
<button type="submit" class="me-2 inline-flex items-center rounded-lg bg-primary-700 px-5 py-2.5 text-center text-sm font-medium text-white hover:bg-primary-800 focus:outline-none focus:ring-4 focus:ring-primary-300 dark:bg-primary-600 dark:hover:bg-primary-700 dark:focus:ring-primary-800">Save information</button>
<button type="button" data-modal-toggle="accountInformationModal2" class="me-2 rounded-lg border border-gray-200 bg-white px-5 py-2.5 text-sm font-medium text-gray-900 hover:bg-gray-100 hover:text-primary-700 focus:z-10 focus:outline-none focus:ring-4 focus:ring-gray-100 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white dark:focus:ring-gray-700">Cancel</button>
</div>
</form>
</div>
</div>
</div>
<div id="deleteOrderModal" tabindex="-1" aria-hidden="true" class="fixed left-0 right-0 top-0 z-50 hidden h-modal w-full items-center justify-center overflow-y-auto overflow-x-hidden md:inset-0 md:h-full">
<div class="relative h-full w-full max-w-md p-4 md:h-auto">
<!-- Modal content -->
<div class="relative rounded-lg bg-white p-4 text-center shadow dark:bg-gray-800 sm:p-5">
<button type="button" class="absolute right-2.5 top-2.5 ml-auto inline-flex items-center rounded-lg bg-transparent p-1.5 text-sm text-gray-400 hover:bg-gray-200 hover:text-gray-900 dark:hover:bg-gray-600 dark:hover:text-white" data-modal-toggle="deleteOrderModal">
<svg aria-hidden="true" class="h-5 w-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>
<span class="sr-only">Close modal</span>
</button>
<div class="mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-lg bg-gray-100 p-2 dark:bg-gray-700">
<svg class="h-8 w-8 text-gray-500 dark:text-gray-400" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 7h14m-9 3v8m4-8v8M10 3h4a1 1 0 0 1 1 1v3H9V4a1 1 0 0 1 1-1ZM6 7h12v13a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7Z" />
</svg>
<span class="sr-only">Danger icon</span>
</div>
<p class="mb-3.5 text-gray-900 dark:text-white"><a href="#" class="font-medium text-primary-700 hover:underline dark:text-primary-500">@heleneeng</a>, are you sure you want to delete this order from your account?</p>
<p class="mb-4 text-gray-500 dark:text-gray-300">This action cannot be undone.</p>
<div class="flex items-center justify-center space-x-4">
<button data-modal-toggle="deleteOrderModal" type="button" class="rounded-lg border border-gray-200 bg-white px-3 py-2 text-sm font-medium text-gray-500 hover:bg-gray-100 hover:text-gray-900 focus:z-10 focus:outline-none focus:ring-4 focus:ring-primary-300 dark:border-gray-500 dark:bg-gray-700 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white dark:focus:ring-gray-600">No, cancel</button>
<button type="submit" class="rounded-lg bg-red-700 px-3 py-2 text-center text-sm font-medium text-white hover:bg-red-700 focus:outline-none focus:ring-4 focus:ring-red-300 dark:bg-red-600 dark:hover:bg-red-700 dark:focus:ring-red-900">Yes, delete</button>
</div>
</div>
</div>
</div>
</section>
{% endblock %}
+2 -1
View File
@@ -1,7 +1,7 @@
from django.urls import path from django.urls import path
from web.views.components import cart, cart_dropdown, list_products from web.views.components import cart, cart_dropdown, list_products
from web.views.users import login, logout, register, reset_password from web.views.users import login, logout, my_account, register, reset_password
from web.views.web import ( from web.views.web import (
add_cart_item, add_cart_item,
cart_detail, cart_detail,
@@ -22,6 +22,7 @@ urlpatterns = [
path("logout/", logout, name="logout"), path("logout/", logout, name="logout"),
path("register/", register, name="register"), path("register/", register, name="register"),
path("reset-password/", reset_password, name="reset-password"), path("reset-password/", reset_password, name="reset-password"),
path("my-account/", my_account, name="my_account"),
# components # components
path("web/components/products/", list_products, name="list_products"), path("web/components/products/", list_products, name="list_products"),
path("web/components/cart-dropdown/", cart_dropdown, name="cart_dropdown"), path("web/components/cart-dropdown/", cart_dropdown, name="cart_dropdown"),
+6
View File
@@ -74,7 +74,13 @@ class ResetPasswordView(TemplateView):
template_name = "web/reset-password.html" template_name = "web/reset-password.html"
class MyAccountView(TemplateView):
template_name = "users/user_details.html"
login = LoginView.as_view() login = LoginView.as_view()
logout = LogoutView.as_view() logout = LogoutView.as_view()
register = RegisterView.as_view() register = RegisterView.as_view()
reset_password = ResetPasswordView.as_view() reset_password = ResetPasswordView.as_view()
my_account = MyAccountView.as_view()