diff --git a/apps/activity/models.py b/apps/activity/models.py index 9d3431be..fe2cfb20 100644 --- a/apps/activity/models.py +++ b/apps/activity/models.py @@ -188,6 +188,12 @@ class Entry(models.Model): verbose_name = _("entry") verbose_name_plural = _("entries") + def __str__(self): + return _("Entry for {guest}, invited by {note} to the activity {activity}").format( + guest=str(self.guest), note=str(self.note), activity=str(self.activity)) if self.guest \ + else _("Entry for {note} to the activity {activity}").format( + guest=str(self.guest), note=str(self.note), activity=str(self.activity)) + def save(self, *args, **kwargs): qs = Entry.objects.filter(~Q(pk=self.pk), activity=self.activity, note=self.note, guest=self.guest) diff --git a/apps/logs/migrations/0002_replace_null_by_blank.py b/apps/logs/migrations/0002_replace_null_by_blank.py new file mode 100644 index 00000000..65fc4b14 --- /dev/null +++ b/apps/logs/migrations/0002_replace_null_by_blank.py @@ -0,0 +1,17 @@ +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('logs', '0001_initial'), + ] + + operations = [ + migrations.RunSQL( + "UPDATE logs_changelog SET previous = '' WHERE previous IS NULL;" + ), + migrations.RunSQL( + "UPDATE logs_changelog SET data = '' WHERE data IS NULL;" + ), + ] diff --git a/apps/logs/migrations/0003_remove_null_tag_on_charfields.py b/apps/logs/migrations/0003_remove_null_tag_on_charfields.py new file mode 100644 index 00000000..a6e3a581 --- /dev/null +++ b/apps/logs/migrations/0003_remove_null_tag_on_charfields.py @@ -0,0 +1,23 @@ +# Generated by Django 2.2.16 on 2020-09-06 19:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('logs', '0002_replace_null_by_blank'), + ] + + operations = [ + migrations.AlterField( + model_name='changelog', + name='data', + field=models.TextField(blank=True, default='', verbose_name='new data'), + ), + migrations.AlterField( + model_name='changelog', + name='previous', + field=models.TextField(blank=True, default='', verbose_name='previous data'), + ), + ] diff --git a/apps/logs/models.py b/apps/logs/models.py index e558ea82..0077af72 100644 --- a/apps/logs/models.py +++ b/apps/logs/models.py @@ -44,12 +44,14 @@ class Changelog(models.Model): ) previous = models.TextField( - null=True, + blank=True, + default="", verbose_name=_('previous data'), ) data = models.TextField( - null=True, + blank=True, + default="", verbose_name=_('new data'), ) @@ -80,3 +82,7 @@ class Changelog(models.Model): class Meta: verbose_name = _("changelog") verbose_name_plural = _("changelogs") + + def __str__(self): + return _("Changelog of type \"{action}\" for model {model} at {timestamp}").format( + action=self.get_action_display(), model=str(self.model), timestamp=str(self.timestamp)) diff --git a/apps/logs/signals.py b/apps/logs/signals.py index e58ba7c1..b0b4d2c2 100644 --- a/apps/logs/signals.py +++ b/apps/logs/signals.py @@ -50,7 +50,7 @@ def save_object(sender, instance, **kwargs): in order to store each modification made """ # noinspection PyProtectedMember - if instance._meta.label_lower in EXCLUDED or hasattr(instance, "_no_log"): + if instance._meta.label_lower in EXCLUDED or hasattr(instance, "_no_signal"): return # noinspection PyProtectedMember @@ -99,7 +99,7 @@ def save_object(sender, instance, **kwargs): model = instance.__class__ fields = changed_fields - previous_json = JSONRenderer().render(CustomSerializer(previous).data).decode("UTF-8") if previous else None + previous_json = JSONRenderer().render(CustomSerializer(previous).data).decode("UTF-8") if previous else "" instance_json = JSONRenderer().render(CustomSerializer(instance).data).decode("UTF-8") Changelog.objects.create(user=user, @@ -117,7 +117,7 @@ def delete_object(sender, instance, **kwargs): Each time a model is deleted, an entry in the table `Changelog` is added in the database """ # noinspection PyProtectedMember - if instance._meta.label_lower in EXCLUDED or hasattr(instance, "_no_log"): + if instance._meta.label_lower in EXCLUDED or hasattr(instance, "_no_signal"): return # Si un utilisateur est connecté, on récupère l'utilisateur courant ainsi que son adresse IP @@ -149,6 +149,6 @@ def delete_object(sender, instance, **kwargs): model=ContentType.objects.get_for_model(instance), instance_pk=instance.pk, previous=instance_json, - data=None, + data="", action="delete" ).save() diff --git a/apps/member/forms.py b/apps/member/forms.py index abefdf2c..20de91b7 100644 --- a/apps/member/forms.py +++ b/apps/member/forms.py @@ -3,7 +3,7 @@ import io -from PIL import Image +from PIL import Image, ImageSequence from django import forms from django.conf import settings from django.contrib.auth.forms import AuthenticationForm @@ -20,7 +20,7 @@ from .models import Profile, Club, Membership class CustomAuthenticationForm(AuthenticationForm): permission_mask = forms.ModelChoiceField( - label="Masque de permissions", + label=_("Permission mask"), queryset=PermissionMask.objects.order_by("rank"), empty_label=None, ) @@ -82,13 +82,19 @@ class ImageForm(forms.Form): height = forms.FloatField(widget=forms.HiddenInput()) def clean(self): - """Load image and crop""" + """ + Load image and crop + + In the future, when Pillow will support APNG we will be able to + simplify this code to save only PNG/APNG. + """ cleaned_data = super().clean() # Image size is limited by Django DATA_UPLOAD_MAX_MEMORY_SIZE image = cleaned_data.get('image') if image: # Let Pillow detect and load image + # If it is an animation, then there will be multiple frames try: im = Image.open(image) except OSError: @@ -96,20 +102,30 @@ class ImageForm(forms.Form): # but Pil is unable to load it raise forms.ValidationError(_('This image cannot be loaded.')) - # Crop image + # Crop each frame x = cleaned_data.get('x', 0) y = cleaned_data.get('y', 0) w = cleaned_data.get('width', 200) h = cleaned_data.get('height', 200) - im = im.crop((x, y, x + w, y + h)) - im = im.resize( - (settings.PIC_WIDTH, settings.PIC_RATIO * settings.PIC_WIDTH), - Image.ANTIALIAS, - ) + frames = [] + for frame in ImageSequence.Iterator(im): + frame = frame.crop((x, y, x + w, y + h)) + frame = frame.resize( + (settings.PIC_WIDTH, settings.PIC_RATIO * settings.PIC_WIDTH), + Image.ANTIALIAS, + ) + frames.append(frame) # Save + om = frames.pop(0) # Get first frame + om.info = im.info # Copy metadata image.file = io.BytesIO() - im.save(image.file, "PNG") + if len(frames) > 1: + # Save as GIF + om.save(image.file, "GIF", save_all=True, append_images=list(frames), loop=0) + else: + # Save as PNG + om.save(image.file, "PNG") return cleaned_data diff --git a/apps/member/migrations/0003_create_bde_and_kfet.py b/apps/member/migrations/0003_create_bde_and_kfet.py index 0464569f..5f218040 100644 --- a/apps/member/migrations/0003_create_bde_and_kfet.py +++ b/apps/member/migrations/0003_create_bde_and_kfet.py @@ -27,8 +27,8 @@ def create_bde_and_kfet(apps, schema_editor): parent_club_id=1, email="tresorerie.bde@example.com", require_memberships=True, - membership_fee_paid=500, - membership_fee_unpaid=500, + membership_fee_paid=3500, + membership_fee_unpaid=3500, membership_duration=396, membership_start="2020-08-01", membership_end="2021-09-30", diff --git a/apps/member/migrations/0004_replace_null_by_blank.py b/apps/member/migrations/0004_replace_null_by_blank.py new file mode 100644 index 00000000..a53e3801 --- /dev/null +++ b/apps/member/migrations/0004_replace_null_by_blank.py @@ -0,0 +1,20 @@ +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('member', '0003_create_bde_and_kfet'), + ] + + operations = [ + migrations.RunSQL( + "UPDATE member_profile SET address = '' WHERE address IS NULL;", + ), + migrations.RunSQL( + "UPDATE member_profile SET ml_events_registration = '' WHERE ml_events_registration IS NULL;", + ), + migrations.RunSQL( + "UPDATE member_profile SET section = '' WHERE section IS NULL;", + ), + ] diff --git a/apps/member/migrations/0005_remove_null_tag_on_charfields.py b/apps/member/migrations/0005_remove_null_tag_on_charfields.py new file mode 100644 index 00000000..11b9f37b --- /dev/null +++ b/apps/member/migrations/0005_remove_null_tag_on_charfields.py @@ -0,0 +1,28 @@ +# Generated by Django 2.2.16 on 2020-09-06 19:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('member', '0004_replace_null_by_blank'), + ] + + operations = [ + migrations.AlterField( + model_name='profile', + name='address', + field=models.CharField(blank=True, default='', max_length=255, verbose_name='address'), + ), + migrations.AlterField( + model_name='profile', + name='ml_events_registration', + field=models.CharField(blank=True, choices=[('', 'No'), ('fr', 'Yes (receive them in french)'), ('en', 'Yes (receive them in english)')], default='', max_length=2, verbose_name='Register on the mailing list to stay informed of the events of the campus (1 mail/week)'), + ), + migrations.AlterField( + model_name='profile', + name='section', + field=models.CharField(blank=True, default='', help_text='e.g. "1A0", "9A♥", "SAPHIRE"', max_length=255, verbose_name='section'), + ), + ] diff --git a/apps/member/models.py b/apps/member/models.py index bce525af..c7467120 100644 --- a/apps/member/models.py +++ b/apps/member/models.py @@ -46,7 +46,7 @@ class Profile(models.Model): help_text=_('e.g. "1A0", "9A♥", "SAPHIRE"'), max_length=255, blank=True, - null=True, + default="", ) department = models.CharField( @@ -83,7 +83,7 @@ class Profile(models.Model): verbose_name=_('address'), max_length=255, blank=True, - null=True, + default="", ) paid = models.BooleanField( @@ -94,11 +94,10 @@ class Profile(models.Model): ml_events_registration = models.CharField( blank=True, - null=True, - default=None, + default='', max_length=2, choices=[ - (None, _("No")), + ('', _("No")), ('fr', _("Yes (receive them in french)")), ('en', _("Yes (receive them in english)")), ], diff --git a/apps/member/signals.py b/apps/member/signals.py index 43659b01..d590f446 100644 --- a/apps/member/signals.py +++ b/apps/member/signals.py @@ -6,7 +6,7 @@ def save_user_profile(instance, created, raw, **_kwargs): """ Hook to create and save a profile when an user is updated if it is not registered with the signup form """ - if not raw and created and instance.is_active: + if not raw and created and instance.is_active and not hasattr(instance, "_no_signal"): from .models import Profile Profile.objects.get_or_create(user=instance) if instance.is_superuser: diff --git a/apps/member/templates/member/includes/club_info.html b/apps/member/templates/member/includes/club_info.html index 92c7b569..51f0ef03 100644 --- a/apps/member/templates/member/includes/club_info.html +++ b/apps/member/templates/member/includes/club_info.html @@ -48,10 +48,10 @@
- {% trans 'Manage aliases' %} ({{ user_object.note.alias_set.all|length }}) + {% trans 'Manage aliases' %} ({{ club.note.alias_set.all|length }})
{% trans 'email'|capfirst %}
{{ club.email }}
- \ No newline at end of file + diff --git a/apps/member/views.py b/apps/member/views.py index 746f5c94..033533ff 100644 --- a/apps/member/views.py +++ b/apps/member/views.py @@ -138,7 +138,7 @@ class UserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): """ We can't display information of a not registered user. """ - return super().get_queryset().filter(profile__registration_valid=True) + return super().get_queryset(**kwargs).filter(profile__registration_valid=True) def get_context_data(self, **kwargs): """ @@ -271,9 +271,17 @@ class PictureUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin, Det def form_valid(self, form): """Save image to note""" - image_field = form.cleaned_data['image'] - image_field.name = "{}_pic.png".format(self.object.note.pk) - self.object.note.display_image = image_field + image = form.cleaned_data['image'] + + # Rename as a PNG or GIF + extension = image.name.split(".")[-1] + if extension == "gif": + image.name = "{}_pic.gif".format(self.object.note.pk) + else: + image.name = "{}_pic.png".format(self.object.note.pk) + + # Save + self.object.note.display_image = image self.object.note.save() return super().form_valid(form) diff --git a/apps/note/apps.py b/apps/note/apps.py index 4881e3b9..b3dc5a0f 100644 --- a/apps/note/apps.py +++ b/apps/note/apps.py @@ -3,7 +3,7 @@ from django.apps import AppConfig from django.conf import settings -from django.db.models.signals import post_save +from django.db.models.signals import post_save, pre_delete from django.utils.translation import gettext_lazy as _ from . import signals @@ -25,3 +25,8 @@ class NoteConfig(AppConfig): signals.save_club_note, sender='member.Club', ) + + pre_delete.connect( + signals.delete_transaction, + sender='note.transaction', + ) diff --git a/apps/note/migrations/0003_replace_null_by_blank.py b/apps/note/migrations/0003_replace_null_by_blank.py new file mode 100644 index 00000000..21da860d --- /dev/null +++ b/apps/note/migrations/0003_replace_null_by_blank.py @@ -0,0 +1,17 @@ +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('note', '0002_create_special_notes'), + ] + + operations = [ + migrations.RunSQL( + "UPDATE note_note SET inactivity_reason = '' WHERE inactivity_reason IS NULL;" + ), + migrations.RunSQL( + "UPDATE note_transaction SET invalidity_reason = '' WHERE invalidity_reason IS NULL;" + ), + ] diff --git a/apps/note/migrations/0004_remove_null_tag_on_charfields.py b/apps/note/migrations/0004_remove_null_tag_on_charfields.py new file mode 100644 index 00000000..012fc359 --- /dev/null +++ b/apps/note/migrations/0004_remove_null_tag_on_charfields.py @@ -0,0 +1,23 @@ +# Generated by Django 2.2.16 on 2020-09-06 19:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('note', '0003_replace_null_by_blank'), + ] + + operations = [ + migrations.AlterField( + model_name='note', + name='inactivity_reason', + field=models.CharField(blank=True, choices=[('manual', 'The user blocked his/her note manually, eg. when he/she left the school for holidays. It can be reactivated at any time.'), ('forced', "The note is blocked by the the BDE and can't be manually reactivated.")], default='', max_length=255), + ), + migrations.AlterField( + model_name='transaction', + name='invalidity_reason', + field=models.CharField(blank=True, default='', max_length=255, verbose_name='invalidity reason'), + ), + ] diff --git a/apps/note/models/notes.py b/apps/note/models/notes.py index 877247df..9efdd1d0 100644 --- a/apps/note/models/notes.py +++ b/apps/note/models/notes.py @@ -70,8 +70,8 @@ class Note(PolymorphicModel): "It can be reactivated at any time.")), ('forced', _("The note is blocked by the the BDE and can't be manually reactivated.")), ], - null=True, - default=None, + blank=True, + default="", ) class Meta: diff --git a/apps/note/models/transactions.py b/apps/note/models/transactions.py index a4f220bd..c28d66da 100644 --- a/apps/note/models/transactions.py +++ b/apps/note/models/transactions.py @@ -90,6 +90,9 @@ class TransactionTemplate(models.Model): def get_absolute_url(self): return reverse('note:template_update', args=(self.pk,)) + def __str__(self): + return self.name + class Transaction(PolymorphicModel): """ @@ -150,8 +153,7 @@ class Transaction(PolymorphicModel): invalidity_reason = models.CharField( verbose_name=_('invalidity reason'), max_length=255, - default=None, - null=True, + default='', blank=True, ) @@ -173,7 +175,7 @@ class Transaction(PolymorphicModel): created = self.pk is None to_transfer = self.amount * self.quantity - if not created: + if not created and not self.valid and not hasattr(self, "_force_save"): # Revert old transaction old_transaction = Transaction.objects.get(pk=self.pk) # Check that nothing important changed @@ -195,7 +197,7 @@ class Transaction(PolymorphicModel): # When a transaction is declared valid, we ensure that the invalidity reason is null, if it was # previously invalid - self.invalidity_reason = None + self.invalidity_reason = "" if source_balance > 9223372036854775807 or source_balance < -9223372036854775808\ or dest_balance > 9223372036854775807 or dest_balance < -9223372036854775808: @@ -242,14 +244,6 @@ class Transaction(PolymorphicModel): self.destination._force_save = True self.destination.save() - def delete(self, **kwargs): - """ - Whenever we want to delete a transaction (caution with this), we ensure the transaction is invalid first. - """ - self.valid = False - self.save(**kwargs) - super().delete(**kwargs) - @property def total(self): return self.amount * self.quantity diff --git a/apps/note/signals.py b/apps/note/signals.py index 06bb480b..c1545ec2 100644 --- a/apps/note/signals.py +++ b/apps/note/signals.py @@ -6,7 +6,8 @@ def save_user_note(instance, raw, **_kwargs): """ Hook to create and save a note when an user is updated """ - if not raw and (instance.is_superuser or instance.profile.registration_valid): + if not raw and (instance.is_superuser or instance.profile.registration_valid)\ + and not hasattr(instance, "_no_signal"): # Create note only when the registration is validated from note.models import NoteUser NoteUser.objects.get_or_create(user=instance) @@ -17,10 +18,17 @@ def save_club_note(instance, raw, **_kwargs): """ Hook to create and save a note when a club is updated """ - if raw: - # When provisionning data, do not try to autocreate - return + # When provisionning data, do not try to autocreate + if not raw and not hasattr(instance, "_no_signal"): + from .models import NoteClub + NoteClub.objects.get_or_create(club=instance) + instance.note.save() - from .models import NoteClub - NoteClub.objects.get_or_create(club=instance) - instance.note.save() + +def delete_transaction(instance, **_kwargs): + """ + Whenever we want to delete a transaction (caution with this), we ensure the transaction is invalid first. + """ + if not hasattr(instance, "_no_signal"): + instance.valid = False + instance.save() diff --git a/apps/note/templates/note/mails/weekly_report.html b/apps/note/templates/note/mails/weekly_report.html index 871e09c2..6ed768a3 100644 --- a/apps/note/templates/note/mails/weekly_report.html +++ b/apps/note/templates/note/mails/weekly_report.html @@ -1,5 +1,7 @@ {% load pretty_money %} +{% load getenv %} {% load render_table from django_tables2 %} +{% load static %} {% load i18n %} @@ -8,13 +10,8 @@ [Note Kfet] Rapport de la Note Kfet - - + +

