1
0
mirror of https://gitlab.crans.org/bde/nk20 synced 2025-02-24 00:51:20 +00:00

Compare commits

..

No commits in common. "a3073ba5a53c2aadb0c3725c756c633d4db50e6e" and "c8afee91d2e3f4b23af43ea26f78879fa8948c0c" have entirely different histories.

9 changed files with 33 additions and 310 deletions

View File

@ -1,10 +1,7 @@
# Copyright (C) 2018-2024 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from django.contrib import admin from django.contrib import admin
from note_kfet.admin import admin_site from note_kfet.admin import admin_site
from .models import QR_code, BasicFood, TransformedFood, Allergen from .models import QR_code, Basic_food, Transformed_food, Allergen
@admin.register(QR_code, site = admin_site) @admin.register(QR_code, site = admin_site)
@ -13,13 +10,13 @@ class QR_codeAdmin(admin.ModelAdmin):
TEMPORARY TEMPORARY
""" """
@admin.register(BasicFood, site = admin_site) @admin.register(Basic_food, site = admin_site)
class Basic_foodAdmin(admin.ModelAdmin): class Basic_foodAdmin(admin.ModelAdmin):
""" """
TEMPORARY TEMPORARY
""" """
@admin.register(TransformedFood, site = admin_site) @admin.register(Transformed_food, site = admin_site)
class Transformed_foodAdmin(admin.ModelAdmin): class Transformed_foodAdmin(admin.ModelAdmin):
""" """
TEMPORARY TEMPORARY

View File

@ -1,10 +1,5 @@
# Copyright (C) 2018-2024 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from django.apps import AppConfig from django.apps import AppConfig
class FoodkfetConfig(AppConfig): class FoodkfetConfig(AppConfig):
name = 'food' name = 'foodkfet'
verbose_name = _('food')

View File

