From efc2b6b0b0bed0687a88cd2c4faabd5b3b19c57b Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 1 Aug 2020 21:44:16 +0200 Subject: [PATCH 001/319] Send mail to users when the note balance is negative --- apps/member/models.py | 13 ++++-- apps/note/models/notes.py | 23 ++++++++++ apps/note/models/transactions.py | 2 +- apps/scripts | 2 +- locale/de/LC_MESSAGES/django.po | 12 ++--- locale/fr/LC_MESSAGES/django.po | 12 ++--- static/js/transfer.js | 4 +- templates/note/mails/negative_balance.html | 44 +++++++++++++++++++ templates/note/mails/negative_balance.txt | 23 ++++++++++ .../note/mails/negative_notes_report.html | 41 +++++++++++++++++ .../note/mails/negative_notes_report.txt | 12 +++++ .../mails/email_validation_email.html | 40 ++++++++++++++--- .../mails/email_validation_email.txt | 16 +++++++ 13 files changed, 218 insertions(+), 26 deletions(-) create mode 100644 templates/note/mails/negative_balance.html create mode 100644 templates/note/mails/negative_balance.txt create mode 100644 templates/note/mails/negative_notes_report.html create mode 100644 templates/note/mails/negative_notes_report.txt create mode 100644 templates/registration/mails/email_validation_email.txt diff --git a/apps/member/models.py b/apps/member/models.py index efd8bf8c..ffe50201 100644 --- a/apps/member/models.py +++ b/apps/member/models.py @@ -131,15 +131,22 @@ class Profile(models.Model): return reverse('user_detail', args=(self.pk,)) def send_email_validation_link(self): - subject = _("Activate your Note Kfet account") - message = loader.render_to_string('registration/mails/email_validation_email.html', + subject = "[Note Kfet]" + _("Activate your Note Kfet account") + message = loader.render_to_string('registration/mails/email_validation_email.txt', { 'user': self.user, 'domain': os.getenv("NOTE_URL", "note.example.com"), 'token': email_validation_token.make_token(self.user), 'uid': urlsafe_base64_encode(force_bytes(self.user.pk)), }) - self.user.email_user(subject, message) + html = loader.render_to_string('registration/mails/email_validation_email.txt', + { + 'user': self.user, + 'domain': os.getenv("NOTE_URL", "note.example.com"), + 'token': email_validation_token.make_token(self.user), + 'uid': urlsafe_base64_encode(force_bytes(self.user.pk)), + }) + self.user.email_user(subject, message, html_message=html) class Club(models.Model): diff --git a/apps/note/models/notes.py b/apps/note/models/notes.py index 99818602..9274dff6 100644 --- a/apps/note/models/notes.py +++ b/apps/note/models/notes.py @@ -7,6 +7,7 @@ from django.conf import settings from django.core.exceptions import ValidationError from django.core.validators import RegexValidator from django.db import models +from django.template.loader import render_to_string from django.utils import timezone from django.utils.translation import gettext_lazy as _ from polymorphic.models import PolymorphicModel @@ -67,6 +68,13 @@ class Note(PolymorphicModel): pretty.short_description = _('Note') + @property + def last_negative_duration(self): + if self.balance >= 0 or self.last_negative is None: + return None + delta = timezone.now() - self.last_negative + return "{:d} jours".format(delta.days) + def save(self, *args, **kwargs): """ Save note with it's alias (called in polymorphic children) @@ -128,6 +136,21 @@ class NoteUser(Note): def pretty(self): return _("%(user)s's note") % {'user': str(self.user)} + def save(self, *args, **kwargs): + if self.pk and self.balance < 0: + old_note = NoteUser.objects.get(pk=self.pk) + if old_note.balance >= 0: + # Passage en négatif + self.last_negative = timezone.now() + self.send_mail_negative_balance() + super().save(*args, **kwargs) + + def send_mail_negative_balance(self): + plain_text = render_to_string("note/mails/negative_balance.txt", dict(note=self)) + html = render_to_string("note/mails/negative_balance.html", dict(note=self)) + self.user.email_user("[Note Kfet] Passage en négatif (compte n°{:d})" + .format(self.user.pk), plain_text, html_message=html) + class NoteClub(Note): """ diff --git a/apps/note/models/transactions.py b/apps/note/models/transactions.py index f504d8e1..6eab05ee 100644 --- a/apps/note/models/transactions.py +++ b/apps/note/models/transactions.py @@ -7,7 +7,7 @@ from django.utils import timezone from django.utils.translation import gettext_lazy as _ from polymorphic.models import PolymorphicModel -from .notes import Note, NoteClub, NoteSpecial +from .notes import Note, NoteClub, NoteSpecial, NoteUser from ..templatetags.pretty_money import pretty_money """ diff --git a/apps/scripts b/apps/scripts index dce51ad2..4b37f828 160000 --- a/apps/scripts +++ b/apps/scripts @@ -1 +1 @@ -Subproject commit dce51ad26134d396d7cbfca7c63bd2ed391dd969 +Subproject commit 4b37f8286f493b1a28bd0faa0052ee3967fe543e diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index bec7e726..d28ecb34 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/LC_MESSAGES/django.po @@ -2128,33 +2128,33 @@ msgstr "" msgid "Forgotten your password or username?" msgstr "" -#: templates/registration/mails/email_validation_email.html:3 +#: templates/registration/mails/email_validation_email.txt:3 msgid "Hi" msgstr "" -#: templates/registration/mails/email_validation_email.html:5 +#: templates/registration/mails/email_validation_email.txt:5 msgid "" "You recently registered on the Note Kfet. Please click on the link below to " "confirm your registration." msgstr "" -#: templates/registration/mails/email_validation_email.html:9 +#: templates/registration/mails/email_validation_email.txt:9 msgid "" "This link is only valid for a couple of days, after that you will need to " "contact us to validate your email." msgstr "" -#: templates/registration/mails/email_validation_email.html:11 +#: 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." msgstr "" -#: templates/registration/mails/email_validation_email.html:13 +#: templates/registration/mails/email_validation_email.txt:13 msgid "Thanks" msgstr "" -#: templates/registration/mails/email_validation_email.html:15 +#: templates/registration/mails/email_validation_email.txt:15 msgid "The Note Kfet team." msgstr "" diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 54c70c71..9df44fec 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -2197,11 +2197,11 @@ msgstr "" msgid "Forgotten your password or username?" msgstr "Mot de passe ou pseudo oublié ?" -#: templates/registration/mails/email_validation_email.html:3 +#: templates/registration/mails/email_validation_email.txt:3 msgid "Hi" msgstr "Bonjour" -#: templates/registration/mails/email_validation_email.html:5 +#: templates/registration/mails/email_validation_email.txt:5 msgid "" "You recently registered on the Note Kfet. Please click on the link below to " "confirm your registration." @@ -2209,7 +2209,7 @@ msgstr "" "Vous vous êtes inscrits récemment sur la Note Kfet. Merci de cliquer sur le " "lien ci-dessous pour confirmer votre adresse email." -#: templates/registration/mails/email_validation_email.html:9 +#: templates/registration/mails/email_validation_email.txt:9 msgid "" "This link is only valid for a couple of days, after that you will need to " "contact us to validate your email." @@ -2217,7 +2217,7 @@ msgstr "" "Ce lien n'est valide que pendant quelques jours. Après cela, vous devrez " "nous contacter pour valider votre email." -#: templates/registration/mails/email_validation_email.html:11 +#: 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." @@ -2225,11 +2225,11 @@ 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." -#: templates/registration/mails/email_validation_email.html:13 +#: templates/registration/mails/email_validation_email.txt:13 msgid "Thanks" msgstr "Merci" -#: templates/registration/mails/email_validation_email.html:15 +#: templates/registration/mails/email_validation_email.txt:15 msgid "The Note Kfet team." msgstr "L'équipe de la Note Kfet." diff --git a/static/js/transfer.js b/static/js/transfer.js index 5b577066..ddaccc2d 100644 --- a/static/js/transfer.js +++ b/static/js/transfer.js @@ -333,9 +333,9 @@ $("#btn_transfer").click(function() { "polymorphic_ctype": SPECIAL_TRANSFER_POLYMORPHIC_CTYPE, "resourcetype": "SpecialTransaction", "source": source_id, - "source_alias": sources_notes_display[0].name, + "source_alias": sources_notes_display.length ? sources_notes_display[0].name : null, "destination": dest_id, - "destination_alias": dests_notes_display[0].name, + "destination_alias": dests_notes_display.length ? dests_notes_display[0].name : null, "last_name": $("#last_name").val(), "first_name": $("#first_name").val(), "bank": $("#bank").val() diff --git a/templates/note/mails/negative_balance.html b/templates/note/mails/negative_balance.html new file mode 100644 index 00000000..30e38cc8 --- /dev/null +++ b/templates/note/mails/negative_balance.html @@ -0,0 +1,44 @@ +{% load pretty_money %} + + + + + + Passage en négatif (compte n°{{ note.user.pk }}) + + +

+ Bonjour {{ note.user.first_name }} {{ note.user.last_name }}, +

+ +

+ Ce mail t'a été envoyé parce que le solde de ta Note Kfet {{ note }} est négatif ! +

+ +

+ Ton solde actuel est de {{ note.balance|pretty_money }}. +

+ +

+ Par ailleurs, le BDE ne sert pas d'alcool aux adhérents dont le solde + est inférieur à 0 € depuis plus de 24h. +

+ +

+ Si tu ne comprends pas ton solde, tu peux consulter ton historique + sur ton compte. +

+ +

+ Tu peux venir recharger ta note rapidement à la Kfet, ou envoyer un mail à + la trésorerie du BdE (tresorerie.bde@lists.crans.org) + pour payer par virement bancaire. +

+ +-- +

+ Le BDE
+ Mail généré par la Note Kfet le {% now "j F Y à H:i:s" %} +

+ + \ No newline at end of file diff --git a/templates/note/mails/negative_balance.txt b/templates/note/mails/negative_balance.txt new file mode 100644 index 00000000..b49caf73 --- /dev/null +++ b/templates/note/mails/negative_balance.txt @@ -0,0 +1,23 @@ +{% load pretty_money %} + +Bonjour {{ note.user.first_name }} {{ note.user.last_name }}, + +Ce mail t'a été envoyé parce que le solde de ta Note Kfet +{{ note }} est négatif ! + +Ton solde actuel est de {{ note.balance|pretty_money }}. + +Par ailleurs, le BDE ne sert pas d'alcool aux adhérents dont le solde +est inférieur à 0 € depuis plus de 24h. + +Si tu ne comprends pas ton solde, tu peux consulter ton historique +sur ton compte {% url "member:user_detail" pk=note.user.pk %} + +Tu peux venir recharger ta note rapidement à la Kfet, ou envoyer un mail à +la trésorerie du BdE (tresorerie.bde@lists.crans.org) pour payer par +virement bancaire. + +-- +Le BDE + +Mail généré par la Note Kfet le {% now "j F Y à H:i:s" %} \ No newline at end of file diff --git a/templates/note/mails/negative_notes_report.html b/templates/note/mails/negative_notes_report.html new file mode 100644 index 00000000..c895b903 --- /dev/null +++ b/templates/note/mails/negative_notes_report.html @@ -0,0 +1,41 @@ +{% load pretty_money %} + + + + + + [Note Kfet] Liste des négatifs + + + + + + + + + + + + + + + {% for note in notes %} + + + + + + + + + {% endfor %} + +
NomPrénomPseudoEmailSoldeDurée
{{ note.user.last_name }}{{ note.user.first_name }}{{ note.user.username }}{{ note.user.email }}{{ note.balance|pretty_money }}{{ note.last_negative_duration }}
+ +-- +

+ Le BDE
+ Mail généré par la Note Kfet le {% now "j F Y à H:i:s" %} +

+ + \ No newline at end of file diff --git a/templates/note/mails/negative_notes_report.txt b/templates/note/mails/negative_notes_report.txt new file mode 100644 index 00000000..b7fa1f23 --- /dev/null +++ b/templates/note/mails/negative_notes_report.txt @@ -0,0 +1,12 @@ +{% load pretty_money %} + + Nom | Prénom | Pseudo | Email | Solde | Durée +---------------------+------------+-----------------+-----------------------------------+----------+----------- +{% for note in notes %} +{{ note.user.last_name }} | {{ note.user.first_name }} | {{ note.user.username }} | {{ note.user.email }} | {{ note.balance|pretty_money }} | {{ note.last_negative_duration }} +{% endfor %} + +-- +Le BDE + +Mail généré par la Note Kfet le {% now "j F Y à H:i:s" %} \ No newline at end of file diff --git a/templates/registration/mails/email_validation_email.html b/templates/registration/mails/email_validation_email.html index 577c1220..0d3afc0e 100644 --- a/templates/registration/mails/email_validation_email.html +++ b/templates/registration/mails/email_validation_email.html @@ -1,15 +1,41 @@ {% load i18n %} -{% trans "Hi" %} {{ user.username }}, + + + + + Passage en négatif (compte n°{{ note.user.pk }}) + + -{% trans "You recently registered on the Note Kfet. Please click on the link below to confirm your registration." %} +

+ {% trans "Hi" %} {{ user.username }}, +

-https://{{ domain }}{% url 'registration:email_validation' uidb64=uid token=token %} +

+ {% trans "You recently registered on the Note Kfet. Please click on the link below to confirm your registration." %} +

-{% trans "This link is only valid for a couple of days, after that you will need to contact us to validate your email." %} +

+ + https://{{ domain }}{% url 'registration:email_validation' uidb64=uid token=token %} + +

-{% 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 "This link is only valid for a couple of days, after that you will need to contact us to validate your email." %} +

-{% trans "Thanks" %}, +

+ {% 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 "The Note Kfet team." %} +

+ {% trans "Thanks" %}, +

+ +-- +

+ {% trans "The Note Kfet team." %} + Mail généré par la Note Kfet le {% now "j F Y à H:i:s" %} +

\ No newline at end of file diff --git a/templates/registration/mails/email_validation_email.txt b/templates/registration/mails/email_validation_email.txt new file mode 100644 index 00000000..69f2d642 --- /dev/null +++ b/templates/registration/mails/email_validation_email.txt @@ -0,0 +1,16 @@ +{% load i18n %} + +{% trans "Hi" %} {{ user.username }}, + +{% trans "You recently registered on the Note Kfet. Please click on the link below to confirm your registration." %} + +https://{{ domain }}{% url 'registration:email_validation' uidb64=uid token=token %} + +{% 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." %} + +{% trans "Thanks" %}, + +{% trans "The Note Kfet team." %} +Mail généré par la Note Kfet le {% now "j F Y à H:i:s" %} \ No newline at end of file From cadf98101389d1785340ce613b34103171247c0b Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 1 Aug 2020 21:48:18 +0200 Subject: [PATCH 002/319] =?UTF-8?q?passer=20en=20n=C3=A9gatif=20->=20?= =?UTF-8?q?=C3=AAtre=20en=20n=C3=A9gatif?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- static/js/consos.js | 6 ++++-- static/js/transfer.js | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/static/js/consos.js b/static/js/consos.js index f0fd3458..7a295b78 100644 --- a/static/js/consos.js +++ b/static/js/consos.js @@ -194,10 +194,12 @@ function consume(source, source_alias, dest, quantity, amount, reason, type, cat if (!isNaN(source.balance)) { let newBalance = source.balance - quantity * amount; if (newBalance <= -5000) - addMsg("Attention, la note émettrice " + source_alias + " passe en négatif sévère.", + addMsg("Attention, La transaction depuis la note " + source_alias + " a été réalisée avec " + + "succès, mais la note émettrice " + source_alias + " est en négatif sévère.", "danger", 10000); else if (newBalance < 0) - addMsg("Attention, la note émettrice " + source_alias + " passe en négatif.", + addMsg("Attention, La transaction depuis la note " + source_alias + " a été réalisée avec " + + "succès, mais la note émettrice " + source_alias + " est en négatif.", "warning", 10000); } reset(); diff --git a/static/js/transfer.js b/static/js/transfer.js index ddaccc2d..65184fd9 100644 --- a/static/js/transfer.js +++ b/static/js/transfer.js @@ -247,7 +247,7 @@ $("#btn_transfer").click(function() { addMsg("Le transfert de " + pretty_money(source.quantity * dest.quantity * amount) + " de la note " + source.name + " vers la note " + dest.name + " a été fait avec succès, " + - "mais la note émettrice passe en négatif sévère.", "danger", 10000); + "mais la note émettrice est en négatif sévère.", "danger", 10000); reset(); return; } @@ -255,7 +255,7 @@ $("#btn_transfer").click(function() { addMsg("Le transfert de " + pretty_money(source.quantity * dest.quantity * amount) + " de la note " + source.name + " vers la note " + dest.name + " a été fait avec succès, " + - "mais la note émettrice passe en négatif.", "warning", 10000); + "mais la note émettrice est en négatif.", "warning", 10000); reset(); return; } From 8434841ec5e320387f5bf4bd988b7557068636b6 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 1 Aug 2020 22:28:28 +0200 Subject: [PATCH 003/319] Fix one permission --- apps/permission/fixtures/initial.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/permission/fixtures/initial.json b/apps/permission/fixtures/initial.json index 5a3001da..3ac709a2 100644 --- a/apps/permission/fixtures/initial.json +++ b/apps/permission/fixtures/initial.json @@ -2207,7 +2207,7 @@ "auth", "user" ], - "query": "{\"memberships__club\": [\"club\"], \"memberships__date__start__lte\": [\"today\"], \"memberships__date__end__gte\": [\"today\"]}", + "query": "{\"memberships__club\": [\"club\"], \"memberships__date_start__lte\": [\"today\"], \"memberships__date_end__gte\": [\"today\"]}", "type": "view", "mask": 3, "field": "", From c0cdb13130e4d1fbd29aa168cd233352a7176a1e Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 1 Aug 2020 22:30:34 +0200 Subject: [PATCH 004/319] Can't concatenate string and proxy --- apps/member/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/member/models.py b/apps/member/models.py index ffe50201..6ba4fb5f 100644 --- a/apps/member/models.py +++ b/apps/member/models.py @@ -131,7 +131,7 @@ class Profile(models.Model): return reverse('user_detail', args=(self.pk,)) def send_email_validation_link(self): - subject = "[Note Kfet]" + _("Activate your Note Kfet account") + subject = "[Note Kfet]" + str(_("Activate your Note Kfet account")) message = loader.render_to_string('registration/mails/email_validation_email.txt', { 'user': self.user, From 5ccbad8359f8f0aa3a6fc3e3fd11d1c05726664e Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 1 Aug 2020 23:03:10 +0200 Subject: [PATCH 005/319] Fix transfer form reset --- static/js/transfer.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/static/js/transfer.js b/static/js/transfer.js index 65184fd9..45d5508a 100644 --- a/static/js/transfer.js +++ b/static/js/transfer.js @@ -16,11 +16,13 @@ function reset(refresh=true) { $("#dest_note_list").html(""); let source_field = $("#source_note"); source_field.val(""); - source_field.trigger("keyup"); + let event = jQuery.Event("keyup"); + event.originalEvent = {charCode: 97}; + source_field.trigger(event); source_field.removeClass('is-invalid'); let dest_field = $("#dest_note"); dest_field.val(""); - dest_field.trigger("keyup"); + dest_field.trigger(event); dest_field.removeClass('is-invalid'); let amount_field = $("#amount"); amount_field.val(""); From 37dc535d6d5d2de5e1c639044ee7d212fef23828 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 1 Aug 2020 23:05:14 +0200 Subject: [PATCH 006/319] Display only one user --- apps/member/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/member/views.py b/apps/member/views.py index 30fbb139..d065b2b6 100644 --- a/apps/member/views.py +++ b/apps/member/views.py @@ -131,7 +131,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().filter(profile__registration_valid=True).distinct() def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) From b706efe463b5ec78309c6ef4c9a3b99bac6f41f0 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 1 Aug 2020 23:26:11 +0200 Subject: [PATCH 007/319] 2A+ can change their selected bus or team if the registration is not validated --- apps/permission/fixtures/initial.json | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/apps/permission/fixtures/initial.json b/apps/permission/fixtures/initial.json index 3ac709a2..d87af102 100644 --- a/apps/permission/fixtures/initial.json +++ b/apps/permission/fixtures/initial.json @@ -2247,6 +2247,22 @@ "description": "Créer une note d'utilisateur" } }, + { + "model": "permission.permission", + "pk": 144, + "fields": { + "model": [ + "wei", + "weiregistration" + ], + "query": "[\"AND\", {\"user\": [\"user\"], \"wei__membership_start__lte\": [\"today\"], \"wei__membership_end__gte\": [\"today\"], \"first_year\": false, \"membership\": null}]", + "type": "change", + "mask": 1, + "field": "information_json", + "permanent": false, + "description": "Modifier mes préférences en terme de bus et d'équipe si mon inscription n'est pas validée et que je suis en 2A+" + } + }, { "model": "permission.role", "pk": 1, @@ -2300,7 +2316,8 @@ 99, 101, 108, - 109 + 109, + 144 ] } }, @@ -2569,7 +2586,8 @@ 140, 141, 142, - 143 + 143, + 144 ] } }, From 0ae61f3643aaab4cae6fbf4e978d9e89f227cb39 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sun, 2 Aug 2020 08:47:23 +0200 Subject: [PATCH 008/319] BDE memberships can start on 1st august --- apps/scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/scripts b/apps/scripts index 4b37f828..1f300c3b 160000 --- a/apps/scripts +++ b/apps/scripts @@ -1 +1 @@ -Subproject commit 4b37f8286f493b1a28bd0faa0052ee3967fe543e +Subproject commit 1f300c3b7bac0b7a31c1a252a83ba68a8268d33d From 2f018f8c9dfbe007e4e628836a115ba081a5d1fb Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sun, 2 Aug 2020 08:57:16 +0200 Subject: [PATCH 009/319] Always query distinct objects --- apps/member/views.py | 2 +- apps/note/views.py | 8 ++++++-- apps/permission/views.py | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/apps/member/views.py b/apps/member/views.py index d065b2b6..30fbb139 100644 --- a/apps/member/views.py +++ b/apps/member/views.py @@ -131,7 +131,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).distinct() + return super().get_queryset().filter(profile__registration_valid=True) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) diff --git a/apps/note/views.py b/apps/note/views.py index 61b86e92..ef9da668 100644 --- a/apps/note/views.py +++ b/apps/note/views.py @@ -33,7 +33,9 @@ class TransactionCreateView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTabl extra_context = {"title": _("Transfer money")} def get_queryset(self, **kwargs): - return super().get_queryset(**kwargs).order_by("-created_at").all()[:20] + return Transaction.objects.filter( + PermissionBackend.filter_queryset(self.request.user, Transaction, "view") + ).order_by("-created_at").all()[:20] def get_context_data(self, **kwargs): """ @@ -139,7 +141,9 @@ class ConsoView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView): table_class = HistoryTable def get_queryset(self, **kwargs): - return super().get_queryset(**kwargs).order_by("-created_at")[:20] + return Transaction.objects.filter( + PermissionBackend.filter_queryset(self.request.user, Transaction, "view") + ).order_by("-created_at").all()[:20] def get_context_data(self, **kwargs): """ diff --git a/apps/permission/views.py b/apps/permission/views.py index 83deddac..9132e5f0 100644 --- a/apps/permission/views.py +++ b/apps/permission/views.py @@ -20,7 +20,7 @@ class ProtectQuerysetMixin: """ def get_queryset(self, **kwargs): qs = super().get_queryset(**kwargs) - return qs.filter(PermissionBackend.filter_queryset(self.request.user, qs.model, "view")) + return qs.filter(PermissionBackend.filter_queryset(self.request.user, qs.model, "view")).distinct() def get_form(self, form_class=None): form = super().get_form(form_class) From f148c8dacb6f01d6cc993250eb7dee931bd59813 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sun, 2 Aug 2020 09:20:21 +0200 Subject: [PATCH 010/319] Better autocomplete field --- static/js/autocomplete_model.js | 7 ++++++- static/js/base.js | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/static/js/autocomplete_model.js b/static/js/autocomplete_model.js index aa1d220c..6e135ad1 100644 --- a/static/js/autocomplete_model.js +++ b/static/js/autocomplete_model.js @@ -18,7 +18,8 @@ $(document).ready(function () { html += li(prefix + "_" + obj.id, obj[name_field]); }); - $("#" + prefix + "_list").html(html); + let results_list = $("#" + prefix + "_list"); + results_list.html(html); objects.results.forEach(function (obj) { $("#" + prefix + "_" + obj.id).click(function() { @@ -32,6 +33,10 @@ $(document).ready(function () { if (input === obj[name_field]) $("#" + prefix + "_pk").val(obj.id); }); + + if (results_list.children().length === 1 && e.originalEvent.keyCode >= 32) { + results_list.children().first().trigger("click"); + } }); }); }); \ No newline at end of file diff --git a/static/js/base.js b/static/js/base.js index fdad58d7..f485635b 100644 --- a/static/js/base.js +++ b/static/js/base.js @@ -86,8 +86,8 @@ function getMatchedNotes(pattern, fun) { * Generate a
  • entry with a given id and text */ function li(id, text, extra_css) { - return "
  • " + text + "
  • \n"; + return "
  • " + text + "
  • \n"; } /** From 8497dbb25c5480b11a865732e5e1ffb6232fad9b Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sun, 2 Aug 2020 09:30:18 +0200 Subject: [PATCH 011/319] Club members can see the club --- apps/permission/fixtures/initial.json | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/permission/fixtures/initial.json b/apps/permission/fixtures/initial.json index d87af102..0fd675c3 100644 --- a/apps/permission/fixtures/initial.json +++ b/apps/permission/fixtures/initial.json @@ -353,7 +353,7 @@ ], "query": "{\"pk\": [\"club\", \"pk\"]}", "type": "view", - "mask": 3, + "mask": 1, "field": "", "permanent": false, "description": "Voir les informations d'un club" @@ -2282,6 +2282,7 @@ 11, 12, 13, + 22, 48, 52, 126 @@ -2306,6 +2307,7 @@ 15, 16, 17, + 22, 78, 79, 83, @@ -2327,7 +2329,9 @@ "fields": { "for_club": null, "name": "Membre de club", - "permissions": [] + "permissions": [ + 22 + ] } }, { @@ -2337,7 +2341,6 @@ "for_club": null, "name": "Bureau de club", "permissions": [ - 22, 47, 49, 50, From 8de7ba14bd0eaf3ca665ce84cfc14e347a3b2c7d Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sun, 2 Aug 2020 09:35:32 +0200 Subject: [PATCH 012/319] Add permission for secretaries --- apps/permission/fixtures/initial.json | 38 +++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/apps/permission/fixtures/initial.json b/apps/permission/fixtures/initial.json index 0fd675c3..09bf4675 100644 --- a/apps/permission/fixtures/initial.json +++ b/apps/permission/fixtures/initial.json @@ -2263,6 +2263,22 @@ "description": "Modifier mes préférences en terme de bus et d'équipe si mon inscription n'est pas validée et que je suis en 2A+" } }, + { + "model": "permission.permission", + "pk": 145, + "fields": { + "model": [ + "note", + "noteclub" + ], + "query": "{}", + "type": "view", + "mask": 1, + "field": "", + "permanent": false, + "description": "Voir toutes les notes de club" + } + }, { "model": "permission.role", "pk": 1, @@ -2760,6 +2776,28 @@ ] } }, + { + "model": "permission.role", + "pk": 19, + "fields": { + "for_club": 1, + "name": "Secrétaire BDE", + "permissions": [ + 54, + 55, + 56, + 57, + 58, + 135, + 136, + 137, + 138, + 139, + 140, + 145 + ] + } + }, { "model": "wei.weirole", "pk": 12, From 7742358b8f2d11bae9b02810d17111fdbec18c9e Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sun, 2 Aug 2020 09:49:45 +0200 Subject: [PATCH 013/319] Secretaries can view and add memberships --- apps/permission/fixtures/initial.json | 45 +++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/apps/permission/fixtures/initial.json b/apps/permission/fixtures/initial.json index 09bf4675..2b9b086c 100644 --- a/apps/permission/fixtures/initial.json +++ b/apps/permission/fixtures/initial.json @@ -2279,6 +2279,38 @@ "description": "Voir toutes les notes de club" } }, + { + "model": "permission.permission", + "pk": 146, + "fields": { + "model": [ + "member", + "membership" + ], + "query": "{}", + "type": "view", + "mask": 3, + "field": "", + "permanent": false, + "description": "Voir tous les adhérents du club" + } + }, + { + "model": "permission.permission", + "pk": 147, + "fields": { + "model": [ + "member", + "membership" + ], + "query": "{}", + "type": "add", + "mask": 3, + "field": "", + "permanent": false, + "description": "Ajouter un membre à n'importe quel club" + } + }, { "model": "permission.role", "pk": 1, @@ -2456,7 +2488,9 @@ 137, 138, 139, - 143 + 143, + 146, + 147 ] } }, @@ -2606,7 +2640,10 @@ 141, 142, 143, - 144 + 144, + 145, + 146, + 147 ] } }, @@ -2794,7 +2831,9 @@ 138, 139, 140, - 145 + 145, + 146, + 147 ] } }, From f870af139e92b17ba59f4d12f4f02d9bf8147a5d Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sun, 2 Aug 2020 09:51:39 +0200 Subject: [PATCH 014/319] Typos --- apps/permission/fixtures/initial.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/permission/fixtures/initial.json b/apps/permission/fixtures/initial.json index 2b9b086c..bbe2e7e9 100644 --- a/apps/permission/fixtures/initial.json +++ b/apps/permission/fixtures/initial.json @@ -68,7 +68,7 @@ "mask": 1, "field": "", "permanent": true, - "description": "Vioir sa propre note d'utilisateur" + "description": "Voir sa propre note d'utilisateur" } }, { @@ -868,7 +868,7 @@ "mask": 3, "field": "", "permanent": false, - "description": "Modifier n'import quel utilisateur" + "description": "Modifier n'importe quel utilisateur" } }, { From 58fe8914cfd5a0dfca76e92bde4e638b1ff827c2 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sun, 2 Aug 2020 22:39:30 +0200 Subject: [PATCH 015/319] :bug: Fix infinite loop in permission check --- apps/permission/models.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/permission/models.py b/apps/permission/models.py index d2ac2195..bf7dabfa 100644 --- a/apps/permission/models.py +++ b/apps/permission/models.py @@ -45,12 +45,11 @@ class InstancedPermission: else: oldpk = obj.pk # Ensure previous models are deleted - count = 0 - while count < 1000: + for ignored in range(1000): if self.model.model_class().objects.filter(pk=obj.pk).exists(): # If the object exists, that means that one permission is currently checked. # We wait before the other permission, at most 1 second. - sleep(1) + sleep(0.001) continue break for o in self.model.model_class().objects.filter(pk=obj.pk).all(): From 0e3c4fcaf6dea06590259447c977c15001d2cdec Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Mon, 3 Aug 2020 10:03:51 +0200 Subject: [PATCH 016/319] Warn users when a transaction has no source or no destination --- static/js/base.js | 3 +++ static/js/consos.js | 16 ++++++++++++++++ static/js/transfer.js | 20 ++++++++++---------- templates/note/conso_form.html | 4 ++-- 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/static/js/base.js b/static/js/base.js index f485635b..cf67759b 100644 --- a/static/js/base.js +++ b/static/js/base.js @@ -217,6 +217,7 @@ function autoCompleteNote(field_id, note_list_id, notes, notes_display, alias_pr // Clear search on click field.click(function () { field.tooltip('hide'); + field.removeClass('is-invalid'); field.val(""); }); @@ -233,6 +234,8 @@ function autoCompleteNote(field_id, note_list_id, notes, notes_display, alias_pr // When the user type something, the matched aliases are refreshed field.keyup(function (e) { + field.removeClass('is-invalid'); + if (e.originalEvent.charCode === 13) return; diff --git a/static/js/consos.js b/static/js/consos.js index 7a295b78..3b6b5bc5 100644 --- a/static/js/consos.js +++ b/static/js/consos.js @@ -154,6 +154,22 @@ function reset() { * Apply all transactions: all notes in `notes` buy each item in `buttons` */ function consumeAll() { + let error = false; + + if (notes_display.length === 0) { + $("#note").addClass('is-invalid'); + $("#note_list").html(li("", "Ajoutez des émetteurs.", "text-danger")); + error = true; + } + + if (buttons.length === 0) { + $("#consos_list").html(li("", "Ajoutez des consommations.", "text-danger")); + error = true; + } + + if (error) + return; + notes_display.forEach(function(note_display) { buttons.forEach(function(button) { consume(note_display.note, note_display.name, button.dest, button.quantity * note_display.quantity, button.amount, diff --git a/static/js/transfer.js b/static/js/transfer.js index 45d5508a..70cf10dc 100644 --- a/static/js/transfer.js +++ b/static/js/transfer.js @@ -219,6 +219,16 @@ $("#btn_transfer").click(function() { error = true; } + if (!sources_notes_display.length && !$("#type_credit").is(':checked')) { + $("#source_note").addClass('is-invalid'); + error = true; + } + + if (!dests_notes_display.length && !$("#type_debit").is(':checked')) { + $("#dest_note").addClass('is-invalid'); + error = true; + } + if (error) return; @@ -300,11 +310,6 @@ $("#btn_transfer").click(function() { let given_reason = reason; let source_id, dest_id; if ($("#type_credit").is(':checked')) { - if (!dests_notes_display.length) { - $("#dest_note").addClass('is-invalid'); - return; - } - user_note = dests_notes_display[0].note.id; source_id = special_note; dest_id = user_note; @@ -313,11 +318,6 @@ $("#btn_transfer").click(function() { reason += " (" + given_reason + ")"; } else { - if (!sources_notes_display.length) { - $("#source_note").addClass('is-invalid'); - return; - } - user_note = sources_notes_display[0].note.id; source_id = user_note; dest_id = special_note; diff --git a/templates/note/conso_form.html b/templates/note/conso_form.html index e6335c6e..a63f7ffe 100644 --- a/templates/note/conso_form.html +++ b/templates/note/conso_form.html @@ -53,9 +53,9 @@ From 0e8174aacdf5b25bf493c48f23f33f9ed775540b Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Mon, 3 Aug 2020 10:50:55 +0200 Subject: [PATCH 017/319] :bug: Fix objects with pk 0 --- apps/permission/models.py | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/apps/permission/models.py b/apps/permission/models.py index bf7dabfa..235977bb 100644 --- a/apps/permission/models.py +++ b/apps/permission/models.py @@ -4,12 +4,15 @@ import functools import json import operator +from copy import copy from time import sleep from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError +from django.core.mail import mail_admins from django.db import models from django.db.models import F, Q, Model +from django.forms import model_to_dict from django.utils.translation import gettext_lazy as _ @@ -38,35 +41,40 @@ class InstancedPermission: if permission_type == self.type: self.update_query() - # Don't increase indexes, if the primary key is an AutoField - if not hasattr(obj, "pk") or not obj.pk: - obj.pk = 0 - oldpk = None - else: - oldpk = obj.pk + obj = copy(obj) + obj.pk = 0 # Ensure previous models are deleted for ignored in range(1000): - if self.model.model_class().objects.filter(pk=obj.pk).exists(): + if self.model.model_class().objects.filter(pk=0).exists(): # If the object exists, that means that one permission is currently checked. # We wait before the other permission, at most 1 second. sleep(0.001) continue break - for o in self.model.model_class().objects.filter(pk=obj.pk).all(): + for o in self.model.model_class().objects.filter(pk=0).all(): o._force_delete = True Model.delete(o) + # An object with pk 0 wouldn't deleted. That's not normal, we alert admins. + msg = "Lors de la vérification d'une permission d'ajout, un objet de clé primaire nulle était "\ + "encore présent.\n"\ + "Type de permission : " + self.type + "\n"\ + "Modèle : " + str(self.model) + "\n"\ + "Objet trouvé : " + str(model_to_dict(o)) + "\n\n"\ + "--\nLe BDE" + mail_admins("[Note Kfet] Un objet a été supprimé de force", msg) + # Force insertion, no data verification, no trigger obj._force_save = True Model.save(obj, force_insert=True) # We don't want log anything obj._no_log = True - ret = self.model.model_class().objects.filter(self.query & Q(pk=obj.pk)).exists() + ret = self.model.model_class().objects.filter(self.query & Q(pk=0)).exists() # Delete testing object obj._force_delete = True Model.delete(obj) - # If the primary key was specified, we restore it - obj.pk = oldpk + with open("/tmp/log", "w") as f: + f.write(str(obj) + ", " + str(obj.pk) + ", " + str(self.model.model_class().objects.filter(pk=0).exists())) return ret if permission_type == self.type: From 6c8843e5fc5cb1ff0a227fd8292721ad981f443c Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Mon, 3 Aug 2020 10:54:52 +0200 Subject: [PATCH 018/319] :bug: Reset transfer form even if the note has not enough money --- static/js/transfer.js | 1 + 1 file changed, 1 insertion(+) diff --git a/static/js/transfer.js b/static/js/transfer.js index 70cf10dc..feca4a0d 100644 --- a/static/js/transfer.js +++ b/static/js/transfer.js @@ -296,6 +296,7 @@ $("#btn_transfer").click(function() { addMsg("Le transfert de " + pretty_money(source.quantity * dest.quantity * amount) + " de la note " + source.name + " vers la note " + dest.name + " a échoué : Solde insuffisant", "danger", 10000); + reset(); }).fail(function (err) { addMsg("Le transfert de " + pretty_money(source.quantity * dest.quantity * amount) + " de la note " + source.name From 94086505e68965dd7508ca2a8767d50ca640c487 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Mon, 3 Aug 2020 11:16:01 +0200 Subject: [PATCH 019/319] Fix note balances --- apps/scripts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/scripts b/apps/scripts index 1f300c3b..f41a5a32 160000 --- a/apps/scripts +++ b/apps/scripts @@ -1 +1 @@ -Subproject commit 1f300c3b7bac0b7a31c1a252a83ba68a8268d33d +Subproject commit f41a5a32f7417a874b497640373ea3911eb1e133 From f8a4087e56f45a282471a1ab9e89ea08a741e2e9 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Mon, 3 Aug 2020 11:32:37 +0200 Subject: [PATCH 020/319] :bug: Display full registration table when the search bar is empty --- apps/registration/views.py | 2 -- apps/wei/views.py | 14 ++++++-------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/apps/registration/views.py b/apps/registration/views.py index 804c9fa9..f4574b0f 100644 --- a/apps/registration/views.py +++ b/apps/registration/views.py @@ -179,8 +179,6 @@ class FutureUserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableVi | Q(profile__section__iregex=pattern) | Q(username__iregex="^" + pattern) ) - else: - qs = qs.none() return qs[:20] diff --git a/apps/wei/views.py b/apps/wei/views.py index 2210a347..fb0f7b32 100644 --- a/apps/wei/views.py +++ b/apps/wei/views.py @@ -236,14 +236,12 @@ class WEIRegistrationsView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTable pattern = self.request.GET.get("search", "") if not pattern: - return qs.none() - - qs = qs.filter( - Q(user__first_name__iregex=pattern) - | Q(user__last_name__iregex=pattern) - | Q(user__note__alias__name__iregex="^" + pattern) - | Q(user__note__alias__normalized_name__iregex="^" + Alias.normalize(pattern)) - ) + qs = qs.filter( + Q(user__first_name__iregex=pattern) + | Q(user__last_name__iregex=pattern) + | Q(user__note__alias__name__iregex="^" + pattern) + | Q(user__note__alias__normalized_name__iregex="^" + Alias.normalize(pattern)) + ) return qs[:20] From 66defee3ea84145039d202ec6aeeede54884cca8 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Mon, 3 Aug 2020 11:41:06 +0200 Subject: [PATCH 021/319] :bug: Display the invalidity reason of an invalid transaction even if we can't validate it --- apps/note/tables.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/apps/note/tables.py b/apps/note/tables.py index 0048a0a5..505e8dfa 100644 --- a/apps/note/tables.py +++ b/apps/note/tables.py @@ -68,12 +68,8 @@ class HistoryTable(tables.Table): "note.change_transaction_invalidity_reason", record) else None, "onmouseover": lambda record: '$("#invalidity_reason_' + str(record.id) + '").show();$("#invalidity_reason_' - + str(record.id) + '").focus();' - if PermissionBackend.check_perm(get_current_authenticated_user(), - "note.change_transaction_invalidity_reason", record) else None, - "onmouseout": lambda record: '$("#invalidity_reason_' + str(record.id) + '").hide()' - if PermissionBackend.check_perm(get_current_authenticated_user(), - "note.change_transaction_invalidity_reason", record) else None, + + str(record.id) + '").focus();', + "onmouseout": lambda record: '$("#invalidity_reason_' + str(record.id) + '").hide()', } } ) @@ -101,15 +97,18 @@ class HistoryTable(tables.Table): """ When the validation status is hovered, an input field is displayed to let the user specify an invalidity reason """ + has_perm = PermissionBackend\ + .check_perm(get_current_authenticated_user(), "note.change_transaction_invalidity_reason", record) + val = "✔" if value else "✖" - if not PermissionBackend\ - .check_perm(get_current_authenticated_user(), "note.change_transaction_invalidity_reason", record): + + if value and not has_perm: return val val += "" return format_html(val) From fbf3a0bcf6d92ab60f6014963c4cff2fee2352d9 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Mon, 3 Aug 2020 12:35:51 +0200 Subject: [PATCH 022/319] :bug: A new user can't take an existing alias as username --- apps/member/models.py | 2 +- apps/registration/forms.py | 8 +- locale/de/LC_MESSAGES/django.po | 473 +++++++++-------- locale/fr/LC_MESSAGES/django.po | 492 +++++++++--------- .../email_validation_email_sent.html | 10 +- .../mails/email_validation_email.html | 2 +- .../mails/email_validation_email.txt | 2 +- 7 files changed, 525 insertions(+), 464 deletions(-) diff --git a/apps/member/models.py b/apps/member/models.py index 6ba4fb5f..5d6544af 100644 --- a/apps/member/models.py +++ b/apps/member/models.py @@ -139,7 +139,7 @@ class Profile(models.Model): 'token': email_validation_token.make_token(self.user), 'uid': urlsafe_base64_encode(force_bytes(self.user.pk)), }) - html = loader.render_to_string('registration/mails/email_validation_email.txt', + html = loader.render_to_string('registration/mails/email_validation_email.html', { 'user': self.user, 'domain': os.getenv("NOTE_URL", "note.example.com"), diff --git a/apps/registration/forms.py b/apps/registration/forms.py index 46559487..3ba791a0 100644 --- a/apps/registration/forms.py +++ b/apps/registration/forms.py @@ -5,7 +5,7 @@ from django import forms from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.models import User from django.utils.translation import gettext_lazy as _ -from note.models import NoteSpecial +from note.models import NoteSpecial, Alias from note_kfet.inputs import AmountInput @@ -22,6 +22,12 @@ class SignUpForm(UserCreationForm): self.fields['email'].required = True self.fields['email'].help_text = _("This address must be valid.") + def clean_username(self): + value = self.cleaned_data["username"] + if Alias.objects.filter(normalized_name=Alias.normalize(value)).exists(): + self.add_error("username", _("An alias with a similar name already exists.")) + return value + class Meta: model = User fields = ('first_name', 'last_name', 'username', 'email', ) diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index d28ecb34..b094a5ac 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-01 15:06+0200\n" +"POT-Creation-Date: 2020-08-03 12:35+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,35 +18,35 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: apps/activity/apps.py:10 apps/activity/models.py:102 -#: apps/activity/models.py:117 +#: apps/activity/apps.py:10 apps/activity/models.py:106 +#: apps/activity/models.py:121 msgid "activity" msgstr "" -#: apps/activity/forms.py:45 apps/activity/models.py:213 +#: apps/activity/forms.py:45 apps/activity/models.py:217 msgid "You can't invite someone once the activity is started." msgstr "" -#: apps/activity/forms.py:48 apps/activity/models.py:216 +#: apps/activity/forms.py:48 apps/activity/models.py:220 msgid "This activity is not validated yet." msgstr "" -#: apps/activity/forms.py:58 apps/activity/models.py:224 +#: apps/activity/forms.py:58 apps/activity/models.py:228 msgid "This person has been already invited 5 times this year." msgstr "" -#: apps/activity/forms.py:62 apps/activity/models.py:228 +#: apps/activity/forms.py:62 apps/activity/models.py:232 msgid "This person is already invited." msgstr "" -#: apps/activity/forms.py:66 apps/activity/models.py:232 +#: apps/activity/forms.py:66 apps/activity/models.py:236 msgid "You can't invite more than 3 people to this activity." msgstr "" -#: apps/activity/models.py:23 apps/activity/models.py:48 -#: apps/member/models.py:151 apps/note/models/notes.py:188 +#: apps/activity/models.py:24 apps/activity/models.py:49 +#: apps/member/models.py:158 apps/note/models/notes.py:212 #: apps/note/models/transactions.py:25 apps/note/models/transactions.py:45 -#: apps/note/models/transactions.py:263 apps/permission/models.py:332 +#: apps/note/models/transactions.py:263 apps/permission/models.py:339 #: apps/wei/models.py:65 apps/wei/models.py:117 #: templates/member/club_info.html:13 templates/member/profile_info.html:14 #: templates/registration/future_profile_detail.html:16 @@ -54,123 +54,123 @@ msgstr "" msgid "name" msgstr "" -#: apps/activity/models.py:27 templates/activity/activity_detail.html:39 +#: apps/activity/models.py:28 templates/activity/activity_detail.html:39 msgid "can invite" msgstr "" -#: apps/activity/models.py:30 templates/activity/activity_detail.html:43 +#: apps/activity/models.py:31 templates/activity/activity_detail.html:43 msgid "guest entry fee" msgstr "" -#: apps/activity/models.py:34 +#: apps/activity/models.py:35 msgid "activity type" msgstr "" -#: apps/activity/models.py:35 +#: apps/activity/models.py:36 msgid "activity types" msgstr "" -#: apps/activity/models.py:53 apps/note/models/transactions.py:81 -#: apps/permission/models.py:113 apps/permission/models.py:192 +#: apps/activity/models.py:54 apps/note/models/transactions.py:81 +#: apps/permission/models.py:120 apps/permission/models.py:199 #: apps/wei/models.py:71 apps/wei/models.py:128 #: templates/activity/activity_detail.html:16 msgid "description" msgstr "" -#: apps/activity/models.py:60 apps/note/models/notes.py:164 -#: apps/note/models/transactions.py:66 apps/permission/models.py:167 +#: apps/activity/models.py:61 apps/note/models/notes.py:188 +#: apps/note/models/transactions.py:66 apps/permission/models.py:174 #: templates/activity/activity_detail.html:19 msgid "type" msgstr "" -#: apps/activity/models.py:66 apps/logs/models.py:21 apps/member/models.py:259 -#: apps/note/models/notes.py:117 apps/treasury/models.py:221 +#: apps/activity/models.py:67 apps/logs/models.py:22 apps/member/models.py:266 +#: apps/note/models/notes.py:126 apps/treasury/models.py:222 #: apps/wei/models.py:159 templates/treasury/sogecredit_detail.html:14 #: templates/wei/survey.html:16 msgid "user" msgstr "" -#: apps/activity/models.py:73 templates/activity/activity_detail.html:33 +#: apps/activity/models.py:74 templates/activity/activity_detail.html:33 msgid "organizer" msgstr "" -#: apps/activity/models.py:80 templates/activity/activity_detail.html:36 +#: apps/activity/models.py:81 templates/activity/activity_detail.html:36 msgid "attendees club" msgstr "" -#: apps/activity/models.py:84 templates/activity/activity_detail.html:22 +#: apps/activity/models.py:85 templates/activity/activity_detail.html:22 msgid "start date" msgstr "" -#: apps/activity/models.py:88 templates/activity/activity_detail.html:25 +#: apps/activity/models.py:89 templates/activity/activity_detail.html:25 msgid "end date" msgstr "" -#: apps/activity/models.py:93 apps/note/models/transactions.py:146 +#: apps/activity/models.py:94 apps/note/models/transactions.py:146 #: templates/activity/activity_detail.html:47 msgid "valid" msgstr "" -#: apps/activity/models.py:98 templates/activity/activity_detail.html:61 +#: apps/activity/models.py:99 templates/activity/activity_detail.html:61 msgid "open" msgstr "" -#: apps/activity/models.py:103 +#: apps/activity/models.py:107 msgid "activities" msgstr "" -#: apps/activity/models.py:122 +#: apps/activity/models.py:126 msgid "entry time" msgstr "" -#: apps/activity/models.py:128 apps/note/apps.py:14 -#: apps/note/models/notes.py:58 +#: apps/activity/models.py:132 apps/note/apps.py:14 +#: apps/note/models/notes.py:60 msgid "note" msgstr "" -#: apps/activity/models.py:139 templates/activity/activity_entry.html:38 +#: apps/activity/models.py:143 templates/activity/activity_entry.html:38 msgid "entry" msgstr "" -#: apps/activity/models.py:140 templates/activity/activity_entry.html:38 +#: apps/activity/models.py:144 templates/activity/activity_entry.html:38 msgid "entries" msgstr "" -#: apps/activity/models.py:146 +#: apps/activity/models.py:150 msgid "Already entered on " msgstr "" -#: apps/activity/models.py:146 apps/activity/tables.py:54 +#: apps/activity/models.py:150 apps/activity/tables.py:54 msgid "{:%Y-%m-%d %H:%M:%S}" msgstr "" -#: apps/activity/models.py:154 +#: apps/activity/models.py:158 msgid "The balance is negative." msgstr "" -#: apps/activity/models.py:184 +#: apps/activity/models.py:188 msgid "last name" msgstr "" -#: apps/activity/models.py:189 templates/member/profile_info.html:14 +#: apps/activity/models.py:193 templates/member/profile_info.html:14 #: templates/registration/future_profile_detail.html:16 #: templates/wei/weimembership_form.html:18 msgid "first name" msgstr "" -#: apps/activity/models.py:196 +#: apps/activity/models.py:200 msgid "inviter" msgstr "" -#: apps/activity/models.py:237 +#: apps/activity/models.py:244 msgid "guest" msgstr "" -#: apps/activity/models.py:238 +#: apps/activity/models.py:245 msgid "guests" msgstr "" -#: apps/activity/models.py:250 +#: apps/activity/models.py:257 msgid "Invitation" msgstr "" @@ -182,26 +182,26 @@ msgstr "" msgid "remove" msgstr "" -#: apps/activity/tables.py:75 apps/treasury/models.py:140 +#: apps/activity/tables.py:75 apps/treasury/models.py:141 msgid "Type" msgstr "" #: apps/activity/tables.py:77 apps/member/forms.py:102 -#: apps/registration/forms.py:64 apps/treasury/forms.py:120 +#: apps/registration/forms.py:70 apps/treasury/forms.py:120 msgid "Last name" msgstr "" #: apps/activity/tables.py:79 apps/member/forms.py:107 -#: apps/registration/forms.py:69 apps/treasury/forms.py:122 +#: apps/registration/forms.py:75 apps/treasury/forms.py:122 #: templates/note/transaction_form.html:129 msgid "First name" msgstr "" -#: apps/activity/tables.py:81 apps/note/models/notes.py:67 +#: apps/activity/tables.py:81 apps/note/models/notes.py:69 msgid "Note" msgstr "" -#: apps/activity/tables.py:83 apps/member/tables.py:42 +#: apps/activity/tables.py:83 apps/member/tables.py:43 msgid "Balance" msgstr "" @@ -209,7 +209,7 @@ msgstr "" msgid "Create new activity" msgstr "" -#: apps/activity/views.py:41 templates/base.html:121 +#: apps/activity/views.py:41 templates/base.html:114 msgid "Activities" msgstr "" @@ -237,75 +237,75 @@ msgstr "" msgid "Logs" msgstr "" -#: apps/logs/models.py:27 +#: apps/logs/models.py:28 msgid "IP Address" msgstr "" -#: apps/logs/models.py:35 apps/permission/models.py:137 +#: apps/logs/models.py:36 apps/permission/models.py:144 msgid "model" msgstr "" -#: apps/logs/models.py:42 +#: apps/logs/models.py:43 msgid "identifier" msgstr "" -#: apps/logs/models.py:47 +#: apps/logs/models.py:48 msgid "previous data" msgstr "" -#: apps/logs/models.py:52 +#: apps/logs/models.py:53 msgid "new data" msgstr "" -#: apps/logs/models.py:60 +#: apps/logs/models.py:61 msgid "create" msgstr "" -#: apps/logs/models.py:61 apps/note/tables.py:161 +#: apps/logs/models.py:62 apps/note/tables.py:160 #: templates/activity/activity_detail.html:67 msgid "edit" msgstr "" -#: apps/logs/models.py:62 apps/note/tables.py:138 apps/note/tables.py:166 -#: apps/permission/models.py:130 apps/wei/tables.py:65 +#: apps/logs/models.py:63 apps/note/tables.py:137 apps/note/tables.py:165 +#: apps/permission/models.py:137 apps/wei/tables.py:65 msgid "delete" msgstr "" -#: apps/logs/models.py:65 +#: apps/logs/models.py:66 msgid "action" msgstr "" -#: apps/logs/models.py:73 +#: apps/logs/models.py:74 msgid "timestamp" msgstr "" -#: apps/logs/models.py:77 +#: apps/logs/models.py:78 msgid "Logs cannot be destroyed." msgstr "" -#: apps/logs/models.py:80 +#: apps/logs/models.py:81 msgid "changelog" msgstr "" -#: apps/logs/models.py:81 +#: apps/logs/models.py:82 msgid "changelogs" msgstr "" -#: apps/member/admin.py:53 apps/member/models.py:178 +#: apps/member/admin.py:52 apps/member/models.py:185 #: templates/member/club_info.html:41 msgid "membership fee (paid students)" msgstr "" -#: apps/member/admin.py:54 apps/member/models.py:183 +#: apps/member/admin.py:53 apps/member/models.py:190 #: templates/member/club_info.html:44 msgid "membership fee (unpaid students)" msgstr "" -#: apps/member/admin.py:68 apps/member/models.py:270 +#: apps/member/admin.py:67 apps/member/models.py:277 msgid "roles" msgstr "" -#: apps/member/admin.py:69 apps/member/models.py:284 +#: apps/member/admin.py:68 apps/member/models.py:291 msgid "fee" msgstr "" @@ -314,22 +314,23 @@ msgid "member" msgstr "" #: apps/member/forms.py:58 apps/member/views.py:82 +#: apps/registration/forms.py:28 msgid "An alias with a similar name already exists." msgstr "" -#: apps/member/forms.py:81 apps/registration/forms.py:44 +#: apps/member/forms.py:81 apps/registration/forms.py:50 msgid "Inscription paid by Société Générale" msgstr "" -#: apps/member/forms.py:83 apps/registration/forms.py:46 +#: apps/member/forms.py:83 apps/registration/forms.py:52 msgid "Check this case is the Société Générale paid the inscription." msgstr "" -#: apps/member/forms.py:88 apps/registration/forms.py:51 +#: apps/member/forms.py:88 apps/registration/forms.py:57 msgid "Credit type" msgstr "" -#: apps/member/forms.py:89 apps/registration/forms.py:52 +#: apps/member/forms.py:89 apps/registration/forms.py:58 msgid "No credit" msgstr "" @@ -337,20 +338,20 @@ msgstr "" msgid "You can credit the note of the user." msgstr "" -#: apps/member/forms.py:95 apps/registration/forms.py:57 +#: apps/member/forms.py:95 apps/registration/forms.py:63 msgid "Credit amount" msgstr "" -#: apps/member/forms.py:112 apps/registration/forms.py:74 +#: apps/member/forms.py:112 apps/registration/forms.py:80 #: apps/treasury/forms.py:124 templates/note/transaction_form.html:135 msgid "Bank" msgstr "" -#: apps/member/forms.py:138 +#: apps/member/forms.py:139 msgid "User" msgstr "" -#: apps/member/forms.py:152 +#: apps/member/forms.py:153 msgid "Roles" msgstr "" @@ -478,94 +479,94 @@ msgstr "" msgid "Activate your Note Kfet account" msgstr "" -#: apps/member/models.py:156 templates/member/club_info.html:57 +#: apps/member/models.py:163 templates/member/club_info.html:57 #: templates/registration/future_profile_detail.html:22 #: templates/wei/weiclub_info.html:52 templates/wei/weimembership_form.html:24 msgid "email" msgstr "" -#: apps/member/models.py:163 +#: apps/member/models.py:170 msgid "parent club" msgstr "" -#: apps/member/models.py:172 +#: apps/member/models.py:179 msgid "require memberships" msgstr "" -#: apps/member/models.py:173 +#: apps/member/models.py:180 msgid "Uncheck if this club don't require memberships." msgstr "" -#: apps/member/models.py:189 templates/member/club_info.html:33 +#: apps/member/models.py:196 templates/member/club_info.html:33 msgid "membership duration" msgstr "" -#: apps/member/models.py:190 +#: apps/member/models.py:197 msgid "The longest time (in days) a membership can last (NULL = infinite)." msgstr "" -#: apps/member/models.py:197 templates/member/club_info.html:23 +#: apps/member/models.py:204 templates/member/club_info.html:23 msgid "membership start" msgstr "" -#: apps/member/models.py:198 +#: apps/member/models.py:205 msgid "How long after January 1st the members can renew their membership." msgstr "" -#: apps/member/models.py:205 templates/member/club_info.html:28 +#: apps/member/models.py:212 templates/member/club_info.html:28 msgid "membership end" msgstr "" -#: apps/member/models.py:206 +#: apps/member/models.py:213 msgid "" "How long the membership can last after January 1st of the next year after " "members can renew their membership." msgstr "" -#: apps/member/models.py:240 apps/member/models.py:265 -#: apps/note/models/notes.py:139 +#: apps/member/models.py:247 apps/member/models.py:272 +#: apps/note/models/notes.py:163 msgid "club" msgstr "" -#: apps/member/models.py:241 +#: apps/member/models.py:248 msgid "clubs" msgstr "" -#: apps/member/models.py:275 +#: apps/member/models.py:282 msgid "membership starts on" msgstr "" -#: apps/member/models.py:279 +#: apps/member/models.py:286 msgid "membership ends on" msgstr "" -#: apps/member/models.py:303 apps/member/views.py:535 apps/wei/views.py:797 +#: apps/member/models.py:310 apps/member/views.py:535 apps/wei/views.py:795 msgid "User is not a member of the parent club" msgstr "" -#: apps/member/models.py:310 +#: apps/member/models.py:317 #, python-brace-format msgid "The role {role} does not apply to the club {club}." msgstr "" -#: apps/member/models.py:321 apps/member/views.py:544 +#: apps/member/models.py:328 apps/member/views.py:544 msgid "User is already a member of the club" msgstr "" -#: apps/member/models.py:372 +#: apps/member/models.py:379 #, python-brace-format msgid "Membership of {user} for the club {club}" msgstr "" -#: apps/member/models.py:375 +#: apps/member/models.py:382 msgid "membership" msgstr "" -#: apps/member/models.py:376 +#: apps/member/models.py:383 msgid "memberships" msgstr "" -#: apps/member/tables.py:113 +#: apps/member/tables.py:114 msgid "Renew" msgstr "" @@ -619,7 +620,7 @@ msgstr "" msgid "Add new member to the club" msgstr "" -#: apps/member/views.py:530 apps/wei/views.py:788 +#: apps/member/views.py:530 apps/wei/views.py:786 msgid "" "This user don't have enough money to join this club, and can't have a " "negative balance." @@ -634,8 +635,8 @@ msgid "The membership must begin before {:%m-%d-%Y}." msgstr "" #: apps/member/views.py:570 apps/member/views.py:572 apps/member/views.py:574 -#: apps/registration/views.py:292 apps/registration/views.py:294 -#: apps/registration/views.py:296 +#: apps/registration/views.py:290 apps/registration/views.py:292 +#: apps/registration/views.py:294 msgid "This field is required." msgstr "" @@ -647,16 +648,16 @@ msgstr "" msgid "Members of the club" msgstr "" -#: apps/note/admin.py:134 apps/note/models/transactions.py:106 +#: apps/note/admin.py:133 apps/note/models/transactions.py:106 msgid "source" msgstr "" -#: apps/note/admin.py:142 apps/note/admin.py:192 +#: apps/note/admin.py:141 apps/note/admin.py:191 #: apps/note/models/transactions.py:55 apps/note/models/transactions.py:119 msgid "destination" msgstr "" -#: apps/note/admin.py:197 apps/note/models/transactions.py:59 +#: apps/note/admin.py:196 apps/note/models/transactions.py:59 #: apps/note/models/transactions.py:137 msgid "amount" msgstr "" @@ -669,104 +670,104 @@ msgstr "" msgid "Maximal size: 2MB" msgstr "" -#: apps/note/models/notes.py:27 +#: apps/note/models/notes.py:29 msgid "account balance" msgstr "" -#: apps/note/models/notes.py:28 +#: apps/note/models/notes.py:30 msgid "in centimes, money credited for this instance" msgstr "" -#: apps/note/models/notes.py:32 +#: apps/note/models/notes.py:34 msgid "last negative date" msgstr "" -#: apps/note/models/notes.py:33 +#: apps/note/models/notes.py:35 msgid "last time the balance was negative" msgstr "" -#: apps/note/models/notes.py:38 +#: apps/note/models/notes.py:40 msgid "active" msgstr "" -#: apps/note/models/notes.py:41 +#: apps/note/models/notes.py:43 msgid "" "Designates whether this note should be treated as active. Unselect this " "instead of deleting notes." msgstr "" -#: apps/note/models/notes.py:45 +#: apps/note/models/notes.py:47 msgid "display image" msgstr "" -#: apps/note/models/notes.py:53 apps/note/models/transactions.py:129 +#: apps/note/models/notes.py:55 apps/note/models/transactions.py:129 msgid "created at" msgstr "" -#: apps/note/models/notes.py:59 +#: apps/note/models/notes.py:61 msgid "notes" msgstr "" -#: apps/note/models/notes.py:77 apps/note/models/notes.py:101 +#: apps/note/models/notes.py:86 apps/note/models/notes.py:110 msgid "This alias is already taken." msgstr "" -#: apps/note/models/notes.py:121 +#: apps/note/models/notes.py:130 msgid "one's note" msgstr "" -#: apps/note/models/notes.py:122 +#: apps/note/models/notes.py:131 msgid "users note" msgstr "" -#: apps/note/models/notes.py:128 +#: apps/note/models/notes.py:137 #, python-format msgid "%(user)s's note" msgstr "" -#: apps/note/models/notes.py:143 +#: apps/note/models/notes.py:167 msgid "club note" msgstr "" -#: apps/note/models/notes.py:144 +#: apps/note/models/notes.py:168 msgid "clubs notes" msgstr "" -#: apps/note/models/notes.py:150 +#: apps/note/models/notes.py:174 #, python-format msgid "Note of %(club)s club" msgstr "" -#: apps/note/models/notes.py:170 +#: apps/note/models/notes.py:194 msgid "special note" msgstr "" -#: apps/note/models/notes.py:171 +#: apps/note/models/notes.py:195 msgid "special notes" msgstr "" -#: apps/note/models/notes.py:194 +#: apps/note/models/notes.py:218 msgid "Invalid alias" msgstr "" -#: apps/note/models/notes.py:210 +#: apps/note/models/notes.py:234 msgid "alias" msgstr "" -#: apps/note/models/notes.py:211 templates/member/club_info.html:54 +#: apps/note/models/notes.py:235 templates/member/club_info.html:54 #: templates/member/profile_info.html:38 templates/wei/weiclub_info.html:48 msgid "aliases" msgstr "" -#: apps/note/models/notes.py:233 +#: apps/note/models/notes.py:257 msgid "Alias is too long." msgstr "" -#: apps/note/models/notes.py:238 +#: apps/note/models/notes.py:262 msgid "An alias with a similar name already exists: {} " msgstr "" -#: apps/note/models/notes.py:251 +#: apps/note/models/notes.py:275 msgid "You can't delete your main alias." msgstr "" @@ -815,7 +816,7 @@ msgstr "" msgid "reason" msgstr "" -#: apps/note/models/transactions.py:151 apps/note/tables.py:113 +#: apps/note/models/transactions.py:151 apps/note/tables.py:112 msgid "invalidity reason" msgstr "" @@ -873,7 +874,7 @@ msgstr "" msgid "membership transaction" msgstr "" -#: apps/note/models/transactions.py:308 apps/treasury/models.py:227 +#: apps/note/models/transactions.py:308 apps/treasury/models.py:228 msgid "membership transactions" msgstr "" @@ -885,17 +886,17 @@ msgstr "" msgid "Click to validate" msgstr "" -#: apps/note/tables.py:111 +#: apps/note/tables.py:110 msgid "No reason specified" msgstr "" -#: apps/note/tables.py:140 apps/note/tables.py:168 apps/wei/tables.py:66 +#: apps/note/tables.py:139 apps/note/tables.py:167 apps/wei/tables.py:66 #: templates/treasury/sogecredit_detail.html:59 #: templates/wei/weiregistration_confirm_delete.html:32 msgid "Delete" msgstr "" -#: apps/note/tables.py:163 apps/wei/tables.py:42 apps/wei/tables.py:43 +#: apps/note/tables.py:162 apps/wei/tables.py:42 apps/wei/tables.py:43 #: templates/member/club_info.html:67 templates/note/conso_form.html:128 #: templates/wei/bus_tables.html:15 templates/wei/busteam_tables.html:15 #: templates/wei/busteam_tables.html:33 templates/wei/weiclub_info.html:68 @@ -906,95 +907,95 @@ msgstr "" msgid "Transfer money" msgstr "" -#: apps/note/views.py:67 +#: apps/note/views.py:69 msgid "Create new button" msgstr "" -#: apps/note/views.py:76 +#: apps/note/views.py:78 msgid "Search button" msgstr "" -#: apps/note/views.py:99 +#: apps/note/views.py:101 msgid "Update button" msgstr "" -#: apps/note/views.py:136 templates/base.html:94 +#: apps/note/views.py:138 templates/base.html:94 msgid "Consumptions" msgstr "" -#: apps/permission/models.py:92 +#: apps/permission/models.py:99 #, python-brace-format msgid "Can {type} {model}.{field} in {query}" msgstr "" -#: apps/permission/models.py:94 +#: apps/permission/models.py:101 #, python-brace-format msgid "Can {type} {model} in {query}" msgstr "" -#: apps/permission/models.py:107 +#: apps/permission/models.py:114 msgid "rank" msgstr "" -#: apps/permission/models.py:120 +#: apps/permission/models.py:127 msgid "permission mask" msgstr "" -#: apps/permission/models.py:121 +#: apps/permission/models.py:128 msgid "permission masks" msgstr "" -#: apps/permission/models.py:127 +#: apps/permission/models.py:134 msgid "add" msgstr "" -#: apps/permission/models.py:128 +#: apps/permission/models.py:135 msgid "view" msgstr "" -#: apps/permission/models.py:129 +#: apps/permission/models.py:136 msgid "change" msgstr "" -#: apps/permission/models.py:161 +#: apps/permission/models.py:168 msgid "query" msgstr "" -#: apps/permission/models.py:174 +#: apps/permission/models.py:181 msgid "mask" msgstr "" -#: apps/permission/models.py:180 +#: apps/permission/models.py:187 msgid "field" msgstr "" -#: apps/permission/models.py:185 +#: apps/permission/models.py:192 msgid "" "Tells if the permission should be granted even if the membership of the user " "is expired." msgstr "" -#: apps/permission/models.py:186 templates/permission/all_rights.html:26 +#: apps/permission/models.py:193 templates/permission/all_rights.html:26 msgid "permanent" msgstr "" -#: apps/permission/models.py:197 +#: apps/permission/models.py:204 msgid "permission" msgstr "" -#: apps/permission/models.py:198 apps/permission/models.py:337 +#: apps/permission/models.py:205 apps/permission/models.py:344 msgid "permissions" msgstr "" -#: apps/permission/models.py:203 +#: apps/permission/models.py:210 msgid "Specifying field applies only to view and change permission types." msgstr "" -#: apps/permission/models.py:342 +#: apps/permission/models.py:349 msgid "for club" msgstr "" -#: apps/permission/models.py:352 apps/permission/models.py:353 +#: apps/permission/models.py:359 apps/permission/models.py:360 msgid "role permissions" msgstr "" @@ -1019,7 +1020,7 @@ msgid "" "{model_name}." msgstr "" -#: apps/permission/views.py:44 templates/base.html:136 +#: apps/permission/views.py:44 templates/base.html:129 msgid "Rights" msgstr "" @@ -1031,21 +1032,21 @@ msgstr "" msgid "registration" msgstr "" -#: apps/registration/forms.py:32 +#: apps/registration/forms.py:38 msgid "Register to the WEI" msgstr "" -#: apps/registration/forms.py:34 +#: apps/registration/forms.py:40 msgid "" "Check this case if you want to register to the WEI. If you hesitate, you " "will be able to register later, after validating your account in the Kfet." msgstr "" -#: apps/registration/forms.py:79 +#: apps/registration/forms.py:85 msgid "Join BDE Club" msgstr "" -#: apps/registration/forms.py:86 +#: apps/registration/forms.py:92 msgid "Join Kfet Club" msgstr "" @@ -1077,32 +1078,32 @@ msgstr "" msgid "Pre-registered users list" msgstr "" -#: apps/registration/views.py:190 +#: apps/registration/views.py:188 msgid "Unregistered users" msgstr "" -#: apps/registration/views.py:203 +#: apps/registration/views.py:201 msgid "Registration detail" msgstr "" -#: apps/registration/views.py:258 +#: apps/registration/views.py:256 msgid "You must join the BDE." msgstr "" -#: apps/registration/views.py:280 +#: apps/registration/views.py:278 msgid "You must join BDE club before joining Kfet club." msgstr "" -#: apps/registration/views.py:285 +#: apps/registration/views.py:283 msgid "" "The entered amount is not enough for the memberships, should be at least {}" msgstr "" -#: apps/registration/views.py:360 +#: apps/registration/views.py:358 msgid "Invalidate pre-registration" msgstr "" -#: apps/treasury/apps.py:12 templates/base.html:126 +#: apps/treasury/apps.py:12 templates/base.html:119 msgid "Treasury" msgstr "" @@ -1136,128 +1137,128 @@ msgstr "" msgid "Amount" msgstr "" -#: apps/treasury/models.py:20 +#: apps/treasury/models.py:21 msgid "Invoice identifier" msgstr "" -#: apps/treasury/models.py:34 +#: apps/treasury/models.py:35 msgid "BDE" msgstr "" -#: apps/treasury/models.py:39 +#: apps/treasury/models.py:40 msgid "Object" msgstr "" -#: apps/treasury/models.py:43 +#: apps/treasury/models.py:44 msgid "Description" msgstr "" -#: apps/treasury/models.py:48 templates/note/transaction_form.html:123 +#: apps/treasury/models.py:49 templates/note/transaction_form.html:123 msgid "Name" msgstr "" -#: apps/treasury/models.py:52 +#: apps/treasury/models.py:53 msgid "Address" msgstr "" -#: apps/treasury/models.py:57 +#: apps/treasury/models.py:58 msgid "Place" msgstr "" -#: apps/treasury/models.py:61 +#: apps/treasury/models.py:62 msgid "Acquitted" msgstr "" -#: apps/treasury/models.py:65 +#: apps/treasury/models.py:66 msgid "invoice" msgstr "" -#: apps/treasury/models.py:66 +#: apps/treasury/models.py:67 msgid "invoices" msgstr "" -#: apps/treasury/models.py:81 +#: apps/treasury/models.py:82 msgid "Designation" msgstr "" -#: apps/treasury/models.py:85 +#: apps/treasury/models.py:86 msgid "Quantity" msgstr "" -#: apps/treasury/models.py:89 +#: apps/treasury/models.py:90 msgid "Unit price" msgstr "" -#: apps/treasury/models.py:105 +#: apps/treasury/models.py:106 msgid "product" msgstr "" -#: apps/treasury/models.py:106 +#: apps/treasury/models.py:107 msgid "products" msgstr "" -#: apps/treasury/models.py:123 +#: apps/treasury/models.py:124 msgid "remittance type" msgstr "" -#: apps/treasury/models.py:124 +#: apps/treasury/models.py:125 msgid "remittance types" msgstr "" -#: apps/treasury/models.py:134 +#: apps/treasury/models.py:135 msgid "Date" msgstr "" -#: apps/treasury/models.py:145 +#: apps/treasury/models.py:146 msgid "Comment" msgstr "" -#: apps/treasury/models.py:150 +#: apps/treasury/models.py:151 msgid "Closed" msgstr "" -#: apps/treasury/models.py:154 +#: apps/treasury/models.py:155 msgid "remittance" msgstr "" -#: apps/treasury/models.py:155 +#: apps/treasury/models.py:156 msgid "remittances" msgstr "" -#: apps/treasury/models.py:187 +#: apps/treasury/models.py:188 msgid "Remittance #{:d}: {}" msgstr "" -#: apps/treasury/models.py:206 apps/treasury/tables.py:76 +#: apps/treasury/models.py:207 apps/treasury/tables.py:76 #: apps/treasury/tables.py:84 templates/treasury/invoice_list.html:13 #: templates/treasury/remittance_list.html:13 #: templates/treasury/sogecredit_list.html:13 msgid "Remittance" msgstr "" -#: apps/treasury/models.py:210 +#: apps/treasury/models.py:211 msgid "special transaction proxy" msgstr "" -#: apps/treasury/models.py:211 +#: apps/treasury/models.py:212 msgid "special transaction proxies" msgstr "" -#: apps/treasury/models.py:233 +#: apps/treasury/models.py:234 msgid "credit transaction" msgstr "" -#: apps/treasury/models.py:296 +#: apps/treasury/models.py:297 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." msgstr "" -#: apps/treasury/models.py:308 templates/treasury/sogecredit_detail.html:10 +#: apps/treasury/models.py:309 templates/treasury/sogecredit_detail.html:10 msgid "Credit from the Société générale" msgstr "" -#: apps/treasury/models.py:309 +#: apps/treasury/models.py:310 msgid "Credits from the Société générale" msgstr "" @@ -1337,7 +1338,7 @@ msgid "Manage credits from the Société générale" msgstr "" #: apps/wei/apps.py:10 apps/wei/models.py:48 apps/wei/models.py:49 -#: apps/wei/models.py:60 apps/wei/models.py:166 templates/base.html:131 +#: apps/wei/models.py:60 apps/wei/models.py:166 templates/base.html:124 msgid "WEI" msgstr "" @@ -1577,89 +1578,89 @@ msgstr "" msgid "View registrations to the WEI" msgstr "" -#: apps/wei/views.py:253 +#: apps/wei/views.py:251 msgid "Find WEI Registration" msgstr "" -#: apps/wei/views.py:264 +#: apps/wei/views.py:262 msgid "Update the WEI" msgstr "" -#: apps/wei/views.py:285 +#: apps/wei/views.py:283 msgid "Create new bus" msgstr "" -#: apps/wei/views.py:316 +#: apps/wei/views.py:314 msgid "Update bus" msgstr "" -#: apps/wei/views.py:346 +#: apps/wei/views.py:344 msgid "Manage bus" msgstr "" -#: apps/wei/views.py:373 +#: apps/wei/views.py:371 msgid "Create new team" msgstr "" -#: apps/wei/views.py:405 +#: apps/wei/views.py:403 msgid "Update team" msgstr "" -#: apps/wei/views.py:436 +#: apps/wei/views.py:434 msgid "Manage WEI team" msgstr "" -#: apps/wei/views.py:458 +#: apps/wei/views.py:456 msgid "Register first year student to the WEI" msgstr "" -#: apps/wei/views.py:470 templates/wei/weiclub_info.html:62 +#: apps/wei/views.py:468 templates/wei/weiclub_info.html:62 msgid "Register 1A" msgstr "" -#: apps/wei/views.py:491 apps/wei/views.py:561 +#: apps/wei/views.py:489 apps/wei/views.py:559 msgid "This user is already registered to this WEI." msgstr "" -#: apps/wei/views.py:496 +#: apps/wei/views.py:494 msgid "" "This user can't be in her/his first year since he/she has already participed " "to a WEI." msgstr "" -#: apps/wei/views.py:513 +#: apps/wei/views.py:511 msgid "Register old student to the WEI" msgstr "" -#: apps/wei/views.py:525 templates/wei/weiclub_info.html:65 +#: apps/wei/views.py:523 templates/wei/weiclub_info.html:65 msgid "Register 2A+" msgstr "" -#: apps/wei/views.py:543 apps/wei/views.py:631 +#: apps/wei/views.py:541 apps/wei/views.py:629 msgid "You already opened an account in the Société générale." msgstr "" -#: apps/wei/views.py:591 +#: apps/wei/views.py:589 msgid "Update WEI Registration" msgstr "" -#: apps/wei/views.py:681 +#: apps/wei/views.py:679 msgid "Delete WEI registration" msgstr "" -#: apps/wei/views.py:692 +#: apps/wei/views.py:690 msgid "You don't have the right to delete this WEI registration." msgstr "" -#: apps/wei/views.py:711 +#: apps/wei/views.py:709 msgid "Validate WEI registration" msgstr "" -#: apps/wei/views.py:792 +#: apps/wei/views.py:790 msgid "This user didn't give her/his caution check." msgstr "" -#: apps/wei/views.py:829 apps/wei/views.py:882 apps/wei/views.py:892 +#: apps/wei/views.py:827 apps/wei/views.py:880 apps/wei/views.py:890 #: templates/wei/survey.html:12 templates/wei/survey_closed.html:12 #: templates/wei/survey_end.html:12 msgid "Survey WEI" @@ -1790,15 +1791,11 @@ msgstr "" msgid "Clubs" msgstr "" -#: templates/base.html:115 -msgid "Registrations" -msgstr "" - -#: templates/base.html:141 +#: templates/base.html:134 msgid "Admin" msgstr "" -#: templates/base.html:180 +#: templates/base.html:173 msgid "" "Your e-mail address is not validated. Please check your mail inbox and click " "on the validation link." @@ -1936,10 +1933,14 @@ msgstr "" msgid "Save Changes" msgstr "" -#: templates/member/user_list.html:16 +#: templates/member/user_list.html:17 msgid "There is no user with this pattern." msgstr "" +#: templates/member/user_list.html:26 +msgid "Registrations" +msgstr "" + #: templates/note/conso_form.html:28 msgid "Consum" msgstr "" @@ -2073,6 +2074,21 @@ msgid "" "activate your account." msgstr "" +#: templates/registration/email_validation_email_sent.html:4 +msgid "Account activation" +msgstr "" + +#: templates/registration/email_validation_email_sent.html:7 +msgid "" +"An email has been sent. Please click on the link to activate your account." +msgstr "" + +#: templates/registration/email_validation_email_sent.html:11 +msgid "" +"You must also go to the Kfet to pay your membership. The WEI registration " +"includes the BDE membership." +msgstr "" + #: templates/registration/future_profile_detail.html:49 #: templates/wei/weiregistration_confirm_delete.html:12 msgid "Delete registration" @@ -2128,32 +2144,39 @@ msgstr "" msgid "Forgotten your password or username?" msgstr "" +#: templates/registration/mails/email_validation_email.html:12 #: templates/registration/mails/email_validation_email.txt:3 msgid "Hi" msgstr "" +#: templates/registration/mails/email_validation_email.html:16 #: templates/registration/mails/email_validation_email.txt:5 msgid "" "You recently registered on the Note Kfet. Please click on the link below to " "confirm your registration." msgstr "" +#: templates/registration/mails/email_validation_email.html:26 #: templates/registration/mails/email_validation_email.txt:9 msgid "" "This link is only valid for a couple of days, after that you will need to " "contact us to validate your email." msgstr "" +#: templates/registration/mails/email_validation_email.html:30 #: 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." +"you can log in. You will need to pay your membership in the Kfet. Note that " +"the WEI registration includes the Kfet membership." msgstr "" +#: templates/registration/mails/email_validation_email.html:34 #: templates/registration/mails/email_validation_email.txt:13 msgid "Thanks" msgstr "" +#: templates/registration/mails/email_validation_email.html:39 #: templates/registration/mails/email_validation_email.txt:15 msgid "The Note Kfet team." msgstr "" diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 9df44fec..511b3efb 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-01 15:06+0200\n" +"POT-Creation-Date: 2020-08-03 12:35+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,36 +18,36 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" -#: apps/activity/apps.py:10 apps/activity/models.py:102 -#: apps/activity/models.py:117 +#: apps/activity/apps.py:10 apps/activity/models.py:106 +#: apps/activity/models.py:121 msgid "activity" msgstr "activité" -#: apps/activity/forms.py:45 apps/activity/models.py:213 +#: apps/activity/forms.py:45 apps/activity/models.py:217 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:48 apps/activity/models.py:216 +#: apps/activity/forms.py:48 apps/activity/models.py:220 msgid "This activity is not validated yet." msgstr "Cette activité n'est pas encore validée." -#: apps/activity/forms.py:58 apps/activity/models.py:224 +#: apps/activity/forms.py:58 apps/activity/models.py:228 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:62 apps/activity/models.py:228 +#: apps/activity/forms.py:62 apps/activity/models.py:232 msgid "This person is already invited." msgstr "Cette personne est déjà invitée." -#: apps/activity/forms.py:66 apps/activity/models.py:232 +#: apps/activity/forms.py:66 apps/activity/models.py:236 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:23 apps/activity/models.py:48 -#: apps/member/models.py:151 apps/note/models/notes.py:188 +#: apps/activity/models.py:24 apps/activity/models.py:49 +#: apps/member/models.py:158 apps/note/models/notes.py:212 #: apps/note/models/transactions.py:25 apps/note/models/transactions.py:45 -#: apps/note/models/transactions.py:263 apps/permission/models.py:332 +#: apps/note/models/transactions.py:263 apps/permission/models.py:339 #: apps/wei/models.py:65 apps/wei/models.py:117 #: templates/member/club_info.html:13 templates/member/profile_info.html:14 #: templates/registration/future_profile_detail.html:16 @@ -55,123 +55,123 @@ msgstr "Vous ne pouvez pas inviter plus de 3 personnes à cette activité." msgid "name" msgstr "nom" -#: apps/activity/models.py:27 templates/activity/activity_detail.html:39 +#: apps/activity/models.py:28 templates/activity/activity_detail.html:39 msgid "can invite" msgstr "peut inviter" -#: apps/activity/models.py:30 templates/activity/activity_detail.html:43 +#: apps/activity/models.py:31 templates/activity/activity_detail.html:43 msgid "guest entry fee" msgstr "cotisation de l'entrée invité" -#: apps/activity/models.py:34 +#: apps/activity/models.py:35 msgid "activity type" msgstr "type d'activité" -#: apps/activity/models.py:35 +#: apps/activity/models.py:36 msgid "activity types" msgstr "types d'activité" -#: apps/activity/models.py:53 apps/note/models/transactions.py:81 -#: apps/permission/models.py:113 apps/permission/models.py:192 +#: apps/activity/models.py:54 apps/note/models/transactions.py:81 +#: apps/permission/models.py:120 apps/permission/models.py:199 #: apps/wei/models.py:71 apps/wei/models.py:128 #: templates/activity/activity_detail.html:16 msgid "description" msgstr "description" -#: apps/activity/models.py:60 apps/note/models/notes.py:164 -#: apps/note/models/transactions.py:66 apps/permission/models.py:167 +#: apps/activity/models.py:61 apps/note/models/notes.py:188 +#: apps/note/models/transactions.py:66 apps/permission/models.py:174 #: templates/activity/activity_detail.html:19 msgid "type" msgstr "type" -#: apps/activity/models.py:66 apps/logs/models.py:21 apps/member/models.py:259 -#: apps/note/models/notes.py:117 apps/treasury/models.py:221 +#: apps/activity/models.py:67 apps/logs/models.py:22 apps/member/models.py:266 +#: apps/note/models/notes.py:126 apps/treasury/models.py:222 #: apps/wei/models.py:159 templates/treasury/sogecredit_detail.html:14 #: templates/wei/survey.html:16 msgid "user" msgstr "utilisateur" -#: apps/activity/models.py:73 templates/activity/activity_detail.html:33 +#: apps/activity/models.py:74 templates/activity/activity_detail.html:33 msgid "organizer" msgstr "organisateur" -#: apps/activity/models.py:80 templates/activity/activity_detail.html:36 +#: apps/activity/models.py:81 templates/activity/activity_detail.html:36 msgid "attendees club" msgstr "club attendu" -#: apps/activity/models.py:84 templates/activity/activity_detail.html:22 +#: apps/activity/models.py:85 templates/activity/activity_detail.html:22 msgid "start date" msgstr "date de début" -#: apps/activity/models.py:88 templates/activity/activity_detail.html:25 +#: apps/activity/models.py:89 templates/activity/activity_detail.html:25 msgid "end date" msgstr "date de fin" -#: apps/activity/models.py:93 apps/note/models/transactions.py:146 +#: apps/activity/models.py:94 apps/note/models/transactions.py:146 #: templates/activity/activity_detail.html:47 msgid "valid" msgstr "valide" -#: apps/activity/models.py:98 templates/activity/activity_detail.html:61 +#: apps/activity/models.py:99 templates/activity/activity_detail.html:61 msgid "open" msgstr "ouvrir" -#: apps/activity/models.py:103 +#: apps/activity/models.py:107 msgid "activities" msgstr "activités" -#: apps/activity/models.py:122 +#: apps/activity/models.py:126 msgid "entry time" msgstr "heure d'entrée" -#: apps/activity/models.py:128 apps/note/apps.py:14 -#: apps/note/models/notes.py:58 +#: apps/activity/models.py:132 apps/note/apps.py:14 +#: apps/note/models/notes.py:60 msgid "note" msgstr "note" -#: apps/activity/models.py:139 templates/activity/activity_entry.html:38 +#: apps/activity/models.py:143 templates/activity/activity_entry.html:38 msgid "entry" msgstr "entrée" -#: apps/activity/models.py:140 templates/activity/activity_entry.html:38 +#: apps/activity/models.py:144 templates/activity/activity_entry.html:38 msgid "entries" msgstr "entrées" -#: apps/activity/models.py:146 +#: apps/activity/models.py:150 msgid "Already entered on " msgstr "Déjà rentré le " -#: apps/activity/models.py:146 apps/activity/tables.py:54 +#: apps/activity/models.py:150 apps/activity/tables.py:54 msgid "{:%Y-%m-%d %H:%M:%S}" msgstr "{:%d/%m/%Y %H:%M:%S}" -#: apps/activity/models.py:154 +#: apps/activity/models.py:158 msgid "The balance is negative." msgstr "La note est en négatif." -#: apps/activity/models.py:184 +#: apps/activity/models.py:188 msgid "last name" msgstr "nom de famille" -#: apps/activity/models.py:189 templates/member/profile_info.html:14 +#: apps/activity/models.py:193 templates/member/profile_info.html:14 #: templates/registration/future_profile_detail.html:16 #: templates/wei/weimembership_form.html:18 msgid "first name" msgstr "prénom" -#: apps/activity/models.py:196 +#: apps/activity/models.py:200 msgid "inviter" msgstr "hôte" -#: apps/activity/models.py:237 +#: apps/activity/models.py:244 msgid "guest" msgstr "invité" -#: apps/activity/models.py:238 +#: apps/activity/models.py:245 msgid "guests" msgstr "invités" -#: apps/activity/models.py:250 +#: apps/activity/models.py:257 msgid "Invitation" msgstr "Invitation" @@ -183,26 +183,26 @@ msgstr "Entré le " msgid "remove" msgstr "supprimer" -#: apps/activity/tables.py:75 apps/treasury/models.py:140 +#: apps/activity/tables.py:75 apps/treasury/models.py:141 msgid "Type" msgstr "Type" #: apps/activity/tables.py:77 apps/member/forms.py:102 -#: apps/registration/forms.py:64 apps/treasury/forms.py:120 +#: apps/registration/forms.py:70 apps/treasury/forms.py:120 msgid "Last name" msgstr "Nom de famille" #: apps/activity/tables.py:79 apps/member/forms.py:107 -#: apps/registration/forms.py:69 apps/treasury/forms.py:122 +#: apps/registration/forms.py:75 apps/treasury/forms.py:122 #: templates/note/transaction_form.html:129 msgid "First name" msgstr "Prénom" -#: apps/activity/tables.py:81 apps/note/models/notes.py:67 +#: apps/activity/tables.py:81 apps/note/models/notes.py:69 msgid "Note" msgstr "Note" -#: apps/activity/tables.py:83 apps/member/tables.py:42 +#: apps/activity/tables.py:83 apps/member/tables.py:43 msgid "Balance" msgstr "Solde du compte" @@ -210,7 +210,7 @@ msgstr "Solde du compte" msgid "Create new activity" msgstr "Créer une nouvelle activité" -#: apps/activity/views.py:41 templates/base.html:121 +#: apps/activity/views.py:41 templates/base.html:114 msgid "Activities" msgstr "Activités" @@ -238,75 +238,75 @@ msgstr "API" msgid "Logs" msgstr "Logs" -#: apps/logs/models.py:27 +#: apps/logs/models.py:28 msgid "IP Address" msgstr "Adresse IP" -#: apps/logs/models.py:35 apps/permission/models.py:137 +#: apps/logs/models.py:36 apps/permission/models.py:144 msgid "model" msgstr "Modèle" -#: apps/logs/models.py:42 +#: apps/logs/models.py:43 msgid "identifier" msgstr "Identifiant" -#: apps/logs/models.py:47 +#: apps/logs/models.py:48 msgid "previous data" msgstr "Données précédentes" -#: apps/logs/models.py:52 +#: apps/logs/models.py:53 msgid "new data" msgstr "Nouvelles données" -#: apps/logs/models.py:60 +#: apps/logs/models.py:61 msgid "create" msgstr "Créer" -#: apps/logs/models.py:61 apps/note/tables.py:161 +#: apps/logs/models.py:62 apps/note/tables.py:160 #: templates/activity/activity_detail.html:67 msgid "edit" msgstr "Modifier" -#: apps/logs/models.py:62 apps/note/tables.py:138 apps/note/tables.py:166 -#: apps/permission/models.py:130 apps/wei/tables.py:65 +#: apps/logs/models.py:63 apps/note/tables.py:137 apps/note/tables.py:165 +#: apps/permission/models.py:137 apps/wei/tables.py:65 msgid "delete" msgstr "Supprimer" -#: apps/logs/models.py:65 +#: apps/logs/models.py:66 msgid "action" msgstr "Action" -#: apps/logs/models.py:73 +#: apps/logs/models.py:74 msgid "timestamp" msgstr "Date" -#: apps/logs/models.py:77 +#: apps/logs/models.py:78 msgid "Logs cannot be destroyed." msgstr "Les logs ne peuvent pas être détruits." -#: apps/logs/models.py:80 +#: apps/logs/models.py:81 msgid "changelog" msgstr "journal de modification" -#: apps/logs/models.py:81 +#: apps/logs/models.py:82 msgid "changelogs" msgstr "journaux de modifications" -#: apps/member/admin.py:53 apps/member/models.py:178 +#: apps/member/admin.py:52 apps/member/models.py:185 #: templates/member/club_info.html:41 msgid "membership fee (paid students)" msgstr "cotisation pour adhérer (normalien élève)" -#: apps/member/admin.py:54 apps/member/models.py:183 +#: apps/member/admin.py:53 apps/member/models.py:190 #: templates/member/club_info.html:44 msgid "membership fee (unpaid students)" msgstr "cotisation pour adhérer (normalien étudiant)" -#: apps/member/admin.py:68 apps/member/models.py:270 +#: apps/member/admin.py:67 apps/member/models.py:277 msgid "roles" msgstr "rôles" -#: apps/member/admin.py:69 apps/member/models.py:284 +#: apps/member/admin.py:68 apps/member/models.py:291 msgid "fee" msgstr "cotisation" @@ -315,22 +315,23 @@ msgid "member" msgstr "adhérent" #: apps/member/forms.py:58 apps/member/views.py:82 +#: apps/registration/forms.py:28 msgid "An alias with a similar name already exists." msgstr "Un alias avec un nom similaire existe déjà." -#: apps/member/forms.py:81 apps/registration/forms.py:44 +#: apps/member/forms.py:81 apps/registration/forms.py:50 msgid "Inscription paid by Société Générale" msgstr "Inscription payée par la Société générale" -#: apps/member/forms.py:83 apps/registration/forms.py:46 +#: apps/member/forms.py:83 apps/registration/forms.py:52 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:88 apps/registration/forms.py:51 +#: apps/member/forms.py:88 apps/registration/forms.py:57 msgid "Credit type" msgstr "Type de rechargement" -#: apps/member/forms.py:89 apps/registration/forms.py:52 +#: apps/member/forms.py:89 apps/registration/forms.py:58 msgid "No credit" msgstr "Pas de rechargement" @@ -338,20 +339,20 @@ msgstr "Pas de rechargement" 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:95 apps/registration/forms.py:57 +#: apps/member/forms.py:95 apps/registration/forms.py:63 msgid "Credit amount" msgstr "Montant à créditer" -#: apps/member/forms.py:112 apps/registration/forms.py:74 +#: apps/member/forms.py:112 apps/registration/forms.py:80 #: apps/treasury/forms.py:124 templates/note/transaction_form.html:135 msgid "Bank" msgstr "Banque" -#: apps/member/forms.py:138 +#: apps/member/forms.py:139 msgid "User" msgstr "Utilisateur" -#: apps/member/forms.py:152 +#: apps/member/forms.py:153 msgid "Roles" msgstr "Rôles" @@ -479,47 +480,47 @@ msgstr "profil utilisateur" msgid "Activate your Note Kfet account" msgstr "Activez votre compte Note Kfet" -#: apps/member/models.py:156 templates/member/club_info.html:57 +#: apps/member/models.py:163 templates/member/club_info.html:57 #: templates/registration/future_profile_detail.html:22 #: templates/wei/weiclub_info.html:52 templates/wei/weimembership_form.html:24 msgid "email" msgstr "courriel" -#: apps/member/models.py:163 +#: apps/member/models.py:170 msgid "parent club" msgstr "club parent" -#: apps/member/models.py:172 +#: apps/member/models.py:179 msgid "require memberships" msgstr "nécessite des adhésions" -#: apps/member/models.py:173 +#: apps/member/models.py:180 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:189 templates/member/club_info.html:33 +#: apps/member/models.py:196 templates/member/club_info.html:33 msgid "membership duration" msgstr "durée de l'adhésion" -#: apps/member/models.py:190 +#: apps/member/models.py:197 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:197 templates/member/club_info.html:23 +#: apps/member/models.py:204 templates/member/club_info.html:23 msgid "membership start" msgstr "début de l'adhésion" -#: apps/member/models.py:198 +#: apps/member/models.py:205 msgid "How long after January 1st the members can renew their membership." msgstr "" "Combien de temps après le 1er Janvier les adhérents peuvent renouveler leur " "adhésion." -#: apps/member/models.py:205 templates/member/club_info.html:28 +#: apps/member/models.py:212 templates/member/club_info.html:28 msgid "membership end" msgstr "fin de l'adhésion" -#: apps/member/models.py:206 +#: apps/member/models.py:213 msgid "" "How long the membership can last after January 1st of the next year after " "members can renew their membership." @@ -527,50 +528,50 @@ msgstr "" "Combien de temps l'adhésion peut durer après le 1er Janvier de l'année " "suivante avant que les adhérents peuvent renouveler leur adhésion." -#: apps/member/models.py:240 apps/member/models.py:265 -#: apps/note/models/notes.py:139 +#: apps/member/models.py:247 apps/member/models.py:272 +#: apps/note/models/notes.py:163 msgid "club" msgstr "club" -#: apps/member/models.py:241 +#: apps/member/models.py:248 msgid "clubs" msgstr "clubs" -#: apps/member/models.py:275 +#: apps/member/models.py:282 msgid "membership starts on" msgstr "l'adhésion commence le" -#: apps/member/models.py:279 +#: apps/member/models.py:286 msgid "membership ends on" msgstr "l'adhésion finit le" -#: apps/member/models.py:303 apps/member/views.py:535 apps/wei/views.py:797 +#: apps/member/models.py:310 apps/member/views.py:535 apps/wei/views.py:795 msgid "User is not a member of the parent club" msgstr "L'utilisateur n'est pas membre du club parent" -#: apps/member/models.py:310 +#: apps/member/models.py:317 #, 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:321 apps/member/views.py:544 +#: apps/member/models.py:328 apps/member/views.py:544 msgid "User is already a member of the club" msgstr "L'utilisateur est déjà membre du club" -#: apps/member/models.py:372 +#: apps/member/models.py:379 #, python-brace-format msgid "Membership of {user} for the club {club}" msgstr "Adhésion de {user} pour le club {club}" -#: apps/member/models.py:375 +#: apps/member/models.py:382 msgid "membership" msgstr "adhésion" -#: apps/member/models.py:376 +#: apps/member/models.py:383 msgid "memberships" msgstr "adhésions" -#: apps/member/tables.py:113 +#: apps/member/tables.py:114 msgid "Renew" msgstr "Renouveler" @@ -624,7 +625,7 @@ msgstr "Modifier le club" msgid "Add new member to the club" msgstr "Ajouter un nouveau membre au club" -#: apps/member/views.py:530 apps/wei/views.py:788 +#: apps/member/views.py:530 apps/wei/views.py:786 msgid "" "This user don't have enough money to join this club, and can't have a " "negative balance." @@ -641,8 +642,8 @@ msgid "The membership must begin before {:%m-%d-%Y}." msgstr "L'adhésion doit commencer avant le {:%d/%m/%Y}." #: apps/member/views.py:570 apps/member/views.py:572 apps/member/views.py:574 -#: apps/registration/views.py:292 apps/registration/views.py:294 -#: apps/registration/views.py:296 +#: apps/registration/views.py:290 apps/registration/views.py:292 +#: apps/registration/views.py:294 msgid "This field is required." msgstr "Ce champ est requis." @@ -654,16 +655,16 @@ msgstr "Gérer les rôles d'un utilisateur dans le club" msgid "Members of the club" msgstr "Membres du club" -#: apps/note/admin.py:134 apps/note/models/transactions.py:106 +#: apps/note/admin.py:133 apps/note/models/transactions.py:106 msgid "source" msgstr "source" -#: apps/note/admin.py:142 apps/note/admin.py:192 +#: apps/note/admin.py:141 apps/note/admin.py:191 #: apps/note/models/transactions.py:55 apps/note/models/transactions.py:119 msgid "destination" msgstr "destination" -#: apps/note/admin.py:197 apps/note/models/transactions.py:59 +#: apps/note/admin.py:196 apps/note/models/transactions.py:59 #: apps/note/models/transactions.py:137 msgid "amount" msgstr "montant" @@ -676,105 +677,105 @@ msgstr "Choisissez une image" msgid "Maximal size: 2MB" msgstr "Taille maximale : 2 Mo" -#: apps/note/models/notes.py:27 +#: apps/note/models/notes.py:29 msgid "account balance" msgstr "solde du compte" -#: apps/note/models/notes.py:28 +#: apps/note/models/notes.py:30 msgid "in centimes, money credited for this instance" msgstr "en centimes, argent crédité pour cette instance" -#: apps/note/models/notes.py:32 +#: apps/note/models/notes.py:34 msgid "last negative date" msgstr "dernier date de négatif" -#: apps/note/models/notes.py:33 +#: apps/note/models/notes.py:35 msgid "last time the balance was negative" msgstr "dernier instant où la note était en négatif" -#: apps/note/models/notes.py:38 +#: apps/note/models/notes.py:40 msgid "active" msgstr "actif" -#: apps/note/models/notes.py:41 +#: apps/note/models/notes.py:43 msgid "" "Designates whether this note should be treated as active. Unselect this " "instead of deleting notes." msgstr "" "Indique si la note est active. Désactiver cela plutôt que supprimer la note." -#: apps/note/models/notes.py:45 +#: apps/note/models/notes.py:47 msgid "display image" msgstr "image affichée" -#: apps/note/models/notes.py:53 apps/note/models/transactions.py:129 +#: apps/note/models/notes.py:55 apps/note/models/transactions.py:129 msgid "created at" msgstr "créée le" -#: apps/note/models/notes.py:59 +#: apps/note/models/notes.py:61 msgid "notes" msgstr "notes" -#: apps/note/models/notes.py:77 apps/note/models/notes.py:101 +#: apps/note/models/notes.py:86 apps/note/models/notes.py:110 msgid "This alias is already taken." msgstr "Cet alias est déjà pris." -#: apps/note/models/notes.py:121 +#: apps/note/models/notes.py:130 msgid "one's note" msgstr "note d'un utilisateur" -#: apps/note/models/notes.py:122 +#: apps/note/models/notes.py:131 msgid "users note" msgstr "notes des utilisateurs" -#: apps/note/models/notes.py:128 +#: apps/note/models/notes.py:137 #, python-format msgid "%(user)s's note" msgstr "Note de %(user)s" -#: apps/note/models/notes.py:143 +#: apps/note/models/notes.py:167 msgid "club note" msgstr "note d'un club" -#: apps/note/models/notes.py:144 +#: apps/note/models/notes.py:168 msgid "clubs notes" msgstr "notes des clubs" -#: apps/note/models/notes.py:150 +#: apps/note/models/notes.py:174 #, python-format msgid "Note of %(club)s club" msgstr "Note du club %(club)s" -#: apps/note/models/notes.py:170 +#: apps/note/models/notes.py:194 msgid "special note" msgstr "note spéciale" -#: apps/note/models/notes.py:171 +#: apps/note/models/notes.py:195 msgid "special notes" msgstr "notes spéciales" -#: apps/note/models/notes.py:194 +#: apps/note/models/notes.py:218 msgid "Invalid alias" msgstr "Alias invalide" -#: apps/note/models/notes.py:210 +#: apps/note/models/notes.py:234 msgid "alias" msgstr "alias" -#: apps/note/models/notes.py:211 templates/member/club_info.html:54 +#: apps/note/models/notes.py:235 templates/member/club_info.html:54 #: templates/member/profile_info.html:38 templates/wei/weiclub_info.html:48 msgid "aliases" msgstr "alias" -#: apps/note/models/notes.py:233 +#: apps/note/models/notes.py:257 msgid "Alias is too long." msgstr "L'alias est trop long." -#: apps/note/models/notes.py:238 +#: apps/note/models/notes.py:262 msgid "An alias with a similar name already exists: {} " msgstr "Un alias avec un nom similaire existe déjà : {}" -#: apps/note/models/notes.py:251 +#: apps/note/models/notes.py:275 msgid "You can't delete your main alias." msgstr "Vous ne pouvez pas supprimer votre alias principal." @@ -823,7 +824,7 @@ msgstr "quantité" msgid "reason" msgstr "raison" -#: apps/note/models/transactions.py:151 apps/note/tables.py:113 +#: apps/note/models/transactions.py:151 apps/note/tables.py:112 msgid "invalidity reason" msgstr "Motif d'invalidité" @@ -885,7 +886,7 @@ msgstr "" msgid "membership transaction" msgstr "Transaction d'adhésion" -#: apps/note/models/transactions.py:308 apps/treasury/models.py:227 +#: apps/note/models/transactions.py:308 apps/treasury/models.py:228 msgid "membership transactions" msgstr "Transactions d'adhésion" @@ -897,17 +898,17 @@ msgstr "Cliquez pour dévalider" msgid "Click to validate" msgstr "Cliquez pour valider" -#: apps/note/tables.py:111 +#: apps/note/tables.py:110 msgid "No reason specified" msgstr "Pas de motif spécifié" -#: apps/note/tables.py:140 apps/note/tables.py:168 apps/wei/tables.py:66 +#: apps/note/tables.py:139 apps/note/tables.py:167 apps/wei/tables.py:66 #: templates/treasury/sogecredit_detail.html:59 #: templates/wei/weiregistration_confirm_delete.html:32 msgid "Delete" msgstr "Supprimer" -#: apps/note/tables.py:163 apps/wei/tables.py:42 apps/wei/tables.py:43 +#: apps/note/tables.py:162 apps/wei/tables.py:42 apps/wei/tables.py:43 #: templates/member/club_info.html:67 templates/note/conso_form.html:128 #: templates/wei/bus_tables.html:15 templates/wei/busteam_tables.html:15 #: templates/wei/busteam_tables.html:33 templates/wei/weiclub_info.html:68 @@ -918,69 +919,69 @@ msgstr "Éditer" msgid "Transfer money" msgstr "Transférer de l'argent" -#: apps/note/views.py:67 +#: apps/note/views.py:69 msgid "Create new button" msgstr "Créer un nouveau bouton" -#: apps/note/views.py:76 +#: apps/note/views.py:78 msgid "Search button" msgstr "Chercher un bouton" -#: apps/note/views.py:99 +#: apps/note/views.py:101 msgid "Update button" msgstr "Modifier le bouton" -#: apps/note/views.py:136 templates/base.html:94 +#: apps/note/views.py:138 templates/base.html:94 msgid "Consumptions" msgstr "Consommations" -#: apps/permission/models.py:92 +#: apps/permission/models.py:99 #, python-brace-format msgid "Can {type} {model}.{field} in {query}" msgstr "Can {type} {model}.{field} in {query}" -#: apps/permission/models.py:94 +#: apps/permission/models.py:101 #, python-brace-format msgid "Can {type} {model} in {query}" msgstr "Can {type} {model} in {query}" -#: apps/permission/models.py:107 +#: apps/permission/models.py:114 msgid "rank" msgstr "Rang" -#: apps/permission/models.py:120 +#: apps/permission/models.py:127 msgid "permission mask" msgstr "masque de permissions" -#: apps/permission/models.py:121 +#: apps/permission/models.py:128 msgid "permission masks" msgstr "masques de permissions" -#: apps/permission/models.py:127 +#: apps/permission/models.py:134 msgid "add" msgstr "ajouter" -#: apps/permission/models.py:128 +#: apps/permission/models.py:135 msgid "view" msgstr "voir" -#: apps/permission/models.py:129 +#: apps/permission/models.py:136 msgid "change" msgstr "modifier" -#: apps/permission/models.py:161 +#: apps/permission/models.py:168 msgid "query" msgstr "requête" -#: apps/permission/models.py:174 +#: apps/permission/models.py:181 msgid "mask" msgstr "masque" -#: apps/permission/models.py:180 +#: apps/permission/models.py:187 msgid "field" msgstr "champ" -#: apps/permission/models.py:185 +#: apps/permission/models.py:192 msgid "" "Tells if the permission should be granted even if the membership of the user " "is expired." @@ -988,29 +989,29 @@ msgstr "" "Indique si la permission doit être attribuée même si l'adhésion de " "l'utilisateur est expirée." -#: apps/permission/models.py:186 templates/permission/all_rights.html:26 +#: apps/permission/models.py:193 templates/permission/all_rights.html:26 msgid "permanent" msgstr "permanent" -#: apps/permission/models.py:197 +#: apps/permission/models.py:204 msgid "permission" msgstr "permission" -#: apps/permission/models.py:198 apps/permission/models.py:337 +#: apps/permission/models.py:205 apps/permission/models.py:344 msgid "permissions" msgstr "permissions" -#: apps/permission/models.py:203 +#: apps/permission/models.py:210 msgid "Specifying field applies only to view and change permission types." msgstr "" "Spécifie le champ concerné, ne fonctionne que pour les permissions view et " "change." -#: apps/permission/models.py:342 +#: apps/permission/models.py:349 msgid "for club" msgstr "s'applique au club" -#: apps/permission/models.py:352 apps/permission/models.py:353 +#: apps/permission/models.py:359 apps/permission/models.py:360 msgid "role permissions" msgstr "Permissions par rôles" @@ -1041,7 +1042,7 @@ msgstr "" "Vous n'avez pas la permission de supprimer cette instance du modèle " "{app_label}.{model_name}." -#: apps/permission/views.py:44 templates/base.html:136 +#: apps/permission/views.py:44 templates/base.html:129 msgid "Rights" msgstr "Droits" @@ -1053,11 +1054,11 @@ msgstr "Tous les droits" msgid "registration" msgstr "inscription" -#: apps/registration/forms.py:32 +#: apps/registration/forms.py:38 msgid "Register to the WEI" msgstr "S'inscrire au WEI" -#: apps/registration/forms.py:34 +#: apps/registration/forms.py:40 msgid "" "Check this case if you want to register to the WEI. If you hesitate, you " "will be able to register later, after validating your account in the Kfet." @@ -1066,11 +1067,11 @@ msgstr "" "pourrez toujours vous inscrire plus tard, après avoir validé votre compte à " "la Kfet." -#: apps/registration/forms.py:79 +#: apps/registration/forms.py:85 msgid "Join BDE Club" msgstr "Adhérer au club BDE" -#: apps/registration/forms.py:86 +#: apps/registration/forms.py:92 msgid "Join Kfet Club" msgstr "Adhérer au club Kfet" @@ -1102,34 +1103,34 @@ msgstr "Renvoyer le lien de validation" msgid "Pre-registered users list" msgstr "Liste des utilisateurs en attente d'inscription" -#: apps/registration/views.py:190 +#: apps/registration/views.py:188 msgid "Unregistered users" msgstr "Utilisateurs en attente d'inscription" -#: apps/registration/views.py:203 +#: apps/registration/views.py:201 msgid "Registration detail" msgstr "Détails de l'inscription" -#: apps/registration/views.py:258 +#: apps/registration/views.py:256 msgid "You must join the BDE." msgstr "Vous devez adhérer au BDE." -#: apps/registration/views.py:280 +#: apps/registration/views.py:278 msgid "You must join BDE club before joining Kfet club." msgstr "Vous devez adhérer au club BDE avant d'adhérer au club Kfet." -#: apps/registration/views.py:285 +#: apps/registration/views.py:283 msgid "" "The entered amount is not enough for the memberships, should be at least {}" msgstr "" "Le montant crédité est trop faible pour adhérer, il doit être au minimum de " "{}" -#: apps/registration/views.py:360 +#: apps/registration/views.py:358 msgid "Invalidate pre-registration" msgstr "Invalider l'inscription" -#: apps/treasury/apps.py:12 templates/base.html:126 +#: apps/treasury/apps.py:12 templates/base.html:119 msgid "Treasury" msgstr "Trésorerie" @@ -1163,118 +1164,118 @@ msgstr "Vous ne pouvez pas changer le type de la remise." msgid "Amount" msgstr "Montant" -#: apps/treasury/models.py:20 +#: apps/treasury/models.py:21 msgid "Invoice identifier" msgstr "Numéro de facture" -#: apps/treasury/models.py:34 +#: apps/treasury/models.py:35 msgid "BDE" msgstr "BDE" -#: apps/treasury/models.py:39 +#: apps/treasury/models.py:40 msgid "Object" msgstr "Objet" -#: apps/treasury/models.py:43 +#: apps/treasury/models.py:44 msgid "Description" msgstr "Description" -#: apps/treasury/models.py:48 templates/note/transaction_form.html:123 +#: apps/treasury/models.py:49 templates/note/transaction_form.html:123 msgid "Name" msgstr "Nom" -#: apps/treasury/models.py:52 +#: apps/treasury/models.py:53 msgid "Address" msgstr "Adresse" -#: apps/treasury/models.py:57 +#: apps/treasury/models.py:58 msgid "Place" msgstr "Lieu" -#: apps/treasury/models.py:61 +#: apps/treasury/models.py:62 msgid "Acquitted" msgstr "Acquittée" -#: apps/treasury/models.py:65 +#: apps/treasury/models.py:66 msgid "invoice" msgstr "facture" -#: apps/treasury/models.py:66 +#: apps/treasury/models.py:67 msgid "invoices" msgstr "factures" -#: apps/treasury/models.py:81 +#: apps/treasury/models.py:82 msgid "Designation" msgstr "Désignation" -#: apps/treasury/models.py:85 +#: apps/treasury/models.py:86 msgid "Quantity" msgstr "Quantité" -#: apps/treasury/models.py:89 +#: apps/treasury/models.py:90 msgid "Unit price" msgstr "Prix unitaire" -#: apps/treasury/models.py:105 +#: apps/treasury/models.py:106 msgid "product" msgstr "produit" -#: apps/treasury/models.py:106 +#: apps/treasury/models.py:107 msgid "products" msgstr "produits" -#: apps/treasury/models.py:123 +#: apps/treasury/models.py:124 msgid "remittance type" msgstr "type de remise" -#: apps/treasury/models.py:124 +#: apps/treasury/models.py:125 msgid "remittance types" msgstr "types de remises" -#: apps/treasury/models.py:134 +#: apps/treasury/models.py:135 msgid "Date" msgstr "Date" -#: apps/treasury/models.py:145 +#: apps/treasury/models.py:146 msgid "Comment" msgstr "Commentaire" -#: apps/treasury/models.py:150 +#: apps/treasury/models.py:151 msgid "Closed" msgstr "Fermée" -#: apps/treasury/models.py:154 +#: apps/treasury/models.py:155 msgid "remittance" msgstr "remise" -#: apps/treasury/models.py:155 +#: apps/treasury/models.py:156 msgid "remittances" msgstr "remises" -#: apps/treasury/models.py:187 +#: apps/treasury/models.py:188 msgid "Remittance #{:d}: {}" msgstr "Remise n°{:d} : {}" -#: apps/treasury/models.py:206 apps/treasury/tables.py:76 +#: apps/treasury/models.py:207 apps/treasury/tables.py:76 #: apps/treasury/tables.py:84 templates/treasury/invoice_list.html:13 #: templates/treasury/remittance_list.html:13 #: templates/treasury/sogecredit_list.html:13 msgid "Remittance" msgstr "Remise" -#: apps/treasury/models.py:210 +#: apps/treasury/models.py:211 msgid "special transaction proxy" msgstr "Proxy de transaction spéciale" -#: apps/treasury/models.py:211 +#: apps/treasury/models.py:212 msgid "special transaction proxies" msgstr "Proxys de transactions spéciales" -#: apps/treasury/models.py:233 +#: apps/treasury/models.py:234 msgid "credit transaction" msgstr "transaction de crédit" -#: apps/treasury/models.py:296 +#: apps/treasury/models.py:297 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." @@ -1282,11 +1283,11 @@ 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:308 templates/treasury/sogecredit_detail.html:10 +#: apps/treasury/models.py:309 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:309 +#: apps/treasury/models.py:310 msgid "Credits from the Société générale" msgstr "Crédits de la Société générale" @@ -1366,7 +1367,7 @@ msgid "Manage credits from the Société générale" msgstr "Gérer les crédits de la Société générale" #: apps/wei/apps.py:10 apps/wei/models.py:48 apps/wei/models.py:49 -#: apps/wei/models.py:60 apps/wei/models.py:166 templates/base.html:131 +#: apps/wei/models.py:60 apps/wei/models.py:166 templates/base.html:124 msgid "WEI" msgstr "WEI" @@ -1621,51 +1622,51 @@ msgstr "Trouver une adhésion au WEI" msgid "View registrations to the WEI" msgstr "Voir les inscriptions au WEI" -#: apps/wei/views.py:253 +#: apps/wei/views.py:251 msgid "Find WEI Registration" msgstr "Trouver une inscription au WEI" -#: apps/wei/views.py:264 +#: apps/wei/views.py:262 msgid "Update the WEI" msgstr "Modifier le WEI" -#: apps/wei/views.py:285 +#: apps/wei/views.py:283 msgid "Create new bus" msgstr "Ajouter un nouveau bus" -#: apps/wei/views.py:316 +#: apps/wei/views.py:314 msgid "Update bus" msgstr "Modifier le bus" -#: apps/wei/views.py:346 +#: apps/wei/views.py:344 msgid "Manage bus" msgstr "Gérer le bus" -#: apps/wei/views.py:373 +#: apps/wei/views.py:371 msgid "Create new team" msgstr "Créer une nouvelle équipe" -#: apps/wei/views.py:405 +#: apps/wei/views.py:403 msgid "Update team" msgstr "Modifier l'équipe" -#: apps/wei/views.py:436 +#: apps/wei/views.py:434 msgid "Manage WEI team" msgstr "Gérer l'équipe WEI" -#: apps/wei/views.py:458 +#: apps/wei/views.py:456 msgid "Register first year student to the WEI" msgstr "Inscrire un 1A au WEI" -#: apps/wei/views.py:470 templates/wei/weiclub_info.html:62 +#: apps/wei/views.py:468 templates/wei/weiclub_info.html:62 msgid "Register 1A" msgstr "Inscrire un 1A" -#: apps/wei/views.py:491 apps/wei/views.py:561 +#: apps/wei/views.py:489 apps/wei/views.py:559 msgid "This user is already registered to this WEI." msgstr "Cette personne est déjà inscrite au WEI." -#: apps/wei/views.py:496 +#: apps/wei/views.py:494 msgid "" "This user can't be in her/his first year since he/she has already participed " "to a WEI." @@ -1673,39 +1674,39 @@ msgstr "" "Cet utilisateur ne peut pas être en première année puisqu'iel a déjà " "participé à un WEI." -#: apps/wei/views.py:513 +#: apps/wei/views.py:511 msgid "Register old student to the WEI" msgstr "Inscrire un 2A+ au WEI" -#: apps/wei/views.py:525 templates/wei/weiclub_info.html:65 +#: apps/wei/views.py:523 templates/wei/weiclub_info.html:65 msgid "Register 2A+" msgstr "Inscrire un 2A+" -#: apps/wei/views.py:543 apps/wei/views.py:631 +#: apps/wei/views.py:541 apps/wei/views.py:629 msgid "You already opened an account in the Société générale." msgstr "Vous avez déjà ouvert un compte auprès de la société générale." -#: apps/wei/views.py:591 +#: apps/wei/views.py:589 msgid "Update WEI Registration" msgstr "Modifier l'inscription WEI" -#: apps/wei/views.py:681 +#: apps/wei/views.py:679 msgid "Delete WEI registration" msgstr "Supprimer l'inscription WEI" -#: apps/wei/views.py:692 +#: apps/wei/views.py:690 msgid "You don't have the right to delete this WEI registration." msgstr "Vous n'avez pas la permission de supprimer cette inscription au WEI." -#: apps/wei/views.py:711 +#: apps/wei/views.py:709 msgid "Validate WEI registration" msgstr "Valider l'inscription WEI" -#: apps/wei/views.py:792 +#: apps/wei/views.py:790 msgid "This user didn't give her/his caution check." msgstr "Cet utilisateur n'a pas donné son chèque de caution." -#: apps/wei/views.py:829 apps/wei/views.py:882 apps/wei/views.py:892 +#: apps/wei/views.py:827 apps/wei/views.py:880 apps/wei/views.py:890 #: templates/wei/survey.html:12 templates/wei/survey_closed.html:12 #: templates/wei/survey_end.html:12 msgid "Survey WEI" @@ -1845,15 +1846,11 @@ msgstr "Utilisateurs" msgid "Clubs" msgstr "Clubs" -#: templates/base.html:115 -msgid "Registrations" -msgstr "Inscriptions" - -#: templates/base.html:141 +#: templates/base.html:134 msgid "Admin" msgstr "Admin" -#: templates/base.html:180 +#: templates/base.html:173 msgid "" "Your e-mail address is not validated. Please check your mail inbox and click " "on the validation link." @@ -1996,10 +1993,14 @@ msgstr "Voir mes adhésions" msgid "Save Changes" msgstr "Sauvegarder les changements" -#: templates/member/user_list.html:16 +#: templates/member/user_list.html:17 msgid "There is no user with this pattern." msgstr "Il n'y a pas d'utilisateur trouvé avec cette entrée." +#: templates/member/user_list.html:26 +msgid "Registrations" +msgstr "Inscriptions" + #: templates/note/conso_form.html:28 msgid "Consum" msgstr "Consommer" @@ -2137,6 +2138,25 @@ msgstr "" "Le lien est invalide. Le jeton a sans doute expiré. Merci de nous contacter " "pour activer votre compte." +#: templates/registration/email_validation_email_sent.html:4 +msgid "Account activation" +msgstr "Activation du compte" + +#: templates/registration/email_validation_email_sent.html:7 +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." + +#: templates/registration/email_validation_email_sent.html:11 +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." + #: templates/registration/future_profile_detail.html:49 #: templates/wei/weiregistration_confirm_delete.html:12 msgid "Delete registration" @@ -2197,10 +2217,12 @@ msgstr "" msgid "Forgotten your password or username?" msgstr "Mot de passe ou pseudo oublié ?" +#: templates/registration/mails/email_validation_email.html:12 #: templates/registration/mails/email_validation_email.txt:3 msgid "Hi" msgstr "Bonjour" +#: templates/registration/mails/email_validation_email.html:16 #: templates/registration/mails/email_validation_email.txt:5 msgid "" "You recently registered on the Note Kfet. Please click on the link below to " @@ -2209,26 +2231,30 @@ msgstr "" "Vous vous êtes inscrits récemment sur la Note Kfet. Merci de cliquer sur le " "lien ci-dessous pour confirmer votre adresse email." +#: templates/registration/mails/email_validation_email.html:26 #: templates/registration/mails/email_validation_email.txt:9 msgid "" "This link is only valid for a couple of days, after that you will need to " "contact us to validate your email." -msgstr "" -"Ce lien n'est valide que pendant quelques jours. Après cela, vous devrez " -"nous contacter pour valider votre email." +msgstr "Ce lien n'est valide que pendant quelques jours." +#: templates/registration/mails/email_validation_email.html:30 #: 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." +"you can log in. You will need to pay your membership in the Kfet. Note that " +"the WEI registration includes the Kfet membership." 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." +"pouvoir vous connecter. Vous devrez payer votre adhésion à la Kfet. Notez " +"que l'adhésion Kfet est incluse dans l'inscription au WEI." +#: templates/registration/mails/email_validation_email.html:34 #: templates/registration/mails/email_validation_email.txt:13 msgid "Thanks" msgstr "Merci" +#: templates/registration/mails/email_validation_email.html:39 #: templates/registration/mails/email_validation_email.txt:15 msgid "The Note Kfet team." msgstr "L'équipe de la Note Kfet." @@ -2311,10 +2337,10 @@ msgid "" "by following the link you received." msgstr "" "Si vous vous êtes déjà inscrits, votre inscription a bien été prise en " -"compte. Le BDE doit d'abord valider votre compte avantque vous puissiez vous " -"connecter. Vous devez vous rendre à la Kfet et payer les frais d'adhésion. " -"Vous devez également valider votre adresse email en suivant le lien que vous " -"avez reçu." +"compte. Le BDE doit d'abord valider votre compte avant que vous puissiez " +"vous connecter. Vous devez vous rendre à la Kfet et payer les frais " +"d'adhésion. Vous devez également valider votre adresse email en suivant le " +"lien que vous avez reçu." #: templates/treasury/invoice_form.html:41 msgid "Add product" diff --git a/templates/registration/email_validation_email_sent.html b/templates/registration/email_validation_email_sent.html index bd4cf8d8..6167ee52 100644 --- a/templates/registration/email_validation_email_sent.html +++ b/templates/registration/email_validation_email_sent.html @@ -1,7 +1,13 @@ {% extends "base.html" %} {% block content %} -

    Account Activation

    +

    {% trans "Account activation" %}

    -An email has been sent. Please click on the link to activate your account. +

    + {% 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 diff --git a/templates/registration/mails/email_validation_email.html b/templates/registration/mails/email_validation_email.html index 0d3afc0e..84a2379f 100644 --- a/templates/registration/mails/email_validation_email.html +++ b/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." %} + {% 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." %}

    diff --git a/templates/registration/mails/email_validation_email.txt b/templates/registration/mails/email_validation_email.txt index 69f2d642..6427200f 100644 --- a/templates/registration/mails/email_validation_email.txt +++ b/templates/registration/mails/email_validation_email.txt @@ -8,7 +8,7 @@ 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." %} +{% 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 "Thanks" %}, From 208dc7f865071d11c869c07b7ae623db7d93cad2 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Mon, 3 Aug 2020 13:33:25 +0200 Subject: [PATCH 023/319] :art: Use multiple checkboxes than multiple select widget --- apps/member/forms.py | 2 ++ apps/wei/forms/registration.py | 11 ++++++++++- apps/wei/views.py | 5 +++-- templates/wei/weiregistration_form.html | 26 +++++++++++++++++++++++++ 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/apps/member/forms.py b/apps/member/forms.py index 50fa9c47..58285b79 100644 --- a/apps/member/forms.py +++ b/apps/member/forms.py @@ -4,6 +4,7 @@ from django import forms from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.models import User +from django.forms import CheckboxSelectMultiple from django.utils.translation import gettext_lazy as _ from note.models import NoteSpecial, Alias from note_kfet.inputs import Autocomplete, AmountInput, DatePickerInput @@ -151,6 +152,7 @@ class MembershipRolesForm(forms.ModelForm): roles = forms.ModelMultipleChoiceField( queryset=Role.objects.filter(weirole=None).all(), label=_("Roles"), + widget=CheckboxSelectMultiple(), ) class Meta: diff --git a/apps/wei/forms/registration.py b/apps/wei/forms/registration.py index 9ce3a350..738db4e2 100644 --- a/apps/wei/forms/registration.py +++ b/apps/wei/forms/registration.py @@ -4,6 +4,7 @@ from django import forms from django.contrib.auth.models import User from django.db.models import Q +from django.forms import CheckboxSelectMultiple from django.utils.translation import gettext_lazy as _ from note_kfet.inputs import AmountInput, DatePickerInput, Autocomplete, ColorWidget @@ -47,6 +48,7 @@ class WEIChooseBusForm(forms.Form): label=_("bus"), help_text=_("This choice is not definitive. The WEI organizers are free to attribute for you a bus and a team," + " in particular if you are a free eletron."), + widget=CheckboxSelectMultiple(), ) team = forms.ModelMultipleChoiceField( @@ -54,17 +56,24 @@ class WEIChooseBusForm(forms.Form): label=_("Team"), required=False, help_text=_("Leave this field empty if you won't be in a team (staff, bus chief, free electron)"), + widget=CheckboxSelectMultiple(), ) roles = forms.ModelMultipleChoiceField( queryset=WEIRole.objects.filter(~Q(name="1A")), label=_("WEI Roles"), help_text=_("Select the roles that you are interested in."), + initial=WEIRole.objects.filter(name="Adhérent WEI").all(), + widget=CheckboxSelectMultiple(), ) class WEIMembershipForm(forms.ModelForm): - roles = forms.ModelMultipleChoiceField(queryset=WEIRole.objects, label=_("WEI Roles")) + roles = forms.ModelMultipleChoiceField( + queryset=WEIRole.objects, + label=_("WEI Roles"), + widget=CheckboxSelectMultiple(), + ) def clean(self): cleaned_data = super().clean() diff --git a/apps/wei/views.py b/apps/wei/views.py index fb0f7b32..8a95c72a 100644 --- a/apps/wei/views.py +++ b/apps/wei/views.py @@ -527,8 +527,9 @@ class WEIRegister2AView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): context["form"].fields["user"].disabled = True choose_bus_form = WEIChooseBusForm() - choose_bus_form.fields["bus"].queryset = Bus.objects.filter(wei=context["club"]) - choose_bus_form.fields["team"].queryset = BusTeam.objects.filter(bus__wei=context["club"]) + choose_bus_form.fields["bus"].queryset = Bus.objects.filter(wei=context["club"]).order_by('name') + choose_bus_form.fields["team"].queryset = BusTeam.objects.filter(bus__wei=context["club"])\ + .order_by('bus__name', 'name') context['membership_form'] = choose_bus_form return context diff --git a/templates/wei/weiregistration_form.html b/templates/wei/weiregistration_form.html index 86aea555..9cf507c8 100644 --- a/templates/wei/weiregistration_form.html +++ b/templates/wei/weiregistration_form.html @@ -14,3 +14,29 @@ {% endblock %} + +{% block extrajavascript %} + +{% endblock %} From 0a2c9d9c8754b4f83d5473d0278f8daf180f225e Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Mon, 3 Aug 2020 13:33:25 +0200 Subject: [PATCH 024/319] :bug: Better entry page --- apps/activity/views.py | 50 +++++++++++++++---------- apps/member/forms.py | 2 + apps/wei/forms/registration.py | 11 +++++- apps/wei/views.py | 5 ++- templates/wei/weiregistration_form.html | 26 +++++++++++++ 5 files changed, 71 insertions(+), 23 deletions(-) diff --git a/apps/activity/views.py b/apps/activity/views.py index cac7f183..923f32ec 100644 --- a/apps/activity/views.py +++ b/apps/activity/views.py @@ -114,28 +114,31 @@ class ActivityEntryView(LoginRequiredMixin, TemplateView): context = super().get_context_data(**kwargs) activity = Activity.objects.filter(PermissionBackend.filter_queryset(self.request.user, Activity, "view"))\ - .get(pk=self.kwargs["pk"]) + .distinct().get(pk=self.kwargs["pk"]) context["activity"] = activity matched = [] - pattern = "^$" - if "search" in self.request.GET: - pattern = self.request.GET["search"] - - if not pattern: - pattern = "^$" - - if pattern[0] != "^": - pattern = "^" + pattern - guest_qs = Guest.objects\ .annotate(balance=F("inviter__balance"), note_name=F("inviter__user__username"))\ - .filter(Q(first_name__regex=pattern) | Q(last_name__regex=pattern) - | Q(inviter__alias__name__regex=pattern) - | Q(inviter__alias__normalized_name__regex=Alias.normalize(pattern))) \ + .filter(activity=activity)\ .filter(PermissionBackend.filter_queryset(self.request.user, Guest, "view"))\ - .distinct()[:20] + .order_by('last_name', 'first_name').distinct() + + if "search" in self.request.GET: + pattern = self.request.GET["search"] + if pattern[0] != "^": + pattern = "^" + pattern + guest_qs = guest_qs.filter( + Q(first_name__regex=pattern) + | Q(last_name__regex=pattern) + | Q(inviter__alias__name__regex=pattern) + | Q(inviter__alias__normalized_name__regex=Alias.normalize(pattern)) + ) + else: + pattern = None + guest_qs = guest_qs.none() + for guest in guest_qs: guest.type = "Invité" matched.append(guest) @@ -145,12 +148,18 @@ class ActivityEntryView(LoginRequiredMixin, TemplateView): username=F("note__noteuser__user__username"), note_name=F("name"), balance=F("note__balance"))\ - .filter(Q(note__polymorphic_ctype__model="noteuser") - & (Q(note__noteuser__user__first_name__regex=pattern) - | Q(note__noteuser__user__last_name__regex=pattern) - | Q(name__regex=pattern) - | Q(normalized_name__regex=Alias.normalize(pattern)))) \ + .filter(note__polymorphic_ctype__model="noteuser")\ .filter(PermissionBackend.filter_queryset(self.request.user, Alias, "view")) + if pattern: + note_qs = note_qs.filter( + Q(note__noteuser__user__first_name__regex=pattern) + | Q(note__noteuser__user__last_name__regex=pattern) + | Q(name__regex=pattern) + | Q(normalized_name__regex=Alias.normalize(pattern)) + ) + else: + note_qs = note_qs.none() + if settings.DATABASES[note_qs.db]["ENGINE"] == 'django.db.backends.postgresql_psycopg2': note_qs = note_qs.distinct('note__pk')[:20] else: @@ -158,6 +167,7 @@ class ActivityEntryView(LoginRequiredMixin, TemplateView): # have distinct aliases rather than distinct notes with a SQLite DB, but it can fill the result page. # In production mode, please use PostgreSQL. note_qs = note_qs.distinct()[:20] + for note in note_qs: note.type = "Adhérent" note.activity = activity diff --git a/apps/member/forms.py b/apps/member/forms.py index 50fa9c47..58285b79 100644 --- a/apps/member/forms.py +++ b/apps/member/forms.py @@ -4,6 +4,7 @@ from django import forms from django.contrib.auth.forms import AuthenticationForm from django.contrib.auth.models import User +from django.forms import CheckboxSelectMultiple from django.utils.translation import gettext_lazy as _ from note.models import NoteSpecial, Alias from note_kfet.inputs import Autocomplete, AmountInput, DatePickerInput @@ -151,6 +152,7 @@ class MembershipRolesForm(forms.ModelForm): roles = forms.ModelMultipleChoiceField( queryset=Role.objects.filter(weirole=None).all(), label=_("Roles"), + widget=CheckboxSelectMultiple(), ) class Meta: diff --git a/apps/wei/forms/registration.py b/apps/wei/forms/registration.py index 9ce3a350..738db4e2 100644 --- a/apps/wei/forms/registration.py +++ b/apps/wei/forms/registration.py @@ -4,6 +4,7 @@ from django import forms from django.contrib.auth.models import User from django.db.models import Q +from django.forms import CheckboxSelectMultiple from django.utils.translation import gettext_lazy as _ from note_kfet.inputs import AmountInput, DatePickerInput, Autocomplete, ColorWidget @@ -47,6 +48,7 @@ class WEIChooseBusForm(forms.Form): label=_("bus"), help_text=_("This choice is not definitive. The WEI organizers are free to attribute for you a bus and a team," + " in particular if you are a free eletron."), + widget=CheckboxSelectMultiple(), ) team = forms.ModelMultipleChoiceField( @@ -54,17 +56,24 @@ class WEIChooseBusForm(forms.Form): label=_("Team"), required=False, help_text=_("Leave this field empty if you won't be in a team (staff, bus chief, free electron)"), + widget=CheckboxSelectMultiple(), ) roles = forms.ModelMultipleChoiceField( queryset=WEIRole.objects.filter(~Q(name="1A")), label=_("WEI Roles"), help_text=_("Select the roles that you are interested in."), + initial=WEIRole.objects.filter(name="Adhérent WEI").all(), + widget=CheckboxSelectMultiple(), ) class WEIMembershipForm(forms.ModelForm): - roles = forms.ModelMultipleChoiceField(queryset=WEIRole.objects, label=_("WEI Roles")) + roles = forms.ModelMultipleChoiceField( + queryset=WEIRole.objects, + label=_("WEI Roles"), + widget=CheckboxSelectMultiple(), + ) def clean(self): cleaned_data = super().clean() diff --git a/apps/wei/views.py b/apps/wei/views.py index fb0f7b32..8a95c72a 100644 --- a/apps/wei/views.py +++ b/apps/wei/views.py @@ -527,8 +527,9 @@ class WEIRegister2AView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): context["form"].fields["user"].disabled = True choose_bus_form = WEIChooseBusForm() - choose_bus_form.fields["bus"].queryset = Bus.objects.filter(wei=context["club"]) - choose_bus_form.fields["team"].queryset = BusTeam.objects.filter(bus__wei=context["club"]) + choose_bus_form.fields["bus"].queryset = Bus.objects.filter(wei=context["club"]).order_by('name') + choose_bus_form.fields["team"].queryset = BusTeam.objects.filter(bus__wei=context["club"])\ + .order_by('bus__name', 'name') context['membership_form'] = choose_bus_form return context diff --git a/templates/wei/weiregistration_form.html b/templates/wei/weiregistration_form.html index 86aea555..9cf507c8 100644 --- a/templates/wei/weiregistration_form.html +++ b/templates/wei/weiregistration_form.html @@ -14,3 +14,29 @@ {% endblock %} + +{% block extrajavascript %} + +{% endblock %} From 5ea8d8f870d5a4f4d0ac852ccd8a43093f800006 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Mon, 3 Aug 2020 16:11:05 +0200 Subject: [PATCH 025/319] :art: Update activity interface --- apps/activity/views.py | 9 ++++-- apps/api/viewsets.py | 4 +-- apps/note/api/views.py | 6 ++++ apps/note/views.py | 12 ++++++-- apps/permission/fixtures/initial.json | 40 +++++++++++++++++++++++++-- 5 files changed, 61 insertions(+), 10 deletions(-) diff --git a/apps/activity/views.py b/apps/activity/views.py index 923f32ec..370e6040 100644 --- a/apps/activity/views.py +++ b/apps/activity/views.py @@ -182,8 +182,11 @@ class ActivityEntryView(LoginRequiredMixin, TemplateView): context["noteuser_ctype"] = ContentType.objects.get_for_model(NoteUser).pk context["notespecial_ctype"] = ContentType.objects.get_for_model(NoteSpecial).pk - context["activities_open"] = Activity.objects.filter(open=True).filter( - PermissionBackend.filter_queryset(self.request.user, Activity, "view")).filter( - PermissionBackend.filter_queryset(self.request.user, Activity, "change")).all() + activities_open = Activity.objects.filter(open=True).filter( + PermissionBackend.filter_queryset(self.request.user, Activity, "view")).distinct().all() + context["activities_open"] = [a for a in activities_open + if PermissionBackend.check_perm(self.request.user, + "activity.add_entry", + Entry(activity=a, note=self.request.user.note,))] return context diff --git a/apps/api/viewsets.py b/apps/api/viewsets.py index 6e0cb6b8..f4dd56f6 100644 --- a/apps/api/viewsets.py +++ b/apps/api/viewsets.py @@ -18,7 +18,7 @@ class ReadProtectedModelViewSet(viewsets.ModelViewSet): def get_queryset(self): user = get_current_authenticated_user() - return self.model.objects.filter(PermissionBackend.filter_queryset(user, self.model, "view")) + return self.model.objects.filter(PermissionBackend.filter_queryset(user, self.model, "view")).distinct() class ReadOnlyProtectedModelViewSet(viewsets.ReadOnlyModelViewSet): @@ -32,4 +32,4 @@ class ReadOnlyProtectedModelViewSet(viewsets.ReadOnlyModelViewSet): def get_queryset(self): user = get_current_authenticated_user() - return self.model.objects.filter(PermissionBackend.filter_queryset(user, self.model, "view")) + return self.model.objects.filter(PermissionBackend.filter_queryset(user, self.model, "view")).distinct() diff --git a/apps/note/api/views.py b/apps/note/api/views.py index a365c343..f806bbf2 100644 --- a/apps/note/api/views.py +++ b/apps/note/api/views.py @@ -9,6 +9,8 @@ from rest_framework import viewsets from rest_framework.response import Response from rest_framework import status from api.viewsets import ReadProtectedModelViewSet, ReadOnlyProtectedModelViewSet +from note_kfet.middlewares import get_current_authenticated_user +from permission.backends import PermissionBackend from .serializers import NotePolymorphicSerializer, AliasSerializer, ConsumerSerializer,\ TemplateCategorySerializer, TransactionTemplateSerializer, TransactionPolymorphicSerializer @@ -150,3 +152,7 @@ class TransactionViewSet(ReadProtectedModelViewSet): serializer_class = TransactionPolymorphicSerializer filter_backends = [SearchFilter] search_fields = ['$reason', ] + + def get_queryset(self): + user = get_current_authenticated_user() + return self.model.objects.filter(PermissionBackend.filter_queryset(user, self.model, "view")) diff --git a/apps/note/views.py b/apps/note/views.py index ef9da668..ad2b2a99 100644 --- a/apps/note/views.py +++ b/apps/note/views.py @@ -10,6 +10,8 @@ from django.utils.translation import gettext_lazy as _ from django.views.generic import CreateView, UpdateView from django_tables2 import SingleTableView from django.urls import reverse_lazy + +from activity.models import Entry from note_kfet.inputs import AmountInput from permission.backends import PermissionBackend from permission.views import ProtectQuerysetMixin @@ -52,9 +54,13 @@ class TransactionCreateView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTabl # Add a shortcut for entry page for open activities if "activity" in settings.INSTALLED_APPS: from activity.models import Activity - context["activities_open"] = Activity.objects.filter(open=True).filter( - PermissionBackend.filter_queryset(self.request.user, Activity, "view")).filter( - PermissionBackend.filter_queryset(self.request.user, Activity, "change")).all() + activities_open = Activity.objects.filter(open=True).filter( + PermissionBackend.filter_queryset(self.request.user, Activity, "view")).distinct().all() + context["activities_open"] = [a for a in activities_open + if PermissionBackend.check_perm(self.request.user, + "activity.add_entry", + Entry(activity=a, + note=self.request.user.note, ))] return context diff --git a/apps/permission/fixtures/initial.json b/apps/permission/fixtures/initial.json index bbe2e7e9..1ce50d80 100644 --- a/apps/permission/fixtures/initial.json +++ b/apps/permission/fixtures/initial.json @@ -2311,6 +2311,38 @@ "description": "Ajouter un membre à n'importe quel club" } }, + { + "model": "permission.permission", + "pk": 148, + "fields": { + "model": [ + "activity", + "activity" + ], + "query": "{\"valid\": false}", + "type": "change", + "mask": 2, + "field": "", + "permanent": false, + "description": "Modifier une activité non validée" + } + }, + { + "model": "permission.permission", + "pk": 149, + "fields": { + "model": [ + "activity", + "activity" + ], + "query": "{\"valid\": false}", + "type": "delete", + "mask": 2, + "field": "", + "permanent": false, + "description": "Supprimer une activité non validée" + } + }, { "model": "permission.role", "pk": 1, @@ -2643,7 +2675,9 @@ 144, 145, 146, - 147 + 147, + 148, + 149 ] } }, @@ -2690,7 +2724,9 @@ 43, 44, 45, - 46 + 46, + 148, + 149 ] } }, From 985a5ca876006cf1b13b6ef30fd3e6de676ae753 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Mon, 3 Aug 2020 18:49:15 +0200 Subject: [PATCH 026/319] :heavy_plus_sign: Add "search transactions page" --- apps/note/forms.py | 82 ++++++++++- apps/note/models/transactions.py | 9 ++ apps/note/urls.py | 1 + apps/note/views.py | 56 +++++++- apps/wei/views.py | 5 +- locale/de/LC_MESSAGES/django.po | 160 +++++++++++++-------- locale/fr/LC_MESSAGES/django.po | 168 +++++++++++++++-------- note_kfet/inputs.py | 8 +- static/js/autocomplete_model.js | 9 ++ templates/member/autocomplete_model.html | 5 + templates/member/club_tables.html | 4 +- templates/member/profile_info.html | 28 ++-- templates/member/profile_tables.html | 8 +- templates/note/search_transactions.html | 57 ++++++++ templates/wei/weiclub_tables.html | 51 +------ 15 files changed, 455 insertions(+), 196 deletions(-) create mode 100644 templates/note/search_transactions.html diff --git a/apps/note/forms.py b/apps/note/forms.py index bc479e20..fe81783e 100644 --- a/apps/note/forms.py +++ b/apps/note/forms.py @@ -3,10 +3,11 @@ from django import forms from django.contrib.contenttypes.models import ContentType +from django.forms import CheckboxSelectMultiple from django.utils.translation import gettext_lazy as _ -from note_kfet.inputs import Autocomplete, AmountInput +from note_kfet.inputs import Autocomplete, AmountInput, DateTimePickerInput -from .models import TransactionTemplate, NoteClub +from .models import TransactionTemplate, NoteClub, Alias class ImageForm(forms.Form): @@ -38,3 +39,80 @@ class TransactionTemplateForm(forms.ModelForm): ), 'amount': AmountInput(), } + + +class SearchTransactionForm(forms.Form): + source = forms.ModelChoiceField( + queryset=Alias.objects.all(), + label=_("Source"), + required=False, + widget=Autocomplete( + Alias, + resetable=True, + attrs={ + 'api_url': '/api/note/alias/', + 'placeholder': 'Note ...', + }, + ), + ) + + destination = forms.ModelChoiceField( + queryset=Alias.objects.all(), + label=_("Destination"), + required=False, + widget=Autocomplete( + Alias, + resetable=True, + attrs={ + 'api_url': '/api/note/alias/', + 'placeholder': 'Note ...', + }, + ), + ) + + type = forms.ModelMultipleChoiceField( + queryset=ContentType.objects.filter(app_label="note", model__endswith="transaction"), + initial=ContentType.objects.filter(app_label="note", model__endswith="transaction"), + label=_("Type"), + required=False, + widget=CheckboxSelectMultiple(), + ) + + reason = forms.CharField( + label=_("Reason"), + required=False, + ) + + valid = forms.BooleanField( + label=_("Valid"), + initial=False, + required=False, + ) + + amount_gte = forms.Field( + label=_("Total amount greater than"), + initial=0, + required=False, + widget=AmountInput(), + ) + + amount_lte = forms.Field( + initial=2 ** 31 - 1, + label=_("Total amount less than"), + required=False, + widget=AmountInput(), + ) + + created_after = forms.Field( + label=_("Created after"), + initial="2000-01-01 00:00", + required=False, + widget=DateTimePickerInput(), + ) + + created_before = forms.Field( + label=_("Created before"), + initial="2042-12-31 21:42", + required=False, + widget=DateTimePickerInput(), + ) diff --git a/apps/note/models/transactions.py b/apps/note/models/transactions.py index 6eab05ee..69306b71 100644 --- a/apps/note/models/transactions.py +++ b/apps/note/models/transactions.py @@ -243,6 +243,7 @@ class RecurrentTransaction(Transaction): TransactionTemplate, on_delete=models.PROTECT, ) + category = models.ForeignKey( TemplateCategory, on_delete=models.PROTECT, @@ -252,6 +253,10 @@ class RecurrentTransaction(Transaction): def type(self): return _('Template') + class Meta: + verbose_name = _("recurrent transaction") + verbose_name_plural = _("recurrent transactions") + class SpecialTransaction(Transaction): """ @@ -290,6 +295,10 @@ class SpecialTransaction(Transaction): raise(ValidationError(_("A special transaction is only possible between a" " Note associated to a payment method and a User or a Club"))) + class Meta: + verbose_name = _("Special transaction") + verbose_name_plural = _("Special transactions") + class MembershipTransaction(Transaction): """ diff --git a/apps/note/urls.py b/apps/note/urls.py index 9d6af317..c5662f2c 100644 --- a/apps/note/urls.py +++ b/apps/note/urls.py @@ -12,4 +12,5 @@ urlpatterns = [ path('buttons/update//', views.TransactionTemplateUpdateView.as_view(), name='template_update'), path('buttons/', views.TransactionTemplateListView.as_view(), name='template_list'), path('consos/', views.ConsoView.as_view(), name='consos'), + path('transactions//', views.TransactionSearchView.as_view(), name='transactions'), ] diff --git a/apps/note/views.py b/apps/note/views.py index ad2b2a99..3524a080 100644 --- a/apps/note/views.py +++ b/apps/note/views.py @@ -5,9 +5,9 @@ import json from django.conf import settings from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.contenttypes.models import ContentType -from django.db.models import Q +from django.db.models import Q, F from django.utils.translation import gettext_lazy as _ -from django.views.generic import CreateView, UpdateView +from django.views.generic import CreateView, UpdateView, DetailView from django_tables2 import SingleTableView from django.urls import reverse_lazy @@ -16,8 +16,8 @@ from note_kfet.inputs import AmountInput from permission.backends import PermissionBackend from permission.views import ProtectQuerysetMixin -from .forms import TransactionTemplateForm -from .models import TemplateCategory, Transaction, TransactionTemplate, RecurrentTransaction, NoteSpecial +from .forms import TransactionTemplateForm, SearchTransactionForm +from .models import TemplateCategory, Transaction, TransactionTemplate, RecurrentTransaction, NoteSpecial, Note from .models.transactions import SpecialTransaction from .tables import HistoryTable, ButtonTable @@ -171,3 +171,51 @@ class ConsoView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView): context['no_cache'] = True return context + + +class TransactionSearchView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): + model = Note + context_object_name = "note" + template_name = "note/search_transactions.html" + extra_context = {"title": _("Search transactions")} + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + + form = SearchTransactionForm(data=self.request.GET if self.request.GET else None) + context["form"] = form + + form.full_clean() + if form.is_valid(): + data = form.cleaned_data + else: + data = {} + + transactions = Transaction.objects.annotate(total_amount=F("quantity") * F("amount")).filter( + PermissionBackend.filter_queryset(self.request.user, Transaction, "view"))\ + .filter(Q(source=self.object) | Q(destination=self.object)).order_by('-created_at') + + if "source" in data and data["source"]: + transactions = transactions.filter(source_id=data["source"].note_id) + if "destination" in data and data["destination"]: + transactions = transactions.filter(destination_id=data["destination"].note_id) + if "type" in data and data["type"]: + transactions = transactions.filter(polymorphic_ctype__in=data["type"]) + if "reason" in data and data["reason"]: + transactions = transactions.filter(reason__iregex=data["reason"]) + if "valid" in data and data["valid"]: + transactions = transactions.filter(valid=data["valid"]) + if "amount_gte" in data and data["amount_gte"]: + transactions = transactions.filter(total_amount__gte=data["amount_gte"]) + if "amount_lte" in data and data["amount_lte"]: + transactions = transactions.filter(total_amount__lte=data["amount_lte"]) + if "created_after" in data and data["created_after"]: + transactions = transactions.filter(created_at__gte=data["created_after"]) + if "created_before" in data and data["created_before"]: + transactions = transactions.filter(created_at__lte=data["created_before"]) + + table = HistoryTable(transactions) + table.paginate(per_page=20) + context["table"] = table + + return context diff --git a/apps/wei/views.py b/apps/wei/views.py index 8a95c72a..ed76cc0f 100644 --- a/apps/wei/views.py +++ b/apps/wei/views.py @@ -130,7 +130,7 @@ class WEIDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): context["my_registration"] = my_registration buses = Bus.objects.filter(PermissionBackend.filter_queryset(self.request.user, Bus, "view")) \ - .filter(wei=self.object).annotate(count=Count("memberships")) + .filter(wei=self.object).annotate(count=Count("memberships")).order_by("name") bus_table = BusTable(data=buses, prefix="bus-") context['buses'] = bus_table @@ -589,9 +589,6 @@ class WEIUpdateRegistrationView(ProtectQuerysetMixin, LoginRequiredMixin, Update form_class = WEIRegistrationForm extra_context = {"title": _("Update WEI Registration")} - def get_queryset(self, **kwargs): - return WEIRegistration.objects - def dispatch(self, request, *args, **kwargs): wei = self.get_object().wei today = date.today() diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index b094a5ac..3f207ceb 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-03 12:35+0200\n" +"POT-Creation-Date: 2020-08-03 18:38+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -46,7 +46,7 @@ msgstr "" #: apps/activity/models.py:24 apps/activity/models.py:49 #: apps/member/models.py:158 apps/note/models/notes.py:212 #: apps/note/models/transactions.py:25 apps/note/models/transactions.py:45 -#: apps/note/models/transactions.py:263 apps/permission/models.py:339 +#: apps/note/models/transactions.py:268 apps/permission/models.py:339 #: apps/wei/models.py:65 apps/wei/models.py:117 #: templates/member/club_info.html:13 templates/member/profile_info.html:14 #: templates/registration/future_profile_detail.html:16 @@ -182,16 +182,16 @@ msgstr "" msgid "remove" msgstr "" -#: apps/activity/tables.py:75 apps/treasury/models.py:141 +#: apps/activity/tables.py:75 apps/note/forms.py:76 apps/treasury/models.py:141 msgid "Type" msgstr "" -#: apps/activity/tables.py:77 apps/member/forms.py:102 +#: apps/activity/tables.py:77 apps/member/forms.py:103 #: apps/registration/forms.py:70 apps/treasury/forms.py:120 msgid "Last name" msgstr "" -#: apps/activity/tables.py:79 apps/member/forms.py:107 +#: apps/activity/tables.py:79 apps/member/forms.py:108 #: apps/registration/forms.py:75 apps/treasury/forms.py:122 #: templates/note/transaction_form.html:129 msgid "First name" @@ -225,7 +225,7 @@ msgstr "" msgid "Invite guest to the activity \"{}\"" msgstr "" -#: apps/activity/views.py:171 +#: apps/activity/views.py:181 msgid "Entry for activity \"{}\"" msgstr "" @@ -313,45 +313,45 @@ msgstr "" msgid "member" msgstr "" -#: apps/member/forms.py:58 apps/member/views.py:82 +#: apps/member/forms.py:59 apps/member/views.py:82 #: apps/registration/forms.py:28 msgid "An alias with a similar name already exists." msgstr "" -#: apps/member/forms.py:81 apps/registration/forms.py:50 +#: apps/member/forms.py:82 apps/registration/forms.py:50 msgid "Inscription paid by Société Générale" msgstr "" -#: apps/member/forms.py:83 apps/registration/forms.py:52 +#: apps/member/forms.py:84 apps/registration/forms.py:52 msgid "Check this case is the Société Générale paid the inscription." msgstr "" -#: apps/member/forms.py:88 apps/registration/forms.py:57 +#: apps/member/forms.py:89 apps/registration/forms.py:57 msgid "Credit type" msgstr "" -#: apps/member/forms.py:89 apps/registration/forms.py:58 +#: apps/member/forms.py:90 apps/registration/forms.py:58 msgid "No credit" msgstr "" -#: apps/member/forms.py:91 +#: apps/member/forms.py:92 msgid "You can credit the note of the user." msgstr "" -#: apps/member/forms.py:95 apps/registration/forms.py:63 +#: apps/member/forms.py:96 apps/registration/forms.py:63 msgid "Credit amount" msgstr "" -#: apps/member/forms.py:112 apps/registration/forms.py:80 +#: apps/member/forms.py:113 apps/registration/forms.py:80 #: apps/treasury/forms.py:124 templates/note/transaction_form.html:135 msgid "Bank" msgstr "" -#: apps/member/forms.py:139 +#: apps/member/forms.py:140 msgid "User" msgstr "" -#: apps/member/forms.py:153 +#: apps/member/forms.py:154 msgid "Roles" msgstr "" @@ -540,7 +540,7 @@ msgstr "" msgid "membership ends on" msgstr "" -#: apps/member/models.py:310 apps/member/views.py:535 apps/wei/views.py:795 +#: apps/member/models.py:310 apps/member/views.py:535 apps/wei/views.py:793 msgid "User is not a member of the parent club" msgstr "" @@ -620,7 +620,7 @@ msgstr "" msgid "Add new member to the club" msgstr "" -#: apps/member/views.py:530 apps/wei/views.py:786 +#: apps/member/views.py:530 apps/wei/views.py:784 msgid "" "This user don't have enough money to join this club, and can't have a " "negative balance." @@ -662,14 +662,46 @@ msgstr "" msgid "amount" msgstr "" -#: apps/note/forms.py:14 +#: apps/note/forms.py:15 msgid "select an image" msgstr "" -#: apps/note/forms.py:15 +#: apps/note/forms.py:16 msgid "Maximal size: 2MB" msgstr "" +#: apps/note/forms.py:47 +msgid "Source" +msgstr "" + +#: apps/note/forms.py:61 +msgid "Destination" +msgstr "" + +#: apps/note/forms.py:82 templates/note/transaction_form.html:104 +msgid "Reason" +msgstr "" + +#: apps/note/forms.py:87 apps/treasury/tables.py:117 +msgid "Valid" +msgstr "" + +#: apps/note/forms.py:93 +msgid "Total amount greater than" +msgstr "" + +#: apps/note/forms.py:101 +msgid "Total amount less than" +msgstr "" + +#: apps/note/forms.py:107 +msgid "Created after" +msgstr "" + +#: apps/note/forms.py:114 +msgid "Created before" +msgstr "" + #: apps/note/models/notes.py:29 msgid "account balance" msgstr "" @@ -842,39 +874,55 @@ msgstr "" msgid "Transfer" msgstr "" -#: apps/note/models/transactions.py:253 +#: apps/note/models/transactions.py:254 msgid "Template" msgstr "" -#: apps/note/models/transactions.py:268 -msgid "first_name" +#: apps/note/models/transactions.py:257 +msgid "recurrent transaction" +msgstr "" + +#: apps/note/models/transactions.py:258 +msgid "recurrent transactions" msgstr "" #: apps/note/models/transactions.py:273 +msgid "first_name" +msgstr "" + +#: apps/note/models/transactions.py:278 msgid "bank" msgstr "" -#: apps/note/models/transactions.py:279 +#: apps/note/models/transactions.py:284 #: templates/activity/activity_entry.html:17 #: templates/note/transaction_form.html:20 msgid "Credit" msgstr "" -#: apps/note/models/transactions.py:279 templates/note/transaction_form.html:24 +#: apps/note/models/transactions.py:284 templates/note/transaction_form.html:24 msgid "Debit" msgstr "" -#: apps/note/models/transactions.py:290 +#: apps/note/models/transactions.py:295 msgid "" "A special transaction is only possible between a Note associated to a " "payment method and a User or a Club" msgstr "" -#: apps/note/models/transactions.py:307 apps/note/models/transactions.py:312 +#: apps/note/models/transactions.py:299 +msgid "Special transaction" +msgstr "" + +#: apps/note/models/transactions.py:300 +msgid "Special transactions" +msgstr "" + +#: apps/note/models/transactions.py:316 apps/note/models/transactions.py:321 msgid "membership transaction" msgstr "" -#: apps/note/models/transactions.py:308 apps/treasury/models.py:228 +#: apps/note/models/transactions.py:317 apps/treasury/models.py:228 msgid "membership transactions" msgstr "" @@ -903,26 +951,30 @@ msgstr "" msgid "Edit" msgstr "" -#: apps/note/views.py:33 +#: apps/note/views.py:35 msgid "Transfer money" msgstr "" -#: apps/note/views.py:69 +#: apps/note/views.py:75 msgid "Create new button" msgstr "" -#: apps/note/views.py:78 +#: apps/note/views.py:84 msgid "Search button" msgstr "" -#: apps/note/views.py:101 +#: apps/note/views.py:107 msgid "Update button" msgstr "" -#: apps/note/views.py:138 templates/base.html:94 +#: apps/note/views.py:144 templates/base.html:94 msgid "Consumptions" msgstr "" +#: apps/note/views.py:180 +msgid "Search transactions" +msgstr "" + #: apps/permission/models.py:99 #, python-brace-format msgid "Can {type} {model}.{field} in {query}" @@ -1288,10 +1340,6 @@ msgstr "" msgid "Remove" msgstr "" -#: apps/treasury/tables.py:117 -msgid "Valid" -msgstr "" - #: apps/treasury/tables.py:124 msgid "Yes" msgstr "" @@ -1342,37 +1390,37 @@ msgstr "" msgid "WEI" msgstr "" -#: apps/wei/forms/registration.py:47 apps/wei/models.py:112 +#: apps/wei/forms/registration.py:48 apps/wei/models.py:112 #: apps/wei/models.py:297 msgid "bus" msgstr "" -#: apps/wei/forms/registration.py:48 +#: apps/wei/forms/registration.py:49 msgid "" "This choice is not definitive. The WEI organizers are free to attribute for " "you a bus and a team, in particular if you are a free eletron." msgstr "" -#: apps/wei/forms/registration.py:54 +#: apps/wei/forms/registration.py:56 msgid "Team" msgstr "" -#: apps/wei/forms/registration.py:56 +#: apps/wei/forms/registration.py:58 msgid "" "Leave this field empty if you won't be in a team (staff, bus chief, free " "electron)" msgstr "" -#: apps/wei/forms/registration.py:61 apps/wei/forms/registration.py:67 +#: apps/wei/forms/registration.py:64 apps/wei/forms/registration.py:74 #: apps/wei/models.py:147 msgid "WEI Roles" msgstr "" -#: apps/wei/forms/registration.py:62 +#: apps/wei/forms/registration.py:65 msgid "Select the roles that you are interested in." msgstr "" -#: apps/wei/forms/registration.py:72 +#: apps/wei/forms/registration.py:81 msgid "This team doesn't belong to the given bus." msgstr "" @@ -1618,7 +1666,7 @@ msgstr "" msgid "Register 1A" msgstr "" -#: apps/wei/views.py:489 apps/wei/views.py:559 +#: apps/wei/views.py:489 apps/wei/views.py:560 msgid "This user is already registered to this WEI." msgstr "" @@ -1636,31 +1684,31 @@ msgstr "" msgid "Register 2A+" msgstr "" -#: apps/wei/views.py:541 apps/wei/views.py:629 +#: apps/wei/views.py:542 apps/wei/views.py:627 msgid "You already opened an account in the Société générale." msgstr "" -#: apps/wei/views.py:589 +#: apps/wei/views.py:590 msgid "Update WEI Registration" msgstr "" -#: apps/wei/views.py:679 +#: apps/wei/views.py:677 msgid "Delete WEI registration" msgstr "" -#: apps/wei/views.py:690 +#: apps/wei/views.py:688 msgid "You don't have the right to delete this WEI registration." msgstr "" -#: apps/wei/views.py:709 +#: apps/wei/views.py:707 msgid "Validate WEI registration" msgstr "" -#: apps/wei/views.py:790 +#: apps/wei/views.py:788 msgid "This user didn't give her/his caution check." msgstr "" -#: apps/wei/views.py:827 apps/wei/views.py:880 apps/wei/views.py:890 +#: apps/wei/views.py:825 apps/wei/views.py:878 apps/wei/views.py:888 #: templates/wei/survey.html:12 templates/wei/survey_closed.html:12 #: templates/wei/survey_end.html:12 msgid "Survey WEI" @@ -1822,6 +1870,10 @@ msgstr "" msgid "Add alias" msgstr "" +#: templates/member/autocomplete_model.html:11 +msgid "Reset" +msgstr "" + #: templates/member/club_info.html:17 msgid "Club Parent" msgstr "" @@ -1990,10 +2042,6 @@ msgstr "" msgid "Action" msgstr "" -#: templates/note/transaction_form.html:104 -msgid "Reason" -msgstr "" - #: templates/note/transaction_form.html:113 msgid "Transfer type" msgstr "" diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index 511b3efb..8fedb67a 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-03 12:35+0200\n" +"POT-Creation-Date: 2020-08-03 18:38+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -47,7 +47,7 @@ msgstr "Vous ne pouvez pas inviter plus de 3 personnes à cette activité." #: apps/activity/models.py:24 apps/activity/models.py:49 #: apps/member/models.py:158 apps/note/models/notes.py:212 #: apps/note/models/transactions.py:25 apps/note/models/transactions.py:45 -#: apps/note/models/transactions.py:263 apps/permission/models.py:339 +#: apps/note/models/transactions.py:268 apps/permission/models.py:339 #: apps/wei/models.py:65 apps/wei/models.py:117 #: templates/member/club_info.html:13 templates/member/profile_info.html:14 #: templates/registration/future_profile_detail.html:16 @@ -183,16 +183,16 @@ msgstr "Entré le " msgid "remove" msgstr "supprimer" -#: apps/activity/tables.py:75 apps/treasury/models.py:141 +#: apps/activity/tables.py:75 apps/note/forms.py:76 apps/treasury/models.py:141 msgid "Type" msgstr "Type" -#: apps/activity/tables.py:77 apps/member/forms.py:102 +#: apps/activity/tables.py:77 apps/member/forms.py:103 #: apps/registration/forms.py:70 apps/treasury/forms.py:120 msgid "Last name" msgstr "Nom de famille" -#: apps/activity/tables.py:79 apps/member/forms.py:107 +#: apps/activity/tables.py:79 apps/member/forms.py:108 #: apps/registration/forms.py:75 apps/treasury/forms.py:122 #: templates/note/transaction_form.html:129 msgid "First name" @@ -226,7 +226,7 @@ msgstr "Modifier l'activité" msgid "Invite guest to the activity \"{}\"" msgstr "Invitation pour l'activité « {} »" -#: apps/activity/views.py:171 +#: apps/activity/views.py:181 msgid "Entry for activity \"{}\"" msgstr "Entrées pour l'activité « {} »" @@ -314,45 +314,45 @@ msgstr "cotisation" msgid "member" msgstr "adhérent" -#: apps/member/forms.py:58 apps/member/views.py:82 +#: apps/member/forms.py:59 apps/member/views.py:82 #: apps/registration/forms.py:28 msgid "An alias with a similar name already exists." msgstr "Un alias avec un nom similaire existe déjà." -#: apps/member/forms.py:81 apps/registration/forms.py:50 +#: apps/member/forms.py:82 apps/registration/forms.py:50 msgid "Inscription paid by Société Générale" msgstr "Inscription payée par la Société générale" -#: apps/member/forms.py:83 apps/registration/forms.py:52 +#: apps/member/forms.py:84 apps/registration/forms.py:52 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:88 apps/registration/forms.py:57 +#: apps/member/forms.py:89 apps/registration/forms.py:57 msgid "Credit type" msgstr "Type de rechargement" -#: apps/member/forms.py:89 apps/registration/forms.py:58 +#: apps/member/forms.py:90 apps/registration/forms.py:58 msgid "No credit" msgstr "Pas de rechargement" -#: apps/member/forms.py:91 +#: apps/member/forms.py:92 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:95 apps/registration/forms.py:63 +#: apps/member/forms.py:96 apps/registration/forms.py:63 msgid "Credit amount" msgstr "Montant à créditer" -#: apps/member/forms.py:112 apps/registration/forms.py:80 +#: apps/member/forms.py:113 apps/registration/forms.py:80 #: apps/treasury/forms.py:124 templates/note/transaction_form.html:135 msgid "Bank" msgstr "Banque" -#: apps/member/forms.py:139 +#: apps/member/forms.py:140 msgid "User" msgstr "Utilisateur" -#: apps/member/forms.py:153 +#: apps/member/forms.py:154 msgid "Roles" msgstr "Rôles" @@ -545,7 +545,7 @@ msgstr "l'adhésion commence le" msgid "membership ends on" msgstr "l'adhésion finit le" -#: apps/member/models.py:310 apps/member/views.py:535 apps/wei/views.py:795 +#: apps/member/models.py:310 apps/member/views.py:535 apps/wei/views.py:793 msgid "User is not a member of the parent club" msgstr "L'utilisateur n'est pas membre du club parent" @@ -625,7 +625,7 @@ msgstr "Modifier le club" msgid "Add new member to the club" msgstr "Ajouter un nouveau membre au club" -#: apps/member/views.py:530 apps/wei/views.py:786 +#: apps/member/views.py:530 apps/wei/views.py:784 msgid "" "This user don't have enough money to join this club, and can't have a " "negative balance." @@ -669,14 +669,46 @@ msgstr "destination" msgid "amount" msgstr "montant" -#: apps/note/forms.py:14 +#: apps/note/forms.py:15 msgid "select an image" msgstr "Choisissez une image" -#: apps/note/forms.py:15 +#: apps/note/forms.py:16 msgid "Maximal size: 2MB" msgstr "Taille maximale : 2 Mo" +#: apps/note/forms.py:47 +msgid "Source" +msgstr "Source" + +#: apps/note/forms.py:61 +msgid "Destination" +msgstr "Destination" + +#: apps/note/forms.py:82 templates/note/transaction_form.html:104 +msgid "Reason" +msgstr "Raison" + +#: apps/note/forms.py:87 apps/treasury/tables.py:117 +msgid "Valid" +msgstr "Valide" + +#: apps/note/forms.py:93 +msgid "Total amount greater than" +msgstr "Montant total supérieur à" + +#: apps/note/forms.py:101 +msgid "Total amount less than" +msgstr "Montant total inférieur à" + +#: apps/note/forms.py:107 +msgid "Created after" +msgstr "Créé après" + +#: apps/note/forms.py:114 +msgid "Created before" +msgstr "Créé avant" + #: apps/note/models/notes.py:29 msgid "account balance" msgstr "solde du compte" @@ -805,11 +837,11 @@ msgstr "mis en avant" #: apps/note/models/transactions.py:87 msgid "transaction template" -msgstr "modèle de transaction" +msgstr "Modèle de transaction" #: apps/note/models/transactions.py:88 msgid "transaction templates" -msgstr "modèles de transaction" +msgstr "Modèles de transaction" #: apps/note/models/transactions.py:112 apps/note/models/transactions.py:125 #: apps/note/tables.py:35 apps/note/tables.py:44 @@ -830,12 +862,12 @@ msgstr "Motif d'invalidité" #: apps/note/models/transactions.py:159 msgid "transaction" -msgstr "transaction" +msgstr "Transaction" #: apps/note/models/transactions.py:160 #: templates/treasury/sogecredit_detail.html:22 msgid "transactions" -msgstr "transactions" +msgstr "Transactions" #: apps/note/models/transactions.py:175 msgid "" @@ -852,29 +884,37 @@ msgstr "" msgid "Transfer" msgstr "Virement" -#: apps/note/models/transactions.py:253 +#: apps/note/models/transactions.py:254 msgid "Template" msgstr "Bouton" -#: apps/note/models/transactions.py:268 +#: apps/note/models/transactions.py:257 +msgid "recurrent transaction" +msgstr "Transaction issue de bouton" + +#: apps/note/models/transactions.py:258 +msgid "recurrent transactions" +msgstr "Transactions issues de boutons" + +#: apps/note/models/transactions.py:273 msgid "first_name" msgstr "prénom" -#: apps/note/models/transactions.py:273 +#: apps/note/models/transactions.py:278 msgid "bank" msgstr "banque" -#: apps/note/models/transactions.py:279 +#: apps/note/models/transactions.py:284 #: templates/activity/activity_entry.html:17 #: templates/note/transaction_form.html:20 msgid "Credit" msgstr "Crédit" -#: apps/note/models/transactions.py:279 templates/note/transaction_form.html:24 +#: apps/note/models/transactions.py:284 templates/note/transaction_form.html:24 msgid "Debit" msgstr "Débit" -#: apps/note/models/transactions.py:290 +#: apps/note/models/transactions.py:295 msgid "" "A special transaction is only possible between a Note associated to a " "payment method and a User or a Club" @@ -882,11 +922,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:307 apps/note/models/transactions.py:312 +#: apps/note/models/transactions.py:299 +msgid "Special transaction" +msgstr "Transaction de crédit/retrait" + +#: apps/note/models/transactions.py:300 +msgid "Special transactions" +msgstr "Transactions de crédit/retrait" + +#: apps/note/models/transactions.py:316 apps/note/models/transactions.py:321 msgid "membership transaction" msgstr "Transaction d'adhésion" -#: apps/note/models/transactions.py:308 apps/treasury/models.py:228 +#: apps/note/models/transactions.py:317 apps/treasury/models.py:228 msgid "membership transactions" msgstr "Transactions d'adhésion" @@ -915,26 +963,30 @@ msgstr "Supprimer" msgid "Edit" msgstr "Éditer" -#: apps/note/views.py:33 +#: apps/note/views.py:35 msgid "Transfer money" msgstr "Transférer de l'argent" -#: apps/note/views.py:69 +#: apps/note/views.py:75 msgid "Create new button" msgstr "Créer un nouveau bouton" -#: apps/note/views.py:78 +#: apps/note/views.py:84 msgid "Search button" msgstr "Chercher un bouton" -#: apps/note/views.py:101 +#: apps/note/views.py:107 msgid "Update button" msgstr "Modifier le bouton" -#: apps/note/views.py:138 templates/base.html:94 +#: apps/note/views.py:144 templates/base.html:94 msgid "Consumptions" msgstr "Consommations" +#: apps/note/views.py:180 +msgid "Search transactions" +msgstr "Rechercher des transactions" + #: apps/permission/models.py:99 #, python-brace-format msgid "Can {type} {model}.{field} in {query}" @@ -1317,10 +1369,6 @@ msgstr "Ajouter" msgid "Remove" msgstr "supprimer" -#: apps/treasury/tables.py:117 -msgid "Valid" -msgstr "Valide" - #: apps/treasury/tables.py:124 msgid "Yes" msgstr "Oui" @@ -1371,12 +1419,12 @@ msgstr "Gérer les crédits de la Société générale" msgid "WEI" msgstr "WEI" -#: apps/wei/forms/registration.py:47 apps/wei/models.py:112 +#: apps/wei/forms/registration.py:48 apps/wei/models.py:112 #: apps/wei/models.py:297 msgid "bus" msgstr "Bus" -#: apps/wei/forms/registration.py:48 +#: apps/wei/forms/registration.py:49 msgid "" "This choice is not definitive. The WEI organizers are free to attribute for " "you a bus and a team, in particular if you are a free eletron." @@ -1385,11 +1433,11 @@ msgstr "" "attribuer un bus et une équipe, en particulier si vous êtes un électron " "libre." -#: apps/wei/forms/registration.py:54 +#: apps/wei/forms/registration.py:56 msgid "Team" msgstr "Équipe" -#: apps/wei/forms/registration.py:56 +#: apps/wei/forms/registration.py:58 msgid "" "Leave this field empty if you won't be in a team (staff, bus chief, free " "electron)" @@ -1397,16 +1445,16 @@ msgstr "" "Laissez ce champ vide si vous ne serez pas dans une équipe (staff, chef de " "bus ou électron libre)" -#: apps/wei/forms/registration.py:61 apps/wei/forms/registration.py:67 +#: apps/wei/forms/registration.py:64 apps/wei/forms/registration.py:74 #: apps/wei/models.py:147 msgid "WEI Roles" msgstr "Rôles au WEI" -#: apps/wei/forms/registration.py:62 +#: apps/wei/forms/registration.py:65 msgid "Select the roles that you are interested in." msgstr "Sélectionnez les rôles qui vous intéressent." -#: apps/wei/forms/registration.py:72 +#: apps/wei/forms/registration.py:81 msgid "This team doesn't belong to the given bus." msgstr "Cette équipe n'appartient pas à ce bus." @@ -1662,7 +1710,7 @@ msgstr "Inscrire un 1A au WEI" msgid "Register 1A" msgstr "Inscrire un 1A" -#: apps/wei/views.py:489 apps/wei/views.py:559 +#: apps/wei/views.py:489 apps/wei/views.py:560 msgid "This user is already registered to this WEI." msgstr "Cette personne est déjà inscrite au WEI." @@ -1682,31 +1730,31 @@ msgstr "Inscrire un 2A+ au WEI" msgid "Register 2A+" msgstr "Inscrire un 2A+" -#: apps/wei/views.py:541 apps/wei/views.py:629 +#: apps/wei/views.py:542 apps/wei/views.py:627 msgid "You already opened an account in the Société générale." msgstr "Vous avez déjà ouvert un compte auprès de la société générale." -#: apps/wei/views.py:589 +#: apps/wei/views.py:590 msgid "Update WEI Registration" msgstr "Modifier l'inscription WEI" -#: apps/wei/views.py:679 +#: apps/wei/views.py:677 msgid "Delete WEI registration" msgstr "Supprimer l'inscription WEI" -#: apps/wei/views.py:690 +#: apps/wei/views.py:688 msgid "You don't have the right to delete this WEI registration." msgstr "Vous n'avez pas la permission de supprimer cette inscription au WEI." -#: apps/wei/views.py:709 +#: apps/wei/views.py:707 msgid "Validate WEI registration" msgstr "Valider l'inscription WEI" -#: apps/wei/views.py:790 +#: apps/wei/views.py:788 msgid "This user didn't give her/his caution check." msgstr "Cet utilisateur n'a pas donné son chèque de caution." -#: apps/wei/views.py:827 apps/wei/views.py:880 apps/wei/views.py:890 +#: apps/wei/views.py:825 apps/wei/views.py:878 apps/wei/views.py:888 #: templates/wei/survey.html:12 templates/wei/survey_closed.html:12 #: templates/wei/survey_end.html:12 msgid "Survey WEI" @@ -1882,6 +1930,10 @@ msgstr "" msgid "Add alias" msgstr "Ajouter un alias" +#: templates/member/autocomplete_model.html:11 +msgid "Reset" +msgstr "" + #: templates/member/club_info.html:17 msgid "Club Parent" msgstr "Club parent" @@ -2050,10 +2102,6 @@ msgstr "Sélection des destinataires" msgid "Action" msgstr "Action" -#: templates/note/transaction_form.html:104 -msgid "Reason" -msgstr "Raison" - #: templates/note/transaction_form.html:113 msgid "Transfer type" msgstr "Type de transfert" diff --git a/note_kfet/inputs.py b/note_kfet/inputs.py index 1a17d5ac..8e3d9e29 100644 --- a/note_kfet/inputs.py +++ b/note_kfet/inputs.py @@ -23,10 +23,11 @@ class AmountInput(NumberInput): class Autocomplete(TextInput): template_name = "member/autocomplete_model.html" - def __init__(self, model, attrs=None): + def __init__(self, model, resetable=False, attrs=None): super().__init__(attrs) self.model = model + self.resetable = resetable self.model_pk = None class Media: @@ -34,6 +35,11 @@ class Autocomplete(TextInput): js = ('js/autocomplete_model.js', ) + def get_context(self, name, value, attrs): + context = super().get_context(name, value, attrs) + context['widget']['resetable'] = self.resetable + return context + def format_value(self, value): if value: self.attrs["model_pk"] = int(value) diff --git a/static/js/autocomplete_model.js b/static/js/autocomplete_model.js index 6e135ad1..9d9ba2d3 100644 --- a/static/js/autocomplete_model.js +++ b/static/js/autocomplete_model.js @@ -10,6 +10,7 @@ $(document).ready(function () { if (!name_field) name_field = "name"; let input = target.val(); + $("#" + prefix + "_reset").removeClass("d-none"); $.getJSON(api_url + (api_url.includes("?") ? "&" : "?") + "format=json&search=^" + input + api_url_suffix, function(objects) { let html = ""; @@ -39,4 +40,12 @@ $(document).ready(function () { } }); }); + + $(".autocomplete-reset").click(function() { + let name = $(this).attr("id").replace("_reset", ""); + $("#" + name + "_pk").val(""); + $("#" + name).val(""); + $("#" + name + "_list").html(""); + $(this).addClass("d-none"); + }); }); \ No newline at end of file diff --git a/templates/member/autocomplete_model.html b/templates/member/autocomplete_model.html index 2236c6ef..0aeca361 100644 --- a/templates/member/autocomplete_model.html +++ b/templates/member/autocomplete_model.html @@ -1,3 +1,5 @@ +{% load i18n %} + + {% if widget.resetable %} + {% trans "Reset" %} + {% endif %}

    diff --git a/templates/member/club_tables.html b/templates/member/club_tables.html index 139d3abc..063c00c5 100644 --- a/templates/member/club_tables.html +++ b/templates/member/club_tables.html @@ -1,5 +1,7 @@ {% load render_table from django_tables2 %} {% load i18n %} +{% load perms %} + {% if managers.data %}
    @@ -29,7 +31,7 @@ {% if history_list.data %}
    diff --git a/templates/member/profile_info.html b/templates/member/profile_info.html index 7be10ba1..35d3e4ea 100644 --- a/templates/member/profile_info.html +++ b/templates/member/profile_info.html @@ -2,22 +2,22 @@
    -

    {% trans "Account #" %} {{ object.pk }}

    +

    {% trans "Account #" %} {{ user.pk }}

    {% trans 'name'|capfirst %}, {% trans 'first name' %}
    -
    {{ object.last_name }} {{ object.first_name }}
    +
    {{ user.last_name }} {{ user.first_name }}
    {% trans 'username'|capfirst %}
    -
    {{ object.username }}
    +
    {{ user.username }}
    - {% if object.pk == user.pk %} + {% if user.pk == user.pk %}
    {% trans 'password'|capfirst %}
    @@ -27,25 +27,25 @@ {% endif %}
    {% trans 'section'|capfirst %}
    -
    {{ object.profile.section }}
    +
    {{ user.profile.section }}
    {% trans 'address'|capfirst %}
    -
    {{ object.profile.address }}
    +
    {{ user.profile.address }}
    {% trans 'balance'|capfirst %}
    -
    {{ object.note.balance | pretty_money }}
    +
    {{ user.note.balance | pretty_money }}
    -
    {% trans 'aliases'|capfirst %}
    -
    {{ object.note.alias_set.all|join:", " }}
    +
    {% trans 'aliases'|capfirst %}
    +
    {{ user.note.alias_set.all|join:", " }}
    - {% if object.pk == user.pk %} + {% if user.pk == user.pk %} {% trans 'Manage auth token' %} {% endif %}