From 980bdb6fd8c13ab5ce5ba5284a8e7d0d86d20f1a Mon Sep 17 00:00:00 2001 From: korenstin Date: Sat, 6 Jul 2024 19:26:21 +0200 Subject: [PATCH] Automatic allergens and expiry_date update --- apps/food/admin.py | 27 +++++---- apps/food/forms.py | 2 +- apps/food/models.py | 60 +++++++++++++++++++ .../food/templates/food/basicfood_detail.html | 9 +++ .../templates/food/create_qrcode_form.html | 11 +--- .../food/transformedfood_detail.html | 2 + apps/food/urls.py | 1 - apps/food/views.py | 58 ++---------------- 8 files changed, 94 insertions(+), 76 deletions(-) diff --git a/apps/food/admin.py b/apps/food/admin.py index 2bb1e302..23384316 100644 --- a/apps/food/admin.py +++ b/apps/food/admin.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: GPL-3.0-or-later from django.contrib import admin +from django.db import transaction from note_kfet.admin import admin_site from .models import Allergen, BasicFood, QRCode, TransformedFood @@ -9,27 +10,29 @@ from .models import Allergen, BasicFood, QRCode, TransformedFood @admin.register(QRCode, site=admin_site) class QRCodeAdmin(admin.ModelAdmin): - """ - TEMPORARY - """ + pass @admin.register(BasicFood, site=admin_site) class BasicFoodAdmin(admin.ModelAdmin): - """ - TEMPORARY - """ + @transaction.atomic + def save_related(self, *args, **kwargs): + ans = super().save_related(*args, **kwargs) + args[1].instance.update() + return ans @admin.register(TransformedFood, site=admin_site) class TransformedFoodAdmin(admin.ModelAdmin): - """ - TEMPORARY - """ + exclude = ["allergens", "expiry_date"] + + @transaction.atomic + def save_related(self, *args, **kwargs): + ans = super().save_related(*args, **kwargs) + args[1].instance.update() + return ans @admin.register(Allergen, site=admin_site) class AllergenAdmin(admin.ModelAdmin): - """ - TEMPORARY - """ + pass diff --git a/apps/food/forms.py b/apps/food/forms.py index 34a4f5f0..fe0775a0 100644 --- a/apps/food/forms.py +++ b/apps/food/forms.py @@ -89,7 +89,7 @@ class TransformedFoodForms(forms.ModelForm): class Meta: model = TransformedFood - fields = ('name', 'creation_date', 'owner', 'is_active', 'allergens') + fields = ('name', 'creation_date', 'owner', 'is_active') widgets = { "owner": Autocomplete( model=Club, diff --git a/apps/food/models.py b/apps/food/models.py index bc5103b5..e68a5c65 100644 --- a/apps/food/models.py +++ b/apps/food/models.py @@ -1,6 +1,8 @@ # Copyright (C) 2018-2024 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later +from datetime import timedelta + from django.db import models, transaction from django.utils import timezone from django.utils.translation import gettext_lazy as _ @@ -120,6 +122,23 @@ class BasicFood(Food): # upload_to='label/', # ) + @transaction.atomic + def update_allergens(self): + # update parents + for parent in self.transformed_ingredient_inv.iterator(): + parent.update_allergens() + + @transaction.atomic + def update_expiry_date(self): + # update parents + for parent in self.transformed_ingredient_inv.iterator(): + parent.update_expiry_date() + + @transaction.atomic + def update(self): + self.update_allergens() + self.update_expiry_date() + class Meta: verbose_name = _('Basic food') verbose_name_plural = _('Basic foods') @@ -146,6 +165,47 @@ class TransformedFood(Food): verbose_name=_('is active'), ) + @transaction.atomic + def update_allergens(self): + # When allergens are changed, simply update the parents' allergens + old_allergens = list(self.allergens.all()) + self.allergens.clear() + for ingredient in self.ingredient.iterator(): + self.allergens.set(self.allergens.union(ingredient.allergens.all())) + + if old_allergens == list(self.allergens.all()): + return + super().save() + + # update parents + for parent in self.transformed_ingredient_inv.iterator(): + parent.update_allergens() + + @transaction.atomic + def update_expiry_date(self): + # When expiry_date is changed, simply update the parents' expiry_date + old_expiry_date = self.expiry_date + self.expiry_date = self.creation_date + timedelta(days=3) + for ingredient in self.ingredient.iterator(): + self.expiry_date = min(self.expiry_date, ingredient.expiry_date) + + if old_expiry_date == self.expiry_date: + return + super().save() + + # update parents + for parent in self.transformed_ingredient_inv.iterator(): + parent.update_expiry_date() + + @transaction.atomic + def update(self): + self.update_allergens() + self.update_expiry_date() + + @transaction.atomic + def save(self, *args, **kwargs): + super().save(*args, **kwargs) + class Meta: verbose_name = _('Transformed food') verbose_name_plural = _('Transformed foods') diff --git a/apps/food/templates/food/basicfood_detail.html b/apps/food/templates/food/basicfood_detail.html index b0629f58..8daefaf8 100644 --- a/apps/food/templates/food/basicfood_detail.html +++ b/apps/food/templates/food/basicfood_detail.html @@ -12,6 +12,15 @@ SPDX-License-Identifier: GPL-3.0-or-later

name : {{ food.name }}

+

owner : {{ food.owner }}

+

arrival_date : {{ food.arrival_date }}

+

expiry_date : {{ food.expiry_date }}

+

allergens :

+ Update
diff --git a/apps/food/templates/food/create_qrcode_form.html b/apps/food/templates/food/create_qrcode_form.html index 74f3ec29..69909b7f 100644 --- a/apps/food/templates/food/create_qrcode_form.html +++ b/apps/food/templates/food/create_qrcode_form.html @@ -10,15 +10,10 @@ SPDX-License-Identifier: GPL-3.0-or-later HTML not finished
{{ title }} -
-
- -
-
+ + New basic food +
{% csrf_token %} {{ form|crispy }} diff --git a/apps/food/templates/food/transformedfood_detail.html b/apps/food/templates/food/transformedfood_detail.html index f2604c65..2ac87989 100644 --- a/apps/food/templates/food/transformedfood_detail.html +++ b/apps/food/templates/food/transformedfood_detail.html @@ -13,6 +13,8 @@ SPDX-License-Identifier: GPL-3.0-or-later

name : {{ food.name }}

owner : {{ food.owner }}

+

creation_date : {{ food.creation_date }}

+

expiry_date : {{ food.expiry_date }}

allergens :

    {% for allergen in food.allergens.iterator %} diff --git a/apps/food/urls.py b/apps/food/urls.py index f47f5fa8..76527033 100644 --- a/apps/food/urls.py +++ b/apps/food/urls.py @@ -15,7 +15,6 @@ urlpatterns = [ path('/create_qrcode', views.QRCodeCreateView.as_view(), name='qrcode_create'), path('create', views.FoodCreateView.as_view(), name='food_create'), path('/create_qrcode/basic', views.QRCodeBasicFoodCreateView.as_view(), name='qrcode_basic_create'), - path('/create_qrcode/transformed', views.QRCodeTransformedFoodCreateView.as_view(), name='qrcode_transformed_create'), path('create/transformed', views.TransformedFoodCreateView.as_view(), name='transformed_create'), path('update/basic/', views.BasicFoodUpdateView.as_view(), name='basic_update'), diff --git a/apps/food/views.py b/apps/food/views.py index 9e79689d..b6fb4bb5 100644 --- a/apps/food/views.py +++ b/apps/food/views.py @@ -45,9 +45,7 @@ class AddIngredientView(ProtectQuerysetMixin, FormView): for transformed_pk in self.request.POST.getlist('ingredient'): transformed = TransformedFood.objects.get(pk=transformed_pk) transformed.ingredient.add(food) - transformed._force_save = True - transformed.save() - transformed.refresh_from_db() + transformed.update() return super().form_valid(form) @@ -77,14 +75,9 @@ class BasicFoodUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): 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._force_save = True - basic_food.save() - basic_food.refresh_from_db() - return super().form_valid(form) + ans = super().form_valid(form) + form.instance.update() + return ans def get_success_url(self, **kwargs): self.object.refresh_from_db() @@ -206,49 +199,6 @@ class QRCodeCreateView(ProtectQuerysetMixin, ProtectedCreateView): ) -class QRCodeTransformedFoodCreateView(ProtectQuerysetMixin, ProtectedCreateView): - """ - A view to add a transformed food with a qrcode - """ - model = TransformedFood - template_name = 'food/transformed_food_form.html' - form_class = TransformedFoodForms - extra_context = {"title": _("Add a new transformed food with QRCode")} - - @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) - # Without microbiological analyzes, the storage time is 3 days - transformed_food.expiry_date = transformed_food.creation_date + timedelta(days=3) - transformed_food.is_ready = True - transformed_food._force_save = True - transformed_food.save() - transformed_food.refresh_from_db() - - qrcode = QRCode() - qrcode.qr_code_number = self.kwargs['slug'] - qrcode.food_container = transformed_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): - return TransformedFood( - name="", - creation_date=timezone.now(), - ) - - class QRCodeView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): """ A view to see a qrcode