1
0
mirror of https://gitlab.crans.org/bde/nk20 synced 2025-02-24 17:11:18 +00:00

Compare commits

..

No commits in common. "97803ac983a1c825b0086ef9d2670cafcfb7a1a3" and "7e6a14296a169cd879c375cf38df36e17c60599b" have entirely different histories.

14 changed files with 119 additions and 284 deletions

View File

@ -1,9 +1,7 @@
# Copyright (C) 2018-2021 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from django.utils import timezone
from django.utils.html import escape
from django.utils.safestring import mark_safe
from django.utils.html import format_html
from django.utils.translation import gettext_lazy as _
import django_tables2 as tables
from django_tables2 import A
@ -54,8 +52,8 @@ class GuestTable(tables.Table):
def render_entry(self, record):
if record.has_entry:
return str(_("Entered on ") + str(_("{:%Y-%m-%d %H:%M:%S}").format(record.entry.time, )))
return mark_safe('<button id="{id}" class="btn btn-danger btn-sm" onclick="remove_guest(this.id)"> '
'{delete_trans}</button>'.format(id=record.id, delete_trans=_("remove").capitalize()))
return format_html('<button id="{id}" class="btn btn-danger btn-sm" onclick="remove_guest(this.id)"> '
'{delete_trans}</button>'.format(id=record.id, delete_trans=_("remove").capitalize()))
def get_row_class(record):
@ -93,7 +91,7 @@ class EntryTable(tables.Table):
if hasattr(record, 'username'):
username = record.username
if username != value:
return mark_safe(escape(value) + " <em>aka.</em> " + escape(username))
return format_html(value + " <em>aka.</em> " + username)
return value
def render_balance(self, value):

View File

