from decimal import Decimal from django.db.models import Sum from django.http.response import HttpResponse, JsonResponse from django.shortcuts import get_object_or_404, redirect, reverse from django.utils.text import gettext_lazy as _ from django.views.decorators.http import require_http_methods from django.views.generic import CreateView, TemplateView from shop.models import ( CartItem, Order, OrderLine, Product, ProductCategory, ShippingMethod, WishlistedProduct, ) from shop.redsys import RedsysClient from shop.utils import create_order_from_cart from web.forms import CreateOrderForm from web.mixins import FilteredQuerysetMixin, PaginatedQuerysetMixin from web.models import WebSettings from web.settings import ANONYMOUS_CART_ID_COOKIE_NAME from web.utils import get_or_create_cart class IndexView(TemplateView): template_name = "web/index.html" def get_context_data(self, **kwargs): settings = WebSettings.load() return { "title": settings.web_title, "description": settings.web_description, } class CategoryView(TemplateView): template_name = "web/index.html" def get_context_data(self, **kwargs): settings = WebSettings.load() slug = kwargs.get("slug") category = ProductCategory.objects.get(slug=slug) return { "title": _(f"{settings.web_title} - {category.name}"), "description": settings.web_description, "category": category, "filter_by_category": True, } class ProductDetail(TemplateView): template_name = "web/product_detail.html" def get_context_data(self, pk, slug, **kwargs): settings = WebSettings.load() product = get_object_or_404(Product, pk=pk) return { "product": product, "title": f"{settings.web_title} - {product.name}", "description": product.description, "image": product.images.first(), } class CartDetail(TemplateView, CreateView): template_name = "web/cart_detail.html" form_class = CreateOrderForm def get_context_data(self, **kwargs): web_settings = WebSettings.load() cart, created = get_or_create_cart(self.request) cart_items = CartItem.objects.filter(cart=cart).prefetch_related("product") return { "title": web_settings.web_title, "cart": cart, "items": cart_items, "description": _("resumen del carrito"), } def post(self, request, *args, **kwargs): form = CreateOrderForm(request.POST) if not form.is_valid(): context = self.get_context_data(**kwargs) context.update({"errors": form.errors}) return self.render_to_response(context) shipping_method_id = form.cleaned_data.get("shipping_method") cart, created = get_or_create_cart(request) 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") email = form.cleaned_data.get("email") shipping_method = get_object_or_404(ShippingMethod, pk=shipping_method_id) order = create_order_from_cart( cart=cart, 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, email=email, ) 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")) redsys_client = RedsysClient() parameters = redsys_client.get_body_for_order(order) items = OrderLine.objects.select_related("product").filter( order=order, product__is_shipping_method=False ) shipping_cost = OrderLine.objects.select_related("product").filter( order=order, product__is_shipping_method=True, ).aggregate(amount=Sum("total")).get("amount") or Decimal("0") base_total = OrderLine.objects.select_related("product").filter( order=order, product__is_shipping_method=False, ).aggregate(amount=Sum("base_total")).get("amount") or Decimal("0") tax_total = OrderLine.objects.select_related("product").filter( order=order, product__is_shipping_method=False, ).aggregate(amount=Sum("taxes")).get("amount") or Decimal("0") settings = WebSettings.load() return { "order": order, "items": items, "signature_version": parameters.get("Ds_SignatureVersion"), "merchant_parameters": parameters.get("Ds_MerchantParameters"), "signature": parameters.get("Ds_Signature"), "redsys_target_url": redsys_client.get_target_url(), "total": round(order.total, 2), "base_total": round(base_total, 2), "tax_total": round(tax_total, 2), "shipping_cost": round(shipping_cost, 2), } class WishlistView(TemplateView): template_name = "web/wishlist.html" def get_context_data(self, **kwargs): settings = WebSettings.load() return { "title": settings.web_title, "description": settings.web_description, } class OrdersView(TemplateView, FilteredQuerysetMixin, PaginatedQuerysetMixin): template_name = "web/orders.html" def get_queryset(self): return Order.objects.filter(user=self.request.user).exclude( status=Order.Statuses.STATUS_PENDING ) def get_context_data(self, **kwargs): settings = WebSettings.load() qs = self.get_queryset() page = self.get_paginated_queryset(qs) return { "title": settings.web_title, "page": page, "has_next_page": page.has_next(), "has_previous_page": page.has_previous(), } @require_http_methods( [ "POST", ] ) def add_cart_item(request, *args, **kwargs): product = get_object_or_404(Product, pk=request.POST.get("product")) cart, created = get_or_create_cart(request) response = HttpResponse(status=201, headers={"HX-Trigger": "updated-cart"}) if created and request.user.is_anonymous: response.set_cookie(ANONYMOUS_CART_ID_COOKIE_NAME, cart.uuid) # Comprobamos si existe una línea de carrito para ese carrito de ese producto existing_cart_item = CartItem.objects.filter(cart=cart, product=product).first() # Si existe, simplemente le sumamos la cantidad a la línea ya existente if existing_cart_item is not None: existing_cart_item.quantity += int(request.POST.get("quantity")) existing_cart_item.save() # Si no, lo creamos else: CartItem.objects.create( cart=cart, quantity=request.POST.get("quantity"), product=product, ) return response @require_http_methods( [ "POST", ] ) def delete_cart_item(request, pk, *args, **kwargs): cart, created = get_or_create_cart(request) cart_item = get_object_or_404(CartItem, pk=pk, cart=cart) cart_item.delete() return HttpResponse(status=204, headers={"HX-Trigger": "updated-cart"}) @require_http_methods( [ "POST", ] ) def add_to_wishlist(request, *args, **kwargs): product = get_object_or_404(Product, pk=request.POST.get("product")) response = HttpResponse(status=201, headers={"HX-Trigger": "updated-wishlist"}) if request.user.is_anonymous: return HttpResponse(status=400) WishlistedProduct.objects.get_or_create( user=request.user, product=product, ) return response @require_http_methods( [ "POST", ] ) def delete_from_wishlist(request, pk, *args, **kwargs): wishlisted_item = get_object_or_404( WishlistedProduct, product_id=pk, user=request.user ) wishlisted_item.delete() return HttpResponse(status=204, headers={"HX-Trigger": "updated-wishlist"}) def manifest(request, *args, **kwargs): settings = WebSettings.load() data = { "name": settings.web_title, "short_name": settings.web_title, "start_url": "/", "background_color": settings.bg_color, "theme_color": settings.theme_color, "icons": [], "display": "standalone", "orientation": "portrait", } if settings.logo_240: data["icons"].append( { "src": settings.logo_240.url, "sizes": "240x240", "type": "image/png", "purpose": "maskable any", } ) if settings.logo_128: data["icons"].append( { "src": settings.logo_128.url, "sizes": "240x240", "type": "image/png", "purpose": "maskable any", } ) return JsonResponse(data) 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() orders = OrdersView.as_view()