mirror of
				https://gitlab.crans.org/bde/nk20
				synced 2025-10-31 15:50:03 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			422 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			422 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # Copyright (C) 2018-2024 by BDE ENS Paris-Saclay
 | |
| # SPDX-License-Identifier: GPL-3.0-or-later
 | |
| 
 | |
| from django.db import transaction
 | |
| from django.contrib.auth.mixins import LoginRequiredMixin
 | |
| from django.http import HttpResponseRedirect
 | |
| from django_tables2.views import MultiTableMixin
 | |
| from django.urls import reverse
 | |
| from django.utils.translation import gettext_lazy as _
 | |
| from django.utils import timezone
 | |
| from django.views.generic import DetailView, UpdateView
 | |
| from django.views.generic.list import ListView
 | |
| from django.forms import HiddenInput
 | |
| from permission.backends import PermissionBackend
 | |
| from permission.views import ProtectQuerysetMixin, ProtectedCreateView
 | |
| 
 | |
| from .forms import AddIngredientForms, BasicFoodForms, QRCodeForms, TransformedFoodForms
 | |
| from .models import BasicFood, Food, QRCode, TransformedFood
 | |
| from .tables import TransformedFoodTable
 | |
| 
 | |
| 
 | |
| class AddIngredientView(ProtectQuerysetMixin, UpdateView):
 | |
|     """
 | |
|     A view to add an ingredient
 | |
|     """
 | |
|     model = Food
 | |
|     template_name = 'food/add_ingredient_form.html'
 | |
|     extra_context = {"title": _("Add the ingredient")}
 | |
|     form_class = AddIngredientForms
 | |
| 
 | |
|     def get_context_data(self, **kwargs):
 | |
|         context = super().get_context_data(**kwargs)
 | |
|         context["pk"] = self.kwargs["pk"]
 | |
|         return context
 | |
| 
 | |
|     @transaction.atomic
 | |
|     def form_valid(self, form):
 | |
|         form.instance.creater = self.request.user
 | |
|         food = Food.objects.get(pk=self.kwargs['pk'])
 | |
|         add_ingredient_form = AddIngredientForms(data=self.request.POST)
 | |
|         if food.is_ready:
 | |
|             form.add_error(None, _("The product is already prepared"))
 | |
|             return self.form_invalid(form)
 | |
|         if not add_ingredient_form.is_valid():
 | |
|             return self.form_invalid(form)
 | |
| 
 | |
|         # We flip logic ""fully used = not is_active""
 | |
|         food.is_active = not food.is_active
 | |
|         # Save the aliment and the allergens associed
 | |
|         for transformed_pk in self.request.POST.getlist('ingredient'):
 | |
|             transformed = TransformedFood.objects.get(pk=transformed_pk)
 | |
|             if not transformed.is_ready:
 | |
|                 transformed.ingredient.add(food)
 | |
|                 transformed.update()
 | |
|         food.save()
 | |
| 
 | |
|         return HttpResponseRedirect(self.get_success_url())
 | |
| 
 | |
|     def get_success_url(self, **kwargs):
 | |
|         return reverse('food:food_list')
 | |
| 
 | |
| 
 | |
| class BasicFoodUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
 | |
|     """
 | |
|     A view to update a basic food
 | |
|     """
 | |
|     model = BasicFood
 | |
|     form_class = BasicFoodForms
 | |
|     template_name = 'food/basicfood_form.html'
 | |
|     extra_context = {"title": _("Update an aliment")}
 | |
| 
 | |
|     @transaction.atomic
 | |
|     def form_valid(self, form):
 | |
|         form.instance.creater = self.request.user
 | |
|         basic_food_form = BasicFoodForms(data=self.request.POST)
 | |
|         if not basic_food_form.is_valid():
 | |
|             return self.form_invalid(form)
 | |
| 
 | |
|         ans = super().form_valid(form)
 | |
|         form.instance.update()
 | |
|         return ans
 | |
