# # 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/producttype_list.jinja" current_tab = "product_types" class ProductTypeCreateView(CounterAdminTabsMixin, CounterAdminMixin, CreateView): """A create view for the admins.""" model = ProductType fields = ["name", "description", "comment", "icon", "priority"] 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", "priority"] 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__priority").desc(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