mirror of
https://gitlab.crans.org/bde/nk20
synced 2025-10-31 23:54:30 +01:00
Fix dish form and add kitchen view
This commit is contained in:
@@ -219,7 +219,7 @@ SupplementFormSet = forms.inlineformset_factory(
|
||||
Dish,
|
||||
Supplement,
|
||||
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
|
||||
*/
|
||||
function serve_button(button_id, table_id, current_state) {
|
||||
console.log("update")
|
||||
const new_state = !current_state;
|
||||
$.ajax({
|
||||
url: '/api/food/order/' + button_id + '/',
|
||||
|
||||
@@ -106,14 +106,10 @@ class OrderTable(tables.Table):
|
||||
get_current_request(), "food.change_order_saved",
|
||||
record) else '')}}, verbose_name=_("Serve"), )
|
||||
|
||||
request = tables.Column(
|
||||
orderable=False
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Order
|
||||
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', )
|
||||
row_attrs = {
|
||||
'class': 'table-row',
|
||||
|
||||
@@ -31,6 +31,9 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
{% trans "Update" %}
|
||||
</a>
|
||||
{% 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 %}
|
||||
<a class="btn btn-sm btn-danger" href="{% url "food:dish_delete" activity_pk=dish.activity.pk pk=dish.pk %}">
|
||||
{% trans "Delete" %}
|
||||
|
||||
@@ -16,7 +16,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
||||
{% crispy form %}
|
||||
</div>
|
||||
<h3 class="card-header text-center">
|
||||
{% trans "Ajouter des suppléments (optionnel)" %}
|
||||
{% trans "Add supplements (optional)" %}
|
||||
</h3>
|
||||
{{ formset.management_form }}
|
||||
<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>/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/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.core.exceptions import PermissionDenied
|
||||
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.views.generic import DetailView, UpdateView, CreateView
|
||||
from django.views.generic.list import ListView
|
||||
@@ -22,7 +22,7 @@ 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
|
||||
from .models import Food, BasicFood, TransformedFood, QRCode, Order, Dish, Supplement
|
||||
from .forms import QRCodeForms, BasicFoodForms, TransformedFoodForms, \
|
||||
ManageIngredientsForm, ManageIngredientsFormSet, AddIngredientForms, \
|
||||
BasicFoodUpdateForms, TransformedFoodUpdateForms, \
|
||||
@@ -591,7 +591,8 @@ class DishCreateView(ProtectQuerysetMixin, ProtectedCreateView):
|
||||
formset = SupplementFormSet(self.request.POST, instance=form.instance)
|
||||
if formset.is_valid():
|
||||
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.instance.save()
|
||||
else:
|
||||
@@ -656,12 +657,54 @@ class DishUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
|
||||
form_class = DishForm
|
||||
extra_context = {"title": _("Update a dish")}
|
||||
|
||||
def get_form(self, **kwargs):
|
||||
form = super().get_form(**kwargs)
|
||||
def get_context_data(self, **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:
|
||||
del form.fields["main"]
|
||||
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):
|
||||
"""
|
||||
@@ -787,17 +830,32 @@ class ServedOrderListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableV
|
||||
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
|
||||
extra_context = {"title": _('Delete dish')}
|
||||
table_class = OrderTable
|
||||
template_name = 'food/kitchen.html'
|
||||
extra_context = {'title': _('Kitchen')}
|
||||
|
||||
def delete(self, request, *args, **kwargs):
|
||||
if self.get_object().served:
|
||||
raise PermissionDenied(_("This order cannot be deleted because it has already been served"))
|
||||
return super().delete(request, *args, **kwargs)
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().filter(~Q(supplements__isnull=True, request=''), activity__pk=self.kwargs["activity_pk"])
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse_lazy('food:order_list', kwargs={"activity_pk": self.kwargs["activity_pk"]})
|
||||
def get_context_data(self, **kwargs):
|
||||
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