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 note_kfet.middlewares import get_current_request | ||||||
| from permission.backends import PermissionBackend | 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): | 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): | class TransformedFoodForms(forms.ModelForm): | ||||||
|     """ |     """ | ||||||
|     Form for add transformed food |     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 | from django.db import migrations, models | ||||||
| import django.db.models.deletion | import django.db.models.deletion | ||||||
| @@ -10,8 +10,8 @@ class Migration(migrations.Migration): | |||||||
|     initial = True |     initial = True | ||||||
|  |  | ||||||
|     dependencies = [ |     dependencies = [ | ||||||
|         ('member', '0011_profile_vss_charter_read'), |  | ||||||
|         ('contenttypes', '0002_remove_content_type_name'), |         ('contenttypes', '0002_remove_content_type_name'), | ||||||
|  |         ('member', '0011_profile_vss_charter_read'), | ||||||
|     ] |     ] | ||||||
|  |  | ||||||
|     operations = [ |     operations = [ | ||||||
| @@ -19,7 +19,7 @@ class Migration(migrations.Migration): | |||||||
|             name='Allergen', |             name='Allergen', | ||||||
|             fields=[ |             fields=[ | ||||||
|                 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |                 ('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={ |             options={ | ||||||
|                 'verbose_name': 'Allergen', |                 'verbose_name': 'Allergen', | ||||||
| @@ -33,7 +33,7 @@ class Migration(migrations.Migration): | |||||||
|                 ('name', models.CharField(max_length=255, verbose_name='name')), |                 ('name', models.CharField(max_length=255, verbose_name='name')), | ||||||
|                 ('expiry_date', models.DateTimeField(verbose_name='expiry date')), |                 ('expiry_date', models.DateTimeField(verbose_name='expiry date')), | ||||||
|                 ('was_eaten', models.BooleanField(default=False, verbose_name='was eaten')), |                 ('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')), |                 ('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')), |                 ('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')), |                 ('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=[ |             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')), |                 ('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)), |                 ('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={ |             options={ | ||||||
|                 'verbose_name': 'Basic food', |                 'verbose_name': 'Basic food', | ||||||
| @@ -55,6 +55,18 @@ class Migration(migrations.Migration): | |||||||
|             }, |             }, | ||||||
|             bases=('food.food',), |             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( |         migrations.CreateModel( | ||||||
|             name='TransformedFood', |             name='TransformedFood', | ||||||
|             fields=[ |             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 member.models import Club | ||||||
| from polymorphic.models import PolymorphicModel | 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): | class QRCode(models.Model): | ||||||
|     """ |     """ | ||||||
| @@ -21,13 +14,13 @@ class QRCode(models.Model): | |||||||
|     """ |     """ | ||||||
|     qr_code_number = models.PositiveIntegerField( |     qr_code_number = models.PositiveIntegerField( | ||||||
|         verbose_name=_("QR-code number"), |         verbose_name=_("QR-code number"), | ||||||
|  |         unique=True, | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     food_container = models.ForeignKey( |     food_container = models.OneToOneField( | ||||||
|         'Food', |         'Food', | ||||||
|         on_delete=models.PROTECT, |         on_delete=models.PROTECT, | ||||||
|         related_name='QR_code', |         related_name='QR_code', | ||||||
|         unique=True, |  | ||||||
|         verbose_name=_('food container'), |         verbose_name=_('food container'), | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
| @@ -77,6 +70,7 @@ class Food(PolymorphicModel): | |||||||
|  |  | ||||||
|     expiry_date = models.DateTimeField( |     expiry_date = models.DateTimeField( | ||||||
|         verbose_name=_('expiry date'), |         verbose_name=_('expiry date'), | ||||||
|  |         null=False, | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     was_eaten = models.BooleanField( |     was_eaten = models.BooleanField( | ||||||
| @@ -84,6 +78,11 @@ class Food(PolymorphicModel): | |||||||
|         verbose_name=_('was eaten'), |         verbose_name=_('was eaten'), | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|  |     is_ready = models.BooleanField( | ||||||
|  |         default=False, | ||||||
|  |         verbose_name=_('is ready'), | ||||||
|  |     ) | ||||||
|  |  | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         return self.name |         return self.name | ||||||
|  |  | ||||||
| @@ -111,7 +110,6 @@ class BasicFood(Food): | |||||||
|     arrival_date = models.DateTimeField( |     arrival_date = models.DateTimeField( | ||||||
|         verbose_name=_('arrival date'), |         verbose_name=_('arrival date'), | ||||||
|         default=timezone.now, |         default=timezone.now, | ||||||
|         blank=True,  # TEMPORARY |  | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     # label = models.ImageField( |     # 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 }} |     {{ title }} | ||||||
|   </h3> |   </h3> | ||||||
|   <div class="card-body"> |   <div class="card-body"> | ||||||
|       <p>name : {{ food.name }}</p> |     <p>name : {{ food.name }}</p> | ||||||
|       <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> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|   | |||||||
| @@ -10,12 +10,12 @@ SPDX-License-Identifier: GPL-3.0-or-later | |||||||
|     {{ title }} |     {{ title }} | ||||||
|   </h3> |   </h3> | ||||||
|     <div class="row"> |     <div class="row"> | ||||||
|         <div class="col-xl-12"> |       <div class="col-xl-12"> | ||||||
|             <div class="btn-group btn-block"> |         <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: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> |             <a href="{% url "food:transformed_create" %}" class="btn btn-sm btn-outline-primary">Transformed</a> | ||||||
|             </div> |  | ||||||
|         </div> |         </div> | ||||||
|  |       </div> | ||||||
|     </div> |     </div> | ||||||
| </div> | </div> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ | |||||||
| {% comment %} | {% comment %} | ||||||
| SPDX-License-Identifier: GPL-3.0-or-later | SPDX-License-Identifier: GPL-3.0-or-later | ||||||
| {% endcomment %} | {% endcomment %} | ||||||
|  | {% load i18n crispy_forms_tags %} | ||||||
|  |  | ||||||
| {% block content %} | {% block content %} | ||||||
| <div class="card bg-white mb-3"> | <div class="card bg-white mb-3"> | ||||||
| @@ -9,13 +10,20 @@ 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="row"> | ||||||
|         <div class="col-xl-12"> |      <div class="col-xl-12"> | ||||||
|             <div class="btn-group btn-block"> |         <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_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> |            <a href="{% url "food:qrcode_transformed_create" slug=slug %}" class="btn btn-sm btn-outline-primary">Transformed</a> | ||||||
|             </div> |  | ||||||
|         </div> |         </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> | </div> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|   | |||||||
| @@ -11,13 +11,14 @@ SPDX-License-Identifier: GPL-3.0-or-later | |||||||
|     {{ title }} |     {{ title }} | ||||||
|   </h3> |   </h3> | ||||||
|   <div class="card-body"> |   <div class="card-body"> | ||||||
|       <p>qrcode : {{ qrcode.qr_code_number }}</p> |     <p>qrcode : {{ qrcode.qr_code_number }}</p> | ||||||
|       <p>name : {{ qrcode.food_container.name }}</p> |     <p>name : {{ qrcode.food_container.name }}</p> | ||||||
|       {% if qrcode.food_container.polymorphic_ctype.name == 'Basic food' %} |     {% if qrcode.food_container.polymorphic_ctype.name == 'Basic food' %} | ||||||
|           <a href="{% url "food:basic_update" pk=qrcode.food_container.pk %}">Update</a> |       <a href="{% url "food:basic_update" pk=qrcode.food_container.pk %}">Update</a> | ||||||
|       {% else %} |     {% else %} | ||||||
|           <a href="{% url "food:transformed_update" pk=qrcode.food_container.pk %}">Update</a> |       <a href="{% url "food:transformed_update" pk=qrcode.food_container.pk %}">Update</a> | ||||||
|       {% endif %} |     {% endif %} | ||||||
|  |     <a href="{% url "food:add_ingredient" pk=qrcode.food_container.pk %}">Add the ingrdient</a> | ||||||
|   </div> |   </div> | ||||||
| </div> | </div> | ||||||
| {% endblock %} | {% endblock %} | ||||||
|   | |||||||
| @@ -13,6 +13,18 @@ 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>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> |     <a href="{% url "food:transformed_update" pk=food.pk %}">Update</a> | ||||||
|   </div> |   </div> | ||||||
| </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' | app_name = 'food' | ||||||
|  |  | ||||||
| urlpatterns = [ | urlpatterns = [ | ||||||
|  |     path('', views.TransfomedListView.as_view(), name='food_list'), | ||||||
|     path('<int:slug>', views.QRCodeView.as_view(), name='qrcode_view'), |     path('<int:slug>', views.QRCodeView.as_view(), name='qrcode_view'), | ||||||
|     path('detail/<int:pk>', views.FoodView.as_view(), name='food_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('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('<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('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'), | ||||||
|     path('update/transformed/<int:pk>', views.TransformedFoodUpdateView.as_view(), name='transformed_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.db import transaction | ||||||
| from django.contrib.auth.mixins import LoginRequiredMixin | from django.contrib.auth.mixins import LoginRequiredMixin | ||||||
| from django.http import HttpResponseRedirect | from django.http import HttpResponseRedirect | ||||||
|  | from django_tables2.views import SingleTableView | ||||||
| from django.urls import reverse | from django.urls import reverse | ||||||
| from django.utils.translation import gettext_lazy as _ | from django.utils.translation import gettext_lazy as _ | ||||||
| from django.utils import timezone | from django.utils import timezone | ||||||
| from django.views.generic import DetailView, UpdateView, TemplateView | from django.views.generic import DetailView, UpdateView, TemplateView | ||||||
|  | from django.views.generic.edit import FormView | ||||||
| from permission.views import ProtectQuerysetMixin, ProtectedCreateView | 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 .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 |     model = Food | ||||||
|     extra_context = {"title": _("Add a new meal")} |     template_name = 'food/add_ingredient_form.html' | ||||||
|     context_object_name = "qrcode" |     extra_context = {"title": _("Add the ingredient")} | ||||||
|     slug_field = "qr_code_number" |     form_class = AddIngredientForms | ||||||
|  |  | ||||||
|     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")} |  | ||||||
|  |  | ||||||
|     def get_context_data(self, **kwargs): |     def get_context_data(self, **kwargs): | ||||||
|         context = super().get_context_data(**kwargs) |         context = super().get_context_data(**kwargs) | ||||||
|         context["slug"] = kwargs["slug"] |         context["pk"] = self.kwargs["pk"] | ||||||
|         return context |         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): |         food = Food.objects.get(pk=self.kwargs['pk']) | ||||||
|     """ |         # Save the aliment and the allergens associed | ||||||
|     A view to add a basic food |         for transformed_pk in self.request.POST.getlist('ingredient'): | ||||||
|     """ |             transformed = TransformedFood.objects.get(pk=transformed_pk) | ||||||
|     model = Food |             transformed.ingredient.add(food) | ||||||
|     extra_context = {"title": _("Add a new meal")} |             transformed._force_save = True | ||||||
|     context_object_name = "food" |             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): | class BasicFoodUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): | ||||||
|     """ |  | ||||||
|     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) |  | ||||||
|     ##################################################################### |  | ||||||
|     """ |     """ | ||||||
|     A view to add a basic food |     A view to add a basic food | ||||||
|     """ |     """ | ||||||
| @@ -98,16 +91,21 @@ class BasicFoodFormView(ProtectQuerysetMixin): | |||||||
|         return reverse('food:food_view', kwargs={"pk": self.object.pk}) |         return reverse('food:food_view', kwargs={"pk": self.object.pk}) | ||||||
|  |  | ||||||
|  |  | ||||||
| class BasicFoodUpdateView(BasicFoodFormView, LoginRequiredMixin, UpdateView): | class FoodCreateView(ProtectQuerysetMixin, LoginRequiredMixin, TemplateView): | ||||||
|     pass |     """ | ||||||
|  |     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): | class FoodView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): | ||||||
|     def get_sample_object(self): |     """ | ||||||
|         return BasicFood( |     A view to see a food | ||||||
|             name="", |     """ | ||||||
|             expiry_date=timezone.now(), |     model = Food | ||||||
|         ) |     extra_context = {"title": _("Details")} | ||||||
|  |     context_object_name = "food" | ||||||
|  |  | ||||||
|  |  | ||||||
| class QRCodeBasicFoodCreateView(ProtectQuerysetMixin, ProtectedCreateView): | 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) |     # - 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 |     model = BasicFood | ||||||
|     form_class = BasicFoodForms |     form_class = BasicFoodForms | ||||||
|     template_name = 'food/basic_food_form.html' |     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 |     @transaction.atomic | ||||||
|     def form_valid(self, form): |     def form_valid(self, form): | ||||||
| @@ -135,6 +133,7 @@ class QRCodeBasicFoodCreateView(ProtectQuerysetMixin, ProtectedCreateView): | |||||||
|         basic_food = form.save(commit=False) |         basic_food = form.save(commit=False) | ||||||
|         # We assume the date of labeling and the same as the date of arrival |         # We assume the date of labeling and the same as the date of arrival | ||||||
|         basic_food.arrival_date = timezone.now() |         basic_food.arrival_date = timezone.now() | ||||||
|  |         basic_food.is_ready = True | ||||||
|         basic_food._force_save = True |         basic_food._force_save = True | ||||||
|         basic_food.save() |         basic_food.save() | ||||||
|         basic_food.refresh_from_db() |         basic_food.refresh_from_db() | ||||||
| @@ -148,7 +147,7 @@ class QRCodeBasicFoodCreateView(ProtectQuerysetMixin, ProtectedCreateView): | |||||||
|  |  | ||||||
|     def get_success_url(self, **kwargs): |     def get_success_url(self, **kwargs): | ||||||
|         self.object.refresh_from_db() |         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): |     def get_sample_object(self): | ||||||
|         return BasicFood( |         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): | 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 |     A view to add a tranformed food | ||||||
|     """ |     """ | ||||||
| @@ -204,48 +308,16 @@ class TransformedFoodCreateView(TransformedFoodFormView, ProtectedCreateView): | |||||||
|         ) |         ) | ||||||
|  |  | ||||||
|  |  | ||||||
| class QRCodeTransformedFoodCreateView(ProtectQuerysetMixin, ProtectedCreateView): | class TransfomedListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView): | ||||||
|     ##################################################################### |  | ||||||
|     # TO DO |  | ||||||
|     # - fix picture save |  | ||||||
|     # - implement solution crop and convert image (reuse or recode ImageForm from members apps) |  | ||||||
|     ##################################################################### |  | ||||||
|     """ |     """ | ||||||
|     A view to add a basic food |     Displays all Activities, and classify if they are on-going or upcoming ones. | ||||||
|     """ |     """ | ||||||
|     model = TransformedFood |     model = TransformedFood | ||||||
|     template_name = 'food/transformed_food_form.html' |     table_class = TransformedFoodTable | ||||||
|     form_class = TransformedFoodForms |     ordering = ('-name',) | ||||||
|     extra_context = {"title": _("Add a new meal")} |     extra_context = {"title": _("Transformed food")} | ||||||
|  |  | ||||||
|     @transaction.atomic |     def get_queryset(self, **kwargs): | ||||||
|     def form_valid(self, form): |         return super().get_queryset(**kwargs)\ | ||||||
|         form.instance.creater = self.request.user |             .filter(is_ready=False)\ | ||||||
|         transformed_food_form = TransformedFoodForms(data=self.request.POST) |             .distinct() | ||||||
|         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(), |  | ||||||
|         ) |  | ||||||
|   | |||||||
| @@ -69,6 +69,7 @@ INSTALLED_APPS = [ | |||||||
|     # Note apps |     # Note apps | ||||||
|     'api', |     'api', | ||||||
|     'activity', |     'activity', | ||||||
|  |     'food', | ||||||
|     'logs', |     'logs', | ||||||
|     'member', |     'member', | ||||||
|     'note', |     'note', | ||||||
| @@ -77,7 +78,6 @@ INSTALLED_APPS = [ | |||||||
|     'scripts', |     'scripts', | ||||||
|     'treasury', |     'treasury', | ||||||
|     'wei', |     'wei', | ||||||
|     'food', |  | ||||||
| ] | ] | ||||||
|  |  | ||||||
| MIDDLEWARE = [ | 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> |                             <a class="nav-link {% if request.path_info == url %}active{% endif %}" href="{{ url }}"><i class="fa fa-coffee"></i> {% trans 'Consumptions' %}</a> | ||||||
|                         </li> |                         </li> | ||||||
|                     {% endif %} |                     {% 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" %} |                     {% if user.is_authenticated and user|is_member:"Kfet" %} | ||||||
|                         <li class="nav-item"> |                         <li class="nav-item"> | ||||||
|                             {% url 'note:transfer' as url %} |                             {% url 'note:transfer' as url %} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user