Add order interface

Signed-off-by: Emmy D'ANELLO <ynerant@crans.org>
This commit is contained in:
Emmy D'ANELLO 2022-08-18 17:27:59 +02:00
parent 5174c84b33
commit 45334e4e02
Signed by: ynerant
GPG Key ID: 3A75C55819C8CF85
10 changed files with 371 additions and 59 deletions

View File

@ -0,0 +1,17 @@
{% extends "base.html" %}
{% comment %}
SPDX-License-Identifier: GPL-3.0-or-later
{% endcomment %}
{% load crispy_forms_tags %}
{% load i18n %}
{% block content %}
<div class="card bg-light mb-3">
<h3 class="card-header text-center">
{{ title }}
</h3>
<div class="card-body">
{% crispy form %}
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,34 @@
# Generated by Django 2.2.27 on 2022-08-18 15:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('sheets', '0001_initial'),
]
operations = [
migrations.RemoveField(
model_name='order',
name='gift',
),
migrations.AddField(
model_name='orderedfood',
name='gift',
field=models.IntegerField(default=0, verbose_name='gift'),
preserve_default=False,
),
migrations.AddField(
model_name='orderedmeal',
name='gift',
field=models.IntegerField(default=0, verbose_name='gift'),
preserve_default=False,
),
migrations.AlterField(
model_name='orderedfood',
name='status',
field=models.CharField(choices=[('QUEUED', 'queued'), ('READY', 'ready'), ('SERVED', 'served'), ('CANCELED', 'canceled')], default='QUEUED', max_length=8, verbose_name='status'),
),
]

View File

@ -137,7 +137,7 @@ class Meal(models.Model):
) )
def __str__(self): def __str__(self):
return self.name return _("meal").capitalize() + " " + self.name
class Meta: class Meta:
verbose_name = _("meal") verbose_name = _("meal")
@ -162,10 +162,6 @@ class Order(models.Model):
auto_now_add=True, auto_now_add=True,
) )
gift = models.IntegerField(
verbose_name=_("gift"),
)
class Meta: class Meta:
verbose_name = _("order") verbose_name = _("order")
verbose_name_plural = _("orders") verbose_name_plural = _("orders")
@ -184,6 +180,10 @@ class OrderedMeal(models.Model):
verbose_name=_("meal"), verbose_name=_("meal"),
) )
gift = models.IntegerField(
verbose_name=_("gift"),
)
class Meta: class Meta:
verbose_name = _("ordered meal") verbose_name = _("ordered meal")
verbose_name_plural = _("ordered meals") verbose_name_plural = _("ordered meals")
@ -229,6 +229,10 @@ class OrderedFood(models.Model):
verbose_name=_("priority request"), verbose_name=_("priority request"),
) )
gift = models.IntegerField(
verbose_name=_("gift"),
)
number = models.IntegerField( number = models.IntegerField(
verbose_name=_("number"), verbose_name=_("number"),
help_text=_("How many times the user ordered this."), help_text=_("How many times the user ordered this."),
@ -242,6 +246,7 @@ class OrderedFood(models.Model):
('SERVED', _("served")), ('SERVED', _("served")),
('CANCELED', _("canceled")), ('CANCELED', _("canceled")),
], ],
default='QUEUED',
verbose_name=_("status"), verbose_name=_("status"),
) )
@ -268,14 +273,16 @@ class SheetOrderTransaction(Transaction):
return _("note sheet") return _("note sheet")
@property @property
def price(self): def get_price(self):
if self.ordered_food.meal: if self.ordered_food.meal:
return sum(ordered_food.price + sum(opt.extra_cost for opt in ordered_food.options.all()) return self.ordered_food.meal.meal.price + self.ordered_food.meal.gift + sum(
sum(opt.extra_cost for opt in ordered_food.options.all())
for ordered_food in self.ordered_food.meal.orderedfood_set.exclude(status='CANCELED').all()) for ordered_food in self.ordered_food.meal.orderedfood_set.exclude(status='CANCELED').all())
elif self.ordered_food.status == 'CANCELED': elif self.ordered_food.status == 'CANCELED':
return 0 return 0
else: else:
return self.ordered_food.food.price + sum(opt.extra_cost for opt in self.ordered_food.options.all()) return self.ordered_food.food.price + self.ordered_food.gift \
+ sum(opt.extra_cost for opt in self.ordered_food.options.all())
class Meta: class Meta:
verbose_name = _("sheet order transaction") verbose_name = _("sheet order transaction")