| 
 | |
|     def get_success_url(self, **kwargs):
 | |
|         self.object.refresh_from_db()
 | |
|         return reverse('food:food_view', kwargs={"pk": self.object.pk})
 | |
| 
 | |
|     def get_context_data(self, **kwargs):
 | |
|         context = super().get_context_data(**kwargs)
 | |
|         return context
 | |
| 
 | |
| 
 | |
| class FoodView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
 | |
|     """
 | |
|     A view to see a food
 | |
|     """
 | |
|     model = Food
 | |
|     extra_context = {"title": _("Details of:")}
 | |
|     context_object_name = "food"
 | |
| 
 | |
|     def get_context_data(self, **kwargs):
 | |
|         context = super().get_context_data(**kwargs)
 | |
| 
 | |
|         context["can_update"] = PermissionBackend.check_perm(self.request, "food.change_food")
 | |
|         context["can_add_ingredient"] = PermissionBackend.check_perm(self.request, "food.change_transformedfood")
 | |
|         return context
 | |
| 
 | |
| 
 | |
| class QRCodeBasicFoodCreateView(ProtectQuerysetMixin, ProtectedCreateView):
 | |
|     #####################################################################
 | |
|     # TO DO
 | |
|     # - this feature is very pratical for meat or fish, nevertheless we can implement this later
 | |
|     # - fix picture save
 | |
|     # - implement solution crop and convert image (reuse or recode ImageForm from members apps)
 | |
|     #####################################################################
 | |
|     """
 | |
|     A view to add a basic food with a qrcode
 | |
|     """
 | |
|     model = BasicFood
 | |
|     form_class = BasicFoodForms
 | |
|     template_name = 'food/basicfood_form.html'
 | |
|     extra_context = {"title": _("Add a new basic food with QRCode")}
 | |
| 
 | |
|     @transaction.atomic
 | |
|     def form_valid(self, form):
 | |
|         form.instance.creater = self.request.user
 | |
|         basic_food_form = BasicFoodForms(data=self.request.POST)
 | |
|         if not basic_food_form.is_valid():
 | |
|             return self.form_invalid(form)
 | |
| 
 | |
|         # Save the aliment and the allergens associed
 | |
|         basic_food = form.save(commit=False)
 | |
|         # We assume the date of labeling and the same as the date of arrival
 | |
|         basic_food.arrival_date = timezone.now()
 | |
|         basic_food.is_ready = False
 | |
|         basic_food.is_active = True
 | |
|         basic_food.was_eaten = False
 | |
|         basic_food._force_save = True
 | |
|         basic_food.save()
 | |
|         basic_food.refresh_from_db()
 | |
| 
 | |
|         qrcode = QRCode()
 | |
|         qrcode.qr_code_number = self.kwargs['slug']
 | |
|         qrcode.food_container = basic_food
 | |
|         qrcode.save()
 | |
| 
 | |
|         return super().form_valid(form)
 | |
| 
 | |
|     def get_success_url(self, **kwargs):
 | |
|         self.object.refresh_from_db()
 | |
|         return reverse('food:qrcode_view', kwargs={"slug": self.kwargs['slug']})
 | |
| 
 | |
|     def get_sample_object(self):
 | |
| 
 | |
|         # We choose a club which may work or BDE else
 | |
|         owner_id = 1
 | |
|         for membership in self.request.user.memberships.all():
 | |
|             club_id = membership.club.id
 | |
|             food = BasicFood(name="", expiry_date=timezone.now(), owner_id=club_id)
 | |
|             if PermissionBackend.check_perm(self.request, "food.add_basicfood", food):
 | |
|                 owner_id = club_id
 | |
| 
 | |
|         return BasicFood(
 | |
|             name="",
 | |
|             expiry_date=timezone.now(),
 | |
|             owner_id=owner_id,
 | |
|         )
 | |
| 
 | |
|     def get_context_data(self, **kwargs):
 | |
|         # Some field are hidden on create
 | |
