mirror of
				https://gitlab.crans.org/bde/nk20
				synced 2025-10-31 15:50:03 +01:00 
			
		
		
		
	Adding ingredients to a preparation
This commit is contained in:
		| @@ -11,7 +11,20 @@ from note_kfet.inputs import Autocomplete, DateTimePickerInput | ||||
| from note_kfet.middlewares import get_current_request | ||||
| from permission.backends import PermissionBackend | ||||
|  | ||||
| from .models import BasicFood, TransformedFood | ||||
| from .models import BasicFood, QRCode, TransformedFood | ||||
|  | ||||
|  | ||||
| class AddIngredientForms(forms.ModelForm): | ||||
|     """ | ||||
|     Form for add an ingredient | ||||
|     """ | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         super().__init__(*args, **kwargs) | ||||
|         self.fields['ingredient'].queryset = self.fields['ingredient'].queryset.filter(is_ready=False) | ||||
|  | ||||
|     class Meta: | ||||
|         model = TransformedFood | ||||
|         fields = ('ingredient',) | ||||
|  | ||||
|  | ||||
| class BasicFoodForms(forms.ModelForm): | ||||
| @@ -42,6 +55,19 @@ class BasicFoodForms(forms.ModelForm): | ||||
|         } | ||||
|  | ||||
|  | ||||
| class QRCodeForms(forms.ModelForm): | ||||
|     """ | ||||
|     Form for create QRCode | ||||
|     """ | ||||
|     def __init__(self, *args, **kwargs): | ||||
|         super().__init__(*args, **kwargs) | ||||
|         self.fields['food_container'].queryset = self.fields['food_container'].queryset.filter(is_ready=False) | ||||
|  | ||||
|     class Meta: | ||||
|         model = QRCode | ||||
|         fields = ('food_container',) | ||||
|  | ||||
|  | ||||
| class TransformedFoodForms(forms.ModelForm): | ||||
|     """ | ||||
|     Form for add transformed food | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| # Generated by Django 2.2.28 on 2024-07-03 07:40 | ||||
| # Generated by Django 2.2.28 on 2024-07-05 08:57 | ||||
|  | ||||
| from django.db import migrations, models | ||||
| import django.db.models.deletion | ||||
| @@ -10,8 +10,8 @@ class Migration(migrations.Migration): | ||||
|     initial = True | ||||
|  | ||||
|     dependencies = [ | ||||
|         ('member', '0011_profile_vss_charter_read'), | ||||
|         ('contenttypes', '0002_remove_content_type_name'), | ||||
|         ('member', '0011_profile_vss_charter_read'), | ||||
|     ] | ||||
|  | ||||
|     operations = [ | ||||
| @@ -19,7 +19,7 @@ class Migration(migrations.Migration): | ||||
|             name='Allergen', | ||||
|             fields=[ | ||||
|                 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||||
|                 ('name', models.CharField(max_length=255, null=True, verbose_name='name')), | ||||
|                 ('name', models.CharField(max_length=255, verbose_name='name')), | ||||
|             ], | ||||
|             options={ | ||||
|                 'verbose_name': 'Allergen', | ||||
| @@ -33,7 +33,7 @@ class Migration(migrations.Migration): | ||||
|                 ('name', models.CharField(max_length=255, verbose_name='name')), | ||||
|                 ('expiry_date', models.DateTimeField(verbose_name='expiry date')), | ||||
|                 ('was_eaten', models.BooleanField(default=False, verbose_name='was eaten')), | ||||
|                 ('code', models.IntegerField(unique=True, verbose_name='code')), | ||||
|                 ('is_ready', models.BooleanField(default=False, verbose_name='is ready')), | ||||
|                 ('allergens', models.ManyToManyField(blank=True, to='food.Allergen', verbose_name='allergen')), | ||||
|                 ('owner', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='+', to='member.Club', verbose_name='owner')), | ||||
|                 ('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_food.food_set+', to='contenttypes.ContentType')), | ||||
| @@ -47,7 +47,7 @@ class Migration(migrations.Migration): | ||||
|             fields=[ | ||||
|                 ('food_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='food.Food')), | ||||
|                 ('date_type', models.CharField(choices=[('DLC', 'DLC'), ('DDM', 'DDM')], max_length=255)), | ||||
|                 ('arrival_date', models.DateTimeField(blank=True, default=django.utils.timezone.now, verbose_name='arrival date')), | ||||
|                 ('arrival_date', models.DateTimeField(default=django.utils.timezone.now, verbose_name='arrival date')), | ||||
|             ], | ||||
|             options={ | ||||
|                 'verbose_name': 'Basic food', | ||||
| @@ -55,6 +55,18 @@ class Migration(migrations.Migration): | ||||
|             }, | ||||
|             bases=('food.food',), | ||||
|         ), | ||||
|         migrations.CreateModel( | ||||
|             name='QRCode', | ||||
|             fields=[ | ||||
|                 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||||
|                 ('qr_code_number', models.PositiveIntegerField(unique=True, verbose_name='QR-code number')), | ||||
|                 ('food_container', models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, related_name='QR_code', to='food.Food', verbose_name='food container')), | ||||
|             ], | ||||
|             options={ | ||||
|                 'verbose_name': 'QR-code', | ||||
|                 'verbose_name_plural': 'QR-codes', | ||||
|             }, | ||||
|         ), | ||||
|         migrations.CreateModel( | ||||
|             name='TransformedFood', | ||||
|             fields=[ | ||||
|   | ||||
| @@ -1,30 +0,0 @@ | ||||
| # Generated by Django 2.2.28 on 2024-07-03 13:49 | ||||
|  | ||||
| from django.db import migrations, models | ||||
| import django.db.models.deletion | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|  | ||||
|     dependencies = [ | ||||
|         ('food', '0001_initial'), | ||||
|     ] | ||||
|  | ||||
|     operations = [ | ||||
|         migrations.RemoveField( | ||||
|             model_name='food', | ||||
|             name='code', | ||||
|         ), | ||||
|         migrations.CreateModel( | ||||
|             name='QRCode', | ||||
|             fields=[ | ||||
|                 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||||
|                 ('qr_code_number', models.PositiveIntegerField(verbose_name='QR-code number')), | ||||
|                 ('food_container', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='QR_code', to='food.Food', unique=True, verbose_name='food container')), | ||||
|             ], | ||||
|             options={ | ||||
|                 'verbose_name': 'QR-code', | ||||
|                 'verbose_name_plural': 'QR-codes', | ||||
|             }, | ||||
|         ), | ||||
|     ] | ||||
| @@ -7,13 +7,6 @@ from django.utils.translation import gettext_lazy as _ | ||||
| from member.models import Club | ||||
| from polymorphic.models import PolymorphicModel | ||||
|  | ||||
| ################################################################# | ||||
| # TO DO | ||||
| # - link allergen with one food (basic or transformed) with check | ||||
| # - check on basic food | ||||
| # - check on transformed food | ||||
| ################################################################# | ||||
|  | ||||
|  | ||||
| class QRCode(models.Model): | ||||
|     """ | ||||
| @@ -21,13 +14,13 @@ class QRCode(models.Model): | ||||
|     """ | ||||
|     qr_code_number = models.PositiveIntegerField( | ||||
|         verbose_name=_("QR-code number"), | ||||
|         unique=True, | ||||
|     ) | ||||
|  | ||||
|     food_container = models.ForeignKey( | ||||
|     food_container = models.OneToOneField( | ||||
|         'Food', | ||||
|         on_delete=models.PROTECT, | ||||
|         related_name='QR_code', | ||||
|         unique=True, | ||||
|         verbose_name=_('food container'), | ||||
|     ) | ||||
|  | ||||
| @@ -77,6 +70,7 @@ class Food(PolymorphicModel): | ||||
|  | ||||
|     expiry_date = models.DateTimeField( | ||||
|         verbose_name=_('expiry date'), | ||||
|         null=False, | ||||
|     ) | ||||
|  | ||||
|     was_eaten = models.BooleanField( | ||||
| @@ -84,6 +78,11 @@ class Food(PolymorphicModel): | ||||
|         verbose_name=_('was eaten'), | ||||
|     ) | ||||
|  | ||||
|     is_ready = models.BooleanField( | ||||
|         default=False, | ||||
|         verbose_name=_('is ready'), | ||||
|     ) | ||||
|  | ||||
|     def __str__(self): | ||||
|         return self.name | ||||
|  | ||||
| @@ -111,7 +110,6 @@ class BasicFood(Food): | ||||
|     arrival_date = models.DateTimeField( | ||||
|         verbose_name=_('arrival date'), | ||||
|         default=timezone.now, | ||||
|         blank=True,  # TEMPORARY | ||||
|     ) | ||||
|  | ||||
|     # label = models.ImageField( | ||||
|   | ||||
							
								
								
									
										19
									
								
								apps/food/tables.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								apps/food/tables.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| # Copyright (C) 2018-2024 by BDE ENS Paris-Saclay | ||||
| # SPDX-License-Identifier: GPL-3.0-or-later | ||||
|  | ||||
| import django_tables2 as tables | ||||
| from django_tables2 import A | ||||
|  | ||||
| from .models import TransformedFood | ||||
|  | ||||
|  | ||||
| class TransformedFoodTable(tables.Table): | ||||
|     name = tables.LinkColumn( | ||||
|         'food:food_view', | ||||
|         args=[A('pk'), ], | ||||
|     ) | ||||
|  | ||||
|     class Meta: | ||||
|         model = TransformedFood | ||||
|         template_name = 'django_tables2/bootstrap4.html' | ||||
|         fields = ('name', ) | ||||
							
								
								
									
										21
									
								
								apps/food/templates/food/add_ingredient_form.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								apps/food/templates/food/add_ingredient_form.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| {% extends "base.html" %} | ||||
| {% comment %} | ||||
| SPDX-License-Identifier: GPL-3.0-or-later | ||||
| {% endcomment %} | ||||
| {% load i18n crispy_forms_tags %} | ||||
|  | ||||
| {% block content %} | ||||
| <div class="card bg-white mb-3"> | ||||
|   <h3 class="card-header text-center"> | ||||
|     HTML not finished <br> | ||||
|     {{ title }} | ||||
|   </h3> | ||||
|   <div class="card-body" id="form"> | ||||
|     <form method="post"> | ||||
|       {%  csrf_token %} | ||||
|       {{ form|crispy }} | ||||
|       <button class="btn btn-primary" type="submit">{% trans "Submit"%}</button> | ||||
|     </form> | ||||
|   </div> | ||||
| </div> | ||||
| {% endblock %} | ||||
| @@ -11,8 +11,8 @@ SPDX-License-Identifier: GPL-3.0-or-later | ||||
|     {{ title }} | ||||
|   </h3> | ||||
|   <div class="card-body"> | ||||
|       <p>name : {{ food.name }}</p> | ||||
|       <a href="{% url "food:basic_update" pk=food.pk %}">Update</a> | ||||
|     <p>name : {{ food.name }}</p> | ||||
|     <a href="{% url "food:basic_update" pk=food.pk %}">Update</a> | ||||
|   </div> | ||||
| </div> | ||||
| {% endblock %} | ||||
|   | ||||
| @@ -10,12 +10,12 @@ SPDX-License-Identifier: GPL-3.0-or-later | ||||
|     {{ title }} | ||||
|   </h3> | ||||
|     <div class="row"> | ||||
|         <div class="col-xl-12"> | ||||
|             <div class="btn-group btn-block"> | ||||
|                 <a href="{% url "food:basic_create" %}" class="btn btn-sm btn-outline-primary">Basic</a> | ||||
|                 <a href="{% url "food:transformed_create" %}" class="btn btn-sm btn-outline-primary">Transformed</a> | ||||
|             </div> | ||||
|       <div class="col-xl-12"> | ||||
|         <div class="btn-group btn-block"> | ||||
|             <a href="{% url "food:basic_create" %}" class="btn btn-sm btn-outline-primary">Basic</a> | ||||
|             <a href="{% url "food:transformed_create" %}" class="btn btn-sm btn-outline-primary">Transformed</a> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div> | ||||
| </div> | ||||
| {% endblock %} | ||||
|   | ||||
| @@ -2,6 +2,7 @@ | ||||
| {% comment %} | ||||
| SPDX-License-Identifier: GPL-3.0-or-later | ||||
| {% endcomment %} | ||||
| {% load i18n crispy_forms_tags %} | ||||
|  | ||||
| {% block content %} | ||||
| <div class="card bg-white mb-3"> | ||||
| @@ -9,13 +10,20 @@ SPDX-License-Identifier: GPL-3.0-or-later | ||||
|     HTML not finished <br> | ||||
|     {{ title }} | ||||
|   </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 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> | ||||
|   <div class="card-body" id="form"> | ||||
|     <form method="post"> | ||||
|       {%  csrf_token %} | ||||
|       {{ form|crispy }} | ||||
|       <button class="btn btn-primary" type="submit">{% trans "Submit"%}</button> | ||||
|     </form> | ||||
|   </div> | ||||
| </div> | ||||
| {% endblock %} | ||||
|   | ||||
| @@ -11,13 +11,14 @@ SPDX-License-Identifier: GPL-3.0-or-later | ||||
|     {{ title }} | ||||
|   </h3> | ||||
|   <div class="card-body"> | ||||
|       <p>qrcode : {{ qrcode.qr_code_number }}</p> | ||||
|       <p>name : {{ qrcode.food_container.name }}</p> | ||||
|       {% if qrcode.food_container.polymorphic_ctype.name == 'Basic food' %} | ||||
|           <a href="{% url "food:basic_update" pk=qrcode.food_container.pk %}">Update</a> | ||||
|       {% else %} | ||||
|           <a href="{% url "food:transformed_update" pk=qrcode.food_container.pk %}">Update</a> | ||||
|       {% endif %} | ||||
|     <p>qrcode : {{ qrcode.qr_code_number }}</p> | ||||
|     <p>name : {{ qrcode.food_container.name }}</p> | ||||
|     {% if qrcode.food_container.polymorphic_ctype.name == 'Basic food' %} | ||||
|       <a href="{% url "food:basic_update" pk=qrcode.food_container.pk %}">Update</a> | ||||
|     {% else %} | ||||
|       <a href="{% url "food:transformed_update" pk=qrcode.food_container.pk %}">Update</a> | ||||
|     {% endif %} | ||||
|     <a href="{% url "food:add_ingredient" pk=qrcode.food_container.pk %}">Add the ingrdient</a> | ||||
|   </div> | ||||
| </div> | ||||
| {% endblock %} | ||||
|   | ||||
| @@ -13,6 +13,18 @@ SPDX-License-Identifier: GPL-3.0-or-later | ||||
|   <div class="card-body"> | ||||
|     <p>name : {{ food.name }}</p> | ||||
|     <p>owner : {{ food.owner }}</p> | ||||
|     <p>allergens :</p> | ||||
|     <ul> | ||||
|       {% for allergen in food.allergens.iterator %} | ||||
|         <li>{{ allergen.name }}</li> | ||||
|       {% endfor %} | ||||
|     </ul> | ||||
|     <p>ingredients :</p> | ||||
|     <ul> | ||||
|       {% for ingredient in food.ingredient.iterator %} | ||||
|         <li><a href="{% url "food:food_view" pk=ingredient.pk %}">{{ ingredient.name }}</a></li> | ||||
|       {% endfor %} | ||||
|     </ul> | ||||
|     <a href="{% url "food:transformed_update" pk=food.pk %}">Update</a> | ||||
|   </div> | ||||
| </div> | ||||
|   | ||||
							
								
								
									
										20
									
								
								apps/food/templates/food/transformedfood_list.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								apps/food/templates/food/transformedfood_list.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| {% extends "base.html" %} | ||||
| {% comment %} | ||||
| SPDX-License-Identifier: GPL-3.0-or-later | ||||
| {% endcomment %} | ||||
| {% load render_table from django_tables2 %} | ||||
| {% load i18n %} | ||||
|  | ||||
| {% block content %} | ||||
| <div class="card bg-light mb-3"> | ||||
|   <h3 class="card-header text-center"> | ||||
|     Transformed food | ||||
|   </h3> | ||||
|   <div class="card-footer"> | ||||
|     <a class="btn btn-sm btn-success" href="{% url 'food:transformed_create' %}" data-turbolinks="false"> | ||||
|       New transformed food | ||||
|     </a> | ||||
|   </div> | ||||
|   {% render_table table %} | ||||
| </div> | ||||
| {% endblock %} | ||||
| @@ -8,6 +8,7 @@ from . import views | ||||
| app_name = 'food' | ||||
|  | ||||
| urlpatterns = [ | ||||
|     path('', views.TransfomedListView.as_view(), name='food_list'), | ||||
|     path('<int:slug>', views.QRCodeView.as_view(), name='qrcode_view'), | ||||
|     path('detail/<int:pk>', views.FoodView.as_view(), name='food_view'), | ||||
|  | ||||
| @@ -15,9 +16,10 @@ urlpatterns = [ | ||||
|     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/transformed', views.QRCodeTransformedFoodCreateView.as_view(), name='qrcode_transformed_create'), | ||||
|     path('create/basic', views.BasicFoodCreateView.as_view(), name='basic_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/transformed/<int:pk>', views.TransformedFoodUpdateView.as_view(), name='transformed_update'), | ||||
|  | ||||
|     path('add/<int:pk>', views.AddIngredientView.as_view(), name='add_ingredient'), | ||||
| ] | ||||
|   | ||||
| @@ -6,69 +6,62 @@ from datetime import timedelta | ||||
| from django.db import transaction | ||||
| from django.contrib.auth.mixins import LoginRequiredMixin | ||||
| from django.http import HttpResponseRedirect | ||||
| from django_tables2.views import SingleTableView | ||||
| 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, TemplateView | ||||
| from django.views.generic.edit import FormView | ||||
| from permission.views import ProtectQuerysetMixin, ProtectedCreateView | ||||
|  | ||||
| from .forms import BasicFoodForms, TransformedFoodForms | ||||
| from .forms import AddIngredientForms, BasicFoodForms, QRCodeForms, TransformedFoodForms | ||||
| from .models import BasicFood, Food, QRCode, TransformedFood | ||||
| from .tables import TransformedFoodTable | ||||
|  | ||||
|  | ||||
| class QRCodeView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): | ||||
| class AddIngredientView(ProtectQuerysetMixin, FormView): | ||||
|     """ | ||||
|     A view to add a basic food | ||||
|     A view to see a qrcode | ||||
|     """ | ||||
|     model = QRCode | ||||
|     extra_context = {"title": _("Add a new meal")} | ||||
|     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)) | ||||
|  | ||||
|  | ||||
| class QRCodeCreateView(ProtectQuerysetMixin, LoginRequiredMixin, TemplateView): | ||||
|     """ | ||||
|     A view to add a basic food | ||||
|     """ | ||||
|     template_name = 'food/create_qrcode_form.html' | ||||
|     extra_context = {"title": _("Add a new aliment")} | ||||
|     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["slug"] = kwargs["slug"] | ||||
|         context["pk"] = self.kwargs["pk"] | ||||
|         return context | ||||
|  | ||||
|     @transaction.atomic | ||||
|     def form_valid(self, form): | ||||
|         form.instance.creater = self.request.user | ||||
|         add_ingredient_form = AddIngredientForms(data=self.request.POST) | ||||
|         if not add_ingredient_form.is_valid(): | ||||
|             return self.form_invalid(form) | ||||
|  | ||||
| class FoodView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): | ||||
|     """ | ||||
|     A view to add a basic food | ||||
|     """ | ||||
|     model = Food | ||||
|     extra_context = {"title": _("Add a new meal")} | ||||
|     context_object_name = "food" | ||||
|         food = Food.objects.get(pk=self.kwargs['pk']) | ||||
|         # Save the aliment and the allergens associed | ||||
|         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() | ||||
|  | ||||
|         return super().form_valid(form) | ||||
|  | ||||
|     def get_success_url(self, **kwargs): | ||||
|         return reverse('food:food_list') | ||||
|  | ||||
|     def get_sample_object(self): | ||||
|         return TransformedFood( | ||||
|             name="", | ||||
|             creation_date=timezone.now(), | ||||
|         ) | ||||
|  | ||||
|  | ||||
| class FoodCreateView(ProtectQuerysetMixin, LoginRequiredMixin, TemplateView): | ||||
|     """ | ||||
|     A view to add a basic food | ||||
|     """ | ||||
|     template_name = 'food/create_food_form.html' | ||||
|     extra_context = {"title": _("Add a new aliment")} | ||||
|  | ||||
|  | ||||
| class BasicFoodFormView(ProtectQuerysetMixin): | ||||
|     ##################################################################### | ||||
|     # TO DO | ||||
|     # - fix picture save | ||||
|     # - implement solution crop and convert image (reuse or recode ImageForm from members apps) | ||||
|     ##################################################################### | ||||
| class BasicFoodUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): | ||||
|     """ | ||||
|     A view to add a basic food | ||||
|     """ | ||||
| @@ -98,16 +91,21 @@ class BasicFoodFormView(ProtectQuerysetMixin): | ||||
|         return reverse('food:food_view', kwargs={"pk": self.object.pk}) | ||||
|  | ||||
|  | ||||
| class BasicFoodUpdateView(BasicFoodFormView, LoginRequiredMixin, UpdateView): | ||||
|     pass | ||||
| class FoodCreateView(ProtectQuerysetMixin, LoginRequiredMixin, TemplateView): | ||||
|     """ | ||||
|     A view to add a new aliment | ||||
|     """ | ||||
|     template_name = 'food/create_food_form.html' | ||||
|     extra_context = {"title": _("Add a new aliment")} | ||||
|  | ||||
|  | ||||
| class BasicFoodCreateView(BasicFoodFormView, ProtectedCreateView): | ||||
|     def get_sample_object(self): | ||||
|         return BasicFood( | ||||
|             name="", | ||||
|             expiry_date=timezone.now(), | ||||
|         ) | ||||
| class FoodView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): | ||||
|     """ | ||||
|     A view to see a food | ||||
|     """ | ||||
|     model = Food | ||||
|     extra_context = {"title": _("Details")} | ||||
|     context_object_name = "food" | ||||
|  | ||||
|  | ||||
| class QRCodeBasicFoodCreateView(ProtectQuerysetMixin, ProtectedCreateView): | ||||
| @@ -117,12 +115,12 @@ class QRCodeBasicFoodCreateView(ProtectQuerysetMixin, ProtectedCreateView): | ||||
|     # - implement solution crop and convert image (reuse or recode ImageForm from members apps) | ||||
|     ##################################################################### | ||||
|     """ | ||||
|     A view to add a basic food | ||||
|     A view to add a basic food with a qrcode | ||||
|     """ | ||||
|     model = BasicFood | ||||
|     form_class = BasicFoodForms | ||||
|     template_name = 'food/basic_food_form.html' | ||||
|     extra_context = {"title": _("Add a new aliment")} | ||||
|     extra_context = {"title": _("Add a new basic food with QRCode")} | ||||
|  | ||||
|     @transaction.atomic | ||||
|     def form_valid(self, form): | ||||
| @@ -135,6 +133,7 @@ class QRCodeBasicFoodCreateView(ProtectQuerysetMixin, ProtectedCreateView): | ||||
|         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 = True | ||||
|         basic_food._force_save = True | ||||
|         basic_food.save() | ||||
|         basic_food.refresh_from_db() | ||||
| @@ -148,7 +147,7 @@ class QRCodeBasicFoodCreateView(ProtectQuerysetMixin, ProtectedCreateView): | ||||
|  | ||||
|     def get_success_url(self, **kwargs): | ||||
|         self.object.refresh_from_db() | ||||
|         return reverse('food:food_view', kwargs={"pk": self.object.pk}) | ||||
|         return reverse('food:qrcode_view', kwargs={"slug": self.kwargs['slug']}) | ||||
|  | ||||
|     def get_sample_object(self): | ||||
|         return BasicFood( | ||||
| @@ -157,12 +156,117 @@ class QRCodeBasicFoodCreateView(ProtectQuerysetMixin, ProtectedCreateView): | ||||
|         ) | ||||
|  | ||||
|  | ||||
| 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"] | ||||
|         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.is_ready = True | ||||
|         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"], | ||||
|         ) | ||||
|  | ||||
|  | ||||
| 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 | ||||
|     """ | ||||
|     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)) | ||||
|  | ||||
|  | ||||
| class TransformedFoodFormView(ProtectQuerysetMixin): | ||||
|     ##################################################################### | ||||
|     # TO DO | ||||
|     # - fix picture save | ||||
|     # - implement solution crop and convert image (reuse or recode ImageForm from members apps) | ||||
|     ##################################################################### | ||||
|     """ | ||||
|     A view to add a tranformed food | ||||
|     """ | ||||
| @@ -204,48 +308,16 @@ class TransformedFoodCreateView(TransformedFoodFormView, ProtectedCreateView): | ||||
|         ) | ||||
|  | ||||
|  | ||||
| class QRCodeTransformedFoodCreateView(ProtectQuerysetMixin, ProtectedCreateView): | ||||
|     ##################################################################### | ||||
|     # TO DO | ||||
|     # - fix picture save | ||||
|     # - implement solution crop and convert image (reuse or recode ImageForm from members apps) | ||||
|     ##################################################################### | ||||
| class TransfomedListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView): | ||||
|     """ | ||||
|     A view to add a basic food | ||||
|     Displays all Activities, and classify if they are on-going or upcoming ones. | ||||
|     """ | ||||
|     model = TransformedFood | ||||
|     template_name = 'food/transformed_food_form.html' | ||||
|     form_class = TransformedFoodForms | ||||
|     extra_context = {"title": _("Add a new meal")} | ||||
|     table_class = TransformedFoodTable | ||||
|     ordering = ('-name',) | ||||
|     extra_context = {"title": _("Transformed food")} | ||||
|  | ||||
|     @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._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:food_view', kwargs={"pk": self.object.pk}) | ||||
|  | ||||
|     def get_sample_object(self): | ||||
|         return BasicFood( | ||||
|             name="", | ||||
|             expiry_date=timezone.now(), | ||||
|         ) | ||||
|     def get_queryset(self, **kwargs): | ||||
|         return super().get_queryset(**kwargs)\ | ||||
|             .filter(is_ready=False)\ | ||||
|             .distinct() | ||||
|   | ||||
| @@ -69,6 +69,7 @@ INSTALLED_APPS = [ | ||||
|     # Note apps | ||||
|     'api', | ||||
|     'activity', | ||||
|     'food', | ||||
|     'logs', | ||||
|     'member', | ||||
|     'note', | ||||
| @@ -77,7 +78,6 @@ INSTALLED_APPS = [ | ||||
|     'scripts', | ||||
|     'treasury', | ||||
|     'wei', | ||||
|     'food', | ||||
| ] | ||||
|  | ||||
| MIDDLEWARE = [ | ||||
|   | ||||
| @@ -66,6 +66,10 @@ SPDX-License-Identifier: GPL-3.0-or-later | ||||
|                             <a class="nav-link {% if request.path_info == url %}active{% endif %}" href="{{ url }}"><i class="fa fa-coffee"></i> {% trans 'Consumptions' %}</a> | ||||
|                         </li> | ||||
|                     {% endif %} | ||||
|                     <li class="nav-item"> | ||||
|                         {% url 'food:food_list' as url %} | ||||
|                         <a data-turbolinks="false" class="nav-link" href="{{ url }}">Food</a> | ||||
|                     </li> | ||||
|                     {% if user.is_authenticated and user|is_member:"Kfet" %} | ||||
|                         <li class="nav-item"> | ||||
|                             {% url 'note:transfer' as url %} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user