Sith/counter/views/admin.py
2024-12-18 14:48:59 +01:00

290 lines
9.5 KiB
Python

#
# 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)
# SEE : https://raw.githubusercontent.com/ae-utbm/sith/master/LICENSE
# OR WITHIN THE LOCAL FILE "LICENSE"
#
#
import itertools
from datetime import timedelta
from operator import itemgetter
from django.conf import settings
from django.core.exceptions import PermissionDenied
from django.db.models import F
from django.forms import CheckboxSelectMultiple
from django.forms.models import modelform_factory
from django.shortcuts import get_object_or_404
from django.urls import reverse, reverse_lazy
from django.utils import timezone
from django.views.generic import DetailView, ListView
from django.views.generic.edit import CreateView, DeleteView, UpdateView
from core.utils import get_semester_code, get_start_of_semester
from core.views import CanEditMixin, CanViewMixin
from counter.forms import CounterEditForm, ProductEditForm
from counter.models import Counter, Product, ProductType, Refilling, Selling
from counter.utils import is_logged_in_counter
from counter.views.mixins import CounterAdminMixin, CounterAdminTabsMixin
class CounterListView(CounterAdminTabsMixin, CanViewMixin, ListView):
"""A list view for the admins."""
model = Counter
template_name = "counter/counter_list.jinja"
current_tab = "counters"
class CounterEditView(CounterAdminTabsMixin, CounterAdminMixin, UpdateView):
"""Edit a counter's main informations (for the counter's manager)."""
model = Counter
form_class = CounterEditForm
pk_url_kwarg = "counter_id"
template_name = "core/edit.jinja"
current_tab = "counters"
def dispatch(self, request, *args, **kwargs):
obj = self.get_object()
self.edit_club.append(obj.club)
return super().dispatch(request, *args, **kwargs)
def get_success_url(self):
return reverse_lazy("counter:admin", kwargs={"counter_id": self.object.id})
class CounterEditPropView(CounterAdminTabsMixin, CounterAdminMixin, UpdateView):
"""Edit a counter's main informations (for the counter's admin)."""
model = Counter
form_class = modelform_factory(Counter, fields=["name", "club", "type"])
pk_url_kwarg = "counter_id"
template_name = "core/edit.jinja"
current_tab = "counters"
class CounterCreateView(CounterAdminTabsMixin, CounterAdminMixin, CreateView):
"""Create a counter (for the admins)."""
model = Counter
form_class = modelform_factory(
Counter,
fields=["name", "club", "type", "products"],
widgets={"products": CheckboxSelectMultiple},
)
template_name = "core/create.jinja"
current_tab = "counters"
class CounterDeleteView(CounterAdminTabsMixin, CounterAdminMixin, DeleteView):
"""Delete a counter (for the admins)."""
model = Counter
pk_url_kwarg = "counter_id"
template_name = "core/delete_confirm.jinja"
success_url = reverse_lazy("counter:admin_list")
current_tab = "counters"
# Product management
class ProductTypeListView(CounterAdminTabsMixin, CounterAdminMixin, ListView):
"""A list view for the admins."""
model = ProductType
template_name = "counter/product_type_list.jinja"
current_tab = "product_types"
context_object_name = "product_types"
class ProductTypeCreateView(CounterAdminTabsMixin, CounterAdminMixin, CreateView):
"""A create view for the admins."""
model = ProductType
fields = ["name", "description", "comment", "icon"]
template_name = "core/create.jinja"
current_tab = "products"
class ProductTypeEditView(CounterAdminTabsMixin, CounterAdminMixin, UpdateView):
"""An edit view for the admins."""
model = ProductType
template_name = "core/edit.jinja"
fields = ["name", "description", "comment", "icon"]
pk_url_kwarg = "type_id"
current_tab = "products"
class ProductListView(CounterAdminTabsMixin, CounterAdminMixin, ListView):
model = Product
queryset = Product.objects.values("id", "name", "code", "product_type__name")
template_name = "counter/product_list.jinja"
ordering = [
F("product_type__order").asc(nulls_last=True),
"product_type",
"name",
]
def get_context_data(self, **kwargs):
res = super().get_context_data(**kwargs)
res["object_list"] = itertools.groupby(
res["object_list"], key=itemgetter("product_type__name")
)
return res
class ArchivedProductListView(ProductListView):
"""A list view for the admins."""
current_tab = "archive"
def get_queryset(self):
return super().get_queryset().filter(archived=True)
class ActiveProductListView(ProductListView):
"""A list view for the admins."""
current_tab = "products"
def get_queryset(self):
return super().get_queryset().filter(archived=False)
class ProductCreateView(CounterAdminTabsMixin, CounterAdminMixin, CreateView):
"""A create view for the admins."""
model = Product
form_class = ProductEditForm
template_name = "core/create.jinja"
current_tab = "products"
class ProductEditView(CounterAdminTabsMixin, CounterAdminMixin, UpdateView):
"""An edit view for the admins."""
model = Product
form_class = ProductEditForm
pk_url_kwarg = "product_id"
template_name = "core/edit.jinja"
current_tab = "products"
class RefillingDeleteView(DeleteView):
"""Delete a refilling (for the admins)."""
model = Refilling
pk_url_kwarg = "refilling_id"
template_name = "core/delete_confirm.jinja"
def dispatch(self, request, *args, **kwargs):
"""We have here a very particular right handling, we can't inherit from CanEditPropMixin."""
self.object = self.get_object()
if timezone.now() - self.object.date <= timedelta(
minutes=settings.SITH_LAST_OPERATIONS_LIMIT
) and is_logged_in_counter(request):
self.success_url = reverse(
"counter:details", kwargs={"counter_id": self.object.counter.id}
)
return super().dispatch(request, *args, **kwargs)
elif self.object.is_owned_by(request.user):
self.success_url = reverse(
"core:user_account", kwargs={"user_id": self.object.customer.user.id}
)
return super().dispatch(request, *args, **kwargs)
raise PermissionDenied
class SellingDeleteView(DeleteView):
"""Delete a selling (for the admins)."""
model = Selling
pk_url_kwarg = "selling_id"
template_name = "core/delete_confirm.jinja"
def dispatch(self, request, *args, **kwargs):
"""We have here a very particular right handling, we can't inherit from CanEditPropMixin."""
self.object = self.get_object()
if timezone.now() - self.object.date <= timedelta(
minutes=settings.SITH_LAST_OPERATIONS_LIMIT
) and is_logged_in_counter(request):
self.success_url = reverse(
"counter:details", kwargs={"counter_id": self.object.counter.id}
)
return super().dispatch(request, *args, **kwargs)
elif self.object.is_owned_by(request.user):
self.success_url = reverse(
"core:user_account", kwargs={"user_id": self.object.customer.user.id}
)
return super().dispatch(request, *args, **kwargs)
raise PermissionDenied
class CounterStatView(DetailView, CounterAdminMixin):
"""Show the bar stats."""
model = Counter
pk_url_kwarg = "counter_id"
template_name = "counter/stats.jinja"
def get_context_data(self, **kwargs):
"""Add stats to the context."""
counter: Counter = self.object
semester_start = get_start_of_semester()
office_hours = counter.get_top_barmen()
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]
),
}
)
return kwargs
def dispatch(self, request, *args, **kwargs):
try:
return super().dispatch(request, *args, **kwargs)
except PermissionDenied:
if (
request.user.is_root
or request.user.is_board_member
or self.get_object().is_owned_by(request.user)
):
return super(CanEditMixin, self).dispatch(request, *args, **kwargs)
raise PermissionDenied
class CounterRefillingListView(CounterAdminTabsMixin, CounterAdminMixin, ListView):
"""List of refillings on a counter."""
model = Refilling
template_name = "counter/refilling_list.jinja"
current_tab = "counters"
paginate_by = 30
def dispatch(self, request, *args, **kwargs):
self.counter = get_object_or_404(Counter, pk=kwargs["counter_id"])
self.queryset = Refilling.objects.filter(counter__id=self.counter.id)
return super().dispatch(request, *args, **kwargs)
def get_context_data(self, **kwargs):
kwargs = super().get_context_data(**kwargs)
kwargs["counter"] = self.counter
return kwargs