|         context = super().get_context_data(**kwargs)
 | |
| 
 | |
|         form = context['form']
 | |
|         form.fields['is_active'].widget = HiddenInput()
 | |
|         form.fields['was_eaten'].widget = HiddenInput()
 | |
| 
 | |
|         copy = self.request.GET.get('copy', None)
 | |
|         if copy is not None:
 | |
|             basic = BasicFood.objects.get(pk=copy)
 | |
|             for field in ['date_type', 'expiry_date', 'name', 'owner']:
 | |
|                 form.fields[field].initial = getattr(basic, field)
 | |
|             for field in ['allergens']:
 | |
|                 form.fields[field].initial = getattr(basic, field).all()
 | |
| 
 | |
|         return context
 | |
| 
 | |
| 
 | |
| class QRCodeCreateView(ProtectQuerysetMixin, ProtectedCreateView):
 | |
|     """
 | |
|     A view to add a new qrcode
 | |
|     """
 | |
|     model = QRCode
 | |
|     template_name = 'food/create_qrcode_form.html'
 | |
|     form_class = QRCodeForms
 | |
|     extra_context = {"title": _("Add a new QRCode")}
 | |
| 
 | |
|     def get(self, *args, **kwargs):
 | |
|         qrcode = kwargs["slug"]
 | |
|         if self.model.objects.filter(qr_code_number=qrcode).count() > 0:
 | |
|             return HttpResponseRedirect(reverse("food:qrcode_view", kwargs=kwargs))
 | |
|         else:
 | |
|             return super().get(*args, **kwargs)
 | |
| 
 | |
|     def get_context_data(self, **kwargs):
 | |
|         context = super().get_context_data(**kwargs)
 | |
|         context["slug"] = self.kwargs["slug"]
 | |
| 
 | |
|         context["last_basic"] = BasicFood.objects.order_by('-pk').all()[:10]
 | |
| 
 | |
|         return context
 | |
| 
 | |
|     @transaction.atomic
 | |
|     def form_valid(self, form):
 | |
|         form.instance.creater = self.request.user
 | |
|         qrcode_food_form = QRCodeForms(data=self.request.POST)
 | |
|         if not qrcode_food_form.is_valid():
 | |
|             return self.form_invalid(form)
 | |
| 
 | |
|         # Save the qrcode
 | |
|         qrcode = form.save(commit=False)
 | |
|         qrcode.qr_code_number = self.kwargs["slug"]
 | |
|         qrcode._force_save = True
 | |
|         qrcode.save()
 | |
|         qrcode.refresh_from_db()
 | |
| 
 | |
|         qrcode.food_container.save()
 | |
| 
 | |
|         return super().form_valid(form)
 | |
| 
 | |
|     def get_success_url(self, **kwargs):
 | |
|         self.object.refresh_from_db()
 | |
|         return reverse('food:qrcode_view', kwargs={"slug": self.kwargs['slug']})
 | |
| 
 | |
|     def get_sample_object(self):
 | |
|         return QRCode(
 | |
|             qr_code_number=self.kwargs["slug"],
 | |
|             food_container_id=1
 | |
|         )
 | |
| 
 | |
| 
 | |
| class QRCodeView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
 | |
|     """
 | |
|     A view to see a qrcode
 | |
|     """
 | |
|     model = QRCode
 | |
|     extra_context = {"title": _("QRCode")}
 | |
|     context_object_name = "qrcode"
 | |
|     slug_field = "qr_code_number"
 | |
| 
 | |
|     def get(self, *args, **kwargs):
 | |
|         qrcode = kwargs["slug"]
 | |
|         if self.model.objects.filter(qr_code_number=qrcode).count() > 0:
 | |
|             return super().get(*args, **kwargs)
 | |
|         else:
 | |
|             return HttpResponseRedirect(reverse("food:qrcode_create", kwargs=kwargs))
 | |
| 
 | |
|     def get_context_data(self, **kwargs):
 | |
