mirror of
https://framagit.org/la-chariotte/la-chariotte.git
synced 2025-05-01 11:22:24 +02:00

When a grouped_order_detail view was called with authenticated user, when prefilling the firstName, lastName and email also inserted a new OrderAuthor object in the database. Now use SimpleNamespace, instead of OrderAuthor object, to carry those values to the template.
411 lines
15 KiB
Python
411 lines
15 KiB
Python
import csv
|
|
import json
|
|
from types import SimpleNamespace
|
|
|
|
from django import http
|
|
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
|
|
from django.core.serializers.json import DjangoJSONEncoder
|
|
from django.shortcuts import get_object_or_404, redirect
|
|
from django.urls import reverse, reverse_lazy
|
|
from django.utils import timezone
|
|
from django.views import generic
|
|
from django_weasyprint import WeasyTemplateResponseMixin
|
|
from icalendar import Calendar, Event, vCalAddress, vText
|
|
|
|
from ..forms import GroupedOrderForm, Item, JoinGroupedOrderForm
|
|
from ..models import GroupedOrder, OrderAuthor
|
|
from .mixins import UserIsOrgaMixin
|
|
|
|
|
|
class IndexView(LoginRequiredMixin, generic.ListView):
|
|
"""View showing all the grouped orders managed by the authenticated user"""
|
|
|
|
template_name = "order/index.html"
|
|
context_object_name = "grouped_order_list"
|
|
|
|
def get_queryset(self):
|
|
grouped_orders = GroupedOrder.objects.filter(orga=self.request.user)
|
|
|
|
now = timezone.now()
|
|
today = now.date()
|
|
|
|
# Get the 5 most recent old grouped orders
|
|
old = grouped_orders.filter(delivery_date__lt=today).order_by("-delivery_date")[
|
|
:5
|
|
]
|
|
|
|
# Get grouped orders that have crossed their ordering deadline
|
|
# but the delivery date is still to come.
|
|
crossed_deadline = (
|
|
grouped_orders.filter(delivery_date__gte=today)
|
|
.filter(deadline__lt=now)
|
|
.order_by("-delivery_date")
|
|
)
|
|
|
|
# Get all incoming grouped orders.
|
|
incoming = grouped_orders.filter(deadline__gte=now).order_by("deadline")
|
|
return {
|
|
"old_grouped_orders": old,
|
|
"crossed_deadline_grouped_orders": crossed_deadline,
|
|
"incoming_grouped_orders": incoming,
|
|
}
|
|
|
|
|
|
class JoinGroupedOrderView(generic.FormView, generic.RedirectView, LoginRequiredMixin):
|
|
form_class = JoinGroupedOrderForm
|
|
template_name = "dashboard.html"
|
|
|
|
def form_valid(self, form):
|
|
return redirect(
|
|
reverse_lazy(
|
|
"order:grouped_order_detail", kwargs={"code": form.cleaned_data["code"]}
|
|
)
|
|
)
|
|
|
|
|
|
class GroupedOrderEventView(generic.DetailView):
|
|
model = GroupedOrder
|
|
slug_field = "code"
|
|
slug_url_kwarg = "code"
|
|
content_type = "text/calendar"
|
|
response_class = http.HttpResponse
|
|
|
|
def get_content(self):
|
|
event = Event()
|
|
event.add("summary", self.object.name)
|
|
event.add("dtstart", self.object.delivery_date)
|
|
event.add("dtend", self.object.delivery_date)
|
|
event.add("date", self.object.delivery_date)
|
|
event.add("location", vText(self.object.place))
|
|
|
|
description = ""
|
|
if self.object.delivery_slot:
|
|
description += "Heure de livraison : " + self.object.delivery_slot + "\n"
|
|
if self.object.description:
|
|
description += (
|
|
"Note de l'organisateur.ice : " + "\n" + self.object.description
|
|
)
|
|
event.add("description", vText(description))
|
|
|
|
organizer = vCalAddress("MAILTO:" + self.object.orga.email)
|
|
organizer.params["cn"] = vText(
|
|
self.object.orga.first_name + " " + self.object.orga.last_name
|
|
)
|
|
event.add("organizer", organizer)
|
|
cal = Calendar()
|
|
cal.add_component(event)
|
|
return cal.to_ical()
|
|
|
|
def render_to_response(self, context, **response_kwargs):
|
|
response_kwargs.setdefault("content_type", self.content_type)
|
|
|
|
response = self.response_class(content=self.get_content(), **response_kwargs)
|
|
response["Content-Disposition"] = f"attachment; filename={self.object.name}.ics"
|
|
return response
|
|
|
|
|
|
class GroupedOrderDetailView(generic.DetailView):
|
|
model = GroupedOrder
|
|
template_name = "order/grouped_order_detail.html"
|
|
context_object_name = "grouped_order"
|
|
|
|
def get_object(self, queryset=None):
|
|
return get_object_or_404(GroupedOrder, code=self.kwargs.get("code"))
|
|
|
|
def get_context_data(self, **kwargs):
|
|
items = self.get_object().item_set.all()
|
|
|
|
remaining_qty = {item.id: item.get_remaining_nb() for item in items}
|
|
prices_dict = {item.id: item.price for item in items}
|
|
|
|
if self.request.user.is_authenticated:
|
|
order_author = SimpleNamespace(
|
|
first_name=self.request.user.first_name,
|
|
last_name=self.request.user.last_name,
|
|
email=self.request.user.username,
|
|
)
|
|
else:
|
|
order_author = None
|
|
|
|
context = super().get_context_data(**kwargs)
|
|
context.update(
|
|
{
|
|
# Used for the js display of total price of an order
|
|
"prices_dict": json.dumps(prices_dict, cls=DjangoJSONEncoder),
|
|
"remaining_qty": remaining_qty,
|
|
"order_author": order_author,
|
|
}
|
|
)
|
|
return context
|
|
|
|
|
|
class GroupedOrderOverview(UserIsOrgaMixin, generic.DetailView):
|
|
model = GroupedOrder
|
|
template_name = "order/grouped_order_overview.html"
|
|
context_object_name = "grouped_order"
|
|
|
|
def get_object(self, queryset=None):
|
|
return get_object_or_404(GroupedOrder, code=self.kwargs.get("code"))
|
|
|
|
def test_func(self):
|
|
# Staff can see but not edit grouped orders
|
|
return super().test_func() or self.request.user.is_staff
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
# Compute grouped order total price before display
|
|
self.get_object().compute_total_price()
|
|
self.get_object().compute_items_ordered_nb()
|
|
return super().get(self, request, *args, **kwargs)
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(GroupedOrderOverview, self).get_context_data(**kwargs)
|
|
# Add share link to context
|
|
context["share_link"] = self.request.build_absolute_uri(
|
|
reverse("order:grouped_order_detail", args=(self.get_object().code,))
|
|
)
|
|
participants = OrderAuthor.objects.filter(
|
|
order__in=self.get_object().order_set.all()
|
|
)
|
|
context["emails_list"] = set(participant.email for participant in participants)
|
|
context["total_ordered_items"] = self.get_object().get_total_ordered_items()
|
|
return context
|
|
|
|
|
|
class GroupedOrderCreateView(LoginRequiredMixin, generic.CreateView):
|
|
model = GroupedOrder
|
|
form_class = GroupedOrderForm
|
|
template_name = "order/grouped_order_create.html"
|
|
|
|
def get_form_kwargs(self):
|
|
kwargs = super().get_form_kwargs()
|
|
kwargs["user"] = self.request.user
|
|
return kwargs
|
|
|
|
def form_valid(self, form):
|
|
"""If the form is valid, generate a unique code and save"""
|
|
self.object = form.save()
|
|
self.object.create_code_from_pk()
|
|
return super().form_valid(form)
|
|
|
|
|
|
class GroupedOrderUpdateView(UserIsOrgaMixin, generic.UpdateView):
|
|
model = GroupedOrder
|
|
template_name = "order/grouped_order_update.html"
|
|
context_object_name = "grouped_order"
|
|
form_class = GroupedOrderForm
|
|
|
|
def get_object(self, queryset=None):
|
|
return get_object_or_404(GroupedOrder, code=self.kwargs.get("code"))
|
|
|
|
def get_form_kwargs(self):
|
|
kwargs = super().get_form_kwargs()
|
|
kwargs["user"] = self.request.user
|
|
return kwargs
|
|
|
|
|
|
class GroupedOrderDuplicateView(UserIsOrgaMixin, generic.RedirectView):
|
|
def get_object(self, queryset=None):
|
|
return get_object_or_404(GroupedOrder, code=self.kwargs.get("code"))
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
# overwrite the ``get`` function to copy the initial grouped order before
|
|
# redirecting to the update view of the new grouped order
|
|
initial_grouped_order = get_object_or_404(
|
|
GroupedOrder, code=self.kwargs.get("code")
|
|
)
|
|
new_grouped_order = GroupedOrder.objects.create(
|
|
name=f"{initial_grouped_order.name} - copie",
|
|
orga=self.request.user,
|
|
delivery_date=initial_grouped_order.delivery_date,
|
|
deadline=initial_grouped_order.deadline,
|
|
place=initial_grouped_order.place,
|
|
description=initial_grouped_order.description,
|
|
)
|
|
|
|
# create a unique code for the new grouped order
|
|
new_grouped_order.create_code_from_pk()
|
|
new_grouped_order.save()
|
|
|
|
# duplicate each item and add it to new_grouped_order
|
|
for item in initial_grouped_order.item_set.all():
|
|
item.pk = None
|
|
item.ordered_nb = 0
|
|
item.save()
|
|
new_grouped_order.item_set.add(item)
|
|
|
|
self.kwargs["new_go_code"] = new_grouped_order.code
|
|
|
|
return super().get(request, *args, **kwargs)
|
|
|
|
def get_redirect_url(self, *args, **kwargs):
|
|
return reverse_lazy(
|
|
"order:update_grouped_order", kwargs={"code": self.kwargs["new_go_code"]}
|
|
)
|
|
|
|
|
|
class GroupedOrderDeleteView(UserIsOrgaMixin, generic.DeleteView):
|
|
model = GroupedOrder
|
|
template_name = "order/grouped_order_confirm_delete.html"
|
|
context_object_name = "grouped_order"
|
|
|
|
def get_object(self, queryset=None):
|
|
return get_object_or_404(GroupedOrder, code=self.kwargs.get("code"))
|
|
|
|
def get_success_url(self):
|
|
return reverse_lazy("order:index")
|
|
|
|
def form_valid(self, form):
|
|
# Delete related OrderAuthors
|
|
grouped_order = self.get_object()
|
|
for order in grouped_order.order_set.all():
|
|
order.author.delete()
|
|
return super().form_valid(form)
|
|
|
|
|
|
class GroupedOrderAddItemsView(UserPassesTestMixin, generic.ListView):
|
|
model = Item
|
|
template_name = "order/grouped_order_add_items.html"
|
|
queryset = Item.objects.all()
|
|
|
|
def get_queryset(self):
|
|
items = super().get_queryset()
|
|
items = items.filter(grouped_order__code=self.kwargs.get("code"))
|
|
return items
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(GroupedOrderAddItemsView, self).get_context_data(**kwargs)
|
|
context["grouped_order"] = GroupedOrder.objects.get(
|
|
code=self.kwargs.get("code")
|
|
)
|
|
return context
|
|
|
|
def test_func(self):
|
|
# Restrict access to the manager
|
|
grouped_order = get_object_or_404(GroupedOrder, code=self.kwargs.get("code"))
|
|
return grouped_order.orga == self.request.user
|
|
|
|
|
|
class GroupedOrderExportView(UserIsOrgaMixin, generic.DetailView):
|
|
model = GroupedOrder
|
|
template_name = "order/grouped_order_sheet.html"
|
|
context_object_name = "grouped_order"
|
|
|
|
def test_func(self):
|
|
# Grouped order orga, superuser and staff can get this view
|
|
return super().test_func() or self.request.user.is_staff
|
|
|
|
def get_object(self, queryset=None):
|
|
return get_object_or_404(GroupedOrder, code=self.kwargs.get("code"))
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(GroupedOrderExportView, self).get_context_data(**kwargs)
|
|
grouped_order = self.get_object()
|
|
|
|
items = grouped_order.item_set.filter(ordered_nb__gt=0).order_by("name")
|
|
orders = grouped_order.order_set.all().order_by(
|
|
"author__last_name", "author__first_name"
|
|
)
|
|
orders_dict = {}
|
|
|
|
for order in orders:
|
|
ordered_values = []
|
|
for item in items:
|
|
match = order.ordered_items.filter(item=item).first()
|
|
value = match.nb if match else 0
|
|
ordered_values.append(value)
|
|
orders_dict[order] = ordered_values
|
|
|
|
context["items"] = items
|
|
context["orders_dict"] = orders_dict
|
|
|
|
return context
|
|
|
|
|
|
class DownloadGroupedOrderSheetView(WeasyTemplateResponseMixin, GroupedOrderExportView):
|
|
def get_pdf_filename(self):
|
|
# This is the name of the file that will be generated to download.
|
|
return f"{self.get_object().delivery_date} - {self.get_object().name}"
|
|
|
|
|
|
class ExportGroupOrderEmailAdressesToDownloadView(UserPassesTestMixin, generic.View):
|
|
def test_func(self):
|
|
# Restrict access to the manager, superuser and staff
|
|
origin = get_object_or_404(GroupedOrder, code=self.kwargs.get("code"))
|
|
return origin.orga == self.request.user or self.request.user.is_staff
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
grouped_order = get_object_or_404(GroupedOrder, code=self.kwargs.get("code"))
|
|
participants = OrderAuthor.objects.filter(
|
|
order__in=grouped_order.order_set.all()
|
|
)
|
|
email_list = set(participant.email for participant in participants)
|
|
|
|
format = self.request.GET.get("format", "json")
|
|
if format == "csv":
|
|
response = http.HttpResponse(content_type="text/csv")
|
|
filename = f"commande _{grouped_order.name.replace(' ', '_')}"
|
|
response["Content-Disposition"] = f'attachment; filename="{filename}.csv"'
|
|
writer = csv.writer(response)
|
|
for email in email_list:
|
|
writer.writerow([email])
|
|
return response
|
|
else:
|
|
email_list = ";\n".join(email_list)
|
|
return http.HttpResponse(f"{email_list}")
|
|
|
|
|
|
class ExportGroupedOrderToCSVView(GroupedOrderExportView):
|
|
def get(self, request, *args, **kwargs):
|
|
super(ExportGroupedOrderToCSVView, self).get(self, request, *args, **kwargs)
|
|
context = self.get_context_data()
|
|
|
|
response = http.HttpResponse(
|
|
content_type="text/csv",
|
|
headers={
|
|
"Content-Disposition": f'attachment; filename="{ context["object"].name }-commandes"'
|
|
},
|
|
)
|
|
writer = csv.writer(response)
|
|
|
|
# write headers rows
|
|
row = ["", ""]
|
|
for item in context["items"]:
|
|
row.append(item.name)
|
|
row.append("Prix de la commande")
|
|
row.append("Mail")
|
|
row.append("Téléphone")
|
|
row.append("Note")
|
|
row.append("Date")
|
|
row.append("Heure")
|
|
writer.writerow(row)
|
|
|
|
row = ["", "Prix unitaire TTC (€)"]
|
|
for item in context["items"]:
|
|
row.append(str(item.price).replace(".", ","))
|
|
writer.writerow(row)
|
|
|
|
row = ["Nom", "Prénom"]
|
|
writer.writerow(row)
|
|
|
|
# write ordered values rows
|
|
for order, ordered_items in context["orders_dict"].items():
|
|
row = [order.author.last_name]
|
|
row.append(order.author.first_name)
|
|
for ordered_nb in ordered_items:
|
|
row.append(ordered_nb)
|
|
row.append(str(order.price).replace(".", ","))
|
|
row.append(order.author.email)
|
|
row.append(f"'{order.author.phone}")
|
|
row.append(order.note)
|
|
row.append(order.created_date.strftime("%d/%m/%Y"))
|
|
row.append(order.created_date.strftime("%H:%M"))
|
|
writer.writerow(row)
|
|
|
|
# write total row
|
|
row = ["", "TOTAL"]
|
|
for item in context["items"]:
|
|
row.append(item.ordered_nb)
|
|
row.append(str(context["object"].total_price).replace(".", ","))
|
|
writer.writerow(row)
|
|
|
|
return response
|