@ -10,25 +10,21 @@ SPDX-License-Identifier: GPL-2.0-or-later
{# bandeau transfert/crédit/débit/activité #}
<div class="row">
<div class="col-xl-12">
<div class="btn-group btn-block">
<div class="btn-group btn-group-toggle btn-block" data-toggle="buttons">
<label for="type_transfer" class="btn btn-sm btn-outline-primary active">
<input type="radio" name="transaction_type" id="type_transfer">
{% trans "Transfer" %}
<div class="btn-group btn-group-toggle btn-block" data-toggle="buttons">
<label for="type_transfer" class="btn btn-sm btn-outline-primary active">
<input type="radio" name="transaction_type" id="type_transfer">
{% trans "Transfer" %}
</label>
{% if "note.notespecial"|not_empty_model_list %}
<label for="type_credit" class="btn btn-sm btn-outline-primary">
<input type="radio" name="transaction_type" id="type_credit">
{% trans "Credit" %}
</label>
{% if "note.notespecial"|not_empty_model_list %}
<label for="type_credit" class="btn btn-sm btn-outline-primary">
<input type="radio" name="transaction_type" id="type_credit">
{% trans "Credit" %}
</label>
<label for="type_debit" class="btn btn-sm btn-outline-primary">
<input type="radio" name="transaction_type" id="type_debit">
{% trans "Debit" %}
</label>
{% endif %}
</div>
{# Add shortcuts for opened activites if necessary #}
<label for="type_debit" class="btn btn-sm btn-outline-primary">
<input type="radio" name="transaction_type" id="type_debit">
{% trans "Debit" %}
</label>
{% endif %}
{% for activity in activities_open %}
<a href="{% url "activity:activity_entry" pk=activity.pk %}" class="btn btn-sm btn-outline-primary">
{% trans "Entries" %} {{ activity.name }}

View File

@ -53,7 +53,7 @@ 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
activities_open = Activity.objects.filter(open=True, activity_type__manage_entries=True).filter(
activities_open = Activity.objects.filter(open=True).filter(
PermissionBackend.filter_queryset(self.request, Activity, "view")).distinct().all()
context["activities_open"] = [a for a in activities_open
if PermissionBackend.check_perm(self.request,

View File

@ -46,8 +46,7 @@ class SignUpForm(UserCreationForm):
class DeclareSogeAccountOpenedForm(forms.Form):
soge_account = forms.BooleanField(
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."),
label=_("I declare that I opened 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,

View File

@ -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,16 +305,8 @@ class SogeCredit(models.Model):
@property
def amount(self):
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
return self.credit_transaction.total if self.valid \
else sum(transaction.total for transaction in self.transactions.all())
def update_transactions(self):
"""
@ -331,15 +323,13 @@ class SogeCredit(models.Model):
if bde_qs.exists():
m = bde_qs.get()
if MembershipTransaction.objects.filter(membership=m).exists(): # non-free membership
if m.transaction not in self.transactions.all():
self.transactions.add(m.transaction)
if m.transaction not in self.transactions.all():
self.transactions.add(m.transaction)
if kfet_qs.exists():
m = kfet_qs.get()
if MembershipTransaction.objects.filter(membership=m).exists(): # non-free membership
if m.transaction not in self.transactions.all():
self.transactions.add(m.transaction)
if m.transaction not in self.transactions.all():
self.transactions.add(m.transaction)
if 'wei' in settings.INSTALLED_APPS:
from wei.models import WEIClub
@ -347,9 +337,8 @@ 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 MembershipTransaction.objects.filter(membership=m).exists(): # non-free membership
if m.transaction not in self.transactions.all():
self.transactions.add(m.transaction)
if m.transaction not in self.transactions.all():
self.transactions.add(m.transaction)
for tr in self.transactions.all():
tr.valid = False
@ -443,7 +432,6 @@ 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)

View File

@ -50,19 +50,15 @@ class WEIBusInformation:
self.bus.information = d
self.bus.save()
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]
def free_seats(self, surveys: List["WEISurvey"] = None):
size = self.bus.size
already_occupied = WEIMembership.objects.filter(bus=self.bus).count()
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 quota - valid_surveys
return size - already_occupied - valid_surveys
def has_free_seats(self, surveys=None, quotas=None):
return self.free_seats(surveys, quotas) > 0
def has_free_seats(self, surveys=None):
return self.free_seats(surveys) > 0
class WEISurveyAlgorithm:
@ -90,20 +86,14 @@ class WEISurveyAlgorithm:
"""
Queryset of all first year registrations
"""
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
return WEIRegistration.objects.filter(wei__year=cls.get_survey_class().get_year(), first_year=True)
@classmethod
def get_buses(cls) -> QuerySet:
"""
Queryset of all buses of the associated wei.
"""
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
return Bus.objects.filter(wei__year=cls.get_survey_class().get_year(), size__gt=0)
@classmethod
def get_bus_information(cls, bus):
@ -145,10 +135,7 @@ class WEISurvey:
"""
The WEI associated to this kind of survey.
"""
if not hasattr(cls, '_wei'):
cls._wei = WEIClub.objects.get(year=cls.get_year())
return cls._wei
return WEIClub.objects.get(year=cls.get_year())
@classmethod
def get_survey_information_class(cls):
@ -223,15 +210,3 @@ 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

View File

@ -1,17 +1,13 @@
# 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',
@ -139,41 +135,20 @@ 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)
# 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
return sum(bus_info.scores[getattr(self.information, 'word' + str(i))] for i in range(1, 21)) / 20
@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):
"""
@ -189,72 +164,19 @@ class WEISurveyAlgorithm2021(WEISurveyAlgorithm):
def get_bus_information_class(cls):
return WEIBusInformation2021
def run_algorithm(self, display_tqdm=False):
def run_algorithm(self):
"""
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()] # 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
surveys = [s for s in surveys if s.is_complete()]
free_surveys = [s for s in surveys if not s.information.valid] # Remaining surveys
while free_surveys: # Some students are not affected
survey = free_surveys[0]
buses = survey.ordered_buses() # Preferences of the student
for bus, current_score in buses:
if self.get_bus_information(bus).has_free_seats(surveys, quotas):
for bus, _ignored in buses:
if self.get_bus_information(bus).has_free_seats(surveys):
# Selected bus has free places. Put student in the bus
survey.select_bus(bus)
survey.save()
@ -262,6 +184,7 @@ 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
@ -283,11 +206,6 @@ 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()

View File

@ -24,15 +24,7 @@ class Command(BaseCommand):
sid = transaction.savepoint()
algorithm = CurrentSurvey.get_algorithm_class()()
try:
from tqdm import tqdm
del tqdm
display_tqdm = True
except ImportError:
display_tqdm = False
algorithm.run_algorithm(display_tqdm=display_tqdm)
algorithm.run_algorithm()
output = options['output']
registrations = algorithm.get_registrations()
@ -42,13 +34,8 @@ 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:
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(r.user.username + "\n")
output.write("\n")
if not options['doit']:

View File

@ -95,7 +95,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
</div>
{% endif %}
{% if can_validate_1a %}
{% if can_validate_1a or True %}
<a href="{% url 'wei:wei_1A_list' pk=object.pk %}" class="btn btn-block btn-info">{% trans "Attribute buses" %}</a>
{% endif %}
{% endblock %}

View File

@ -2,7 +2,6 @@
\usepackage{fontspec}
\usepackage[margin=1.5cm]{geometry}
\usepackage{longtable}
\begin{document}
\begin{center}
@ -20,7 +19,7 @@
\begin{center}
\footnotesize
\begin{longtable}{ccccccccc}
\begin{tabular}{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 %}
@ -28,20 +27,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{longtable}
\end{tabular}
\end{center}
\footnotesize
Section = Année à l'ENS + code du département
\begin{center}
\begin{longtable}{ccccccccc}
\begin{tabular}{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{longtable}
\end{tabular}
\end{center}
\end{document}

View File

@ -7,7 +7,6 @@ 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
@ -192,10 +191,6 @@ 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
@ -556,12 +551,6 @@ 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):
@ -663,12 +652,6 @@ 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):
@ -1198,10 +1181,7 @@ 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)
.filter(PermissionBackend.filter_queryset(self.request, Bus, "view"))
.all())
context['bus_repartition_table'] = BusRepartitionTable(Bus.objects.filter(wei=self.club, size__gt=0).all())
return context
@ -1238,4 +1218,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:wei_1A_list', args=(wei.pk, ))
return reverse_lazy('wei_1A_list', args=(wei.pk, ))

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-13 23:26+0200\n"
"POT-Creation-Date: 2021-09-12 19:30+0200\n"
"PO-Revision-Date: 2020-11-16 20:02+0000\n"
"Last-Translator: Yohann D'ANELLO <ynerant@crans.org>\n"
"Language-Team: French <http://translate.ynerant.fr/projects/nk20/nk20/fr/>\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:67 apps/wei/models.py:131 apps/wei/tables.py:282
#: apps/wei/models.py:66 apps/wei/models.py:123 apps/wei/tables.py:283
#: 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:78 apps/wei/models.py:142
#: apps/permission/models.py:189 apps/wei/models.py:77 apps/wei/models.py:134
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:173 apps/wei/templates/wei/attribute_bus_1A.html:13
#: apps/wei/models.py:165 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:226 apps/wei/tables.py:257
#: apps/member/apps.py:14 apps/wei/tables.py:227 apps/wei/tables.py:258
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 or I will open soon a bank account in the Société générale with the BDE "
"I declare that I opened a bank account in the Société générale with the BDE "
"partnership."
msgstr ""
"Je déclare avoir ouvert ou ouvrir prochainement un compte à la société générale avec le partenariat "
"Je déclare avoir ouvert 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:50 apps/wei/models.py:51
#: apps/wei/models.py:62 apps/wei/models.py:180
#: 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
#: 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:126
#: apps/wei/models.py:323
#: apps/wei/forms/registration.py:59 apps/wei/models.py:118
#: apps/wei/models.py:315
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:161
#: apps/wei/models.py:153
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:25 apps/wei/templates/wei/base.html:36
#: apps/wei/models.py:24 apps/wei/templates/wei/base.html:36
msgid "year"
msgstr "année"
#: apps/wei/models.py:29 apps/wei/templates/wei/base.html:30
#: apps/wei/models.py:28 apps/wei/templates/wei/base.html:30
msgid "date start"
msgstr "début"
#: apps/wei/models.py:33 apps/wei/templates/wei/base.html:33
#: apps/wei/models.py:32 apps/wei/templates/wei/base.html:33
msgid "date end"
msgstr "fin"
#: apps/wei/models.py:71 apps/wei/tables.py:305
#: apps/wei/models.py:70 apps/wei/tables.py:306
msgid "seat count in the bus"
msgstr "nombre de sièges dans le bus"
#: apps/wei/models.py:83
#: apps/wei/models.py:82
msgid "survey information"
msgstr "informations sur le questionnaire"
#: apps/wei/models.py:84
#: apps/wei/models.py:83
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:113
#: apps/wei/models.py:105
msgid "Bus"
msgstr "Bus"
#: apps/wei/models.py:114 apps/wei/templates/wei/weiclub_detail.html:51
#: apps/wei/models.py:106 apps/wei/templates/wei/weiclub_detail.html:51
msgid "Buses"
msgstr "Bus"
#: apps/wei/models.py:135
#: apps/wei/models.py:127
msgid "color"
msgstr "couleur"
#: apps/wei/models.py:136
#: apps/wei/models.py:128
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:150
#: apps/wei/models.py:142
msgid "Bus team"
msgstr "Équipe de bus"
#: apps/wei/models.py:151
#: apps/wei/models.py:143
msgid "Bus teams"
msgstr "Équipes de bus"
#: apps/wei/models.py:160
#: apps/wei/models.py:152
msgid "WEI Role"
msgstr "Rôle au WEI"
#: apps/wei/models.py:185
#: apps/wei/models.py:177
msgid "Credit from Société générale"
msgstr "Crédit de la Société générale"
#: apps/wei/models.py:190
#: apps/wei/models.py:182
msgid "Caution check given"
msgstr "Chèque de caution donné"
#: apps/wei/models.py:194 apps/wei/templates/wei/weimembership_form.html:64
#: apps/wei/models.py:186 apps/wei/templates/wei/weimembership_form.html:64
msgid "birth date"
msgstr "date de naissance"
#: apps/wei/models.py:200 apps/wei/models.py:210
#: apps/wei/models.py:192 apps/wei/models.py:202
msgid "Male"
msgstr "Homme"
#: apps/wei/models.py:201 apps/wei/models.py:211
#: apps/wei/models.py:193 apps/wei/models.py:203
msgid "Female"
msgstr "Femme"
#: apps/wei/models.py:202
#: apps/wei/models.py:194
msgid "Non binary"
msgstr "Non-binaire"
#: apps/wei/models.py:204 apps/wei/templates/wei/attribute_bus_1A.html:22
#: apps/wei/models.py:196 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:213 apps/wei/templates/wei/weimembership_form.html:58
#: apps/wei/models.py:205 apps/wei/templates/wei/weimembership_form.html:58
msgid "clothing cut"
msgstr "coupe de vêtement"
#: apps/wei/models.py:226 apps/wei/templates/wei/weimembership_form.html:61
#: apps/wei/models.py:218 apps/wei/templates/wei/weimembership_form.html:61
msgid "clothing size"
msgstr "taille de vêtement"
#: apps/wei/models.py:232 apps/wei/templates/wei/attribute_bus_1A.html:28
#: apps/wei/models.py:224 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:237 apps/wei/templates/wei/weimembership_form.html:70
#: apps/wei/models.py:229 apps/wei/templates/wei/weimembership_form.html:70
msgid "emergency contact name"
msgstr "nom du contact en cas d'urgence"
#: apps/wei/models.py:242 apps/wei/templates/wei/weimembership_form.html:73
#: apps/wei/models.py:234 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:247 apps/wei/templates/wei/weimembership_form.html:52
#: apps/wei/models.py:239 apps/wei/templates/wei/weimembership_form.html:52
msgid "first year"
msgstr "première année"
#: apps/wei/models.py:248
#: apps/wei/models.py:240
msgid "Tells if the user is new in the school."
msgstr "Indique si l'utilisateur est nouveau dans l'école."
#: apps/wei/models.py:253
#: apps/wei/models.py:245
msgid "registration information"
msgstr "informations sur l'inscription"
#: apps/wei/models.py:254
#: apps/wei/models.py:246
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:312
#: apps/wei/models.py:304
msgid "WEI User"
msgstr "Participant au WEI"
#: apps/wei/models.py:313
#: apps/wei/models.py:305
msgid "WEI Users"
msgstr "Participants au WEI"
#: apps/wei/models.py:333
#: apps/wei/models.py:325
msgid "team"
msgstr "équipe"
#: apps/wei/models.py:343
#: apps/wei/models.py:335
msgid "WEI registration"
msgstr "Inscription au WEI"
#: apps/wei/models.py:347
#: apps/wei/models.py:339
msgid "WEI membership"
msgstr "Adhésion au WEI"
#: apps/wei/models.py:348
#: apps/wei/models.py:340
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:210 apps/wei/templates/wei/bus_detail.html:32
#: apps/wei/tables.py:211 apps/wei/templates/wei/bus_detail.html:32
#: apps/wei/templates/wei/busteam_detail.html:50
msgid "Teams"
msgstr "Équipes"
#: apps/wei/tables.py:219 apps/wei/tables.py:260
#: apps/wei/tables.py:220 apps/wei/tables.py:261
msgid "Members count"
msgstr "Nombre de membres"
#: apps/wei/tables.py:226 apps/wei/tables.py:257
#: apps/wei/tables.py:227 apps/wei/tables.py:258
msgid "members"
msgstr "adhérents"
#: apps/wei/tables.py:287
#: apps/wei/tables.py:288
msgid "suggested first year"
msgstr "1A suggérés"
#: apps/wei/tables.py:293
#: apps/wei/tables.py:294
msgid "validated first year"
msgstr "1A validés"
#: apps/wei/tables.py:299
#: apps/wei/tables.py:300
msgid "validated staff"
msgstr "2A+ validés"
#: apps/wei/tables.py:310
#: apps/wei/tables.py:311
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:1191
#: apps/wei/views.py:1190
msgid "Attribute bus"
msgstr "Attribuer un bus"
@ -3252,15 +3252,16 @@ 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 "
"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."
"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."
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, 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."
"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."
#: note_kfet/templates/base.html:195
msgid "Contact us"

View File

@ -96,11 +96,7 @@ 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' }
if (!note.email_confirmed) { css += ' bg-primary' }
else if (!note.is_active || (note.membership && note.membership.date_end < new Date().toISOString())) { css += ' bg-info' }
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' }
return css
}

View File

@ -170,8 +170,8 @@ SPDX-License-Identifier: GPL-3.0-or-later
{% if user.sogecredit and not user.sogecredit.valid %}
<div class="alert alert-info">
{% 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 membership and the WEI are 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 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.
{% endblocktrans %}
@ -193,8 +193,6 @@ SPDX-License-Identifier: GPL-3.0-or-later
<span class="text-muted mr-1">
<a href="mailto:{{ "CONTACT_EMAIL" | getenv }}"
class="text-muted">{% trans "Contact us" %}</a> &mdash;
<a href="mailto:{{ "SUPPORT_EMAIL" | getenv }}"
class="text-muted">{% trans "Technical Support" %}</a> &mdash;
</span>
{% csrf_token %}
<select title="language" name="language"