View File

@ -1,11 +1,11 @@
{% extends "wei/base.html" %} {% extends "base.html" %}
{% comment %} {% comment %}
SPDX-License-Identifier: GPL-3.0-or-later SPDX-License-Identifier: GPL-3.0-or-later
{% endcomment %} {% endcomment %}
{% load crispy_forms_tags %} {% load crispy_forms_tags %}
{% load i18n %} {% load i18n %}
{% block profile_content %} {% block content %}
<div class="card bg-light mb-3"> <div class="card bg-light mb-3">
<h3 class="card-header text-center"> <h3 class="card-header text-center">
{{ title }} {{ title }}

View File

@ -1,11 +1,11 @@
{% extends "wei/base.html" %} {% extends "base.html" %}
{% comment %} {% comment %}
SPDX-License-Identifier: GPL-3.0-or-later SPDX-License-Identifier: GPL-3.0-or-later
{% endcomment %} {% endcomment %}
{% load crispy_forms_tags %} {% load crispy_forms_tags %}
{% load i18n %} {% load i18n %}
{% block profile_content %} {% block content %}
<div class="card bg-light mb-3"> <div class="card bg-light mb-3">
<h3 class="card-header text-center"> <h3 class="card-header text-center">
{{ title }} {{ title }}

View File

@ -75,7 +75,7 @@
</div> </div>
</div> </div>
<div class="card-footer text-center"> <div class="card-footer text-center">
<a class="btn btn-success"> <a href="{% url 'sheets:sheet_order' pk=sheet.pk %}" class="btn btn-success">
{% trans "Order now" %} {% trans "Order now" %}
</a> </a>
</div> </div>

View File

@ -1,11 +1,11 @@
{% extends "wei/base.html" %} {% extends "base.html" %}
{% comment %} {% comment %}
SPDX-License-Identifier: GPL-3.0-or-later SPDX-License-Identifier: GPL-3.0-or-later
{% endcomment %} {% endcomment %}
{% load crispy_forms_tags %} {% load crispy_forms_tags %}
{% load i18n %} {% load i18n %}
{% block profile_content %} {% block content %}
<div class="card bg-light mb-3"> <div class="card bg-light mb-3">
<h3 class="card-header text-center"> <h3 class="card-header text-center">
{{ title }} {{ title }}

View File

@ -3,7 +3,7 @@
from django.urls import path from django.urls import path
from sheets.views import FoodCreateView, FoodUpdateView, MealCreateView, MealUpdateView, \ from sheets.views import FoodCreateView, FoodUpdateView, MealCreateView, MealUpdateView, OrderView, \
SheetCreateView, SheetDetailView, SheetListView, SheetUpdateView SheetCreateView, SheetDetailView, SheetListView, SheetUpdateView
app_name = 'sheets' app_name = 'sheets'
@ -17,4 +17,5 @@ urlpatterns = [
path('food/<int:pk>/update/', FoodUpdateView.as_view(), name="food_update"), path('food/<int:pk>/update/', FoodUpdateView.as_view(), name="food_update"),
path('meal/create/<int:pk>/', MealCreateView.as_view(), name="meal_create"), path('meal/create/<int:pk>/', MealCreateView.as_view(), name="meal_create"),
path('meal/<int:pk>/update/', MealUpdateView.as_view(), name="meal_update"), path('meal/<int:pk>/update/', MealUpdateView.as_view(), name="meal_update"),
path('order/<int:pk>/', OrderView.as_view(), name="sheet_order"),
] ]

View File

