mirror of
https://gitlab.crans.org/bde/nk20
synced 2025-11-01 16:14:30 +01:00
Fix dish form and add kitchen view
This commit is contained in:
@@ -219,7 +219,7 @@ SupplementFormSet = forms.inlineformset_factory(
|
|||||||
Dish,
|
Dish,
|
||||||
Supplement,
|
Supplement,
|
||||||
form=SupplementForm,
|
form=SupplementForm,
|
||||||
extra=0,
|
extra=1,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ function delete_button (button_id, table_id) {
|
|||||||
* @param table_id: Id of the table to reload
|
* @param table_id: Id of the table to reload
|
||||||
*/
|
*/
|
||||||
function serve_button(button_id, table_id, current_state) {
|
function serve_button(button_id, table_id, current_state) {
|
||||||
console.log("update")
|
|
||||||
const new_state = !current_state;
|
const new_state = !current_state;
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: '/api/food/order/' + button_id + '/',
|
url: '/api/food/order/' + button_id + '/',
|
||||||
|
|||||||
@@ -106,14 +106,10 @@ class OrderTable(tables.Table):
|
|||||||
get_current_request(), "food.change_order_saved",
|
get_current_request(), "food.change_order_saved",
|
||||||
record) else '')}}, verbose_name=_("Serve"), )
|
record) else '')}}, verbose_name=_("Serve"), )
|
||||||
|
|
||||||
request = tables.Column(
|
|
||||||
orderable=False
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Order
|
model = Order
|
||||||
template_name = 'django_tables2/bootstrap4.html'
|
template_name = 'django_tables2/bootstrap4.html'
|
||||||
fields = ('ordered_at', 'user', 'dish', 'supplements', 'request', 'serve', 'delete')
|
fields = ('number', 'ordered_at', 'user', 'dish', 'supplements', 'request', 'serve', 'delete')
|
||||||
order_by = ('ordered_at', )
|
order_by = ('ordered_at', )
|
||||||
row_attrs = {
|
row_attrs = {
|
||||||
'class': 'table-row',
|
'class': 'table-row',
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
{% trans "Update" %}
|
{% trans "Update" %}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<a class="btn btn-sm btn-primary" href="{% url "food:dish_list" activity_pk=dish.activity.pk %}">
|
||||||
|
{% trans "Return to dish list" %}
|
||||||
|
</a>
|
||||||
{% if delete %}
|
{% if delete %}
|
||||||
<a class="btn btn-sm btn-danger" href="{% url "food:dish_delete" activity_pk=dish.activity.pk pk=dish.pk %}">
|
<a class="btn btn-sm btn-danger" href="{% url "food:dish_delete" activity_pk=dish.activity.pk pk=dish.pk %}">
|
||||||
{% trans "Delete" %}
|
{% trans "Delete" %}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
{% crispy form %}
|
{% crispy form %}
|
||||||
</div>
|
</div>
|
||||||
<h3 class="card-header text-center">
|
<h3 class="card-header text-center">
|
||||||
{% trans "Ajouter des suppléments (optionnel)" %}
|
{% trans "Add supplements (optional)" %}
|
||||||
</h3>
|
</h3>
|
||||||
{{ formset.management_form }}
|
{{ formset.management_form }}
|
||||||
<table class="table table-condensed table-striped">
|
<table class="table table-condensed table-striped">
|
||||||
|
|||||||
41
apps/food/templates/food/kitchen.html
Normal file
41
apps/food/templates/food/kitchen.html
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% comment %}
|
||||||
|
Copyright (C) 2018-2025 by BDE ENS Paris-Saclay
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
{% endcomment %}
|
||||||
|
{% load render_table from django_tables2 %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<!-- Colonne de plats -->
|
||||||
|
<div style="display: flex; flex-wrap: wrap; gap: 1rem; margin-bottom: 2rem;">
|
||||||
|
{% for food, quantity in orders.items %}
|
||||||
|
<div class="card bg-white mb-3" style="flex: 1 1 calc(33.333% - 1rem); border: 1px solid #ccc; padding: 1rem; border-radius: 0.5rem; box-sizing: border-box;">
|
||||||
|
|
||||||
|
<h3 class="card-header text-center">
|
||||||
|
<strong>{{ food }}</strong><br>
|
||||||
|
</h3>
|
||||||
|
<h1 class="card-body text-center">
|
||||||
|
{{ quantity }}</h1>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Colonne de la table -->
|
||||||
|
<div class="card bg-white mb-3">
|
||||||
|
<h3 class="card-header text-center">
|
||||||
|
{% trans "Special orders" %}
|
||||||
|
</h3>
|
||||||
|
{% if table.data %}
|
||||||
|
{% render_table table %}
|
||||||
|
{% else %}
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
{% trans "There are no special orders." %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@@ -28,5 +28,5 @@ urlpatterns = [
|
|||||||
path('activity/<int:activity_pk>/order/', views.OrderCreateView.as_view(), name='order_create'),
|
path('activity/<int:activity_pk>/order/', views.OrderCreateView.as_view(), name='order_create'),
|
||||||
path('activity/<int:activity_pk>/orders/', views.OrderListView.as_view(), name='order_list'),
|
path('activity/<int:activity_pk>/orders/', views.OrderListView.as_view(), name='order_list'),
|
||||||
path('activity/<int:activity_pk>/orders/served', views.ServedOrderListView.as_view(), name='served_order_list'),
|
path('activity/<int:activity_pk>/orders/served', views.ServedOrderListView.as_view(), name='served_order_list'),
|
||||||
path('activity/orders/<int:pk>/delete/', views.OrderDeleteView.as_view(), name='order_delete'),
|
path('activity/<int:activity_pk>/kitchen/', views.KitchenView.as_view(), name='kitchen'),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from crispy_forms.helper import FormHelper
|
|||||||
from django_tables2.views import SingleTableView, MultiTableMixin
|
from django_tables2.views import SingleTableView, MultiTableMixin
|
||||||
from django.core.exceptions import PermissionDenied
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.db.models import Q
|
from django.db.models import Q, Count
|
||||||
from django.http import HttpResponseRedirect, Http404
|
from django.http import HttpResponseRedirect, Http404
|
||||||
from django.views.generic import DetailView, UpdateView, CreateView
|
from django.views.generic import DetailView, UpdateView, CreateView
|
||||||
from django.views.generic.list import ListView
|
from django.views.generic.list import ListView
|
||||||
@@ -22,7 +22,7 @@ from activity.models import Activity
|
|||||||
from permission.backends import PermissionBackend
|
from permission.backends import PermissionBackend
|
||||||
from permission.views import ProtectQuerysetMixin, ProtectedCreateView, LoginRequiredMixin
|
from permission.views import ProtectQuerysetMixin, ProtectedCreateView, LoginRequiredMixin
|
||||||
|
|
||||||
from .models import Food, BasicFood, TransformedFood, QRCode, Order, Dish
|
from .models import Food, BasicFood, TransformedFood, QRCode, Order, Dish, Supplement
|
||||||
from .forms import QRCodeForms, BasicFoodForms, TransformedFoodForms, \
|
from .forms import QRCodeForms, BasicFoodForms, TransformedFoodForms, \
|
||||||
ManageIngredientsForm, ManageIngredientsFormSet, AddIngredientForms, \
|
ManageIngredientsForm, ManageIngredientsFormSet, AddIngredientForms, \
|
||||||
BasicFoodUpdateForms, TransformedFoodUpdateForms, \
|
BasicFoodUpdateForms, TransformedFoodUpdateForms, \
|
||||||
@@ -591,7 +591,8 @@ class DishCreateView(ProtectQuerysetMixin, ProtectedCreateView):
|
|||||||
formset = SupplementFormSet(self.request.POST, instance=form.instance)
|
formset = SupplementFormSet(self.request.POST, instance=form.instance)
|
||||||
if formset.is_valid():
|
if formset.is_valid():
|
||||||
for f in formset:
|
for f in formset:
|
||||||
if f.is_valid():
|
# We don't save the product if the price is not entered, ie. if the line is empty
|
||||||
|
if f.is_valid() and f.instance.price:
|
||||||
f.save()
|
f.save()
|
||||||
f.instance.save()
|
f.instance.save()
|
||||||
else:
|
else:
|
||||||
@@ -656,12 +657,54 @@ class DishUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
|
|||||||
form_class = DishForm
|
form_class = DishForm
|
||||||
extra_context = {"title": _("Update a dish")}
|
extra_context = {"title": _("Update a dish")}
|
||||||
|
|
||||||
def get_form(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
form = super().get_form(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
form = context['form']
|
||||||
|
form.helper = FormHelper()
|
||||||
|
# Remove form tag on the generation of the form in the template (already present on the template)
|
||||||
|
form.helper.form_tag = False
|
||||||
|
# The formset handles the set of the supplements
|
||||||
|
form_set = SupplementFormSet(instance=form.instance)
|
||||||
|
context['formset'] = form_set
|
||||||
|
context['helper'] = SupplementFormSetHelper()
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
def get_form(self, form_class=None):
|
||||||
|
form = super().get_form(form_class)
|
||||||
if 'main' in form.fields:
|
if 'main' in form.fields:
|
||||||
del form.fields["main"]
|
del form.fields["main"]
|
||||||
return form
|
return form
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def form_valid(self, form):
|
||||||
|
activity = Activity.objects.get(pk=self.kwargs["activity_pk"])
|
||||||
|
|
||||||
|
form.instance.activity = activity
|
||||||
|
|
||||||
|
ret = super().form_valid(form)
|
||||||
|
|
||||||
|
# For each supplement, we save it
|
||||||
|
formset = SupplementFormSet(self.request.POST, instance=form.instance)
|
||||||
|
saved = []
|
||||||
|
if formset.is_valid():
|
||||||
|
for f in formset:
|
||||||
|
# We don't save the product if the price is not entered, ie. if the line is empty
|
||||||
|
if f.is_valid() and f.instance.price:
|
||||||
|
f.save()
|
||||||
|
f.instance.save()
|
||||||
|
saved.append(f.instance.pk)
|
||||||
|
else:
|
||||||
|
f.instance = None
|
||||||
|
# Remove old supplements that weren't given in the form
|
||||||
|
Supplement.objects.filter(~Q(pk__in=saved), dish=form.instance).delete()
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return reverse_lazy('food:dish_detail', kwargs={"activity_pk": self.kwargs["activity_pk"], "pk": self.kwargs["pk"]})
|
||||||
|
|
||||||
|
|
||||||
class DishDeleteView(ProtectQuerysetMixin, LoginRequiredMixin, DeleteView):
|
class DishDeleteView(ProtectQuerysetMixin, LoginRequiredMixin, DeleteView):
|
||||||
"""
|
"""
|
||||||
@@ -787,17 +830,32 @@ class ServedOrderListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableV
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class OrderDeleteView(ProtectQuerysetMixin, LoginRequiredMixin, DeleteView):
|
class KitchenView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
|
||||||
"""
|
"""
|
||||||
Delete an order
|
The view to display useful information for the kitchen
|
||||||
"""
|
"""
|
||||||
model = Order
|
model = Order
|
||||||
extra_context = {"title": _('Delete dish')}
|
table_class = OrderTable
|
||||||
|
template_name = 'food/kitchen.html'
|
||||||
|
extra_context = {'title': _('Kitchen')}
|
||||||
|
|
||||||
def delete(self, request, *args, **kwargs):
|
def get_queryset(self):
|
||||||
if self.get_object().served:
|
return super().get_queryset().filter(~Q(supplements__isnull=True, request=''), activity__pk=self.kwargs["activity_pk"])
|
||||||
raise PermissionDenied(_("This order cannot be deleted because it has already been served"))
|
|
||||||
return super().delete(request, *args, **kwargs)
|
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_context_data(self, **kwargs):
|
||||||
return reverse_lazy('food:order_list', kwargs={"activity_pk": self.kwargs["activity_pk"]})
|
context = super().get_context_data(**kwargs)
|
||||||
|
|
||||||
|
orders_count = Order.objects.values('dish__main__name').annotate(quantity=Count('id'))
|
||||||
|
|
||||||
|
context["orders"] = {o['dish__main__name']: o['quantity'] for o in orders_count}
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
def get_table(self, **kwargs):
|
||||||
|
table = super().get_table(**kwargs)
|
||||||
|
|
||||||
|
hide = ["ordered_at", "serve", "delete"]
|
||||||
|
for field in hide:
|
||||||
|
table.columns.hide(field)
|
||||||
|
|
||||||
|
return table
|
||||||
|
|||||||
Reference in New Issue
Block a user