diff --git a/apps/api/urls.py b/apps/api/urls.py index 0659427f..ef631004 100644 --- a/apps/api/urls.py +++ b/apps/api/urls.py @@ -15,29 +15,33 @@ router = routers.DefaultRouter() router.register('models', ContentTypeViewSet) router.register('user', UserViewSet) +if "activity" in settings.INSTALLED_APPS: + from activity.api.urls import register_activity_urls + register_activity_urls(router, 'activity') + +if "food" in settings.INSTALLED_APPS: + from food.api.urls import register_food_urls + register_food_urls(router, 'food') + +if "logs" in settings.INSTALLED_APPS: + from logs.api.urls import register_logs_urls + register_logs_urls(router, 'logs') + if "member" in settings.INSTALLED_APPS: from member.api.urls import register_members_urls register_members_urls(router, 'members') -if "member" in settings.INSTALLED_APPS: - from activity.api.urls import register_activity_urls - register_activity_urls(router, 'activity') - if "note" in settings.INSTALLED_APPS: from note.api.urls import register_note_urls register_note_urls(router, 'note') -if "treasury" in settings.INSTALLED_APPS: - from treasury.api.urls import register_treasury_urls - register_treasury_urls(router, 'treasury') - if "permission" in settings.INSTALLED_APPS: from permission.api.urls import register_permission_urls register_permission_urls(router, 'permission') -if "logs" in settings.INSTALLED_APPS: - from logs.api.urls import register_logs_urls - register_logs_urls(router, 'logs') +if "treasury" in settings.INSTALLED_APPS: + from treasury.api.urls import register_treasury_urls + register_treasury_urls(router, 'treasury') if "wei" in settings.INSTALLED_APPS: from wei.api.urls import register_wei_urls diff --git a/apps/food/__init__.py b/apps/food/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/food/admin.py b/apps/food/admin.py new file mode 100644 index 00000000..fa32755a --- /dev/null +++ b/apps/food/admin.py @@ -0,0 +1,37 @@ +# Copyright (C) 2018-2024 by BDE ENS Paris-Saclay +# SPDX-License-Identifier: GPL-3.0-or-later + +from django.contrib import admin +from django.db import transaction +from note_kfet.admin import admin_site + +from .models import Allergen, BasicFood, QRCode, TransformedFood + + +@admin.register(QRCode, site=admin_site) +class QRCodeAdmin(admin.ModelAdmin): + pass + + +@admin.register(BasicFood, site=admin_site) +class BasicFoodAdmin(admin.ModelAdmin): + @transaction.atomic + def save_related(self, *args, **kwargs): + ans = super().save_related(*args, **kwargs) + args[1].instance.update() + return ans + + +@admin.register(TransformedFood, site=admin_site) +class TransformedFoodAdmin(admin.ModelAdmin): + exclude = ["allergens", "expiry_date"] + + @transaction.atomic + def save_related(self, request, form, *args, **kwargs): + super().save_related(request, form, *args, **kwargs) + form.instance.update() + + +@admin.register(Allergen, site=admin_site) +class AllergenAdmin(admin.ModelAdmin): + pass diff --git a/apps/food/api/__init__.py b/apps/food/api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/food/api/serializers.py b/apps/food/api/serializers.py new file mode 100644 index 00000000..9c42013f --- /dev/null +++ b/apps/food/api/serializers.py @@ -0,0 +1,50 @@ +# Copyright (C) 2018-2024 by BDE ENS Paris-Saclay +# SPDX-License-Identifier: GPL-3.0-or-later + +from rest_framework import serializers + +from ..models import Allergen, BasicFood, QRCode, TransformedFood + + +class AllergenSerializer(serializers.ModelSerializer): + """ + REST API Serializer for Allergen. + The djangorestframework plugin will analyse the model `Allergen` and parse all fields in the API. + """ + + class Meta: + model = Allergen + fields = '__all__' + + +class BasicFoodSerializer(serializers.ModelSerializer): + """ + REST API Serializer for BasicFood. + The djangorestframework plugin will analyse the model `BasicFood` and parse all fields in the API. + """ + + class Meta: + model = BasicFood + fields = '__all__' + + +class QRCodeSerializer(serializers.ModelSerializer): + """ + REST API Serializer for QRCode. + The djangorestframework plugin will analyse the model `QRCode` and parse all fields in the API. + """ + + class Meta: + model = QRCode + fields = '__all__' + + +class TransformedFoodSerializer(serializers.ModelSerializer): + """ + REST API Serializer for TransformedFood. + The djangorestframework plugin will analyse the model `TransformedFood` and parse all fields in the API. + """ + + class Meta: + model = TransformedFood + fields = '__all__' diff --git a/apps/food/api/urls.py b/apps/food/api/urls.py new file mode 100644 index 00000000..acfb635d --- /dev/null +++ b/apps/food/api/urls.py @@ -0,0 +1,14 @@ +# Copyright (C) 2018-2024 by BDE ENS Paris-Saclay +# SPDX-License-Identifier: GPL-3.0-or-later + +from .views import AllergenViewSet, BasicFoodViewSet, QRCodeViewSet, TransformedFoodViewSet + + +def register_food_urls(router, path): + """ + Configure router for Food REST API. + """ + router.register(path + '/allergen', AllergenViewSet) + router.register(path + '/basic_food', BasicFoodViewSet) + router.register(path + '/qrcode', QRCodeViewSet) + router.register(path + '/transformed_food', TransformedFoodViewSet) diff --git a/apps/food/api/views.py b/apps/food/api/views.py new file mode 100644 index 00000000..824ff809 --- /dev/null +++ b/apps/food/api/views.py @@ -0,0 +1,61 @@ +# Copyright (C) 2018-2024 by BDE ENS Paris-Saclay +# SPDX-License-Identifier: GPL-3.0-or-later + +from api.viewsets import ReadProtectedModelViewSet +from django_filters.rest_framework import DjangoFilterBackend +from rest_framework.filters import SearchFilter + +from .serializers import AllergenSerializer, BasicFoodSerializer, QRCodeSerializer, TransformedFoodSerializer +from ..models import Allergen, BasicFood, QRCode, TransformedFood + + +class AllergenViewSet(ReadProtectedModelViewSet): + """ + REST API View set. + The djangorestframework plugin will get all `Allergen` objects, serialize it to JSON with the given serializer, + then render it on /api/food/allergen/ + """ + queryset = Allergen.objects.order_by('id') + serializer_class = AllergenSerializer + filter_backends = [DjangoFilterBackend, SearchFilter] + filterset_fields = ['name', ] + search_fields = ['$name', ] + + +class BasicFoodViewSet(ReadProtectedModelViewSet): + """ + REST API View set. + The djangorestframework plugin will get all `BasicFood` objects, serialize it to JSON with the given serializer, + then render it on /api/food/basic_food/ + """ + queryset = BasicFood.objects.order_by('id') + serializer_class = BasicFoodSerializer + filter_backends = [DjangoFilterBackend, SearchFilter] + filterset_fields = ['name', ] + search_fields = ['$name', ] + + +class QRCodeViewSet(ReadProtectedModelViewSet): + """ + REST API View set. + The djangorestframework plugin will get all `QRCode` objects, serialize it to JSON with the given serializer, + then render it on /api/food/qrcode/ + """ + queryset = QRCode.objects.order_by('id') + serializer_class = QRCodeSerializer + filter_backends = [DjangoFilterBackend, SearchFilter] + filterset_fields = ['qr_code_number', ] + search_fields = ['$qr_code_number', ] + + +class TransformedFoodViewSet(ReadProtectedModelViewSet): + """ + REST API View set. + The djangorestframework plugin will get all `TransformedFood` objects, serialize it to JSON with the given serializer, + then render it on /api/food/transformed_food/ + """ + queryset = TransformedFood.objects.order_by('id') + serializer_class = TransformedFoodSerializer + filter_backends = [DjangoFilterBackend, SearchFilter] + filterset_fields = ['name', ] + search_fields = ['$name', ] diff --git a/apps/food/apps.py b/apps/food/apps.py new file mode 100644 index 00000000..62ede85f --- /dev/null +++ b/apps/food/apps.py @@ -0,0 +1,11 @@ +# Copyright (C) 2018-2024 by BDE ENS Paris-Saclay +# SPDX-License-Identifier: GPL-3.0-or-later + + +from django.utils.translation import gettext_lazy as _ +from django.apps import AppConfig + + +class FoodkfetConfig(AppConfig): + name = 'food' + verbose_name = _('food') diff --git a/apps/food/forms.py b/apps/food/forms.py new file mode 100644 index 00000000..4f567e59 --- /dev/null +++ b/apps/food/forms.py @@ -0,0 +1,114 @@ +# 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 bootstrap_datepicker_plus.widgets import DateTimePickerInput +from note_kfet.inputs import Autocomplete +from note_kfet.middlewares import get_current_request +from permission.backends import PermissionBackend + +from .models import BasicFood, QRCode, TransformedFood + + +class AddIngredientForms(forms.ModelForm): + """ + Form for add an ingredient + """ + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields['ingredient'].queryset = self.fields['ingredient'].queryset.filter( + polymorphic_ctype__model='transformedfood', + is_ready=False, + is_active=True, + was_eaten=False, + ) + # Caution, the logic is inverted here, we flip the logic on saving in AddIngredientView + self.fields['is_active'].initial = True + self.fields['is_active'].label = _("Fully used") + + class Meta: + model = TransformedFood + fields = ('ingredient', 'is_active') + + +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 + + # Some example + self.fields['name'].widget.attrs.update({"placeholder": _("Pasta METRO 5kg")}) + 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 = BasicFood + fields = ('name', 'owner', 'date_type', 'expiry_date', 'is_active', 'was_eaten', 'allergens',) + widgets = { + "owner": Autocomplete( + model=Club, + attrs={"api_url": "/api/members/club/"}, + ), + 'expiry_date': DateTimePickerInput(), + } + + +class QRCodeForms(forms.ModelForm): + """ + Form for create QRCode + """ + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields['food_container'].queryset = self.fields['food_container'].queryset.filter( + is_active=True, + was_eaten=False, + polymorphic_ctype__model='transformedfood', + ) + + class Meta: + model = QRCode + fields = ('food_container',) + + +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 + self.fields['is_ready'].initial = False + self.fields['was_eaten'].initial = False + + # 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', 'is_ready', 'was_eaten', 'shelf_life') + widgets = { + "owner": Autocomplete( + model=Club, + attrs={"api_url": "/api/members/club/"}, + ), + 'creation_date': DateTimePickerInput(), + } diff --git a/apps/food/migrations/0001_initial.py b/apps/food/migrations/0001_initial.py new file mode 100644 index 00000000..011d0f3f --- /dev/null +++ b/apps/food/migrations/0001_initial.py @@ -0,0 +1,84 @@ +# Generated by Django 2.2.28 on 2024-07-05 08:57 + +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + ('member', '0011_profile_vss_charter_read'), + ] + + operations = [ + migrations.CreateModel( + name='Allergen', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255, verbose_name='name')), + ], + options={ + 'verbose_name': 'Allergen', + 'verbose_name_plural': 'Allergens', + }, + ), + migrations.CreateModel( + name='Food', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=255, verbose_name='name')), + ('expiry_date', models.DateTimeField(verbose_name='expiry date')), + ('was_eaten', models.BooleanField(default=False, verbose_name='was eaten')), + ('is_ready', models.BooleanField(default=False, verbose_name='is ready')), + ('allergens', models.ManyToManyField(blank=True, to='food.Allergen', verbose_name='allergen')), + ('owner', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='+', to='member.Club', verbose_name='owner')), + ('polymorphic_ctype', models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='polymorphic_food.food_set+', to='contenttypes.ContentType')), + ], + options={ + 'verbose_name': 'foods', + }, + ), + migrations.CreateModel( + name='BasicFood', + fields=[ + ('food_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='food.Food')), + ('date_type', models.CharField(choices=[('DLC', 'DLC'), ('DDM', 'DDM')], max_length=255)), + ('arrival_date', models.DateTimeField(default=django.utils.timezone.now, verbose_name='arrival date')), + ], + options={ + 'verbose_name': 'Basic food', + 'verbose_name_plural': 'Basic foods', + }, + bases=('food.food',), + ), + migrations.CreateModel( + name='QRCode', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('qr_code_number', models.PositiveIntegerField(unique=True, verbose_name='QR-code number')), + ('food_container', models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, related_name='QR_code', to='food.Food', verbose_name='food container')), + ], + options={ + 'verbose_name': 'QR-code', + 'verbose_name_plural': 'QR-codes', + }, + ), + migrations.CreateModel( + name='TransformedFood', + fields=[ + ('food_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='food.Food')), + ('creation_date', models.DateTimeField(verbose_name='creation date')), + ('is_active', models.BooleanField(default=True, verbose_name='is active')), + ('ingredient', models.ManyToManyField(blank=True, related_name='transformed_ingredient_inv', to='food.Food', verbose_name='transformed ingredient')), + ], + options={ + 'verbose_name': 'Transformed food', + 'verbose_name_plural': 'Transformed foods', + }, + bases=('food.food',), + ), + ] diff --git a/apps/food/migrations/0002_transformedfood_shelf_life.py b/apps/food/migrations/0002_transformedfood_shelf_life.py new file mode 100644 index 00000000..46673643 --- /dev/null +++ b/apps/food/migrations/0002_transformedfood_shelf_life.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.28 on 2024-07-06 20:37 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('food', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='transformedfood', + name='shelf_life', + field=models.DurationField(default=datetime.timedelta(days=3), verbose_name='shelf life'), + ), + ] diff --git a/apps/food/migrations/0003_create_14_allergens_mandatory.py b/apps/food/migrations/0003_create_14_allergens_mandatory.py new file mode 100644 index 00000000..236eaea4 --- /dev/null +++ b/apps/food/migrations/0003_create_14_allergens_mandatory.py @@ -0,0 +1,62 @@ +from django.db import migrations + +def create_14_mandatory_allergens(apps, schema_editor): + """ + There are 14 mandatory allergens, they are pre-injected + """ + + Allergen = apps.get_model("food", "allergen") + + Allergen.objects.get_or_create( + name="Gluten", + ) + Allergen.objects.get_or_create( + name="Fruits à coques", + ) + Allergen.objects.get_or_create( + name="Crustacés", + ) + Allergen.objects.get_or_create( + name="Céléri", + ) + Allergen.objects.get_or_create( + name="Oeufs", + ) + Allergen.objects.get_or_create( + name="Moutarde", + ) + Allergen.objects.get_or_create( + name="Poissons", + ) + Allergen.objects.get_or_create( + name="Soja", + ) + Allergen.objects.get_or_create( + name="Lait", + ) + Allergen.objects.get_or_create( + name="Sulfites", + ) + Allergen.objects.get_or_create( + name="Sésame", + ) + Allergen.objects.get_or_create( + name="Lupin", + ) + Allergen.objects.get_or_create( + name="Arachides", + ) + Allergen.objects.get_or_create( + name="Mollusques", + ) + +class Migration(migrations.Migration): + dependencies = [ + ('food', '0002_transformedfood_shelf_life'), + ] + + operations = [ + migrations.RunPython(create_14_mandatory_allergens), + ] + + diff --git a/apps/food/migrations/0004_auto_20240813_2358.py b/apps/food/migrations/0004_auto_20240813_2358.py new file mode 100644 index 00000000..d7fdf200 --- /dev/null +++ b/apps/food/migrations/0004_auto_20240813_2358.py @@ -0,0 +1,28 @@ +# Generated by Django 2.2.28 on 2024-08-13 21:58 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('food', '0003_create_14_allergens_mandatory'), + ] + + operations = [ + migrations.RemoveField( + model_name='transformedfood', + name='is_active', + ), + migrations.AddField( + model_name='food', + name='is_active', + field=models.BooleanField(default=True, verbose_name='is active'), + ), + migrations.AlterField( + model_name='qrcode', + name='food_container', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='QR_code', to='food.Food', verbose_name='food container'), + ), + ] diff --git a/apps/food/migrations/__init__.py b/apps/food/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/food/models.py b/apps/food/models.py new file mode 100644 index 00000000..97e00ff9 --- /dev/null +++ b/apps/food/models.py @@ -0,0 +1,226 @@ +# Copyright (C) 2018-2024 by BDE ENS Paris-Saclay +# SPDX-License-Identifier: GPL-3.0-or-later + +from datetime import timedelta + +from django.db import models, transaction +from django.utils import timezone +from django.utils.translation import gettext_lazy as _ +from member.models import Club +from polymorphic.models import PolymorphicModel + + +class QRCode(models.Model): + """ + An QRCode model + """ + qr_code_number = models.PositiveIntegerField( + verbose_name=_("QR-code number"), + unique=True, + ) + + food_container = models.ForeignKey( + 'Food', + on_delete=models.CASCADE, + related_name='QR_code', + verbose_name=_('food container'), + ) + + class Meta: + verbose_name = _("QR-code") + verbose_name_plural = _("QR-codes") + + def __str__(self): + return _("QR-code number {qr_code_number}").format(qr_code_number=self.qr_code_number) + + +class Allergen(models.Model): + """ + A list of allergen and alimentary restrictions + """ + name = models.CharField( + verbose_name=_('name'), + max_length=255, + ) + + class Meta: + verbose_name = _('Allergen') + verbose_name_plural = _('Allergens') + + def __str__(self): + return self.name + + +class Food(PolymorphicModel): + name = models.CharField( + verbose_name=_('name'), + max_length=255, + ) + + owner = models.ForeignKey( + Club, + on_delete=models.PROTECT, + related_name='+', + verbose_name=_('owner'), + ) + + allergens = models.ManyToManyField( + Allergen, + blank=True, + verbose_name=_('allergen'), + ) + + expiry_date = models.DateTimeField( + verbose_name=_('expiry date'), + null=False, + ) + + was_eaten = models.BooleanField( + default=False, + verbose_name=_('was eaten'), + ) + + # is_ready != is_active : is_ready signifie que la nourriture est prête à être manger, + # is_active signifie que la nourriture n'est pas encore archivé + # il sert dans les cas où il est plus intéressant que de l'open soit conservé (confiture par ex) + + is_ready = models.BooleanField( + default=False, + verbose_name=_('is ready'), + ) + + is_active = models.BooleanField( + default=True, + verbose_name=_('is active'), + ) + + def __str__(self): + 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) + + class Meta: + verbose_name = _('food') + verbose_name = _('foods') + + +class BasicFood(Food): + """ + Food which has been directly buy on supermarket + """ + date_type = models.CharField( + max_length=255, + choices=( + ("DLC", "DLC"), + ("DDM", "DDM"), + ) + ) + + arrival_date = models.DateTimeField( + verbose_name=_('arrival date'), + default=timezone.now, + ) + + # label = models.ImageField( + # verbose_name=_('food label'), + # max_length=255, + # blank=False, + # null=False, + # upload_to='label/', + # ) + + @transaction.atomic + def update_allergens(self): + # update parents + for parent in self.transformed_ingredient_inv.iterator(): + parent.update_allergens() + + @transaction.atomic + def update_expiry_date(self): + # update parents + for parent in self.transformed_ingredient_inv.iterator(): + parent.update_expiry_date() + + @transaction.atomic + def update(self): + self.update_allergens() + self.update_expiry_date() + + class Meta: + verbose_name = _('Basic food') + verbose_name_plural = _('Basic foods') + + +class TransformedFood(Food): + """ + Transformed food are a mix between basic food and meal + """ + creation_date = models.DateTimeField( + verbose_name=_('creation date'), + ) + + ingredient = models.ManyToManyField( + Food, + blank=True, + symmetrical=False, + related_name='transformed_ingredient_inv', + verbose_name=_('transformed ingredient'), + ) + + # Without microbiological analyzes, the storage time is 3 days + shelf_life = models.DurationField( + verbose_name=_("shelf life"), + default=timedelta(days=3), + ) + + @transaction.atomic + def archive(self): + # When a meal are archived, if it was eaten, update ingredient fully used for this meal + raise NotImplementedError + + @transaction.atomic + def update_allergens(self): + # When allergens are changed, simply update the parents' allergens + old_allergens = list(self.allergens.all()) + self.allergens.clear() + for ingredient in self.ingredient.iterator(): + self.allergens.set(self.allergens.union(ingredient.allergens.all())) + + if old_allergens == list(self.allergens.all()): + return + super().save() + + # update parents + for parent in self.transformed_ingredient_inv.iterator(): + parent.update_allergens() + + @transaction.atomic + def update_expiry_date(self): + # When expiry_date is changed, simply update the parents' expiry_date + old_expiry_date = self.expiry_date + self.expiry_date = self.creation_date + self.shelf_life + for ingredient in self.ingredient.iterator(): + self.expiry_date = min(self.expiry_date, ingredient.expiry_date) + + if old_expiry_date == self.expiry_date: + return + super().save() + + # update parents + for parent in self.transformed_ingredient_inv.iterator(): + parent.update_expiry_date() + + @transaction.atomic + def update(self): + self.update_allergens() + self.update_expiry_date() + + @transaction.atomic + def save(self, *args, **kwargs): + super().save(*args, **kwargs) + + class Meta: + verbose_name = _('Transformed food') + verbose_name_plural = _('Transformed foods') diff --git a/apps/food/tables.py b/apps/food/tables.py new file mode 100644 index 00000000..4a180c76 --- /dev/null +++ b/apps/food/tables.py @@ -0,0 +1,19 @@ +# Copyright (C) 2018-2024 by BDE ENS Paris-Saclay +# SPDX-License-Identifier: GPL-3.0-or-later + +import django_tables2 as tables +from django_tables2 import A + +from .models import TransformedFood + + +class TransformedFoodTable(tables.Table): + name = tables.LinkColumn( + 'food:food_view', + args=[A('pk'), ], + ) + + class Meta: + model = TransformedFood + template_name = 'django_tables2/bootstrap4.html' + fields = ('name', "owner", "allergens", "expiry_date") diff --git a/apps/food/templates/food/add_ingredient_form.html b/apps/food/templates/food/add_ingredient_form.html new file mode 100644 index 00000000..395928e4 --- /dev/null +++ b/apps/food/templates/food/add_ingredient_form.html @@ -0,0 +1,20 @@ +{% extends "base.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n crispy_forms_tags %} + +{% block content %} +
+

+ {{ title }} +

