mirror of
				https://gitlab.crans.org/bde/nk20
				synced 2025-10-30 23:39:54 +01:00 
			
		
		
		
	Merge branch 'beta' into 'master'
Magnifique UI pour le WEI See merge request bde/nk20!179
This commit is contained in:
		| @@ -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)"), | ||||
|     ) | ||||
|   | ||||
| @@ -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', | ||||
| ] | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|  | ||||
|   | ||||
| @@ -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), | ||||
|         } | ||||
|   | ||||
							
								
								
									
										20
									
								
								apps/wei/templates/wei/1A_list.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								apps/wei/templates/wei/1A_list.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| {% extends "wei/base.html" %} | ||||
|  | ||||
| {% load i18n %} | ||||
| {% load render_table from django_tables2 %} | ||||
|  | ||||
| {% block profile_content %} | ||||
|     <div class="card"> | ||||
|         <div class="card-header text-center"> | ||||
|             <h3>{% trans "Attribute first year members into buses" %}</h3> | ||||
|         </div> | ||||
|  | ||||
|         <div class="card-body"> | ||||
|             {% render_table bus_repartition_table %} | ||||
|             <hr> | ||||
|             <a href="{% url 'wei:wei_bus_1A_next' pk=club.pk %}" class="btn btn-block btn-success">{% trans "Start attribution!" %}</a> | ||||
|             <hr> | ||||
|             {% render_table table %} | ||||
|         </div> | ||||
|     </div> | ||||
| {% endblock %} | ||||
							
								
								
									
										88
									
								
								apps/wei/templates/wei/attribute_bus_1A.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								apps/wei/templates/wei/attribute_bus_1A.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,88 @@ | ||||
