la-chariotte/la_chariotte/order/views/order.py

196 lines
6.3 KiB
Python

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.utils import timezone
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
error_message = None
first_name = request.POST["first_name"]
last_name = request.POST["last_name"]
note = request.POST["note"]
# check if required/optional phone is supplied
# When not supplied, use "" because the order_author table phone has a NOT NULL statement
error_message = None
if grouped_order.required_phone == 0:
phone = ""
else:
if "phone" in request.POST and request.POST["phone"] != "":
# Phone is supplied, whether required or not
phone = request.POST["phone"]
elif grouped_order.required_phone == 2:
# Phone is not supplied, but was required
error_message = (
"Le numéro de téléphone est obligatoire pour cette commande groupée"
)
phone = ""
else:
# Phone is not supplied, but was not mandatory
phone = ""
# check if required/optional email is supplied
# When not supplied, use "" because the order_author table email has a NOT NULL statement
if grouped_order.required_email == 0:
email = ""
else:
if "email" in request.POST and request.POST["email"] != "":
# email is supplied, whether required or not
email = request.POST["email"]
elif grouped_order.required_email == 2:
# email is not supplied, but was required
error_message = (
"L'adresse email est obligatoire pour cette commande groupée"
)
email = ""
else:
# email is not supplied, but was not mandatory
email = ""
# create an author
author = OrderAuthor.objects.create(
first_name=first_name, last_name=last_name, email=email, phone=phone
)
if error_message:
author.delete()
return render(
request,
"order/grouped_order_detail.html",
{
"grouped_order": grouped_order,
"error_message": error_message,
"note": note,
"author": author,
},
)
# create an order
order = Order.objects.create(
author=author,
grouped_order=grouped_order,
note=note,
created_date=timezone.now(),
)
# add items to the order
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()
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
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"""
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):
# Restrict access to the manager or a superuser
return (
self.get_object().grouped_order.orga == self.request.user
or self.request.user.is_superuser
)