mirror of https://gitlab.crans.org/bde/nk20
Adding ingredients to a preparation
This commit is contained in:
parent
260513ae3b
commit
48462f2ffc
|
@ -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(
|
||||||
|
|
|
@ -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', )
|
|
@ -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>
|
||||||
|
|
|
@ -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 %}
|
||||||
|
|
Loading…
Reference in New Issue