| {% extends "wei/base.html" %} | ||||
|  | ||||
| {% load i18n %} | ||||
|  | ||||
| {% block profile_content %} | ||||
|     <div class="card"> | ||||
|         <div class="card-header text-center"> | ||||
|             <h3>{% trans "Bus attribution" %}</h3> | ||||
|         </div> | ||||
|  | ||||
|         <div class="card-body"> | ||||
|             <dl class="row"> | ||||
|                 <dt class="col-xl-6">{% trans 'user'|capfirst %}</dt> | ||||
|                 <dd class="col-xl-6">{{ object.user }}</dd> | ||||
|  | ||||
|                 <dt class="col-xl-6">{% trans 'last name'|capfirst %}</dt> | ||||
|                 <dd class="col-xl-6">{{ object.user.last_name }}</dd> | ||||
|  | ||||
|                 <dt class="col-xl-6">{% trans 'first name'|capfirst %}</dt> | ||||
|                 <dd class="col-xl-6">{{ object.user.first_name }}</dd> | ||||
|  | ||||
|                 <dt class="col-xl-6">{% trans 'gender'|capfirst %}</dt> | ||||
|                 <dd class="col-xl-6">{{ object.get_gender_display }}</dd> | ||||
|  | ||||
|                 <dt class="col-xl-6">{% trans 'department'|capfirst %}</dt> | ||||
|                 <dd class="col-xl-6">{{ object.user.profile.get_department_display }}</dd> | ||||
|  | ||||
|                 <dt class="col-xl-6">{% trans 'health issues'|capfirst %}</dt> | ||||
|                 <dd class="col-xl-6">{{ object.health_issues|default:"—" }}</dd> | ||||
|  | ||||
|                 <dt class="col-xl-6">{% trans 'suggested bus'|capfirst %}</dt> | ||||
|                 <dd class="col-xl-6">{{ survey.information.selected_bus_name }}</dd> | ||||
|             </dl> | ||||
|  | ||||
|             <div class="card"> | ||||
|                 <div class="card-header"> | ||||
|                     <button class="btn btn-link" data-toggle="collapse" data-target="#raw-survey">{% trans "View raw survey information" %}</button> | ||||
|                 </div> | ||||
|                 <div class="collapse" id="raw-survey"> | ||||
|                     <dl class="row"> | ||||
|                         {% for key, value in survey.registration.information.items %} | ||||
|                             <dt class="col-xl-6">{{ key }}</dt> | ||||
|                             <dd class="col-xl-6">{{ value }}</dd> | ||||
|                         {% endfor %} | ||||
|                     </dl> | ||||
|                 </div> | ||||
|             </div> | ||||
|  | ||||
|             <hr> | ||||
|  | ||||
|             {% for bus, score in survey.ordered_buses %} | ||||
|                 <button class="btn btn-{% if bus.pk == survey.information.selected_bus_pk %}success{% else %}light{% endif %}" onclick="choose_bus({{ bus.pk }})"> | ||||
|                     {{ bus }} ({{ score|floatformat:2 }}) : {{ bus.memberships.count }}+{{ bus.suggested_first_year }} / {{ bus.size }} | ||||
|                 </button> | ||||
|             {% endfor %} | ||||
|  | ||||
|             <a href="{% url 'wei:wei_1A_list' pk=object.wei.pk %}" class="btn btn-block btn-info">{% trans "Back to main list" %}</a> | ||||
|         </div> | ||||
|     </div> | ||||
| {% endblock %} | ||||
|  | ||||
| {% block extrajavascript %} | ||||
|     <script> | ||||
|         function choose_bus(bus_id) { | ||||
|             let valid_buses = [{% for bus, score in survey.ordered_buses %}{{ bus.pk }}, {% endfor %}]; | ||||
|             if (valid_buses.indexOf(bus_id) === -1) { | ||||
|                 console.log("Invalid chosen bus") | ||||
|                 return | ||||
|             } | ||||
|  | ||||
|             $.ajax({ | ||||
|                 url: "/api/wei/membership/{{ object.membership.id }}/", | ||||
|                 type: "PATCH", | ||||
|                 dataType: "json", | ||||
|                 headers: { | ||||
|                     "X-CSRFTOKEN": CSRF_TOKEN | ||||
|                 }, | ||||
|                 data: { | ||||
|                     bus: bus_id, | ||||
|                 } | ||||
|             }).done(function () { | ||||
|                 window.location = "{% url 'wei:wei_bus_1A_next' pk=object.wei.pk %}" | ||||
|             }).fail(function (xhr) { | ||||
|                 errMsg(xhr.responseJSON) | ||||
|             }) | ||||
|         } | ||||
|     </script> | ||||
| {% endblock %} | ||||
| @@ -94,6 +94,10 @@ SPDX-License-Identifier: GPL-3.0-or-later | ||||
|     </div> | ||||
| </div> | ||||
| {% endif %} | ||||
|  | ||||
|     {% 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 %} | ||||
|  | ||||
| {% block extrajavascript %} | ||||
|   | ||||
| @@ -53,7 +53,7 @@ SPDX-License-Identifier: GPL-3.0-or-later | ||||
|                 <dd class="col-xl-6">{{ registration.first_year|yesno }}</dd> | ||||
|  | ||||
|                 <dt class="col-xl-6">{% trans 'gender'|capfirst %}</dt> | ||||
|                 <dd class="col-xl-6">{{ registration.gender }}</dd> | ||||
|                 <dd class="col-xl-6">{{ registration.get_gender_display }}</dd> | ||||
|  | ||||
|                 <dt class="col-xl-6">{% trans 'clothing cut'|capfirst %}</dt> | ||||
|                 <dd class="col-xl-6">{{ registration.clothing_cut }}</dd> | ||||
|   | ||||
| @@ -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/<int:wei_pk>/memberships/pdf/<int:bus_pk>/<int:team_pk>/', MemberListRenderView.as_view(), | ||||
|          name="wei_memberships_team_pdf"), | ||||
|     path('bus-1A/list/<int:pk>/', WEI1AListView.as_view(), name="wei_1A_list"), | ||||
|     path('add-bus/<int:pk>/', BusCreateView.as_view(), name="add_bus"), | ||||
|     path('manage-bus/<int:pk>/', BusManageView.as_view(), name="manage_bus"), | ||||
|     path('update-bus/<int:pk>/', BusUpdateView.as_view(), name="update_bus"), | ||||
| @@ -40,4 +40,6 @@ urlpatterns = [ | ||||
|     path('survey/<int:pk>/', WEISurveyView.as_view(), name="wei_survey"), | ||||
|     path('survey/<int:pk>/end/', WEISurveyEndView.as_view(), name="wei_survey_end"), | ||||
|     path('detail/<int:pk>/closed/', WEIClosedView.as_view(), name="wei_closed"), | ||||
|     path('bus-1A/<int:pk>/', WEIAttributeBus1AView.as_view(), name="wei_bus_1A"), | ||||
|     path('bus-1A/next/<int:pk>/', WEIAttributeBus1ANextView.as_view(), name="wei_bus_1A_next"), | ||||
| ] | ||||
|   | ||||
| @@ -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,6 +880,8 @@ class WEIValidateRegistrationView(ProtectQuerysetMixin, ProtectedCreateView): | ||||
|             form.fields["bank"].disabled = True | ||||
|             form.fields["bank"].initial = "Société générale" | ||||
|  | ||||
|         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 | ||||
| @@ -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, )) | ||||
|   | ||||
| @@ -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 <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: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" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user