+ 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
+
+
+
+
+
+
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/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 "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 %}