@ -1,18 +1,28 @@
# Copyright (C) 2018-2022 by BDE ENS Paris-Saclay # Copyright (C) 2018-2022 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
from datetime import timedelta
from crispy_forms.bootstrap import Accordion, AccordionGroup, FormActions
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import Fieldset, Submit, Row, Field
from django import forms
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.db import transaction
from django.forms import Form
from django.urls import reverse_lazy from django.urls import reverse_lazy
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 django.views.generic import DetailView, UpdateView from django.views.generic import DetailView, UpdateView, FormView
from django_tables2 import SingleTableView from django_tables2 import SingleTableView
from note.models import Alias, Note
from note.templatetags.pretty_money import pretty_money
from note_kfet.inputs import AmountInput, Autocomplete
from permission.backends import PermissionBackend from permission.backends import PermissionBackend
from permission.views import ProtectQuerysetMixin, ProtectedCreateView from permission.views import ProtectQuerysetMixin, ProtectedCreateView
from .forms import FoodForm, MealForm, SheetForm, FoodOptionsFormSet, FoodOptionFormSetHelper from .forms import FoodForm, MealForm, SheetForm, FoodOptionsFormSet, FoodOptionFormSetHelper
from .models import Sheet, Food, Meal from .models import Sheet, Food, Meal, Order, OrderedMeal, OrderedFood, SheetOrderTransaction
from .tables import SheetTable from .tables import SheetTable
@ -45,13 +55,13 @@ class SheetCreateView(ProtectQuerysetMixin, ProtectedCreateView):
) )
class SheetUpdateView(ProtectQuerysetMixin, UpdateView): class SheetUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
model = Sheet model = Sheet
form_class = SheetForm form_class = SheetForm
extra_context = {"title": _("Update note sheet")} extra_context = {"title": _("Update note sheet")}
class SheetDetailView(ProtectQuerysetMixin, DetailView): class SheetDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
model = Sheet model = Sheet
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
@ -114,7 +124,7 @@ class FoodCreateView(ProtectQuerysetMixin, ProtectedCreateView):
return reverse_lazy('sheets:sheet_detail', args=(self.kwargs['pk'],)) return reverse_lazy('sheets:sheet_detail', args=(self.kwargs['pk'],))
class FoodUpdateView(ProtectQuerysetMixin, UpdateView): class FoodUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
model = Food model = Food
form_class = FoodForm form_class = FoodForm
extra_context = {"title": _("Update food")} extra_context = {"title": _("Update food")}
@ -176,7 +186,7 @@ class MealCreateView(ProtectQuerysetMixin, ProtectedCreateView):
return reverse_lazy('sheets:sheet_detail', args=(self.object.sheet_id,)) return reverse_lazy('sheets:sheet_detail', args=(self.object.sheet_id,))
class MealUpdateView(ProtectQuerysetMixin, UpdateView): class MealUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
model = Meal model = Meal
form_class = MealForm form_class = MealForm
extra_context = {"title": _("Update meal")} extra_context = {"title": _("Update meal")}
@ -188,3 +198,211 @@ class MealUpdateView(ProtectQuerysetMixin, UpdateView):
def get_success_url(self): def get_success_url(self):
return reverse_lazy('sheets:sheet_detail', args=(self.object.sheet_id,)) return reverse_lazy('sheets:sheet_detail', args=(self.object.sheet_id,))
class OrderView(LoginRequiredMixin, FormView, DetailView):
model = Sheet
template_name = 'sheets/order.html'
extra_context = {'title': _("Order now")}
def get_form(self, form_class=None):
form = Form()
form.helper = FormHelper()
layout_fields = []
self.object = self.get_object()
form.fields['note'] = forms.ModelChoiceField(
queryset=Note.objects.filter(PermissionBackend.filter_queryset(self.request, Note, 'note.view_note')),
label=_("Orderer"),
initial=self.request.user.note,
widget=Autocomplete(
model=Note,
attrs={
"api_url": "/api/note/note/",
'placeholder': _("Who orders")
},
),
)
layout_fields.append(Field('note', css_class='is-valid'))
for meal in self.object.meal_set.filter(available=True).all():
form.fields[f'meal_{meal.id}_quantity'] = forms.IntegerField(
label=_("Quantity"),
initial=0,
)
form.fields[f'meal_{meal.id}_gift'] = forms.IntegerField(
label=_("gift").capitalize(),
initial=0,
widget=AmountInput(),
)
form.fields[f'meal_{meal.id}_remark'] = forms.CharField(
max_length=255,
required=False,
label=_("remark").capitalize(),
help_text=_("Allergies,…"),
)
form.fields[f'meal_{meal.id}_priority'] = forms.CharField(
max_length=64,
required=False,
label=_("priority request").capitalize(),
help_text=_("Lesson at 13h30,…"),
)
ag = AccordionGroup(f"{meal} ({pretty_money(meal.price)})",
Row(Field(f'meal_{meal.id}_quantity', wrapper_class='col-sm-9'),
Field(f'meal_{meal.id}_gift', wrapper_class='col-sm-3')),
Row(Field(f'meal_{meal.id}_remark', wrapper_class='col-sm-9'),
Field(f'meal_{meal.id}_priority', wrapper_class='col-sm-3')))
for food in meal.content.filter(available=True).all():
if food.foodoption_set.count():
options_fieldset = Fieldset(_("Options for ") + str(food))
options_row = Row(css_class='ml-0')
for option in food.foodoption_set.filter(available=True).all():
form.fields[f'meal_{meal.id}_food_{food.id}_option_{option.id}'] = forms.BooleanField(
label=f"{option}{f' ({pretty_money(option.extra_cost)})' if option.extra_cost else ''}",
required=False,
)
options_row.fields.append(
Field(f'meal_{meal.id}_food_{food.id}_option_{option.id}', wrapper_class='col-sm-12'))
options_fieldset.fields.append(options_row)
ag.fields.append(options_fieldset)
layout_fields.append(ag)
for food in self.object.food_set.filter(available=True).all():
form.fields[f'food_{food.id}_quantity'] = forms.IntegerField(
label=_("quantity").capitalize(),
initial=0,
)
form.fields[f'food_{food.id}_gift'] = forms.IntegerField(
label=_("gift").capitalize(),
initial=0,
widget=AmountInput(),
)
form.fields[f'food_{food.id}_remark'] = forms.CharField(
max_length=255,
required=False,
label=_("remark").capitalize(),
help_text=_("Allergies,…"),
)
form.fields[f'food_{food.id}_priority'] = forms.CharField(
max_length=255,
required=False,
label=_("priority request").capitalize(),
help_text=_("Lesson at 13h30,…"),
)
ag = AccordionGroup(f"{food} ({pretty_money(food.price)})",
Row(Field(f'food_{food.id}_quantity', wrapper_class='col-sm-9'),
Field(f'food_{food.id}_gift', wrapper_class='col-sm-3')),
Row(Field(f'food_{food.id}_remark', wrapper_class='col-sm-9'),
Field(f'food_{food.id}_priority', wrapper_class='col-sm-3')))
if food.foodoption_set.count():
options_fieldset = Fieldset(_("Options"))
options_row = Row(css_class='ml-0')
for option in food.foodoption_set.all():
form.fields[f'food_{food.id}_option_{option.id}'] = forms.BooleanField(
label=f"{option}{f' ({pretty_money(option.extra_cost)})' if option.extra_cost else ''}",
required=False,
)
options_row.fields.append(Field(f'food_{food.id}_option_{option.id}', wrapper_class='col-sm-12'))
options_fieldset.fields.append(options_row)
ag.fields.append(options_fieldset)
layout_fields.append(ag)
layout_fields.append(FormActions(Submit('submit', _("Order now"))))
form.helper.layout = Accordion(*layout_fields)
if self.request.method in ['PUT', 'POST']:
form.data = self.request.POST
form.files = self.request.FILES
form.is_bound = not form.data or not form.files
return form
def form_valid(self, form):
data = form.cleaned_data
sheet = self.get_object()
with transaction.atomic():
order = Order.objects.create(sheet_id=self.kwargs['pk'], note=data['note'])
total_quantity = 0
for meal in sheet.meal_set.filter(available=True).all():
quantity = data[f'meal_{meal.id}_quantity']
if not quantity:
continue
total_quantity += quantity
gift = data[f'meal_{meal.id}_gift']
remark = data[f'meal_{meal.id}_remark'] or ''
priority = data[f'meal_{meal.id}_priority'] or ''
ordered_meal = OrderedMeal.objects.create(order=order, meal=meal, gift=gift)
for ignored in range(quantity):
for food in meal.content.filter(available=True).all():
n = OrderedFood.objects.filter(order__sheet_id=self.kwargs['pk'],
order__note=order.note,
order__date__gte=timezone.now() - timedelta(hours=6),
food=food).exclude(status='CANCELED').count()
of = OrderedFood.objects.create(order=order, meal=ordered_meal, food=food,
remark=remark, priority=priority, number=n + 1, gift=0)
for option in food.foodoption_set.filter(available=True).all():
if data[f'meal_{meal.id}_food_{food.id}_option_{option.id}']:
of.options.add(option)
of.save()
first_food = ordered_meal.orderedfood_set.first()
tr = SheetOrderTransaction(source_id=order.note_id, destination=first_food.food.club.note,
source_alias=str(order.note), destination_alias=first_food.food.club.name,
quantity=quantity, ordered_food=first_food,
reason=f"{meal.name} - {sheet.name}")
tr.amount = tr.get_price / tr.quantity
tr.save()
for food in sheet.food_set.filter(available=True).all():
quantity = data[f'food_{food.id}_quantity']
if not quantity:
continue
total_quantity += quantity
gift = data[f'food_{meal.id}_gift']
remark = data[f'food_{meal.id}_remark'] or ''
priority = data[f'food_{meal.id}_priority'] or ''
for ignored in range(quantity):
n = OrderedFood.objects.filter(order__sheet_id=self.kwargs['pk'],
order__note=order.note,
order__date__gte=timezone.now() - timedelta(hours=6),
food=food).exclude(state='CANCELED').count()
of = OrderedFood.objects.create(order=order, food=food, gift=gift,
remark=remark, priority=priority, number=n + 1)
for option in food.foodoption_set.filter(available=True).all():
if data[f'meal_{meal.id}_food_{food.id}_option_{option.id}']:
of.options.add(option)
of.options.save()
tr = SheetOrderTransaction(source_id=order.note_id, destination_id=first_food.club.note,
source_alias=str(order.note), destination_alias=first_food.club.name,
quantity=quantity, ordered_food=of,
reason=f"{food.name} - {sheet.name}")
tr.amount = tr.get_price / tr.quantity
tr.save()
if total_quantity == 0:
form.add_error(None, _("You didn't select anything."))
transaction.rollback()
return self.form_invalid(form)
return super().form_valid(form)
def get_success_url(self):
return reverse_lazy('sheets:sheet_detail', args=(self.kwargs['pk'],))