|         context = super().get_context_data(**kwargs)
 | |
| 
 | |
|         qr_code_number = self.kwargs['slug']
 | |
|         qrcode = self.model.objects.get(qr_code_number=qr_code_number)
 | |
| 
 | |
|         model = qrcode.food_container.polymorphic_ctype.model
 | |
| 
 | |
|         if model == "basicfood":
 | |
|             context["can_update_basic"] = PermissionBackend.check_perm(self.request, "food.change_basicfood")
 | |
|             context["can_view_detail"] = PermissionBackend.check_perm(self.request, "food.view_basicfood")
 | |
|         if model == "transformedfood":
 | |
|             context["can_update_transformed"] = PermissionBackend.check_perm(self.request, "food.change_transformedfood")
 | |
|             context["can_view_detail"] = PermissionBackend.check_perm(self.request, "food.view_transformedfood")
 | |
|         context["can_add_ingredient"] = PermissionBackend.check_perm(self.request, "food.change_transformedfood")
 | |
|         return context
 | |
| 
 | |
| 
 | |
| class TransformedFoodCreateView(ProtectQuerysetMixin, ProtectedCreateView):
 | |
|     """
 | |
|     A view to add a tranformed food
 | |
|     """
 | |
|     model = TransformedFood
 | |
|     template_name = 'food/transformedfood_form.html'
 | |
|     form_class = TransformedFoodForms
 | |
|     extra_context = {"title": _("Add a new meal")}
 | |
| 
 | |
|     @transaction.atomic
 | |
|     def form_valid(self, form):
 | |
|         form.instance.creater = self.request.user
 | |
|         transformed_food_form = TransformedFoodForms(data=self.request.POST)
 | |
|         if not transformed_food_form.is_valid():
 | |
|             return self.form_invalid(form)
 | |
| 
 | |
|         # Save the aliment and allergens associated
 | |
|         transformed_food = form.save(commit=False)
 | |
|         transformed_food.expiry_date = transformed_food.creation_date
 | |
|         transformed_food.is_active = True
 | |
|         transformed_food.is_ready = False
 | |
|         transformed_food.was_eaten = False
 | |
|         transformed_food._force_save = True
 | |
|         transformed_food.save()
 | |
|         transformed_food.refresh_from_db()
 | |
|         ans = super().form_valid(form)
 | |
|         transformed_food.update()
 | |
|         return ans
 | |
| 
 | |
|     def get_success_url(self, **kwargs):
 | |
|         self.object.refresh_from_db()
 | |
|         return reverse('food:food_view', kwargs={"pk": self.object.pk})
 | |
| 
 | |
|     def get_sample_object(self):
 | |
|         # We choose a club which may work or BDE else
 | |
|         owner_id = 1
 | |
|         for membership in self.request.user.memberships.all():
 | |
|             club_id = membership.club.id
 | |
|             food = TransformedFood(name="",
 | |
|                                    creation_date=timezone.now(),
 | |
|                                    expiry_date=timezone.now(),
 | |
|                                    owner_id=club_id)
 | |
|             if PermissionBackend.check_perm(self.request, "food.add_transformedfood", food):
 | |
|                 owner_id = club_id
 | |
|                 break
 | |
| 
 | |
|         return TransformedFood(
 | |
|             name="",
 | |
|             owner_id=owner_id,
 | |
|             creation_date=timezone.now(),
 | |
|             expiry_date=timezone.now(),
 | |
|         )
 | |
| 
 | |
|     def get_context_data(self, **kwargs):
 | |
|         context = super().get_context_data(**kwargs)
 | |
| 
 | |
|         # Some field are hidden on create
 | |
|         form = context['form']
 | |
|         form.fields['is_active'].widget = HiddenInput()
 | |
|         form.fields['is_ready'].widget = HiddenInput()
 | |
|         form.fields['was_eaten'].widget = HiddenInput()
 | |