+
+
+ {% csrf_token %} + {{ form|crispy }} + +
+
+
+{% endblock %} diff --git a/apps/food/templates/food/basicfood_detail.html b/apps/food/templates/food/basicfood_detail.html new file mode 100644 index 00000000..846fadba --- /dev/null +++ b/apps/food/templates/food/basicfood_detail.html @@ -0,0 +1,37 @@ +{% extends "base.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n crispy_forms_tags %} + +{% block content %} +
+

+ {{ title }} {{ food.name }} +

+
+ + {% if can_update %} + {% trans 'Update' %} + {% endif %} + {% if can_add_ingredient %} + + {% trans 'Add to a meal' %} + + {% endif %} +
+
+{% endblock %} diff --git a/apps/food/templates/food/basicfood_form.html b/apps/food/templates/food/basicfood_form.html new file mode 100644 index 00000000..6fe6f06f --- /dev/null +++ b/apps/food/templates/food/basicfood_form.html @@ -0,0 +1,20 @@ +{% extends "base.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n crispy_forms_tags %} + +{% block content %} +
+

+ {{ title }} +

+
+
+ {% csrf_token %} + {{ form | crispy }} + +
+
+
+{% endblock %} diff --git a/apps/food/templates/food/create_qrcode_form.html b/apps/food/templates/food/create_qrcode_form.html new file mode 100644 index 00000000..456b9970 --- /dev/null +++ b/apps/food/templates/food/create_qrcode_form.html @@ -0,0 +1,55 @@ +{% extends "base.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load render_table from django_tables2 %} +{% load i18n crispy_forms_tags %} + +{% block content %} +
+

+ {{ title }} +

+
+ + {% trans 'New basic food' %} + +
+ {% csrf_token %} + {{ form|crispy }} + +
+
+

{% trans "Copy constructor" %}

+ + + + + + + + + + + {% for basic in last_basic %} + + + + + + + {% endfor %} + +
+ {% trans "Name" %} + + {% trans "Owner" %} + + {% trans "Arrival date" %} + + {% trans "Expiry date" %} +
{{ basic.name }}{{ basic.owner }}{{ basic.arrival_date }}{{ basic.expiry_date }}
+
+
+
+{% endblock %} diff --git a/apps/food/templates/food/qrcode_detail.html b/apps/food/templates/food/qrcode_detail.html new file mode 100644 index 00000000..6e3e8110 --- /dev/null +++ b/apps/food/templates/food/qrcode_detail.html @@ -0,0 +1,39 @@ +{% extends "base.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n crispy_forms_tags %} + +{% block content %} +
+

+ {{ title }} {% trans 'number' %} {{ qrcode.qr_code_number }} +

+
+ + {% if qrcode.food_container.polymorphic_ctype.model == 'basicfood' and can_update_basic %} + + {% trans 'Update' %} + + {% elif can_update_transformed %} + + {% trans 'Update' %} + + {% endif %} + {% if can_view_detail %} + + {% trans 'View details' %} + + {% endif %} + {% if can_add_ingredient %} + + {% trans 'Add to a meal' %} + + {% endif %} +
+
+{% endblock %} diff --git a/apps/food/templates/food/transformedfood_detail.html b/apps/food/templates/food/transformedfood_detail.html new file mode 100644 index 00000000..ca32bc06 --- /dev/null +++ b/apps/food/templates/food/transformedfood_detail.html @@ -0,0 +1,51 @@ +{% extends "base.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n crispy_forms_tags %} + +{% block content %} +
+

+ {{ title }} {{ food.name }} +

+
+ + {% if can_update %} + + {% trans 'Update' %} + + {% endif %} + {% if can_add_ingredient %} + + {% trans 'Add to a meal' %} + + {% endif %} +
+
+{% endblock %} diff --git a/apps/food/templates/food/transformedfood_form.html b/apps/food/templates/food/transformedfood_form.html new file mode 100644 index 00000000..395928e4 --- /dev/null +++ b/apps/food/templates/food/transformedfood_form.html @@ -0,0 +1,20 @@ +{% extends "base.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load i18n crispy_forms_tags %} + +{% block content %} +
+

+ {{ title }} +

+
+
+ {% csrf_token %} + {{ form|crispy }} + +
+
+
+{% endblock %} diff --git a/apps/food/templates/food/transformedfood_list.html b/apps/food/templates/food/transformedfood_list.html new file mode 100644 index 00000000..4416cdb7 --- /dev/null +++ b/apps/food/templates/food/transformedfood_list.html @@ -0,0 +1,60 @@ +{% extends "base.html" %} +{% comment %} +SPDX-License-Identifier: GPL-3.0-or-later +{% endcomment %} +{% load render_table from django_tables2 %} +{% load i18n %} + +{% block content %} +
+

+ {% trans "Meal served" %} +

+ {% if can_create_meal %} + + {% endif %} + {% if served.data %} + {% render_table served %} + {% else %} +
+
+ {% trans "There is no meal served." %} +
+
+ {% endif %} +
+ +
+

+ {% trans "Open" %} +

+ {% if open.data %} + {% render_table open %} + {% else %} +
+
+ {% trans "There is no free meal." %} +
+
+ {% endif %} +
+ +
+

+ {% trans "All meals" %} +

+ {% if table.data %} + {% render_table table %} + {% else %} +
+
+ {% trans "There is no meal." %} +
+
+ {% endif %} +
+{% endblock %} diff --git a/apps/food/tests.py b/apps/food/tests.py new file mode 100644 index 00000000..a79ca8be --- /dev/null +++ b/apps/food/tests.py @@ -0,0 +1,3 @@ +# from django.test import TestCase + +# Create your tests here. diff --git a/apps/food/urls.py b/apps/food/urls.py new file mode 100644 index 00000000..09bb8ebe --- /dev/null +++ b/apps/food/urls.py @@ -0,0 +1,21 @@ +# Copyright (C) 2018-2024 by BDE ENS Paris-Saclay +# SPDX-License-Identifier: GPL-3.0-or-later + +from django.urls import path + +from . import views + +app_name = 'food' + +urlpatterns = [ + path('', views.TransformedListView.as_view(), name='food_list'), + path('', views.QRCodeView.as_view(), name='qrcode_view'), + path('detail/', views.FoodView.as_view(), name='food_view'), + + path('/create_qrcode', views.QRCodeCreateView.as_view(), name='qrcode_create'), + path('/create_qrcode/basic', views.QRCodeBasicFoodCreateView.as_view(), name='qrcode_basic_create'), + path('create/transformed', views.TransformedFoodCreateView.as_view(), name='transformed_create'), + path('update/basic/', views.BasicFoodUpdateView.as_view(), name='basic_update'), + path('update/transformed/', views.TransformedFoodUpdateView.as_view(), name='transformed_update'), + path('add/', views.AddIngredientView.as_view(), name='add_ingredient'), +] diff --git a/apps/food/views.py b/apps/food/views.py new file mode 100644 index 00000000..88964a5f --- /dev/null +++ b/apps/food/views.py @@ -0,0 +1,421 @@ +# Copyright (C) 2018-2024 by BDE ENS Paris-Saclay +# SPDX-License-Identifier: GPL-3.0-or-later + +from django.db import transaction +from django.contrib.auth.mixins import LoginRequiredMixin +from django.http import HttpResponseRedirect +from django_tables2.views import MultiTableMixin +from django.urls import reverse +from django.utils.translation import gettext_lazy as _ +from django.utils import timezone +from django.views.generic import DetailView, UpdateView +from django.views.generic.list import ListView +from django.forms import HiddenInput +from permission.backends import PermissionBackend +from permission.views import ProtectQuerysetMixin, ProtectedCreateView + +from .forms import AddIngredientForms, BasicFoodForms, QRCodeForms, TransformedFoodForms +from .models import BasicFood, Food, QRCode, TransformedFood +from .tables import TransformedFoodTable + + +class AddIngredientView(ProtectQuerysetMixin, UpdateView): + """ + A view to add an ingredient + """ + model = Food + template_name = 'food/add_ingredient_form.html' + extra_context = {"title": _("Add the ingredient")} + form_class = AddIngredientForms + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["pk"] = self.kwargs["pk"] + return context + + @transaction.atomic + def form_valid(self, form): + form.instance.creater = self.request.user + food = Food.objects.get(pk=self.kwargs['pk']) + add_ingredient_form = AddIngredientForms(data=self.request.POST) + if food.is_ready: + form.add_error(None, _("The product is already prepared")) + return self.form_invalid(form) + if not add_ingredient_form.is_valid(): + return self.form_invalid(form) + + # We flip logic ""fully used = not is_active"" + food.is_active = not food.is_active + # Save the aliment and the allergens associed + for transformed_pk in self.request.POST.getlist('ingredient'): + transformed = TransformedFood.objects.get(pk=transformed_pk) + if not transformed.is_ready: + transformed.ingredient.add(food) + transformed.update() + food.save() + + return HttpResponseRedirect(self.get_success_url()) + + def get_success_url(self, **kwargs): + return reverse('food:food_list') + + +class BasicFoodUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): + """ + A view to update a basic food + """ + model = BasicFood + form_class = BasicFoodForms + template_name = 'food/basicfood_form.html' + extra_context = {"title": _("Update an aliment")} + + @transaction.atomic + def form_valid(self, form): + form.instance.creater = self.request.user + basic_food_form = BasicFoodForms(data=self.request.POST) + if not basic_food_form.is_valid(): + return self.form_invalid(form) + + ans = super().form_valid(form) + form.instance.update() + return ans + + def get_success_url(self, **kwargs): + self.object.refresh_from_db() + return reverse('food:food_view', kwargs={"pk": self.object.pk}) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + return context + + +class FoodView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): + """ + A view to see a food + """ + model = Food + extra_context = {"title": _("Details of:")} + context_object_name = "food" + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + + context["can_update"] = PermissionBackend.check_perm(self.request, "food.change_food") + context["can_add_ingredient"] = PermissionBackend.check_perm(self.request, "food.change_transformedfood") + return context + + +class QRCodeBasicFoodCreateView(ProtectQuerysetMixin, ProtectedCreateView): + ##################################################################### + # TO DO + # - this feature is very pratical for meat or fish, nevertheless we can implement this later + # - fix picture save + # - implement solution crop and convert image (reuse or recode ImageForm from members apps) + ##################################################################### + """ + A view to add a basic food with a qrcode + """ + model = BasicFood + form_class = BasicFoodForms + template_name = 'food/basicfood_form.html' + extra_context = {"title": _("Add a new basic food with QRCode")} + + @transaction.atomic + def form_valid(self, form): + form.instance.creater = self.request.user + basic_food_form = BasicFoodForms(data=self.request.POST) + if not basic_food_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.is_ready = False + basic_food.is_active = True + basic_food.was_eaten = False + basic_food._force_save = True + basic_food.save() + basic_food.refresh_from_db() + + qrcode = QRCode() + qrcode.qr_code_number = self.kwargs['slug'] + qrcode.food_container = basic_food + qrcode.save() + + return super().form_valid(form) + + def get_success_url(self, **kwargs): + self.object.refresh_from_db() + return reverse('food:qrcode_view', kwargs={"slug": self.kwargs['slug']}) + + def get_sample_object(self): + + # We choose a club which may work or BDE else + owner_id = 1 + for membership in self.request.user.memberships.all(): + club_id = membership.club.id + food = BasicFood(name="", expiry_date=timezone.now(), owner_id=club_id) + if PermissionBackend.check_perm(self.request, "food.add_basicfood", food): + owner_id = club_id + + return BasicFood( + name="", + expiry_date=timezone.now(), + owner_id=owner_id, + ) + + def get_context_data(self, **kwargs): + # Some field are hidden on create + context = super().get_context_data(**kwargs) + + form = context['form'] + form.fields['is_active'].widget = HiddenInput() + form.fields['was_eaten'].widget = HiddenInput() + + copy = self.request.GET.get('copy', None) + if copy is not None: + basic = BasicFood.objects.get(pk=copy) + for field in ['date_type', 'expiry_date', 'name', 'owner']: + form.fields[field].initial = getattr(basic, field) + for field in ['allergens']: + form.fields[field].initial = getattr(basic, field).all() + + return context + + +class QRCodeCreateView(ProtectQuerysetMixin, ProtectedCreateView): + """ + A view to add a new qrcode + """ + model = QRCode + template_name = 'food/create_qrcode_form.html' + form_class = QRCodeForms + extra_context = {"title": _("Add a new QRCode")} + + def get(self, *args, **kwargs): + qrcode = kwargs["slug"] + if self.model.objects.filter(qr_code_number=qrcode).count() > 0: + return HttpResponseRedirect(reverse("food:qrcode_view", kwargs=kwargs)) + else: + return super().get(*args, **kwargs) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context["slug"] = self.kwargs["slug"] + + context["last_basic"] = BasicFood.objects.order_by('-pk').all()[:10] + + return context + + @transaction.atomic + def form_valid(self, form): + form.instance.creater = self.request.user + qrcode_food_form = QRCodeForms(data=self.request.POST) + if not qrcode_food_form.is_valid(): + return self.form_invalid(form) + + # Save the qrcode + qrcode = form.save(commit=False) + qrcode.qr_code_number = self.kwargs["slug"] + qrcode._force_save = True + qrcode.save() + qrcode.refresh_from_db() + + qrcode.food_container.save() + + return super().form_valid(form) + + def get_success_url(self, **kwargs): + self.object.refresh_from_db() + return reverse('food:qrcode_view', kwargs={"slug": self.kwargs['slug']}) + + def get_sample_object(self): + return QRCode( + qr_code_number=self.kwargs["slug"], + food_container_id=1 + ) + + +class QRCodeView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): + """ + A view to see a qrcode + """ + model = QRCode + extra_context = {"title": _("QRCode")} + context_object_name = "qrcode" + slug_field = "qr_code_number" + + def get(self, *args, **kwargs): + qrcode = kwargs["slug"] + if self.model.objects.filter(qr_code_number=qrcode).count() > 0: + return super().get(*args, **kwargs) + else: + return HttpResponseRedirect(reverse("food:qrcode_create", kwargs=kwargs)) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + + qr_code_number = self.kwargs['slug'] + qrcode = self.model.objects.get(qr_code_number=qr_code_number) + + model = qrcode.food_container.polymorphic_ctype.model + + if model == "basicfood": + context["can_update_basic"] = PermissionBackend.check_perm(self.request, "food.change_basicfood") + context["can_view_detail"] = PermissionBackend.check_perm(self.request, "food.view_basicfood") + if model == "transformedfood": + context["can_update_transformed"] = PermissionBackend.check_perm(self.request, "food.change_transformedfood") + context["can_view_detail"] = PermissionBackend.check_perm(self.request, "food.view_transformedfood") + context["can_add_ingredient"] = PermissionBackend.check_perm(self.request, "food.change_transformedfood") + return context + + +class TransformedFoodCreateView(ProtectQuerysetMixin, ProtectedCreateView): + """ + A view to add a tranformed food + """ + model = TransformedFood + template_name = 'food/transformedfood_form.html' + form_class = TransformedFoodForms + extra_context = {"title": _("Add a new meal")} + + @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) + transformed_food.expiry_date = transformed_food.creation_date + transformed_food.is_active = True + transformed_food.is_ready = False + transformed_food.was_eaten = False + transformed_food._force_save = True + transformed_food.save() + transformed_food.refresh_from_db() + ans = super().form_valid(form) + transformed_food.update() + return ans + + def get_success_url(self, **kwargs): + self.object.refresh_from_db() + return reverse('food:food_view', kwargs={"pk": self.object.pk}) + + def get_sample_object(self): + # We choose a club which may work or BDE else + owner_id = 1 + for membership in self.request.user.memberships.all(): + club_id = membership.club.id + food = TransformedFood(name="", + creation_date=timezone.now(), + expiry_date=timezone.now(), + owner_id=club_id) + if PermissionBackend.check_perm(self.request, "food.add_transformedfood", food): + owner_id = club_id + break + + return TransformedFood( + name="", + owner_id=owner_id, + creation_date=timezone.now(), + expiry_date=timezone.now(), + ) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + + # Some field are hidden on create + form = context['form'] + form.fields['is_active'].widget = HiddenInput() + form.fields['is_ready'].widget = HiddenInput() + form.fields['was_eaten'].widget = HiddenInput() + form.fields['shelf_life'].widget = HiddenInput() + + return context + + +class TransformedFoodUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView): + """ + A view to update transformed product + """ + model = TransformedFood + template_name = 'food/transformedfood_form.html' + form_class = TransformedFoodForms + extra_context = {'title': _('Update a meal')} + + @transaction.atomic + def form_valid(self, form): + form.instance.creater = self.request.user + transformedfood_form = TransformedFoodForms(data=self.request.POST) + if not transformedfood_form.is_valid(): + return self.form_invalid(form) + + ans = super().form_valid(form) + form.instance.update() + return ans + + def get_success_url(self, **kwargs): + self.object.refresh_from_db() + return reverse('food:food_view', kwargs={"pk": self.object.pk}) + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + return context + + +class TransformedListView(ProtectQuerysetMixin, LoginRequiredMixin, MultiTableMixin, ListView): + """ + Displays ready TransformedFood + """ + model = TransformedFood + tables = [TransformedFoodTable, TransformedFoodTable, TransformedFoodTable] + extra_context = {"title": _("Transformed food")} + + def get_queryset(self, **kwargs): + return super().get_queryset(**kwargs).distinct() + + def get_tables(self): + tables = super().get_tables() + + tables[0].prefix = "all-" + tables[1].prefix = "open-" + tables[2].prefix = "served-" + return tables + + def get_tables_data(self): + # first table = all transformed food, second table = free, third = served + return [ + self.get_queryset().order_by("-creation_date"), + TransformedFood.objects.filter(is_ready=True, is_active=True, was_eaten=False, expiry_date__lt=timezone.now()) + .filter(PermissionBackend.filter_queryset(self.request, TransformedFood, "view")) + .distinct() + .order_by("-creation_date"), + TransformedFood.objects.filter(is_ready=True, is_active=True, was_eaten=False, expiry_date__gte=timezone.now()) + .filter(PermissionBackend.filter_queryset(self.request, TransformedFood, "view")) + .distinct() + .order_by("-creation_date") + ] + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + + # We choose a club which should work + for membership in self.request.user.memberships.all(): + club_id = membership.club.id + food = TransformedFood( + name="", + owner_id=club_id, + creation_date=timezone.now(), + expiry_date=timezone.now(), + ) + if PermissionBackend.check_perm(self.request, "food.add_transformedfood", food): + context['can_create_meal'] = True + break + + tables = context["tables"] + for name, table in zip(["table", "open", "served"], tables): + context[name] = table + return context diff --git a/apps/permission/fixtures/initial.json b/apps/permission/fixtures/initial.json index 1b97acac..9e4ba924 100644 --- a/apps/permission/fixtures/initial.json +++ b/apps/permission/fixtures/initial.json @@ -3304,6 +3304,454 @@ "description": "Voir le tableau des ouvreur⋅ses" } }, + { + "model": "permission.permission", + "pk": 211, + "fields": { + "model": [ + "food", + "transformedfood" + ], + "query": "{}", + "type": "view", + "mask": 3, + "field": "", + "permanent": false, + "description": "Voir tout les plats" + } + }, + { + "model": "permission.permission", + "pk": 212, + "fields": { + "model": [ + "food", + "transformedfood" + ], + "query": "{\"owner\": [\"club\"]}", + "type": "view", + "mask": 3, + "field": "", + "permanent": false, + "description": "Voir tout les plats de son club" + } + }, + { + "model": "permission.permission", + "pk": 213, + "fields": { + "model": [ + "food", + "transformedfood" + ], + "query": "{\"is_ready\": true, \"is_active\": true, \"was_eaten\": false}", + "type": "view", + "mask": 1, + "field": "", + "permanent": false, + "description": "Voir les plats préparés actifs servis" + } + }, + { + "model": "permission.permission", + "pk": 214, + "fields": { + "model": [ + "food", + "qrcode" + ], + "query": "{}", + "type": "add", + "mask": 3, + "field": "", + "permanent": false, + "description": "Initialiser un QR code de traçabilité" + } + }, + { + "model": "permission.permission", + "pk": 215, + "fields": { + "model": [ + "food", + "basicfood" + ], + "query": "{\"owner\": [\"club\"]}", + "type": "add", + "mask": 3, + "field": "", + "permanent": false, + "description": "Créer un nouvel ingrédient pour son club" + } + }, + { + "model": "permission.permission", + "pk": 216, + "fields": { + "model": [ + "food", + "basicfood" + ], + "query": "{}", + "type": "add", + "mask": 3, + "field": "", + "permanent": false, + "description": "Créer un nouvel ingrédient" + } + }, + { + "model": "permission.permission", + "pk": 217, + "fields": { + "model": [ + "food", + "basicfood" + ], + "query": "{}", + "type": "view", + "mask": 3, + "field": "", + "permanent": false, + "description": "Voir toute la bouffe" + } + }, + { + "model": "permission.permission", + "pk": 218, + "fields": { + "model": [ + "food", + "basicfood" + ], + "query": "{\"is_active\": true}", + "type": "view", + "mask": 3, + "field": "", + "permanent": false, + "description": "Voir toute la bouffe active" + } + }, + { + "model": "permission.permission", + "pk": 219, + "fields": { + "model": [ + "food", + "basicfood" + ], + "query": "{\"is_active\": true, \"owner\": [\"club\"]}", + "type": "view", + "mask": 3, + "field": "", + "permanent": false, + "description": "Voir la bouffe active de son club" + } + }, + { + "model": "permission.permission", + "pk": 220, + "fields": { + "model": [ + "food", + "basicfood" + ], + "query": "{}", + "type": "change", + "mask": 3, + "field": "", + "permanent": false, + "description": "Modifier de la bouffe" + } + }, + { + "model": "permission.permission", + "pk": 221, + "fields": { + "model": [ + "food", + "basicfood" + ], + "query": "{\"is_active\": true, \"was_eaten\": false}", + "type": "change", + "mask": 3, + "field": "allergens", + "permanent": false, + "description": "Modifier les allergènes de la bouffe existante" + } + }, + { + "model": "permission.permission", + "pk": 222, + "fields": { + "model": [ + "food", + "basicfood" + ], + "query": "{\"is_active\": true, \"was_eaten\": false, \"owner\": [\"club\"]}", + "type": "change", + "mask": 3, + "field": "allergens", + "permanent": false, + "description": "Modifier les allergènes de la bouffe appartenant à son club" + } + }, + { + "model": "permission.permission", + "pk": 223, + "fields": { + "model": [ + "food", + "transformedfood" + ], + "query": "{}", + "type": "add", + "mask": 3, + "field": "", + "permanent": false, + "description": "Créer un plat" + } + }, + { + "model": "permission.permission", + "pk": 224, + "fields": { + "model": [ + "food", + "transformedfood" + ], + "query": "{\"owner\": [\"club\"]}", + "type": "add", + "mask": 3, + "field": "", + "permanent": false, + "description": "Créer un plat pour son club" + } + }, + { + "model": "permission.permission", + "pk": 225, + "fields": { + "model": [ + "food", + "transformedfood" + ], + "query": "{}", + "type": "change", + "mask": 3, + "field": "", + "permanent": false, + "description": "Modifier tout les plats" + } + }, + { + "model": "permission.permission", + "pk": 226, + "fields": { + "model": [ + "food", + "transformedfood" + ], + "query": "{\"is_active\": true}", + "type": "change", + "mask": 3, + "field": "was_eaten", + "permanent": false, + "description": "Indiquer si un plat a été mangé" + } + }, + { + "model": "permission.permission", + "pk": 227, + "fields": { + "model": [ + "food", + "transformedfood" + ], + "query": "{\"is_active\": true, \"owner\": [\"club\"]}", + "type": "change", + "mask": 3, + "field": "is_ready", + "permanent": false, + "description": "Indiquer si un plat de son club est prêt" + } + }, + { + "model": "permission.permission", + "pk": 228, + "fields": { + "model": [ + "food", + "transformedfood" + ], + "query": "{\"is_active\": true}", + "type": "change", + "mask": 3, + "field": "is_active", + "permanent": false, + "description": "Archiver un plat" + } + }, + { + "model": "permission.permission", + "pk": 229, + "fields": { + "model": [ + "food", + "basicfood" + ], + "query": "{\"is_active\": true}", + "type": "change", + "mask": 3, + "field": "is_active", + "permanent": false, + "description": "Archiver de la bouffe" + } + }, + { + "model": "permission.permission", + "pk": 230, + "fields": { + "model": [ + "food", + "transformedfood" + ], + "query": "{\"is_active\": true}", + "type": "view", + "mask": 3, + "field": "", + "permanent": false, + "description": "Voir tout les plats actifs" + } + }, + { + "model": "permission.permission", + "pk": 231, + "fields": { + "model": [ + "food", + "qrcode" + ], + "query": "{}", + "type": "view", + "mask": 3, + "field": "", + "permanent": false, + "description": "Voir tous les QR codes" + } + }, + { + "model": "permission.permission", + "pk": 232, + "fields": { + "model": [ + "food", + "qrcode" + ], + "query": "{\"food_container__is_active\": true}", + "type": "view", + "mask": 3, + "field": "", + "permanent": false, + "description": "Voir tous les QR codes actifs" + } + }, + { + "model": "permission.permission", + "pk": 233, + "fields": { + "model": [ + "food", + "qrcode" + ], + "query": "{\"food_container__owner\": [\"club\"], \"food_container__is_active\": true}", + "type": "view", + "mask": 3, + "field": "", + "permanent": false, + "description": "Voir tous les QR codes actifs de son club" + } + }, + { + "model": "permission.permission", + "pk" : 234, + "fields": { + "model": [ + "food", + "transformedfood" + ], + "query": "{\"owner\": [\"club\"], \"is_active\": true}", + "type": "change", + "mask": 3, + "field": "ingredients", + "permanent": false, + "description": "Changer les ingrédients d'un plat actif de son club" + } + }, + { + "model": "permission.permission", + "pk": 235, + "fields": { + "model": [ + "food", + "food" + ], + "query": "{}", + "type": "view", + "mask": 3, + "field": "", + "permanent": false, + "description": "Voir bouffe" + } + }, + { + "model": "permission.permission", + "pk": 236, + "fields": { + "model": [ + "food", + "food" + ], + "query": "{\"is_active\": true}", + "type": "view", + "mask": 3, + "field": "", + "permanent": false, + "description": "Voir bouffe active" + } + }, + { + "model": "permission.permission", + "pk": 237, + "fields": { + "model": [ + "food", + "food" + ], + "query": "{\"is_active\": true, \"owner\": [\"club\"]}", + "type": "view", + "mask": 3, + "field": "", + "permanent": false, + "description": "Voir bouffe active de son club" + } + }, + { + "model": "permission.permission", + "pk": 238, + "fields": { + "model": [ + "food", + "food" + ], + "query": "{}", + "type": "change", + "mask": 3, + "field": "", + "permanent": false, + "description": "Modifier bouffe" + } + }, { "model": "permission.role", "pk": 1, @@ -3391,7 +3839,8 @@ 157, 158, 159, - 160 + 160, + 213 ] } }, @@ -3417,7 +3866,17 @@ 49, 50, 141, - 169 + 169, + 212, + 214, + 215, + 219, + 222, + 224, + 227, + 233, + 234, + 237 ] } }, @@ -3591,7 +4050,21 @@ 166, 167, 168, - 182 + 182, + 212, + 214, + 215, + 218, + 221, + 224, + 226, + 227, + 228, + 229, + 230, + 232, + 234, + 236 ] } }, @@ -3799,7 +4272,8 @@ 168, 176, 177, - 197 + 197, + 211 ] } }, @@ -3817,6 +4291,27 @@ ] } }, + { + "model": "permission.role", + "pk": 22, + "fields": { + "for_club": 2, + "name": "Respo Bouffe", + "permissions": [ + 137, + 211, + 214, + 216, + 217, + 220, + 223, + 225, + 231, + 235, + 238 + ] + } + }, { "model": "wei.weirole", "pk": 12, diff --git a/apps/scripts b/apps/scripts index 472c9c33..f580f9b9 160000 --- a/apps/scripts +++ b/apps/scripts @@ -1 +1 @@ -Subproject commit 472c9c33cea3a9c277033f2108fd81304fb62097 +Subproject commit f580f9b9e9beee76605975fdbc3a2014769e3c61 diff --git a/docs/apps/food.rst b/docs/apps/food.rst new file mode 100644 index 00000000..e34ad40f --- /dev/null +++ b/docs/apps/food.rst @@ -0,0 +1,83 @@ +Application Food +================ + +L'application ``food`` s'occupe de la traçabilité et permet notamment l'obtention de la liste des allergènes. + +Modèles +------- + +L'application comporte 5 modèles : Allergen, QRCode, Food, BasicFood, TransformedFood. + +Food +~~~~ + +Ce modèle est un PolymorphicModel et ne sert uniquement à créer BasicFood et TransformedFood. + +Le modèle regroupe : + +* Nom du produit +* Propriétaire (doit-être un Club) +* Allergènes (ManyToManyField) +* date d'expiration +* a été mangé (booléen) +* est prêt (booléen) + +BasicFood +~~~~~~~~~ + +Les BasicFood correspondent aux produits non modifiés à la Kfet. Ils peuvent correspondre à la fois à des produits achetés en magasin ou à des produits Terre à Terre. Ces produits seront les ingrédients de tous les plats préparés et en conséquent sont les seuls produits à nécessité une saisie manuelle des allergènes. + +Le modèle regroupe : + +* Type de date (DLC = date limite de consommation, DDM = date de durabilité minimale) +* Date d'arrivée +* Champs de Food + +TransformedFood +~~~~~~~~~~~~~~~ + +Les TransformedFood correspondent aux produits préparés à la Kfet. Ils peuvent être composés de BasicFood et/ou de TransformedFood. La date d'expiration et les allergènes sont automatiquement mis à jour par update (qui doit être exécuté après modification des ingrédients dans les forms par exemple). + +Le modèle regroupe : + +* Durée de consommation (par défaut 3 jours) +* Ingrédients (ManyToManyField vers Food) +* Date de création +* Champs de Food + +Allergen +~~~~~~~~ + +Le modèle regroupe : + +* Nom + +QRCode +~~~~~~ + +Le modèle regroupe : + +* nombre (unique, entier positif) +* food (OneToOneField vers Food) + +Création de BasicFood +~~~~~~~~~~~~~~~~~~~~~ + +Un BasicFood a toujours besoin d'un QRCode (depuis l'interface web). Il convient donc de coller le QRCode puis de le scanner et de compléter le formulaire. + +Création de TransformedFood +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Pour créer un TransformedFood, il suffit d'aller dans l'onglet ``traçabilité`` et de cliquer sur l'onglet. + +Ajouter un ingrédient +~~~~~~~~~~~~~~~~~~~~~ + +Un ingrédient a forcément un QRCode. Il convient donc de scanner le QRCode de l'ingrédient et de sélectionner le produit auquel il doit être ajouté. + +Remarque : Un produit fini doit avoir un QRCode et inversement. + +Terminer un plat +~~~~~~~~~~~~~~~~ + +Il suffit de coller le QRCode sur le plat, de le scanner et de sélectionner le produit. diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index 6542cc2a..3abeae7b 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-03-22 00:33+0100\n" +"POT-Creation-Date: 2024-08-17 11:57+0200\n" "PO-Revision-Date: 2020-11-16 20:02+0000\n" "Last-Translator: bleizi \n" "Language-Team: German \n" @@ -18,8 +18,8 @@ msgstr "" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Weblate 4.3.2\n" -#: apps/activity/apps.py:10 apps/activity/models.py:127 -#: apps/activity/models.py:167 +#: apps/activity/apps.py:10 apps/activity/models.py:129 +#: apps/activity/models.py:169 msgid "activity" msgstr "Veranstaltung" @@ -27,33 +27,33 @@ msgstr "Veranstaltung" msgid "The note of this club is inactive." msgstr "" -#: apps/activity/forms.py:41 apps/activity/models.py:140 +#: apps/activity/forms.py:41 apps/activity/models.py:142 msgid "The end date must be after the start date." msgstr "Das Abschlussdatum muss nach das Anfangsdatum sein." -#: apps/activity/forms.py:82 apps/activity/models.py:269 +#: apps/activity/forms.py:82 apps/activity/models.py:271 msgid "You can't invite someone once the activity is started." msgstr "" "Sie dürfen nicht jemandem einladen wenn die Veranstaltung angefangen hat." -#: apps/activity/forms.py:85 apps/activity/models.py:272 +#: apps/activity/forms.py:85 apps/activity/models.py:274 msgid "This activity is not validated yet." msgstr "Diese Veranstaltung ist noch nicht bestätigt." -#: apps/activity/forms.py:95 apps/activity/models.py:280 +#: apps/activity/forms.py:95 apps/activity/models.py:282 msgid "This person has been already invited 5 times this year." msgstr "Diese Person wurde schon 5 mal dieses Jahr eingeladen." -#: apps/activity/forms.py:99 apps/activity/models.py:284 +#: apps/activity/forms.py:99 apps/activity/models.py:286 msgid "This person is already invited." msgstr "Diese Person wurde schon eingeladen." -#: apps/activity/forms.py:103 apps/activity/models.py:288 +#: apps/activity/forms.py:103 apps/activity/models.py:290 msgid "You can't invite more than 3 people to this activity." msgstr "Sie dürfen höchstens 3 Leute zu dieser Veranstaltung einladen." -#: apps/activity/models.py:28 apps/activity/models.py:63 -#: apps/member/models.py:203 +#: apps/activity/models.py:28 apps/activity/models.py:63 apps/food/models.py:42 +#: apps/food/models.py:56 apps/member/models.py:203 #: apps/member/templates/member/includes/club_info.html:4 #: apps/member/templates/member/includes/profile_info.html:4 #: apps/note/models/notes.py:263 apps/note/models/transactions.py:26 @@ -99,121 +99,121 @@ msgstr "Vearnstaltungarte" msgid "description" msgstr "Beschreibung" -#: apps/activity/models.py:72 +#: apps/activity/models.py:74 msgid "location" msgstr "Ort" -#: apps/activity/models.py:76 +#: apps/activity/models.py:78 msgid "Place where the activity is organized, eg. Kfet." msgstr "Wo findet die Veranstaltung statt ? (z.B Kfet)." -#: apps/activity/models.py:83 +#: apps/activity/models.py:85 #: apps/activity/templates/activity/includes/activity_info.html:22 #: apps/note/models/notes.py:207 apps/note/models/transactions.py:67 #: apps/permission/models.py:163 msgid "type" msgstr "Type" -#: apps/activity/models.py:89 apps/logs/models.py:22 apps/member/models.py:313 +#: apps/activity/models.py:91 apps/logs/models.py:22 apps/member/models.py:318 #: apps/note/models/notes.py:148 apps/treasury/models.py:293 #: apps/wei/models.py:171 apps/wei/templates/wei/attribute_bus_1A.html:13 #: apps/wei/templates/wei/survey.html:15 msgid "user" msgstr "User" -#: apps/activity/models.py:96 +#: apps/activity/models.py:98 #: apps/activity/templates/activity/includes/activity_info.html:36 msgid "organizer" msgstr "Veranstalter" -#: apps/activity/models.py:97 +#: apps/activity/models.py:99 msgid "Club that organizes the activity. The entry fees will go to this club." msgstr "" "Die Veranstaltung wurde von einem Club organisert. Die Eintrittsbeiträge " "gehen an diesen Club." -#: apps/activity/models.py:104 +#: apps/activity/models.py:106 #: apps/activity/templates/activity/includes/activity_info.html:39 msgid "attendees club" msgstr "Teilnehmer" -#: apps/activity/models.py:105 +#: apps/activity/models.py:107 msgid "Club that is authorized to join the activity. Mostly the Kfet club." msgstr "Club die an die Veranstaltung teilnehmen können." -#: apps/activity/models.py:109 +#: apps/activity/models.py:111 #: apps/activity/templates/activity/includes/activity_info.html:25 msgid "start date" msgstr "Anfangsdatum" -#: apps/activity/models.py:113 +#: apps/activity/models.py:115 #: apps/activity/templates/activity/includes/activity_info.html:28 msgid "end date" msgstr "Abschlussdatum" -#: apps/activity/models.py:118 +#: apps/activity/models.py:120 #: apps/activity/templates/activity/includes/activity_info.html:50 #: apps/note/models/transactions.py:149 msgid "valid" msgstr "gültig" -#: apps/activity/models.py:123 +#: apps/activity/models.py:125 #: apps/activity/templates/activity/includes/activity_info.html:65 msgid "open" msgstr "geöffnet" -#: apps/activity/models.py:128 +#: apps/activity/models.py:130 msgid "activities" msgstr "Veranstaltungen" -#: apps/activity/models.py:172 +#: apps/activity/models.py:174 msgid "entry time" msgstr "Eintrittzeit" -#: apps/activity/models.py:178 apps/note/apps.py:14 +#: apps/activity/models.py:180 apps/note/apps.py:14 #: apps/note/models/notes.py:77 msgid "note" msgstr "Note" -#: apps/activity/models.py:189 +#: apps/activity/models.py:191 #: apps/activity/templates/activity/activity_entry.html:46 msgid "entry" msgstr "Eintritt" -#: apps/activity/models.py:190 +#: apps/activity/models.py:192 #: apps/activity/templates/activity/activity_entry.html:46 msgid "entries" msgstr "Eintritte" -#: apps/activity/models.py:193 +#: apps/activity/models.py:195 #, python-brace-format msgid "Entry for {guest}, invited by {note} to the activity {activity}" msgstr "Eintritt für {guest}, von {note} zur Vanstaltung {activity} eingeladen" -#: apps/activity/models.py:195 +#: apps/activity/models.py:197 #, python-brace-format msgid "Entry for {note} to the activity {activity}" msgstr "Eintritt von {note} zur Veranstaltung {activity}" -#: apps/activity/models.py:202 +#: apps/activity/models.py:204 msgid "Already entered on " msgstr "Schon eingetretten " -#: apps/activity/models.py:202 apps/activity/tables.py:56 +#: apps/activity/models.py:204 apps/activity/tables.py:56 msgid "{:%Y-%m-%d %H:%M:%S}" msgstr "{:%Y-%m-%d %H:%M:%S}" -#: apps/activity/models.py:210 +#: apps/activity/models.py:212 msgid "The balance is negative." msgstr "Kontostand ist im Rot." -#: apps/activity/models.py:240 +#: apps/activity/models.py:242 #: apps/treasury/templates/treasury/sogecredit_detail.html:14 #: apps/wei/templates/wei/attribute_bus_1A.html:16 msgid "last name" msgstr "Nachname" -#: apps/activity/models.py:245 +#: apps/activity/models.py:247 #: apps/member/templates/member/includes/profile_info.html:4 #: apps/registration/templates/registration/future_profile_detail.html:16 #: apps/treasury/templates/treasury/sogecredit_detail.html:17 @@ -222,19 +222,19 @@ msgstr "Nachname" msgid "first name" msgstr "Vorname" -#: apps/activity/models.py:252 +#: apps/activity/models.py:254 msgid "inviter" msgstr "Einlader" -#: apps/activity/models.py:256 +#: apps/activity/models.py:258 msgid "guest" msgstr "Gast" -#: apps/activity/models.py:257 +#: apps/activity/models.py:259 msgid "guests" msgstr "Gäste" -#: apps/activity/models.py:310 +#: apps/activity/models.py:312 msgid "Invitation" msgstr "Einladung" @@ -246,7 +246,9 @@ msgstr "Die Veranstaltung ist geöffnet." msgid "The validation of the activity is pending." msgstr "Diese Veranstaltung ist noch nicht bestätigt." -#: apps/activity/tables.py:43 apps/treasury/tables.py:107 +#: apps/activity/tables.py:43 +#: apps/member/templates/member/picture_update.html:18 +#: apps/treasury/tables.py:107 msgid "Remove" msgstr "Entfernen" @@ -262,15 +264,15 @@ msgstr "entfernen" msgid "Type" msgstr "Type" -#: apps/activity/tables.py:84 apps/member/forms.py:193 -#: apps/registration/forms.py:92 apps/treasury/forms.py:131 +#: apps/activity/tables.py:84 apps/member/forms.py:196 +#: apps/registration/forms.py:91 apps/treasury/forms.py:131 #: apps/wei/forms/registration.py:104 msgid "Last name" msgstr "Nachname" -#: apps/activity/tables.py:86 apps/member/forms.py:198 +#: apps/activity/tables.py:86 apps/member/forms.py:201 #: apps/note/templates/note/transaction_form.html:138 -#: apps/registration/forms.py:97 apps/treasury/forms.py:133 +#: apps/registration/forms.py:96 apps/treasury/forms.py:133 #: apps/wei/forms/registration.py:109 msgid "First name" msgstr "Vorname" @@ -297,7 +299,7 @@ msgstr "Gastliste" #: apps/note/models/transactions.py:261 #: apps/note/templates/note/transaction_form.html:17 #: apps/note/templates/note/transaction_form.html:152 -#: note_kfet/templates/base.html:72 +#: note_kfet/templates/base.html:78 msgid "Transfer" msgstr "Überweisen" @@ -334,6 +336,10 @@ msgid "Entry done!" msgstr "Eintrittseite" #: apps/activity/templates/activity/activity_form.html:16 +#: apps/food/templates/food/add_ingredient_form.html:16 +#: apps/food/templates/food/basicfood_form.html:16 +#: apps/food/templates/food/create_qrcode_form.html:19 +#: apps/food/templates/food/transformedfood_form.html:16 #: apps/member/templates/member/add_members.html:46 #: apps/member/templates/member/club_form.html:16 #: apps/note/templates/note/transactiontemplate_form.html:18 @@ -399,39 +405,39 @@ msgstr "bearbeiten" msgid "Invite" msgstr "Einladen" -#: apps/activity/views.py:36 +#: apps/activity/views.py:37 msgid "Create new activity" msgstr "Neue Veranstaltung schaffen" -#: apps/activity/views.py:67 note_kfet/templates/base.html:90 +#: apps/activity/views.py:67 note_kfet/templates/base.html:96 msgid "Activities" msgstr "Veranstaltungen" -#: apps/activity/views.py:93 +#: apps/activity/views.py:108 msgid "Activity detail" msgstr "Veranstaltunginfo" -#: apps/activity/views.py:113 +#: apps/activity/views.py:128 msgid "Update activity" msgstr "Veranstaltung bearbeiten" -#: apps/activity/views.py:140 +#: apps/activity/views.py:155 msgid "Invite guest to the activity \"{}\"" msgstr "Gast zur Veranstaltung \"{}\" einladen" -#: apps/activity/views.py:178 +#: apps/activity/views.py:193 msgid "You are not allowed to display the entry interface for this activity." msgstr "Sie haben nicht das Recht diese Seite zu benuzten." -#: apps/activity/views.py:181 +#: apps/activity/views.py:196 msgid "This activity does not support activity entries." msgstr "Diese Veranstaltung braucht nicht Eintritt." -#: apps/activity/views.py:184 +#: apps/activity/views.py:199 msgid "This activity is closed." msgstr "Diese Veranstaltung ist geschlossen." -#: apps/activity/views.py:280 +#: apps/activity/views.py:295 msgid "Entry for activity \"{}\"" msgstr "Eintritt zur Veranstaltung \"{}\"" @@ -439,6 +445,298 @@ msgstr "Eintritt zur Veranstaltung \"{}\"" msgid "API" msgstr "API" +#: apps/food/apps.py:11 apps/food/models.py:105 +msgid "food" +msgstr "" + +#: apps/food/forms.py:32 +msgid "Fully used" +msgstr "" + +#: apps/food/forms.py:50 +msgid "Pasta METRO 5kg" +msgstr "" + +#: apps/food/forms.py:96 +msgid "Lasagna" +msgstr "" + +#: apps/food/models.py:18 +#, fuzzy +#| msgid "phone number" +msgid "QR-code number" +msgstr "Telefonnummer" + +#: apps/food/models.py:26 +msgid "food container" +msgstr "" + +#: apps/food/models.py:30 +msgid "QR-code" +msgstr "" + +#: apps/food/models.py:31 +msgid "QR-codes" +msgstr "" + +#: apps/food/models.py:34 +#, python-brace-format +msgid "QR-code number {qr_code_number}" +msgstr "" + +#: apps/food/models.py:47 +msgid "Allergen" +msgstr "" + +#: apps/food/models.py:48 apps/food/templates/food/basicfood_detail.html:17 +#: apps/food/templates/food/transformedfood_detail.html:20 +msgid "Allergens" +msgstr "" + +#: apps/food/models.py:64 +msgid "owner" +msgstr "" + +#: apps/food/models.py:70 +msgid "allergen" +msgstr "" + +#: apps/food/models.py:74 +#, fuzzy +#| msgid "birth date" +msgid "expiry date" +msgstr "Geburtsdatum" + +#: apps/food/models.py:80 +msgid "was eaten" +msgstr "" + +#: apps/food/models.py:89 +msgid "is ready" +msgstr "" + +#: apps/food/models.py:94 +#, fuzzy +#| msgid "active" +msgid "is active" +msgstr "Aktiv" + +#: apps/food/models.py:106 +msgid "foods" +msgstr "" + +#: apps/food/models.py:122 +#, fuzzy +#| msgid "start date" +msgid "arrival date" +msgstr "Anfangsdatum" + +#: apps/food/models.py:152 +msgid "Basic food" +msgstr "" + +#: apps/food/models.py:153 +msgid "Basic foods" +msgstr "" + +#: apps/food/models.py:161 +#, fuzzy +#| msgid "created at" +msgid "creation date" +msgstr "erschafft am" + +#: apps/food/models.py:169 +msgid "transformed ingredient" +msgstr "" + +#: apps/food/models.py:174 +msgid "shelf life" +msgstr "" + +#: apps/food/models.py:225 apps/food/views.py:365 +#, fuzzy +#| msgid "Transfer money" +msgid "Transformed food" +msgstr "Geld überweisen" + +#: apps/food/models.py:226 +msgid "Transformed foods" +msgstr "" + +#: apps/food/templates/food/basicfood_detail.html:14 +#: apps/food/templates/food/qrcode_detail.html:15 +#: apps/food/templates/food/transformedfood_detail.html:14 +#, fuzzy +#| msgid "Owned" +msgid "Owner" +msgstr "Besetzt" + +#: apps/food/templates/food/basicfood_detail.html:15 +#, fuzzy +#| msgid "start date" +msgid "Arrival date" +msgstr "Anfangsdatum" + +#: apps/food/templates/food/basicfood_detail.html:16 +#: apps/food/templates/food/qrcode_detail.html:16 +#: apps/food/templates/food/transformedfood_detail.html:19 +#, fuzzy +#| msgid "birth date" +msgid "Expiry date" +msgstr "Geburtsdatum" + +#: apps/food/templates/food/basicfood_detail.html:24 +#: apps/food/templates/food/transformedfood_detail.html:36 +#, fuzzy +#| msgid "active" +msgid "Active" +msgstr "Aktiv" + +#: apps/food/templates/food/basicfood_detail.html:25 +#: apps/food/templates/food/transformedfood_detail.html:37 +msgid "Eaten" +msgstr "" + +#: apps/food/templates/food/basicfood_detail.html:28 +#: apps/food/templates/food/qrcode_detail.html:20 +#: apps/food/templates/food/qrcode_detail.html:24 +#: apps/food/templates/food/transformedfood_detail.html:41 +#, fuzzy +#| msgid "Update bus" +msgid "Update" +msgstr "Bus bearbeiten" + +#: apps/food/templates/food/basicfood_detail.html:32 +#: apps/food/templates/food/qrcode_detail.html:34 +#: apps/food/templates/food/transformedfood_detail.html:46 +#, fuzzy +#| msgid "Add team" +msgid "Add to a meal" +msgstr "Neue Team" + +#: apps/food/templates/food/create_qrcode_form.html:14 +#, fuzzy +#| msgid "Transfer money" +msgid "New basic food" +msgstr "Geld überweisen" + +#: apps/food/templates/food/qrcode_detail.html:10 +#, fuzzy +#| msgid "phone number" +msgid "number" +msgstr "Telefonnummer" + +#: apps/food/templates/food/qrcode_detail.html:14 +#: apps/note/templates/note/transaction_form.html:132 +#: apps/treasury/models.py:60 +msgid "Name" +msgstr "Name" + +#: apps/food/templates/food/qrcode_detail.html:29 +#, fuzzy +#| msgid "Profile detail" +msgid "View details" +msgstr "Profile detail" + +#: apps/food/templates/food/transformedfood_detail.html:16 +#: apps/food/templates/food/transformedfood_detail.html:35 +msgid "Ready" +msgstr "" + +#: apps/food/templates/food/transformedfood_detail.html:18 +#, fuzzy +#| msgid "created at" +msgid "Creation date" +msgstr "erschafft am" + +#: apps/food/templates/food/transformedfood_detail.html:27 +msgid "Ingredients" +msgstr "" + +#: apps/food/templates/food/transformedfood_detail.html:34 +msgid "Shelf life" +msgstr "" + +#: apps/food/templates/food/transformedfood_list.html:11 +msgid "Meal served" +msgstr "" + +#: apps/food/templates/food/transformedfood_list.html:16 +#, fuzzy +#| msgid "New user" +msgid "New meal" +msgstr "Neue User" + +#: apps/food/templates/food/transformedfood_list.html:25 +#, fuzzy +#| msgid "There is no results." +msgid "There is no meal served." +msgstr "Es gibt keine Ergebnisse." + +#: apps/food/templates/food/transformedfood_list.html:33 +msgid "Open" +msgstr "" + +#: apps/food/templates/food/transformedfood_list.html:40 +#, fuzzy +#| msgid "There is no results." +msgid "There is no free meal." +msgstr "Es gibt keine Ergebnisse." + +#: apps/food/templates/food/transformedfood_list.html:48 +msgid "All meals" +msgstr "" + +#: apps/food/templates/food/transformedfood_list.html:55 +#, fuzzy +#| msgid "There is no results." +msgid "There is no meal." +msgstr "Es gibt keine Ergebnisse." + +#: apps/food/views.py:28 +msgid "Add the ingredient" +msgstr "" + +#: apps/food/views.py:42 +#, fuzzy +#| msgid "This credit is already validated." +msgid "The product is already prepared" +msgstr "Dieser Kredit ist bereits validiert." + +#: apps/food/views.py:70 +#, fuzzy +#| msgid "Update an invoice" +msgid "Update an aliment" +msgstr "Rechnung bearbeiten" + +#: apps/food/views.py:97 +#, fuzzy +#| msgid "WEI Detail" +msgid "Details of:" +msgstr "WEI Infos" + +#: apps/food/views.py:121 +msgid "Add a new basic food with QRCode" +msgstr "" + +#: apps/food/views.py:185 +msgid "Add a new QRCode" +msgstr "" + +#: apps/food/views.py:235 +msgid "QRCode" +msgstr "" + +#: apps/food/views.py:271 +msgid "Add a new meal" +msgstr "" + +#: apps/food/views.py:337 +#, fuzzy +#| msgid "Update team" +msgid "Update a meal" +msgstr "Team bearbeiten" + #: apps/logs/apps.py:11 msgid "Logs" msgstr "Logs" @@ -508,11 +806,11 @@ msgstr "Mitgliedschaftpreis (bezahlte Studenten)" msgid "membership fee (unpaid students)" msgstr "Mitgliedschaftpreis (unbezahlte Studenten)" -#: apps/member/admin.py:65 apps/member/models.py:325 +#: apps/member/admin.py:65 apps/member/models.py:330 msgid "roles" msgstr "Rollen" -#: apps/member/admin.py:66 apps/member/models.py:339 +#: apps/member/admin.py:66 apps/member/models.py:344 msgid "fee" msgstr "Preis" @@ -565,49 +863,49 @@ msgstr "Maximal Größe: 2MB" msgid "This image cannot be loaded." msgstr "Dieses Bild kann nicht geladen werden." -#: apps/member/forms.py:148 apps/member/views.py:102 -#: apps/registration/forms.py:34 apps/registration/views.py:266 +#: apps/member/forms.py:151 apps/member/views.py:102 +#: apps/registration/forms.py:33 apps/registration/views.py:276 msgid "An alias with a similar name already exists." msgstr "Ein ähnliches Alias ist schon benutzt." -#: apps/member/forms.py:172 +#: apps/member/forms.py:175 msgid "Inscription paid by Société Générale" msgstr "Mitgliedschaft von der Société Générale bezahlt" -#: apps/member/forms.py:174 +#: apps/member/forms.py:177 msgid "Check this case if the Société Générale paid the inscription." msgstr "Die Société Générale die Mitgliedschaft bezahlt." -#: apps/member/forms.py:179 apps/registration/forms.py:79 +#: apps/member/forms.py:182 apps/registration/forms.py:78 #: apps/wei/forms/registration.py:91 msgid "Credit type" msgstr "Kredittype" -#: apps/member/forms.py:180 apps/registration/forms.py:80 +#: apps/member/forms.py:183 apps/registration/forms.py:79 #: apps/wei/forms/registration.py:92 msgid "No credit" msgstr "Kein Kredit" -#: apps/member/forms.py:182 +#: apps/member/forms.py:185 msgid "You can credit the note of the user." msgstr "Sie dûrfen diese Note kreditieren." -#: apps/member/forms.py:186 apps/registration/forms.py:85 +#: apps/member/forms.py:189 apps/registration/forms.py:84 #: apps/wei/forms/registration.py:97 msgid "Credit amount" msgstr "Kreditanzahl" -#: apps/member/forms.py:203 apps/note/templates/note/transaction_form.html:144 -#: apps/registration/forms.py:102 apps/treasury/forms.py:135 +#: apps/member/forms.py:206 apps/note/templates/note/transaction_form.html:144 +#: apps/registration/forms.py:101 apps/treasury/forms.py:135 #: apps/wei/forms/registration.py:114 msgid "Bank" msgstr "Bank" -#: apps/member/forms.py:230 +#: apps/member/forms.py:233 msgid "User" msgstr "User" -#: apps/member/forms.py:244 +#: apps/member/forms.py:247 msgid "Roles" msgstr "Rollen" @@ -857,46 +1155,52 @@ msgid "Maximal date of a membership, after which members must renew it." msgstr "" "Maximales Datum einer Mitgliedschaft, nach dem Mitglieder es erneuern müssen." -#: apps/member/models.py:263 apps/member/models.py:319 +#: apps/member/models.py:263 +#, fuzzy +#| msgid "Validate registration" +msgid "add to registration form" +msgstr "Registrierung validieren" + +#: apps/member/models.py:268 apps/member/models.py:324 #: apps/note/models/notes.py:176 msgid "club" msgstr "Club" -#: apps/member/models.py:264 +#: apps/member/models.py:269 msgid "clubs" msgstr "Clubs" -#: apps/member/models.py:330 +#: apps/member/models.py:335 msgid "membership starts on" msgstr "Mitgliedschaft fängt an" -#: apps/member/models.py:334 +#: apps/member/models.py:339 msgid "membership ends on" msgstr "Mitgliedschaft endet am" -#: apps/member/models.py:343 apps/note/models/transactions.py:385 +#: apps/member/models.py:348 apps/note/models/transactions.py:385 msgid "membership" msgstr "Mitgliedschaft" -#: apps/member/models.py:344 +#: apps/member/models.py:349 msgid "memberships" msgstr "Mitgliedschaften" -#: apps/member/models.py:348 +#: apps/member/models.py:353 #, python-brace-format msgid "Membership of {user} for the club {club}" msgstr "Mitgliedschaft von {user} für das Club {club}" -#: apps/member/models.py:367 +#: apps/member/models.py:372 #, python-brace-format msgid "The role {role} does not apply to the club {club}." msgstr "Die Rolle {role} ist nicht erlaubt für das Club {club}." -#: apps/member/models.py:376 apps/member/views.py:712 +#: apps/member/models.py:381 apps/member/views.py:715 msgid "User is already a member of the club" msgstr "User ist schon ein Mitglied dieser club" -#: apps/member/models.py:388 apps/member/views.py:721 +#: apps/member/models.py:393 apps/member/views.py:724 msgid "User is not a member of the parent club" msgstr "User ist noch nicht Mitglied des Urclubs" @@ -1013,7 +1317,7 @@ msgstr "" #: apps/member/templates/member/club_alias.html:10 #: apps/member/templates/member/profile_alias.html:10 apps/member/views.py:287 -#: apps/member/views.py:517 +#: apps/member/views.py:520 msgid "Note aliases" msgstr "Note Aliases" @@ -1169,11 +1473,11 @@ msgstr "" msgid "Show my applications" msgstr "" -#: apps/member/templates/member/picture_update.html:35 +#: apps/member/templates/member/picture_update.html:38 msgid "Nevermind" msgstr "Vergessen" -#: apps/member/templates/member/picture_update.html:36 +#: apps/member/templates/member/picture_update.html:39 msgid "Crop and upload" msgstr "Beschneiden und hochladen" @@ -1218,7 +1522,7 @@ msgstr "Speichern" msgid "Registrations" msgstr "Anmeldung" -#: apps/member/views.py:72 apps/registration/forms.py:24 +#: apps/member/views.py:72 apps/registration/forms.py:23 msgid "This address must be valid." msgstr "Diese Adresse muss gültig sein." @@ -1238,31 +1542,31 @@ msgstr "" msgid "Update note picture" msgstr "Notebild ändern" -#: apps/member/views.py:354 +#: apps/member/views.py:357 msgid "Manage auth token" msgstr "Auth token bearbeiten" -#: apps/member/views.py:381 +#: apps/member/views.py:384 msgid "Create new club" msgstr "Neue Club" -#: apps/member/views.py:400 +#: apps/member/views.py:403 msgid "Search club" msgstr "Club finden" -#: apps/member/views.py:433 +#: apps/member/views.py:436 msgid "Club detail" msgstr "Club Details" -#: apps/member/views.py:540 +#: apps/member/views.py:543 msgid "Update club" msgstr "Club bearbeiten" -#: apps/member/views.py:574 +#: apps/member/views.py:577 msgid "Add new member to the club" msgstr "Neue Mitglieder" -#: apps/member/views.py:703 apps/wei/views.py:973 +#: apps/member/views.py:706 apps/wei/views.py:973 msgid "" "This user don't have enough money to join this club, and can't have a " "negative balance." @@ -1270,19 +1574,19 @@ msgstr "" "Diese User hat nicht genug Geld um Mitglied zu werden, und darf nich im Rot " "sein." -#: apps/member/views.py:725 +#: apps/member/views.py:728 msgid "The membership must start after {:%m-%d-%Y}." msgstr "Die Mitgliedschaft muss nach {:%m-%d-Y} anfängen." -#: apps/member/views.py:730 +#: apps/member/views.py:733 msgid "The membership must begin before {:%m-%d-%Y}." msgstr "Die Mitgliedschaft muss vor {:%m-%d-Y} anfängen." -#: apps/member/views.py:880 +#: apps/member/views.py:883 msgid "Manage roles of an user in the club" msgstr "Rollen in diesen Club bearbeiten" -#: apps/member/views.py:905 +#: apps/member/views.py:908 msgid "Members of the club" msgstr "Mitlglieder dieses Club" @@ -1747,11 +2051,6 @@ msgstr "Aktion" msgid "Amount" msgstr "Anzahl" -#: apps/note/templates/note/transaction_form.html:132 -#: apps/treasury/models.py:60 -msgid "Name" -msgstr "Name" - #: apps/note/templates/note/transaction_form.html:177 msgid "Select emitter" msgstr "Sender auswählen" @@ -2029,7 +2328,7 @@ msgstr "" "diesen Parametern zu erstellen. Bitte korrigieren Sie Ihre Daten und " "versuchen Sie es erneut." -#: apps/permission/views.py:112 note_kfet/templates/base.html:108 +#: apps/permission/views.py:112 note_kfet/templates/base.html:114 msgid "Rights" msgstr "Rechten" @@ -2041,15 +2340,15 @@ msgstr "Alle Rechten" msgid "registration" msgstr "Anmeldung" -#: apps/registration/forms.py:40 +#: apps/registration/forms.py:39 msgid "This email address is already used." msgstr "Diese email adresse ist schon benutzt." -#: apps/registration/forms.py:60 +#: apps/registration/forms.py:59 msgid "Register to the WEI" msgstr "Zu WEI anmelden" -#: apps/registration/forms.py:62 +#: apps/registration/forms.py:61 msgid "" "Check this case if you want to register to the WEI. If you hesitate, you " "will be able to register later, after validating your account in the Kfet." @@ -2058,11 +2357,11 @@ msgstr "" "falls Zweifel, können Sie sich später nach Bestätigung Ihres Kontos im Kfet " "registrieren." -#: apps/registration/forms.py:107 +#: apps/registration/forms.py:106 msgid "Join BDE Club" msgstr "BDE Mitglieder werden" -#: apps/registration/forms.py:114 +#: apps/registration/forms.py:113 msgid "Join Kfet Club" msgstr "Kfet Mitglieder werden" @@ -2173,58 +2472,64 @@ msgstr "Danke" msgid "The Note Kfet team." msgstr "Die NoteKfet Team." -#: apps/registration/views.py:41 +#: apps/registration/views.py:42 msgid "Register new user" msgstr "Neuen User registrieren" -#: apps/registration/views.py:99 +#: apps/registration/views.py:100 msgid "Email validation" msgstr "Email validierung" -#: apps/registration/views.py:101 +#: apps/registration/views.py:102 msgid "Validate email" msgstr "Email validieren" -#: apps/registration/views.py:145 +#: apps/registration/views.py:146 msgid "Email validation unsuccessful" msgstr "Email validierung unerfolgreich" -#: apps/registration/views.py:156 +#: apps/registration/views.py:157 msgid "Email validation email sent" msgstr "Validierungsemail wurde gesendet" -#: apps/registration/views.py:164 +#: apps/registration/views.py:165 msgid "Resend email validation link" msgstr "E-Mail-Validierungslink erneut senden" -#: apps/registration/views.py:182 +#: apps/registration/views.py:183 msgid "Pre-registered users list" msgstr "Vorregistrierte Userliste" -#: apps/registration/views.py:206 +#: apps/registration/views.py:207 msgid "Unregistered users" msgstr "Unregistrierte Users" -#: apps/registration/views.py:219 +#: apps/registration/views.py:220 msgid "Registration detail" msgstr "Registrierung Detailen" -#: apps/registration/views.py:293 +#: apps/registration/views.py:256 +#, fuzzy, python-format +#| msgid "Note of %(club)s club" +msgid "Join %(club)s Club" +msgstr "%(club)s Note" + +#: apps/registration/views.py:299 msgid "You must join the BDE." msgstr "Sie müssen die BDE beitreten." -#: apps/registration/views.py:323 +#: apps/registration/views.py:330 msgid "" "The entered amount is not enough for the memberships, should be at least {}" msgstr "" "Der eingegebene Betrag reicht für die Mitgliedschaft nicht aus, sollte " "mindestens {} betragen" -#: apps/registration/views.py:417 +#: apps/registration/views.py:425 msgid "Invalidate pre-registration" msgstr "Ungültige Vorregistrierung" -#: apps/treasury/apps.py:12 note_kfet/templates/base.html:96 +#: apps/treasury/apps.py:12 note_kfet/templates/base.html:102 msgid "Treasury" msgstr "Quaestor" @@ -2650,7 +2955,7 @@ msgstr "Krediten von der Société générale handeln" #: apps/wei/apps.py:10 apps/wei/models.py:37 apps/wei/models.py:38 #: apps/wei/models.py:62 apps/wei/models.py:178 -#: note_kfet/templates/base.html:102 +#: note_kfet/templates/base.html:108 msgid "WEI" msgstr "WEI" @@ -3284,19 +3589,19 @@ msgstr "" msgid "Attribute bus" msgstr "" -#: note_kfet/settings/base.py:172 +#: note_kfet/settings/base.py:173 msgid "German" msgstr "Deutsch" -#: note_kfet/settings/base.py:173 +#: note_kfet/settings/base.py:174 msgid "English" msgstr "English" -#: note_kfet/settings/base.py:174 +#: note_kfet/settings/base.py:175 msgid "Spanish" msgstr "Spanisch" -#: note_kfet/settings/base.py:175 +#: note_kfet/settings/base.py:176 msgid "French" msgstr "Französich" @@ -3360,34 +3665,38 @@ msgstr "Reset" msgid "The ENS Paris-Saclay BDE note." msgstr "Die BDE ENS-Paris-Saclay Note." -#: note_kfet/templates/base.html:78 +#: note_kfet/templates/base.html:72 +msgid "Food" +msgstr "" + +#: note_kfet/templates/base.html:84 msgid "Users" msgstr "Users" -#: note_kfet/templates/base.html:84 +#: note_kfet/templates/base.html:90 msgid "Clubs" msgstr "Clubs" -#: note_kfet/templates/base.html:113 +#: note_kfet/templates/base.html:119 msgid "Admin" msgstr "Admin" -#: note_kfet/templates/base.html:127 +#: note_kfet/templates/base.html:133 msgid "My account" msgstr "Mein Konto" -#: note_kfet/templates/base.html:130 +#: note_kfet/templates/base.html:136 msgid "Log out" msgstr "Abmelden" -#: note_kfet/templates/base.html:138 +#: note_kfet/templates/base.html:144 #: note_kfet/templates/registration/signup.html:6 #: note_kfet/templates/registration/signup.html:11 #: note_kfet/templates/registration/signup.html:28 msgid "Sign up" msgstr "Registrieren" -#: note_kfet/templates/base.html:145 +#: note_kfet/templates/base.html:151 #: note_kfet/templates/registration/login.html:6 #: note_kfet/templates/registration/login.html:15 #: note_kfet/templates/registration/login.html:38 @@ -3395,13 +3704,13 @@ msgstr "Registrieren" msgid "Log in" msgstr "Anmelden" -#: note_kfet/templates/base.html:159 +#: note_kfet/templates/base.html:165 msgid "" "You are not a BDE member anymore. Please renew your membership if you want " "to use the note." msgstr "" -#: note_kfet/templates/base.html:165 +#: note_kfet/templates/base.html:171 msgid "" "Your e-mail address is not validated. Please check your mail inbox and click " "on the validation link." @@ -3409,7 +3718,7 @@ msgstr "" "Ihre E-Mail-Adresse ist nicht validiert. Bitte überprüfen Sie Ihren " "Posteingang und klicken Sie auf den Validierungslink." -#: note_kfet/templates/base.html:171 +#: note_kfet/templates/base.html:177 msgid "" "You declared that you opened a bank account in the Société générale. The " "bank did not validate the creation of the account to the BDE, so the " @@ -3418,15 +3727,19 @@ msgid "" "creation." msgstr "" -#: note_kfet/templates/base.html:194 +#: note_kfet/templates/base.html:200 msgid "Contact us" msgstr "Kontakt" -#: note_kfet/templates/base.html:196 +#: note_kfet/templates/base.html:202 msgid "Technical Support" msgstr "" -#: note_kfet/templates/base.html:198 +#: note_kfet/templates/base.html:204 +msgid "Charte Info (FR)" +msgstr "" + +#: note_kfet/templates/base.html:206 msgid "FAQ (FR)" msgstr "FAQ (FR)" @@ -3677,6 +3990,298 @@ msgstr "" "müssen Ihre E-Mail-Adresse auch überprüfen, indem Sie dem Link folgen, den " "Sie erhalten haben." +#, fuzzy +#~| msgid "Email validation" +#~ msgid "Enter a valid color." +#~ msgstr "Email validierung" + +#, fuzzy +#~| msgid "Email validation" +#~ msgid "Enter a valid value." +#~ msgstr "Email validierung" + +#, fuzzy +#~| msgid "Invitation" +#~ msgid "Syndication" +#~ msgstr "Einladung" + +#, fuzzy +#~| msgid "There is no results." +#~ msgid "That page contains no results" +#~ msgstr "Es gibt keine Ergebnisse." + +#, fuzzy +#~| msgid "Email validation" +#~ msgid "Enter a valid URL." +#~ msgstr "Email validierung" + +#, fuzzy +#~| msgid "Email validation" +#~ msgid "Enter a valid integer." +#~ msgstr "Email validierung" + +#, fuzzy +#~| msgid "Email validation" +#~ msgid "Enter a valid email address." +#~ msgstr "Email validierung" + +#, fuzzy +#~| msgid "This activity is not validated yet." +#~ msgid "Enter a valid IPv4 address." +#~ msgstr "Diese Veranstaltung ist noch nicht bestätigt." + +#, fuzzy +#~| msgid "This activity is not validated yet." +#~ msgid "Enter a valid IPv6 address." +#~ msgstr "Diese Veranstaltung ist noch nicht bestätigt." + +#, fuzzy +#~| msgid "This activity is not validated yet." +#~ msgid "Enter a valid IPv4 or IPv6 address." +#~ msgstr "Diese Veranstaltung ist noch nicht bestätigt." + +#, fuzzy +#~| msgid "phone number" +#~ msgid "Enter a number." +#~ msgstr "Telefonnummer" + +#, fuzzy +#~| msgid "add" +#~ msgid "and" +#~ msgstr "hinzufügen" + +#, fuzzy, python-format +#~| msgid "A template with this name already exist" +#~ msgid "%(model_name)s with this %(field_labels)s already exists." +#~ msgstr "Eine Vorlage mit diesem Namen ist bereits vorhanden" + +#, fuzzy +#~| msgid "This image cannot be loaded." +#~ msgid "This field cannot be null." +#~ msgstr "Dieses Bild kann nicht geladen werden." + +#, fuzzy +#~| msgid "This image cannot be loaded." +#~ msgid "This field cannot be blank." +#~ msgstr "Dieses Bild kann nicht geladen werden." + +#, fuzzy, python-format +#~| msgid "A template with this name already exist" +#~ msgid "%(model_name)s with this %(field_label)s already exists." +#~ msgstr "Eine Vorlage mit diesem Namen ist bereits vorhanden" + +#, fuzzy +#~| msgid "phone number" +#~ msgid "Decimal number" +#~ msgstr "Telefonnummer" + +#, fuzzy +#~| msgid "action" +#~ msgid "Duration" +#~ msgstr "Aktion" + +#, fuzzy +#~| msgid "address" +#~ msgid "Email address" +#~ msgstr "Adresse" + +#, fuzzy +#~| msgid "phone number" +#~ msgid "Floating point number" +#~ msgstr "Telefonnummer" + +#, fuzzy +#~| msgid "IP Address" +#~ msgid "IPv4 address" +#~ msgstr "IP Adresse" + +#, fuzzy +#~| msgid "IP Address" +#~ msgid "IP address" +#~ msgstr "IP Adresse" + +#, fuzzy +#~| msgid "Invoice identifier" +#~ msgid "Universally unique identifier" +#~ msgstr "Rechnungskennung" + +#, fuzzy, python-format +#~| msgid "A template with this name already exist" +#~ msgid "%(model)s instance with %(field)s %(value)r does not exist." +#~ msgstr "Eine Vorlage mit diesem Namen ist bereits vorhanden" + +#, fuzzy +#~| msgid "phone number" +#~ msgid "Enter a whole number." +#~ msgstr "Telefonnummer" + +#, fuzzy +#~| msgid "Email validation" +#~ msgid "Enter a valid date." +#~ msgstr "Email validierung" + +#, fuzzy +#~| msgid "Email validation" +#~ msgid "Enter a valid time." +#~ msgstr "Email validierung" + +#, fuzzy +#~| msgid "Email validation" +#~ msgid "Enter a valid date/time." +#~ msgstr "Email validierung" + +#, fuzzy +#~| msgid "Email validation" +#~ msgid "Enter a valid duration." +#~ msgstr "Email validierung" + +#, fuzzy +#~| msgid "phone number" +#~ msgid "Enter a complete value." +#~ msgstr "Telefonnummer" + +#, fuzzy +#~| msgid "Email validation" +#~ msgid "Enter a valid UUID." +#~ msgstr "Email validierung" + +#, fuzzy, python-format +#~| msgid "This activity is not validated yet." +#~ msgid "\"%(pk)s\" is not a valid value." +#~ msgstr "Diese Veranstaltung ist noch nicht bestätigt." + +#, fuzzy +#~| msgid "Current activity" +#~ msgid "Currently" +#~ msgstr "Aktuelle Veranstaltung" + +#, fuzzy +#~| msgid "change" +#~ msgid "Change" +#~ msgstr "bearbeiten" + +#, fuzzy +#~| msgid "Search WEI" +#~ msgid "March" +#~ msgstr "WEI finden" + +#, fuzzy +#~| msgid "member" +#~ msgid "September" +#~ msgstr "Mitglied" + +#, fuzzy +#~| msgid "member" +#~ msgid "November" +#~ msgstr "Mitglied" + +#, fuzzy +#~| msgid "member" +#~ msgid "December" +#~ msgstr "Mitglied" + +#, fuzzy +#~| msgid "add" +#~ msgid "jan" +#~ msgstr "hinzufügen" + +#, fuzzy +#~| msgid "fee" +#~ msgid "feb" +#~ msgstr "Preis" + +#, fuzzy +#~| msgid "product" +#~ msgid "oct" +#~ msgstr "Produkt" + +#, fuzzy +#~| msgid "Search WEI" +#~ msgctxt "abbrev. month" +#~ msgid "March" +#~ msgstr "WEI finden" + +#, fuzzy +#~| msgid "Search WEI" +#~ msgctxt "alt. month" +#~ msgid "March" +#~ msgstr "WEI finden" + +#, fuzzy +#~| msgid "member" +#~ msgctxt "alt. month" +#~ msgid "September" +#~ msgstr "Mitglied" + +#, fuzzy +#~| msgid "member" +#~ msgctxt "alt. month" +#~ msgid "November" +#~ msgstr "Mitglied" + +#, fuzzy +#~| msgid "member" +#~ msgctxt "alt. month" +#~ msgid "December" +#~ msgstr "Mitglied" + +#, fuzzy +#~| msgid "This activity is not validated yet." +#~ msgid "This is not a valid IPv6 address." +#~ msgstr "Diese Veranstaltung ist noch nicht bestätigt." + +#, fuzzy, python-format +#~| msgid "year" +#~ msgid "%d year" +#~ msgid_plural "%d years" +#~ msgstr[0] "Jahr" +#~ msgstr[1] "Jahr" + +#, fuzzy +#~| msgid "No reason specified" +#~ msgid "No year specified" +#~ msgstr "Kein Grund gegeben" + +#, fuzzy +#~| msgid "No reason specified" +#~ msgid "No month specified" +#~ msgstr "Kein Grund gegeben" + +#, fuzzy +#~| msgid "No reason specified" +#~ msgid "No day specified" +#~ msgstr "Kein Grund gegeben" + +#, fuzzy +#~| msgid "No reason specified" +#~ msgid "No week specified" +#~ msgstr "Kein Grund gegeben" + +#, fuzzy +#~| msgid "Reset my password" +#~ msgid "Resource owner password-based" +#~ msgstr "Mein Passwort zurücksetzen" + +#, fuzzy +#~| msgid "This address must be valid." +#~ msgid "The access token is invalid." +#~ msgstr "Diese Adresse muss gültig sein." + +#, fuzzy +#~| msgid "This address must be valid." +#~ msgid "The access token has expired." +#~ msgstr "Diese Adresse muss gültig sein." + +#, fuzzy +#~| msgid "This address must be valid." +#~ msgid "The access token is valid but does not have enough scope." +#~ msgstr "Diese Adresse muss gültig sein." + +#, fuzzy +#~| msgid "WEI registration" +#~ msgid "In preparation" +#~ msgstr "WEI Registrierung" + #~ msgid "Join BDA Club" #~ msgstr "BDA Mitglieder werden" diff --git a/locale/es/LC_MESSAGES/django.po b/locale/es/LC_MESSAGES/django.po index 73702a57..31c5e750 100644 --- a/locale/es/LC_MESSAGES/django.po +++ b/locale/es/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-03-22 00:33+0100\n" +"POT-Creation-Date: 2024-08-17 11:57+0200\n" "PO-Revision-Date: 2022-04-11 23:12+0200\n" "Last-Translator: bleizi \n" "Language-Team: \n" @@ -18,8 +18,8 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.0.1\n" -#: apps/activity/apps.py:10 apps/activity/models.py:127 -#: apps/activity/models.py:167 +#: apps/activity/apps.py:10 apps/activity/models.py:129 +#: apps/activity/models.py:169 msgid "activity" msgstr "actividad" @@ -27,32 +27,32 @@ msgstr "actividad" msgid "The note of this club is inactive." msgstr "La note del club está inactiva." -#: apps/activity/forms.py:41 apps/activity/models.py:140 +#: apps/activity/forms.py:41 apps/activity/models.py:142 msgid "The end date must be after the start date." msgstr "La fecha final tiene que ser después de la fecha de inicio." -#: apps/activity/forms.py:82 apps/activity/models.py:269 +#: apps/activity/forms.py:82 apps/activity/models.py:271 msgid "You can't invite someone once the activity is started." msgstr "No se puede invitar a alguien una vez que arrancó la actividad." -#: apps/activity/forms.py:85 apps/activity/models.py:272 +#: apps/activity/forms.py:85 apps/activity/models.py:274 msgid "This activity is not validated yet." msgstr "Esta actividad no fue validada por ahora." -#: apps/activity/forms.py:95 apps/activity/models.py:280 +#: apps/activity/forms.py:95 apps/activity/models.py:282 msgid "This person has been already invited 5 times this year." msgstr "Esta persona ya fue invitada 5 veces este año." -#: apps/activity/forms.py:99 apps/activity/models.py:284 +#: apps/activity/forms.py:99 apps/activity/models.py:286 msgid "This person is already invited." msgstr "Esta persona ya está invitada." -#: apps/activity/forms.py:103 apps/activity/models.py:288 +#: apps/activity/forms.py:103 apps/activity/models.py:290 msgid "You can't invite more than 3 people to this activity." msgstr "Usted no puede invitar más de 3 persona a esta actividad." -#: apps/activity/models.py:28 apps/activity/models.py:63 -#: apps/member/models.py:203 +#: apps/activity/models.py:28 apps/activity/models.py:63 apps/food/models.py:42 +#: apps/food/models.py:56 apps/member/models.py:203 #: apps/member/templates/member/includes/club_info.html:4 #: apps/member/templates/member/includes/profile_info.html:4 #: apps/note/models/notes.py:263 apps/note/models/transactions.py:26 @@ -98,121 +98,121 @@ msgstr "tipos de actividad" msgid "description" msgstr "descripción" -#: apps/activity/models.py:72 +#: apps/activity/models.py:74 msgid "location" msgstr "ubicación" -#: apps/activity/models.py:76 +#: apps/activity/models.py:78 msgid "Place where the activity is organized, eg. Kfet." msgstr "Lugar donde se organiza la actividad, por ejemplo la Kfet." -#: apps/activity/models.py:83 +#: apps/activity/models.py:85 #: apps/activity/templates/activity/includes/activity_info.html:22 #: apps/note/models/notes.py:207 apps/note/models/transactions.py:67 #: apps/permission/models.py:163 msgid "type" msgstr "tipo" -#: apps/activity/models.py:89 apps/logs/models.py:22 apps/member/models.py:313 +#: apps/activity/models.py:91 apps/logs/models.py:22 apps/member/models.py:318 #: apps/note/models/notes.py:148 apps/treasury/models.py:293 #: apps/wei/models.py:171 apps/wei/templates/wei/attribute_bus_1A.html:13 #: apps/wei/templates/wei/survey.html:15 msgid "user" msgstr "usuario" -#: apps/activity/models.py:96 +#: apps/activity/models.py:98 #: apps/activity/templates/activity/includes/activity_info.html:36 msgid "organizer" msgstr "organizador" -#: apps/activity/models.py:97 +#: apps/activity/models.py:99 msgid "Club that organizes the activity. The entry fees will go to this club." msgstr "" "El club que organiza la actividad. Los pagos de entrada serán dados a este " "club." -#: apps/activity/models.py:104 +#: apps/activity/models.py:106 #: apps/activity/templates/activity/includes/activity_info.html:39 msgid "attendees club" msgstr "club esperado" -#: apps/activity/models.py:105 +#: apps/activity/models.py:107 msgid "Club that is authorized to join the activity. Mostly the Kfet club." msgstr "Club permitido unirse a la actividad. Generalmente el club Kfet." -#: apps/activity/models.py:109 +#: apps/activity/models.py:111 #: apps/activity/templates/activity/includes/activity_info.html:25 msgid "start date" msgstr "fecha de inicio" -#: apps/activity/models.py:113 +#: apps/activity/models.py:115 #: apps/activity/templates/activity/includes/activity_info.html:28 msgid "end date" msgstr "fecha de fin" -#: apps/activity/models.py:118 +#: apps/activity/models.py:120 #: apps/activity/templates/activity/includes/activity_info.html:50 #: apps/note/models/transactions.py:149 msgid "valid" msgstr "válido" -#: apps/activity/models.py:123 +#: apps/activity/models.py:125 #: apps/activity/templates/activity/includes/activity_info.html:65 msgid "open" msgstr "abierto" -#: apps/activity/models.py:128 +#: apps/activity/models.py:130 msgid "activities" msgstr "actividades" -#: apps/activity/models.py:172 +#: apps/activity/models.py:174 msgid "entry time" msgstr "hora de entrada" -#: apps/activity/models.py:178 apps/note/apps.py:14 +#: apps/activity/models.py:180 apps/note/apps.py:14 #: apps/note/models/notes.py:77 msgid "note" msgstr "note" -#: apps/activity/models.py:189 +#: apps/activity/models.py:191 #: apps/activity/templates/activity/activity_entry.html:46 msgid "entry" msgstr "entrada" -#: apps/activity/models.py:190 +#: apps/activity/models.py:192 #: apps/activity/templates/activity/activity_entry.html:46 msgid "entries" msgstr "entradas" -#: apps/activity/models.py:193 +#: apps/activity/models.py:195 #, python-brace-format msgid "Entry for {guest}, invited by {note} to the activity {activity}" msgstr "Entrada para {guest}, invitado por {note} en la actividad {activity}" -#: apps/activity/models.py:195 +#: apps/activity/models.py:197 #, python-brace-format msgid "Entry for {note} to the activity {activity}" msgstr "Entrada para {note} en la actividad {activity}" -#: apps/activity/models.py:202 +#: apps/activity/models.py:204 msgid "Already entered on " msgstr "Entrado ya el " -#: apps/activity/models.py:202 apps/activity/tables.py:56 +#: apps/activity/models.py:204 apps/activity/tables.py:56 msgid "{:%Y-%m-%d %H:%M:%S}" msgstr "{:%d/%m/%Y %H:%M:%S}" -#: apps/activity/models.py:210 +#: apps/activity/models.py:212 msgid "The balance is negative." msgstr "El saldo es negativo." -#: apps/activity/models.py:240 +#: apps/activity/models.py:242 #: apps/treasury/templates/treasury/sogecredit_detail.html:14 #: apps/wei/templates/wei/attribute_bus_1A.html:16 msgid "last name" msgstr "apellido" -#: apps/activity/models.py:245 +#: apps/activity/models.py:247 #: apps/member/templates/member/includes/profile_info.html:4 #: apps/registration/templates/registration/future_profile_detail.html:16 #: apps/treasury/templates/treasury/sogecredit_detail.html:17 @@ -221,19 +221,19 @@ msgstr "apellido" msgid "first name" msgstr "nombre" -#: apps/activity/models.py:252 +#: apps/activity/models.py:254 msgid "inviter" msgstr "huésped" -#: apps/activity/models.py:256 +#: apps/activity/models.py:258 msgid "guest" msgstr "invitado" -#: apps/activity/models.py:257 +#: apps/activity/models.py:259 msgid "guests" msgstr "invitados" -#: apps/activity/models.py:310 +#: apps/activity/models.py:312 msgid "Invitation" msgstr "Invitación" @@ -245,7 +245,9 @@ msgstr "La actividad está actualmente abierta." msgid "The validation of the activity is pending." msgstr "La validación de esta actividad es pendiente." -#: apps/activity/tables.py:43 apps/treasury/tables.py:107 +#: apps/activity/tables.py:43 +#: apps/member/templates/member/picture_update.html:18 +#: apps/treasury/tables.py:107 msgid "Remove" msgstr "Quitar" @@ -261,15 +263,15 @@ msgstr "quitar" msgid "Type" msgstr "Tipo" -#: apps/activity/tables.py:84 apps/member/forms.py:193 -#: apps/registration/forms.py:92 apps/treasury/forms.py:131 +#: apps/activity/tables.py:84 apps/member/forms.py:196 +#: apps/registration/forms.py:91 apps/treasury/forms.py:131 #: apps/wei/forms/registration.py:104 msgid "Last name" msgstr "Apellido" -#: apps/activity/tables.py:86 apps/member/forms.py:198 +#: apps/activity/tables.py:86 apps/member/forms.py:201 #: apps/note/templates/note/transaction_form.html:138 -#: apps/registration/forms.py:97 apps/treasury/forms.py:133 +#: apps/registration/forms.py:96 apps/treasury/forms.py:133 #: apps/wei/forms/registration.py:109 msgid "First name" msgstr "Nombre" @@ -294,7 +296,7 @@ msgstr "Invitados suprimidos" #: apps/note/models/transactions.py:261 #: apps/note/templates/note/transaction_form.html:17 #: apps/note/templates/note/transaction_form.html:152 -#: note_kfet/templates/base.html:72 +#: note_kfet/templates/base.html:78 msgid "Transfer" msgstr "Transferencia" @@ -329,6 +331,10 @@ msgid "Entry done!" msgstr "Entrada echa !" #: apps/activity/templates/activity/activity_form.html:16 +#: apps/food/templates/food/add_ingredient_form.html:16 +#: apps/food/templates/food/basicfood_form.html:16 +#: apps/food/templates/food/create_qrcode_form.html:19 +#: apps/food/templates/food/transformedfood_form.html:16 #: apps/member/templates/member/add_members.html:46 #: apps/member/templates/member/club_form.html:16 #: apps/note/templates/note/transactiontemplate_form.html:18 @@ -394,41 +400,41 @@ msgstr "modificar" msgid "Invite" msgstr "Invitar" -#: apps/activity/views.py:36 +#: apps/activity/views.py:37 msgid "Create new activity" msgstr "Crear una nueva actividad" -#: apps/activity/views.py:67 note_kfet/templates/base.html:90 +#: apps/activity/views.py:67 note_kfet/templates/base.html:96 msgid "Activities" msgstr "Actividades" -#: apps/activity/views.py:93 +#: apps/activity/views.py:108 msgid "Activity detail" msgstr "Detalles de la actividad" -#: apps/activity/views.py:113 +#: apps/activity/views.py:128 msgid "Update activity" msgstr "Modificar la actividad" -#: apps/activity/views.py:140 +#: apps/activity/views.py:155 msgid "Invite guest to the activity \"{}\"" msgstr "Invitar alguien para la actividad \"{}\"" -#: apps/activity/views.py:178 +#: apps/activity/views.py:193 msgid "You are not allowed to display the entry interface for this activity." msgstr "" "Usted no tiene derecho a mostrar la interfaz de las entradas para esta " "actividad." -#: apps/activity/views.py:181 +#: apps/activity/views.py:196 msgid "This activity does not support activity entries." msgstr "Esta actividad no necesita entradas." -#: apps/activity/views.py:184 +#: apps/activity/views.py:199 msgid "This activity is closed." msgstr "Esta actividad esta cerrada." -#: apps/activity/views.py:280 +#: apps/activity/views.py:295 msgid "Entry for activity \"{}\"" msgstr "Entradas para la actividad \"{}\"" @@ -436,6 +442,298 @@ msgstr "Entradas para la actividad \"{}\"" msgid "API" msgstr "API" +#: apps/food/apps.py:11 apps/food/models.py:105 +msgid "food" +msgstr "" + +#: apps/food/forms.py:32 +msgid "Fully used" +msgstr "" + +#: apps/food/forms.py:50 +msgid "Pasta METRO 5kg" +msgstr "" + +#: apps/food/forms.py:96 +msgid "Lasagna" +msgstr "" + +#: apps/food/models.py:18 +#, fuzzy +#| msgid "phone number" +msgid "QR-code number" +msgstr "número de teléfono" + +#: apps/food/models.py:26 +msgid "food container" +msgstr "" + +#: apps/food/models.py:30 +msgid "QR-code" +msgstr "" + +#: apps/food/models.py:31 +msgid "QR-codes" +msgstr "" + +#: apps/food/models.py:34 +#, python-brace-format +msgid "QR-code number {qr_code_number}" +msgstr "" + +#: apps/food/models.py:47 +msgid "Allergen" +msgstr "" + +#: apps/food/models.py:48 apps/food/templates/food/basicfood_detail.html:17 +#: apps/food/templates/food/transformedfood_detail.html:20 +msgid "Allergens" +msgstr "" + +#: apps/food/models.py:64 +msgid "owner" +msgstr "" + +#: apps/food/models.py:70 +msgid "allergen" +msgstr "" + +#: apps/food/models.py:74 +#, fuzzy +#| msgid "birth date" +msgid "expiry date" +msgstr "fecha de nacimiento" + +#: apps/food/models.py:80 +msgid "was eaten" +msgstr "" + +#: apps/food/models.py:89 +msgid "is ready" +msgstr "" + +#: apps/food/models.py:94 +#, fuzzy +#| msgid "active" +msgid "is active" +msgstr "activo" + +#: apps/food/models.py:106 +msgid "foods" +msgstr "" + +#: apps/food/models.py:122 +#, fuzzy +#| msgid "invalidate" +msgid "arrival date" +msgstr "invalidar" + +#: apps/food/models.py:152 +msgid "Basic food" +msgstr "" + +#: apps/food/models.py:153 +msgid "Basic foods" +msgstr "" + +#: apps/food/models.py:161 +#, fuzzy +#| msgid "created at" +msgid "creation date" +msgstr "creada el" + +#: apps/food/models.py:169 +msgid "transformed ingredient" +msgstr "" + +#: apps/food/models.py:174 +msgid "shelf life" +msgstr "" + +#: apps/food/models.py:225 apps/food/views.py:365 +#, fuzzy +#| msgid "Transfer money" +msgid "Transformed food" +msgstr "Transferir dinero" + +#: apps/food/models.py:226 +msgid "Transformed foods" +msgstr "" + +#: apps/food/templates/food/basicfood_detail.html:14 +#: apps/food/templates/food/qrcode_detail.html:15 +#: apps/food/templates/food/transformedfood_detail.html:14 +#, fuzzy +#| msgid "Owned" +msgid "Owner" +msgstr "Tenido" + +#: apps/food/templates/food/basicfood_detail.html:15 +#, fuzzy +#| msgid "invalidate" +msgid "Arrival date" +msgstr "invalidar" + +#: apps/food/templates/food/basicfood_detail.html:16 +#: apps/food/templates/food/qrcode_detail.html:16 +#: apps/food/templates/food/transformedfood_detail.html:19 +#, fuzzy +#| msgid "birth date" +msgid "Expiry date" +msgstr "fecha de nacimiento" + +#: apps/food/templates/food/basicfood_detail.html:24 +#: apps/food/templates/food/transformedfood_detail.html:36 +#, fuzzy +#| msgid "active" +msgid "Active" +msgstr "activo" + +#: apps/food/templates/food/basicfood_detail.html:25 +#: apps/food/templates/food/transformedfood_detail.html:37 +msgid "Eaten" +msgstr "" + +#: apps/food/templates/food/basicfood_detail.html:28 +#: apps/food/templates/food/qrcode_detail.html:20 +#: apps/food/templates/food/qrcode_detail.html:24 +#: apps/food/templates/food/transformedfood_detail.html:41 +#, fuzzy +#| msgid "Update bus" +msgid "Update" +msgstr "Modificar el bus" + +#: apps/food/templates/food/basicfood_detail.html:32 +#: apps/food/templates/food/qrcode_detail.html:34 +#: apps/food/templates/food/transformedfood_detail.html:46 +#, fuzzy +#| msgid "Add team" +msgid "Add to a meal" +msgstr "Añadir un equipo" + +#: apps/food/templates/food/create_qrcode_form.html:14 +#, fuzzy +#| msgid "Transfer money" +msgid "New basic food" +msgstr "Transferir dinero" + +#: apps/food/templates/food/qrcode_detail.html:10 +#, fuzzy +#| msgid "phone number" +msgid "number" +msgstr "número de teléfono" + +#: apps/food/templates/food/qrcode_detail.html:14 +#: apps/note/templates/note/transaction_form.html:132 +#: apps/treasury/models.py:60 +msgid "Name" +msgstr "Nombre" + +#: apps/food/templates/food/qrcode_detail.html:29 +#, fuzzy +#| msgid "Profile detail" +msgid "View details" +msgstr "Detalles del usuario" + +#: apps/food/templates/food/transformedfood_detail.html:16 +#: apps/food/templates/food/transformedfood_detail.html:35 +msgid "Ready" +msgstr "" + +#: apps/food/templates/food/transformedfood_detail.html:18 +#, fuzzy +#| msgid "created at" +msgid "Creation date" +msgstr "creada el" + +#: apps/food/templates/food/transformedfood_detail.html:27 +msgid "Ingredients" +msgstr "" + +#: apps/food/templates/food/transformedfood_detail.html:34 +msgid "Shelf life" +msgstr "" + +#: apps/food/templates/food/transformedfood_list.html:11 +msgid "Meal served" +msgstr "" + +#: apps/food/templates/food/transformedfood_list.html:16 +#, fuzzy +#| msgid "New user" +msgid "New meal" +msgstr "Nuevo usuario" + +#: apps/food/templates/food/transformedfood_list.html:25 +#, fuzzy +#| msgid "There is no results." +msgid "There is no meal served." +msgstr "No hay resultado." + +#: apps/food/templates/food/transformedfood_list.html:33 +msgid "Open" +msgstr "" + +#: apps/food/templates/food/transformedfood_list.html:40 +#, fuzzy +#| msgid "There is no results." +msgid "There is no free meal." +msgstr "No hay resultado." + +#: apps/food/templates/food/transformedfood_list.html:48 +msgid "All meals" +msgstr "" + +#: apps/food/templates/food/transformedfood_list.html:55 +#, fuzzy +#| msgid "There is no results." +msgid "There is no meal." +msgstr "No hay resultado." + +#: apps/food/views.py:28 +msgid "Add the ingredient" +msgstr "" + +#: apps/food/views.py:42 +#, fuzzy +#| msgid "This credit is already validated." +msgid "The product is already prepared" +msgstr "Este crédito ya fue validado." + +#: apps/food/views.py:70 +#, fuzzy +#| msgid "Update an invoice" +msgid "Update an aliment" +msgstr "Modificar una factura" + +#: apps/food/views.py:97 +#, fuzzy +#| msgid "WEI Detail" +msgid "Details of:" +msgstr "Detalles del WEI" + +#: apps/food/views.py:121 +msgid "Add a new basic food with QRCode" +msgstr "" + +#: apps/food/views.py:185 +msgid "Add a new QRCode" +msgstr "" + +#: apps/food/views.py:235 +msgid "QRCode" +msgstr "" + +#: apps/food/views.py:271 +msgid "Add a new meal" +msgstr "" + +#: apps/food/views.py:337 +#, fuzzy +#| msgid "Update team" +msgid "Update a meal" +msgstr "Modificar el equipo" + #: apps/logs/apps.py:11 msgid "Logs" msgstr "Logs" @@ -505,11 +803,11 @@ msgstr "pago de afiliación (estudiantes pagados)" msgid "membership fee (unpaid students)" msgstr "pago de afiliación (estudiantes no pagados)" -#: apps/member/admin.py:65 apps/member/models.py:325 +#: apps/member/admin.py:65 apps/member/models.py:330 msgid "roles" msgstr "papel" -#: apps/member/admin.py:66 apps/member/models.py:339 +#: apps/member/admin.py:66 apps/member/models.py:344 msgid "fee" msgstr "pago" @@ -561,49 +859,49 @@ msgstr "Tamaño máximo : 2Mo" msgid "This image cannot be loaded." msgstr "Esta imagen no puede ser cargada." -#: apps/member/forms.py:148 apps/member/views.py:102 -#: apps/registration/forms.py:34 apps/registration/views.py:266 +#: apps/member/forms.py:151 apps/member/views.py:102 +#: apps/registration/forms.py:33 apps/registration/views.py:276 msgid "An alias with a similar name already exists." msgstr "Un alias similar ya existe." -#: apps/member/forms.py:172 +#: apps/member/forms.py:175 msgid "Inscription paid by Société Générale" msgstr "Registración pagadas por Société Générale" -#: apps/member/forms.py:174 +#: apps/member/forms.py:177 msgid "Check this case if the Société Générale paid the inscription." msgstr "Marcar esta casilla si Société Générale pagó la registración." -#: apps/member/forms.py:179 apps/registration/forms.py:79 +#: apps/member/forms.py:182 apps/registration/forms.py:78 #: apps/wei/forms/registration.py:91 msgid "Credit type" msgstr "Tipo de crédito" -#: apps/member/forms.py:180 apps/registration/forms.py:80 +#: apps/member/forms.py:183 apps/registration/forms.py:79 #: apps/wei/forms/registration.py:92 msgid "No credit" msgstr "No crédito" -#: apps/member/forms.py:182 +#: apps/member/forms.py:185 msgid "You can credit the note of the user." msgstr "Usted puede acreditar la note del usuario." -#: apps/member/forms.py:186 apps/registration/forms.py:85 +#: apps/member/forms.py:189 apps/registration/forms.py:84 #: apps/wei/forms/registration.py:97 msgid "Credit amount" msgstr "Valor del crédito" -#: apps/member/forms.py:203 apps/note/templates/note/transaction_form.html:144 -#: apps/registration/forms.py:102 apps/treasury/forms.py:135 +#: apps/member/forms.py:206 apps/note/templates/note/transaction_form.html:144 +#: apps/registration/forms.py:101 apps/treasury/forms.py:135 #: apps/wei/forms/registration.py:114 msgid "Bank" msgstr "Banco" -#: apps/member/forms.py:230 +#: apps/member/forms.py:233 msgid "User" msgstr "Usuario" -#: apps/member/forms.py:244 +#: apps/member/forms.py:247 msgid "Roles" msgstr "Papeles" @@ -850,46 +1148,52 @@ msgstr "" "Ultima fecha de una afiliación, después de la cual los miembros tienen que " "prorrogarla." -#: apps/member/models.py:263 apps/member/models.py:319 +#: apps/member/models.py:263 +#, fuzzy +#| msgid "Validate registration" +msgid "add to registration form" +msgstr "Validar la afiliación" + +#: apps/member/models.py:268 apps/member/models.py:324 #: apps/note/models/notes.py:176 msgid "club" msgstr "club" -#: apps/member/models.py:264 +#: apps/member/models.py:269 msgid "clubs" msgstr "clubs" -#: apps/member/models.py:330 +#: apps/member/models.py:335 msgid "membership starts on" msgstr "afiliación empezá el" -#: apps/member/models.py:334 +#: apps/member/models.py:339 msgid "membership ends on" msgstr "afiliación termina el" -#: apps/member/models.py:343 apps/note/models/transactions.py:385 +#: apps/member/models.py:348 apps/note/models/transactions.py:385 msgid "membership" msgstr "afiliación" -#: apps/member/models.py:344 +#: apps/member/models.py:349 msgid "memberships" msgstr "afiliaciones" -#: apps/member/models.py:348 +#: apps/member/models.py:353 #, python-brace-format msgid "Membership of {user} for the club {club}" msgstr "Afiliación of {user} for the club {club}" -#: apps/member/models.py:367 +#: apps/member/models.py:372 #, python-brace-format msgid "The role {role} does not apply to the club {club}." msgstr "El papel {role} no se encuentra en el club {club}." -#: apps/member/models.py:376 apps/member/views.py:712 +#: apps/member/models.py:381 apps/member/views.py:715 msgid "User is already a member of the club" msgstr "Usuario ya esta un miembro del club" -#: apps/member/models.py:388 apps/member/views.py:721 +#: apps/member/models.py:393 apps/member/views.py:724 msgid "User is not a member of the parent club" msgstr "Usuario no es un miembro del club pariente" @@ -1003,7 +1307,7 @@ msgstr "" #: apps/member/templates/member/club_alias.html:10 #: apps/member/templates/member/profile_alias.html:10 apps/member/views.py:287 -#: apps/member/views.py:517 +#: apps/member/views.py:520 msgid "Note aliases" msgstr "Alias de la note" @@ -1151,11 +1455,11 @@ msgstr "Introspección :" msgid "Show my applications" msgstr "Mostrar mis aplicaciones" -#: apps/member/templates/member/picture_update.html:35 +#: apps/member/templates/member/picture_update.html:38 msgid "Nevermind" msgstr "No importa" -#: apps/member/templates/member/picture_update.html:36 +#: apps/member/templates/member/picture_update.html:39 msgid "Crop and upload" msgstr "Podar y subir" @@ -1204,7 +1508,7 @@ msgstr "Guardar cambios" msgid "Registrations" msgstr "Registraciones" -#: apps/member/views.py:72 apps/registration/forms.py:24 +#: apps/member/views.py:72 apps/registration/forms.py:23 msgid "This address must be valid." msgstr "Este correo tiene que ser valido." @@ -1224,31 +1528,31 @@ msgstr "Amistades de note" msgid "Update note picture" msgstr "Modificar la imagen de la note" -#: apps/member/views.py:354 +#: apps/member/views.py:357 msgid "Manage auth token" msgstr "Gestionar los token de autentificación" -#: apps/member/views.py:381 +#: apps/member/views.py:384 msgid "Create new club" msgstr "Crear un nuevo club" -#: apps/member/views.py:400 +#: apps/member/views.py:403 msgid "Search club" msgstr "Buscar un club" -#: apps/member/views.py:433 +#: apps/member/views.py:436 msgid "Club detail" msgstr "Detalles del club" -#: apps/member/views.py:540 +#: apps/member/views.py:543 msgid "Update club" msgstr "Modificar el club" -#: apps/member/views.py:574 +#: apps/member/views.py:577 msgid "Add new member to the club" msgstr "Añadir un nuevo miembro al club" -#: apps/member/views.py:703 apps/wei/views.py:973 +#: apps/member/views.py:706 apps/wei/views.py:973 msgid "" "This user don't have enough money to join this club, and can't have a " "negative balance." @@ -1256,19 +1560,19 @@ msgstr "" "Este usuario no tiene suficiente dinero para unirse a este club, y no puede " "tener un saldo negativo." -#: apps/member/views.py:725 +#: apps/member/views.py:728 msgid "The membership must start after {:%m-%d-%Y}." msgstr "La afiliación tiene que empezar después del {:%d-%m-%Y}." -#: apps/member/views.py:730 +#: apps/member/views.py:733 msgid "The membership must begin before {:%m-%d-%Y}." msgstr "La afiliación tiene que empezar antes del {:%d-%m-%Y}." -#: apps/member/views.py:880 +#: apps/member/views.py:883 msgid "Manage roles of an user in the club" msgstr "Gestionar los papeles de un usuario en el club" -#: apps/member/views.py:905 +#: apps/member/views.py:908 msgid "Members of the club" msgstr "Miembros del club" @@ -1731,11 +2035,6 @@ msgstr "Acción" msgid "Amount" msgstr "Monto" -#: apps/note/templates/note/transaction_form.html:132 -#: apps/treasury/models.py:60 -msgid "Name" -msgstr "Nombre" - #: apps/note/templates/note/transaction_form.html:177 msgid "Select emitter" msgstr "Elegir el remitente" @@ -2007,7 +2306,7 @@ msgid "" "with these parameters. Please correct your data and retry." msgstr "" -#: apps/permission/views.py:112 note_kfet/templates/base.html:108 +#: apps/permission/views.py:112 note_kfet/templates/base.html:114 msgid "Rights" msgstr "Permisos" @@ -2019,15 +2318,15 @@ msgstr "Todos los permisos" msgid "registration" msgstr "afiliación" -#: apps/registration/forms.py:40 +#: apps/registration/forms.py:39 msgid "This email address is already used." msgstr "Este correo electrónico ya esta utilizado." -#: apps/registration/forms.py:60 +#: apps/registration/forms.py:59 msgid "Register to the WEI" msgstr "Registrarse en el WEI" -#: apps/registration/forms.py:62 +#: apps/registration/forms.py:61 msgid "" "Check this case if you want to register to the WEI. If you hesitate, you " "will be able to register later, after validating your account in the Kfet." @@ -2035,11 +2334,11 @@ msgstr "" "Marcar esta casilla si usted quiere registrarse en el WEI. Si duda, podrá " "registrarse más tarde, después de validar su cuenta Note Kfet." -#: apps/registration/forms.py:107 +#: apps/registration/forms.py:106 msgid "Join BDE Club" msgstr "Afiliarse al club BDE" -#: apps/registration/forms.py:114 +#: apps/registration/forms.py:113 msgid "Join Kfet Club" msgstr "Afiliarse al club Kfet" @@ -2148,58 +2447,64 @@ msgstr "Gracias" msgid "The Note Kfet team." msgstr "El equipo Note Kfet." -#: apps/registration/views.py:41 +#: apps/registration/views.py:42 msgid "Register new user" msgstr "Registrar un nuevo usuario" -#: apps/registration/views.py:99 +#: apps/registration/views.py:100 msgid "Email validation" msgstr "Validación del correo electrónico" -#: apps/registration/views.py:101 +#: apps/registration/views.py:102 msgid "Validate email" msgstr "Validar el correo electrónico" -#: apps/registration/views.py:145 +#: apps/registration/views.py:146 msgid "Email validation unsuccessful" msgstr "La validación del correo electrónico fracasó" -#: apps/registration/views.py:156 +#: apps/registration/views.py:157 msgid "Email validation email sent" msgstr "Correo de validación enviado" -#: apps/registration/views.py:164 +#: apps/registration/views.py:165 msgid "Resend email validation link" msgstr "Reenviar el enlace de validación" -#: apps/registration/views.py:182 +#: apps/registration/views.py:183 msgid "Pre-registered users list" msgstr "Lista de los usuarios con afiliación pendiente" -#: apps/registration/views.py:206 +#: apps/registration/views.py:207 msgid "Unregistered users" msgstr "Usuarios con afiliación pendiente" -#: apps/registration/views.py:219 +#: apps/registration/views.py:220 msgid "Registration detail" msgstr "Detalles de la afiliación" -#: apps/registration/views.py:293 +#: apps/registration/views.py:256 +#, fuzzy, python-format +#| msgid "Note of %(club)s club" +msgid "Join %(club)s Club" +msgstr "Note del club %(club)s" + +#: apps/registration/views.py:299 msgid "You must join the BDE." msgstr "Usted tiene que afiliarse al BDE." -#: apps/registration/views.py:323 +#: apps/registration/views.py:330 msgid "" "The entered amount is not enough for the memberships, should be at least {}" msgstr "" "El monto dado no es suficiente para las afiliaciones, tiene que ser al menos " "{}" -#: apps/registration/views.py:417 +#: apps/registration/views.py:425 msgid "Invalidate pre-registration" msgstr "Invalidar la afiliación" -#: apps/treasury/apps.py:12 note_kfet/templates/base.html:96 +#: apps/treasury/apps.py:12 note_kfet/templates/base.html:102 msgid "Treasury" msgstr "Tesorería" @@ -2616,7 +2921,7 @@ msgstr "Gestionar los créditos de la Société Générale" #: apps/wei/apps.py:10 apps/wei/models.py:37 apps/wei/models.py:38 #: apps/wei/models.py:62 apps/wei/models.py:178 -#: note_kfet/templates/base.html:102 +#: note_kfet/templates/base.html:108 msgid "WEI" msgstr "WEI" @@ -3230,19 +3535,19 @@ msgstr "Repartir los primer años en los buses" msgid "Attribute bus" msgstr "Repartir en un bus" -#: note_kfet/settings/base.py:172 +#: note_kfet/settings/base.py:173 msgid "German" msgstr "Alemán" -#: note_kfet/settings/base.py:173 +#: note_kfet/settings/base.py:174 msgid "English" msgstr "Ingles" -#: note_kfet/settings/base.py:174 +#: note_kfet/settings/base.py:175 msgid "Spanish" msgstr "Español" -#: note_kfet/settings/base.py:175 +#: note_kfet/settings/base.py:176 msgid "French" msgstr "Francés" @@ -3304,34 +3609,38 @@ msgstr "Reiniciar" msgid "The ENS Paris-Saclay BDE note." msgstr "La note del BDE de la ENS Paris-Saclay." -#: note_kfet/templates/base.html:78 +#: note_kfet/templates/base.html:72 +msgid "Food" +msgstr "" + +#: note_kfet/templates/base.html:84 msgid "Users" msgstr "Usuarios" -#: note_kfet/templates/base.html:84 +#: note_kfet/templates/base.html:90 msgid "Clubs" msgstr "Clubs" -#: note_kfet/templates/base.html:113 +#: note_kfet/templates/base.html:119 msgid "Admin" msgstr "" -#: note_kfet/templates/base.html:127 +#: note_kfet/templates/base.html:133 msgid "My account" msgstr "Mi cuenta" -#: note_kfet/templates/base.html:130 +#: note_kfet/templates/base.html:136 msgid "Log out" msgstr "Desconectarse" -#: note_kfet/templates/base.html:138 +#: note_kfet/templates/base.html:144 #: note_kfet/templates/registration/signup.html:6 #: note_kfet/templates/registration/signup.html:11 #: note_kfet/templates/registration/signup.html:28 msgid "Sign up" msgstr "Registrar" -#: note_kfet/templates/base.html:145 +#: note_kfet/templates/base.html:151 #: note_kfet/templates/registration/login.html:6 #: note_kfet/templates/registration/login.html:15 #: note_kfet/templates/registration/login.html:38 @@ -3339,7 +3648,7 @@ msgstr "Registrar" msgid "Log in" msgstr "Conectarse" -#: note_kfet/templates/base.html:159 +#: note_kfet/templates/base.html:165 msgid "" "You are not a BDE member anymore. Please renew your membership if you want " "to use the note." @@ -3347,7 +3656,7 @@ msgstr "" "Usted ya no está miembro del BDE. Por favor renueva su afiliación si quiere " "usar la note." -#: note_kfet/templates/base.html:165 +#: note_kfet/templates/base.html:171 msgid "" "Your e-mail address is not validated. Please check your mail inbox and click " "on the validation link." @@ -3355,7 +3664,7 @@ msgstr "" "Su correo electrónico no fue validado. Por favor mire en sus correos y haga " "clic en el enlace de validación." -#: note_kfet/templates/base.html:171 +#: note_kfet/templates/base.html:177 msgid "" "You declared that you opened a bank account in the Société générale. The " "bank did not validate the creation of the account to the BDE, so the " @@ -3368,15 +3677,19 @@ msgstr "" "pagados. El proceso de convalidación puede durar unos días. Por favor " "comprueba que fue hasta el final de la creación de la cuenta." -#: note_kfet/templates/base.html:194 +#: note_kfet/templates/base.html:200 msgid "Contact us" msgstr "Contactarnos" -#: note_kfet/templates/base.html:196 +#: note_kfet/templates/base.html:202 msgid "Technical Support" msgstr "Soporte técnico" -#: note_kfet/templates/base.html:198 +#: note_kfet/templates/base.html:204 +msgid "Charte Info (FR)" +msgstr "" + +#: note_kfet/templates/base.html:206 msgid "FAQ (FR)" msgstr "FAQ (FR)" @@ -3601,6 +3914,323 @@ msgstr "" "pagar su afiliación. Tambien tiene que validar su correo electronico con el " "enlace que recibió." +#, fuzzy +#~| msgid "invalidate" +#~ msgid "Enter a valid color." +#~ msgstr "invalidar" + +#, fuzzy +#~| msgid "invalidate" +#~ msgid "Enter a valid value." +#~ msgstr "invalidar" + +#, fuzzy +#~| msgid "Invitation" +#~ msgid "Syndication" +#~ msgstr "Invitación" + +#, fuzzy +#~| msgid "There is no results." +#~ msgid "That page contains no results" +#~ msgstr "No hay resultado." + +#, fuzzy +#~| msgid "invalidate" +#~ msgid "Enter a valid URL." +#~ msgstr "invalidar" + +#, fuzzy +#~| msgid "invalidate" +#~ msgid "Enter a valid integer." +#~ msgstr "invalidar" + +#, fuzzy +#~| msgid "invalidate" +#~ msgid "Enter a valid email address." +#~ msgstr "invalidar" + +#, fuzzy +#~| msgid "This activity is not validated yet." +#~ msgid "Enter a valid IPv4 address." +#~ msgstr "Esta actividad no fue validada por ahora." + +#, fuzzy +#~| msgid "This activity is not validated yet." +#~ msgid "Enter a valid IPv6 address." +#~ msgstr "Esta actividad no fue validada por ahora." + +#, fuzzy +#~| msgid "This activity is not validated yet." +#~ msgid "Enter a valid IPv4 or IPv6 address." +#~ msgstr "Esta actividad no fue validada por ahora." + +#, fuzzy +#~| msgid "phone number" +#~ msgid "Enter a number." +#~ msgstr "número de teléfono" + +#, fuzzy +#~| msgid "add" +#~ msgid "and" +#~ msgstr "añadir" + +#, fuzzy, python-format +#~| msgid "A template with this name already exist" +#~ msgid "%(model_name)s with this %(field_labels)s already exists." +#~ msgstr "Un plantilla de transacción con un nombre similar ya existe" + +#, fuzzy +#~| msgid "This image cannot be loaded." +#~ msgid "This field cannot be null." +#~ msgstr "Esta imagen no puede ser cargada." + +#, fuzzy +#~| msgid "This image cannot be loaded." +#~ msgid "This field cannot be blank." +#~ msgstr "Esta imagen no puede ser cargada." + +#, fuzzy, python-format +#~| msgid "A template with this name already exist" +#~ msgid "%(model_name)s with this %(field_label)s already exists." +#~ msgstr "Un plantilla de transacción con un nombre similar ya existe" + +#, fuzzy +#~| msgid "phone number" +#~ msgid "Decimal number" +#~ msgstr "número de teléfono" + +#, fuzzy +#~| msgid "action" +#~ msgid "Duration" +#~ msgstr "acción" + +#, fuzzy +#~| msgid "address" +#~ msgid "Email address" +#~ msgstr "dirección" + +#, fuzzy +#~| msgid "phone number" +#~ msgid "Floating point number" +#~ msgstr "número de teléfono" + +#, fuzzy +#~| msgid "IP Address" +#~ msgid "IPv4 address" +#~ msgstr "Dirección IP" + +#, fuzzy +#~| msgid "IP Address" +#~ msgid "IP address" +#~ msgstr "Dirección IP" + +#, fuzzy +#~| msgid "Invoice identifier" +#~ msgid "Universally unique identifier" +#~ msgstr "Numero de factura" + +#, fuzzy, python-format +#~| msgid "A template with this name already exist" +#~ msgid "%(model)s instance with %(field)s %(value)r does not exist." +#~ msgstr "Un plantilla de transacción con un nombre similar ya existe" + +#, fuzzy +#~| msgid "phone number" +#~ msgid "Enter a whole number." +#~ msgstr "número de teléfono" + +#, fuzzy +#~| msgid "invalidate" +#~ msgid "Enter a valid date." +#~ msgstr "invalidar" + +#, fuzzy +#~| msgid "invalidate" +#~ msgid "Enter a valid time." +#~ msgstr "invalidar" + +#, fuzzy +#~| msgid "invalidate" +#~ msgid "Enter a valid date/time." +#~ msgstr "invalidar" + +#, fuzzy +#~| msgid "Email validation" +#~ msgid "Enter a valid duration." +#~ msgstr "Validación del correo electrónico" + +#, fuzzy +#~| msgid "invalidate" +#~ msgid "Enter a list of values." +#~ msgstr "invalidar" + +#, fuzzy +#~| msgid "phone number" +#~ msgid "Enter a complete value." +#~ msgstr "número de teléfono" + +#, fuzzy +#~| msgid "invalidate" +#~ msgid "Enter a valid UUID." +#~ msgstr "invalidar" + +#, fuzzy, python-format +#~| msgid "This activity is not validated yet." +#~ msgid "\"%(pk)s\" is not a valid value." +#~ msgstr "Esta actividad no fue validada por ahora." + +#, fuzzy +#~| msgid "Current activity" +#~ msgid "Currently" +#~ msgstr "Actividad actual" + +#, fuzzy +#~| msgid "change" +#~ msgid "Change" +#~ msgstr "cambiar" + +#, fuzzy +#~| msgid "Search WEI" +#~ msgid "March" +#~ msgstr "Buscar un WEI" + +#, fuzzy +#~| msgid "member" +#~ msgid "September" +#~ msgstr "miembro" + +#, fuzzy +#~| msgid "member" +#~ msgid "November" +#~ msgstr "miembro" + +#, fuzzy +#~| msgid "member" +#~ msgid "December" +#~ msgstr "miembro" + +#, fuzzy +#~| msgid "add" +#~ msgid "jan" +#~ msgstr "añadir" + +#, fuzzy +#~| msgid "fee" +#~ msgid "feb" +#~ msgstr "pago" + +#, fuzzy +#~| msgid "product" +#~ msgid "oct" +#~ msgstr "producto" + +#, fuzzy +#~| msgid "Search WEI" +#~ msgctxt "abbrev. month" +#~ msgid "March" +#~ msgstr "Buscar un WEI" + +#, fuzzy +#~| msgid "Search WEI" +#~ msgctxt "alt. month" +#~ msgid "March" +#~ msgstr "Buscar un WEI" + +#, fuzzy +#~| msgid "member" +#~ msgctxt "alt. month" +#~ msgid "September" +#~ msgstr "miembro" + +#, fuzzy +#~| msgid "member" +#~ msgctxt "alt. month" +#~ msgid "November" +#~ msgstr "miembro" + +#, fuzzy +#~| msgid "member" +#~ msgctxt "alt. month" +#~ msgid "December" +#~ msgstr "miembro" + +#, fuzzy +#~| msgid "This activity is not validated yet." +#~ msgid "This is not a valid IPv6 address." +#~ msgstr "Esta actividad no fue validada por ahora." + +#, fuzzy, python-format +#~| msgid "year" +#~ msgid "%d year" +#~ msgid_plural "%d years" +#~ msgstr[0] "año" +#~ msgstr[1] "año" + +#, fuzzy +#~| msgid "No reason specified" +#~ msgid "No year specified" +#~ msgstr "Ningún motivo dado" + +#, fuzzy +#~| msgid "No reason specified" +#~ msgid "No month specified" +#~ msgstr "Ningún motivo dado" + +#, fuzzy +#~| msgid "No reason specified" +#~ msgid "No day specified" +#~ msgstr "Ningún motivo dado" + +#, fuzzy +#~| msgid "No reason specified" +#~ msgid "No week specified" +#~ msgstr "Ningún motivo dado" + +#, fuzzy +#~| msgid "Client secret" +#~ msgid "Confidential" +#~ msgstr "Secreto cliente" + +#, fuzzy +#~| msgid "Authorization:" +#~ msgid "Authorization code" +#~ msgstr "Autorizaciones :" + +#, fuzzy +#~| msgid "Reset my password" +#~ msgid "Resource owner password-based" +#~ msgstr "Reiniciar mi contraseña" + +#, fuzzy +#~| msgid "Client secret" +#~ msgid "Client credentials" +#~ msgstr "Secreto cliente" + +#, fuzzy +#~| msgid "This address must be valid." +#~ msgid "The access token is invalid." +#~ msgstr "Este correo tiene que ser valido." + +#, fuzzy +#~| msgid "This address must be valid." +#~ msgid "The access token has expired." +#~ msgstr "Este correo tiene que ser valido." + +#, fuzzy +#~| msgid "The user does not have enough money." +#~ msgid "The access token is valid but does not have enough scope." +#~ msgstr "El usuario no tiene suficientemente dinero." + +#, fuzzy +#~| msgid "Application requires following permissions:" +#~ msgid "Application requires following permissions" +#~ msgstr "La aplicación necesita los derechos siguientes :" + +#, fuzzy +#~| msgid "WEI registration" +#~ msgid "In preparation" +#~ msgstr "Apuntación al WEI" + #~ msgid "Join BDA Club" #~ msgstr "Afiliarse al club BDA" diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 50f83a93..e3edfeea 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-03-22 00:33+0100\n" +"POT-Creation-Date: 2024-08-17 11:57+0200\n" "PO-Revision-Date: 2022-04-11 22:05+0200\n" "Last-Translator: bleizi \n" "Language-Team: French \n" @@ -28,33 +28,33 @@ msgstr "activité" msgid "The note of this club is inactive." msgstr "La note du club est inactive." -#: apps/activity/forms.py:41 apps/activity/models.py:140 +#: apps/activity/forms.py:41 apps/activity/models.py:142 msgid "The end date must be after the start date." msgstr "La date de fin doit être après celle de début." -#: apps/activity/forms.py:82 apps/activity/models.py:269 +#: apps/activity/forms.py:82 apps/activity/models.py:271 msgid "You can't invite someone once the activity is started." msgstr "" "Vous ne pouvez pas inviter quelqu'un une fois que l'activité a démarré." -#: apps/activity/forms.py:85 apps/activity/models.py:272 +#: apps/activity/forms.py:85 apps/activity/models.py:274 msgid "This activity is not validated yet." msgstr "Cette activité n'est pas encore validée." -#: apps/activity/forms.py:95 apps/activity/models.py:280 +#: apps/activity/forms.py:95 apps/activity/models.py:282 msgid "This person has been already invited 5 times this year." msgstr "Cette personne a déjà été invitée 5 fois cette année." -#: apps/activity/forms.py:99 apps/activity/models.py:284 +#: apps/activity/forms.py:99 apps/activity/models.py:286 msgid "This person is already invited." msgstr "Cette personne est déjà invitée." -#: apps/activity/forms.py:103 apps/activity/models.py:288 +#: apps/activity/forms.py:103 apps/activity/models.py:290 msgid "You can't invite more than 3 people to this activity." msgstr "Vous ne pouvez pas inviter plus de 3 personnes à cette activité." -#: apps/activity/models.py:28 apps/activity/models.py:63 -#: apps/member/models.py:203 +#: apps/activity/models.py:28 apps/activity/models.py:63 apps/food/models.py:42 +#: apps/food/models.py:56 apps/member/models.py:203 #: apps/member/templates/member/includes/club_info.html:4 #: apps/member/templates/member/includes/profile_info.html:4 #: apps/note/models/notes.py:263 apps/note/models/transactions.py:26 @@ -100,121 +100,121 @@ msgstr "types d'activité" msgid "description" msgstr "description" -#: apps/activity/models.py:72 +#: apps/activity/models.py:74 msgid "location" msgstr "lieu" -#: apps/activity/models.py:76 +#: apps/activity/models.py:78 msgid "Place where the activity is organized, eg. Kfet." msgstr "Lieu où l'activité est organisée, par exemple la Kfet." -#: apps/activity/models.py:83 +#: apps/activity/models.py:85 #: apps/activity/templates/activity/includes/activity_info.html:22 #: apps/note/models/notes.py:207 apps/note/models/transactions.py:67 #: apps/permission/models.py:163 msgid "type" msgstr "type" -#: apps/activity/models.py:89 apps/logs/models.py:22 apps/member/models.py:318 +#: apps/activity/models.py:91 apps/logs/models.py:22 apps/member/models.py:318 #: apps/note/models/notes.py:148 apps/treasury/models.py:293 #: apps/wei/models.py:171 apps/wei/templates/wei/attribute_bus_1A.html:13 #: apps/wei/templates/wei/survey.html:15 msgid "user" msgstr "utilisateur⋅rice" -#: apps/activity/models.py:96 +#: apps/activity/models.py:98 #: apps/activity/templates/activity/includes/activity_info.html:36 msgid "organizer" msgstr "organisateur·rice" -#: apps/activity/models.py:97 +#: apps/activity/models.py:99 msgid "Club that organizes the activity. The entry fees will go to this club." msgstr "" "Le club qui organise l'activité. Les coûts d'invitation iront pour ce club." -#: apps/activity/models.py:104 +#: apps/activity/models.py:106 #: apps/activity/templates/activity/includes/activity_info.html:39 msgid "attendees club" msgstr "club attendu" -#: apps/activity/models.py:105 +#: apps/activity/models.py:107 msgid "Club that is authorized to join the activity. Mostly the Kfet club." msgstr "" "Club qui est autorisé à rejoindre l'activité. Très souvent le club Kfet." -#: apps/activity/models.py:109 +#: apps/activity/models.py:111 #: apps/activity/templates/activity/includes/activity_info.html:25 msgid "start date" msgstr "date de début" -#: apps/activity/models.py:113 +#: apps/activity/models.py:115 #: apps/activity/templates/activity/includes/activity_info.html:28 msgid "end date" msgstr "date de fin" -#: apps/activity/models.py:118 +#: apps/activity/models.py:120 #: apps/activity/templates/activity/includes/activity_info.html:50 #: apps/note/models/transactions.py:149 msgid "valid" msgstr "valide" -#: apps/activity/models.py:123 +#: apps/activity/models.py:125 #: apps/activity/templates/activity/includes/activity_info.html:65 msgid "open" msgstr "ouvrir" -#: apps/activity/models.py:128 +#: apps/activity/models.py:130 msgid "activities" msgstr "activités" -#: apps/activity/models.py:172 +#: apps/activity/models.py:174 msgid "entry time" msgstr "heure d'entrée" -#: apps/activity/models.py:178 apps/note/apps.py:14 +#: apps/activity/models.py:180 apps/note/apps.py:14 #: apps/note/models/notes.py:77 msgid "note" msgstr "note" -#: apps/activity/models.py:189 +#: apps/activity/models.py:191 #: apps/activity/templates/activity/activity_entry.html:46 msgid "entry" msgstr "entrée" -#: apps/activity/models.py:190 +#: apps/activity/models.py:192 #: apps/activity/templates/activity/activity_entry.html:46 msgid "entries" msgstr "entrées" -#: apps/activity/models.py:193 +#: apps/activity/models.py:195 #, python-brace-format msgid "Entry for {guest}, invited by {note} to the activity {activity}" msgstr "Entrée pour {guest}, invité·e par {note} à l'activité {activity}" -#: apps/activity/models.py:195 +#: apps/activity/models.py:197 #, python-brace-format msgid "Entry for {note} to the activity {activity}" msgstr "Entrée de la note {note} pour l'activité « {activity} »" -#: apps/activity/models.py:202 +#: apps/activity/models.py:204 msgid "Already entered on " msgstr "Déjà rentré·e le " -#: apps/activity/models.py:202 apps/activity/tables.py:56 +#: apps/activity/models.py:204 apps/activity/tables.py:56 msgid "{:%Y-%m-%d %H:%M:%S}" msgstr "{:%d/%m/%Y %H:%M:%S}" -#: apps/activity/models.py:210 +#: apps/activity/models.py:212 msgid "The balance is negative." msgstr "La note est en négatif." -#: apps/activity/models.py:240 +#: apps/activity/models.py:242 #: apps/treasury/templates/treasury/sogecredit_detail.html:14 #: apps/wei/templates/wei/attribute_bus_1A.html:16 msgid "last name" msgstr "nom de famille" -#: apps/activity/models.py:245 +#: apps/activity/models.py:247 #: apps/member/templates/member/includes/profile_info.html:4 #: apps/registration/templates/registration/future_profile_detail.html:16 #: apps/treasury/templates/treasury/sogecredit_detail.html:17 @@ -223,19 +223,19 @@ msgstr "nom de famille" msgid "first name" msgstr "prénom" -#: apps/activity/models.py:252 +#: apps/activity/models.py:254 msgid "inviter" msgstr "hôte" -#: apps/activity/models.py:256 +#: apps/activity/models.py:258 msgid "guest" msgstr "invité·e" -#: apps/activity/models.py:257 +#: apps/activity/models.py:259 msgid "guests" msgstr "invité·e·s" -#: apps/activity/models.py:310 +#: apps/activity/models.py:312 msgid "Invitation" msgstr "Invitation" @@ -257,8 +257,9 @@ msgstr "Cette activité est actuellement ouverte." msgid "The validation of the activity is pending." msgstr "La validation de cette activité est en attente." -#: apps/activity/tables.py:43 apps/treasury/tables.py:107 +#: apps/activity/tables.py:43 #: apps/member/templates/member/picture_update.html:18 +#: apps/treasury/tables.py:107 msgid "Remove" msgstr "Supprimer" @@ -275,14 +276,14 @@ msgid "Type" msgstr "Type" #: apps/activity/tables.py:84 apps/member/forms.py:196 -#: apps/registration/forms.py:92 apps/treasury/forms.py:131 +#: apps/registration/forms.py:91 apps/treasury/forms.py:131 #: apps/wei/forms/registration.py:104 msgid "Last name" msgstr "Nom de famille" #: apps/activity/tables.py:86 apps/member/forms.py:201 #: apps/note/templates/note/transaction_form.html:138 -#: apps/registration/forms.py:97 apps/treasury/forms.py:133 +#: apps/registration/forms.py:96 apps/treasury/forms.py:133 #: apps/wei/forms/registration.py:109 msgid "First name" msgstr "Prénom" @@ -307,7 +308,7 @@ msgstr "Invité·e supprimé·e" #: apps/note/models/transactions.py:261 #: apps/note/templates/note/transaction_form.html:17 #: apps/note/templates/note/transaction_form.html:152 -#: note_kfet/templates/base.html:72 +#: note_kfet/templates/base.html:78 msgid "Transfer" msgstr "Virement" @@ -336,13 +337,18 @@ msgstr "Retour à la page de l'activité" #: apps/activity/templates/activity/activity_entry.html:129 msgid "Entry done, but caution: the user is not a Kfet member." msgstr "" -"Entrée effectuée, mais attention : la personne n'est pas un·e adhérent·e Kfet." +"Entrée effectuée, mais attention : la personne n'est pas un·e adhérent·e " +"Kfet." #: apps/activity/templates/activity/activity_entry.html:132 msgid "Entry done!" msgstr "Entrée effectuée !" #: apps/activity/templates/activity/activity_form.html:16 +#: apps/food/templates/food/add_ingredient_form.html:16 +#: apps/food/templates/food/basicfood_form.html:16 +#: apps/food/templates/food/create_qrcode_form.html:19 +#: apps/food/templates/food/transformedfood_form.html:16 #: apps/member/templates/member/add_members.html:46 #: apps/member/templates/member/club_form.html:16 #: apps/note/templates/note/transactiontemplate_form.html:18 @@ -408,11 +414,11 @@ msgstr "modifier" msgid "Invite" msgstr "Inviter" -#: apps/activity/views.py:36 +#: apps/activity/views.py:37 msgid "Create new activity" msgstr "Créer une nouvelle activité" -#: apps/activity/views.py:68 note_kfet/templates/base.html:90 +#: apps/activity/views.py:67 note_kfet/templates/base.html:96 msgid "Activities" msgstr "Activités" @@ -450,6 +456,258 @@ msgstr "Entrées pour l'activité « {} »" msgid "API" msgstr "API" +#: apps/food/apps.py:11 apps/food/models.py:105 +msgid "food" +msgstr "bouffe" + +#: apps/food/forms.py:32 +msgid "Fully used" +msgstr "Entièrement utilisé" + +#: apps/food/forms.py:50 +msgid "Pasta METRO 5kg" +msgstr "Pâtes METRO 5kg" + +#: apps/food/forms.py:96 +msgid "Lasagna" +msgstr "Lasagnes" + +#: apps/food/models.py:18 +msgid "QR-code number" +msgstr "numéro de QR-code" + +#: apps/food/models.py:26 +msgid "food container" +msgstr "récipient" + +#: apps/food/models.py:30 +msgid "QR-code" +msgstr "QR-code" + +#: apps/food/models.py:31 +msgid "QR-codes" +msgstr "QR-codes" + +#: apps/food/models.py:34 +#, python-brace-format +msgid "QR-code number {qr_code_number}" +msgstr "numéro du QR-code {qr_code_number}" + +#: apps/food/models.py:47 +msgid "Allergen" +msgstr "Allergène" + +#: apps/food/models.py:48 apps/food/templates/food/basicfood_detail.html:17 +#: apps/food/templates/food/transformedfood_detail.html:20 +msgid "Allergens" +msgstr "Allergènes" + +#: apps/food/models.py:64 +msgid "owner" +msgstr "propriétaire" + +#: apps/food/models.py:70 +msgid "allergen" +msgstr "allergène" + +#: apps/food/models.py:74 +msgid "expiry date" +msgstr "date de péremption" + +#: apps/food/models.py:80 +msgid "was eaten" +msgstr "a été mangé" + +#: apps/food/models.py:89 +msgid "is ready" +msgstr "est prêt" + +#: apps/food/models.py:94 +msgid "is active" +msgstr "est en cours" + +#: apps/food/models.py:106 +msgid "foods" +msgstr "bouffes" + +#: apps/food/models.py:122 +msgid "arrival date" +msgstr "date d'arrivée" + +#: apps/food/models.py:152 +msgid "Basic food" +msgstr "Aliment basique" + +#: apps/food/models.py:153 +msgid "Basic foods" +msgstr "Aliments basiques" + +#: apps/food/models.py:161 +msgid "creation date" +msgstr "date de création" + +#: apps/food/models.py:169 +msgid "transformed ingredient" +msgstr "ingrédients tranformées" + +#: apps/food/models.py:174 +msgid "shelf life" +msgstr "durée de vie" + +#: apps/food/models.py:225 apps/food/views.py:365 +msgid "Transformed food" +msgstr "Aliment transformé" + +#: apps/food/models.py:226 +msgid "Transformed foods" +msgstr "Aliments transformés" + +#: apps/food/templates/food/create_qrcode_form.html:31 +#: apps/food/templates/food/basicfood_detail.html:14 +#: apps/food/templates/food/qrcode_detail.html:15 +#: apps/food/templates/food/transformedfood_detail.html:14 +msgid "Owner" +msgstr "Propriétaire" + +#: apps/food/templates/food/create_qrcode_form.html:34 +#: apps/food/templates/food/basicfood_detail.html:15 +msgid "Arrival date" +msgstr "Date d'arrivée" + +#: apps/food/templates/food/create_qrcode_form.html:37 +#: apps/food/templates/food/basicfood_detail.html:16 +#: apps/food/templates/food/qrcode_detail.html:16 +#: apps/food/templates/food/transformedfood_detail.html:19 +msgid "Expiry date" +msgstr "Date de péremption" + +#: apps/food/templates/food/basicfood_detail.html:24 +#: apps/food/templates/food/transformedfood_detail.html:36 +msgid "Active" +msgstr "Actif" + +#: apps/food/templates/food/basicfood_detail.html:25 +#: apps/food/templates/food/transformedfood_detail.html:37 +msgid "Eaten" +msgstr "Mangé" + +#: apps/food/templates/food/basicfood_detail.html:28 +#: apps/food/templates/food/qrcode_detail.html:20 +#: apps/food/templates/food/qrcode_detail.html:24 +#: apps/food/templates/food/transformedfood_detail.html:41 +msgid "Update" +msgstr "Modifier" + +#: apps/food/templates/food/basicfood_detail.html:32 +#: apps/food/templates/food/qrcode_detail.html:34 +#: apps/food/templates/food/transformedfood_detail.html:46 +msgid "Add to a meal" +msgstr "Ajouter à un plat" + +#: apps/food/templates/food/create_qrcode_form.html:14 +msgid "New basic food" +msgstr "Nouvel aliment basique" + +#: apps/food/templates/food/create_qrcode_form.html:23 +msgid "Copy constructor" +msgstr "Constructeur de copie" + +#: apps/food/templates/food/qrcode_detail.html:10 +msgid "number" +msgstr "numéro" + +#: apps/food/templates/food/create_qrcode_form.html:28 +#: apps/food/templates/food/qrcode_detail.html:14 +#: apps/note/templates/note/transaction_form.html:132 +#: apps/treasury/models.py:60 +msgid "Name" +msgstr "Nom" + +#: apps/food/templates/food/qrcode_detail.html:29 +msgid "View details" +msgstr "Voir plus" + +#: apps/food/templates/food/transformedfood_detail.html:16 +#: apps/food/templates/food/transformedfood_detail.html:35 +msgid "Ready" +msgstr "Prêt" + +#: apps/food/templates/food/transformedfood_detail.html:18 +msgid "Creation date" +msgstr "Date de création" + +#: apps/food/templates/food/transformedfood_detail.html:27 +msgid "Ingredients" +msgstr "Ingrédients" + +#: apps/food/templates/food/transformedfood_detail.html:34 +msgid "Shelf life" +msgstr "Durée de vie" + +#: apps/food/templates/food/transformedfood_list.html:11 +msgid "Meal served" +msgstr "Plat servis" + +#: apps/food/templates/food/transformedfood_list.html:16 +msgid "New meal" +msgstr "Nouveau plat" + +#: apps/food/templates/food/transformedfood_list.html:25 +msgid "There is no meal served." +msgstr "Il n'y a pas de plat servi." + +#: apps/food/templates/food/transformedfood_list.html:33 +msgid "Open" +msgstr "Open" + +#: apps/food/templates/food/transformedfood_list.html:40 +msgid "There is no free meal." +msgstr "Il n'y a pas de plat en open" + +#: apps/food/templates/food/transformedfood_list.html:48 +msgid "All meals" +msgstr "Tout les plats" + +#: apps/food/templates/food/transformedfood_list.html:55 +msgid "There is no meal." +msgstr "Il n'y a pas de plat" + +#: apps/food/views.py:28 +msgid "Add the ingredient" +msgstr "Ajouter un ingrédient" + +#: apps/food/views.py:42 +msgid "The product is already prepared" +msgstr "Le produit est déjà prêt" + +#: apps/food/views.py:70 +msgid "Update an aliment" +msgstr "Modifier un aliment" + +#: apps/food/views.py:97 +msgid "Details of:" +msgstr "Détails de:" + +#: apps/food/views.py:121 +msgid "Add a new basic food with QRCode" +msgstr "Ajouter un nouvel ingrédient avec un QR-code" + +#: apps/food/views.py:185 +msgid "Add a new QRCode" +msgstr "Ajouter un nouveau QR-code" + +#: apps/food/views.py:235 +msgid "QRCode" +msgstr "QR-code" + +#: apps/food/views.py:271 +msgid "Add a new meal" +msgstr "Ajouter un nouveau plat" + +#: apps/food/views.py:337 +msgid "Update a meal" +msgstr "Modifier le plat" + #: apps/logs/apps.py:11 msgid "Logs" msgstr "Logs" @@ -574,8 +832,8 @@ msgstr "Taille maximale : 2 Mo" msgid "This image cannot be loaded." msgstr "Cette image ne peut pas être chargée." -#: apps/member/forms.py:148 apps/member/views.py:102 -#: apps/registration/forms.py:34 apps/registration/views.py:276 +#: apps/member/forms.py:151 apps/member/views.py:102 +#: apps/registration/forms.py:33 apps/registration/views.py:276 msgid "An alias with a similar name already exists." msgstr "Un alias avec un nom similaire existe déjà." @@ -587,12 +845,12 @@ msgstr "Inscription payée par la Société générale" msgid "Check this case if the Société Générale paid the inscription." msgstr "Cochez cette case si la Société Générale a payé l'inscription." -#: apps/member/forms.py:182 apps/registration/forms.py:79 +#: apps/member/forms.py:182 apps/registration/forms.py:78 #: apps/wei/forms/registration.py:91 msgid "Credit type" msgstr "Type de rechargement" -#: apps/member/forms.py:183 apps/registration/forms.py:80 +#: apps/member/forms.py:183 apps/registration/forms.py:79 #: apps/wei/forms/registration.py:92 msgid "No credit" msgstr "Pas de rechargement" @@ -601,13 +859,13 @@ msgstr "Pas de rechargement" msgid "You can credit the note of the user." msgstr "Vous pouvez créditer la note de l'utilisateur⋅rice avant l'adhésion." -#: apps/member/forms.py:186 apps/registration/forms.py:85 +#: apps/member/forms.py:189 apps/registration/forms.py:84 #: apps/wei/forms/registration.py:97 msgid "Credit amount" msgstr "Montant à créditer" #: apps/member/forms.py:206 apps/note/templates/note/transaction_form.html:144 -#: apps/registration/forms.py:102 apps/treasury/forms.py:135 +#: apps/registration/forms.py:101 apps/treasury/forms.py:135 #: apps/wei/forms/registration.py:114 msgid "Bank" msgstr "Banque" @@ -766,8 +1024,8 @@ msgid "" "Register on the mailing list to stay informed of the events of the campus (1 " "mail/week)" msgstr "" -"S'inscrire sur la liste de diffusion pour rester informé·e des événements sur " -"le campus (1 mail par semaine)" +"S'inscrire sur la liste de diffusion pour rester informé·e des événements " +"sur le campus (1 mail par semaine)" #: apps/member/models.py:108 msgid "" @@ -860,8 +1118,8 @@ msgstr "fin de l'adhésion" #: apps/member/models.py:259 msgid "Maximal date of a membership, after which members must renew it." msgstr "" -"Date maximale d'une fin d'adhésion, après laquelle les adhérent·e·s doivent la " -"renouveler." +"Date maximale d'une fin d'adhésion, après laquelle les adhérent·e·s doivent " +"la renouveler." #: apps/member/models.py:263 msgid "add to registration form" @@ -902,11 +1160,11 @@ msgstr "Adhésion de {user} pour le club {club}" msgid "The role {role} does not apply to the club {club}." msgstr "Le rôle {role} ne s'applique pas au club {club}." -#: apps/member/models.py:381 apps/member/views.py:712 +#: apps/member/models.py:381 apps/member/views.py:715 msgid "User is already a member of the club" msgstr "L'utilisateur·rice est déjà membre du club" -#: apps/member/models.py:393 apps/member/views.py:721 +#: apps/member/models.py:393 apps/member/views.py:724 msgid "User is not a member of the parent club" msgstr "L'utilisateur·rice n'est pas membre du club parent" @@ -1020,7 +1278,7 @@ msgstr "" #: apps/member/templates/member/club_alias.html:10 #: apps/member/templates/member/profile_alias.html:10 apps/member/views.py:287 -#: apps/member/views.py:517 +#: apps/member/views.py:520 msgid "Note aliases" msgstr "Alias de la note" @@ -1221,7 +1479,7 @@ msgstr "Sauvegarder les changements" msgid "Registrations" msgstr "Inscriptions" -#: apps/member/views.py:72 apps/registration/forms.py:24 +#: apps/member/views.py:72 apps/registration/forms.py:23 msgid "This address must be valid." msgstr "Cette adresse doit être valide." @@ -1241,31 +1499,31 @@ msgstr "Amitiés note" msgid "Update note picture" msgstr "Modifier la photo de la note" -#: apps/member/views.py:354 +#: apps/member/views.py:357 msgid "Manage auth token" msgstr "Gérer les jetons d'authentification" -#: apps/member/views.py:381 +#: apps/member/views.py:384 msgid "Create new club" msgstr "Créer un nouveau club" -#: apps/member/views.py:400 +#: apps/member/views.py:403 msgid "Search club" msgstr "Chercher un club" -#: apps/member/views.py:433 +#: apps/member/views.py:436 msgid "Club detail" msgstr "Détails du club" -#: apps/member/views.py:540 +#: apps/member/views.py:543 msgid "Update club" msgstr "Modifier le club" -#: apps/member/views.py:574 +#: apps/member/views.py:577 msgid "Add new member to the club" msgstr "Ajouter un·e nouvelleau membre au club" -#: apps/member/views.py:703 apps/wei/views.py:973 +#: apps/member/views.py:706 apps/wei/views.py:973 msgid "" "This user don't have enough money to join this club, and can't have a " "negative balance." @@ -1273,19 +1531,19 @@ msgstr "" "Cet⋅te utilisateur⋅rice n'a pas assez d'argent pour rejoindre ce club et ne " "peut pas avoir un solde négatif." -#: apps/member/views.py:725 +#: apps/member/views.py:728 msgid "The membership must start after {:%m-%d-%Y}." msgstr "L'adhésion doit commencer après le {:%d/%m/%Y}." -#: apps/member/views.py:730 +#: apps/member/views.py:733 msgid "The membership must begin before {:%m-%d-%Y}." msgstr "L'adhésion doit commencer avant le {:%d/%m/%Y}." -#: apps/member/views.py:880 +#: apps/member/views.py:883 msgid "Manage roles of an user in the club" msgstr "Gérer les rôles d'un⋅e utilisateur⋅rice dans le club" -#: apps/member/views.py:905 +#: apps/member/views.py:908 msgid "Members of the club" msgstr "Membres du club" @@ -1397,6 +1655,7 @@ msgstr "" "La note est bloquée de force par le BDE et ne peut pas être débloquée par læ " "propriétaire de la note." + #: apps/note/models/notes.py:78 msgid "notes" msgstr "notes" @@ -1743,11 +2002,6 @@ msgstr "Action" msgid "Amount" msgstr "Montant" -#: apps/note/templates/note/transaction_form.html:132 -#: apps/treasury/models.py:60 -msgid "Name" -msgstr "Nom" - #: apps/note/templates/note/transaction_form.html:177 msgid "Select emitter" msgstr "Sélection de l'émetteur⋅rice" @@ -2022,7 +2276,7 @@ msgstr "" "Vous n'avez pas la permission d'ajouter une instance du modèle « {model} » " "avec ces paramètres. Merci de les corriger et de réessayer." -#: apps/permission/views.py:112 note_kfet/templates/base.html:108 +#: apps/permission/views.py:112 note_kfet/templates/base.html:114 msgid "Rights" msgstr "Droits" @@ -2034,15 +2288,15 @@ msgstr "Tous les droits" msgid "registration" msgstr "inscription" -#: apps/registration/forms.py:40 +#: apps/registration/forms.py:39 msgid "This email address is already used." msgstr "Cette adresse e-mail est déjà prise." -#: apps/registration/forms.py:60 +#: apps/registration/forms.py:59 msgid "Register to the WEI" msgstr "S'inscrire au WEI" -#: apps/registration/forms.py:62 +#: apps/registration/forms.py:61 msgid "" "Check this case if you want to register to the WEI. If you hesitate, you " "will be able to register later, after validating your account in the Kfet." @@ -2051,11 +2305,11 @@ msgstr "" "pourrez toujours vous inscrire plus tard, après avoir validé votre compte à " "la Kfet." -#: apps/registration/forms.py:107 +#: apps/registration/forms.py:106 msgid "Join BDE Club" msgstr "Adhérer au club BDE" -#: apps/registration/forms.py:114 +#: apps/registration/forms.py:113 msgid "Join Kfet Club" msgstr "Adhérer au club Kfet" @@ -2162,39 +2416,39 @@ msgstr "Merci" msgid "The Note Kfet team." msgstr "L'équipe de la Note Kfet." -#: apps/registration/views.py:41 +#: apps/registration/views.py:42 msgid "Register new user" msgstr "Enregistrer un⋅e nouvel⋅le utilisateur⋅rice" -#: apps/registration/views.py:99 +#: apps/registration/views.py:100 msgid "Email validation" msgstr "Validation de l'adresse e-mail" -#: apps/registration/views.py:101 +#: apps/registration/views.py:102 msgid "Validate email" msgstr "Valider l'adresse e-mail" -#: apps/registration/views.py:145 +#: apps/registration/views.py:146 msgid "Email validation unsuccessful" msgstr "La validation de l'adresse e-mail a échoué" -#: apps/registration/views.py:156 +#: apps/registration/views.py:157 msgid "Email validation email sent" msgstr "L'e-mail de vérification de l'adresse e-mail a bien été envoyé" -#: apps/registration/views.py:164 +#: apps/registration/views.py:165 msgid "Resend email validation link" msgstr "Renvoyer le lien de validation" -#: apps/registration/views.py:182 +#: apps/registration/views.py:183 msgid "Pre-registered users list" msgstr "Liste des utilisateur⋅rices en attente d'inscription" -#: apps/registration/views.py:206 +#: apps/registration/views.py:207 msgid "Unregistered users" msgstr "Utilisateur·rices en attente d'inscription" -#: apps/registration/views.py:219 +#: apps/registration/views.py:220 msgid "Registration detail" msgstr "Détails de l'inscription" @@ -2218,7 +2472,7 @@ msgstr "" msgid "Invalidate pre-registration" msgstr "Invalider l'inscription" -#: apps/treasury/apps.py:12 note_kfet/templates/base.html:96 +#: apps/treasury/apps.py:12 note_kfet/templates/base.html:102 msgid "Treasury" msgstr "Trésorerie" @@ -2544,7 +2798,8 @@ msgstr "" #: apps/treasury/templates/treasury/sogecredit_detail.html:44 msgid "If you think there is an error, please contact the \"respos info\"." -msgstr "Si vous pensez qu'il y a une erreur, merci de contacter un·e respo info." +msgstr "" +"Si vous pensez qu'il y a une erreur, merci de contacter un·e respo info." #: apps/treasury/templates/treasury/sogecredit_detail.html:50 msgid "This credit is already validated." @@ -2634,7 +2889,7 @@ msgstr "Gérer les crédits de la Société générale" #: apps/wei/apps.py:10 apps/wei/models.py:37 apps/wei/models.py:38 #: apps/wei/models.py:62 apps/wei/models.py:178 -#: note_kfet/templates/base.html:102 +#: note_kfet/templates/base.html:108 msgid "WEI" msgstr "WEI" @@ -3254,19 +3509,19 @@ msgstr "Répartir les 1A dans les bus" msgid "Attribute bus" msgstr "Attribuer un bus" -#: note_kfet/settings/base.py:172 +#: note_kfet/settings/base.py:173 msgid "German" msgstr "Allemand" -#: note_kfet/settings/base.py:173 +#: note_kfet/settings/base.py:174 msgid "English" msgstr "Anglais" -#: note_kfet/settings/base.py:174 +#: note_kfet/settings/base.py:175 msgid "Spanish" msgstr "Espagnol" -#: note_kfet/settings/base.py:175 +#: note_kfet/settings/base.py:176 msgid "French" msgstr "Français" @@ -3331,34 +3586,38 @@ msgstr "Réinitialiser" msgid "The ENS Paris-Saclay BDE note." msgstr "La note du BDE de l'ENS Paris-Saclay." -#: note_kfet/templates/base.html:78 +#: note_kfet/templates/base.html:72 +msgid "Food" +msgstr "Bouffe" + +#: note_kfet/templates/base.html:84 msgid "Users" msgstr "Utilisateur·rices" -#: note_kfet/templates/base.html:84 +#: note_kfet/templates/base.html:90 msgid "Clubs" msgstr "Clubs" -#: note_kfet/templates/base.html:113 +#: note_kfet/templates/base.html:119 msgid "Admin" msgstr "Admin" -#: note_kfet/templates/base.html:127 +#: note_kfet/templates/base.html:133 msgid "My account" msgstr "Mon compte" -#: note_kfet/templates/base.html:130 +#: note_kfet/templates/base.html:136 msgid "Log out" msgstr "Se déconnecter" -#: note_kfet/templates/base.html:138 +#: note_kfet/templates/base.html:144 #: note_kfet/templates/registration/signup.html:6 #: note_kfet/templates/registration/signup.html:11 #: note_kfet/templates/registration/signup.html:28 msgid "Sign up" msgstr "Inscription" -#: note_kfet/templates/base.html:145 +#: note_kfet/templates/base.html:151 #: note_kfet/templates/registration/login.html:6 #: note_kfet/templates/registration/login.html:15 #: note_kfet/templates/registration/login.html:38 @@ -3366,15 +3625,15 @@ msgstr "Inscription" msgid "Log in" msgstr "Se connecter" -#: note_kfet/templates/base.html:159 +#: note_kfet/templates/base.html:165 msgid "" "You are not a BDE member anymore. Please renew your membership if you want " "to use the note." msgstr "" -"Vous n'êtes plus adhérent·e BDE. Merci de réadhérer si vous voulez profiter de " -"la note." +"Vous n'êtes plus adhérent·e BDE. Merci de réadhérer si vous voulez profiter " +"de la note." -#: note_kfet/templates/base.html:165 +#: note_kfet/templates/base.html:171 msgid "" "Your e-mail address is not validated. Please check your mail inbox and click " "on the validation link." @@ -3382,7 +3641,7 @@ msgstr "" "Votre adresse e-mail n'est pas validée. Merci de vérifier votre boîte mail " "et de cliquer sur le lien de validation." -#: note_kfet/templates/base.html:171 +#: note_kfet/templates/base.html:177 msgid "" "You declared that you opened a bank account in the Société générale. The " "bank did not validate the creation of the account to the BDE, so the " @@ -3396,22 +3655,22 @@ msgstr "" "vérification peut durer quelques jours. Merci de vous assurer de bien aller " "au bout de vos démarches." -#: note_kfet/templates/base.html:194 +#: note_kfet/templates/base.html:200 msgid "Contact us" msgstr "Nous contacter" -#: note_kfet/templates/base.html:196 +#: note_kfet/templates/base.html:202 msgid "Technical Support" msgstr "Support technique" -#: note_kfet/templates/base.html:198 -msgid "FAQ (FR)" -msgstr "FAQ (FR)" - -#: note_kfet/templates/base.html:200 +#: note_kfet/templates/base.html:204 msgid "Charte Info (FR)" msgstr "Charte Info (FR)" +#: note_kfet/templates/base.html:206 +msgid "FAQ (FR)" +msgstr "FAQ (FR)" + #: note_kfet/templates/base_search.html:15 msgid "Search by attribute such as name…" msgstr "Chercher par un attribut tel que le nom…" @@ -3640,6 +3899,335 @@ msgstr "" "d'adhésion. Vous devez également valider votre adresse email en suivant le " "lien que vous avez reçu." +#, fuzzy +#~| msgid "invalidate" +#~ msgid "Enter a valid color." +#~ msgstr "dévalider" + +#, fuzzy +#~| msgid "invalidate" +#~ msgid "Enter a valid value." +#~ msgstr "dévalider" + +#, fuzzy +#~| msgid "Invitation" +#~ msgid "Syndication" +#~ msgstr "Invitation" + +#, fuzzy +#~| msgid "There is no results." +#~ msgid "That page contains no results" +#~ msgstr "Il n'y a pas de résultat." + +#, fuzzy +#~| msgid "invalidate" +#~ msgid "Enter a valid URL." +#~ msgstr "dévalider" + +#, fuzzy +#~| msgid "invalidate" +#~ msgid "Enter a valid integer." +#~ msgstr "dévalider" + +#, fuzzy +#~| msgid "invalidate" +#~ msgid "Enter a valid email address." +#~ msgstr "dévalider" + +#, fuzzy +#~| msgid "This activity is not validated yet." +#~ msgid "Enter a valid IPv4 address." +#~ msgstr "Cette activité n'est pas encore validée." + +#, fuzzy +#~| msgid "This activity is not validated yet." +#~ msgid "Enter a valid IPv6 address." +#~ msgstr "Cette activité n'est pas encore validée." + +#, fuzzy +#~| msgid "This activity is not validated yet." +#~ msgid "Enter a valid IPv4 or IPv6 address." +#~ msgstr "Cette activité n'est pas encore validée." + +#, fuzzy +#~| msgid "phone number" +#~ msgid "Enter a number." +#~ msgstr "numéro de téléphone" + +#, fuzzy +#~| msgid "add" +#~ msgid "and" +#~ msgstr "ajouter" + +#, fuzzy, python-format +#~| msgid "A template with this name already exist" +#~ msgid "%(model_name)s with this %(field_labels)s already exists." +#~ msgstr "Un modèle de transaction avec un nom similaire existe déjà" + +#, fuzzy +#~| msgid "This image cannot be loaded." +#~ msgid "This field cannot be null." +#~ msgstr "Cette image ne peut pas être chargée." + +#, fuzzy +#~| msgid "This image cannot be loaded." +#~ msgid "This field cannot be blank." +#~ msgstr "Cette image ne peut pas être chargée." + +#, fuzzy, python-format +#~| msgid "A template with this name already exist" +#~ msgid "%(model_name)s with this %(field_label)s already exists." +#~ msgstr "Un modèle de transaction avec un nom similaire existe déjà" + +#, fuzzy +#~| msgid "phone number" +#~ msgid "Decimal number" +#~ msgstr "numéro de téléphone" + +#, fuzzy +#~| msgid "action" +#~ msgid "Duration" +#~ msgstr "action" + +#, fuzzy +#~| msgid "address" +#~ msgid "Email address" +#~ msgstr "adresse" + +#, fuzzy +#~| msgid "phone number" +#~ msgid "Floating point number" +#~ msgstr "numéro de téléphone" + +#, fuzzy +#~| msgid "IP Address" +#~ msgid "IPv4 address" +#~ msgstr "Adresse IP" + +#, fuzzy +#~| msgid "IP Address" +#~ msgid "IP address" +#~ msgstr "Adresse IP" + +#, fuzzy +#~| msgid "Invoice identifier" +#~ msgid "Universally unique identifier" +#~ msgstr "Numéro de facture" + +#, fuzzy, python-format +#~| msgid "A template with this name already exist" +#~ msgid "%(model)s instance with %(field)s %(value)r does not exist." +#~ msgstr "Un modèle de transaction avec un nom similaire existe déjà" + +#, fuzzy +#~| msgid "phone number" +#~ msgid "Enter a whole number." +#~ msgstr "numéro de téléphone" + +#, fuzzy +#~| msgid "invalidate" +#~ msgid "Enter a valid date." +#~ msgstr "dévalider" + +#, fuzzy +#~| msgid "invalidate" +#~ msgid "Enter a valid time." +#~ msgstr "dévalider" + +#, fuzzy +#~| msgid "invalidate" +#~ msgid "Enter a valid date/time." +#~ msgstr "dévalider" + +#, fuzzy +#~| msgid "Email validation" +#~ msgid "Enter a valid duration." +#~ msgstr "Validation de l'adresse mail" + +#, fuzzy +#~| msgid "invalidate" +#~ msgid "Enter a list of values." +#~ msgstr "dévalider" + +#, fuzzy +#~| msgid "phone number" +#~ msgid "Enter a complete value." +#~ msgstr "numéro de téléphone" + +#, fuzzy +#~| msgid "invalidate" +#~ msgid "Enter a valid UUID." +#~ msgstr "dévalider" + +#, fuzzy, python-format +#~| msgid "This activity is not validated yet." +#~ msgid "\"%(pk)s\" is not a valid value." +#~ msgstr "Cette activité n'est pas encore validée." + +#, fuzzy +#~| msgid "Current activity" +#~ msgid "Currently" +#~ msgstr "Activité en cours" + +#, fuzzy +#~| msgid "change" +#~ msgid "Change" +#~ msgstr "modifier" + +#, fuzzy +#~| msgid "Search" +#~ msgid "March" +#~ msgstr "Recherche" + +#, fuzzy +#~| msgid "member" +#~ msgid "September" +#~ msgstr "adhérent·e" + +#, fuzzy +#~| msgid "member" +#~ msgid "November" +#~ msgstr "adhérent·e" + +#, fuzzy +#~| msgid "member" +#~ msgid "December" +#~ msgstr "adhérent·e" + +#, fuzzy +#~| msgid "add" +#~ msgid "jan" +#~ msgstr "ajouter" + +#, fuzzy +#~| msgid "fee" +#~ msgid "feb" +#~ msgstr "cotisation" + +#, fuzzy +#~| msgid "product" +#~ msgid "oct" +#~ msgstr "produit" + +#, fuzzy +#~| msgid "Search" +#~ msgctxt "abbrev. month" +#~ msgid "March" +#~ msgstr "Recherche" + +#, fuzzy +#~| msgid "Search" +#~ msgctxt "alt. month" +#~ msgid "March" +#~ msgstr "Recherche" + +#, fuzzy +#~| msgid "member" +#~ msgctxt "alt. month" +#~ msgid "September" +#~ msgstr "adhérent·e" + +#, fuzzy +#~| msgid "member" +#~ msgctxt "alt. month" +#~ msgid "November" +#~ msgstr "adhérent·e" + +#, fuzzy +#~| msgid "member" +#~ msgctxt "alt. month" +#~ msgid "December" +#~ msgstr "adhérent·e" + +#, fuzzy +#~| msgid "This activity is not validated yet." +#~ msgid "This is not a valid IPv6 address." +#~ msgstr "Cette activité n'est pas encore validée." + +#, fuzzy, python-format +#~| msgid "year" +#~ msgid "%d year" +#~ msgid_plural "%d years" +#~ msgstr[0] "année" +#~ msgstr[1] "année" + +#, fuzzy +#~| msgid "No reason specified" +#~ msgid "No year specified" +#~ msgstr "Pas de motif spécifié" + +#, fuzzy +#~| msgid "No reason specified" +#~ msgid "No month specified" +#~ msgstr "Pas de motif spécifié" + +#, fuzzy +#~| msgid "No reason specified" +#~ msgid "No day specified" +#~ msgstr "Pas de motif spécifié" + +#, fuzzy +#~| msgid "No reason specified" +#~ msgid "No week specified" +#~ msgstr "Pas de motif spécifié" + +#, fuzzy +#~| msgid "Client secret" +#~ msgid "Confidential" +#~ msgstr "Secret client" + +#, fuzzy +#~| msgid "Authorization:" +#~ msgid "Authorization code" +#~ msgstr "Autorisation :" + +#, fuzzy +#~| msgid "Reset my password" +#~ msgid "Resource owner password-based" +#~ msgstr "Réinitialiser mon mot de passe" + +#, fuzzy +#~| msgid "Client secret" +#~ msgid "Client credentials" +#~ msgstr "Secret client" + +#, fuzzy +#~| msgid "This address must be valid." +#~ msgid "The access token is invalid." +#~ msgstr "Cette adresse doit être valide." + +#, fuzzy +#~| msgid "This address must be valid." +#~ msgid "The access token has expired." +#~ msgstr "Cette adresse doit être valide." + +#, fuzzy +#~| msgid "The user does not have enough money." +#~ msgid "The access token is valid but does not have enough scope." +#~ msgstr "L'utilisateur·ice n'a pas assez d'argent." + +#, fuzzy +#~| msgid "Application requires following permissions:" +#~ msgid "Application requires following permissions" +#~ msgstr "L'application requiert les permissions suivantes :" + +#~ msgid "pasta" +#~ msgstr "pâtes" + +#~ msgid "In preparation" +#~ msgstr "En cours de préparation" + +#~ msgid "Free" +#~ msgstr "Open" + +#~ msgid "Add a new aliment" +#~ msgstr "Ajouter un nouvel aliment" + +#, fuzzy +#~| msgid "Transformed food" +#~ msgid "New transformed food" +#~ msgstr "Bouffe transformée" + #, fuzzy #~| msgid "People having you as a friend" #~ msgid "You already have that person as a friend" diff --git a/note_kfet/settings/base.py b/note_kfet/settings/base.py index 168f34bd..9c5a9458 100644 --- a/note_kfet/settings/base.py +++ b/note_kfet/settings/base.py @@ -70,6 +70,7 @@ INSTALLED_APPS = [ # Note apps 'api', 'activity', + 'food', 'logs', 'member', 'note', diff --git a/note_kfet/templates/base.html b/note_kfet/templates/base.html index 63d0ddfe..9f5ae867 100644 --- a/note_kfet/templates/base.html +++ b/note_kfet/templates/base.html @@ -66,10 +66,16 @@ SPDX-License-Identifier: GPL-3.0-or-later {% trans 'Consumptions' %} {% endif %} + {% if request.user.is_authenticated %} + + {% endif %} {% if user.is_authenticated and user|is_member:"Kfet" %} {% endif %} {% if "auth.user"|model_list_length >= 2 %} diff --git a/note_kfet/urls.py b/note_kfet/urls.py index 9008a16d..b2b64dcf 100644 --- a/note_kfet/urls.py +++ b/note_kfet/urls.py @@ -21,6 +21,7 @@ urlpatterns = [ path('activity/', include('activity.urls')), path('treasury/', include('treasury.urls')), path('wei/', include('wei.urls')), + path('food/',include('food.urls')), # Include Django Contrib and Core routers path('i18n/', include('django.conf.urls.i18n')),