View File

@ -7,7 +7,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-08-18 14:49+0200\n" "POT-Creation-Date: 2022-08-18 17:20+0200\n"
"PO-Revision-Date: 2022-04-11 22:05+0200\n" "PO-Revision-Date: 2022-04-11 22:05+0200\n"
"Last-Translator: elkmaennchen <elkmaennchen@crans.org>\n" "Last-Translator: elkmaennchen <elkmaennchen@crans.org>\n"
"Language-Team: French <http://translate.ynerant.fr/projects/nk20/nk20/fr/>\n" "Language-Team: French <http://translate.ynerant.fr/projects/nk20/nk20/fr/>\n"
@ -1476,7 +1476,7 @@ msgstr "modèles de transaction"
msgid "used alias" msgid "used alias"
msgstr "alias utilisé" msgstr "alias utilisé"
#: apps/note/models/transactions.py:136 #: apps/note/models/transactions.py:136 apps/sheets/views.py:276
msgid "quantity" msgid "quantity"
msgstr "quantité" msgstr "quantité"
@ -2188,7 +2188,7 @@ msgid "the note sheet will be private until this field is checked."
msgstr "la feuille de note restera privée tant que ce champ n'est pas coché." msgstr "la feuille de note restera privée tant que ce champ n'est pas coché."
#: apps/sheets/models.py:41 apps/sheets/models.py:54 apps/sheets/models.py:116 #: apps/sheets/models.py:41 apps/sheets/models.py:54 apps/sheets/models.py:116
#: apps/sheets/models.py:151 apps/sheets/models.py:268 #: apps/sheets/models.py:151 apps/sheets/models.py:273
msgid "note sheet" msgid "note sheet"
msgstr "feuille de note" msgstr "feuille de note"
@ -2231,7 +2231,8 @@ msgstr "options de nourriture"
msgid "content" msgid "content"
msgstr "contenu" msgstr "contenu"
#: apps/sheets/models.py:143 apps/sheets/models.py:184 #: apps/sheets/models.py:140 apps/sheets/models.py:143
#: apps/sheets/models.py:180
msgid "meal" msgid "meal"
msgstr "menu" msgstr "menu"
@ -2243,19 +2244,20 @@ msgstr "menus"
msgid "date" msgid "date"
msgstr "date" msgstr "date"
#: apps/sheets/models.py:166 #: apps/sheets/models.py:166 apps/sheets/models.py:174
msgid "gift"
msgstr "don"
#: apps/sheets/models.py:170 apps/sheets/models.py:178
#: apps/sheets/models.py:196 #: apps/sheets/models.py:196
msgid "order" msgid "order"
msgstr "commande" msgstr "commande"
#: apps/sheets/models.py:171 #: apps/sheets/models.py:167
msgid "orders" msgid "orders"
msgstr "commandes" msgstr "commandes"
#: apps/sheets/models.py:184 apps/sheets/models.py:233 apps/sheets/views.py:235
#: apps/sheets/views.py:280
msgid "gift"
msgstr "don"
#: apps/sheets/models.py:188 apps/sheets/models.py:204 #: apps/sheets/models.py:188 apps/sheets/models.py:204
msgid "ordered meal" msgid "ordered meal"
msgstr "menu commandé" msgstr "menu commandé"
@ -2268,56 +2270,56 @@ msgstr "menus commandés"
msgid "options" msgid "options"
msgstr "options" msgstr "options"
#: apps/sheets/models.py:222 #: apps/sheets/models.py:222 apps/sheets/views.py:242 apps/sheets/views.py:287
msgid "remark" msgid "remark"
msgstr "remarques" msgstr "remarques"
#: apps/sheets/models.py:229 #: apps/sheets/models.py:229 apps/sheets/views.py:248 apps/sheets/views.py:293
msgid "priority request" msgid "priority request"
msgstr "demande de priorité" msgstr "demande de priorité"
#: apps/sheets/models.py:233 #: apps/sheets/models.py:237
msgid "number" msgid "number"
msgstr "numéro" msgstr "numéro"
#: apps/sheets/models.py:234 #: apps/sheets/models.py:238
msgid "How many times the user ordered this." msgid "How many times the user ordered this."
msgstr "Combien de fois cet⋅te utilisateur⋅rice a commandé ceci." msgstr "Combien de fois cet⋅te utilisateur⋅rice a commandé ceci."
#: apps/sheets/models.py:240 #: apps/sheets/models.py:244
msgid "queued" msgid "queued"
msgstr "en attente" msgstr "en attente"
#: apps/sheets/models.py:241 #: apps/sheets/models.py:245
msgid "ready" msgid "ready"
msgstr "prêt" msgstr "prêt"
#: apps/sheets/models.py:242 #: apps/sheets/models.py:246
msgid "served" msgid "served"
msgstr "servi" msgstr "servi"
#: apps/sheets/models.py:243 #: apps/sheets/models.py:247
msgid "canceled" msgid "canceled"
msgstr "annulé" msgstr "annulé"
#: apps/sheets/models.py:245 #: apps/sheets/models.py:250
msgid "status" msgid "status"
msgstr "statut" msgstr "statut"
#: apps/sheets/models.py:251 #: apps/sheets/models.py:256
msgid "served date" msgid "served date"
msgstr "date de service" msgstr "date de service"
#: apps/sheets/models.py:255 apps/sheets/models.py:256 #: apps/sheets/models.py:260 apps/sheets/models.py:261
#: apps/sheets/models.py:263 #: apps/sheets/models.py:268
msgid "ordered food" msgid "ordered food"
msgstr "nourriture commandée" msgstr "nourriture commandée"
#: apps/sheets/models.py:281 #: apps/sheets/models.py:288
msgid "sheet order transaction" msgid "sheet order transaction"
msgstr "transaction de commande sur feuille de note" msgstr "transaction de commande sur feuille de note"
#: apps/sheets/models.py:282 #: apps/sheets/models.py:289
msgid "sheet order transactions" msgid "sheet order transactions"
msgstr "transactions de commande sur feuille de note" msgstr "transactions de commande sur feuille de note"
@ -2347,7 +2349,8 @@ msgstr "Ajouter un plat"
msgid "Add new meal" msgid "Add new meal"
msgstr "Ajouter un menu" msgstr "Ajouter un menu"
#: apps/sheets/templates/sheets/sheet_detail.html:79 #: apps/sheets/templates/sheets/sheet_detail.html:79 apps/sheets/views.py:206
#: apps/sheets/views.py:317
msgid "Order now" msgid "Order now"
msgstr "Commander maintenant" msgstr "Commander maintenant"
@ -2359,34 +2362,70 @@ msgstr "Créer une feuille de note"
msgid "Note sheet listing" msgid "Note sheet listing"
msgstr "Liste des feuilles de notes" msgstr "Liste des feuilles de notes"
#: apps/sheets/views.py:23 #: apps/sheets/views.py:33
msgid "Search note sheet" msgid "Search note sheet"
msgstr "Chercher une feuille de note" msgstr "Chercher une feuille de note"
#: apps/sheets/views.py:38 #: apps/sheets/views.py:48
msgid "Create note sheet" msgid "Create note sheet"
msgstr "Créer une feuille de note" msgstr "Créer une feuille de note"
#: apps/sheets/views.py:51 #: apps/sheets/views.py:61
msgid "Update note sheet" msgid "Update note sheet"
msgstr "Modifier une feuille de note" msgstr "Modifier une feuille de note"
#: apps/sheets/views.py:74 #: apps/sheets/views.py:84
msgid "Create new food" msgid "Create new food"
msgstr "Créer un plat" msgstr "Créer un plat"
#: apps/sheets/views.py:120 #: apps/sheets/views.py:130
msgid "Update food" msgid "Update food"
msgstr "Modifier un plat" msgstr "Modifier un plat"
#: apps/sheets/views.py:157 #: apps/sheets/views.py:167
msgid "Create new meal" msgid "Create new meal"
msgstr "Créer un menu" msgstr "Créer un menu"
#: apps/sheets/views.py:182 #: apps/sheets/views.py:192
msgid "Update meal" msgid "Update meal"
msgstr "Modifier un menu" msgstr "Modifier un menu"
#: apps/sheets/views.py:217
#, fuzzy
#| msgid "order"
msgid "Orderer"
msgstr "commande"
#: apps/sheets/views.py:223
#, fuzzy
#| msgid "orders"
msgid "Who orders"
msgstr "commandes"
#: apps/sheets/views.py:231 apps/treasury/models.py:140
msgid "Quantity"
msgstr "Quantité"
#: apps/sheets/views.py:243 apps/sheets/views.py:288
msgid "Allergies,…"
msgstr "Allergies,…"
#: apps/sheets/views.py:249 apps/sheets/views.py:294
msgid "Lesson at 13h30,…"
msgstr "Cours à 13h30,…"
#: apps/sheets/views.py:260
msgid "Options for "
msgstr "Options pour "
#: apps/sheets/views.py:304
msgid "Options"
msgstr "Options"
#: apps/sheets/views.py:401
msgid "You didn't select anything."
msgstr "Vous n'avez rien sélectionné."
#: apps/treasury/apps.py:12 note_kfet/templates/base.html:96 #: apps/treasury/apps.py:12 note_kfet/templates/base.html:96
msgid "Treasury" msgid "Treasury"
msgstr "Trésorerie" msgstr "Trésorerie"
@ -2473,10 +2512,6 @@ msgstr "Facture n°{id}"
msgid "Designation" msgid "Designation"
msgstr "Désignation" msgstr "Désignation"
#: apps/treasury/models.py:140
msgid "Quantity"
msgstr "Quantité"
#: apps/treasury/models.py:145 #: apps/treasury/models.py:145
msgid "Unit price" msgid "Unit price"
msgstr "Prix unitaire" msgstr "Prix unitaire"