@@ -27,7 +24,7 @@ Ensuite, un rapport vous est envoyé à la fréquence demandée seulement si vous avez consommé depuis le dernier rapport.
Pour arrêter de recevoir des rapports, il vous suffit de modifier votre profil Note et de - mettre la fréquence des rapports à 0 ou -1.
+ mettre la fréquence des rapports à 0.
Pour toutes suggestions par rapport à ce service, contactez notekfet2020@lists.crans.org.

diff --git a/apps/note/templates/note/mails/weekly_report.txt b/apps/note/templates/note/mails/weekly_report.txt new file mode 100644 index 00000000..3d9bcf67 --- /dev/null +++ b/apps/note/templates/note/mails/weekly_report.txt @@ -0,0 +1,32 @@ +{% load pretty_money %} +{% load getenv %} +{% load i18n %} + +Bonjour, + +Vous recevez ce mail car vous avez défini une « Fréquence des rapports » dans la Note. +Le premier rapport récapitule toutes vos consommations depuis la création de votre compte. +Ensuite, un rapport vous est envoyé à la fréquence demandée seulement si vous avez consommé +depuis le dernier rapport. +Pour arrêter de recevoir des rapports, il vous suffit de modifier votre profil Note et de +mettre la fréquence des rapports à 0. +Pour toutes suggestions par rapport à ce service, contactez notekfet2020@lists.crans.org. + +Rapport d'activité de {{ user.first_name|safe }} {{ user.last_name|safe }} (note : {{ user|safe }}) +depuis le {{ last_report }} jusqu'au {{ now }}. + +Dépenses totales : {{ outcoming|pretty_money }} +Apports totaux : {{ incoming|pretty_money }} +Différentiel : {{ diff|pretty_money }} +Nouveau solde : {{ user.note.balance|pretty_money }} + + +Rapport détaillé : + +| Source | Destination | Créée le | Quantité | Montant | Raison | Type | Total | Valide | ++----------------------+----------------------+---------------------+----------+----------+----------------------------------+------------------+----------+---------+ +{% for tr in last_transactions %}| {{ tr.source|safe|truncatechars:20|center:"20" }} | {{ tr.destination|safe|truncatechars:20|center:"20" }} | {{ tr.created_at|date:"Y-m-d H:i:s" }} | {{ tr.quantity|center:"8" }} | {{ tr.amount|pretty_money|center:"8" }} | {{ tr.reason|safe|truncatechars:32|center:"32" }} | {{ tr.type|safe|center:"16" }} | {{ tr.total|pretty_money|center:"8" }} | {{ tr.valid|yesno|center:"7" }} | +{% endfor %} +-- +Le BDE +{% trans "Mail generated by the Note Kfet on the" %} {% now "j F Y à H:i:s" %} diff --git a/apps/note/templates/note/transaction_form.html b/apps/note/templates/note/transaction_form.html index 9c484799..f5ff0b73 100644 --- a/apps/note/templates/note/transaction_form.html +++ b/apps/note/templates/note/transaction_form.html @@ -65,9 +65,9 @@ SPDX-License-Identifier: GPL-2.0-or-later

- + {% trans "I am the emitter" %} - +
diff --git a/apps/permission/models.py b/apps/permission/models.py index 3d395a75..ff348404 100644 --- a/apps/permission/models.py +++ b/apps/permission/models.py @@ -57,8 +57,8 @@ class InstancedPermission: # Force insertion, no data verification, no trigger obj._force_save = True - # We don't want log anything - obj._no_log = True + # We don't want to trigger any signal (log, ...) + obj._no_signal = True Model.save(obj, force_insert=True) ret = self.model.model_class().objects.filter(self.query & Q(pk=0)).exists() # Delete testing object diff --git a/apps/permission/signals.py b/apps/permission/signals.py index 112247eb..e738545a 100644 --- a/apps/permission/signals.py +++ b/apps/permission/signals.py @@ -28,7 +28,7 @@ def pre_save_object(sender, instance, **kwargs): if instance._meta.label_lower in EXCLUDED: return - if hasattr(instance, "_force_save"): + if hasattr(instance, "_force_save") or hasattr(instance, "_no_signal"): return user = get_current_authenticated_user() @@ -82,7 +82,8 @@ def pre_delete_object(instance, **kwargs): if instance._meta.label_lower in EXCLUDED: return - if hasattr(instance, "_force_delete") or hasattr(instance, "pk") and instance.pk == 0: + if hasattr(instance, "_force_delete") or hasattr(instance, "pk") and instance.pk == 0 \ + or hasattr(instance, "_no_signal"): # Don't check permissions on force-deleted objects return diff --git a/apps/permission/tests/test_permission_queries.py b/apps/permission/tests/test_permission_queries.py index 4d73ae11..fdd530a5 100644 --- a/apps/permission/tests/test_permission_queries.py +++ b/apps/permission/tests/test_permission_queries.py @@ -78,7 +78,6 @@ class PermissionQueryTestCase(TestCase): query = instanced.query model = perm.model.model_class() model.objects.filter(query).all() - # print("Good query for permission", perm) except (FieldError, AttributeError, ValueError, TypeError, JSONDecodeError): print("Query error for permission", perm) print("Query:", perm.query) diff --git a/apps/permission/views.py b/apps/permission/views.py index 70aa7184..343152f5 100644 --- a/apps/permission/views.py +++ b/apps/permission/views.py @@ -8,6 +8,7 @@ from django.contrib.auth.models import User from django.core.exceptions import PermissionDenied from django.db.models import Q from django.forms import HiddenInput +from django.http import Http404 from django.utils.translation import gettext_lazy as _ from django.views.generic import UpdateView, TemplateView, CreateView from member.models import Membership @@ -24,9 +25,20 @@ class ProtectQuerysetMixin: Display 404 error if the user can't see an object, remove the fields the user can't update on an update form (useful if the user can't change only specified fields). """ - def get_queryset(self, **kwargs): + def get_queryset(self, filter_permissions=True, **kwargs): qs = super().get_queryset(**kwargs) - return qs.filter(PermissionBackend.filter_queryset(self.request.user, qs.model, "view")).distinct() + return qs.filter(PermissionBackend.filter_queryset(self.request.user, qs.model, "view")).distinct()\ + if filter_permissions else qs + + def get_object(self, queryset=None): + try: + return super().get_object(queryset) + except Http404 as e: + try: + super().get_object(self.get_queryset(filter_permissions=False)) + raise PermissionDenied() + except Http404: + raise e def get_form(self, form_class=None): form = super().get_form(form_class) diff --git a/apps/registration/static/registration/css/login.css b/apps/registration/static/registration/css/login.css index b789b2f7..b1bac970 100644 --- a/apps/registration/static/registration/css/login.css +++ b/apps/registration/static/registration/css/login.css @@ -16,4 +16,8 @@ Font-Awesome attribution is already done inside SVG files #login-form select { -moz-appearance: none; cursor: pointer; -} \ No newline at end of file +} + +#login-form .asteriskField { + display: none; +} diff --git a/apps/registration/templates/registration/email_validation_complete.html b/apps/registration/templates/registration/email_validation_complete.html index dca26470..11a84fe9 100644 --- a/apps/registration/templates/registration/email_validation_complete.html +++ b/apps/registration/templates/registration/email_validation_complete.html @@ -5,14 +5,29 @@ SPDX-License-Identifier: GPL-3.0-or-later {% load i18n %} {% block content %} - {% if validlink %} - {% trans "Your email have successfully been validated." %} +
+

+ {{ title }} +

+
+ {% if validlink %} +

+ {% trans "Your email have successfully been validated." %} +

{% if user_object.profile.registration_valid %} +

{% blocktrans %}You can now log in.{% endblocktrans %} +

{% else %} +

{% trans "You must pay now your membership in the Kfet to complete your registration." %} +

{% endif %} - {% else %} - {% trans "The link was invalid. The token may have expired. Please send us an email to activate your account." %} - {% endif %} + {% else %} +

+ {% trans "The link was invalid. The token may have expired. Please send us an email to activate your account." %} +

+ {% endif %} +
+
{% endblock %} diff --git a/apps/registration/templates/registration/email_validation_email_sent.html b/apps/registration/templates/registration/email_validation_email_sent.html index 627c864b..f6db4cac 100644 --- a/apps/registration/templates/registration/email_validation_email_sent.html +++ b/apps/registration/templates/registration/email_validation_email_sent.html @@ -5,13 +5,17 @@ SPDX-License-Identifier: GPL-3.0-or-later {% load i18n %} {% block content %} -

{% trans "Account activation" %}

- -

- {% trans "An email has been sent. Please click on the link to activate your account." %} -

- -

- {% trans "You must also go to the Kfet to pay your membership. The WEI registration includes the BDE membership." %} -

-{% endblock %} \ No newline at end of file +
+

+ {% trans "Account activation" %} +

+
+

+ {% trans "An email has been sent. Please click on the link to activate your account." %} +

+

+ {% trans "You must also go to the Kfet to pay your membership." %} +

+
+
+{% endblock %} diff --git a/apps/registration/templates/registration/mails/email_validation_email.html b/apps/registration/templates/registration/mails/email_validation_email.html index 0d5b41f5..40d246c9 100644 --- a/apps/registration/templates/registration/mails/email_validation_email.html +++ b/apps/registration/templates/registration/mails/email_validation_email.html @@ -27,7 +27,7 @@

- {% trans "After that, you'll have to wait that someone validates your account before you can log in. You will need to pay your membership in the Kfet. Note that the WEI registration includes the Kfet membership." %} + {% trans "After that, you'll have to wait that someone validates your account before you can log in. You will need to pay your membership in the Kfet." %}

@@ -38,4 +38,4 @@

{% trans "The Note Kfet team." %}
{% trans "Mail generated by the Note Kfet on the" %} {% now "j F Y à H:i:s" %} -

\ No newline at end of file +

