mirror of https://gitlab.crans.org/bde/nk20
Automatic allergens and expiry_date update
This commit is contained in:
parent
fda9df3d6b
commit
980bdb6fd8
|
@ -2,6 +2,7 @@
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
from django.db import transaction
|
||||||
from note_kfet.admin import admin_site
|
from note_kfet.admin import admin_site
|
||||||
|
|
||||||
from .models import Allergen, BasicFood, QRCode, TransformedFood
|
from .models import Allergen, BasicFood, QRCode, TransformedFood
|
||||||
|
@ -9,27 +10,29 @@ from .models import Allergen, BasicFood, QRCode, TransformedFood
|
||||||
|
|
||||||
@admin.register(QRCode, site=admin_site)
|
@admin.register(QRCode, site=admin_site)
|
||||||
class QRCodeAdmin(admin.ModelAdmin):
|
class QRCodeAdmin(admin.ModelAdmin):
|
||||||
"""
|
pass
|
||||||
TEMPORARY
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(BasicFood, site=admin_site)
|
@admin.register(BasicFood, site=admin_site)
|
||||||
class BasicFoodAdmin(admin.ModelAdmin):
|
class BasicFoodAdmin(admin.ModelAdmin):
|
||||||
"""
|
@transaction.atomic
|
||||||
TEMPORARY
|
def save_related(self, *args, **kwargs):
|
||||||
"""
|
ans = super().save_related(*args, **kwargs)
|
||||||
|
args[1].instance.update()
|
||||||
|
return ans
|
||||||
|
|
||||||
|
|
||||||
@admin.register(TransformedFood, site=admin_site)
|
@admin.register(TransformedFood, site=admin_site)
|
||||||
class TransformedFoodAdmin(admin.ModelAdmin):
|
class TransformedFoodAdmin(admin.ModelAdmin):
|
||||||
"""
|
exclude = ["allergens", "expiry_date"]
|
||||||
TEMPORARY
|
|
||||||
"""
|
@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)
|
@admin.register(Allergen, site=admin_site)
|
||||||
class AllergenAdmin(admin.ModelAdmin):
|
class AllergenAdmin(admin.ModelAdmin):
|
||||||
"""
|
pass
|
||||||
TEMPORARY
|
|
||||||
"""
|
|
||||||
|
|
|
@ -89,7 +89,7 @@ class TransformedFoodForms(forms.ModelForm):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = TransformedFood
|
model = TransformedFood
|
||||||
fields = ('name', 'creation_date', 'owner', 'is_active', 'allergens')
|
fields = ('name', 'creation_date', 'owner', 'is_active')
|
||||||
widgets = {
|
widgets = {
|
||||||
"owner": Autocomplete(
|
"owner": Autocomplete(
|
||||||
model=Club,
|
model=Club,
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
# Copyright (C) 2018-2024 by BDE ENS Paris-Saclay
|
# Copyright (C) 2018-2024 by BDE ENS Paris-Saclay
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
from django.db import models, transaction
|
from django.db import models, transaction
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
@ -120,6 +122,23 @@ class BasicFood(Food):
|
||||||
# upload_to='label/',
|
# 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:
|
class Meta:
|
||||||
verbose_name = _('Basic food')
|
verbose_name = _('Basic food')
|
||||||
verbose_name_plural = _('Basic foods')
|
verbose_name_plural = _('Basic foods')
|
||||||
|
@ -146,6 +165,47 @@ class TransformedFood(Food):
|
||||||
verbose_name=_('is active'),
|
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:
|
class Meta:
|
||||||
verbose_name = _('Transformed food')
|
verbose_name = _('Transformed food')
|
||||||
verbose_name_plural = _('Transformed foods')
|
verbose_name_plural = _('Transformed foods')
|
||||||
|
|
|
@ -12,6 +12,15 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
</h3>
|
</h3>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p>name : {{ food.name }}</p>
|
<p>name : {{ food.name }}</p>
|
||||||
|
<p>owner : {{ food.owner }}</p>
|
||||||
|
<p>arrival_date : {{ food.arrival_date }}</p>
|
||||||
|
<p>expiry_date : {{ food.expiry_date }}</p>
|
||||||
|
<p>allergens :</p>
|
||||||
|
<ul>
|
||||||
|
{% for allergen in food.allergens.iterator %}
|
||||||
|
<li>{{ allergen.name }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
<a href="{% url "food:basic_update" pk=food.pk %}">Update</a>
|
<a href="{% url "food:basic_update" pk=food.pk %}">Update</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -10,15 +10,10 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
HTML not finished <br>
|
HTML not finished <br>
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</h3>
|
</h3>
|
||||||
<div class="row">
|
|
||||||
<div class="col-xl-12">
|
|
||||||
<div class="btn-group btn-block">
|
|
||||||
<a href="{% url "food:qrcode_basic_create" slug=slug %}" class="btn btn-sm btn-outline-primary">Basic</a>
|
|
||||||
<a href="{% url "food:qrcode_transformed_create" slug=slug %}" class="btn btn-sm btn-outline-primary">Transformed</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-body" id="form">
|
<div class="card-body" id="form">
|
||||||
|
<a class="btn btn-sm btn-success" href="{% url "food:qrcode_basic_create" slug=slug %}" data-turbolinks="false">
|
||||||
|
New basic food
|
||||||
|
</a>
|
||||||
<form method="post">
|
<form method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{{ form|crispy }}
|
{{ form|crispy }}
|
||||||
|
|
|
@ -13,6 +13,8 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<p>name : {{ food.name }}</p>
|
<p>name : {{ food.name }}</p>
|
||||||
<p>owner : {{ food.owner }}</p>
|
<p>owner : {{ food.owner }}</p>
|
||||||
|
<p>creation_date : {{ food.creation_date }}</p>
|
||||||
|
<p>expiry_date : {{ food.expiry_date }}</p>
|
||||||
<p>allergens :</p>
|
<p>allergens :</p>
|
||||||
<ul>
|
<ul>
|
||||||
{% for allergen in food.allergens.iterator %}
|
{% for allergen in food.allergens.iterator %}
|
||||||
|
|
|
@ -15,7 +15,6 @@ urlpatterns = [
|
||||||
path('<int:slug>/create_qrcode', views.QRCodeCreateView.as_view(), name='qrcode_create'),
|
path('<int:slug>/create_qrcode', views.QRCodeCreateView.as_view(), name='qrcode_create'),
|
||||||
path('create', views.FoodCreateView.as_view(), name='food_create'),
|
path('create', views.FoodCreateView.as_view(), name='food_create'),
|
||||||
path('<int:slug>/create_qrcode/basic', views.QRCodeBasicFoodCreateView.as_view(), name='qrcode_basic_create'),
|
path('<int:slug>/create_qrcode/basic', views.QRCodeBasicFoodCreateView.as_view(), name='qrcode_basic_create'),
|
||||||
path('<int:slug>/create_qrcode/transformed', views.QRCodeTransformedFoodCreateView.as_view(), name='qrcode_transformed_create'),
|
|
||||||
path('create/transformed', views.TransformedFoodCreateView.as_view(), name='transformed_create'),
|
path('create/transformed', views.TransformedFoodCreateView.as_view(), name='transformed_create'),
|
||||||
|
|
||||||
path('update/basic/<int:pk>', views.BasicFoodUpdateView.as_view(), name='basic_update'),
|
path('update/basic/<int:pk>', views.BasicFoodUpdateView.as_view(), name='basic_update'),
|
||||||
|
|
|
@ -45,9 +45,7 @@ class AddIngredientView(ProtectQuerysetMixin, FormView):
|
||||||
for transformed_pk in self.request.POST.getlist('ingredient'):
|
for transformed_pk in self.request.POST.getlist('ingredient'):
|
||||||
transformed = TransformedFood.objects.get(pk=transformed_pk)
|
transformed = TransformedFood.objects.get(pk=transformed_pk)
|
||||||
transformed.ingredient.add(food)
|
transformed.ingredient.add(food)
|
||||||
transformed._force_save = True
|
transformed.update()
|
||||||
transformed.save()
|
|
||||||
transformed.refresh_from_db()
|
|
||||||
|
|
||||||
return super().form_valid(form)
|
return super().form_valid(form)
|
||||||
|
|
||||||
|
@ -77,14 +75,9 @@ class BasicFoodUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
|
||||||
if not basic_food_form.is_valid():
|
if not basic_food_form.is_valid():
|
||||||
return self.form_invalid(form)
|
return self.form_invalid(form)
|
||||||
|
|
||||||
# Save the aliment and the allergens associed
|
ans = super().form_valid(form)
|
||||||
basic_food = form.save(commit=False)
|
form.instance.update()
|
||||||
# We assume the date of labeling and the same as the date of arrival
|
return ans
|
||||||
basic_food.arrival_date = timezone.now()
|
|
||||||
basic_food._force_save = True
|
|
||||||
basic_food.save()
|
|
||||||
basic_food.refresh_from_db()
|
|
||||||
return super().form_valid(form)
|
|
||||||
|
|
||||||
def get_success_url(self, **kwargs):
|
def get_success_url(self, **kwargs):
|
||||||
self.object.refresh_from_db()
|
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):
|
class QRCodeView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
|
||||||
"""
|
"""
|
||||||
A view to see a qrcode
|
A view to see a qrcode
|
||||||
|
|
Loading…
Reference in New Issue