|         form.fields['shelf_life'].widget = HiddenInput()
 | |
| 
 | |
|         return context
 | |
| 
 | |
| 
 | |
| class TransformedFoodUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
 | |
|     """
 | |
|     A view to update transformed product
 | |
|     """
 | |
|     model = TransformedFood
 | |
|     template_name = 'food/transformedfood_form.html'
 | |
|     form_class = TransformedFoodForms
 | |
|     extra_context = {'title': _('Update a meal')}
 | |
| 
 | |
|     @transaction.atomic
 | |
|     def form_valid(self, form):
 | |
|         form.instance.creater = self.request.user
 | |
|         transformedfood_form = TransformedFoodForms(data=self.request.POST)
 | |
|         if not transformedfood_form.is_valid():
 | |
|             return self.form_invalid(form)
 | |
| 
 | |
|         ans = super().form_valid(form)
 | |
|         form.instance.update()
 | |
|         return ans
 | |
| 
 | |
|     def get_success_url(self, **kwargs):
 | |
|         self.object.refresh_from_db()
 | |
|         return reverse('food:food_view', kwargs={"pk": self.object.pk})
 | |
| 
 | |
|     def get_context_data(self, **kwargs):
 | |
|         context = super().get_context_data(**kwargs)
 | |
|         return context
 | |
| 
 | |
| 
 | |
| class TransformedListView(ProtectQuerysetMixin, LoginRequiredMixin, MultiTableMixin, ListView):
 | |
|     """
 | |
|     Displays ready TransformedFood
 | |
|     """
 | |
|     model = TransformedFood
 | |
|     tables = [TransformedFoodTable, TransformedFoodTable, TransformedFoodTable]
 | |
|     extra_context = {"title": _("Transformed food")}
 | |
| 
 | |
|     def get_queryset(self, **kwargs):
 | |
|         return super().get_queryset(**kwargs).distinct()
 | |
| 
 | |
|     def get_tables(self):
 | |
|         tables = super().get_tables()
 | |
| 
 | |
|         tables[0].prefix = "all-"
 | |
|         tables[1].prefix = "open-"
 | |
|         tables[2].prefix = "served-"
 | |
|         return tables
 | |
| 
 | |
|     def get_tables_data(self):
 | |
|         # first table = all transformed food, second table = free, third = served
 | |
|         return [
 | |
|             self.get_queryset().order_by("-creation_date"),
 | |
|             TransformedFood.objects.filter(is_ready=True, is_active=True, was_eaten=False, expiry_date__lt=timezone.now())
 | |
|                                    .filter(PermissionBackend.filter_queryset(self.request, TransformedFood, "view"))
 | |
|                                    .distinct()
 | |
|                                    .order_by("-creation_date"),
 | |
|             TransformedFood.objects.filter(is_ready=True, is_active=True, was_eaten=False, expiry_date__gte=timezone.now())
 | |
|                                    .filter(PermissionBackend.filter_queryset(self.request, TransformedFood, "view"))
 | |
|                                    .distinct()
 | |
|                                    .order_by("-creation_date")
 | |
|         ]
 | |
| 
 | |
|     def get_context_data(self, **kwargs):
 | |
|         context = super().get_context_data(**kwargs)
 | |
| 
 | |
|         # We choose a club which should work
 | |
|         for membership in self.request.user.memberships.all():
 | |
|             club_id = membership.club.id
 | |
|             food = TransformedFood(
 | |
|                 name="",
 | |
|                 owner_id=club_id,
 | |
|                 creation_date=timezone.now(),
 | |
|                 expiry_date=timezone.now(),
 | |
|             )
 | |
|             if PermissionBackend.check_perm(self.request, "food.add_transformedfood", food):
 | |
|                 context['can_create_meal'] = True
 | |
|                 break
 | |
| 
 | |
|         tables = context["tables"]
 | |
|         for name, table in zip(["table", "open", "served"], tables):
 | |
|             context[name] = table
 | |
|         return context
 |