from django import http from django.contrib.auth.mixins import UserPassesTestMixin from django.shortcuts import get_object_or_404, render from django.urls import reverse, reverse_lazy from django.views import generic from la_chariotte.mail.utils import send_order_confirmation_mail from ..models import GroupedOrder, Order, OrderAuthor, OrderedItem def place_order(request, code): # Creates an AnonymousUser and an Order with related OrderedItems grouped_order = get_object_or_404(GroupedOrder, code=code) # Handle permissions user_is_orga = request.user == grouped_order.orga is_to_be_delivered = grouped_order.is_to_be_delivered() is_open = grouped_order.is_open() access_allowed = is_open or (user_is_orga and is_to_be_delivered) if not access_allowed: return http.HttpResponseForbidden() # get a dict with quantity_{{item_id}}:[ {{ quantity on phone }},{{ quantity on desktop }} ] orders_dict = { key: request.POST.getlist(key) for key, value in request.POST.items() if key.startswith("quantity") } # transform it into quantity_{{item_id}}: {{ greatest of the two quantities }} for i in orders_dict: value = ( orders_dict[i][0] if orders_dict[i][0] >= orders_dict[i][1] else orders_dict[i][1] ) orders_dict[i] = value # create an order first_name = request.POST["first_name"] last_name = request.POST["last_name"] phone = request.POST["phone"] email = request.POST["email"] note = request.POST["note"] author = OrderAuthor.objects.create( first_name=first_name, last_name=last_name, email=email, phone=phone ) order = Order.objects.create(author=author, grouped_order=grouped_order, note=note) # add items to the order error_message = None for key, quantity in orders_dict.items(): quantity = int(quantity) item = grouped_order.item_set.get(pk=key.split("_")[1]) # check if too many items are ordered error_message = validate_item_ordered_nb(item, quantity) if error_message: break # stop creating items if there is an error if quantity > 0: OrderedItem.objects.create(nb=quantity, order=order, item=item) # Redisplay the form with error messages if there is an error if error_message: order.delete() author.delete() grouped_order.compute_items_ordered_nb() return render( request, "order/grouped_order_detail.html", { "grouped_order": grouped_order, "error_message": error_message, "note": order.note, "author": author, }, ) # check if the order contains articles error_message = validate_articles_ordered_nb(order) # Redisplay the form with error messages if there is an error if error_message: order.delete() author.delete() return render( request, "order/grouped_order_detail.html", { "grouped_order": grouped_order, "error_message": error_message, "note": order.note, "author": author, }, ) # Send confirmation mail and redirect to confirmation page order.compute_order_price() grouped_order.compute_items_ordered_nb() send_order_confirmation_mail(order) # Redirect to prevent data from being posted twice when the user hits the Back # button. return http.HttpResponseRedirect( reverse("order:order_confirm", args=(grouped_order.code, order.pk)) ) def validate_item_ordered_nb(item, ordered_nb): """Returns an error message if the ordered items are not available""" if item.get_remaining_nb() is not None and item.get_remaining_nb() - ordered_nb < 0: return f"Trop de {item.name} commandés pour la quantité disponible" return None def validate_articles_ordered_nb(order): """Return an error if no items are ordered""" order.compute_order_articles_nb() if order.articles_nb == 0: return "Veuillez commander au moins un produit" return None class OrderDetailView(generic.DetailView): model = Order class OrderDeleteView(UserPassesTestMixin, generic.DeleteView): model = Order def get_success_url(self): return reverse_lazy( "order:grouped_order_overview", args=[self.object.grouped_order.code] ) def test_func(self): """Accessible only if the requesting user is the grouped order organizer""" return self.get_object().grouped_order.orga == self.request.user