diff --git a/apps/registration/templates/registration/mails/email_validation_email.txt b/apps/registration/templates/registration/mails/email_validation_email.txt index 5ce48110..7b280bb2 100644 --- a/apps/registration/templates/registration/mails/email_validation_email.txt +++ b/apps/registration/templates/registration/mails/email_validation_email.txt @@ -8,9 +8,9 @@ https://{{ domain }}{% url 'registration:email_validation' uidb64=uid token=toke {% trans "This link is only valid for a couple of days, after that you will need to contact us to validate your email." %} -{% trans "After that, you'll have to wait that someone validates your account before you can log in. You will need to pay your membership in the Kfet. Note that the WEI registration includes the Kfet membership." %} +{% trans "After that, you'll have to wait that someone validates your account before you can log in. You will need to pay your membership in the Kfet." %} {% trans "Thanks" %}, {% trans "The Note Kfet team." %} -{% trans "Mail generated by the Note Kfet on the" %} {% now "j F Y à H:i:s" %} \ No newline at end of file +{% trans "Mail generated by the Note Kfet on the" %} {% now "j F Y à H:i:s" %} diff --git a/apps/registration/tests/test_registration.py b/apps/registration/tests/test_registration.py index e2191445..adb773f9 100644 --- a/apps/registration/tests/test_registration.py +++ b/apps/registration/tests/test_registration.py @@ -364,7 +364,7 @@ class TestValidateRegistration(TestCase): self.assertTrue(Membership.objects.filter(club__name="Kfet", user=self.user).exists()) self.assertTrue(SogeCredit.objects.filter(user=self.user).exists()) self.assertEqual(Transaction.objects.filter( - Q(source=self.user.note) | Q(destination=self.user.note)).count(), 2) + Q(source=self.user.note) | Q(destination=self.user.note)).count(), 3) self.assertFalse(Transaction.objects.filter(valid=True).exists()) response = self.client.get(self.user.profile.get_absolute_url()) diff --git a/apps/registration/views.py b/apps/registration/views.py index 7a924591..1f71931e 100644 --- a/apps/registration/views.py +++ b/apps/registration/views.py @@ -21,6 +21,7 @@ from note.templatetags.pretty_money import pretty_money from permission.backends import PermissionBackend from permission.models import Role from permission.views import ProtectQuerysetMixin +from treasury.models import SogeCredit from .forms import SignUpForm, ValidationForm from .tables import FutureUserTable @@ -219,6 +220,9 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin, fee += bde.membership_fee_paid if user.profile.paid else bde.membership_fee_unpaid kfet = Club.objects.get(name="Kfet") fee += kfet.membership_fee_paid if user.profile.paid else kfet.membership_fee_unpaid + # In 2020, for COVID-19 reasons, the BDE offered 80 € to each new member that opens a Sogé account, + # since there is no WEI. + fee += 8000 ctx["total_fee"] = "{:.02f}".format(fee / 100, ) return ctx @@ -342,6 +346,11 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin, membership.roles.add(Role.objects.get(name="Adhérent Kfet")) membership.save() + if soge: + soge_credit = SogeCredit.objects.get(user=user) + # Update the credit transaction amount + soge_credit.save() + return ret def get_success_url(self): diff --git a/apps/scripts b/apps/scripts index 4f5a7947..e5b76b7c 160000 --- a/apps/scripts +++ b/apps/scripts @@ -1 +1 @@ -Subproject commit 4f5a794798a48cbbf10b42f0a519743fcbb96c33 +Subproject commit e5b76b7c35592aba4225115f933f2a7ed3a66df3 diff --git a/apps/treasury/models.py b/apps/treasury/models.py index e57496ec..d611650f 100644 --- a/apps/treasury/models.py +++ b/apps/treasury/models.py @@ -109,6 +109,9 @@ class Invoice(models.Model): verbose_name = _("invoice") verbose_name_plural = _("invoices") + def __str__(self): + return _("Invoice #{id}").format(id=self.id) + class Product(models.Model): """ @@ -151,6 +154,9 @@ class Product(models.Model): verbose_name = _("product") verbose_name_plural = _("products") + def __str__(self): + return f"{self.designation} ({self.invoice})" + class RemittanceType(models.Model): """ @@ -256,6 +262,9 @@ class SpecialTransactionProxy(models.Model): verbose_name = _("special transaction proxy") verbose_name_plural = _("special transaction proxies") + def __str__(self): + return str(self.transaction) + class SogeCredit(models.Model): """ @@ -282,11 +291,11 @@ class SogeCredit(models.Model): @property def valid(self): - return self.credit_transaction is not None + return self.credit_transaction.valid @property def amount(self): - return sum(transaction.total for transaction in self.transactions.all()) + return sum(transaction.total for transaction in self.transactions.all()) + 8000 def invalidate(self): """ @@ -295,11 +304,7 @@ class SogeCredit(models.Model): """ if self.valid: self.credit_transaction.valid = False - self.credit_transaction._force_save = True self.credit_transaction.save() - self.credit_transaction._force_delete = True - self.credit_transaction.delete() - self.credit_transaction = None for transaction in self.transactions.all(): transaction.valid = False transaction._force_save = True @@ -312,17 +317,10 @@ class SogeCredit(models.Model): # First invalidate all transaction and delete the credit if already did (and force mode) self.invalidate() - self.credit_transaction = SpecialTransaction.objects.create( - source=NoteSpecial.objects.get(special_type="Virement bancaire"), - destination=self.user.note, - quantity=1, - amount=self.amount, - reason="Crédit société générale", - last_name=self.user.last_name, - first_name=self.user.first_name, - bank="Société générale", - created_at=self.transactions.order_by("-created_at").first().created_at, - ) + # Refresh credit amount + self.save() + self.credit_transaction.valid = True + self.credit_transaction.save() self.save() for transaction in self.transactions.all(): @@ -331,6 +329,25 @@ class SogeCredit(models.Model): transaction.created_at = timezone.now() transaction.save() + def save(self, *args, **kwargs): + if not self.credit_transaction: + self.credit_transaction = SpecialTransaction.objects.create( + source=NoteSpecial.objects.get(special_type="Virement bancaire"), + destination=self.user.note, + quantity=1, + amount=0, + reason="Crédit société générale", + last_name=self.user.last_name, + first_name=self.user.first_name, + bank="Société générale", + valid=False, + ) + elif not self.valid: + self.credit_transaction.amount = self.amount + self.credit_transaction._force_save = True + self.credit_transaction.save() + super().save(*args, **kwargs) + def delete(self, **kwargs): """ Deleting a SogeCredit is equivalent to say that the Société générale didn't pay. @@ -349,8 +366,14 @@ class SogeCredit(models.Model): transaction.valid = True transaction.created_at = timezone.now() transaction.save() + self.credit_transaction.valid = False + self.credit_transaction.reason += " (invalide)" + self.credit_transaction.save() super().delete(**kwargs) class Meta: verbose_name = _("Credit from the Société générale") verbose_name_plural = _("Credits from the Société générale") + + def __str__(self): + return _("Soge credit for {user}").format(user=str(self.user)) diff --git a/apps/treasury/signals.py b/apps/treasury/signals.py index b7038ab6..f08540d1 100644 --- a/apps/treasury/signals.py +++ b/apps/treasury/signals.py @@ -9,9 +9,10 @@ def save_special_transaction(instance, created, **kwargs): When a special transaction is created, we create its linked proxy """ - if instance.is_credit(): - if created and RemittanceType.objects.filter(note=instance.source).exists(): - SpecialTransactionProxy.objects.create(transaction=instance, remittance=None).save() - else: - if created and RemittanceType.objects.filter(note=instance.destination).exists(): - SpecialTransactionProxy.objects.create(transaction=instance, remittance=None).save() + if not hasattr(instance, "_no_signal"): + if instance.is_credit(): + if created and RemittanceType.objects.filter(note=instance.source).exists(): + SpecialTransactionProxy.objects.create(transaction=instance, remittance=None).save() + else: + if created and RemittanceType.objects.filter(note=instance.destination).exists(): + SpecialTransactionProxy.objects.create(transaction=instance, remittance=None).save() diff --git a/apps/treasury/templates/treasury/sogecredit_list.html b/apps/treasury/templates/treasury/sogecredit_list.html index 1eb1aba5..c561da72 100644 --- a/apps/treasury/templates/treasury/sogecredit_list.html +++ b/apps/treasury/templates/treasury/sogecredit_list.html @@ -30,7 +30,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
diff --git a/apps/treasury/tests/test_treasury.py b/apps/treasury/tests/test_treasury.py index 0d6e5d62..505453b9 100644 --- a/apps/treasury/tests/test_treasury.py +++ b/apps/treasury/tests/test_treasury.py @@ -353,7 +353,6 @@ class TestSogeCredits(TestCase): soge_credit.refresh_from_db() self.assertTrue(soge_credit.valid) self.user.note.refresh_from_db() - self.assertEqual(self.user.note.balance, 0) self.assertEqual( Transaction.objects.filter(Q(source=self.user.note) | Q(destination=self.user.note)).count(), 3) self.assertTrue(self.user.profile.soge) @@ -391,7 +390,7 @@ class TestSogeCredits(TestCase): self.user.note.refresh_from_db() self.assertEqual(self.user.note.balance, 0) self.assertEqual( - Transaction.objects.filter(Q(source=self.user.note) | Q(destination=self.user.note)).count(), 3) + Transaction.objects.filter(Q(source=self.user.note) | Q(destination=self.user.note)).count(), 4) self.assertFalse(self.user.profile.soge) def test_invoice_api(self): diff --git a/apps/treasury/views.py b/apps/treasury/views.py index 7e9ecc51..ecefc5cf 100644 --- a/apps/treasury/views.py +++ b/apps/treasury/views.py @@ -209,7 +209,7 @@ class InvoiceRenderView(LoginRequiredMixin, View): # The file has to be rendered twice for ignored in range(2): error = subprocess.Popen( - ["xelatex", "-interaction=nonstopmode", "invoice-{}.tex".format(pk)], + ["/usr/bin/xelatex", "-interaction=nonstopmode", "invoice-{}.tex".format(pk)], cwd=tmp_dir, stdin=open(os.devnull, "r"), stderr=open(os.devnull, "wb"), @@ -425,11 +425,8 @@ class SogeCreditListView(LoginRequiredMixin, ProtectQuerysetMixin, SingleTableVi | Q(user__note__alias__normalized_name__iregex="^" + Alias.normalize(pattern)) ) - if "valid" in self.request.GET: - q = Q(credit_transaction=None) - if not self.request.GET["valid"]: - q = ~q - qs = qs.filter(q) + if "valid" not in self.request.GET or not self.request.GET["valid"]: + qs = qs.filter(credit_transaction__valid=False) return qs[:20] diff --git a/apps/wei/tests/test_wei_registration.py b/apps/wei/tests/test_wei_registration.py index e1724419..6d294bdd 100644 --- a/apps/wei/tests/test_wei_registration.py +++ b/apps/wei/tests/test_wei_registration.py @@ -690,7 +690,7 @@ class TestWEIRegistration(TestCase): """ with open("/dev/null", "wb") as devnull: return subprocess.call( - ["which", "xelatex"], + ["/usr/bin/which", "xelatex"], stdout=devnull, stderr=devnull, ) == 0 diff --git a/apps/wei/views.py b/apps/wei/views.py index ced85473..8246bebf 100644 --- a/apps/wei/views.py +++ b/apps/wei/views.py @@ -1103,7 +1103,7 @@ class MemberListRenderView(LoginRequiredMixin, View): with open(os.devnull, "wb") as devnull: error = subprocess.Popen( - ["xelatex", "-interaction=nonstopmode", "{}/wei-list.tex".format(tmp_dir)], + ["/usr/bin/xelatex", "-interaction=nonstopmode", "{}/wei-list.tex".format(tmp_dir)], cwd=tmp_dir, stderr=devnull, stdout=devnull, diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index b943b130..3891a934 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: 2020-09-06 12:32+0200\n" +"POT-Creation-Date: 2020-09-07 19:43+0200\n" "PO-Revision-Date: 2020-09-03 23:47+0200\n" "Last-Translator: \n" "Language-Team: \n" @@ -27,33 +27,33 @@ msgstr "Veranstaltung" msgid "The end date must be after the start date." msgstr "Das Abschlussdatum muss nach das Anfangsdatum sein." -#: apps/activity/forms.py:76 apps/activity/models.py:262 +#: apps/activity/forms.py:76 apps/activity/models.py:268 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:79 apps/activity/models.py:265 +#: apps/activity/forms.py:79 apps/activity/models.py:271 msgid "This activity is not validated yet." msgstr "Diese Veranstaltung ist noch nicht bestätigt." -#: apps/activity/forms.py:89 apps/activity/models.py:273 +#: apps/activity/forms.py:89 apps/activity/models.py:279 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:93 apps/activity/models.py:277 +#: apps/activity/forms.py:93 apps/activity/models.py:283 msgid "This person is already invited." msgstr "Diese Person wurde schon eingeladen." -#: apps/activity/forms.py:97 apps/activity/models.py:281 +#: apps/activity/forms.py:97 apps/activity/models.py:287 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:200 +#: apps/member/models.py:199 #: apps/member/templates/member/includes/club_info.html:4 #: apps/member/templates/member/includes/profile_info.html:4 #: apps/note/models/notes.py:253 apps/note/models/transactions.py:26 -#: apps/note/models/transactions.py:46 apps/note/models/transactions.py:303 +#: apps/note/models/transactions.py:46 apps/note/models/transactions.py:296 #: apps/permission/models.py:329 #: apps/registration/templates/registration/future_profile_detail.html:16 #: apps/wei/models.py:66 apps/wei/models.py:118 @@ -110,8 +110,8 @@ msgstr "Wo findet die Veranstaltung statt ? (z.B Kfet)" msgid "type" msgstr "Type" -#: apps/activity/models.py:89 apps/logs/models.py:22 apps/member/models.py:305 -#: apps/note/models/notes.py:144 apps/treasury/models.py:267 +#: apps/activity/models.py:89 apps/logs/models.py:22 apps/member/models.py:304 +#: apps/note/models/notes.py:144 apps/treasury/models.py:276 #: apps/treasury/templates/treasury/sogecredit_detail.html:14 #: apps/wei/models.py:160 apps/wei/templates/wei/survey.html:15 msgid "user" @@ -149,7 +149,7 @@ msgstr "Abschlussdatum" #: apps/activity/models.py:118 #: apps/activity/templates/activity/includes/activity_info.html:50 -#: apps/note/models/transactions.py:146 +#: apps/note/models/transactions.py:149 msgid "valid" msgstr "gültig" @@ -181,42 +181,52 @@ msgstr "Eintritt" msgid "entries" msgstr "Eintritte" -#: apps/activity/models.py:195 +#: apps/activity/models.py:192 +#, 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:194 +#, python-brace-format +msgid "Entry for {note} to the activity {activity}" +msgstr "Eintritt von {note} zur Veranstaltung {activity}" + +#: apps/activity/models.py:201 msgid "Already entered on " msgstr "Schon eingetretten " -#: apps/activity/models.py:195 apps/activity/tables.py:54 +#: apps/activity/models.py:201 apps/activity/tables.py:54 msgid "{:%Y-%m-%d %H:%M:%S}" msgstr "{:%Y-%m-%d %H:%M:%S}" -#: apps/activity/models.py:203 +#: apps/activity/models.py:209 msgid "The balance is negative." msgstr "Kontostand ist im Rot." -#: apps/activity/models.py:233 +#: apps/activity/models.py:239 msgid "last name" msgstr "Nachname" -#: apps/activity/models.py:238 +#: apps/activity/models.py:244 #: apps/member/templates/member/includes/profile_info.html:4 #: apps/registration/templates/registration/future_profile_detail.html:16 #: apps/wei/templates/wei/weimembership_form.html:14 msgid "first name" msgstr "Vorname" -#: apps/activity/models.py:245 +#: apps/activity/models.py:251 msgid "inviter" msgstr "Einlader" -#: apps/activity/models.py:289 +#: apps/activity/models.py:295 msgid "guest" msgstr "Gast" -#: apps/activity/models.py:290 +#: apps/activity/models.py:296 msgid "guests" msgstr "Gäste" -#: apps/activity/models.py:302 +#: apps/activity/models.py:308 msgid "Invitation" msgstr "Einladung" @@ -240,17 +250,17 @@ msgstr "Eingetreten um " msgid "remove" msgstr "entfernen" -#: apps/activity/tables.py:80 apps/note/forms.py:68 apps/treasury/models.py:186 +#: apps/activity/tables.py:80 apps/note/forms.py:68 apps/treasury/models.py:192 msgid "Type" msgstr "Type" -#: apps/activity/tables.py:82 apps/member/forms.py:167 +#: apps/activity/tables.py:82 apps/member/forms.py:183 #: apps/registration/forms.py:81 apps/treasury/forms.py:129 #: apps/wei/forms/registration.py:96 msgid "Last name" msgstr "Nachname" -#: apps/activity/tables.py:84 apps/member/forms.py:172 +#: apps/activity/tables.py:84 apps/member/forms.py:188 #: apps/note/templates/note/transaction_form.html:134 #: apps/registration/forms.py:86 apps/treasury/forms.py:131 #: apps/wei/forms/registration.py:101 @@ -270,21 +280,21 @@ msgid "Guests list" msgstr "Gastliste" #: apps/activity/templates/activity/activity_entry.html:14 -#: apps/note/models/transactions.py:260 +#: apps/note/models/transactions.py:253 #: apps/note/templates/note/transaction_form.html:16 #: apps/note/templates/note/transaction_form.html:148 -#: note_kfet/templates/base.html:69 +#: note_kfet/templates/base.html:70 msgid "Transfer" msgstr "Überweisen" #: apps/activity/templates/activity/activity_entry.html:18 -#: apps/note/models/transactions.py:319 +#: apps/note/models/transactions.py:312 #: apps/note/templates/note/transaction_form.html:21 msgid "Credit" msgstr "Kredit" #: apps/activity/templates/activity/activity_entry.html:21 -#: apps/note/models/transactions.py:319 +#: apps/note/models/transactions.py:312 #: apps/note/templates/note/transaction_form.html:25 msgid "Debit" msgstr "Soll" @@ -356,7 +366,7 @@ msgid "validate" msgstr "validate" #: apps/activity/templates/activity/includes/activity_info.html:71 -#: apps/logs/models.py:62 apps/note/tables.py:195 +#: apps/logs/models.py:64 apps/note/tables.py:195 msgid "edit" msgstr "bearbeiten" @@ -368,7 +378,7 @@ msgstr "Einladen" msgid "Create new activity" msgstr "Neue Veranstaltung schaffen" -#: apps/activity/views.py:63 note_kfet/templates/base.html:87 +#: apps/activity/views.py:63 note_kfet/templates/base.html:88 msgid "Activities" msgstr "Veranstaltungen" @@ -420,59 +430,64 @@ msgstr "Model" msgid "identifier" msgstr "Kennzeichnung" -#: apps/logs/models.py:48 +#: apps/logs/models.py:49 msgid "previous data" msgstr "ehemalige Daten" -#: apps/logs/models.py:53 +#: apps/logs/models.py:55 msgid "new data" msgstr "neue Daten" -#: apps/logs/models.py:61 +#: apps/logs/models.py:63 msgid "create" msgstr "schaffen" -#: apps/logs/models.py:63 apps/note/tables.py:165 apps/note/tables.py:201 +#: apps/logs/models.py:65 apps/note/tables.py:165 apps/note/tables.py:201 #: apps/permission/models.py:127 apps/treasury/tables.py:38 #: apps/wei/tables.py:75 msgid "delete" msgstr "entfernen" -#: apps/logs/models.py:66 +#: apps/logs/models.py:68 msgid "action" msgstr "Aktion" -#: apps/logs/models.py:74 +#: apps/logs/models.py:76 msgid "timestamp" msgstr "Zeitstempel" -#: apps/logs/models.py:78 +#: apps/logs/models.py:80 msgid "Logs cannot be destroyed." msgstr "Logs können nicht entfernen sein." -#: apps/logs/models.py:81 +#: apps/logs/models.py:83 msgid "changelog" msgstr "Changelog" -#: apps/logs/models.py:82 +#: apps/logs/models.py:84 msgid "changelogs" msgstr "Changelogs" -#: apps/member/admin.py:50 apps/member/models.py:227 +#: apps/logs/models.py:87 +#, python-brace-format +msgid "Changelog of type \"{action}\" for model {model} at {timestamp}" +msgstr "Changelog \"{action}\" für Model {model} an {timestamp}" + +#: apps/member/admin.py:50 apps/member/models.py:226 #: apps/member/templates/member/includes/club_info.html:34 msgid "membership fee (paid students)" msgstr "Mitgliedschaftpreis (bezahlte Studenten)" -#: apps/member/admin.py:51 apps/member/models.py:232 +#: apps/member/admin.py:51 apps/member/models.py:231 #: apps/member/templates/member/includes/club_info.html:37 msgid "membership fee (unpaid students)" msgstr "Mitgliedschaftpreis (unbezahlte Studenten)" -#: apps/member/admin.py:65 apps/member/models.py:316 +#: apps/member/admin.py:65 apps/member/models.py:315 msgid "roles" msgstr "Rollen" -#: apps/member/admin.py:66 apps/member/models.py:330 +#: apps/member/admin.py:66 apps/member/models.py:329 msgid "fee" msgstr "Preis" @@ -480,6 +495,10 @@ msgstr "Preis" msgid "member" msgstr "Mitglied" +#: apps/member/forms.py:23 +msgid "Permission mask" +msgstr "Berechtigungsmaske" + #: apps/member/forms.py:45 msgid "Report frequency" msgstr "Bericht Frequenz" @@ -500,53 +519,53 @@ msgstr "Wählen sie ein Bild aus" msgid "Maximal size: 2MB" msgstr "Maximal Größe: 2MB" -#: apps/member/forms.py:97 +#: apps/member/forms.py:103 msgid "This image cannot be loaded." msgstr "Dieses Bild kann nicht geladen werden." -#: apps/member/forms.py:123 apps/member/views.py:98 +#: apps/member/forms.py:139 apps/member/views.py:98 #: apps/registration/forms.py:33 apps/registration/views.py:237 msgid "An alias with a similar name already exists." msgstr "Ein ähnliches Alias ist schon benutzt." -#: apps/member/forms.py:146 apps/registration/forms.py:61 +#: apps/member/forms.py:162 apps/registration/forms.py:61 msgid "Inscription paid by Société Générale" msgstr "Mitgliedschaft von der Société Générale bezahlt" -#: apps/member/forms.py:148 apps/registration/forms.py:63 +#: apps/member/forms.py:164 apps/registration/forms.py:63 msgid "Check this case is the Société Générale paid the inscription." msgstr "Die Société Générale die Mitgliedschaft bezahlt." -#: apps/member/forms.py:153 apps/registration/forms.py:68 +#: apps/member/forms.py:169 apps/registration/forms.py:68 #: apps/wei/forms/registration.py:83 msgid "Credit type" msgstr "Kredittype" -#: apps/member/forms.py:154 apps/registration/forms.py:69 +#: apps/member/forms.py:170 apps/registration/forms.py:69 #: apps/wei/forms/registration.py:84 msgid "No credit" msgstr "Kein Kredit" -#: apps/member/forms.py:156 +#: apps/member/forms.py:172 msgid "You can credit the note of the user." msgstr "Sie dûrfen diese Note kreditieren." -#: apps/member/forms.py:160 apps/registration/forms.py:74 +#: apps/member/forms.py:176 apps/registration/forms.py:74 #: apps/wei/forms/registration.py:89 msgid "Credit amount" msgstr "Kreditanzahl" -#: apps/member/forms.py:177 apps/note/templates/note/transaction_form.html:140 +#: apps/member/forms.py:193 apps/note/templates/note/transaction_form.html:140 #: apps/registration/forms.py:91 apps/treasury/forms.py:133 #: apps/wei/forms/registration.py:106 msgid "Bank" msgstr "Bank" -#: apps/member/forms.py:204 +#: apps/member/forms.py:220 msgid "User" msgstr "User" -#: apps/member/forms.py:218 +#: apps/member/forms.py:234 msgid "Roles" msgstr "Rollen" @@ -662,19 +681,19 @@ msgstr "bezahlt" msgid "Tells if the user receive a salary." msgstr "User ist bezahlt." -#: apps/member/models.py:101 apps/treasury/tables.py:146 +#: apps/member/models.py:100 apps/treasury/tables.py:146 msgid "No" msgstr "Nein" -#: apps/member/models.py:102 +#: apps/member/models.py:101 msgid "Yes (receive them in french)" msgstr "Ja (auf Fränzosich)" -#: apps/member/models.py:103 +#: apps/member/models.py:102 msgid "Yes (receive them in english)" msgstr "Ja (auf English)" -#: apps/member/models.py:105 +#: apps/member/models.py:104 msgid "" "Register on the mailing list to stay informed of the events of the campus (1 " "mail/week)" @@ -682,7 +701,7 @@ msgstr "" "Melden Sie sich auf der Mailingliste an, um über die Ereignisse des Campus " "informiert zu bleiben (1 Mail / Woche)" -#: apps/member/models.py:110 +#: apps/member/models.py:109 msgid "" "Register on the mailing list to stay informed of the sport events of the " "campus (1 mail/week)" @@ -690,7 +709,7 @@ msgstr "" "Melden Sie sich auf der Mailingliste an, um über die Sportereignisse des " "Campus informiert zu bleiben (1 Mail / Woche)" -#: apps/member/models.py:115 +#: apps/member/models.py:114 msgid "" "Register on the mailing list to stay informed of the art events of the " "campus (1 mail/week)" @@ -698,31 +717,31 @@ msgstr "" "Melden Sie sich auf der Mailingliste an, um über die Kunstereignisse des " "Campus informiert zu bleiben (1 Mail / Woche)" -#: apps/member/models.py:119 +#: apps/member/models.py:118 msgid "report frequency (in days)" msgstr "Bericht Frequenz (Tagen)" -#: apps/member/models.py:124 +#: apps/member/models.py:123 msgid "last report date" msgstr "letzen Bericht Datum" -#: apps/member/models.py:129 +#: apps/member/models.py:128 msgid "email confirmed" msgstr "email bestätigt" -#: apps/member/models.py:134 +#: apps/member/models.py:133 msgid "registration valid" msgstr "Anmeldung gültig" -#: apps/member/models.py:163 apps/member/models.py:164 +#: apps/member/models.py:162 apps/member/models.py:163 msgid "user profile" msgstr "Userprofile" -#: apps/member/models.py:174 +#: apps/member/models.py:173 msgid "Activate your Note Kfet account" msgstr "Ihre Note Kfet Konto bestätigen" -#: apps/member/models.py:205 +#: apps/member/models.py:204 #: apps/member/templates/member/includes/club_info.html:55 #: apps/member/templates/member/includes/profile_info.html:31 #: apps/registration/templates/registration/future_profile_detail.html:22 @@ -731,88 +750,88 @@ msgstr "Ihre Note Kfet Konto bestätigen" msgid "email" msgstr "Email" -#: apps/member/models.py:212 +#: apps/member/models.py:211 msgid "parent club" msgstr "Urclub" -#: apps/member/models.py:221 +#: apps/member/models.py:220 msgid "require memberships" msgstr "erfordern Mitgliedschaft" -#: apps/member/models.py:222 +#: apps/member/models.py:221 msgid "Uncheck if this club don't require memberships." msgstr "" "Deaktivieren Sie diese Option, wenn für diesen Club keine Mitgliedschaft " "erforderlich ist." -#: apps/member/models.py:238 +#: apps/member/models.py:237 #: apps/member/templates/member/includes/club_info.html:26 msgid "membership duration" msgstr "Mitgliedscahftzeit" -#: apps/member/models.py:239 +#: apps/member/models.py:238 msgid "The longest time (in days) a membership can last (NULL = infinite)." msgstr "Wie lang am höchsten eine Mitgliedschaft dauern kann." -#: apps/member/models.py:246 +#: apps/member/models.py:245 #: apps/member/templates/member/includes/club_info.html:16 msgid "membership start" msgstr "Mitgliedschaftanfangsdatum" -#: apps/member/models.py:247 +#: apps/member/models.py:246 msgid "Date from which the members can renew their membership." msgstr "Ab wann kann man sein Mitgliedschaft erneuern." -#: apps/member/models.py:253 +#: apps/member/models.py:252 #: apps/member/templates/member/includes/club_info.html:21 msgid "membership end" msgstr "Mitgliedschaftenddatum" -#: apps/member/models.py:254 +#: apps/member/models.py:253 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:286 apps/member/models.py:311 +#: apps/member/models.py:285 apps/member/models.py:310 #: apps/note/models/notes.py:185 msgid "club" msgstr "Club" -#: apps/member/models.py:287 +#: apps/member/models.py:286 msgid "clubs" msgstr "Clubs" -#: apps/member/models.py:321 +#: apps/member/models.py:320 msgid "membership starts on" msgstr "Mitgliedschaft fängt an" -#: apps/member/models.py:325 +#: apps/member/models.py:324 msgid "membership ends on" msgstr "Mitgliedschaft endet am" -#: apps/member/models.py:375 +#: apps/member/models.py:419 #, 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:384 apps/member/views.py:651 +#: apps/member/models.py:428 apps/member/views.py:628 msgid "User is already a member of the club" msgstr "User ist schon ein Mitglied dieser club" -#: apps/member/models.py:432 +#: apps/member/models.py:440 msgid "User is not a member of the parent club" msgstr "User ist noch nicht Mitglied des Urclubs" -#: apps/member/models.py:480 +#: apps/member/models.py:488 #, python-brace-format msgid "Membership of {user} for the club {club}" msgstr "Mitgliedschaft von {user} für das Club {club}" -#: apps/member/models.py:483 apps/note/models/transactions.py:360 +#: apps/member/models.py:491 apps/note/models/transactions.py:353 msgid "membership" msgstr "Mitgliedschaft" -#: apps/member/models.py:484 +#: apps/member/models.py:492 msgid "memberships" msgstr "Mitgliedschaften" @@ -907,7 +926,7 @@ msgstr "" #: apps/member/templates/member/club_alias.html:10 #: apps/member/templates/member/profile_alias.html:10 apps/member/views.py:236 -#: apps/member/views.py:425 +#: apps/member/views.py:433 msgid "Note aliases" msgstr "Note Aliases" @@ -1058,31 +1077,31 @@ msgstr "User finden" msgid "Update note picture" msgstr "Notebild ändern" -#: apps/member/views.py:293 +#: apps/member/views.py:301 msgid "Manage auth token" msgstr "Auth token bearbeiten" -#: apps/member/views.py:320 +#: apps/member/views.py:328 msgid "Create new club" msgstr "Neue Club" -#: apps/member/views.py:339 +#: apps/member/views.py:347 msgid "Search club" msgstr "Club finden" -#: apps/member/views.py:372 +#: apps/member/views.py:380 msgid "Club detail" msgstr "Club Details" -#: apps/member/views.py:448 +#: apps/member/views.py:456 msgid "Update club" msgstr "Club bearbeiten" -#: apps/member/views.py:482 +#: apps/member/views.py:490 msgid "Add new member to the club" msgstr "Neue Mitglieder" -#: apps/member/views.py:642 apps/wei/views.py:922 +#: apps/member/views.py:619 apps/wei/views.py:922 msgid "" "This user don't have enough money to join this club, and can't have a " "negative balance." @@ -1090,44 +1109,44 @@ msgstr "" "Diese User hat nicht genug Geld um Mitglied zu werden, und darf nich im Rot " "sein." -#: apps/member/views.py:655 +#: apps/member/views.py:632 msgid "The membership must start after {:%m-%d-%Y}." msgstr "Die Mitgliedschaft muss nach {:%m-%d-Y} anfängen." -#: apps/member/views.py:660 +#: apps/member/views.py:637 msgid "The membership must begin before {:%m-%d-%Y}." msgstr "Die Mitgliedschaft muss vor {:%m-%d-Y} anfängen." -#: apps/member/views.py:676 apps/member/views.py:678 apps/member/views.py:680 +#: apps/member/views.py:644 apps/member/views.py:646 apps/member/views.py:648 #: apps/registration/views.py:287 apps/registration/views.py:289 #: apps/registration/views.py:291 apps/wei/views.py:927 apps/wei/views.py:931 msgid "This field is required." msgstr "Dies ist ein Pflichtfeld." -#: apps/member/views.py:753 +#: apps/member/views.py:783 msgid "Manage roles of an user in the club" msgstr "Rollen in diesen Club bearbeiten" -#: apps/member/views.py:778 +#: apps/member/views.py:808 msgid "Members of the club" msgstr "Mitlglieder dieses Club" -#: apps/note/admin.py:129 apps/note/models/transactions.py:106 +#: apps/note/admin.py:129 apps/note/models/transactions.py:109 msgid "source" msgstr "Sender" #: apps/note/admin.py:137 apps/note/admin.py:205 -#: apps/note/models/transactions.py:56 apps/note/models/transactions.py:119 +#: apps/note/models/transactions.py:56 apps/note/models/transactions.py:122 msgid "destination" msgstr "Empfänger" #: apps/note/admin.py:210 apps/note/models/transactions.py:60 -#: apps/note/models/transactions.py:137 +#: apps/note/models/transactions.py:140 msgid "amount" msgstr "Anzahl" #: apps/note/api/serializers.py:183 apps/note/api/serializers.py:189 -#: apps/note/models/transactions.py:224 +#: apps/note/models/transactions.py:226 msgid "" "The transaction can't be saved since the source note or the destination note " "is not active." @@ -1187,7 +1206,7 @@ msgstr "letztes mal im Rot" msgid "display image" msgstr "Bild" -#: apps/note/models/notes.py:54 apps/note/models/transactions.py:129 +#: apps/note/models/notes.py:54 apps/note/models/transactions.py:132 msgid "created at" msgstr "erschafft am" @@ -1312,33 +1331,33 @@ msgstr "Transaktionsvorlage" msgid "transaction templates" msgstr "Transaktionsvorlagen" -#: apps/note/models/transactions.py:112 apps/note/models/transactions.py:125 +#: apps/note/models/transactions.py:115 apps/note/models/transactions.py:128 #: apps/note/tables.py:34 apps/note/tables.py:44 msgid "used alias" msgstr "benutzte Aliasen" -#: apps/note/models/transactions.py:133 +#: apps/note/models/transactions.py:136 msgid "quantity" msgstr "Anzahl" -#: apps/note/models/transactions.py:141 +#: apps/note/models/transactions.py:144 msgid "reason" msgstr "Grund" -#: apps/note/models/transactions.py:151 apps/note/tables.py:140 +#: apps/note/models/transactions.py:154 apps/note/tables.py:140 msgid "invalidity reason" msgstr "Ungültigkeit Grund" -#: apps/note/models/transactions.py:159 +#: apps/note/models/transactions.py:161 msgid "transaction" msgstr "Transaktion" -#: apps/note/models/transactions.py:160 +#: apps/note/models/transactions.py:162 #: apps/treasury/templates/treasury/sogecredit_detail.html:22 msgid "transactions" msgstr "Transaktionen" -#: apps/note/models/transactions.py:182 +#: apps/note/models/transactions.py:184 #, python-brace-format msgid "" "You can't update the {field} on a Transaction. Please invalidate it and " @@ -1347,7 +1366,7 @@ msgstr "" "Sie können das {field} einer Transaktion nicht aktualisieren. Bitte machen " "Sie es ungültig und erstellen Sie eine andere." -#: apps/note/models/transactions.py:202 +#: apps/note/models/transactions.py:204 msgid "" "The note balances must be between - 92 233 720 368 547 758.08 € and 92 233 " "720 368 547 758.07 €." @@ -1355,34 +1374,34 @@ msgstr "" "Die Notenguthaben müssen zwischen - 92 233 720 368 547 758,08 € und 92 233 " "720 368 547 758,07 € liegen." -#: apps/note/models/transactions.py:280 +#: apps/note/models/transactions.py:273 msgid "" "The destination of this transaction must equal to the destination of the " "template." msgstr "" "Der Empfänger dieser Transaktion muss dem Empfänger der Vorlage entsprechen." -#: apps/note/models/transactions.py:289 +#: apps/note/models/transactions.py:282 msgid "Template" msgstr "Vorlage" -#: apps/note/models/transactions.py:292 +#: apps/note/models/transactions.py:285 msgid "recurrent transaction" msgstr "wiederkehrende Transaktion" -#: apps/note/models/transactions.py:293 +#: apps/note/models/transactions.py:286 msgid "recurrent transactions" msgstr "wiederkehrende Transaktionen" -#: apps/note/models/transactions.py:308 +#: apps/note/models/transactions.py:301 msgid "first_name" msgstr "Vorname" -#: apps/note/models/transactions.py:313 +#: apps/note/models/transactions.py:306 msgid "bank" msgstr "Bank" -#: apps/note/models/transactions.py:330 +#: apps/note/models/transactions.py:323 msgid "" "A special transaction is only possible between a Note associated to a " "payment method and a User or a Club" @@ -1390,19 +1409,19 @@ msgstr "" "Eine Sondertransaktion ist nur zwischen einer Note, die einer " "Zahlungsmethode zugeordnet ist, und einem User oder einem Club möglich" -#: apps/note/models/transactions.py:338 +#: apps/note/models/transactions.py:331 msgid "Special transaction" msgstr "Sondertransaktion" -#: apps/note/models/transactions.py:339 +#: apps/note/models/transactions.py:332 msgid "Special transactions" msgstr "Sondertranskationen" -#: apps/note/models/transactions.py:355 +#: apps/note/models/transactions.py:348 msgid "membership transaction" msgstr "Mitgliedschafttransaktion" -#: apps/note/models/transactions.py:356 apps/treasury/models.py:273 +#: apps/note/models/transactions.py:349 apps/treasury/models.py:282 msgid "membership transactions" msgstr "Mitgliedschaftttransaktionen" @@ -1474,7 +1493,8 @@ msgstr "Verlauf der letzten Transaktionen" #: apps/note/templates/note/mails/negative_balance.txt:25 #: apps/note/templates/note/mails/negative_notes_report.html:46 #: apps/note/templates/note/mails/negative_notes_report.txt:13 -#: apps/note/templates/note/mails/weekly_report.html:54 +#: apps/note/templates/note/mails/weekly_report.html:51 +#: apps/note/templates/note/mails/weekly_report.txt:32 #: apps/registration/templates/registration/mails/email_validation_email.html:40 #: apps/registration/templates/registration/mails/email_validation_email.txt:16 msgid "Mail generated by the Note Kfet on the" @@ -1574,7 +1594,7 @@ msgstr "Tatsen finden" msgid "Update button" msgstr "Tatse bearbeiten" -#: apps/note/views.py:151 note_kfet/templates/base.html:63 +#: apps/note/views.py:151 note_kfet/templates/base.html:64 msgid "Consumptions" msgstr "Verbräuche" @@ -1683,7 +1703,7 @@ msgstr "" "Sie haben nicht die Berechtigung, eine Instanz von model {app_label}. " "{model_name} hinzufügen." -#: apps/permission/signals.py:101 +#: apps/permission/signals.py:102 #, python-brace-format msgid "" "You don't have the permission to delete this instance of model {app_label}." @@ -1752,7 +1772,7 @@ msgstr "" "diesen Parametern zu erstellen. Bitte korrigieren Sie Ihre Daten und " "versuchen Sie es erneut." -#: apps/permission/views.py:96 note_kfet/templates/base.html:105 +#: apps/permission/views.py:96 note_kfet/templates/base.html:106 msgid "Rights" msgstr "Rechten" @@ -1789,23 +1809,23 @@ msgstr "BDE Mitglieder werden" msgid "Join Kfet Club" msgstr "Kfet Mitglieder werden" -#: apps/registration/templates/registration/email_validation_complete.html:9 +#: apps/registration/templates/registration/email_validation_complete.html:15 msgid "Your email have successfully been validated." msgstr "Ihre E-Mail wurde erfolgreich validiert." -#: apps/registration/templates/registration/email_validation_complete.html:11 +#: apps/registration/templates/registration/email_validation_complete.html:19 #, python-format msgid "You can now log in." msgstr "Sie können sich jetz anmelden ." -#: apps/registration/templates/registration/email_validation_complete.html:13 +#: apps/registration/templates/registration/email_validation_complete.html:23 msgid "" "You must pay now your membership in the Kfet to complete your registration." msgstr "" "Sie müssen jetzt Ihre Mitgliedschaft im Kfet bezahlen, um Ihre Registrierung " "abzuschließen." -#: apps/registration/templates/registration/email_validation_complete.html:16 +#: apps/registration/templates/registration/email_validation_complete.html:28 msgid "" "The link was invalid. The token may have expired. Please send us an email to " "activate your account." @@ -1813,24 +1833,20 @@ msgstr "" "Der Link war ungültig. Das Token ist möglicherweise abgelaufen. Bitte senden " "Sie uns eine E-Mail, um Ihr Konto zu aktivieren." -#: apps/registration/templates/registration/email_validation_email_sent.html:8 +#: apps/registration/templates/registration/email_validation_email_sent.html:10 msgid "Account activation" msgstr "Kontoaktivierung" -#: apps/registration/templates/registration/email_validation_email_sent.html:11 +#: apps/registration/templates/registration/email_validation_email_sent.html:14 msgid "" "An email has been sent. Please click on the link to activate your account." msgstr "" "Eine E-Mail wurde gesendet. Bitte klicken Sie auf den Link, um Ihr Konto zu " "aktivieren." -#: apps/registration/templates/registration/email_validation_email_sent.html:15 -msgid "" -"You must also go to the Kfet to pay your membership. The WEI registration " -"includes the BDE membership." -msgstr "" -"Sie müssen auch zum Kfet gehen, um Ihre Mitgliedschaft zu bezahlen. Die WEI-" -"Registrierung beinhaltet die BDE-Mitgliedschaft." +#: apps/registration/templates/registration/email_validation_email_sent.html:17 +msgid "You must also go to the Kfet to pay your membership." +msgstr "Sie müssen auch zum Kfet gehen, um Ihre Mitgliedschaft zu bezahlen." #: apps/registration/templates/registration/future_profile_detail.html:49 #: apps/wei/templates/wei/weiregistration_confirm_delete.html:11 @@ -1878,12 +1894,10 @@ msgstr "" #: apps/registration/templates/registration/mails/email_validation_email.txt:11 msgid "" "After that, you'll have to wait that someone validates your account before " -"you can log in. You will need to pay your membership in the Kfet. Note that " -"the WEI registration includes the Kfet membership." +"you can log in. You will need to pay your membership in the Kfet." msgstr "" "Danach müssen Sie warten, bis jemand Ihr Konto validiert, bevor Sie sich " -"anmelden können. Sie müssen Ihre Mitgliedschaft im Kfet bezahlen. Beachten " -"Sie, dass die WEI-Registrierung die Kfet-Mitgliedschaft enthält." +"anmelden können. Sie müssen Ihre Mitgliedschaft im Kfet bezahlen." #: apps/registration/templates/registration/mails/email_validation_email.html:34 #: apps/registration/templates/registration/mails/email_validation_email.txt:13 @@ -1946,7 +1960,7 @@ msgstr "" msgid "Invalidate pre-registration" msgstr "Ungültige Vorregistrierung" -#: apps/treasury/apps.py:12 note_kfet/templates/base.html:93 +#: apps/treasury/apps.py:12 note_kfet/templates/base.html:94 msgid "Treasury" msgstr "Quaestor" @@ -1963,7 +1977,7 @@ msgstr "Überweisung ist bereits geschlossen." msgid "You can't change the type of the remittance." msgstr "Sie können die Art der Überweisung nicht ändern." -#: apps/treasury/forms.py:123 apps/treasury/models.py:252 +#: apps/treasury/forms.py:123 apps/treasury/models.py:258 #: apps/treasury/tables.py:97 apps/treasury/tables.py:105 #: apps/treasury/templates/treasury/invoice_list.html:16 #: apps/treasury/templates/treasury/remittance_list.html:16 @@ -1995,7 +2009,7 @@ msgstr "Beschreibung" msgid "Address" msgstr "Adresse" -#: apps/treasury/models.py:60 apps/treasury/models.py:180 +#: apps/treasury/models.py:60 apps/treasury/models.py:186 msgid "Date" msgstr "Datum" @@ -2015,7 +2029,7 @@ msgstr "Eine Rechnung kann nicht bearbeitet werden, wenn sie gesperrt ist." msgid "tex source" msgstr "Tex Quelle" -#: apps/treasury/models.py:109 apps/treasury/models.py:122 +#: apps/treasury/models.py:109 apps/treasury/models.py:125 msgid "invoice" msgstr "Rechnung" @@ -2023,67 +2037,72 @@ msgstr "Rechnung" msgid "invoices" msgstr "Rechnungen" -#: apps/treasury/models.py:127 +#: apps/treasury/models.py:113 +#, python-brace-format +msgid "Invoice #{id}" +msgstr "Rechnung #{id}" + +#: apps/treasury/models.py:130 msgid "Designation" msgstr "Bezeichnung" -#: apps/treasury/models.py:131 +#: apps/treasury/models.py:134 msgid "Quantity" msgstr "Qualität" -#: apps/treasury/models.py:135 +#: apps/treasury/models.py:138 msgid "Unit price" msgstr "Einzelpreis" -#: apps/treasury/models.py:151 +#: apps/treasury/models.py:154 msgid "product" msgstr "Produkt" -#: apps/treasury/models.py:152 +#: apps/treasury/models.py:155 msgid "products" msgstr "Produkten" -#: apps/treasury/models.py:169 +#: apps/treasury/models.py:175 msgid "remittance type" msgstr "Überweisungstyp" -#: apps/treasury/models.py:170 +#: apps/treasury/models.py:176 msgid "remittance types" msgstr "Überweisungstypen" -#: apps/treasury/models.py:191 +#: apps/treasury/models.py:197 msgid "Comment" msgstr "Kommentar" -#: apps/treasury/models.py:196 +#: apps/treasury/models.py:202 msgid "Closed" msgstr "Geschlossen" -#: apps/treasury/models.py:200 +#: apps/treasury/models.py:206 msgid "remittance" msgstr "Überweisung" -#: apps/treasury/models.py:201 +#: apps/treasury/models.py:207 msgid "remittances" msgstr "Überweisungen" -#: apps/treasury/models.py:233 +#: apps/treasury/models.py:239 msgid "Remittance #{:d}: {}" msgstr "Überweisung #{:d}:{}" -#: apps/treasury/models.py:256 +#: apps/treasury/models.py:262 msgid "special transaction proxy" msgstr "spezielle Transaktion Proxy" -#: apps/treasury/models.py:257 +#: apps/treasury/models.py:263 msgid "special transaction proxies" msgstr "spezielle Transaktion Proxies" -#: apps/treasury/models.py:279 +#: apps/treasury/models.py:288 msgid "credit transaction" msgstr "Kredit Transaktion" -#: apps/treasury/models.py:343 +#: apps/treasury/models.py:352 msgid "" "This user doesn't have enough money to pay the memberships with its note. " "Please ask her/him to credit the note before invalidating this credit." @@ -2091,15 +2110,20 @@ msgstr "" "Dieser Benutzer hat nicht genug Geld, um die Mitgliedschaften mit seiner " "Note zu bezahlen." -#: apps/treasury/models.py:355 +#: apps/treasury/models.py:364 #: apps/treasury/templates/treasury/sogecredit_detail.html:10 msgid "Credit from the Société générale" msgstr "Kredit von der Société générale" -#: apps/treasury/models.py:356 +#: apps/treasury/models.py:365 msgid "Credits from the Société générale" msgstr "Krediten von der Société générale" +#: apps/treasury/models.py:368 +#, python-brace-format +msgid "Soge credit for {user}" +msgstr "Kredit von der Société générale für {user}" + #: apps/treasury/tables.py:20 msgid "Invoice #{:d}" msgstr "Rechnung #{:d}" @@ -2338,7 +2362,7 @@ msgstr "Krediten von der Société générale handeln" #: apps/wei/apps.py:10 apps/wei/models.py:49 apps/wei/models.py:50 #: apps/wei/models.py:61 apps/wei/models.py:167 -#: note_kfet/templates/base.html:99 +#: note_kfet/templates/base.html:100 msgid "WEI" msgstr "WEI" @@ -2942,23 +2966,46 @@ msgstr "" msgid "Reset" msgstr "Reset" -#: note_kfet/templates/base.html:13 +#: note_kfet/templates/base.html:14 msgid "The ENS Paris-Saclay BDE note." msgstr "Die BDE ENS-Paris-Saclay Note." -#: note_kfet/templates/base.html:75 +#: note_kfet/templates/base.html:76 msgid "Users" msgstr "Users" -#: note_kfet/templates/base.html:81 +#: note_kfet/templates/base.html:82 msgid "Clubs" msgstr "Clubs" -#: note_kfet/templates/base.html:110 +#: note_kfet/templates/base.html:111 msgid "Admin" msgstr "Admin" -#: note_kfet/templates/base.html:154 +#: note_kfet/templates/base.html:125 +msgid "My account" +msgstr "Mein Konto" + +#: note_kfet/templates/base.html:128 +msgid "Log out" +msgstr "Abmelden" + +#: note_kfet/templates/base.html:136 +#: note_kfet/templates/registration/signup.html:6 +#: note_kfet/templates/registration/signup.html:11 +#: note_kfet/templates/registration/signup.html:27 +msgid "Sign up" +msgstr "Registrieren" + +#: note_kfet/templates/base.html:143 +#: note_kfet/templates/registration/login.html:6 +#: note_kfet/templates/registration/login.html:15 +#: note_kfet/templates/registration/login.html:38 +#: note_kfet/templates/registration/password_reset_complete.html:15 +msgid "Log in" +msgstr "Anmelden" + +#: note_kfet/templates/base.html:155 msgid "" "Your e-mail address is not validated. Please check your mail inbox and click " "on the validation link." @@ -2966,6 +3013,10 @@ 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:172 +msgid "Contact us" +msgstr "Kontakt" + #: note_kfet/templates/base_search.html:15 msgid "Search by attribute such as name…" msgstr "Suche nach Attributen wie Name…" @@ -2998,13 +3049,6 @@ msgstr "" msgid "Log in again" msgstr "Nochmal anmelden" -#: note_kfet/templates/registration/login.html:6 -#: note_kfet/templates/registration/login.html:15 -#: note_kfet/templates/registration/login.html:38 -#: note_kfet/templates/registration/password_reset_complete.html:15 -msgid "Log in" -msgstr "Anmelden" - #: note_kfet/templates/registration/login.html:20 #, python-format msgid "" @@ -3096,12 +3140,6 @@ msgstr "" msgid "Reset my password" msgstr "Mein Passwort zurücksetzen" -#: note_kfet/templates/registration/signup.html:6 -#: note_kfet/templates/registration/signup.html:11 -#: note_kfet/templates/registration/signup.html:27 -msgid "Sign up" -msgstr "Registrieren" - #: note_kfet/templates/registration/signup.html:15 msgid "" "If you already signed up, your registration is taken into account. The BDE " diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 1b715643..5e6e2740 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: 2020-09-06 12:32+0200\n" +"POT-Creation-Date: 2020-09-07 19:43+0200\n" "PO-Revision-Date: 2020-09-02 23:18+0200\n" "Last-Translator: \n" "Language-Team: \n" @@ -27,33 +27,33 @@ msgstr "activité" 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:76 apps/activity/models.py:262 +#: apps/activity/forms.py:76 apps/activity/models.py:268 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:79 apps/activity/models.py:265 +#: apps/activity/forms.py:79 apps/activity/models.py:271 msgid "This activity is not validated yet." msgstr "Cette activité n'est pas encore validée." -#: apps/activity/forms.py:89 apps/activity/models.py:273 +#: apps/activity/forms.py:89 apps/activity/models.py:279 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:93 apps/activity/models.py:277 +#: apps/activity/forms.py:93 apps/activity/models.py:283 msgid "This person is already invited." msgstr "Cette personne est déjà invitée." -#: apps/activity/forms.py:97 apps/activity/models.py:281 +#: apps/activity/forms.py:97 apps/activity/models.py:287 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:200 +#: apps/member/models.py:199 #: apps/member/templates/member/includes/club_info.html:4 #: apps/member/templates/member/includes/profile_info.html:4 #: apps/note/models/notes.py:253 apps/note/models/transactions.py:26 -#: apps/note/models/transactions.py:46 apps/note/models/transactions.py:303 +#: apps/note/models/transactions.py:46 apps/note/models/transactions.py:296 #: apps/permission/models.py:329 #: apps/registration/templates/registration/future_profile_detail.html:16 #: apps/wei/models.py:66 apps/wei/models.py:118 @@ -110,8 +110,8 @@ msgstr "Lieu où l'activité est organisée, par exemple la Kfet." msgid "type" msgstr "type" -#: apps/activity/models.py:89 apps/logs/models.py:22 apps/member/models.py:305 -#: apps/note/models/notes.py:144 apps/treasury/models.py:267 +#: apps/activity/models.py:89 apps/logs/models.py:22 apps/member/models.py:304 +#: apps/note/models/notes.py:144 apps/treasury/models.py:276 #: apps/treasury/templates/treasury/sogecredit_detail.html:14 #: apps/wei/models.py:160 apps/wei/templates/wei/survey.html:15 msgid "user" @@ -149,7 +149,7 @@ msgstr "date de fin" #: apps/activity/models.py:118 #: apps/activity/templates/activity/includes/activity_info.html:50 -#: apps/note/models/transactions.py:146 +#: apps/note/models/transactions.py:149 msgid "valid" msgstr "valide" @@ -181,42 +181,52 @@ msgstr "entrée" msgid "entries" msgstr "entrées" -#: apps/activity/models.py:195 +#: apps/activity/models.py:192 +#, python-brace-format +msgid "Entry for {guest}, invited by {note} to the activity {activity}" +msgstr "Entrée pour {guest}, invité par {note} à l'activité {activity}" + +#: apps/activity/models.py:194 +#, 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:201 msgid "Already entered on " msgstr "Déjà rentré le " -#: apps/activity/models.py:195 apps/activity/tables.py:54 +#: apps/activity/models.py:201 apps/activity/tables.py:54 msgid "{:%Y-%m-%d %H:%M:%S}" msgstr "{:%d/%m/%Y %H:%M:%S}" -#: apps/activity/models.py:203 +#: apps/activity/models.py:209 msgid "The balance is negative." msgstr "La note est en négatif." -#: apps/activity/models.py:233 +#: apps/activity/models.py:239 msgid "last name" msgstr "nom de famille" -#: apps/activity/models.py:238 +#: apps/activity/models.py:244 #: apps/member/templates/member/includes/profile_info.html:4 #: apps/registration/templates/registration/future_profile_detail.html:16 #: apps/wei/templates/wei/weimembership_form.html:14 msgid "first name" msgstr "prénom" -#: apps/activity/models.py:245 +#: apps/activity/models.py:251 msgid "inviter" msgstr "hôte" -#: apps/activity/models.py:289 +#: apps/activity/models.py:295 msgid "guest" msgstr "invité" -#: apps/activity/models.py:290 +#: apps/activity/models.py:296 msgid "guests" msgstr "invités" -#: apps/activity/models.py:302 +#: apps/activity/models.py:308 msgid "Invitation" msgstr "Invitation" @@ -240,17 +250,17 @@ msgstr "Entré le " msgid "remove" msgstr "supprimer" -#: apps/activity/tables.py:80 apps/note/forms.py:68 apps/treasury/models.py:186 +#: apps/activity/tables.py:80 apps/note/forms.py:68 apps/treasury/models.py:192 msgid "Type" msgstr "Type" -#: apps/activity/tables.py:82 apps/member/forms.py:167 +#: apps/activity/tables.py:82 apps/member/forms.py:183 #: apps/registration/forms.py:81 apps/treasury/forms.py:129 #: apps/wei/forms/registration.py:96 msgid "Last name" msgstr "Nom de famille" -#: apps/activity/tables.py:84 apps/member/forms.py:172 +#: apps/activity/tables.py:84 apps/member/forms.py:188 #: apps/note/templates/note/transaction_form.html:134 #: apps/registration/forms.py:86 apps/treasury/forms.py:131 #: apps/wei/forms/registration.py:101 @@ -270,21 +280,21 @@ msgid "Guests list" msgstr "Liste des invités" #: apps/activity/templates/activity/activity_entry.html:14 -#: apps/note/models/transactions.py:260 +#: apps/note/models/transactions.py:253 #: apps/note/templates/note/transaction_form.html:16 #: apps/note/templates/note/transaction_form.html:148 -#: note_kfet/templates/base.html:69 +#: note_kfet/templates/base.html:70 msgid "Transfer" msgstr "Virement" #: apps/activity/templates/activity/activity_entry.html:18 -#: apps/note/models/transactions.py:319 +#: apps/note/models/transactions.py:312 #: apps/note/templates/note/transaction_form.html:21 msgid "Credit" msgstr "Crédit" #: apps/activity/templates/activity/activity_entry.html:21 -#: apps/note/models/transactions.py:319 +#: apps/note/models/transactions.py:312 #: apps/note/templates/note/transaction_form.html:25 msgid "Debit" msgstr "Débit" @@ -356,7 +366,7 @@ msgid "validate" msgstr "valider" #: apps/activity/templates/activity/includes/activity_info.html:71 -#: apps/logs/models.py:62 apps/note/tables.py:195 +#: apps/logs/models.py:64 apps/note/tables.py:195 msgid "edit" msgstr "modifier" @@ -368,7 +378,7 @@ msgstr "Inviter" msgid "Create new activity" msgstr "Créer une nouvelle activité" -#: apps/activity/views.py:63 note_kfet/templates/base.html:87 +#: apps/activity/views.py:63 note_kfet/templates/base.html:88 msgid "Activities" msgstr "Activités" @@ -422,59 +432,64 @@ msgstr "modèle" msgid "identifier" msgstr "identifiant" -#: apps/logs/models.py:48 +#: apps/logs/models.py:49 msgid "previous data" msgstr "données précédentes" -#: apps/logs/models.py:53 +#: apps/logs/models.py:55 msgid "new data" msgstr "ouvelles données" -#: apps/logs/models.py:61 +#: apps/logs/models.py:63 msgid "create" msgstr "créer" -#: apps/logs/models.py:63 apps/note/tables.py:165 apps/note/tables.py:201 +#: apps/logs/models.py:65 apps/note/tables.py:165 apps/note/tables.py:201 #: apps/permission/models.py:127 apps/treasury/tables.py:38 #: apps/wei/tables.py:75 msgid "delete" msgstr "supprimer" -#: apps/logs/models.py:66 +#: apps/logs/models.py:68 msgid "action" msgstr "action" -#: apps/logs/models.py:74 +#: apps/logs/models.py:76 msgid "timestamp" msgstr "date" -#: apps/logs/models.py:78 +#: apps/logs/models.py:80 msgid "Logs cannot be destroyed." msgstr "Les logs ne peuvent pas être détruits." -#: apps/logs/models.py:81 +#: apps/logs/models.py:83 msgid "changelog" msgstr "journal de modification" -#: apps/logs/models.py:82 +#: apps/logs/models.py:84 msgid "changelogs" msgstr "journaux de modifications" -#: apps/member/admin.py:50 apps/member/models.py:227 +#: apps/logs/models.py:87 +#, python-brace-format +msgid "Changelog of type \"{action}\" for model {model} at {timestamp}" +msgstr "Changelog de type « {action} » pour le modèle {model} à {timestamp}" + +#: apps/member/admin.py:50 apps/member/models.py:226 #: apps/member/templates/member/includes/club_info.html:34 msgid "membership fee (paid students)" msgstr "cotisation pour adhérer (normalien élève)" -#: apps/member/admin.py:51 apps/member/models.py:232 +#: apps/member/admin.py:51 apps/member/models.py:231 #: apps/member/templates/member/includes/club_info.html:37 msgid "membership fee (unpaid students)" msgstr "cotisation pour adhérer (normalien étudiant)" -#: apps/member/admin.py:65 apps/member/models.py:316 +#: apps/member/admin.py:65 apps/member/models.py:315 msgid "roles" msgstr "rôles" -#: apps/member/admin.py:66 apps/member/models.py:330 +#: apps/member/admin.py:66 apps/member/models.py:329 msgid "fee" msgstr "cotisation" @@ -482,6 +497,10 @@ msgstr "cotisation" msgid "member" msgstr "adhérent" +#: apps/member/forms.py:23 +msgid "Permission mask" +msgstr "Masque de permissions" + #: apps/member/forms.py:45 msgid "Report frequency" msgstr "Fréquence des rapports (en jours)" @@ -502,53 +521,53 @@ msgstr "choisissez une image" msgid "Maximal size: 2MB" msgstr "Taille maximale : 2 Mo" -#: apps/member/forms.py:97 +#: apps/member/forms.py:103 msgid "This image cannot be loaded." msgstr "Cette image ne peut pas être chargée." -#: apps/member/forms.py:123 apps/member/views.py:98 +#: apps/member/forms.py:139 apps/member/views.py:98 #: apps/registration/forms.py:33 apps/registration/views.py:237 msgid "An alias with a similar name already exists." msgstr "Un alias avec un nom similaire existe déjà." -#: apps/member/forms.py:146 apps/registration/forms.py:61 +#: apps/member/forms.py:162 apps/registration/forms.py:61 msgid "Inscription paid by Société Générale" msgstr "Inscription payée par la Société générale" -#: apps/member/forms.py:148 apps/registration/forms.py:63 +#: apps/member/forms.py:164 apps/registration/forms.py:63 msgid "Check this case is 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:153 apps/registration/forms.py:68 +#: apps/member/forms.py:169 apps/registration/forms.py:68 #: apps/wei/forms/registration.py:83 msgid "Credit type" msgstr "Type de rechargement" -#: apps/member/forms.py:154 apps/registration/forms.py:69 +#: apps/member/forms.py:170 apps/registration/forms.py:69 #: apps/wei/forms/registration.py:84 msgid "No credit" msgstr "Pas de rechargement" -#: apps/member/forms.py:156 +#: apps/member/forms.py:172 msgid "You can credit the note of the user." msgstr "Vous pouvez créditer la note de l'utisateur avant l'adhésion." -#: apps/member/forms.py:160 apps/registration/forms.py:74 +#: apps/member/forms.py:176 apps/registration/forms.py:74 #: apps/wei/forms/registration.py:89 msgid "Credit amount" msgstr "Montant à créditer" -#: apps/member/forms.py:177 apps/note/templates/note/transaction_form.html:140 +#: apps/member/forms.py:193 apps/note/templates/note/transaction_form.html:140 #: apps/registration/forms.py:91 apps/treasury/forms.py:133 #: apps/wei/forms/registration.py:106 msgid "Bank" msgstr "Banque" -#: apps/member/forms.py:204 +#: apps/member/forms.py:220 msgid "User" msgstr "Utilisateur" -#: apps/member/forms.py:218 +#: apps/member/forms.py:234 msgid "Roles" msgstr "Rôles" @@ -664,19 +683,19 @@ msgstr "payé" msgid "Tells if the user receive a salary." msgstr "Indique si l'utilisateur perçoit un salaire." -#: apps/member/models.py:101 apps/treasury/tables.py:146 +#: apps/member/models.py:100 apps/treasury/tables.py:146 msgid "No" msgstr "Non" -#: apps/member/models.py:102 +#: apps/member/models.py:101 msgid "Yes (receive them in french)" msgstr "Oui (les recevoir en français)" -#: apps/member/models.py:103 +#: apps/member/models.py:102 msgid "Yes (receive them in english)" msgstr "Oui (les recevoir en anglais)" -#: apps/member/models.py:105 +#: apps/member/models.py:104 msgid "" "Register on the mailing list to stay informed of the events of the campus (1 " "mail/week)" @@ -684,7 +703,7 @@ msgstr "" "S'inscrire sur la liste de diffusion pour rester informé des événements sur " "le campus (1 mail par semaine)" -#: apps/member/models.py:110 +#: apps/member/models.py:109 msgid "" "Register on the mailing list to stay informed of the sport events of the " "campus (1 mail/week)" @@ -692,7 +711,7 @@ msgstr "" "S'inscrire sur la liste de diffusion pour rester informé des actualités " "sportives sur le campus (1 mail par semaine)" -#: apps/member/models.py:115 +#: apps/member/models.py:114 msgid "" "Register on the mailing list to stay informed of the art events of the " "campus (1 mail/week)" @@ -700,31 +719,31 @@ msgstr "" "S'inscrire sur la liste de diffusion pour rester informé des actualités " "artistiques sur le campus (1 mail par semaine)" -#: apps/member/models.py:119 +#: apps/member/models.py:118 msgid "report frequency (in days)" msgstr "fréquence des rapports (en jours)" -#: apps/member/models.py:124 +#: apps/member/models.py:123 msgid "last report date" msgstr "date de dernier rapport" -#: apps/member/models.py:129 +#: apps/member/models.py:128 msgid "email confirmed" msgstr "adresse email confirmée" -#: apps/member/models.py:134 +#: apps/member/models.py:133 msgid "registration valid" msgstr "inscription valide" -#: apps/member/models.py:163 apps/member/models.py:164 +#: apps/member/models.py:162 apps/member/models.py:163 msgid "user profile" msgstr "profil utilisateur" -#: apps/member/models.py:174 +#: apps/member/models.py:173 msgid "Activate your Note Kfet account" msgstr "Activez votre compte Note Kfet" -#: apps/member/models.py:205 +#: apps/member/models.py:204 #: apps/member/templates/member/includes/club_info.html:55 #: apps/member/templates/member/includes/profile_info.html:31 #: apps/registration/templates/registration/future_profile_detail.html:22 @@ -733,88 +752,88 @@ msgstr "Activez votre compte Note Kfet" msgid "email" msgstr "courriel" -#: apps/member/models.py:212 +#: apps/member/models.py:211 msgid "parent club" msgstr "club parent" -#: apps/member/models.py:221 +#: apps/member/models.py:220 msgid "require memberships" msgstr "nécessite des adhésions" -#: apps/member/models.py:222 +#: apps/member/models.py:221 msgid "Uncheck if this club don't require memberships." msgstr "Décochez si ce club n'utilise pas d'adhésions." -#: apps/member/models.py:238 +#: apps/member/models.py:237 #: apps/member/templates/member/includes/club_info.html:26 msgid "membership duration" msgstr "durée de l'adhésion" -#: apps/member/models.py:239 +#: apps/member/models.py:238 msgid "The longest time (in days) a membership can last (NULL = infinite)." msgstr "La durée maximale (en jours) d'une adhésion (NULL = infinie)." -#: apps/member/models.py:246 +#: apps/member/models.py:245 #: apps/member/templates/member/includes/club_info.html:16 msgid "membership start" msgstr "début de l'adhésion" -#: apps/member/models.py:247 +#: apps/member/models.py:246 msgid "Date from which the members can renew their membership." msgstr "" "Date à partir de laquelle les adhérents peuvent renouveler leur adhésion." -#: apps/member/models.py:253 +#: apps/member/models.py:252 #: apps/member/templates/member/includes/club_info.html:21 msgid "membership end" msgstr "fin de l'adhésion" -#: apps/member/models.py:254 +#: apps/member/models.py:253 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érents doivent la " "renouveler." -#: apps/member/models.py:286 apps/member/models.py:311 +#: apps/member/models.py:285 apps/member/models.py:310 #: apps/note/models/notes.py:185 msgid "club" msgstr "club" -#: apps/member/models.py:287 +#: apps/member/models.py:286 msgid "clubs" msgstr "clubs" -#: apps/member/models.py:321 +#: apps/member/models.py:320 msgid "membership starts on" msgstr "l'adhésion commence le" -#: apps/member/models.py:325 +#: apps/member/models.py:324 msgid "membership ends on" msgstr "l'adhésion finit le" -#: apps/member/models.py:375 +#: apps/member/models.py:419 #, python-brace-format 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:384 apps/member/views.py:651 +#: apps/member/models.py:428 apps/member/views.py:628 msgid "User is already a member of the club" msgstr "L'utilisateur est déjà membre du club" -#: apps/member/models.py:432 +#: apps/member/models.py:440 msgid "User is not a member of the parent club" msgstr "L'utilisateur n'est pas membre du club parent" -#: apps/member/models.py:480 +#: apps/member/models.py:488 #, python-brace-format msgid "Membership of {user} for the club {club}" msgstr "Adhésion de {user} pour le club {club}" -#: apps/member/models.py:483 apps/note/models/transactions.py:360 +#: apps/member/models.py:491 apps/note/models/transactions.py:353 msgid "membership" msgstr "adhésion" -#: apps/member/models.py:484 +#: apps/member/models.py:492 msgid "memberships" msgstr "adhésions" @@ -909,7 +928,7 @@ msgstr "" #: apps/member/templates/member/club_alias.html:10 #: apps/member/templates/member/profile_alias.html:10 apps/member/views.py:236 -#: apps/member/views.py:425 +#: apps/member/views.py:433 msgid "Note aliases" msgstr "Alias de la note" @@ -1060,31 +1079,31 @@ msgstr "Chercher un utilisateur" msgid "Update note picture" msgstr "Modifier la photo de la note" -#: apps/member/views.py:293 +#: apps/member/views.py:301 msgid "Manage auth token" msgstr "Gérer les jetons d'authentification" -#: apps/member/views.py:320 +#: apps/member/views.py:328 msgid "Create new club" msgstr "Créer un nouveau club" -#: apps/member/views.py:339 +#: apps/member/views.py:347 msgid "Search club" msgstr "Chercher un club" -#: apps/member/views.py:372 +#: apps/member/views.py:380 msgid "Club detail" msgstr "Détails du club" -#: apps/member/views.py:448 +#: apps/member/views.py:456 msgid "Update club" msgstr "Modifier le club" -#: apps/member/views.py:482 +#: apps/member/views.py:490 msgid "Add new member to the club" msgstr "Ajouter un nouveau membre au club" -#: apps/member/views.py:642 apps/wei/views.py:922 +#: apps/member/views.py:619 apps/wei/views.py:922 msgid "" "This user don't have enough money to join this club, and can't have a " "negative balance." @@ -1092,44 +1111,44 @@ msgstr "" "Cet utilisateur n'a pas assez d'argent pour rejoindre ce club et ne peut pas " "avoir un solde négatif." -#: apps/member/views.py:655 +#: apps/member/views.py:632 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:660 +#: apps/member/views.py:637 msgid "The membership must begin before {:%m-%d-%Y}." msgstr "L'adhésion doit commencer avant le {:%d/%m/%Y}." -#: apps/member/views.py:676 apps/member/views.py:678 apps/member/views.py:680 +#: apps/member/views.py:644 apps/member/views.py:646 apps/member/views.py:648 #: apps/registration/views.py:287 apps/registration/views.py:289 #: apps/registration/views.py:291 apps/wei/views.py:927 apps/wei/views.py:931 msgid "This field is required." msgstr "Ce champ est requis." -#: apps/member/views.py:753 +#: apps/member/views.py:783 msgid "Manage roles of an user in the club" msgstr "Gérer les rôles d'un utilisateur dans le club" -#: apps/member/views.py:778 +#: apps/member/views.py:808 msgid "Members of the club" msgstr "Membres du club" -#: apps/note/admin.py:129 apps/note/models/transactions.py:106 +#: apps/note/admin.py:129 apps/note/models/transactions.py:109 msgid "source" msgstr "source" #: apps/note/admin.py:137 apps/note/admin.py:205 -#: apps/note/models/transactions.py:56 apps/note/models/transactions.py:119 +#: apps/note/models/transactions.py:56 apps/note/models/transactions.py:122 msgid "destination" msgstr "destination" #: apps/note/admin.py:210 apps/note/models/transactions.py:60 -#: apps/note/models/transactions.py:137 +#: apps/note/models/transactions.py:140 msgid "amount" msgstr "montant" #: apps/note/api/serializers.py:183 apps/note/api/serializers.py:189 -#: apps/note/models/transactions.py:224 +#: apps/note/models/transactions.py:226 msgid "" "The transaction can't be saved since the source note or the destination note " "is not active." @@ -1189,7 +1208,7 @@ msgstr "dernier instant où la note était en négatif" msgid "display image" msgstr "image affichée" -#: apps/note/models/notes.py:54 apps/note/models/transactions.py:129 +#: apps/note/models/notes.py:54 apps/note/models/transactions.py:132 msgid "created at" msgstr "créée le" @@ -1315,33 +1334,33 @@ msgstr "modèle de transaction" msgid "transaction templates" msgstr "modèles de transaction" -#: apps/note/models/transactions.py:112 apps/note/models/transactions.py:125 +#: apps/note/models/transactions.py:115 apps/note/models/transactions.py:128 #: apps/note/tables.py:34 apps/note/tables.py:44 msgid "used alias" msgstr "alias utilisé" -#: apps/note/models/transactions.py:133 +#: apps/note/models/transactions.py:136 msgid "quantity" msgstr "quantité" -#: apps/note/models/transactions.py:141 +#: apps/note/models/transactions.py:144 msgid "reason" msgstr "raison" -#: apps/note/models/transactions.py:151 apps/note/tables.py:140 +#: apps/note/models/transactions.py:154 apps/note/tables.py:140 msgid "invalidity reason" msgstr "motif d'invalidité" -#: apps/note/models/transactions.py:159 +#: apps/note/models/transactions.py:161 msgid "transaction" msgstr "transaction" -#: apps/note/models/transactions.py:160 +#: apps/note/models/transactions.py:162 #: apps/treasury/templates/treasury/sogecredit_detail.html:22 msgid "transactions" msgstr "transactions" -#: apps/note/models/transactions.py:182 +#: apps/note/models/transactions.py:184 #, python-brace-format msgid "" "You can't update the {field} on a Transaction. Please invalidate it and " @@ -1350,7 +1369,7 @@ msgstr "" "Vous ne pouvez pas mettre à jour le champ {field} dans une transaction. " "Merci de l'invalider et d'en créer une autre." -#: apps/note/models/transactions.py:202 +#: apps/note/models/transactions.py:204 msgid "" "The note balances must be between - 92 233 720 368 547 758.08 € and 92 233 " "720 368 547 758.07 €." @@ -1359,7 +1378,7 @@ msgstr "" "€ et 92 233 720 368 547 758.07 €. Ne cherchez pas à capitaliser l'argent du " "BDE." -#: apps/note/models/transactions.py:280 +#: apps/note/models/transactions.py:273 msgid "" "The destination of this transaction must equal to the destination of the " "template." @@ -1367,27 +1386,27 @@ msgstr "" "Le destinataire de cette transaction doit être identique à celui du bouton " "utilisé." -#: apps/note/models/transactions.py:289 +#: apps/note/models/transactions.py:282 msgid "Template" msgstr "Bouton" -#: apps/note/models/transactions.py:292 +#: apps/note/models/transactions.py:285 msgid "recurrent transaction" msgstr "transaction issue de bouton" -#: apps/note/models/transactions.py:293 +#: apps/note/models/transactions.py:286 msgid "recurrent transactions" msgstr "transactions issues de boutons" -#: apps/note/models/transactions.py:308 +#: apps/note/models/transactions.py:301 msgid "first_name" msgstr "prénom" -#: apps/note/models/transactions.py:313 +#: apps/note/models/transactions.py:306 msgid "bank" msgstr "banque" -#: apps/note/models/transactions.py:330 +#: apps/note/models/transactions.py:323 msgid "" "A special transaction is only possible between a Note associated to a " "payment method and a User or a Club" @@ -1395,19 +1414,19 @@ msgstr "" "Une transaction spéciale n'est possible que entre une note associée à un " "mode de paiement et un utilisateur ou un club" -#: apps/note/models/transactions.py:338 +#: apps/note/models/transactions.py:331 msgid "Special transaction" msgstr "Transaction de crédit/retrait" -#: apps/note/models/transactions.py:339 +#: apps/note/models/transactions.py:332 msgid "Special transactions" msgstr "Transactions de crédit/retrait" -#: apps/note/models/transactions.py:355 +#: apps/note/models/transactions.py:348 msgid "membership transaction" msgstr "transaction d'adhésion" -#: apps/note/models/transactions.py:356 apps/treasury/models.py:273 +#: apps/note/models/transactions.py:349 apps/treasury/models.py:282 msgid "membership transactions" msgstr "transactions d'adhésion" @@ -1479,7 +1498,8 @@ msgstr "Historique des transactions récentes" #: apps/note/templates/note/mails/negative_balance.txt:25 #: apps/note/templates/note/mails/negative_notes_report.html:46 #: apps/note/templates/note/mails/negative_notes_report.txt:13 -#: apps/note/templates/note/mails/weekly_report.html:54 +#: apps/note/templates/note/mails/weekly_report.html:51 +#: apps/note/templates/note/mails/weekly_report.txt:32 #: apps/registration/templates/registration/mails/email_validation_email.html:40 #: apps/registration/templates/registration/mails/email_validation_email.txt:16 msgid "Mail generated by the Note Kfet on the" @@ -1579,7 +1599,7 @@ msgstr "Chercher un bouton" msgid "Update button" msgstr "Modifier le bouton" -#: apps/note/views.py:151 note_kfet/templates/base.html:63 +#: apps/note/views.py:151 note_kfet/templates/base.html:64 msgid "Consumptions" msgstr "Consommations" @@ -1690,7 +1710,7 @@ msgstr "" "Vous n'avez pas la permission d'ajouter une instance du modèle {app_label}." "{model_name}." -#: apps/permission/signals.py:101 +#: apps/permission/signals.py:102 #, python-brace-format msgid "" "You don't have the permission to delete this instance of model {app_label}." @@ -1758,7 +1778,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:96 note_kfet/templates/base.html:105 +#: apps/permission/views.py:96 note_kfet/templates/base.html:106 msgid "Rights" msgstr "Droits" @@ -1795,23 +1815,23 @@ msgstr "Adhérer au club BDE" msgid "Join Kfet Club" msgstr "Adhérer au club Kfet" -#: apps/registration/templates/registration/email_validation_complete.html:9 +#: apps/registration/templates/registration/email_validation_complete.html:15 msgid "Your email have successfully been validated." msgstr "Votre adresse e-mail a bien été validée." -#: apps/registration/templates/registration/email_validation_complete.html:11 +#: apps/registration/templates/registration/email_validation_complete.html:19 #, python-format msgid "You can now log in." msgstr "Vous pouvez désormais vous connecter." -#: apps/registration/templates/registration/email_validation_complete.html:13 +#: apps/registration/templates/registration/email_validation_complete.html:23 msgid "" "You must pay now your membership in the Kfet to complete your registration." msgstr "" "Vous devez désormais payer votre adhésion à la Kfet pour compléter votre " "inscription." -#: apps/registration/templates/registration/email_validation_complete.html:16 +#: apps/registration/templates/registration/email_validation_complete.html:28 msgid "" "The link was invalid. The token may have expired. Please send us an email to " "activate your account." @@ -1819,24 +1839,20 @@ msgstr "" "Le lien est invalide. Le jeton a sans doute expiré. Merci de nous contacter " "pour activer votre compte." -#: apps/registration/templates/registration/email_validation_email_sent.html:8 +#: apps/registration/templates/registration/email_validation_email_sent.html:10 msgid "Account activation" msgstr "Activation du compte" -#: apps/registration/templates/registration/email_validation_email_sent.html:11 +#: apps/registration/templates/registration/email_validation_email_sent.html:14 msgid "" "An email has been sent. Please click on the link to activate your account." msgstr "" "Un email vient de vous être envoyé. Merci de cliquer sur le lien de " "validation pour activer votre compte." -#: apps/registration/templates/registration/email_validation_email_sent.html:15 -msgid "" -"You must also go to the Kfet to pay your membership. The WEI registration " -"includes the BDE membership." -msgstr "" -"Vous devrez également vous rendre à la Kfet pour payer votre adhésion. " -"L'inscription au WEI inclut l'adhésion au BDE." +#: apps/registration/templates/registration/email_validation_email_sent.html:17 +msgid "You must also go to the Kfet to pay your membership." +msgstr "Vous devrez également vous rendre à la Kfet pour payer votre adhésion." #: apps/registration/templates/registration/future_profile_detail.html:49 #: apps/wei/templates/wei/weiregistration_confirm_delete.html:11 @@ -1882,12 +1898,10 @@ msgstr "Ce lien n'est valide que pendant quelques jours." #: apps/registration/templates/registration/mails/email_validation_email.txt:11 msgid "" "After that, you'll have to wait that someone validates your account before " -"you can log in. You will need to pay your membership in the Kfet. Note that " -"the WEI registration includes the Kfet membership." +"you can log in. You will need to pay your membership in the Kfet." msgstr "" "Après cela, vous devrez attendre que quelqu'un valide votre compte avant de " -"pouvoir vous connecter. Vous devrez payer votre adhésion à la Kfet. Notez " -"que l'adhésion Kfet est incluse dans l'inscription au WEI." +"pouvoir vous connecter. Vous devrez payer votre adhésion à la Kfet." #: apps/registration/templates/registration/mails/email_validation_email.html:34 #: apps/registration/templates/registration/mails/email_validation_email.txt:13 @@ -1950,7 +1964,7 @@ msgstr "" msgid "Invalidate pre-registration" msgstr "Invalider l'inscription" -#: apps/treasury/apps.py:12 note_kfet/templates/base.html:93 +#: apps/treasury/apps.py:12 note_kfet/templates/base.html:94 msgid "Treasury" msgstr "Trésorerie" @@ -1967,7 +1981,7 @@ msgstr "La remise est déjà fermée." msgid "You can't change the type of the remittance." msgstr "Vous ne pouvez pas changer le type de la remise." -#: apps/treasury/forms.py:123 apps/treasury/models.py:252 +#: apps/treasury/forms.py:123 apps/treasury/models.py:258 #: apps/treasury/tables.py:97 apps/treasury/tables.py:105 #: apps/treasury/templates/treasury/invoice_list.html:16 #: apps/treasury/templates/treasury/remittance_list.html:16 @@ -1999,7 +2013,7 @@ msgstr "Description" msgid "Address" msgstr "Adresse" -#: apps/treasury/models.py:60 apps/treasury/models.py:180 +#: apps/treasury/models.py:60 apps/treasury/models.py:186 msgid "Date" msgstr "Date" @@ -2019,7 +2033,7 @@ msgstr "Une facture ne peut plus être modifiée si elle est verrouillée." msgid "tex source" msgstr "fichier TeX source" -#: apps/treasury/models.py:109 apps/treasury/models.py:122 +#: apps/treasury/models.py:109 apps/treasury/models.py:125 msgid "invoice" msgstr "facture" @@ -2027,67 +2041,72 @@ msgstr "facture" msgid "invoices" msgstr "factures" -#: apps/treasury/models.py:127 +#: apps/treasury/models.py:113 +#, python-brace-format +msgid "Invoice #{id}" +msgstr "Facture n°{id}" + +#: apps/treasury/models.py:130 msgid "Designation" msgstr "Désignation" -#: apps/treasury/models.py:131 +#: apps/treasury/models.py:134 msgid "Quantity" msgstr "Quantité" -#: apps/treasury/models.py:135 +#: apps/treasury/models.py:138 msgid "Unit price" msgstr "Prix unitaire" -#: apps/treasury/models.py:151 +#: apps/treasury/models.py:154 msgid "product" msgstr "produit" -#: apps/treasury/models.py:152 +#: apps/treasury/models.py:155 msgid "products" msgstr "produits" -#: apps/treasury/models.py:169 +#: apps/treasury/models.py:175 msgid "remittance type" msgstr "type de remise" -#: apps/treasury/models.py:170 +#: apps/treasury/models.py:176 msgid "remittance types" msgstr "types de remises" -#: apps/treasury/models.py:191 +#: apps/treasury/models.py:197 msgid "Comment" msgstr "Commentaire" -#: apps/treasury/models.py:196 +#: apps/treasury/models.py:202 msgid "Closed" msgstr "Fermée" -#: apps/treasury/models.py:200 +#: apps/treasury/models.py:206 msgid "remittance" msgstr "remise" -#: apps/treasury/models.py:201 +#: apps/treasury/models.py:207 msgid "remittances" msgstr "remises" -#: apps/treasury/models.py:233 +#: apps/treasury/models.py:239 msgid "Remittance #{:d}: {}" msgstr "Remise n°{:d} : {}" -#: apps/treasury/models.py:256 +#: apps/treasury/models.py:262 msgid "special transaction proxy" msgstr "proxy de transaction spéciale" -#: apps/treasury/models.py:257 +#: apps/treasury/models.py:263 msgid "special transaction proxies" msgstr "proxys de transactions spéciales" -#: apps/treasury/models.py:279 +#: apps/treasury/models.py:288 msgid "credit transaction" msgstr "transaction de crédit" -#: apps/treasury/models.py:343 +#: apps/treasury/models.py:352 msgid "" "This user doesn't have enough money to pay the memberships with its note. " "Please ask her/him to credit the note before invalidating this credit." @@ -2095,15 +2114,20 @@ msgstr "" "Cet utilisateur n'a pas assez d'argent pour payer les adhésions avec sa " "note. Merci de lui demander de recharger sa note avant d'invalider ce crédit." -#: apps/treasury/models.py:355 +#: apps/treasury/models.py:364 #: apps/treasury/templates/treasury/sogecredit_detail.html:10 msgid "Credit from the Société générale" msgstr "Crédit de la Société générale" -#: apps/treasury/models.py:356 +#: apps/treasury/models.py:365 msgid "Credits from the Société générale" msgstr "Crédits de la Société générale" +#: apps/treasury/models.py:368 +#, python-brace-format +msgid "Soge credit for {user}" +msgstr "Crédit de la société générale pour l'utilisateur {user}" + #: apps/treasury/tables.py:20 msgid "Invoice #{:d}" msgstr "Facture n°{:d}" @@ -2340,7 +2364,7 @@ msgstr "Gérer les crédits de la Société générale" #: apps/wei/apps.py:10 apps/wei/models.py:49 apps/wei/models.py:50 #: apps/wei/models.py:61 apps/wei/models.py:167 -#: note_kfet/templates/base.html:99 +#: note_kfet/templates/base.html:100 msgid "WEI" msgstr "WEI" @@ -2944,23 +2968,46 @@ msgstr "" msgid "Reset" msgstr "Réinitialiser" -#: note_kfet/templates/base.html:13 +#: note_kfet/templates/base.html:14 msgid "The ENS Paris-Saclay BDE note." msgstr "La note du BDE de l'ENS Paris-Saclay." -#: note_kfet/templates/base.html:75 +#: note_kfet/templates/base.html:76 msgid "Users" msgstr "Utilisateurs" -#: note_kfet/templates/base.html:81 +#: note_kfet/templates/base.html:82 msgid "Clubs" msgstr "Clubs" -#: note_kfet/templates/base.html:110 +#: note_kfet/templates/base.html:111 msgid "Admin" msgstr "Admin" -#: note_kfet/templates/base.html:154 +#: note_kfet/templates/base.html:125 +msgid "My account" +msgstr "Mon compte" + +#: note_kfet/templates/base.html:128 +msgid "Log out" +msgstr "Se déconnecter" + +#: note_kfet/templates/base.html:136 +#: note_kfet/templates/registration/signup.html:6 +#: note_kfet/templates/registration/signup.html:11 +#: note_kfet/templates/registration/signup.html:27 +msgid "Sign up" +msgstr "Inscription" + +#: note_kfet/templates/base.html:143 +#: note_kfet/templates/registration/login.html:6 +#: note_kfet/templates/registration/login.html:15 +#: note_kfet/templates/registration/login.html:38 +#: note_kfet/templates/registration/password_reset_complete.html:15 +msgid "Log in" +msgstr "Se connecter" + +#: note_kfet/templates/base.html:155 msgid "" "Your e-mail address is not validated. Please check your mail inbox and click " "on the validation link." @@ -2968,6 +3015,10 @@ 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:172 +msgid "Contact us" +msgstr "Nous contacter" + #: note_kfet/templates/base_search.html:15 msgid "Search by attribute such as name…" msgstr "Chercher par un attribut tel que le nom …" @@ -2999,13 +3050,6 @@ msgstr "Merci d'avoir utilisé la Note Kfet." msgid "Log in again" msgstr "Se connecter à nouveau" -#: note_kfet/templates/registration/login.html:6 -#: note_kfet/templates/registration/login.html:15 -#: note_kfet/templates/registration/login.html:38 -#: note_kfet/templates/registration/password_reset_complete.html:15 -msgid "Log in" -msgstr "Se connecter" - #: note_kfet/templates/registration/login.html:20 #, python-format msgid "" @@ -3097,12 +3141,6 @@ msgstr "" msgid "Reset my password" msgstr "Réinitialiser mon mot de passe" -#: note_kfet/templates/registration/signup.html:6 -#: note_kfet/templates/registration/signup.html:11 -#: note_kfet/templates/registration/signup.html:27 -msgid "Sign up" -msgstr "Inscription" - #: note_kfet/templates/registration/signup.html:15 msgid "" "If you already signed up, your registration is taken into account. The BDE " diff --git a/note_kfet/templates/base.html b/note_kfet/templates/base.html index 6d092367..f65fe87c 100644 --- a/note_kfet/templates/base.html +++ b/note_kfet/templates/base.html @@ -3,7 +3,8 @@ SPDX-License-Identifier: GPL-3.0-or-later {% endcomment %} - +{% get_current_language as LANGUAGE_CODE %}{% get_current_language_bidi as LANGUAGE_BIDI %} + @@ -37,7 +38,7 @@ SPDX-License-Identifier: GPL-3.0-or-later - {# Si un formulaire requiert des données supplémentaires (notamment JS), les données sont chargées #} + {# If extra ressources are needed for a form, load here #} {% if form.media %} {{ form.media }} {% endif %} @@ -46,7 +47,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
-