Sith/counter/views/admin.py

290 lines
9.5 KiB
Python
Raw Normal View History

#
# Copyright 2023 © AE UTBM
# ae@utbm.fr / ae.info@utbm.fr
#
# This file is part of the website of the UTBM Student Association (AE UTBM),
# https://ae.utbm.fr.
#
# You can find the source code of the website at https://github.com/ae-utbm/sith
#
# LICENSED UNDER THE GNU GENERAL PUBLIC LICENSE VERSION 3 (GPLv3)
2024-09-23 08:25:27 +00:00
# SEE : https://raw.githubusercontent.com/ae-utbm/sith/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
#
#
2024-10-13 10:32:50 +00:00
import itertools
2024-11-27 17:42:26 +00:00
from datetime import timedelta
2024-10-19 22:27:25 +00:00
from operator import itemgetter
2024-06-24 11:07:36 +00:00
from django.conf import settings
from django.core.exceptions import PermissionDenied
from django.db.models import F
2024-06-24 11:07:36 +00:00
from django.forms import CheckboxSelectMultiple
from django.forms.models import modelform_factory
2024-11-27 17:42:26 +00:00
from django.shortcuts import get_object_or_404
2024-06-24 11:07:36 +00:00
from django.urls import reverse, reverse_lazy
from django.utils import timezone
2024-11-27 17:42:26 +00:00
from django.views.generic import DetailView, ListView
from django.views.generic.edit import CreateView, DeleteView, UpdateView
2024-06-24 11:07:36 +00:00
from core.utils import get_semester_code, get_start_of_semester
2024-11-27 17:42:26 +00:00
from core.views import CanEditMixin, CanViewMixin
from counter.forms import CounterEditForm, ProductEditForm
from counter.models import Counter, Product, ProductType, Refilling, Selling
2024-08-05 08:46:15 +00:00
from counter.utils import is_logged_in_counter
2024-11-27 18:02:48 +00:00
from counter.views.mixins import CounterAdminMixin, CounterAdminTabsMixin
2016-03-28 12:54:35 +00:00
2016-09-28 09:07:32 +00:00
class CounterListView(CounterAdminTabsMixin, CanViewMixin, ListView):
2024-07-12 07:34:16 +00:00
"""A list view for the admins."""
2018-10-04 19:29:19 +00:00
2016-03-31 08:36:00 +00:00
model = Counter
2018-10-04 19:29:19 +00:00
template_name = "counter/counter_list.jinja"
current_tab = "counters"
2017-06-12 07:47:24 +00:00
2017-04-04 13:45:02 +00:00
class CounterEditView(CounterAdminTabsMixin, CounterAdminMixin, UpdateView):
2024-07-12 07:34:16 +00:00
"""Edit a counter's main informations (for the counter's manager)."""
2018-10-04 19:29:19 +00:00
model = Counter
form_class = CounterEditForm
pk_url_kwarg = "counter_id"
2018-10-04 19:29:19 +00:00
template_name = "core/edit.jinja"
current_tab = "counters"
2017-04-03 11:50:28 +00:00
def dispatch(self, request, *args, **kwargs):
obj = self.get_object()
2017-04-03 13:00:13 +00:00
self.edit_club.append(obj.club)
2024-06-27 12:46:43 +00:00
return super().dispatch(request, *args, **kwargs)
2017-04-03 11:50:28 +00:00
def get_success_url(self):
2018-10-04 19:29:19 +00:00
return reverse_lazy("counter:admin", kwargs={"counter_id": self.object.id})
2017-06-12 07:47:24 +00:00
2017-04-04 13:45:02 +00:00
class CounterEditPropView(CounterAdminTabsMixin, CounterAdminMixin, UpdateView):
2024-07-12 07:34:16 +00:00
"""Edit a counter's main informations (for the counter's admin)."""
2018-10-04 19:29:19 +00:00
2016-03-29 08:30:24 +00:00
model = Counter
2018-10-04 19:29:19 +00:00
form_class = modelform_factory(Counter, fields=["name", "club", "type"])
2016-03-29 08:30:24 +00:00
pk_url_kwarg = "counter_id"
2018-10-04 19:29:19 +00:00
template_name = "core/edit.jinja"
current_tab = "counters"
2016-03-29 08:30:24 +00:00
2017-06-12 07:47:24 +00:00
2017-04-04 13:45:02 +00:00
class CounterCreateView(CounterAdminTabsMixin, CounterAdminMixin, CreateView):
2024-07-12 07:34:16 +00:00
"""Create a counter (for the admins)."""
2018-10-04 19:29:19 +00:00
2016-03-29 08:30:24 +00:00
model = Counter
2018-10-04 19:29:19 +00:00
form_class = modelform_factory(
Counter,
fields=["name", "club", "type", "products"],
widgets={"products": CheckboxSelectMultiple},
)
template_name = "core/create.jinja"
current_tab = "counters"
2016-03-29 08:30:24 +00:00
2017-06-12 07:47:24 +00:00
2017-04-04 13:45:02 +00:00
class CounterDeleteView(CounterAdminTabsMixin, CounterAdminMixin, DeleteView):
2024-07-12 07:34:16 +00:00
"""Delete a counter (for the admins)."""
2018-10-04 19:29:19 +00:00
2016-03-29 08:30:24 +00:00
model = Counter
pk_url_kwarg = "counter_id"
2018-10-04 19:29:19 +00:00
template_name = "core/delete_confirm.jinja"
success_url = reverse_lazy("counter:admin_list")
current_tab = "counters"
2016-03-31 08:36:00 +00:00
2018-10-04 19:29:19 +00:00
2016-07-27 15:23:02 +00:00
# Product management
2017-06-12 07:47:24 +00:00
2017-04-04 13:45:02 +00:00
class ProductTypeListView(CounterAdminTabsMixin, CounterAdminMixin, ListView):
2024-07-12 07:34:16 +00:00
"""A list view for the admins."""
2018-10-04 19:29:19 +00:00
2016-07-27 18:05:45 +00:00
model = ProductType
2024-12-18 11:16:24 +00:00
template_name = "counter/product_type_list.jinja"
current_tab = "product_types"
2024-12-18 11:16:24 +00:00
context_object_name = "product_types"
2016-07-27 18:05:45 +00:00
2017-06-12 07:47:24 +00:00
2017-04-04 13:45:02 +00:00
class ProductTypeCreateView(CounterAdminTabsMixin, CounterAdminMixin, CreateView):
2024-07-12 07:34:16 +00:00
"""A create view for the admins."""
2018-10-04 19:29:19 +00:00
2016-07-27 18:05:45 +00:00
model = ProductType
2024-12-15 17:55:09 +00:00
fields = ["name", "description", "comment", "icon"]
2018-10-04 19:29:19 +00:00
template_name = "core/create.jinja"
current_tab = "products"
2016-07-27 18:05:45 +00:00
2017-06-12 07:47:24 +00:00
2017-04-04 13:45:02 +00:00
class ProductTypeEditView(CounterAdminTabsMixin, CounterAdminMixin, UpdateView):
2024-07-12 07:34:16 +00:00
"""An edit view for the admins."""
2018-10-04 19:29:19 +00:00
2016-07-27 18:05:45 +00:00
model = ProductType
2018-10-04 19:29:19 +00:00
template_name = "core/edit.jinja"
2024-12-15 17:55:09 +00:00
fields = ["name", "description", "comment", "icon"]
2016-07-27 18:05:45 +00:00
pk_url_kwarg = "type_id"
current_tab = "products"
2016-07-27 18:05:45 +00:00
2017-06-12 07:47:24 +00:00
2024-10-13 10:32:50 +00:00
class ProductListView(CounterAdminTabsMixin, CounterAdminMixin, ListView):
model = Product
2024-10-19 22:27:25 +00:00
queryset = Product.objects.values("id", "name", "code", "product_type__name")
2018-10-04 19:29:19 +00:00
template_name = "counter/product_list.jinja"
2024-10-13 10:32:50 +00:00
ordering = [
2024-12-15 17:55:09 +00:00
F("product_type__order").asc(nulls_last=True),
2024-10-13 10:32:50 +00:00
"product_type",
"name",
]
def get_context_data(self, **kwargs):
res = super().get_context_data(**kwargs)
res["object_list"] = itertools.groupby(
2024-10-19 22:27:25 +00:00
res["object_list"], key=itemgetter("product_type__name")
2024-10-13 10:32:50 +00:00
)
return res
class ArchivedProductListView(ProductListView):
"""A list view for the admins."""
current_tab = "archive"
2024-10-13 10:32:50 +00:00
def get_queryset(self):
return super().get_queryset().filter(archived=True)
2017-06-12 07:47:24 +00:00
2024-10-13 10:32:50 +00:00
class ActiveProductListView(ProductListView):
2024-07-12 07:34:16 +00:00
"""A list view for the admins."""
2018-10-04 19:29:19 +00:00
current_tab = "products"
2024-10-13 10:32:50 +00:00
def get_queryset(self):
return super().get_queryset().filter(archived=False)
2017-06-12 07:47:24 +00:00
2017-04-04 13:45:02 +00:00
class ProductCreateView(CounterAdminTabsMixin, CounterAdminMixin, CreateView):
2024-07-12 07:34:16 +00:00
"""A create view for the admins."""
2018-10-04 19:29:19 +00:00
2016-07-27 15:23:02 +00:00
model = Product
form_class = ProductEditForm
2018-10-04 19:29:19 +00:00
template_name = "core/create.jinja"
current_tab = "products"
2016-07-27 15:23:02 +00:00
2017-06-12 07:47:24 +00:00
2017-04-04 13:45:02 +00:00
class ProductEditView(CounterAdminTabsMixin, CounterAdminMixin, UpdateView):
2024-07-12 07:34:16 +00:00
"""An edit view for the admins."""
2018-10-04 19:29:19 +00:00
2016-07-27 15:23:02 +00:00
model = Product
form_class = ProductEditForm
2016-07-27 15:23:02 +00:00
pk_url_kwarg = "product_id"
2018-10-04 19:29:19 +00:00
template_name = "core/edit.jinja"
current_tab = "products"
2016-08-18 19:06:10 +00:00
2017-06-12 07:47:24 +00:00
2016-09-28 09:07:32 +00:00
class RefillingDeleteView(DeleteView):
2024-07-12 07:34:16 +00:00
"""Delete a refilling (for the admins)."""
2018-10-04 19:29:19 +00:00
2016-08-18 19:06:10 +00:00
model = Refilling
pk_url_kwarg = "refilling_id"
2018-10-04 19:29:19 +00:00
template_name = "core/delete_confirm.jinja"
2016-08-18 19:06:10 +00:00
2016-09-28 09:07:32 +00:00
def dispatch(self, request, *args, **kwargs):
2024-07-12 07:34:16 +00:00
"""We have here a very particular right handling, we can't inherit from CanEditPropMixin."""
2016-09-28 09:07:32 +00:00
self.object = self.get_object()
if timezone.now() - self.object.date <= timedelta(
minutes=settings.SITH_LAST_OPERATIONS_LIMIT
2024-08-05 08:46:15 +00:00
) and is_logged_in_counter(request):
2018-10-04 19:29:19 +00:00
self.success_url = reverse(
"counter:details", kwargs={"counter_id": self.object.counter.id}
)
2024-06-27 12:46:43 +00:00
return super().dispatch(request, *args, **kwargs)
2016-09-28 09:07:32 +00:00
elif self.object.is_owned_by(request.user):
2018-10-04 19:29:19 +00:00
self.success_url = reverse(
"core:user_account", kwargs={"user_id": self.object.customer.user.id}
)
2024-06-27 12:46:43 +00:00
return super().dispatch(request, *args, **kwargs)
2016-09-28 09:07:32 +00:00
raise PermissionDenied
2016-08-18 19:06:10 +00:00
2017-06-12 07:47:24 +00:00
2016-09-28 09:07:32 +00:00
class SellingDeleteView(DeleteView):
2024-07-12 07:34:16 +00:00
"""Delete a selling (for the admins)."""
2018-10-04 19:29:19 +00:00
2016-08-18 19:06:10 +00:00
model = Selling
pk_url_kwarg = "selling_id"
2018-10-04 19:29:19 +00:00
template_name = "core/delete_confirm.jinja"
2016-08-18 19:06:10 +00:00
2016-09-28 09:07:32 +00:00
def dispatch(self, request, *args, **kwargs):
2024-07-12 07:34:16 +00:00
"""We have here a very particular right handling, we can't inherit from CanEditPropMixin."""
2016-09-28 09:07:32 +00:00
self.object = self.get_object()
if timezone.now() - self.object.date <= timedelta(
minutes=settings.SITH_LAST_OPERATIONS_LIMIT
2024-08-05 08:46:15 +00:00
) and is_logged_in_counter(request):
2018-10-04 19:29:19 +00:00
self.success_url = reverse(
"counter:details", kwargs={"counter_id": self.object.counter.id}
)
2024-06-27 12:46:43 +00:00
return super().dispatch(request, *args, **kwargs)
2016-09-28 09:07:32 +00:00
elif self.object.is_owned_by(request.user):
2018-10-04 19:29:19 +00:00
self.success_url = reverse(
"core:user_account", kwargs={"user_id": self.object.customer.user.id}
)
2024-06-27 12:46:43 +00:00
return super().dispatch(request, *args, **kwargs)
2016-09-28 09:07:32 +00:00
raise PermissionDenied
2016-08-18 19:06:10 +00:00
2018-10-04 19:29:19 +00:00
2017-04-04 13:45:02 +00:00
class CounterStatView(DetailView, CounterAdminMixin):
2024-07-12 07:34:16 +00:00
"""Show the bar stats."""
2018-10-04 19:29:19 +00:00
2016-09-15 09:07:03 +00:00
model = Counter
pk_url_kwarg = "counter_id"
2018-10-04 19:29:19 +00:00
template_name = "counter/stats.jinja"
2016-09-15 09:07:03 +00:00
def get_context_data(self, **kwargs):
2024-07-12 07:34:16 +00:00
"""Add stats to the context."""
counter: Counter = self.object
semester_start = get_start_of_semester()
office_hours = counter.get_top_barmen()
2024-06-27 12:46:43 +00:00
kwargs = super().get_context_data(**kwargs)
kwargs.update(
{
"counter": counter,
"current_semester": get_semester_code(),
"total_sellings": counter.get_total_sales(since=semester_start),
"top_customers": counter.get_top_customers(since=semester_start)[:100],
"top_barman": office_hours[:100],
"top_barman_semester": (
office_hours.filter(start__gt=semester_start)[:100]
),
}
2018-10-04 19:29:19 +00:00
)
2016-09-15 09:07:03 +00:00
return kwargs
def dispatch(self, request, *args, **kwargs):
2016-09-27 14:44:12 +00:00
try:
2024-06-27 12:46:43 +00:00
return super().dispatch(request, *args, **kwargs)
except PermissionDenied:
2018-10-04 19:29:19 +00:00
if (
request.user.is_root
or request.user.is_board_member
or self.get_object().is_owned_by(request.user)
2018-10-04 19:29:19 +00:00
):
return super(CanEditMixin, self).dispatch(request, *args, **kwargs)
raise PermissionDenied
2017-06-12 07:47:24 +00:00
2017-09-02 13:05:36 +00:00
class CounterRefillingListView(CounterAdminTabsMixin, CounterAdminMixin, ListView):
2024-07-12 07:34:16 +00:00
"""List of refillings on a counter."""
2018-10-04 19:29:19 +00:00
2017-09-02 13:05:36 +00:00
model = Refilling
2018-10-04 19:29:19 +00:00
template_name = "counter/refilling_list.jinja"
2017-09-02 13:05:36 +00:00
current_tab = "counters"
paginate_by = 30
def dispatch(self, request, *args, **kwargs):
2018-10-04 19:29:19 +00:00
self.counter = get_object_or_404(Counter, pk=kwargs["counter_id"])
2017-09-02 13:05:36 +00:00
self.queryset = Refilling.objects.filter(counter__id=self.counter.id)
2024-06-27 12:46:43 +00:00
return super().dispatch(request, *args, **kwargs)
2017-09-02 13:05:36 +00:00
def get_context_data(self, **kwargs):
2024-06-27 12:46:43 +00:00
kwargs = super().get_context_data(**kwargs)
2018-10-04 19:29:19 +00:00
kwargs["counter"] = self.counter
2017-09-02 13:05:36 +00:00
return kwargs