mirror of
https://gitlab.crans.org/bde/nk20
synced 2025-11-07 23:39:50 +01:00
Add model Recipe
This commit is contained in:
@@ -9,7 +9,8 @@ from django_tables2.views import SingleTableView, MultiTableMixin
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.db import transaction
|
||||
from django.db.models import Q, Count
|
||||
from django.http import HttpResponseRedirect, Http404
|
||||
from django.http import HttpResponseRedirect, Http404, JsonResponse
|
||||
from django.views.decorators.http import require_GET
|
||||
from django.views.generic import DetailView, UpdateView, CreateView
|
||||
from django.views.generic.list import ListView
|
||||
from django.views.generic.base import RedirectView
|
||||
@@ -22,12 +23,13 @@ from activity.models import Activity
|
||||
from permission.backends import PermissionBackend
|
||||
from permission.views import ProtectQuerysetMixin, ProtectedCreateView, LoginRequiredMixin
|
||||
|
||||
from .models import Food, BasicFood, TransformedFood, QRCode, Order, Dish, Supplement
|
||||
from .models import Food, BasicFood, TransformedFood, QRCode, Order, Dish, Supplement, Recipe
|
||||
from .forms import QRCodeForms, BasicFoodForms, TransformedFoodForms, \
|
||||
ManageIngredientsForm, ManageIngredientsFormSet, AddIngredientForms, \
|
||||
BasicFoodUpdateForms, TransformedFoodUpdateForms, \
|
||||
DishForm, SupplementFormSet, SupplementFormSetHelper, OrderForm
|
||||
from .tables import FoodTable, DishTable, OrderTable
|
||||
DishForm, SupplementFormSet, SupplementFormSetHelper, OrderForm, RecipeForm, \
|
||||
RecipeIngredientsForm, RecipeIngredientsFormSet, UseRecipeForm
|
||||
from .tables import FoodTable, DishTable, OrderTable, RecipeTable
|
||||
from .utils import pretty_duration
|
||||
|
||||
|
||||
@@ -118,6 +120,10 @@ class FoodListView(ProtectQuerysetMixin, LoginRequiredMixin, MultiTableMixin, Li
|
||||
|
||||
context['can_add_meal'] = PermissionBackend.check_perm(self.request, 'food.transformedfood_add')
|
||||
|
||||
context['can_add_recipe'] = PermissionBackend.check_perm(self.request, 'food.recipe_add')
|
||||
|
||||
context['can_view_recipes'] = PermissionBackend.check_perm(self.request, 'food.recipe_view')
|
||||
|
||||
context["open_activities"] = Activity.objects.filter(activity_type__name="Perm bouffe", open=True)
|
||||
|
||||
return context
|
||||
@@ -329,7 +335,7 @@ class ManageIngredientsView(LoginRequiredMixin, UpdateView):
|
||||
if not (ingredient.polymorphic_ctype.model == 'basicfood' and ingredient.date_type == 'DDM'):
|
||||
self.object.expiry_date = min(self.object.expiry_date, ingredient.expiry_date)
|
||||
self.object.allergens.set(self.object.allergens.union(ingredient.allergens.all()))
|
||||
self.object.tracese.set(self.object.traces.union(ingredient.traces.all()))
|
||||
self.object.traces.set(self.object.traces.union(ingredient.traces.all()))
|
||||
|
||||
self.object.save(old_ingredients=old_ingredients, old_allergens=old_allergens, old_traces=old_traces)
|
||||
return HttpResponseRedirect(self.get_success_url())
|
||||
@@ -355,6 +361,7 @@ class ManageIngredientsView(LoginRequiredMixin, UpdateView):
|
||||
'qr_number': '' if qr.count() == 0 else qr[0].qr_code_number,
|
||||
'fully_used': 'true' if ingredient.end_of_life else '',
|
||||
})
|
||||
|
||||
return context
|
||||
|
||||
def get_success_url(self, **kwargs):
|
||||
@@ -874,3 +881,166 @@ class KitchenView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
|
||||
table.columns.hide(field)
|
||||
|
||||
return table
|
||||
|
||||
|
||||
class RecipeCreateView(ProtectQuerysetMixin, ProtectedCreateView):
|
||||
"""
|
||||
Create a recipe
|
||||
"""
|
||||
model = Recipe
|
||||
form_class = RecipeForm
|
||||
extra_context = {"title": _("Create a recipe")}
|
||||
|
||||
def get_sample_object(self):
|
||||
return Recipe(name='Sample recipe')
|
||||
|
||||
@transaction.atomic
|
||||
def form_valid(self, form):
|
||||
formset = RecipeIngredientsFormSet(self.request.POST)
|
||||
if formset.is_valid():
|
||||
ingredients = [f.cleaned_data['name'] for f in formset if f.cleaned_data.get('name')]
|
||||
self.object = form.save(commit=False)
|
||||
self.object.ingredients = ingredients
|
||||
self.object.save()
|
||||
return super().form_valid(form)
|
||||
else:
|
||||
return self.form_invalid(form)
|
||||
|
||||
def get_context_data(self, *args, **kwargs):
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
context['form'] = RecipeIngredientsForm()
|
||||
context['recipe_form'] = self.get_form()
|
||||
if self.request.POST:
|
||||
context['formset'] = RecipeIngredientsFormSet(self.request.POST,)
|
||||
else:
|
||||
context['formset'] = RecipeIngredientsFormSet()
|
||||
return context
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy('food:recipe_create')
|
||||
|
||||
|
||||
class RecipeListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
|
||||
"""
|
||||
List all recipes
|
||||
"""
|
||||
model = Recipe
|
||||
table_class = RecipeTable
|
||||
extra_context = {"title": _('All recipes')}
|
||||
|
||||
def get_context_data(self, *args, **kwargs):
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
|
||||
context['can_add_recipe'] = PermissionBackend.check_perm(self.request, 'food.recipe_add')
|
||||
|
||||
return context
|
||||
|
||||
|
||||
class RecipeDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
|
||||
"""
|
||||
List all recipes
|
||||
"""
|
||||
model = Recipe
|
||||
extra_context = {"title": _('Details of:')}
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["ingredients"] = self.object.ingredients
|
||||
context["update"] = PermissionBackend.check_perm(self.request, "food.change_recipe")
|
||||
|
||||
return context
|
||||
|
||||
|
||||
class RecipeUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
|
||||
"""
|
||||
Create a recipe
|
||||
"""
|
||||
model = Recipe
|
||||
form_class = RecipeForm
|
||||
extra_context = {"title": _("Create a recipe")}
|
||||
|
||||
def get_sample_object(self):
|
||||
return Recipe(name='Sample recipe')
|
||||
|
||||
@transaction.atomic
|
||||
def form_valid(self, form):
|
||||
formset = RecipeIngredientsFormSet(self.request.POST)
|
||||
if formset.is_valid():
|
||||
ingredients = [f.cleaned_data['name'] for f in formset if f.cleaned_data.get('name')]
|
||||
self.object = form.save(commit=False)
|
||||
self.object.ingredients = ingredients
|
||||
self.object.save()
|
||||
return super().form_valid(form)
|
||||
else:
|
||||
return self.form_invalid(form)
|
||||
|
||||
def get_context_data(self, *args, **kwargs):
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
context['form'] = RecipeIngredientsForm()
|
||||
context['recipe_form'] = self.get_form()
|
||||
if self.request.POST:
|
||||
formset = RecipeIngredientsFormSet(self.request.POST,)
|
||||
else:
|
||||
formset = RecipeIngredientsFormSet()
|
||||
ingredients = self.object.ingredients
|
||||
context["ingredients_count"] = len(ingredients)
|
||||
formset.extra += len(ingredients)
|
||||
context["formset"] = formset
|
||||
context["ingredients"] = []
|
||||
for ingredient in ingredients:
|
||||
context["ingredients"].append({"name": ingredient})
|
||||
return context
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy('food:recipe_detail', kwargs={"pk": self.object.pk})
|
||||
|
||||
|
||||
class UseRecipeView(LoginRequiredMixin, UpdateView):
|
||||
"""
|
||||
Add ingredients to a TransformedFood using a Recipe
|
||||
"""
|
||||
model = TransformedFood
|
||||
fields = '__all__'
|
||||
template_name = 'food/use_recipe_form.html'
|
||||
extra_context = {"title": _("Use a recipe:")}
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
|
||||
context["form"] = UseRecipeForm()
|
||||
|
||||
return context
|
||||
|
||||
|
||||
@require_GET
|
||||
def get_ingredients_for_recipe(request):
|
||||
recipe_id = request.GET.get('recipe_id')
|
||||
if not recipe_id:
|
||||
return JsonResponse({'error': 'Missing recipe_id'}, status=400)
|
||||
|
||||
try:
|
||||
recipe = Recipe.objects.get(pk=recipe_id)
|
||||
except Recipe.DoesNotExist:
|
||||
return JsonResponse({'error': 'Recipe not found'}, status=404)
|
||||
|
||||
# 🔧 Supporte les deux cas : ManyToMany ou simple liste
|
||||
ingredients_field = recipe.ingredients
|
||||
|
||||
if hasattr(ingredients_field, "values_list"):
|
||||
# Cas ManyToManyField
|
||||
ingredient_names = list(ingredients_field.values_list('name', flat=True))
|
||||
elif isinstance(ingredients_field, (list, tuple)):
|
||||
# Cas liste directe
|
||||
ingredient_names = ingredients_field
|
||||
else:
|
||||
return JsonResponse({'error': 'Unsupported ingredients type'}, status=500)
|
||||
|
||||
# Union des Foods dont le nom commence par un nom d’ingrédient
|
||||
query = Q()
|
||||
for name in ingredient_names:
|
||||
query |= Q(name__istartswith=name)
|
||||
|
||||
qs = Food.objects.filter(query).distinct()
|
||||
|
||||
data = [{'id': f.id, 'name': f.name, 'qr_code_numbers': ", ".join(str(q.qr_code_number) for q in f.QR_code.all())} for f in qs]
|
||||
return JsonResponse({'ingredients': data})
|
||||
|
||||
Reference in New Issue
Block a user