diff --git a/apps/member/models.py b/apps/member/models.py
index 73b7c668..9bb4ecf0 100644
--- a/apps/member/models.py
+++ b/apps/member/models.py
@@ -74,7 +74,7 @@ class Profile(models.Model):
promotion = models.PositiveSmallIntegerField(
null=True,
- default=datetime.date.today().year,
+ default=datetime.date.today().year if datetime.date.today().month >= 8 else datetime.date.today().year - 1,
verbose_name=_("promotion"),
help_text=_("Year of entry to the school (None if not ENS student)"),
)
diff --git a/apps/wei/forms/__init__.py b/apps/wei/forms/__init__.py
index ecec33d5..10765752 100644
--- a/apps/wei/forms/__init__.py
+++ b/apps/wei/forms/__init__.py
@@ -1,10 +1,10 @@
# Copyright (C) 2018-2021 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
-from .registration import WEIForm, WEIRegistrationForm, WEIMembershipForm, BusForm, BusTeamForm
+from .registration import WEIForm, WEIRegistrationForm, WEIMembership1AForm, WEIMembershipForm, BusForm, BusTeamForm
from .surveys import WEISurvey, WEISurveyInformation, WEISurveyAlgorithm, CurrentSurvey
__all__ = [
- 'WEIForm', 'WEIRegistrationForm', 'WEIMembershipForm', 'BusForm', 'BusTeamForm',
+ 'WEIForm', 'WEIRegistrationForm', 'WEIMembership1AForm', 'WEIMembershipForm', 'BusForm', 'BusTeamForm',
'WEISurvey', 'WEISurveyInformation', 'WEISurveyAlgorithm', 'CurrentSurvey',
]
diff --git a/apps/wei/forms/registration.py b/apps/wei/forms/registration.py
index 474d83ee..e934fb50 100644
--- a/apps/wei/forms/registration.py
+++ b/apps/wei/forms/registration.py
@@ -48,8 +48,7 @@ class WEIRegistrationForm(forms.ModelForm):
'placeholder': 'Nom ...',
},
),
- "birth_date": DatePickerInput(options={'defaultDate': '2000-01-01',
- 'minDate': '1900-01-01',
+ "birth_date": DatePickerInput(options={'minDate': '1900-01-01',
'maxDate': '2100-01-01'}),
}
@@ -118,7 +117,8 @@ class WEIMembershipForm(forms.ModelForm):
def clean(self):
cleaned_data = super().clean()
- if cleaned_data["team"] is not None and cleaned_data["team"].bus != cleaned_data["bus"]:
+ if 'team' in cleaned_data and cleaned_data["team"] is not None \
+ and cleaned_data["team"].bus != cleaned_data["bus"]:
self.add_error('bus', _("This team doesn't belong to the given bus."))
return cleaned_data
@@ -144,6 +144,20 @@ class WEIMembershipForm(forms.ModelForm):
}
+class WEIMembership1AForm(WEIMembershipForm):
+ """
+ Used to confirm registrations of first year members without choosing a bus now.
+ """
+ roles = None
+
+ def clean(self):
+ return super(forms.ModelForm, self).clean()
+
+ class Meta:
+ model = WEIMembership
+ fields = ('credit_type', 'credit_amount', 'last_name', 'first_name', 'bank',)
+
+
class BusForm(forms.ModelForm):
class Meta:
model = Bus
diff --git a/apps/wei/models.py b/apps/wei/models.py
index 7ab56f57..6b7272b4 100644
--- a/apps/wei/models.py
+++ b/apps/wei/models.py
@@ -7,6 +7,7 @@ from datetime import date
from django.conf import settings
from django.contrib.auth.models import User
from django.db import models
+from django.db.models import Q
from django.utils.translation import gettext_lazy as _
from phonenumber_field.modelfields import PhoneNumberField
from member.models import Club, Membership
@@ -98,6 +99,13 @@ class Bus(models.Model):
"""
self.information_json = json.dumps(information, indent=2)
+ @property
+ def suggested_first_year(self):
+ registrations = WEIRegistration.objects.filter(Q(membership__isnull=True) | Q(membership__bus__isnull=True),
+ first_year=True, wei=self.wei)
+ registrations = [r for r in registrations if 'selected_bus_pk' in r.information]
+ return sum(1 for r in registrations if r.information['selected_bus_pk'] == self.pk)
+
def __str__(self):
return self.name
diff --git a/apps/wei/tables.py b/apps/wei/tables.py
index 0f862cc9..687f8f07 100644
--- a/apps/wei/tables.py
+++ b/apps/wei/tables.py
@@ -4,6 +4,7 @@
from datetime import date
import django_tables2 as tables
+from django.db.models import Q
from django.urls import reverse_lazy
from django.utils.html import format_html
from django.utils.translation import gettext_lazy as _
@@ -102,9 +103,9 @@ class WEIRegistrationTable(tables.Table):
if record.fee > record.user.note.balance and not record.soge_credit:
btn_class = 'btn-secondary'
tooltip = _("The user does not have enough money.")
- elif record.first_year and 'selected_bus_pk' not in record.information:
+ elif record.first_year:
btn_class = 'btn-info'
- tooltip = _("The user is in first year, and the repartition algorithm didn't run.")
+ tooltip = _("The user is in first year. You may validate the credit, the algorithm will run later.")
else:
btn_class = 'btn-success'
tooltip = _("The user has enough money, you can validate the registration.")
@@ -169,6 +170,35 @@ class WEIMembershipTable(tables.Table):
}
+class WEIRegistration1ATable(tables.Table):
+ user = tables.LinkColumn(
+ 'wei:wei_bus_1A',
+ args=[A('pk')],
+ )
+
+ preferred_bus = tables.Column(
+ verbose_name=_('preferred bus').capitalize,
+ accessor='pk',
+ orderable=False,
+ )
+
+ def render_preferred_bus(self, record):
+ information = record.information
+ return information['selected_bus_name'] if 'selected_bus_name' in information else "—"
+
+ class Meta:
+ attrs = {
+ 'class': 'table table-condensed table-striped table-hover'
+ }
+ model = WEIRegistration
+ template_name = 'django_tables2/bootstrap4.html'
+ fields = ('user', 'user__last_name', 'user__first_name', 'gender',
+ 'user__profile__department', 'preferred_bus', 'membership__bus', )
+ row_attrs = {
+ 'class': lambda record: '' if 'selected_bus_pk' in record.information else 'bg-danger',
+ }
+
+
class BusTable(tables.Table):
name = tables.LinkColumn(
'wei:manage_bus',
@@ -245,3 +275,66 @@ class BusTeamTable(tables.Table):
'id': lambda record: "row-" + str(record.pk),
'data-href': lambda record: reverse_lazy('wei:manage_bus_team', args=(record.pk, ))
}
+
+
+class BusRepartitionTable(tables.Table):
+ name = tables.Column(
+ verbose_name=_("name").capitalize,
+ accessor='name',
+ )
+
+ suggested_first_year = tables.Column(
+ verbose_name=_("suggested first year").capitalize,
+ accessor='pk',
+ orderable=False,
+ )
+
+ validated_first_year = tables.Column(
+ verbose_name=_("validated first year").capitalize,
+ accessor='pk',
+ orderable=False,
+ )
+
+ validated_staff = tables.Column(
+ verbose_name=_("validated staff").capitalize,
+ accessor='pk',
+ orderable=False,
+ )
+
+ size = tables.Column(
+ verbose_name=_("seat count in the bus").capitalize,
+ accessor='size',
+ )
+
+ free_seats = tables.Column(
+ verbose_name=_("free seats").capitalize,
+ accessor='pk',
+ orderable=False,
+ )
+
+ def render_suggested_first_year(self, record):
+ registrations = WEIRegistration.objects.filter(Q(membership__isnull=True) | Q(membership__bus__isnull=True),
+ first_year=True, wei=record.wei)
+ registrations = [r for r in registrations if 'selected_bus_pk' in r.information]
+ return sum(1 for r in registrations if r.information['selected_bus_pk'] == record.pk)
+
+ def render_validated_first_year(self, record):
+ return WEIRegistration.objects.filter(first_year=True, membership__bus=record).count()
+
+ def render_validated_staff(self, record):
+ return WEIRegistration.objects.filter(first_year=False, membership__bus=record).count()
+
+ def render_free_seats(self, record):
+ return record.size - self.render_validated_staff(record) - self.render_validated_first_year(record)
+
+ class Meta:
+ attrs = {
+ 'class': 'table table-condensed table-striped table-hover'
+ }
+ models = Bus
+ template_name = 'django_tables2/bootstrap4.html'
+ fields = ('name', )
+ row_attrs = {
+ 'class': 'table-row',
+ 'id': lambda record: "row-" + str(record.pk),
+ }
diff --git a/apps/wei/templates/wei/1A_list.html b/apps/wei/templates/wei/1A_list.html
new file mode 100644
index 00000000..d9b82937
--- /dev/null
+++ b/apps/wei/templates/wei/1A_list.html
@@ -0,0 +1,20 @@
+{% extends "wei/base.html" %}
+
+{% load i18n %}
+{% load render_table from django_tables2 %}
+
+{% block profile_content %}
+
+{% endblock %}
diff --git a/apps/wei/templates/wei/attribute_bus_1A.html b/apps/wei/templates/wei/attribute_bus_1A.html
new file mode 100644
index 00000000..3305981b
--- /dev/null
+++ b/apps/wei/templates/wei/attribute_bus_1A.html
@@ -0,0 +1,88 @@
+{% extends "wei/base.html" %}
+
+{% load i18n %}
+
+{% block profile_content %}
+
+
+
+
+
+ - {% trans 'user'|capfirst %}
+ - {{ object.user }}
+
+ - {% trans 'last name'|capfirst %}
+ - {{ object.user.last_name }}
+
+ - {% trans 'first name'|capfirst %}
+ - {{ object.user.first_name }}
+
+ - {% trans 'gender'|capfirst %}
+ - {{ object.get_gender_display }}
+
+ - {% trans 'department'|capfirst %}
+ - {{ object.user.profile.get_department_display }}
+
+ - {% trans 'health issues'|capfirst %}
+ - {{ object.health_issues|default:"—" }}
+
+ - {% trans 'suggested bus'|capfirst %}
+ - {{ survey.information.selected_bus_name }}
+
+
+
+
+
+
+ {% for key, value in survey.registration.information.items %}
+ - {{ key }}
+ - {{ value }}
+ {% endfor %}
+
+
+
+
+
+
+ {% for bus, score in survey.ordered_buses %}
+
+ {% endfor %}
+
+
{% trans "Back to main list" %}
+
+
+{% endblock %}
+
+{% block extrajavascript %}
+
+{% endblock %}
diff --git a/apps/wei/templates/wei/weiclub_detail.html b/apps/wei/templates/wei/weiclub_detail.html
index 40786add..9ffa7374 100644
--- a/apps/wei/templates/wei/weiclub_detail.html
+++ b/apps/wei/templates/wei/weiclub_detail.html
@@ -94,6 +94,10 @@ SPDX-License-Identifier: GPL-3.0-or-later
{% endif %}
+
+ {% if can_validate_1a or True %}
+ {% trans "Attribute buses" %}
+ {% endif %}
{% endblock %}
{% block extrajavascript %}
diff --git a/apps/wei/templates/wei/weimembership_form.html b/apps/wei/templates/wei/weimembership_form.html
index 1225175d..7d1059b7 100644
--- a/apps/wei/templates/wei/weimembership_form.html
+++ b/apps/wei/templates/wei/weimembership_form.html
@@ -53,7 +53,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
{{ registration.first_year|yesno }}
{% trans 'gender'|capfirst %}
- {{ registration.gender }}
+ {{ registration.get_gender_display }}
{% trans 'clothing cut'|capfirst %}
{{ registration.clothing_cut }}
diff --git a/apps/wei/urls.py b/apps/wei/urls.py
index a7e8ca99..fb497216 100644
--- a/apps/wei/urls.py
+++ b/apps/wei/urls.py
@@ -3,12 +3,11 @@
from django.urls import path
-from .views import CurrentWEIDetailView, WEIListView, WEICreateView, WEIDetailView, WEIUpdateView,\
- WEIRegistrationsView, WEIMembershipsView, MemberListRenderView,\
- BusCreateView, BusManageView, BusUpdateView, BusTeamCreateView, BusTeamManageView, BusTeamUpdateView,\
- WEIRegister1AView, WEIRegister2AView, WEIUpdateRegistrationView, WEIDeleteRegistrationView,\
- WEIValidateRegistrationView, WEISurveyView, WEISurveyEndView, WEIClosedView
-
+from .views import CurrentWEIDetailView, WEI1AListView, WEIListView, WEICreateView, WEIDetailView, WEIUpdateView, \
+ WEIRegistrationsView, WEIMembershipsView, MemberListRenderView, \
+ BusCreateView, BusManageView, BusUpdateView, BusTeamCreateView, BusTeamManageView, BusTeamUpdateView, \
+ WEIAttributeBus1AView, WEIAttributeBus1ANextView, WEIRegister1AView, WEIRegister2AView, WEIUpdateRegistrationView, \
+ WEIDeleteRegistrationView, WEIValidateRegistrationView, WEISurveyView, WEISurveyEndView, WEIClosedView
app_name = 'wei'
urlpatterns = [
@@ -24,6 +23,7 @@ urlpatterns = [
name="wei_memberships_bus_pdf"),
path('detail//memberships/pdf///', MemberListRenderView.as_view(),
name="wei_memberships_team_pdf"),
+ path('bus-1A/list//', WEI1AListView.as_view(), name="wei_1A_list"),
path('add-bus//', BusCreateView.as_view(), name="add_bus"),
path('manage-bus//', BusManageView.as_view(), name="manage_bus"),
path('update-bus//', BusUpdateView.as_view(), name="update_bus"),
@@ -40,4 +40,6 @@ urlpatterns = [
path('survey//', WEISurveyView.as_view(), name="wei_survey"),
path('survey//end/', WEISurveyEndView.as_view(), name="wei_survey_end"),
path('detail//closed/', WEIClosedView.as_view(), name="wei_closed"),
+ path('bus-1A//', WEIAttributeBus1AView.as_view(), name="wei_bus_1A"),
+ path('bus-1A/next//', WEIAttributeBus1ANextView.as_view(), name="wei_bus_1A_next"),
]
diff --git a/apps/wei/views.py b/apps/wei/views.py
index 348ac751..0f385d94 100644
--- a/apps/wei/views.py
+++ b/apps/wei/views.py
@@ -13,8 +13,7 @@ from django.core.exceptions import PermissionDenied
from django.db import transaction
from django.db.models import Q, Count
from django.db.models.functions.text import Lower
-from django.forms import HiddenInput
-from django.http import HttpResponse
+from django.http import HttpResponse, Http404
from django.shortcuts import redirect
from django.template.loader import render_to_string
from django.urls import reverse_lazy
@@ -32,8 +31,10 @@ from permission.views import ProtectQuerysetMixin, ProtectedCreateView
from .forms.registration import WEIChooseBusForm
from .models import WEIClub, WEIRegistration, WEIMembership, Bus, BusTeam, WEIRole
-from .forms import WEIForm, WEIRegistrationForm, BusForm, BusTeamForm, WEIMembershipForm, CurrentSurvey
-from .tables import WEITable, WEIRegistrationTable, BusTable, BusTeamTable, WEIMembershipTable
+from .forms import WEIForm, WEIRegistrationForm, BusForm, BusTeamForm, WEIMembership1AForm, \
+ WEIMembershipForm, CurrentSurvey
+from .tables import BusRepartitionTable, BusTable, BusTeamTable, WEITable, WEIRegistrationTable, \
+ WEIRegistration1ATable, WEIMembershipTable
class CurrentWEIDetailView(LoginRequiredMixin, RedirectView):
@@ -511,7 +512,8 @@ class WEIRegister1AView(ProtectQuerysetMixin, ProtectedCreateView):
if today >= wei.date_start or today < wei.membership_start:
return redirect(reverse_lazy('wei:wei_closed', args=(wei.pk,)))
# Don't register twice
- if 'myself' in self.request.path and WEIRegistration.objects.filter(wei=wei, user=self.request.user).exists():
+ if 'myself' in self.request.path and not self.request.user.is_anonymous \
+ and WEIRegistration.objects.filter(wei=wei, user=self.request.user).exists():
obj = WEIRegistration.objects.get(wei=wei, user=self.request.user)
return redirect(reverse_lazy('wei:wei_update_registration', args=(obj.pk,)))
return super().dispatch(request, *args, **kwargs)
@@ -590,7 +592,8 @@ class WEIRegister2AView(ProtectQuerysetMixin, ProtectedCreateView):
if today >= wei.date_start or today < wei.membership_start:
return redirect(reverse_lazy('wei:wei_closed', args=(wei.pk,)))
# Don't register twice
- if 'myself' in self.request.path and WEIRegistration.objects.filter(wei=wei, user=self.request.user).exists():
+ if 'myself' in self.request.path and not self.request.user.is_anonymous \
+ and WEIRegistration.objects.filter(wei=wei, user=self.request.user).exists():
obj = WEIRegistration.objects.get(wei=wei, user=self.request.user)
return redirect(reverse_lazy('wei:wei_update_registration', args=(obj.pk,)))
return super().dispatch(request, *args, **kwargs)
@@ -677,17 +680,8 @@ class WEIUpdateRegistrationView(ProtectQuerysetMixin, LoginRequiredMixin, Update
context["club"] = self.object.wei
if self.object.is_validated:
- membership_form = WEIMembershipForm(instance=self.object.membership,
- data=self.request.POST if self.request.POST else None)
- for field_name, field in membership_form.fields.items():
- if not PermissionBackend.check_perm(
- self.request, "wei.change_membership_" + field_name, self.object.membership):
- field.widget = HiddenInput()
- del membership_form.fields["credit_type"]
- del membership_form.fields["credit_amount"]
- del membership_form.fields["first_name"]
- del membership_form.fields["last_name"]
- del membership_form.fields["bank"]
+ membership_form = self.get_membership_form(instance=self.object.membership,
+ data=self.request.POST)
context["membership_form"] = membership_form
elif not self.object.first_year and PermissionBackend.check_perm(
self.request, "wei.change_weiregistration_information_json", self.object):
@@ -719,11 +713,24 @@ class WEIUpdateRegistrationView(ProtectQuerysetMixin, LoginRequiredMixin, Update
del form.fields["information_json"]
return form
+ def get_membership_form(self, data=None, instance=None):
+ membership_form = WEIMembershipForm(data if data else None, instance=instance)
+ del membership_form.fields["credit_type"]
+ del membership_form.fields["credit_amount"]
+ del membership_form.fields["first_name"]
+ del membership_form.fields["last_name"]
+ del membership_form.fields["bank"]
+ for field_name, _field in list(membership_form.fields.items()):
+ if not PermissionBackend.check_perm(
+ self.request, "wei.change_weimembership_" + field_name, self.object.membership):
+ del membership_form.fields[field_name]
+ return membership_form
+
@transaction.atomic
def form_valid(self, form):
# If the membership is already validated, then we update the bus and the team (and the roles)
if form.instance.is_validated:
- membership_form = WEIMembershipForm(self.request.POST, instance=form.instance.membership)
+ membership_form = self.get_membership_form(self.request.POST, form.instance.membership)
if not membership_form.is_valid():
return self.form_invalid(form)
membership_form.save()
@@ -797,7 +804,6 @@ class WEIValidateRegistrationView(ProtectQuerysetMixin, ProtectedCreateView):
Validate WEI Registration
"""
model = WEIMembership
- form_class = WEIMembershipForm
extra_context = {"title": _("Validate WEI registration")}
def get_sample_object(self):
@@ -853,6 +859,12 @@ class WEIValidateRegistrationView(ProtectQuerysetMixin, ProtectedCreateView):
return context
+ def get_form_class(self):
+ registration = WEIRegistration.objects.get(pk=self.kwargs["pk"])
+ if registration.first_year and 'sleected_bus_pk' not in registration.information:
+ return WEIMembership1AForm
+ return WEIMembershipForm
+
def get_form(self, form_class=None):
form = super().get_form(form_class)
registration = WEIRegistration.objects.get(pk=self.kwargs["pk"])
@@ -868,25 +880,27 @@ class WEIValidateRegistrationView(ProtectQuerysetMixin, ProtectedCreateView):
form.fields["bank"].disabled = True
form.fields["bank"].initial = "Société générale"
- form.fields["bus"].widget.attrs["api_url"] = "/api/wei/bus/?wei=" + str(registration.wei.pk)
- if registration.first_year:
- # Use the results of the survey to fill initial data
- # A first year has no other role than "1A"
- del form.fields["roles"]
- survey = CurrentSurvey(registration)
- if survey.information.valid:
- form.fields["bus"].initial = survey.information.get_selected_bus()
- else:
- # Use the choice of the member to fill initial data
- information = registration.information
- if "preferred_bus_pk" in information and len(information["preferred_bus_pk"]) == 1:
- form["bus"].initial = Bus.objects.get(pk=information["preferred_bus_pk"][0])
- if "preferred_team_pk" in information and len(information["preferred_team_pk"]) == 1:
- form["team"].initial = BusTeam.objects.get(pk=information["preferred_team_pk"][0])
- if "preferred_roles_pk" in information:
- form["roles"].initial = WEIRole.objects.filter(
- Q(pk__in=information["preferred_roles_pk"]) | Q(name="Adhérent WEI")
- ).all()
+ if 'bus' in form.fields:
+ # For 2A+ and hardcoded 1A
+ form.fields["bus"].widget.attrs["api_url"] = "/api/wei/bus/?wei=" + str(registration.wei.pk)
+ if registration.first_year:
+ # Use the results of the survey to fill initial data
+ # A first year has no other role than "1A"
+ del form.fields["roles"]
+ survey = CurrentSurvey(registration)
+ if survey.information.valid:
+ form.fields["bus"].initial = survey.information.get_selected_bus()
+ else:
+ # Use the choice of the member to fill initial data
+ information = registration.information
+ if "preferred_bus_pk" in information and len(information["preferred_bus_pk"]) == 1:
+ form["bus"].initial = Bus.objects.get(pk=information["preferred_bus_pk"][0])
+ if "preferred_team_pk" in information and len(information["preferred_team_pk"]) == 1:
+ form["team"].initial = BusTeam.objects.get(pk=information["preferred_team_pk"][0])
+ if "preferred_roles_pk" in information:
+ form["roles"].initial = WEIRole.objects.filter(
+ Q(pk__in=information["preferred_roles_pk"]) | Q(name="Adhérent WEI")
+ ).all()
return form
@transaction.atomic
@@ -1146,3 +1160,62 @@ class MemberListRenderView(LoginRequiredMixin, View):
shutil.rmtree(tmp_dir)
return response
+
+
+class WEI1AListView(LoginRequiredMixin, ProtectQuerysetMixin, SingleTableView):
+ model = WEIRegistration
+ template_name = "wei/1A_list.html"
+ table_class = WEIRegistration1ATable
+ extra_context = {"title": _("Attribute buses to first year members")}
+
+ def dispatch(self, request, *args, **kwargs):
+ self.club = WEIClub.objects.get(pk=self.kwargs["pk"])
+ return super().dispatch(request, *args, **kwargs)
+
+ def get_queryset(self, filter_permissions=True, **kwargs):
+ qs = super().get_queryset(filter_permissions, **kwargs)
+ qs = qs.filter(first_year=True, membership__isnull=False)
+ qs = qs.order_by('-membership__bus')
+ return qs
+
+ 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())
+ return context
+
+
+class WEIAttributeBus1AView(ProtectQuerysetMixin, DetailView):
+ model = WEIRegistration
+ template_name = "wei/attribute_bus_1A.html"
+ extra_context = {"title": _("Attribute bus")}
+
+ def get_queryset(self, filter_permissions=True, **kwargs):
+ qs = super().get_queryset(filter_permissions, **kwargs)
+ qs = qs.filter(first_year=True)
+ return qs
+
+ def dispatch(self, request, *args, **kwargs):
+ obj = self.get_object()
+ if 'selected_bus_pk' not in obj.information:
+ return redirect(reverse_lazy('wei:wei_survey', args=(obj.pk,)))
+ return super().dispatch(request, *args, **kwargs)
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ context['club'] = self.object.wei
+ context['survey'] = CurrentSurvey(self.object)
+ return context
+
+
+class WEIAttributeBus1ANextView(LoginRequiredMixin, RedirectView):
+ def get_redirect_url(self, *args, **kwargs):
+ wei = WEIClub.objects.filter(pk=self.kwargs['pk'])
+ if not wei.exists():
+ raise Http404
+ wei = wei.get()
+ qs = WEIRegistration.objects.filter(wei=wei, membership__isnull=False, membership__bus__isnull=True)
+ 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, ))
diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po
index 6416a03a..7d71955d 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-08 18:46+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 \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/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"
@@ -111,8 +111,9 @@ msgid "type"
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:286
-#: apps/wei/models.py:165 apps/wei/templates/wei/survey.html:15
+#: 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/templates/wei/survey.html:15
msgid "user"
msgstr "utilisateur"
@@ -204,6 +205,7 @@ msgstr "La note est en négatif."
#: apps/activity/models.py:240
#: apps/treasury/templates/treasury/sogecredit_detail.html:14
+#: apps/wei/templates/wei/attribute_bus_1A.html:16
msgid "last name"
msgstr "nom de famille"
@@ -211,6 +213,7 @@ msgstr "nom de famille"
#: apps/member/templates/member/includes/profile_info.html:4
#: apps/registration/templates/registration/future_profile_detail.html:16
#: apps/treasury/templates/treasury/sogecredit_detail.html:17
+#: apps/wei/templates/wei/attribute_bus_1A.html:19
#: apps/wei/templates/wei/weimembership_form.html:14
msgid "first name"
msgstr "prénom"
@@ -251,20 +254,20 @@ msgstr "Entré le "
msgid "remove"
msgstr "supprimer"
-#: apps/activity/tables.py:80 apps/note/forms.py:68 apps/treasury/models.py:200
+#: apps/activity/tables.py:80 apps/note/forms.py:68 apps/treasury/models.py:199
msgid "Type"
msgstr "Type"
#: apps/activity/tables.py:82 apps/member/forms.py:186
#: apps/registration/forms.py:90 apps/treasury/forms.py:131
-#: apps/wei/forms/registration.py:105
+#: apps/wei/forms/registration.py:104
msgid "Last name"
msgstr "Nom de famille"
#: apps/activity/tables.py:84 apps/member/forms.py:191
#: apps/note/templates/note/transaction_form.html:134
#: apps/registration/forms.py:95 apps/treasury/forms.py:133
-#: apps/wei/forms/registration.py:110
+#: apps/wei/forms/registration.py:109
msgid "First name"
msgstr "Prénom"
@@ -461,7 +464,7 @@ msgstr "créer"
#: apps/logs/models.py:65 apps/note/tables.py:165 apps/note/tables.py:201
#: apps/permission/models.py:127 apps/treasury/tables.py:38
-#: apps/wei/tables.py:73
+#: apps/wei/tables.py:74
msgid "delete"
msgstr "supprimer"
@@ -508,7 +511,7 @@ msgstr "rôles"
msgid "fee"
msgstr "cotisation"
-#: apps/member/apps.py:14 apps/wei/tables.py:196 apps/wei/tables.py:227
+#: apps/member/apps.py:14 apps/wei/tables.py:227 apps/wei/tables.py:258
msgid "member"
msgstr "adhérent"
@@ -554,12 +557,12 @@ msgid "Check this case if 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:172 apps/registration/forms.py:77
-#: apps/wei/forms/registration.py:92
+#: apps/wei/forms/registration.py:91
msgid "Credit type"
msgstr "Type de rechargement"
#: apps/member/forms.py:173 apps/registration/forms.py:78
-#: apps/wei/forms/registration.py:93
+#: apps/wei/forms/registration.py:92
msgid "No credit"
msgstr "Pas de rechargement"
@@ -568,13 +571,13 @@ msgid "You can credit the note of the user."
msgstr "Vous pouvez créditer la note de l'utilisateur avant l'adhésion."
#: apps/member/forms.py:179 apps/registration/forms.py:83
-#: apps/wei/forms/registration.py:98
+#: apps/wei/forms/registration.py:97
msgid "Credit amount"
msgstr "Montant à créditer"
#: apps/member/forms.py:196 apps/note/templates/note/transaction_form.html:140
#: apps/registration/forms.py:100 apps/treasury/forms.py:135
-#: apps/wei/forms/registration.py:115
+#: apps/wei/forms/registration.py:114
msgid "Bank"
msgstr "Banque"
@@ -620,7 +623,8 @@ msgstr "section"
msgid "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\""
msgstr "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\""
-#: apps/member/models.py:54 apps/wei/templates/wei/weimembership_form.html:32
+#: apps/member/models.py:54 apps/wei/templates/wei/attribute_bus_1A.html:25
+#: apps/wei/templates/wei/weimembership_form.html:32
msgid "department"
msgstr "département"
@@ -1188,7 +1192,7 @@ msgstr "Modifier le club"
msgid "Add new member to the club"
msgstr "Ajouter un nouveau membre au club"
-#: apps/member/views.py:642 apps/wei/views.py:932
+#: apps/member/views.py:642 apps/wei/views.py:956
msgid ""
"This user don't have enough money to join this club, and can't have a "
"negative balance."
@@ -1494,8 +1498,8 @@ msgstr ""
"mode de paiement et un utilisateur ou un club"
#: apps/note/models/transactions.py:355 apps/note/models/transactions.py:358
-#: apps/note/models/transactions.py:361 apps/wei/views.py:937
-#: apps/wei/views.py:941
+#: apps/note/models/transactions.py:361 apps/wei/views.py:961
+#: apps/wei/views.py:965
msgid "This field is required."
msgstr "Ce champ est requis."
@@ -1511,7 +1515,7 @@ msgstr "Transactions de crédit/retrait"
msgid "membership transaction"
msgstr "transaction d'adhésion"
-#: apps/note/models/transactions.py:385 apps/treasury/models.py:293
+#: apps/note/models/transactions.py:385 apps/treasury/models.py:292
msgid "membership transactions"
msgstr "transactions d'adhésion"
@@ -1530,7 +1534,7 @@ msgstr "Pas de motif spécifié"
#: apps/note/tables.py:169 apps/note/tables.py:203 apps/treasury/tables.py:39
#: apps/treasury/templates/treasury/invoice_confirm_delete.html:30
#: apps/treasury/templates/treasury/sogecredit_detail.html:65
-#: apps/wei/tables.py:74 apps/wei/tables.py:117
+#: apps/wei/tables.py:75 apps/wei/tables.py:118
#: apps/wei/templates/wei/weiregistration_confirm_delete.html:31
#: note_kfet/templates/oauth2_provider/application_confirm_delete.html:18
#: note_kfet/templates/oauth2_provider/application_detail.html:39
@@ -1539,7 +1543,7 @@ msgid "Delete"
msgstr "Supprimer"
#: apps/note/tables.py:197 apps/note/templates/note/conso_form.html:132
-#: apps/wei/tables.py:48 apps/wei/tables.py:49
+#: apps/wei/tables.py:49 apps/wei/tables.py:50
#: apps/wei/templates/wei/base.html:89
#: apps/wei/templates/wei/bus_detail.html:20
#: apps/wei/templates/wei/busteam_detail.html:20
@@ -1625,7 +1629,7 @@ msgid "Amount"
msgstr "Montant"
#: apps/note/templates/note/transaction_form.html:128
-#: apps/treasury/models.py:55
+#: apps/treasury/models.py:54
msgid "Name"
msgstr "Nom"
@@ -2102,7 +2106,7 @@ msgstr "Invalider l'inscription"
msgid "Treasury"
msgstr "Trésorerie"
-#: apps/treasury/forms.py:26 apps/treasury/models.py:94
+#: apps/treasury/forms.py:26 apps/treasury/models.py:93
#: apps/treasury/templates/treasury/invoice_form.html:22
msgid "This invoice is locked and can no longer be edited."
msgstr "Cette facture est verrouillée et ne peut plus être éditée."
@@ -2115,7 +2119,7 @@ msgstr "La remise est déjà fermée."
msgid "You can't change the type of the remittance."
msgstr "Vous ne pouvez pas changer le type de la remise."
-#: apps/treasury/forms.py:125 apps/treasury/models.py:268
+#: apps/treasury/forms.py:125 apps/treasury/models.py:267
#: apps/treasury/tables.py:97 apps/treasury/tables.py:105
#: apps/treasury/templates/treasury/invoice_list.html:16
#: apps/treasury/templates/treasury/remittance_list.html:16
@@ -2127,120 +2131,120 @@ msgstr "Remise"
msgid "No attached remittance"
msgstr "Pas de remise associée"
-#: apps/treasury/models.py:27
+#: apps/treasury/models.py:26
msgid "Invoice identifier"
msgstr "Numéro de facture"
-#: apps/treasury/models.py:41
+#: apps/treasury/models.py:40
msgid "BDE"
msgstr "BDE"
-#: apps/treasury/models.py:46
+#: apps/treasury/models.py:45
msgid "Object"
msgstr "Objet"
-#: apps/treasury/models.py:50
+#: apps/treasury/models.py:49
msgid "Description"
msgstr "Description"
-#: apps/treasury/models.py:59
+#: apps/treasury/models.py:58
msgid "Address"
msgstr "Adresse"
-#: apps/treasury/models.py:64 apps/treasury/models.py:194
+#: apps/treasury/models.py:63 apps/treasury/models.py:193
msgid "Date"
msgstr "Date"
-#: apps/treasury/models.py:68
+#: apps/treasury/models.py:67
msgid "Acquitted"
msgstr "Acquittée"
-#: apps/treasury/models.py:73
+#: apps/treasury/models.py:72
msgid "Locked"
msgstr "Verrouillée"
-#: apps/treasury/models.py:74
+#: apps/treasury/models.py:73
msgid "An invoice can't be edited when it is locked."
msgstr "Une facture ne peut plus être modifiée si elle est verrouillée."
-#: apps/treasury/models.py:80
+#: apps/treasury/models.py:79
msgid "tex source"
msgstr "fichier TeX source"
-#: apps/treasury/models.py:114 apps/treasury/models.py:130
+#: apps/treasury/models.py:113 apps/treasury/models.py:129
msgid "invoice"
msgstr "facture"
-#: apps/treasury/models.py:115
+#: apps/treasury/models.py:114
msgid "invoices"
msgstr "factures"
-#: apps/treasury/models.py:118
+#: apps/treasury/models.py:117
#, python-brace-format
msgid "Invoice #{id}"
msgstr "Facture n°{id}"
-#: apps/treasury/models.py:135
+#: apps/treasury/models.py:134
msgid "Designation"
msgstr "Désignation"
-#: apps/treasury/models.py:141
+#: apps/treasury/models.py:140
msgid "Quantity"
msgstr "Quantité"
-#: apps/treasury/models.py:146
+#: apps/treasury/models.py:145
msgid "Unit price"
msgstr "Prix unitaire"
-#: apps/treasury/models.py:162
+#: apps/treasury/models.py:161
msgid "product"
msgstr "produit"
-#: apps/treasury/models.py:163
+#: apps/treasury/models.py:162
msgid "products"
msgstr "produits"
-#: apps/treasury/models.py:183
+#: apps/treasury/models.py:182
msgid "remittance type"
msgstr "type de remise"
-#: apps/treasury/models.py:184
+#: apps/treasury/models.py:183
msgid "remittance types"
msgstr "types de remises"
-#: apps/treasury/models.py:205
+#: apps/treasury/models.py:204
msgid "Comment"
msgstr "Commentaire"
-#: apps/treasury/models.py:210
+#: apps/treasury/models.py:209
msgid "Closed"
msgstr "Fermée"
-#: apps/treasury/models.py:214
+#: apps/treasury/models.py:213
msgid "remittance"
msgstr "remise"
-#: apps/treasury/models.py:215
+#: apps/treasury/models.py:214
msgid "remittances"
msgstr "remises"
-#: apps/treasury/models.py:248
+#: apps/treasury/models.py:247
msgid "Remittance #{:d}: {}"
msgstr "Remise n°{:d} : {}"
-#: apps/treasury/models.py:272
+#: apps/treasury/models.py:271
msgid "special transaction proxy"
msgstr "proxy de transaction spéciale"
-#: apps/treasury/models.py:273
+#: apps/treasury/models.py:272
msgid "special transaction proxies"
msgstr "proxys de transactions spéciales"
-#: apps/treasury/models.py:299
+#: apps/treasury/models.py:298
msgid "credit transaction"
msgstr "transaction de crédit"
-#: apps/treasury/models.py:418
+#: apps/treasury/models.py:419
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."
@@ -2248,16 +2252,16 @@ 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:438
+#: apps/treasury/models.py:439
#: apps/treasury/templates/treasury/sogecredit_detail.html:10
msgid "Credit from the Société générale"
msgstr "Crédit de la Société générale"
-#: apps/treasury/models.py:439
+#: apps/treasury/models.py:440
msgid "Credits from the Société générale"
msgstr "Crédits de la Société générale"
-#: apps/treasury/models.py:442
+#: apps/treasury/models.py:443
#, python-brace-format
msgid "Soge credit for {user}"
msgstr "Crédit de la société générale pour l'utilisateur {user}"
@@ -2437,7 +2441,7 @@ msgstr ""
"demande de crédit."
#: apps/treasury/templates/treasury/sogecredit_detail.html:63
-#: apps/wei/tables.py:59 apps/wei/tables.py:101
+#: apps/wei/tables.py:60 apps/wei/tables.py:102
msgid "Validate"
msgstr "Valider"
@@ -2516,12 +2520,12 @@ msgstr ""
"L'utilisateur sélectionné n'est pas validé. Merci de d'abord valider son "
"compte."
-#: apps/wei/forms/registration.py:60 apps/wei/models.py:118
+#: apps/wei/forms/registration.py:59 apps/wei/models.py:118
#: apps/wei/models.py:315
msgid "bus"
msgstr "bus"
-#: apps/wei/forms/registration.py:61
+#: apps/wei/forms/registration.py:60
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."
@@ -2530,11 +2534,11 @@ msgstr ""
"attribuer un bus et une équipe, en particulier si vous êtes un électron "
"libre."
-#: apps/wei/forms/registration.py:68
+#: apps/wei/forms/registration.py:67
msgid "Team"
msgstr "Équipe"
-#: apps/wei/forms/registration.py:70
+#: apps/wei/forms/registration.py:69
msgid ""
"Leave this field empty if you won't be in a team (staff, bus chief, free "
"electron)"
@@ -2542,12 +2546,12 @@ 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:76 apps/wei/forms/registration.py:86
+#: apps/wei/forms/registration.py:75 apps/wei/forms/registration.py:85
#: apps/wei/models.py:153
msgid "WEI Roles"
msgstr "Rôles au WEI"
-#: apps/wei/forms/registration.py:77
+#: apps/wei/forms/registration.py:76
msgid "Select the roles that you are interested in."
msgstr "Sélectionnez les rôles qui vous intéressent."
@@ -2571,7 +2575,7 @@ msgstr "début"
msgid "date end"
msgstr "fin"
-#: apps/wei/models.py:70
+#: apps/wei/models.py:70 apps/wei/tables.py:306
msgid "seat count in the bus"
msgstr "nombre de sièges dans le bus"
@@ -2637,7 +2641,8 @@ msgstr "Femme"
msgid "Non binary"
msgstr "Non-binaire"
-#: apps/wei/models.py:196 apps/wei/templates/wei/weimembership_form.html:55
+#: 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"
@@ -2649,7 +2654,8 @@ msgstr "coupe de vêtement"
msgid "clothing size"
msgstr "taille de vêtement"
-#: apps/wei/models.py:224 apps/wei/templates/wei/weimembership_form.html:67
+#: 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é"
@@ -2705,37 +2711,83 @@ msgstr "Adhésion au WEI"
msgid "WEI memberships"
msgstr "Adhésions au WEI"
-#: apps/wei/tables.py:104
+#: apps/wei/tables.py:105
msgid "The user does not have enough money."
msgstr "L'utilisateur n'a pas assez d'argent."
-#: apps/wei/tables.py:107
-msgid "The user is in first year, and the repartition algorithm didn't run."
+#: apps/wei/tables.py:108
+msgid ""
+"The user is in first year. You may validate the credit, the algorithm will "
+"run later."
msgstr ""
-"L'utilisateur est en première année, et l'algorithme de répartition n'a pas "
-"tourné."
+"L'utilisateur est en première année, vous pouvez valider le crédit, "
+"l'algorithme tournera plus tard."
-#: apps/wei/tables.py:110
+#: apps/wei/tables.py:111
msgid "The user has enough money, you can validate the registration."
msgstr "L'utilisateur a assez d'argent, l'inscription est possible."
-#: apps/wei/tables.py:142
+#: apps/wei/tables.py:143
msgid "Year"
msgstr "Année"
-#: apps/wei/tables.py:180 apps/wei/templates/wei/bus_detail.html:32
+#: apps/wei/tables.py:180 apps/wei/templates/wei/weimembership_form.html:102
+msgid "preferred bus"
+msgstr "bus préféré"
+
+#: 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:189 apps/wei/tables.py:230
+#: apps/wei/tables.py:220 apps/wei/tables.py:261
msgid "Members count"
msgstr "Nombre de membres"
-#: apps/wei/tables.py:196 apps/wei/tables.py:227
+#: apps/wei/tables.py:227 apps/wei/tables.py:258
msgid "members"
msgstr "adhérents"
+#: apps/wei/tables.py:288
+msgid "suggested first year"
+msgstr "1A suggérés"
+
+#: apps/wei/tables.py:294
+msgid "validated first year"
+msgstr "1A validés"
+
+#: apps/wei/tables.py:300
+msgid "validated staff"
+msgstr "2A+ validés"
+
+#: apps/wei/tables.py:311
+msgid "free seats"
+msgstr "sièges libres"
+
+#: apps/wei/templates/wei/1A_list.html:9
+msgid "Attribute first year members into buses"
+msgstr "Attribuer les 1A dans les bus"
+
+#: apps/wei/templates/wei/1A_list.html:15
+msgid "Start attribution!"
+msgstr "Démarrer l'attribution !"
+
+#: apps/wei/templates/wei/attribute_bus_1A.html:8
+msgid "Bus attribution"
+msgstr "Répartition des bus"
+
+#: apps/wei/templates/wei/attribute_bus_1A.html:31
+msgid "suggested bus"
+msgstr "bus suggéré"
+
+#: apps/wei/templates/wei/attribute_bus_1A.html:37
+msgid "View raw survey information"
+msgstr "Voir les informations brutes du sondage"
+
+#: apps/wei/templates/wei/attribute_bus_1A.html:57
+msgid "Back to main list"
+msgstr "Retour à la liste principale"
+
#: apps/wei/templates/wei/base.html:44
msgid "WEI fee (paid students)"
msgstr "Prix du WEI (élèves)"
@@ -2752,11 +2804,11 @@ msgstr "Prix du WEI (étudiants)"
msgid "WEI list"
msgstr "Liste des WEI"
-#: apps/wei/templates/wei/base.html:81 apps/wei/views.py:517
+#: apps/wei/templates/wei/base.html:81 apps/wei/views.py:523
msgid "Register 1A"
msgstr "Inscrire un 1A"
-#: apps/wei/templates/wei/base.html:85 apps/wei/views.py:592
+#: apps/wei/templates/wei/base.html:85 apps/wei/views.py:603
msgid "Register 2A+"
msgstr "Inscrire un 2A+"
@@ -2785,8 +2837,8 @@ msgstr "Télécharger au format PDF"
#: apps/wei/templates/wei/survey.html:11
#: apps/wei/templates/wei/survey_closed.html:11
-#: apps/wei/templates/wei/survey_end.html:11 apps/wei/views.py:988
-#: apps/wei/views.py:1043 apps/wei/views.py:1053
+#: apps/wei/templates/wei/survey_end.html:11 apps/wei/views.py:1011
+#: apps/wei/views.py:1066 apps/wei/views.py:1076
msgid "Survey WEI"
msgstr "Questionnaire WEI"
@@ -2827,7 +2879,11 @@ msgstr "Membres du WEI"
msgid "Unvalidated registrations"
msgstr "Inscriptions non validées"
-#: apps/wei/templates/wei/weiclub_list.html:14 apps/wei/views.py:77
+#: apps/wei/templates/wei/weiclub_detail.html:99
+msgid "Attribute buses"
+msgstr "Répartition dans les bus"
+
+#: apps/wei/templates/wei/weiclub_list.html:14 apps/wei/views.py:78
msgid "Create WEI"
msgstr "Créer un WEI"
@@ -2863,10 +2919,6 @@ msgstr "L'algorithme n'a pas été exécuté."
msgid "caution check given"
msgstr "chèque de caution donné"
-#: apps/wei/templates/wei/weimembership_form.html:102
-msgid "preferred bus"
-msgstr "bus préféré"
-
#: apps/wei/templates/wei/weimembership_form.html:105
msgid "preferred team"
msgstr "équipe préférée"
@@ -2968,67 +3020,67 @@ msgstr "Il n'y a pas de pré-inscription en attente avec cette entrée."
msgid "View validated memberships..."
msgstr "Voir les adhésions validées ..."
-#: apps/wei/views.py:56
+#: apps/wei/views.py:57
msgid "Search WEI"
msgstr "Chercher un WEI"
-#: apps/wei/views.py:107
+#: apps/wei/views.py:108
msgid "WEI Detail"
msgstr "Détails du WEI"
-#: apps/wei/views.py:202
+#: apps/wei/views.py:203
msgid "View members of the WEI"
msgstr "Voir les membres du WEI"
-#: apps/wei/views.py:230
+#: apps/wei/views.py:231
msgid "Find WEI Membership"
msgstr "Trouver une adhésion au WEI"
-#: apps/wei/views.py:240
+#: apps/wei/views.py:241
msgid "View registrations to the WEI"
msgstr "Voir les inscriptions au WEI"
-#: apps/wei/views.py:264
+#: apps/wei/views.py:265
msgid "Find WEI Registration"
msgstr "Trouver une inscription au WEI"
-#: apps/wei/views.py:275
+#: apps/wei/views.py:276
msgid "Update the WEI"
msgstr "Modifier le WEI"
-#: apps/wei/views.py:296
+#: apps/wei/views.py:297
msgid "Create new bus"
msgstr "Ajouter un nouveau bus"
-#: apps/wei/views.py:334
+#: apps/wei/views.py:335
msgid "Update bus"
msgstr "Modifier le bus"
-#: apps/wei/views.py:366
+#: apps/wei/views.py:367
msgid "Manage bus"
msgstr "Gérer le bus"
-#: apps/wei/views.py:393
+#: apps/wei/views.py:394
msgid "Create new team"
msgstr "Créer une nouvelle équipe"
-#: apps/wei/views.py:433
+#: apps/wei/views.py:434
msgid "Update team"
msgstr "Modifier l'équipe"
-#: apps/wei/views.py:464
+#: apps/wei/views.py:465
msgid "Manage WEI team"
msgstr "Gérer l'équipe WEI"
-#: apps/wei/views.py:486
+#: apps/wei/views.py:487
msgid "Register first year student to the WEI"
msgstr "Inscrire un 1A au WEI"
-#: apps/wei/views.py:539 apps/wei/views.py:627
+#: apps/wei/views.py:545 apps/wei/views.py:638
msgid "This user is already registered to this WEI."
msgstr "Cette personne est déjà inscrite au WEI."
-#: apps/wei/views.py:544
+#: apps/wei/views.py:550
msgid ""
"This user can't be in her/his first year since he/she has already "
"participated to a WEI."
@@ -3036,30 +3088,38 @@ msgstr ""
"Cet utilisateur ne peut pas être en première année puisqu'il a déjà "
"participé à un WEI."
-#: apps/wei/views.py:561
+#: apps/wei/views.py:567
msgid "Register old student to the WEI"
msgstr "Inscrire un 2A+ au WEI"
-#: apps/wei/views.py:611 apps/wei/views.py:700
+#: apps/wei/views.py:622 apps/wei/views.py:704
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:657
+#: apps/wei/views.py:668
msgid "Update WEI Registration"
msgstr "Modifier l'inscription WEI"
-#: apps/wei/views.py:761
+#: apps/wei/views.py:778
msgid "Delete WEI registration"
msgstr "Supprimer l'inscription WEI"
-#: apps/wei/views.py:772
+#: apps/wei/views.py:789
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:791
+#: apps/wei/views.py:807
msgid "Validate WEI registration"
msgstr "Valider l'inscription WEI"
+#: apps/wei/views.py:1169
+msgid "Attribute buses to first year members"
+msgstr "Répartir les 1A dans les bus"
+
+#: apps/wei/views.py:1190
+msgid "Attribute bus"
+msgstr "Attribuer un bus"
+
#: note_kfet/settings/base.py:161
msgid "German"
msgstr "Allemand"