diff --git a/shop/migrations/0001_initial.py b/shop/migrations/0001_initial.py index 77c10dc..708d53f 100644 --- a/shop/migrations/0001_initial.py +++ b/shop/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.3 on 2025-01-02 13:36 +# Generated by Django 5.1.3 on 2025-01-03 11:17 import django.db.models.deletion import django.utils.timezone @@ -275,6 +275,7 @@ class Migration(migrations.Migration): verbose_name="tipo de dirección", ), ), + ("email", models.EmailField(max_length=254, verbose_name="e-mail")), ( "default", models.BooleanField(default=True, verbose_name="por defecto"), @@ -354,6 +355,12 @@ class Migration(migrations.Migration): verbose_name="total", ), ), + ( + "email", + models.EmailField( + blank=True, max_length=254, verbose_name="e-mail" + ), + ), ( "billing_address", models.CharField( @@ -411,6 +418,8 @@ class Migration(migrations.Migration): ( "user", models.ForeignKey( + blank=True, + null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL, verbose_name="cliente", diff --git a/shop/models.py b/shop/models.py index 9bd07b0..472c55c 100644 --- a/shop/models.py +++ b/shop/models.py @@ -356,7 +356,8 @@ class Order(TimestampedModel): default=Decimal("0"), max_digits=13, decimal_places=2, verbose_name=_("total") ) - user = models.ForeignKey(User, on_delete=models.PROTECT, verbose_name=_("cliente")) + user = models.ForeignKey(User, blank=True, null=True, on_delete=models.PROTECT, verbose_name=_("cliente")) + email = models.EmailField(blank=True, verbose_name=_('e-mail')) # Datos de facturación billing_address = models.CharField( @@ -492,11 +493,12 @@ class CustomerAddress(models.Model): default=Types.SHIPPING, verbose_name=_("tipo de dirección"), ) + email = models.EmailField(blank=False, null=False, verbose_name=_("e-mail")) default = models.BooleanField(default=True, verbose_name=_("por defecto")) hidden = models.BooleanField(default=False, db_index=True, verbose_name=_("oculto")) def __str__(self): - return f'{self.full_name} - {self.address}, {self.address_zip}, {self.address_state} - {self.address_country}' + return f"{self.full_name} - {self.address}, {self.address_zip}, {self.address_state} - {self.address_country}" class Meta: verbose_name = _("dirección de cliente") diff --git a/shop/utils.py b/shop/utils.py index 701e0b7..07c6f4b 100644 --- a/shop/utils.py +++ b/shop/utils.py @@ -73,22 +73,36 @@ def delete_product_batch(batch: ProductBatch): def create_order_from_cart( cart: Cart, - billing_address: CustomerAddress, - shipping_address: CustomerAddress, shipping_method: ShippingMethod, + billing_address_full_name="", + billing_address_address="", + billing_address_town="", + billing_address_state="", + billing_address_country="", + billing_address_zip="", + shipping_address_full_name="", + shipping_address_address="", + shipping_address_town="", + shipping_address_state="", + shipping_address_country="", + shipping_address_zip="", + shipping_address_phone="", + email="", ): order = Order.objects.create( - billing_address=billing_address.address, - billing_city=billing_address.address_town, - billing_state=billing_address.address_state, - billing_country=billing_address.address_country, - billing_zip=billing_address.address_zip, - shipping_address=shipping_address.address, - shipping_city=shipping_address.address_town, - shipping_state=shipping_address.address_state, - shipping_country=shipping_address.address_country, - shipping_zip=shipping_address.address_zip, + billing_address=f'{billing_address_full_name} {billing_address_address}', + billing_city=billing_address_town, + billing_state=billing_address_state, + billing_country=billing_address_country, + billing_zip=billing_address_zip, + contact_phone=shipping_address_phone, + shipping_address=f'{shipping_address_address} {shipping_address_full_name}', + shipping_city=shipping_address_town, + shipping_state=shipping_address_state, + shipping_country=shipping_address_country, + shipping_zip=shipping_address_zip, user=cart.user, + email=email, ) for item in cart.items.all(): diff --git a/web/forms.py b/web/forms.py index 9f412c1..4865cca 100644 --- a/web/forms.py +++ b/web/forms.py @@ -1,6 +1,8 @@ from django import forms from django.forms import widgets +from shop.models import CustomerAddress + class CartItemForm(forms.Form): """ @@ -14,6 +16,24 @@ class CartItemForm(forms.Form): class CreateOrderForm(forms.Form): - shipping_address = forms.IntegerField() - billing_address = forms.IntegerField() + email = forms.CharField(max_length=254) + + shipping_address_full_name = forms.CharField(max_length=128, required=True) + shipping_address = forms.CharField(max_length=128, required=True) + shipping_address_town = forms.CharField(max_length=64, required=True) + shipping_address_zip = forms.CharField(max_length=16, required=True) + shipping_address_state = forms.CharField(max_length=64, required=True) + shipping_address_country = forms.CharField(max_length=64, required=True) + shipping_address_phone = forms.CharField(max_length=16, required=False) + + same_as_shipping = forms.BooleanField(required=False) + + billing_address_full_name = forms.CharField(max_length=128, required=True) + billing_address = forms.CharField(max_length=128, required=True) + billing_address_town = forms.CharField(max_length=64, required=True) + billing_address_zip = forms.CharField(max_length=16, required=True) + billing_address_state = forms.CharField(max_length=64, required=True) + billing_address_country = forms.CharField(max_length=64, required=True) + billing_address_phone = forms.CharField(max_length=16, required=False) + shipping_method = forms.IntegerField() diff --git a/web/templates/components/cart/cart.html b/web/templates/components/cart/cart.html index 4268d2d..e016a47 100644 --- a/web/templates/components/cart/cart.html +++ b/web/templates/components/cart/cart.html @@ -78,27 +78,179 @@ {% translate 'Dirección de envío' %} - {% for address in shipping_addresses %} - - - {% endfor %} +
+ {% if user.is_anonymous %} +
+ + +
+ {% else %} + + {% endif %} +
+ + + + +
+
+ + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +

- {% translate 'Dirección de facturación' %} + {% translate 'Dirección de envío' %}

- {% for address in billing_addresses %} - - - {% endfor %} +
+
+ + + + +
+
+ + +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
diff --git a/web/templates/web/order.html b/web/templates/web/order.html new file mode 100644 index 0000000..2cd181f --- /dev/null +++ b/web/templates/web/order.html @@ -0,0 +1,184 @@ +{% extends 'theme/base.html' %} +{% load static i18n %} + +{% block main %} + {% include 'components/generic/navbar.html' %} + {% load i18n %} +
+
+ {% csrf_token %} +
+

+ {% translate 'Resumen del pedido' %} +

+ +
+
+
+ + {% for item in items %} +
+
+ + {{ item.product.name }} + + + + +
+
+ + {{ item.quantity }}x + +
+
+

{{ item.product.price.price_with_tax }} + €

+
+
+ +
+ + {{ item.product.name }} + + +
+ + {% csrf_token %} + + + +
+
+
+
+ {% endfor %} + + {% if items.count == 0 %} +

+ {% translate 'No hay nada en el carrito...' %} +

+

+ + {% translate 'Volver a inicio' %} + +

+ {% endif %} + +
+

+ {% translate 'Dirección de envío' %} +

+ + {% for address in shipping_addresses %} + + + {% endfor %} +
+ +
+

+ {% translate 'Dirección de facturación' %} +

+ + {% for address in billing_addresses %} + + + {% endfor %} +
+ +
+

+ {% translate 'Opciones de envío' %} +

+ + {% for shipping_method in shipping_methods %} + + + {% endfor %} +
+
+ +
+ + +
+
+

{% translate 'Resumen del pedido' %}

