From f32987457dd47126fbfbbdb3119f52c0774bfb71 Mon Sep 17 00:00:00 2001 From: Laetitia Getti Date: Tue, 4 Jul 2023 11:39:45 +0200 Subject: [PATCH] separate views into several files --- la_chariotte/order/views/__init__.py | 10 ++ .../{views.py => views/grouped_order.py} | 164 +----------------- la_chariotte/order/views/item.py | 38 ++++ la_chariotte/order/views/order.py | 114 ++++++++++++ 4 files changed, 166 insertions(+), 160 deletions(-) create mode 100644 la_chariotte/order/views/__init__.py rename la_chariotte/order/{views.py => views/grouped_order.py} (59%) create mode 100644 la_chariotte/order/views/item.py create mode 100644 la_chariotte/order/views/order.py diff --git a/la_chariotte/order/views/__init__.py b/la_chariotte/order/views/__init__.py new file mode 100644 index 0000000..17a0865 --- /dev/null +++ b/la_chariotte/order/views/__init__.py @@ -0,0 +1,10 @@ +# fmt: off +from .grouped_order import (ExportGroupedOrderEmailAddressesToCSVView, + GroupedOrderAddItemsView, GroupedOrderCreateView, + GroupedOrderDetailView, GroupedOrderOverview, + GroupedOrderSheetView, GroupedOrderUpdateView, + IndexView) +from .item import ItemCreateView, ItemDeleteView +from .order import OrderDetailView, order + +# fmt: on diff --git a/la_chariotte/order/views.py b/la_chariotte/order/views/grouped_order.py similarity index 59% rename from la_chariotte/order/views.py rename to la_chariotte/order/views/grouped_order.py index 099f6ee..a8e9576 100644 --- a/la_chariotte/order/views.py +++ b/la_chariotte/order/views/grouped_order.py @@ -3,16 +3,15 @@ from io import BytesIO from django import http from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin -from django.core.exceptions import ValidationError -from django.shortcuts import get_object_or_404, render +from django.shortcuts import get_object_or_404 from django.template.loader import get_template -from django.urls import reverse, reverse_lazy +from django.urls import reverse from django.utils import timezone from django.views import generic from xhtml2pdf import pisa -from .forms import GroupedOrderForm, ItemCreateForm -from .models import GroupedOrder, Item, Order, OrderAuthor, OrderedItem +from ..forms import GroupedOrderForm, Item +from ..models import GroupedOrder, OrderAuthor class IndexView(LoginRequiredMixin, generic.ListView): @@ -148,146 +147,6 @@ class GroupedOrderAddItemsView(UserPassesTestMixin, generic.ListView): return GroupedOrder.objects.get(pk=grouped_order_id).orga == self.request.user -class ItemCreateView(UserPassesTestMixin, generic.CreateView): - """CreateView for an item""" - - model = Item - form_class = ItemCreateForm - - def get_form_kwargs(self): - kwargs = super().get_form_kwargs() - kwargs["grouped_order"] = GroupedOrder.objects.get(id=self.kwargs.get("pk")) - return kwargs - - def test_func(self): - """Accessible only if the requesting user is the grouped order organizer""" - grouped_order_id = self.kwargs.get("pk") - return GroupedOrder.objects.get(pk=grouped_order_id).orga == self.request.user - - -class ItemDeleteView(UserPassesTestMixin, generic.DeleteView): - """DeleteView for an item - The form does a GET to this view - it displays a confirmation page - then we post this view - """ - - model = Item - - def get_success_url(self): - return reverse_lazy("order:manage_items", args=[self.object.grouped_order.id]) - - 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 - - -def order(request, grouped_order_id): - """Creates an AnonymousUser, and an Order for this GroupedOrder, with related OrderedItems""" - grouped_order = get_object_or_404(GroupedOrder, pk=grouped_order_id) - - # check if the grouped order is ongoing - if not grouped_order.is_ongoing(): - 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"] - 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) - - # 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, - }, - ) - - # 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, - }, - ) - - # Redirect to confirmation page - order.compute_order_price() - grouped_order.compute_items_ordered_nb() - # Always return an http.HttpResponseRedirect after successfully dealing - # with POST data. This prevents data from being posted twice if a - # user hits the Back button. - return http.HttpResponseRedirect( - reverse("order:order_confirm", args=(grouped_order.pk, 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): - """Confirmation page after a user orders""" - - model = Order - - class GroupedOrderSheetMixin: """Mixin for grouped order info export (pdf sheet and csv)""" @@ -361,18 +220,3 @@ class ExportGroupedOrderEmailAddressesToCSVView(UserPassesTestMixin, generic.Vie row = [participant.email for participant in participants] writer.writerow(row) return response - - -# def export_grouped_order_email_addresses_to_csv(request, grouped_order_id): -# """Exports a csv list of participants email addresses - only for the organizer""" - -# # Check if the user is orga -# if request.user -# grouped_order = get_object_or_404(GroupedOrder, pk=grouped_order_id) -# participants = OrderAuthor.objects.filter(order__in=grouped_order.order_set.all()) - -# response = http.HttpResponse(content_type="text/csv", headers={'Content-Disposition': f'attachment; filename="{ grouped_order.name }-mails.csv"'},) -# writer = csv.writer(response) -# row = [participant.email for participant in participants] -# writer.writerow(row) -# return response diff --git a/la_chariotte/order/views/item.py b/la_chariotte/order/views/item.py new file mode 100644 index 0000000..8d8556f --- /dev/null +++ b/la_chariotte/order/views/item.py @@ -0,0 +1,38 @@ +from django.contrib.auth.mixins import UserPassesTestMixin +from django.urls import reverse_lazy +from django.views import generic + +from ..forms import ItemCreateForm +from ..models import GroupedOrder, Item + + +class ItemCreateView(UserPassesTestMixin, generic.CreateView): + """CreateView for an item""" + + model = Item + form_class = ItemCreateForm + + def get_form_kwargs(self): + kwargs = super().get_form_kwargs() + kwargs["grouped_order"] = GroupedOrder.objects.get(id=self.kwargs.get("pk")) + return kwargs + + def test_func(self): + """Accessible only if the requesting user is the grouped order organizer""" + grouped_order_id = self.kwargs.get("pk") + return GroupedOrder.objects.get(pk=grouped_order_id).orga == self.request.user + + +class ItemDeleteView(UserPassesTestMixin, generic.DeleteView): + """DeleteView for an item + The form does a GET to this view - it displays a confirmation page - then we post this view + """ + + model = Item + + def get_success_url(self): + return reverse_lazy("order:manage_items", args=[self.object.grouped_order.id]) + + 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 diff --git a/la_chariotte/order/views/order.py b/la_chariotte/order/views/order.py new file mode 100644 index 0000000..755a1ae --- /dev/null +++ b/la_chariotte/order/views/order.py @@ -0,0 +1,114 @@ +from django import http +from django.shortcuts import get_object_or_404, render +from django.urls import reverse +from django.views import generic + +from ..models import GroupedOrder, Order, OrderAuthor, OrderedItem + + +def order(request, grouped_order_id): + """Creates an AnonymousUser, and an Order for this GroupedOrder, with related OrderedItems""" + grouped_order = get_object_or_404(GroupedOrder, pk=grouped_order_id) + + # check if the grouped order is ongoing + if not grouped_order.is_ongoing(): + 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"] + 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) + + # 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, + }, + ) + + # 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, + }, + ) + + # Redirect to confirmation page + order.compute_order_price() + grouped_order.compute_items_ordered_nb() + # Always return an http.HttpResponseRedirect after successfully dealing + # with POST data. This prevents data from being posted twice if a + # user hits the Back button. + return http.HttpResponseRedirect( + reverse("order:order_confirm", args=(grouped_order.pk, 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): + """Confirmation page after a user orders""" + + model = Order