@ -1,92 +0,0 @@
# Copyright (C) 2018-2024 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from random import shuffle
from django import forms
from django.utils.translation import gettext_lazy as _
from django.utils import timezone
from member.models import Club
from note_kfet.inputs import Autocomplete, DatePickerInput, DateTimePickerInput
from note_kfet.middlewares import get_current_request
from permission.backends import PermissionBackend
from .models import QR_code, Allergen, BasicFood, TransformedFood
class BasicFoodForms(forms.ModelForm):
"""
Form for add non-transformed food
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['name'].widget.attrs.update({"autofocus": "autofocus"})
self.fields['name'].required = True
self.fields['owner'].required = True
self.fields['label'].help_text = _('The lot number must be contained in the picture')
# Some example
self.fields['name'].widget.attrs.update({"placeholder": _("pasta")})
clubs = list(Club.objects.filter(PermissionBackend.filter_queryset(get_current_request(), Club, "change")).all())
shuffle(clubs)
self.fields['owner'].widget.attrs["placeholder"] = ", ".join(club.name for club in clubs[:4]) + ", ..."
def clean_dlm_or_dlc(self):
is_dlc = self.cleaned_data["is_DLC"]
is_ddm = self.cleaned_data["is_DDM"]
if is_dlc and is_ddm:
self.add_error("is_ddm", _("the product cannot be a DLC and a DDM"))
return is_ddm
class Meta:
model = BasicFood
fields = ('name', 'owner', 'is_DLC', 'is_DDM', 'expiry_date', 'label')
widgets = {
"owner": Autocomplete(
model = Club,
attrs = {"api_url": "/api/members/club/"},
),
'expiry_date': DatePickerInput(),
}
class TransformedFoodForms(forms.ModelForm):
"""
Form for add transformed food
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['name'].widget.attrs.update({"autofocus": "autofocus"})
self.fields['name'].required = True
self.fields['owner'].required = True
self.fields['creation_date'].required = True
self.fields['creation_date'].initial = timezone.now
self.fields['is_active'].initial = True
# Some example
self.fields['name'].widget.attrs.update({"placeholder": _("lasagna")})
clubs = list(Club.objects.filter(PermissionBackend.filter_queryset(get_current_request(), Club, "change")).all())
shuffle(clubs)
self.fields['owner'].widget.attrs["placeholder"] = ", ".join(club.name for club in clubs[:4]) + ", ..."
class Meta:
model = TransformedFood
fields = ('name', 'creation_date', 'owner', 'is_active',)
widgets = {
"owner": Autocomplete(
model = Club,
attrs = {"api_url": "/api/members/club/"},
),
'creation_date': DateTimePickerInput(),
}
class AllergenForms(forms.ModelForm):
"""
Form for allergen
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
class Meta:
model = Allergen
exclude = ['basic_food', 'transformed_food']

View File

@ -1,4 +1,4 @@
# Generated by Django 2.2.28 on 2024-05-25 20:32 # Generated by Django 2.2.28 on 2024-05-21 12:05
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
@ -15,15 +15,14 @@ class Migration(migrations.Migration):
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='BasicFood', name='Basic_food',
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, verbose_name='name')), ('name', models.CharField(max_length=255, verbose_name='name')),
('is_DLC', models.BooleanField(default=False, verbose_name='is DLC')), ('is_DLC', models.BooleanField(default=False, verbose_name='is DLC')),
('is_DDM', models.BooleanField(default=False, verbose_name='is DDM')), ('is_DDM', models.BooleanField(default=False, verbose_name='is DDM')),
('arrival_date', models.DateTimeField(default=django.utils.timezone.now, verbose_name='arrival date')), ('expiry_date', models.DateTimeField(blank=True, default=django.utils.timezone.now, verbose_name='expiry date')),
('expiry_date', models.DateTimeField(blank=True, null=True, verbose_name='expiry date')), ('label', models.ImageField(default='pic/default.png', max_length=255, upload_to='label/', verbose_name='food label')),
('label', models.ImageField(max_length=255, upload_to='label/', verbose_name='food label')),
('was_eaten', models.BooleanField(default=False, verbose_name='was eaten')), ('was_eaten', models.BooleanField(default=False, verbose_name='was eaten')),
('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')),
], ],
@ -33,7 +32,7 @@ class Migration(migrations.Migration):
}, },
), ),
migrations.CreateModel( migrations.CreateModel(
name='TransformedFood', name='Transformed_food',
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, verbose_name='name')), ('name', models.CharField(max_length=255, verbose_name='name')),
@ -42,7 +41,7 @@ class Migration(migrations.Migration):
('is_active', models.BooleanField(default=True, verbose_name='is active')), ('is_active', models.BooleanField(default=True, verbose_name='is active')),
('was_eaten', models.BooleanField(default=False, verbose_name='was eaten')), ('was_eaten', models.BooleanField(default=False, verbose_name='was eaten')),
('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')),
('transformed_ingredient', models.ManyToManyField(blank=True, related_name='transformed_ingredient_inv', to='food.TransformedFood', verbose_name='transformed ingredient')), ('transformed_ingredient', models.ManyToManyField(blank=True, related_name='transformed_ingredient_inv', to='food.Transformed_food', verbose_name='transformed ingredient')),
], ],
options={ options={
'verbose_name': 'Transformed food', 'verbose_name': 'Transformed food',
@ -54,8 +53,8 @@ class Migration(migrations.Migration):
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')),
('qr_code_number', models.PositiveIntegerField(verbose_name='QR-code number')), ('qr_code_number', models.PositiveIntegerField(verbose_name='QR-code number')),
('basic_food', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='QR_code', to='food.BasicFood', verbose_name='basic food')), ('basic_food', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='QR_code', to='food.Basic_food', verbose_name='basic food')),
('transformed_food_container', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='QR_code', to='food.TransformedFood', verbose_name='transformed food container')), ('transformed_food_container', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='QR_code', to='food.Transformed_food', verbose_name='transformed food container')),
], ],
options={ options={
'verbose_name': 'QR-code', 'verbose_name': 'QR-code',
@ -63,9 +62,9 @@ class Migration(migrations.Migration):
}, },
), ),
migrations.AddField( migrations.AddField(
model_name='basicfood', model_name='basic_food',
name='transformed_food', name='transformed_food',
field=models.ManyToManyField(blank=True, related_name='BasicFood', to='food.TransformedFood', verbose_name='transformed food'), field=models.ManyToManyField(blank=True, related_name='Basic_food', to='food.Transformed_food', verbose_name='transformed food'),
), ),
migrations.CreateModel( migrations.CreateModel(
name='Allergen', name='Allergen',
@ -86,8 +85,8 @@ class Migration(migrations.Migration):
('groundnut', models.BooleanField(default=False, verbose_name='groundnut')), ('groundnut', models.BooleanField(default=False, verbose_name='groundnut')),
('sesame', models.BooleanField(default=False, verbose_name='sesame')), ('sesame', models.BooleanField(default=False, verbose_name='sesame')),
('alcohol', models.BooleanField(default=False, verbose_name='alcohol')), ('alcohol', models.BooleanField(default=False, verbose_name='alcohol')),
('basic_food', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='Allergen', to='food.BasicFood', verbose_name='basic food')), ('basic_food', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='Allergen', to='food.Basic_food', verbose_name='basic food')),
('transformed_food', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='Allergen', to='food.TransformedFood', verbose_name='transformed food')), ('transformed_food', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='Allergen', to='food.Transformed_food', verbose_name='transformed food')),
], ],
options={ options={
'verbose_name': 'Allergen', 'verbose_name': 'Allergen',

View File

@ -7,18 +7,12 @@ from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.validators import MinValueValidator from django.core.validators import MinValueValidator
from django.db import models, transaction from django.db import models
from django.db.models import Q from django.db.models import Q
from django.utils import timezone from django.utils import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from member.models import Club from member.models import Club
#################################################################
# TO DO
# - link allergen with one food (basic or transformed) with check
# - check on basic food
# - check on transformed food
#################################################################
class QR_code(models.Model): class QR_code(models.Model):
""" """
@ -29,7 +23,7 @@ class QR_code(models.Model):
) )
transformed_food_container = models.ForeignKey( transformed_food_container = models.ForeignKey(
'TransformedFood', 'Transformed_food',
on_delete = models.PROTECT, on_delete = models.PROTECT,
related_name = 'QR_code', related_name = 'QR_code',
null = True, null = True,
@ -38,7 +32,7 @@ class QR_code(models.Model):
) )
basic_food = models.ForeignKey( basic_food = models.ForeignKey(
'BasicFood', 'Basic_food',
on_delete = models.PROTECT, on_delete = models.PROTECT,
related_name = 'QR_code', related_name = 'QR_code',
null = True, null = True,
@ -134,7 +128,7 @@ class Allergen(models.Model):
) )
transformed_food = models.ForeignKey( transformed_food = models.ForeignKey(
'TransformedFood', 'Transformed_food',
on_delete = models.CASCADE, on_delete = models.CASCADE,
related_name = 'Allergen', related_name = 'Allergen',
blank = True, blank = True,
@ -143,7 +137,7 @@ class Allergen(models.Model):
) )
basic_food = models.ForeignKey( basic_food = models.ForeignKey(
'BasicFood', 'Basic_food',
on_delete = models.CASCADE, on_delete = models.CASCADE,
related_name = 'Allergen', related_name = 'Allergen',
blank = True, blank = True,
@ -159,9 +153,7 @@ class Allergen(models.Model):
return _('Allergens of #{id}').format(id=self.id) return _('Allergens of #{id}').format(id=self.id)
class Basic_food(models.Model):
class BasicFood(models.Model):
""" """
Food which has been directly buy on supermarket Food which has been directly buy on supermarket
""" """
@ -180,15 +172,10 @@ class BasicFood(models.Model):
default=False, default=False,
) )
arrival_date = models.DateTimeField(
verbose_name=_('arrival date'),
default=timezone.now,
)
expiry_date = models.DateTimeField( expiry_date = models.DateTimeField(
verbose_name=_('expiry date'), verbose_name=_('expiry date'),
default=timezone.now,
blank=True, blank=True,
null = True,
) )
owner = models.ForeignKey( owner = models.ForeignKey(
@ -204,6 +191,7 @@ class BasicFood(models.Model):
blank=False, blank=False,
null=False, null=False,
upload_to='label/', upload_to='label/',
default= 'pic/default.png',
) )
was_eaten = models.BooleanField( was_eaten = models.BooleanField(
@ -212,8 +200,8 @@ class BasicFood(models.Model):
) )
transformed_food = models.ManyToManyField( transformed_food = models.ManyToManyField(
'TransformedFood', 'Transformed_food',
related_name= 'BasicFood', related_name= 'Basic_food',
blank = True, blank = True,
verbose_name = _('transformed food'), verbose_name = _('transformed food'),
) )
@ -226,15 +214,7 @@ class BasicFood(models.Model):
def __str__(self): def __str__(self):
return self.name return self.name
@transaction.atomic class Transformed_food(models.Model):
def save(self, force_insert=False, force_update=False, using= None, update_fields=None):
# Check if is_DLC and is DDM are not both True
if self.is_DLC and self.is_DDM:
raise ValidationError("The product cannot be a DLC and a DDM")
return super().save(force_insert, force_update, using, update_fields)
class TransformedFood(models.Model):
""" """
Transformed food are a mix between basic food and meal Transformed food are a mix between basic food and meal
""" """
@ -284,6 +264,4 @@ class TransformedFood(models.Model):
def __str__(self): def __str__(self):
return self.name return self.name
@transaction.atomic
def save(self, force_insert=False, force_update=False, using= None, update_fields=None):
return super().save(force_insert, force_update, using, update_fields)

View File

@ -1,22 +0,0 @@
{% 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">
<form method="post">
{% csrf_token %}
{{ form|crispy }}
{{ allergenform|crispy }}
<button class="btn btn-primary" type="submit">{% trans "Submit"%}</button>
</form>
</div>
</div>
{% endblock %}

View File

@ -1,21 +0,0 @@
{% 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">
<form method="post">
{% csrf_token %}
{{ form|crispy }}
<button class="btn btn-primary" type="submit">{% trans "Submit"%}</button>
</form>
</div>
</div>
{% endblock %}

View File

@ -1,19 +1,7 @@
# Copyright (C) 2018-2024 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from django.urls import path from django.urls import path
from . import views from . import views
###############################
# TO DO
# - name url correctly, thinking about the scheme of the app
###############################
app_name = 'food'
urlpatterns = [ urlpatterns = [
path('0', views.BasicFoodCreateView.as_view(), name = 'basic_food'), path('', views.index, name='index')
path('1', views.TransformedFoodCreateView.as_view(), name = 'transformed_food'),
] ]

View File

@ -1,104 +1,5 @@
# Copyright (C) 2018-2024 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from django.urls import reverse_lazy
from django.db import transaction
from django.utils.translation import gettext_lazy as _
from django.utils import timezone
from datetime import timedelta
from permission.views import ProtectQuerysetMixin, ProtectedCreateView
from django.shortcuts import render from django.shortcuts import render
from django.http import HttpResponse
from .forms import BasicFoodForms, TransformedFoodForms, AllergenForms def index(request):
from .models import BasicFood, TransformedFood, Allergen return HttpResponse('test')
class BasicFoodCreateView(ProtectQuerysetMixin, ProtectedCreateView):
#####################################################################
# TO DO
# - fix picture save
# - implement solution crop and convert image (reuse or recode ImageForm from members apps
# - implement AllergenForms
# - redirect to another view after the poll is submitted
#####################################################################
"""
A view to add a basic food
"""
model = BasicFood
form_class = BasicFoodForms
template_name = 'food/basic_food_form.html'
extra_context = {"title": _("Add a new aliment")}
def get_sample_object(self):
return BasicFood(
name="",
is_DLC=False,
is_DDM=False,
expiry_date=timezone.now(),
label='pic/default.png',
)
@transaction.atomic
def form_valid(self, form):
form.instance.creater = self.request.user
basic_food_form = BasicFoodForms(data=self.request.POST)
allergen_form = AllergenForms(data=self.request.POST)
if not basic_food_form.is_valid() or not allergen_form.is_valid():
return self.form_invalid(form)
# Save the aliment and the allergens associed
basic_food = form.save(commit=False)
# We assume the date of labeling and the same as the date of arrival
basic_food.arrival_date = timezone.now
basic_food._force_save = True
basic_food.save()
basic_food.refresh_from_db()
return super().form_valid(form)
def get_success_url(self, **kwargs):
self.object.refresh_from_db()
# TEMPORARY, I create a fonctionnal view before
# return reverse_lazy('food:basicfood', kwargs={"pk": self.object.pk})
return '0'
class TransformedFoodCreateView(ProtectQuerysetMixin, ProtectedCreateView):
###############################################
# TO DO
# -redirect to another view after submit
###############################################
"""
A view to add a tranformed food
"""
model = TransformedFood
template_name = 'food/transformed_food_form.html'
form_class = TransformedFoodForms
extra_context = {"title": _("Add a new meal")}
def get_sample_object(self):
return TransformedFood(
name="",
creation_date=timezone.now(),
)
@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()
return super().form_valid(form)
def get_success_url(self, **kwargs):
self.object.refresh_from_db()
# TEMPORARY, I create a fonctionnal view before
# return reverse_lazy('food:tranformed_food', kwargs={"pk": self.object.pk})
return '1'