+ +
+
+
+
{% translate 'Base imponible' %}
+
{{ base_total }} €
+
+ +
+
{% translate 'Descuentos' %}
+
-{{ savings }} €
+
+ +
+
{% translate 'Gastos de envío' %}
+
{{ shipping_cost }} €
+
+ +
+
{% translate 'Impuestos' %}
+
{{ tax_total }} €
+
+
+ +
+
{% translate 'Total' %}
+
{{ total }} €
+
+
+ + + + +
+
+
+ +
+ +
+{% endblock %} diff --git a/web/urls.py b/web/urls.py index ce8d5a1..2d2507b 100644 --- a/web/urls.py +++ b/web/urls.py @@ -17,6 +17,7 @@ from web.views.web import ( delete_from_wishlist, index, manifest, + order_detail, product_detail, wishlist, ) @@ -29,6 +30,7 @@ urlpatterns = [ path("categories//", category_view, name="category_view"), path("products///", product_detail, name="product_detail"), path("cart/", cart_detail, name="cart_detail"), + path("order//", order_detail, name="order"), # users path("login/", login, name="login"), path("logout/", logout, name="logout"), diff --git a/web/views/components.py b/web/views/components.py index 0da0f6c..7a3f108 100644 --- a/web/views/components.py +++ b/web/views/components.py @@ -91,12 +91,18 @@ def cart(request, *args, **kwargs): total = base_total + tax_total - billing_addresses = CustomerAddress.objects.filter( - user=request.user, address_type=CustomerAddress.Types.BILLING - ) - shipping_addresses = CustomerAddress.objects.filter( - user=request.user, address_type=CustomerAddress.Types.SHIPPING - ) + if request.user.is_authenticated: + billing_address = CustomerAddress.objects.filter( + user=request.user, address_type=CustomerAddress.Types.BILLING, default=True + ).first() + shipping_address = CustomerAddress.objects.filter( + user=request.user, + address_type=CustomerAddress.Types.SHIPPING, + ).first() + else: + billing_address = None + shipping_address = None + shipping_methods = ShippingMethod.objects.all() response = render( @@ -108,8 +114,8 @@ def cart(request, *args, **kwargs): "total": total, "base_total": base_total, "tax_total": tax_total, - "billing_addresses": billing_addresses, - "shipping_addresses": shipping_addresses, + "billing_address": billing_address, + "shipping_address": shipping_address, "shipping_methods": shipping_methods, }, ) diff --git a/web/views/web.py b/web/views/web.py index e97d93b..a4b6757 100644 --- a/web/views/web.py +++ b/web/views/web.py @@ -11,6 +11,8 @@ from shop.models import ( WishlistedProduct, CustomerAddress, ShippingMethod, + Order, + OrderLine, ) from shop.utils import create_order_from_cart from web.forms import CreateOrderForm @@ -88,24 +90,58 @@ class CartDetail(TemplateView, CreateView): context.update({"errors": form.errors}) return self.render_to_response(context) - billing_address_id = form.cleaned_data.get("billing_address") - shipping_address_id = form.cleaned_data.get("shipping_address") shipping_method_id = form.cleaned_data.get("shipping_method") cart, created = get_or_create_cart(request) - billing_address = get_object_or_404(CustomerAddress, pk=billing_address_id) - shipping_address = get_object_or_404(CustomerAddress, pk=shipping_address_id) + billing_address_full_name = form.cleaned_data.get('billing_address_full_name') + billing_address_address = form.cleaned_data.get('billing_address') + billing_address_town = form.cleaned_data.get('billing_address_town') + billing_address_state = form.cleaned_data.get('billing_address_state') + billing_address_country = form.cleaned_data.get('billing_address_country') + billing_address_zip = form.cleaned_data.get('billing_address_zip') + + shipping_address_full_name = form.cleaned_data.get('shipping_address_full_name') + shipping_address_address = form.cleaned_data.get('shipping_address') + shipping_address_town = form.cleaned_data.get('shipping_address_town') + shipping_address_state = form.cleaned_data.get('shipping_address_state') + shipping_address_country = form.cleaned_data.get('shipping_address_country') + shipping_address_zip = form.cleaned_data.get('shipping_address_zip') + shipping_address_phone = form.cleaned_data.get('shipping_address_phone') + shipping_method = get_object_or_404(ShippingMethod, pk=shipping_method_id) order = create_order_from_cart( cart=cart, - billing_address=billing_address, - shipping_address=shipping_address, shipping_method=shipping_method, + billing_address_full_name=billing_address_full_name, + billing_address_address=billing_address_address, + billing_address_town=billing_address_town, + billing_address_state=billing_address_state, + billing_address_country=billing_address_country, + billing_address_zip=billing_address_zip, + shipping_address_full_name=shipping_address_full_name, + shipping_address_address=shipping_address_address, + shipping_address_town=shipping_address_town, + shipping_address_state=shipping_address_state, + shipping_address_country=shipping_address_country, + shipping_address_zip=shipping_address_zip, + shipping_address_phone=shipping_address_phone, ) - return redirect(reverse("web:order", kwargs={"pk": order.pk})) + return redirect(reverse("web:order", kwargs={"uuid": order.uuid})) + + +class OrderDetail(TemplateView): + template_name = "web/order.html" + + def get_context_data(self, **kwargs): + order = get_object_or_404(Order, uuid=kwargs.get("uuid")) + items = OrderLine.objects.filter(order=order) + return { + "order": order, + "items": items, + } class WishlistView(TemplateView): @@ -237,4 +273,5 @@ index = IndexView.as_view() category_view = CategoryView.as_view() product_detail = ProductDetail.as_view() cart_detail = CartDetail.as_view() +order_detail = OrderDetail.as_view() wishlist = WishlistView.as_view()