diff --git a/apps/registration/forms.py b/apps/registration/forms.py
index 17b89c33..21e0da55 100644
--- a/apps/registration/forms.py
+++ b/apps/registration/forms.py
@@ -46,7 +46,8 @@ class SignUpForm(UserCreationForm):
class DeclareSogeAccountOpenedForm(forms.Form):
soge_account = forms.BooleanField(
- label=_("I declare that I opened a bank account in the Société générale with the BDE partnership."),
+ label=_("I declare that I opened or I will open soon a bank account in the Société générale with the BDE \
+ partnership."),
help_text=_("Warning: this engages you to open your bank account. If you finally decides to don't open your "
"account, you will have to pay the BDE membership."),
required=False,
diff --git a/apps/treasury/models.py b/apps/treasury/models.py
index 7e4e1566..427d796d 100644
--- a/apps/treasury/models.py
+++ b/apps/treasury/models.py
@@ -1,6 +1,6 @@
# Copyright (C) 2018-2021 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
-
+import datetime
from datetime import date
from django.conf import settings
@@ -305,8 +305,16 @@ class SogeCredit(models.Model):
@property
def amount(self):
- return self.credit_transaction.total if self.valid \
- else sum(transaction.total for transaction in self.transactions.all())
+ if self.valid:
+ return self.credit_transaction.total
+ amount = sum(transaction.total for transaction in self.transactions.all())
+ if 'wei' in settings.INSTALLED_APPS:
+ from wei.models import WEIMembership
+ if not WEIMembership.objects.filter(club__weiclub__year=datetime.date.today().year, user=self.user)\
+ .exists():
+ # 80 € for people that don't go to WEI
+ amount += 8000
+ return amount
def update_transactions(self):
"""
@@ -323,13 +331,15 @@ class SogeCredit(models.Model):
if bde_qs.exists():
m = bde_qs.get()
- if m.transaction not in self.transactions.all():
- self.transactions.add(m.transaction)
+ if MembershipTransaction.objects.filter(membership=m).exists(): # non-free membership
+ if m.transaction not in self.transactions.all():
+ self.transactions.add(m.transaction)
if kfet_qs.exists():
m = kfet_qs.get()
- if m.transaction not in self.transactions.all():
- self.transactions.add(m.transaction)
+ if MembershipTransaction.objects.filter(membership=m).exists(): # non-free membership
+ if m.transaction not in self.transactions.all():
+ self.transactions.add(m.transaction)
if 'wei' in settings.INSTALLED_APPS:
from wei.models import WEIClub
@@ -337,8 +347,9 @@ class SogeCredit(models.Model):
wei_qs = Membership.objects.filter(user=self.user, club=wei, date_start__gte=wei.membership_start)
if wei_qs.exists():
m = wei_qs.get()
- if m.transaction not in self.transactions.all():
- self.transactions.add(m.transaction)
+ if MembershipTransaction.objects.filter(membership=m).exists(): # non-free membership
+ if m.transaction not in self.transactions.all():
+ self.transactions.add(m.transaction)
for tr in self.transactions.all():
tr.valid = False
@@ -432,6 +443,7 @@ class SogeCredit(models.Model):
# was opened after the validation of the account.
self.credit_transaction.valid = False
self.credit_transaction.reason += " (invalide)"
+ self.credit_transaction._force_save = True
self.credit_transaction.save()
super().delete(**kwargs)
diff --git a/apps/wei/forms/surveys/base.py b/apps/wei/forms/surveys/base.py
index 030f9078..d8e86b3e 100644
--- a/apps/wei/forms/surveys/base.py
+++ b/apps/wei/forms/surveys/base.py
@@ -50,15 +50,19 @@ class WEIBusInformation:
self.bus.information = d
self.bus.save()
- def free_seats(self, surveys: List["WEISurvey"] = None):
- size = self.bus.size
- already_occupied = WEIMembership.objects.filter(bus=self.bus).count()
+ def free_seats(self, surveys: List["WEISurvey"] = None, quotas=None):
+ if not quotas:
+ size = self.bus.size
+ already_occupied = WEIMembership.objects.filter(bus=self.bus).count()
+ quotas = {self.bus: size - already_occupied}
+
+ quota = quotas[self.bus]
valid_surveys = sum(1 for survey in surveys if survey.information.valid
and survey.information.get_selected_bus() == self.bus) if surveys else 0
- return size - already_occupied - valid_surveys
+ return quota - valid_surveys
- def has_free_seats(self, surveys=None):
- return self.free_seats(surveys) > 0
+ def has_free_seats(self, surveys=None, quotas=None):
+ return self.free_seats(surveys, quotas) > 0
class WEISurveyAlgorithm:
@@ -86,14 +90,20 @@ class WEISurveyAlgorithm:
"""
Queryset of all first year registrations
"""
- return WEIRegistration.objects.filter(wei__year=cls.get_survey_class().get_year(), first_year=True)
+ if not hasattr(cls, '_registrations'):
+ cls._registrations = WEIRegistration.objects.filter(wei__year=cls.get_survey_class().get_year(),
+ first_year=True).all()
+
+ return cls._registrations
@classmethod
def get_buses(cls) -> QuerySet:
"""
Queryset of all buses of the associated wei.
"""
- return Bus.objects.filter(wei__year=cls.get_survey_class().get_year(), size__gt=0)
+ if not hasattr(cls, '_buses'):
+ cls._buses = Bus.objects.filter(wei__year=cls.get_survey_class().get_year(), size__gt=0).all()
+ return cls._buses
@classmethod
def get_bus_information(cls, bus):
@@ -135,7 +145,10 @@ class WEISurvey:
"""
The WEI associated to this kind of survey.
"""
- return WEIClub.objects.get(year=cls.get_year())
+ if not hasattr(cls, '_wei'):
+ cls._wei = WEIClub.objects.get(year=cls.get_year())
+
+ return cls._wei
@classmethod
def get_survey_information_class(cls):
@@ -210,3 +223,15 @@ class WEISurvey:
self.information.selected_bus_pk = None
self.information.selected_bus_name = None
self.information.valid = False
+
+ @classmethod
+ def clear_cache(cls):
+ """
+ Clear stored information.
+ """
+ if hasattr(cls, '_wei'):
+ del cls._wei
+ if hasattr(cls.get_algorithm_class(), '_registrations'):
+ del cls.get_algorithm_class()._registrations
+ if hasattr(cls.get_algorithm_class(), '_buses'):
+ del cls.get_algorithm_class()._buses
diff --git a/apps/wei/forms/surveys/wei2021.py b/apps/wei/forms/surveys/wei2021.py
index a6a241cb..e515d447 100644
--- a/apps/wei/forms/surveys/wei2021.py
+++ b/apps/wei/forms/surveys/wei2021.py
@@ -1,13 +1,17 @@
# Copyright (C) 2018-2021 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
+
import time
+from functools import lru_cache
from random import Random
from django import forms
from django.db import transaction
+from django.db.models import Q
from django.utils.translation import gettext_lazy as _
from .base import WEISurvey, WEISurveyInformation, WEISurveyAlgorithm, WEIBusInformation
+from ...models import WEIMembership
WORDS = [
'13 organisé', '3ième mi temps', 'Années 2000', 'Apéro', 'BBQ', 'BP', 'Beauf', 'Binge drinking', 'Bon enfant',
@@ -135,20 +139,41 @@ class WEISurvey2021(WEISurvey):
"""
return self.information.step == 20
+ @classmethod
+ @lru_cache()
+ def word_mean(cls, word):
+ """
+ Calculate the mid-score given by all buses.
+ """
+ buses = cls.get_algorithm_class().get_buses()
+ return sum([cls.get_algorithm_class().get_bus_information(bus).scores[word] for bus in buses]) / buses.count()
+
+ @lru_cache()
def score(self, bus):
if not self.is_complete():
raise ValueError("Survey is not ended, can't calculate score")
- bus_info = self.get_algorithm_class().get_bus_information(bus)
- return sum(bus_info.scores[getattr(self.information, 'word' + str(i))] for i in range(1, 21)) / 20
+ bus_info = self.get_algorithm_class().get_bus_information(bus)
+ # Score is the given score by the bus subtracted to the mid-score of the buses.
+ s = sum(bus_info.scores[getattr(self.information, 'word' + str(i))]
+ - self.word_mean(getattr(self.information, 'word' + str(i))) for i in range(1, 21)) / 20
+ return s
+
+ @lru_cache()
def scores_per_bus(self):
return {bus: self.score(bus) for bus in self.get_algorithm_class().get_buses()}
+ @lru_cache()
def ordered_buses(self):
values = list(self.scores_per_bus().items())
values.sort(key=lambda item: -item[1])
return values
+ @classmethod
+ def clear_cache(cls):
+ cls.word_mean.cache_clear()
+ return super().clear_cache()
+
class WEISurveyAlgorithm2021(WEISurveyAlgorithm):
"""
@@ -164,19 +189,72 @@ class WEISurveyAlgorithm2021(WEISurveyAlgorithm):
def get_bus_information_class(cls):
return WEIBusInformation2021
- def run_algorithm(self):
+ def run_algorithm(self, display_tqdm=False):
"""
Gale-Shapley algorithm implementation.
We modify it to allow buses to have multiple "weddings".
"""
surveys = list(self.get_survey_class()(r) for r in self.get_registrations()) # All surveys
- surveys = [s for s in surveys if s.is_complete()]
- free_surveys = [s for s in surveys if not s.information.valid] # Remaining surveys
+ surveys = [s for s in surveys if s.is_complete()] # Don't consider invalid surveys
+ # Don't manage hardcoded people
+ surveys = [s for s in surveys if not hasattr(s.information, 'hardcoded') or not s.information.hardcoded]
+
+ # Reset previous algorithm run
+ for survey in surveys:
+ survey.free()
+ survey.save()
+
+ non_men = [s for s in surveys if s.registration.gender != 'male']
+ men = [s for s in surveys if s.registration.gender == 'male']
+
+ quotas = {}
+ registrations = self.get_registrations()
+ non_men_total = registrations.filter(~Q(gender='male')).count()
+ for bus in self.get_buses():
+ free_seats = bus.size - WEIMembership.objects.filter(bus=bus, registration__first_year=False).count()
+ # Remove hardcoded people
+ free_seats -= WEIMembership.objects.filter(bus=bus, registration__first_year=True,
+ registration__information_json__icontains="hardcoded").count()
+ quotas[bus] = 4 + int(non_men_total / registrations.count() * free_seats)
+
+ tqdm_obj = None
+ if display_tqdm:
+ from tqdm import tqdm
+ tqdm_obj = tqdm(total=len(non_men), desc="Non-hommes")
+
+ # Repartition for non men people first
+ self.make_repartition(non_men, quotas, tqdm_obj=tqdm_obj)
+
+ quotas = {}
+ for bus in self.get_buses():
+ free_seats = bus.size - WEIMembership.objects.filter(bus=bus, registration__first_year=False).count()
+ free_seats -= sum(1 for s in non_men if s.information.selected_bus_pk == bus.pk)
+ # Remove hardcoded people
+ free_seats -= WEIMembership.objects.filter(bus=bus, registration__first_year=True,
+ registration__information_json__icontains="hardcoded").count()
+ quotas[bus] = free_seats
+
+ if display_tqdm:
+ tqdm_obj.close()
+
+ from tqdm import tqdm
+ tqdm_obj = tqdm(total=len(men), desc="Hommes")
+
+ self.make_repartition(men, quotas, tqdm_obj=tqdm_obj)
+
+ if display_tqdm:
+ tqdm_obj.close()
+
+ # Clear cache information after running algorithm
+ WEISurvey2021.clear_cache()
+
+ def make_repartition(self, surveys, quotas=None, tqdm_obj=None):
+ free_surveys = surveys.copy() # Remaining surveys
while free_surveys: # Some students are not affected
survey = free_surveys[0]
buses = survey.ordered_buses() # Preferences of the student
- for bus, _ignored in buses:
- if self.get_bus_information(bus).has_free_seats(surveys):
+ for bus, current_score in buses:
+ if self.get_bus_information(bus).has_free_seats(surveys, quotas):
# Selected bus has free places. Put student in the bus
survey.select_bus(bus)
survey.save()
@@ -184,7 +262,6 @@ class WEISurveyAlgorithm2021(WEISurveyAlgorithm):
break
else:
# Current bus has not enough places. Remove the least preferred student from the bus if existing
- current_score = survey.score(bus)
least_preferred_survey = None
least_score = -1
# Find the least student in the bus that has a lower score than the current student
@@ -206,6 +283,11 @@ class WEISurveyAlgorithm2021(WEISurveyAlgorithm):
free_surveys.append(least_preferred_survey)
survey.select_bus(bus)
survey.save()
+ free_surveys.remove(survey)
break
else:
raise ValueError(f"User {survey.registration.user} has no free seat")
+
+ if tqdm_obj is not None:
+ tqdm_obj.n = len(surveys) - len(free_surveys)
+ tqdm_obj.refresh()
diff --git a/apps/wei/management/commands/wei_algorithm.py b/apps/wei/management/commands/wei_algorithm.py
index 238bf13c..9e895035 100644
--- a/apps/wei/management/commands/wei_algorithm.py
+++ b/apps/wei/management/commands/wei_algorithm.py
@@ -24,7 +24,15 @@ class Command(BaseCommand):
sid = transaction.savepoint()
algorithm = CurrentSurvey.get_algorithm_class()()
- algorithm.run_algorithm()
+
+ try:
+ from tqdm import tqdm
+ del tqdm
+ display_tqdm = True
+ except ImportError:
+ display_tqdm = False
+
+ algorithm.run_algorithm(display_tqdm=display_tqdm)
output = options['output']
registrations = algorithm.get_registrations()
@@ -34,8 +42,13 @@ class Command(BaseCommand):
for bus, members in per_bus.items():
output.write(bus.name + "\n")
output.write("=" * len(bus.name) + "\n")
+ _order = -1
for r in members:
- output.write(r.user.username + "\n")
+ survey = CurrentSurvey(r)
+ for _order, (b, _score) in enumerate(survey.ordered_buses()):
+ if b == bus:
+ break
+ output.write(f"{r.user.username} ({_order + 1})\n")
output.write("\n")
if not options['doit']:
diff --git a/apps/wei/templates/wei/weiclub_detail.html b/apps/wei/templates/wei/weiclub_detail.html
index 9ffa7374..cd4b5efb 100644
--- a/apps/wei/templates/wei/weiclub_detail.html
+++ b/apps/wei/templates/wei/weiclub_detail.html
@@ -95,7 +95,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
{% endif %}
- {% if can_validate_1a or True %}
+ {% if can_validate_1a %}
{% trans "Attribute buses" %}
{% endif %}
{% endblock %}
diff --git a/apps/wei/templates/wei/weilist_sample.tex b/apps/wei/templates/wei/weilist_sample.tex
index f1b7fbd4..820df64d 100644
--- a/apps/wei/templates/wei/weilist_sample.tex
+++ b/apps/wei/templates/wei/weilist_sample.tex
@@ -2,6 +2,7 @@
\usepackage{fontspec}
\usepackage[margin=1.5cm]{geometry}
+\usepackage{longtable}
\begin{document}
\begin{center}
@@ -19,7 +20,7 @@
\begin{center}
\footnotesize
-\begin{tabular}{ccccccccc}
+\begin{longtable}{ccccccccc}
\textbf{Nom} & \textbf{Prénom} & \textbf{Date de naissance} & \textbf{Genre} & \textbf{Section}
& \textbf{Bus} & \textbf{Équipe} & \textbf{Rôles} \\
{% for membership in memberships %}
@@ -27,20 +28,20 @@
& {{ membership.registration.get_gender_display|safe }} & {{ membership.user.profile.section_generated|safe }} & {{ membership.bus.name|safe }}
& {% if membership.team %}{{ membership.team.name|safe }}{% else %}--{% endif %} & {{ membership.roles.first|safe }} \\
{% endfor %}
-\end{tabular}
+\end{longtable}
\end{center}
\footnotesize
Section = Année à l'ENS + code du département
\begin{center}
-\begin{tabular}{ccccccccc}
+\begin{longtable}{ccccccccc}
\textbf{Code} & A0 & A1 & A2 & A'2 & A''2 & A3 & B1234 & B1 \\
\textbf{Département} & Informatique & Maths & Physique & Physique appliquée & Chimie & Biologie & SAPHIRE & Mécanique \\
\hline
\textbf{Code} & B2 & B3 & B4 & C & D2 & D3 & E & EXT \\
\textbf{Département} & Génie civil & Génie mécanique & EEA & Design & Éco-gestion & Sciences sociales & Anglais & Extérieur
-\end{tabular}
+\end{longtable}
\end{center}
\end{document}
diff --git a/apps/wei/views.py b/apps/wei/views.py
index 0f385d94..80ff770e 100644
--- a/apps/wei/views.py
+++ b/apps/wei/views.py
@@ -7,6 +7,7 @@ import subprocess
from datetime import date, timedelta
from tempfile import mkdtemp
+from django.conf import settings
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.models import User
from django.core.exceptions import PermissionDenied
@@ -191,6 +192,10 @@ class WEIDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
context["not_first_year"] = WEIMembership.objects.filter(user=self.request.user).exists()
+ qs = WEIMembership.objects.filter(club=club, registration__first_year=True, bus__isnull=True)
+ context["can_validate_1a"] = PermissionBackend.check_perm(
+ self.request, "wei.change_weimembership_bus", qs.first()) if qs.exists() else False
+
return context
@@ -551,6 +556,12 @@ class WEIRegister1AView(ProtectQuerysetMixin, ProtectedCreateView):
" participated to a WEI."))
return self.form_invalid(form)
+ if 'treasury' in settings.INSTALLED_APPS:
+ from treasury.models import SogeCredit
+ form.instance.soge_credit = \
+ form.instance.soge_credit \
+ or SogeCredit.objects.filter(user=form.instance.user, credit_transaction__valid=False).exists()
+
return super().form_valid(form)
def get_success_url(self):
@@ -652,6 +663,12 @@ class WEIRegister2AView(ProtectQuerysetMixin, ProtectedCreateView):
form.instance.information = information
form.instance.save()
+ if 'treasury' in settings.INSTALLED_APPS:
+ from treasury.models import SogeCredit
+ form.instance.soge_credit = \
+ form.instance.soge_credit \
+ or SogeCredit.objects.filter(user=form.instance.user, credit_transaction__valid=False).exists()
+
return super().form_valid(form)
def get_success_url(self):
@@ -1181,7 +1198,10 @@ class WEI1AListView(LoginRequiredMixin, ProtectQuerysetMixin, SingleTableView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['club'] = self.club
- context['bus_repartition_table'] = BusRepartitionTable(Bus.objects.filter(wei=self.club, size__gt=0).all())
+ context['bus_repartition_table'] = BusRepartitionTable(
+ Bus.objects.filter(wei=self.club, size__gt=0)
+ .filter(PermissionBackend.filter_queryset(self.request, Bus, "view"))
+ .all())
return context
@@ -1218,4 +1238,4 @@ class WEIAttributeBus1ANextView(LoginRequiredMixin, RedirectView):
qs = qs.filter(information_json__contains='selected_bus_pk') # not perfect, but works...
if qs.exists():
return reverse_lazy('wei:wei_bus_1A', args=(qs.first().pk, ))
- return reverse_lazy('wei_1A_list', args=(wei.pk, ))
+ return reverse_lazy('wei:wei_1A_list', args=(wei.pk, ))
diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po
index 7d71955d..9175e2e7 100644
--- a/locale/fr/LC_MESSAGES/django.po
+++ b/locale/fr/LC_MESSAGES/django.po
@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2021-09-12 19:30+0200\n"
+"POT-Creation-Date: 2021-09-13 23:26+0200\n"
"PO-Revision-Date: 2020-11-16 20:02+0000\n"
"Last-Translator: Yohann D'ANELLO \n"
"Language-Team: French \n"
@@ -56,7 +56,7 @@ msgstr "Vous ne pouvez pas inviter plus de 3 personnes à cette activité."
#: apps/note/models/transactions.py:46 apps/note/models/transactions.py:301
#: apps/permission/models.py:330
#: apps/registration/templates/registration/future_profile_detail.html:16
-#: apps/wei/models.py:66 apps/wei/models.py:123 apps/wei/tables.py:283
+#: apps/wei/models.py:67 apps/wei/models.py:131 apps/wei/tables.py:282
#: apps/wei/templates/wei/base.html:26
#: apps/wei/templates/wei/weimembership_form.html:14
msgid "name"
@@ -91,7 +91,7 @@ msgstr "types d'activité"
#: apps/activity/models.py:68
#: apps/activity/templates/activity/includes/activity_info.html:19
#: apps/note/models/transactions.py:81 apps/permission/models.py:110
-#: apps/permission/models.py:189 apps/wei/models.py:77 apps/wei/models.py:134
+#: apps/permission/models.py:189 apps/wei/models.py:78 apps/wei/models.py:142
msgid "description"
msgstr "description"
@@ -112,7 +112,7 @@ msgstr "type"
#: apps/activity/models.py:89 apps/logs/models.py:22 apps/member/models.py:305
#: apps/note/models/notes.py:148 apps/treasury/models.py:285
-#: apps/wei/models.py:165 apps/wei/templates/wei/attribute_bus_1A.html:13
+#: apps/wei/models.py:173 apps/wei/templates/wei/attribute_bus_1A.html:13
#: apps/wei/templates/wei/survey.html:15
msgid "user"
msgstr "utilisateur"
@@ -511,7 +511,7 @@ msgstr "rôles"
msgid "fee"
msgstr "cotisation"
-#: apps/member/apps.py:14 apps/wei/tables.py:227 apps/wei/tables.py:258
+#: apps/member/apps.py:14 apps/wei/tables.py:226 apps/wei/tables.py:257
msgid "member"
msgstr "adhérent"
@@ -1913,10 +1913,10 @@ msgstr "Cet email est déjà pris."
#: apps/registration/forms.py:49
msgid ""
-"I declare that I opened a bank account in the Société générale with the BDE "
+"I declare that I opened or I will open soon a bank account in the Société générale with the BDE "
"partnership."
msgstr ""
-"Je déclare avoir ouvert un compte à la société générale avec le partenariat "
+"Je déclare avoir ouvert ou ouvrir prochainement un compte à la société générale avec le partenariat "
"du BDE."
#: apps/registration/forms.py:50
@@ -2508,8 +2508,8 @@ msgstr "Liste des crédits de la Société générale"
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:49 apps/wei/models.py:50
-#: apps/wei/models.py:61 apps/wei/models.py:172
+#: apps/wei/apps.py:10 apps/wei/models.py:50 apps/wei/models.py:51
+#: apps/wei/models.py:62 apps/wei/models.py:180
#: note_kfet/templates/base.html:103
msgid "WEI"
msgstr "WEI"
@@ -2520,8 +2520,8 @@ msgstr ""
"L'utilisateur sélectionné n'est pas validé. Merci de d'abord valider son "
"compte."
-#: apps/wei/forms/registration.py:59 apps/wei/models.py:118
-#: apps/wei/models.py:315
+#: apps/wei/forms/registration.py:59 apps/wei/models.py:126
+#: apps/wei/models.py:323
msgid "bus"
msgstr "bus"
@@ -2547,7 +2547,7 @@ msgstr ""
"bus ou électron libre)"
#: apps/wei/forms/registration.py:75 apps/wei/forms/registration.py:85
-#: apps/wei/models.py:153
+#: apps/wei/models.py:161
msgid "WEI Roles"
msgstr "Rôles au WEI"
@@ -2563,123 +2563,123 @@ msgstr "Cette équipe n'appartient pas à ce bus."
msgid "Choose a word:"
msgstr "Choisissez un mot :"
-#: apps/wei/models.py:24 apps/wei/templates/wei/base.html:36
+#: apps/wei/models.py:25 apps/wei/templates/wei/base.html:36
msgid "year"
msgstr "année"
-#: apps/wei/models.py:28 apps/wei/templates/wei/base.html:30
+#: apps/wei/models.py:29 apps/wei/templates/wei/base.html:30
msgid "date start"
msgstr "début"
-#: apps/wei/models.py:32 apps/wei/templates/wei/base.html:33
+#: apps/wei/models.py:33 apps/wei/templates/wei/base.html:33
msgid "date end"
msgstr "fin"
-#: apps/wei/models.py:70 apps/wei/tables.py:306
+#: apps/wei/models.py:71 apps/wei/tables.py:305
msgid "seat count in the bus"
msgstr "nombre de sièges dans le bus"
-#: apps/wei/models.py:82
+#: apps/wei/models.py:83
msgid "survey information"
msgstr "informations sur le questionnaire"
-#: apps/wei/models.py:83
+#: apps/wei/models.py:84
msgid "Information about the survey for new members, encoded in JSON"
msgstr ""
"Informations sur le sondage pour les nouveaux membres, encodées en JSON"
-#: apps/wei/models.py:105
+#: apps/wei/models.py:113
msgid "Bus"
msgstr "Bus"
-#: apps/wei/models.py:106 apps/wei/templates/wei/weiclub_detail.html:51
+#: apps/wei/models.py:114 apps/wei/templates/wei/weiclub_detail.html:51
msgid "Buses"
msgstr "Bus"
-#: apps/wei/models.py:127
+#: apps/wei/models.py:135
msgid "color"
msgstr "couleur"
-#: apps/wei/models.py:128
+#: apps/wei/models.py:136
msgid "The color of the T-Shirt, stored with its number equivalent"
msgstr ""
"La couleur du T-Shirt, stocké sous la forme de son équivalent numérique"
-#: apps/wei/models.py:142
+#: apps/wei/models.py:150
msgid "Bus team"
msgstr "Équipe de bus"
-#: apps/wei/models.py:143
+#: apps/wei/models.py:151
msgid "Bus teams"
msgstr "Équipes de bus"
-#: apps/wei/models.py:152
+#: apps/wei/models.py:160
msgid "WEI Role"
msgstr "Rôle au WEI"
-#: apps/wei/models.py:177
+#: apps/wei/models.py:185
msgid "Credit from Société générale"
msgstr "Crédit de la Société générale"
-#: apps/wei/models.py:182
+#: apps/wei/models.py:190
msgid "Caution check given"
msgstr "Chèque de caution donné"
-#: apps/wei/models.py:186 apps/wei/templates/wei/weimembership_form.html:64
+#: apps/wei/models.py:194 apps/wei/templates/wei/weimembership_form.html:64
msgid "birth date"
msgstr "date de naissance"
-#: apps/wei/models.py:192 apps/wei/models.py:202
+#: apps/wei/models.py:200 apps/wei/models.py:210
msgid "Male"
msgstr "Homme"
-#: apps/wei/models.py:193 apps/wei/models.py:203
+#: apps/wei/models.py:201 apps/wei/models.py:211
msgid "Female"
msgstr "Femme"
-#: apps/wei/models.py:194
+#: apps/wei/models.py:202
msgid "Non binary"
msgstr "Non-binaire"
-#: apps/wei/models.py:196 apps/wei/templates/wei/attribute_bus_1A.html:22
+#: apps/wei/models.py:204 apps/wei/templates/wei/attribute_bus_1A.html:22
#: apps/wei/templates/wei/weimembership_form.html:55
msgid "gender"
msgstr "genre"
-#: apps/wei/models.py:205 apps/wei/templates/wei/weimembership_form.html:58
+#: apps/wei/models.py:213 apps/wei/templates/wei/weimembership_form.html:58
msgid "clothing cut"
msgstr "coupe de vêtement"
-#: apps/wei/models.py:218 apps/wei/templates/wei/weimembership_form.html:61
+#: apps/wei/models.py:226 apps/wei/templates/wei/weimembership_form.html:61
msgid "clothing size"
msgstr "taille de vêtement"
-#: apps/wei/models.py:224 apps/wei/templates/wei/attribute_bus_1A.html:28
+#: apps/wei/models.py:232 apps/wei/templates/wei/attribute_bus_1A.html:28
#: apps/wei/templates/wei/weimembership_form.html:67
msgid "health issues"
msgstr "problèmes de santé"
-#: apps/wei/models.py:229 apps/wei/templates/wei/weimembership_form.html:70
+#: apps/wei/models.py:237 apps/wei/templates/wei/weimembership_form.html:70
msgid "emergency contact name"
msgstr "nom du contact en cas d'urgence"
-#: apps/wei/models.py:234 apps/wei/templates/wei/weimembership_form.html:73
+#: apps/wei/models.py:242 apps/wei/templates/wei/weimembership_form.html:73
msgid "emergency contact phone"
msgstr "téléphone du contact en cas d'urgence"
-#: apps/wei/models.py:239 apps/wei/templates/wei/weimembership_form.html:52
+#: apps/wei/models.py:247 apps/wei/templates/wei/weimembership_form.html:52
msgid "first year"
msgstr "première année"
-#: apps/wei/models.py:240
+#: apps/wei/models.py:248
msgid "Tells if the user is new in the school."
msgstr "Indique si l'utilisateur est nouveau dans l'école."
-#: apps/wei/models.py:245
+#: apps/wei/models.py:253
msgid "registration information"
msgstr "informations sur l'inscription"
-#: apps/wei/models.py:246
+#: apps/wei/models.py:254
msgid ""
"Information about the registration (buses for old members, survey for the "
"new members), encoded in JSON"
@@ -2687,27 +2687,27 @@ msgstr ""
"Informations sur l'inscription (bus pour les 2A+, questionnaire pour les "
"1A), encodées en JSON"
-#: apps/wei/models.py:304
+#: apps/wei/models.py:312
msgid "WEI User"
msgstr "Participant au WEI"
-#: apps/wei/models.py:305
+#: apps/wei/models.py:313
msgid "WEI Users"
msgstr "Participants au WEI"
-#: apps/wei/models.py:325
+#: apps/wei/models.py:333
msgid "team"
msgstr "équipe"
-#: apps/wei/models.py:335
+#: apps/wei/models.py:343
msgid "WEI registration"
msgstr "Inscription au WEI"
-#: apps/wei/models.py:339
+#: apps/wei/models.py:347
msgid "WEI membership"
msgstr "Adhésion au WEI"
-#: apps/wei/models.py:340
+#: apps/wei/models.py:348
msgid "WEI memberships"
msgstr "Adhésions au WEI"
@@ -2735,32 +2735,32 @@ msgstr "Année"
msgid "preferred bus"
msgstr "bus préféré"
-#: apps/wei/tables.py:211 apps/wei/templates/wei/bus_detail.html:32
+#: apps/wei/tables.py:210 apps/wei/templates/wei/bus_detail.html:32
#: apps/wei/templates/wei/busteam_detail.html:50
msgid "Teams"
msgstr "Équipes"
-#: apps/wei/tables.py:220 apps/wei/tables.py:261
+#: apps/wei/tables.py:219 apps/wei/tables.py:260
msgid "Members count"
msgstr "Nombre de membres"
-#: apps/wei/tables.py:227 apps/wei/tables.py:258
+#: apps/wei/tables.py:226 apps/wei/tables.py:257
msgid "members"
msgstr "adhérents"
-#: apps/wei/tables.py:288
+#: apps/wei/tables.py:287
msgid "suggested first year"
msgstr "1A suggérés"
-#: apps/wei/tables.py:294
+#: apps/wei/tables.py:293
msgid "validated first year"
msgstr "1A validés"
-#: apps/wei/tables.py:300
+#: apps/wei/tables.py:299
msgid "validated staff"
msgstr "2A+ validés"
-#: apps/wei/tables.py:311
+#: apps/wei/tables.py:310
msgid "free seats"
msgstr "sièges libres"
@@ -3116,7 +3116,7 @@ msgstr "Valider l'inscription WEI"
msgid "Attribute buses to first year members"
msgstr "Répartir les 1A dans les bus"
-#: apps/wei/views.py:1190
+#: apps/wei/views.py:1191
msgid "Attribute bus"
msgstr "Attribuer un bus"
@@ -3252,16 +3252,15 @@ msgstr ""
msgid ""
"You declared that you opened a bank account in the Société générale. The "
"bank did not validate the creation of the account to the BDE, so the "
-"registration bonus of 80 € is not credited and the membership is not paid "
-"yet. This verification procedure may last a few days. Please make sure that "
-"you go to the end of the account creation."
+"membership and the WEI are not paid yet. This verification procedure may "
+"last a few days. Please make sure that you go to the end of the account "
+"creation."
msgstr ""
"Vous avez déclaré que vous avez ouvert un compte bancaire à la société "
"générale. La banque n'a pas encore validé la création du compte auprès du "
-"BDE, le bonus d'inscription de 80 € n'a donc pas encore été créditée et "
-"l'adhésion n'est pas encore payée. Cette procédure de vérification peut "
-"durer quelques jours. Merci de vous assurer de bien aller au bout de vos "
-"démarches."
+"BDE, l'adhésion et le WEI ne sont donc pas encore payés. Cette procédure de "
+"vérification peut durer quelques jours. Merci de vous assurer de bien aller "
+"au bout de vos démarches."
#: note_kfet/templates/base.html:195
msgid "Contact us"
diff --git a/note_kfet/static/js/base.js b/note_kfet/static/js/base.js
index 1afc858c..e642d15c 100644
--- a/note_kfet/static/js/base.js
+++ b/note_kfet/static/js/base.js
@@ -96,7 +96,11 @@ function displayStyle (note) {
if (!note) { return '' }
const balance = note.balance
var css = ''
- if (balance < -5000) { css += ' text-danger bg-dark' } else if (balance < -1000) { css += ' text-danger' } else if (balance < 0) { css += ' text-warning' } else if (!note.email_confirmed) { css += ' text-white bg-primary' } else if (!note.is_active || (note.membership && note.membership.date_end < new Date().toISOString())) { css += 'text-white bg-info' }
+ if (balance < -5000) { css += ' text-danger bg-dark' }
+ else if (balance < -1000) { css += ' text-danger' }
+ else if (balance < 0) { css += ' text-warning' }
+ if (!note.email_confirmed) { css += ' bg-primary' }
+ else if (!note.is_active || (note.membership && note.membership.date_end < new Date().toISOString())) { css += ' bg-info' }
return css
}
diff --git a/note_kfet/templates/base.html b/note_kfet/templates/base.html
index 09ede8c6..3adcef2c 100644
--- a/note_kfet/templates/base.html
+++ b/note_kfet/templates/base.html
@@ -170,8 +170,8 @@ SPDX-License-Identifier: GPL-3.0-or-later
{% if user.sogecredit and not user.sogecredit.valid %}
{% blocktrans trimmed %}
- You declared that you opened a bank account in the Société générale. The bank did not validate the creation of the account to the BDE,
- so the registration bonus of 80 € is not credited and the membership is not paid yet.
+ You declared that you opened a bank account in the Société générale. The bank did not validate
+ the creation of the account to the BDE, so the membership and the WEI are not paid yet.
This verification procedure may last a few days.
Please make sure that you go to the end of the account creation.
{% endblocktrans %}
@@ -193,6 +193,8 @@ SPDX-License-Identifier: GPL-3.0-or-later
{% trans "Contact us" %} —
+ {% trans "Technical Support" %} —
{% csrf_token %}