diff --git a/apps/member/models.py b/apps/member/models.py index 5d6544afaa6eca5dd0e1c50185083c5442fbc9fc..7bde26805c7867e817612b54c49dc0f044632754 100644 --- a/apps/member/models.py +++ b/apps/member/models.py @@ -10,6 +10,7 @@ from django.core.exceptions import ValidationError from django.db import models from django.template import loader from django.urls import reverse, reverse_lazy +from django.utils import timezone from django.utils.encoding import force_bytes from django.utils.http import urlsafe_base64_encode from django.utils.translation import gettext_lazy as _ @@ -301,13 +302,34 @@ class Membership(models.Model): else: return self.date_start.toordinal() <= datetime.datetime.now().toordinal() + def renew(self): + if Membership.objects.filter( + user=self.user, + club=self.club, + date_start__gte=self.club.membership_start, + ).exists(): + # Membership is already renewed + return + new_membership = Membership( + user=self.user, + club=self.club, + date_start=max(self.date_end + datetime.timedelta(days=1), self.club.membership_start), + ) + from django.forms import model_to_dict + if hasattr(self, '_force_renew_parent') and self._force_renew_parent: + new_membership._force_renew_parent = True + if hasattr(self, '_soge') and self._soge: + new_membership._soge = True + if hasattr(self, '_force_save') and self._force_save: + new_membership._force_save = True + new_membership.save() + new_membership.roles.set(self.roles.all()) + new_membership.save() + def save(self, *args, **kwargs): """ Calculate fee and end date before saving the membership and creating the transaction if needed. """ - if self.club.parent_club is not None: - if not Membership.objects.filter(user=self.user, club=self.club.parent_club).exists(): - raise ValidationError(_('User is not a member of the parent club') + ' ' + self.club.parent_club.name) if self.pk: for role in self.roles.all(): @@ -327,17 +349,54 @@ class Membership(models.Model): ).exists(): raise ValidationError(_('User is already a member of the club')) - if self.user.profile.paid: - self.fee = self.club.membership_fee_paid - else: - self.fee = self.club.membership_fee_unpaid + if self.club.parent_club is not None: + if not Membership.objects.filter( + user=self.user, + club=self.club.parent_club, + date_start__gte=self.club.parent_club.membership_start, + ).exists(): + if hasattr(self, '_force_renew_parent') and self._force_renew_parent: + parent_membership = Membership.objects.filter( + user=self.user, + club=self.club.parent_club, + ).order_by("-date_start") + if parent_membership.exists(): + # Renew the previous membership of the parent club + parent_membership = parent_membership.first() + parent_membership._force_renew_parent = True + if hasattr(self, '_soge'): + parent_membership._soge = True + if hasattr(self, '_force_save'): + parent_membership._force_save = True + parent_membership.renew() + else: + # Create a new membership in the parent club + parent_membership = Membership( + user=self.user, + club=self.club.parent_club, + date_start=self.date_start, + ) + parent_membership._force_renew_parent = True + if hasattr(self, '_soge'): + parent_membership._soge = True + if hasattr(self, '_force_save'): + parent_membership._force_save = True + parent_membership.save() + else: + raise ValidationError(_('User is not a member of the parent club') + + ' ' + self.club.parent_club.name) + + if self.user.profile.paid: + self.fee = self.club.membership_fee_paid + else: + self.fee = self.club.membership_fee_unpaid - if self.club.membership_duration is not None: - self.date_end = self.date_start + datetime.timedelta(days=self.club.membership_duration) - else: - self.date_end = self.date_start + datetime.timedelta(days=424242) - if self.club.membership_end is not None and self.date_end > self.club.membership_end: - self.date_end = self.club.membership_end + if self.club.membership_duration is not None: + self.date_end = self.date_start + datetime.timedelta(days=self.club.membership_duration) + else: + self.date_end = self.date_start + datetime.timedelta(days=424242) + if self.club.membership_end is not None and self.date_end > self.club.membership_end: + self.date_end = self.club.membership_end super().save(*args, **kwargs) @@ -360,8 +419,9 @@ class Membership(models.Model): reason="Adhésion " + self.club.name, ) transaction._force_save = True - print(hasattr(self, '_soge')) - if hasattr(self, '_soge') and "treasury" in settings.INSTALLED_APPS: + if hasattr(self, '_soge') and "treasury" in settings.INSTALLED_APPS\ + and (self.club.name == "BDE" or self.club.name == "Kfet" or + ("wei" in settings.INSTALLED_APPS and hasattr(self.club, "weiclub") and self.club.weiclub)): # If the soge pays, then the transaction is unvalidated in a first time, then submitted for control # to treasurers. transaction.valid = False diff --git a/apps/member/views.py b/apps/member/views.py index edcb0feb32eeeaf420714d3d8e8e475140eda2fe..cc1264a1cb1fdcaf25b33c112ce34086e5aab351 100644 --- a/apps/member/views.py +++ b/apps/member/views.py @@ -442,6 +442,16 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): .get(pk=self.kwargs["club_pk"], weiclub=None) form.fields['credit_amount'].initial = club.membership_fee_paid + c = club + clubs_renewal = [] + additional_fee_renewal = 0 + while c.parent_club is not None: + c = c.parent_club + clubs_renewal.append(c) + additional_fee_renewal += c.membership_fee_paid if user.profile.paid else c.membership_fee_unpaid + context["clubs_renewal"] = clubs_renewal + context["additional_fee_renewal"] = additional_fee_renewal + # If the concerned club is the BDE, then we add the option that Société générale pays the membership. if club.name != "BDE": del form.fields['soge'] @@ -454,26 +464,54 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): context["total_fee"] = "{:.02f}".format(fee / 100, ) else: # This is a renewal. Fields can be pre-completed. + context["renewal"] = True + old_membership = self.get_queryset().get(pk=self.kwargs["pk"]) club = old_membership.club user = old_membership.user + + c = club + clubs_renewal = [] + additional_fee_renewal = 0 + while c.parent_club is not None: + c = c.parent_club + if not Membership.objects.filter( + club=c, + user=user, + date_start__gte=c.membership_start, + ).exists(): + clubs_renewal.append(c) + additional_fee_renewal += c.membership_fee_paid if user.profile.paid else c.membership_fee_unpaid + context["clubs_renewal"] = clubs_renewal + context["additional_fee_renewal"] = additional_fee_renewal + form.fields['user'].initial = user form.fields['user'].disabled = True form.fields['date_start'].initial = old_membership.date_end + timedelta(days=1) - form.fields['credit_amount'].initial = club.membership_fee_paid if user.profile.paid \ - else club.membership_fee_unpaid + form.fields['credit_amount'].initial = (club.membership_fee_paid if user.profile.paid + else club.membership_fee_unpaid) + additional_fee_renewal form.fields['last_name'].initial = user.last_name form.fields['first_name'].initial = user.first_name # If this is a renewal of a BDE membership, Société générale can pays, if it is not yet done - if club.name != "BDE" or user.profile.soge: + if (club.name != "BDE" and club.name != "Kfet") or user.profile.soge: del form.fields['soge'] else: fee = 0 bde = Club.objects.get(name="BDE") - fee += bde.membership_fee_paid if user.profile.paid else bde.membership_fee_unpaid + if not Membership.objects.filter( + club=bde, + user=user, + date_start__gte=bde.membership_start, + ).exists(): + fee += bde.membership_fee_paid if user.profile.paid else bde.membership_fee_unpaid kfet = Club.objects.get(name="Kfet") - fee += kfet.membership_fee_paid if user.profile.paid else kfet.membership_fee_unpaid + if not Membership.objects.filter( + club=kfet, + user=user, + date_start__gte=bde.membership_start, + ).exists(): + fee += kfet.membership_fee_paid if user.profile.paid else kfet.membership_fee_unpaid context["total_fee"] = "{:.02f}".format(fee / 100, ) context['club'] = club @@ -502,7 +540,7 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): last_name = form.cleaned_data["last_name"] first_name = form.cleaned_data["first_name"] bank = form.cleaned_data["bank"] - soge = form.cleaned_data["soge"] and not user.profile.soge and club.name == "BDE" + soge = form.cleaned_data["soge"] and not user.profile.soge and (club.name == "BDE" or club.name == "Kfet") # If Société générale pays, then we store that information but the payment must be controlled by treasurers # later. The membership transaction will be invalidated. @@ -513,10 +551,17 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): if credit_type is None: credit_amount = 0 - if user.profile.paid: - fee = club.membership_fee_paid - else: - fee = club.membership_fee_unpaid + fee = 0 + c = club + while c is not None: + if not Membership.objects.filter( + club=c, + user=user, + date_start__gte=c.membership_start, + ).exists(): + fee += c.membership_fee_paid if user.profile.paid else c.membership_fee_unpaid + c = c.parent_club + if user.note.balance + credit_amount < fee and not Membership.objects.filter( club__name="Kfet", user=user, @@ -524,22 +569,11 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): date_end__gte=datetime.now().date(), ).exists(): # Users without a valid Kfet membership can't have a negative balance. - # Club 2 = Kfet (hard-code :'( ) # TODO Send a notification to the user (with a mail?) to tell her/him to credit her/his note form.add_error('user', _("This user don't have enough money to join this club, and can't have a negative balance.")) return super().form_invalid(form) - if club.parent_club is not None: - if not Membership.objects.filter( - user=form.instance.user, - club=club.parent_club, - date_start__lte=form.instance.date_start, - date_end__gte=form.instance.date_start, - ).exists(): - form.add_error('user', _('User is not a member of the parent club') + ' ' + club.parent_club.name) - return super().form_invalid(form) - if Membership.objects.filter( user=form.instance.user, club=club, @@ -561,7 +595,7 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): # Now, all is fine, the membership can be created. - if club.name == "BDE": + if club.name == "BDE" or club.name == "Kfet": # When we renew the BDE membership, we update the profile section. # We could automate that and remove the section field from the Profile model, # but with this way users can customize their section as they want. @@ -593,6 +627,8 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): transaction._force_save = True transaction.save() + form.instance._force_renew_parent = True + ret = super().form_valid(form) member_role = Role.objects.filter(name="Membre de club").all() @@ -603,33 +639,40 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): # If Société générale pays, then we assume that this is the BDE membership, and we auto-renew the # Kfet membership. if soge: + # If not already done, create BDE and Kfet memberships + bde = Club.objects.get(name="BDE") kfet = Club.objects.get(name="Kfet") - kfet_fee = kfet.membership_fee_paid if user.profile.paid else kfet.membership_fee_unpaid - # Get current membership, to get the end date - old_membership = Membership.objects.filter( - club__name="Kfet", - user=user, - date_start__lte=datetime.today(), - date_end__gte=datetime.today(), - ) - - membership = Membership( - club=kfet, - user=user, - fee=kfet_fee, - date_start=old_membership.get().date_end + timedelta(days=1) - if old_membership.exists() else form.instance.date_start, - ) - membership._force_save = True - membership._soge = True - membership.save() - membership.refresh_from_db() - if old_membership.exists(): - membership.roles.set(old_membership.get().roles.all()) - else: - membership.roles.add(Role.objects.get(name="Adhérent Kfet")) - membership.save() + soge_clubs = [bde, kfet] + for club in soge_clubs: + fee = club.membership_fee_paid if user.profile.paid else club.membership_fee_unpaid + + # Get current membership, to get the end date + old_membership = Membership.objects.filter( + club=club, + user=user, + ).order_by("-date_start") + + if old_membership.filter(date_start__gte=club.membership_start).exists(): + # Membership is already renewed + continue + + membership = Membership( + club=club, + user=user, + fee=fee, + date_start=max(old_membership.first().date_end + timedelta(days=1), club.membership_start) + if old_membership.exists() else form.instance.date_start, + ) + membership._force_save = True + membership._soge = True + membership.save() + membership.refresh_from_db() + if old_membership.exists(): + membership.roles.set(old_membership.get().roles.all()) + else: + membership.roles.add(Role.objects.get(name="Adhérent Kfet")) + membership.save() return ret diff --git a/apps/treasury/views.py b/apps/treasury/views.py index 22215254a5545a02f44ac2d698fb32bd255abae6..088345b8343dbad9a35274cc1e8368c92347e52b 100644 --- a/apps/treasury/views.py +++ b/apps/treasury/views.py @@ -353,18 +353,13 @@ class SogeCreditListView(LoginRequiredMixin, ProtectQuerysetMixin, SingleTableVi qs = super().get_queryset() if "search" in self.request.GET: pattern = self.request.GET["search"] - - if not pattern: - return qs.none() - - qs = qs.filter( - Q(user__first_name__iregex=pattern) - | Q(user__last_name__iregex=pattern) - | Q(user__note__alias__name__iregex="^" + pattern) - | Q(user__note__alias__normalized_name__iregex="^" + Alias.normalize(pattern)) - ) - else: - qs = qs.none() + if pattern: + qs = qs.filter( + Q(user__first_name__iregex=pattern) + | Q(user__last_name__iregex=pattern) + | Q(user__note__alias__name__iregex="^" + pattern) + | Q(user__note__alias__normalized_name__iregex="^" + Alias.normalize(pattern)) + ) if "valid" in self.request.GET: q = Q(credit_transaction=None) diff --git a/apps/wei/forms/registration.py b/apps/wei/forms/registration.py index 738db4e2c06ef159b5950b04f0b10d628c6d9c5b..98215f4b7452e4b7920fce5cf3e7a65665fc73a9 100644 --- a/apps/wei/forms/registration.py +++ b/apps/wei/forms/registration.py @@ -6,6 +6,8 @@ from django.contrib.auth.models import User from django.db.models import Q from django.forms import CheckboxSelectMultiple from django.utils.translation import gettext_lazy as _ + +from note.models import NoteSpecial from note_kfet.inputs import AmountInput, DatePickerInput, Autocomplete, ColorWidget from ..models import WEIClub, WEIRegistration, Bus, BusTeam, WEIMembership, WEIRole @@ -75,6 +77,35 @@ class WEIMembershipForm(forms.ModelForm): widget=CheckboxSelectMultiple(), ) + credit_type = forms.ModelChoiceField( + queryset=NoteSpecial.objects.all(), + label=_("Credit type"), + empty_label=_("No credit"), + required=False, + ) + + credit_amount = forms.IntegerField( + label=_("Credit amount"), + widget=AmountInput(), + initial=0, + required=False, + ) + + last_name = forms.CharField( + label=_("Last name"), + required=False, + ) + + first_name = forms.CharField( + label=_("First name"), + required=False, + ) + + bank = forms.CharField( + label=_("Bank"), + required=False, + ) + def clean(self): cleaned_data = super().clean() if cleaned_data["team"] is not None and cleaned_data["team"].bus != cleaned_data["bus"]: diff --git a/apps/wei/tables.py b/apps/wei/tables.py index 41c35a47b55400bbd8dca6f83bf08852460e5a3a..0fae6848eb9fc7bbeacb507a0ac0bd9bc6c90c3a 100644 --- a/apps/wei/tables.py +++ b/apps/wei/tables.py @@ -3,9 +3,13 @@ import django_tables2 as tables from django.urls import reverse_lazy +from django.utils import timezone +from django.utils.html import format_html from django.utils.translation import gettext_lazy as _ from django_tables2 import A +from note_kfet.middlewares import get_current_authenticated_user +from permission.backends import PermissionBackend from .models import WEIClub, WEIRegistration, Bus, BusTeam, WEIMembership @@ -53,8 +57,12 @@ class WEIRegistrationTable(tables.Table): verbose_name=_("Validate"), text=_("Validate"), attrs={ + 'th': { + 'id': 'validate-membership-header' + }, 'a': { - 'class': 'btn btn-success' + 'class': 'btn btn-success', + 'data-type': 'validate-membership' } } ) @@ -65,12 +73,33 @@ class WEIRegistrationTable(tables.Table): verbose_name=_("delete"), text=_("Delete"), attrs={ + 'th': { + 'id': 'delete-membership-header' + }, 'a': { - 'class': 'btn btn-danger' + 'class': 'btn btn-danger', + 'data-type': 'delete-membership' } }, ) + def render_validate(self, record): + if PermissionBackend.check_perm(get_current_authenticated_user(), "wei.add_weimembership", WEIMembership( + club=record.wei, + user=record.user, + date_start=timezone.now().date(), + date_end=timezone.now().date(), + fee=0, + registration=record, + )): + return _("Validate") + return format_html("<span class='no-perm'></span>") + + def render_delete(self, record): + if PermissionBackend.check_perm(get_current_authenticated_user(), "wei.delete_weimembership", record): + return _("Delete") + return format_html("<span class='no-perm'></span>") + class Meta: attrs = { 'class': 'table table-condensed table-striped table-hover' diff --git a/apps/wei/views.py b/apps/wei/views.py index 7731f08bc43c9ddb7a4e537133529de23cab3617..fe2a47a5b014b35b6f28923c651a10aa5096bba5 100644 --- a/apps/wei/views.py +++ b/apps/wei/views.py @@ -24,10 +24,11 @@ from django.utils.translation import gettext_lazy as _ from django.views.generic.edit import BaseFormView, DeleteView from django_tables2 import SingleTableView from member.models import Membership, Club -from note.models import Transaction, NoteClub, Alias +from note.models import Transaction, NoteClub, Alias, SpecialTransaction, NoteSpecial from note.tables import HistoryTable from note_kfet.settings import BASE_DIR from permission.backends import PermissionBackend +from permission.models import Role from permission.views import ProtectQuerysetMixin from .forms.registration import WEIChooseBusForm @@ -666,6 +667,15 @@ class WEIUpdateRegistrationView(ProtectQuerysetMixin, LoginRequiredMixin, Update survey = CurrentSurvey(self.object) if not survey.is_complete(): return reverse_lazy("wei:wei_survey", kwargs={"pk": self.object.pk}) + if PermissionBackend.check_perm(self.request.user, "wei.add_weimembership", WEIMembership( + club=self.object.wei, + user=self.object.user, + date_start=timezone.now().date(), + date_end=timezone.now().date(), + fee=0, + registration=self.object, + )): + return reverse_lazy("wei:validate_registration", kwargs={"pk": self.object.pk}) return reverse_lazy("wei:wei_detail", kwargs={"pk": self.object.wei.pk}) @@ -723,19 +733,55 @@ class WEIValidateRegistrationView(ProtectQuerysetMixin, LoginRequiredMixin, Crea if survey.information.valid: context["suggested_bus"] = survey.information.get_selected_bus() context["club"] = registration.wei - context["fee"] = registration.wei.membership_fee_paid if registration.user.profile.paid \ - else registration.wei.membership_fee_unpaid + + kfet = registration.wei.parent_club + bde = kfet.parent_club + context["kfet_member"] = Membership.objects.filter( - club__name="Kfet", + club__name=kfet.name, + user=registration.user, + date_start__gte=kfet.membership_start, + ).exists() + context["bde_member"] = Membership.objects.filter( + club__name=bde.name, user=registration.user, - date_start__gte=registration.wei.parent_club.membership_start, + date_start__gte=bde.membership_start, ).exists() + fee = registration.wei.membership_fee_paid if registration.user.profile.paid \ + else registration.wei.membership_fee_unpaid + if not context["kfet_member"]: + fee += kfet.membership_fee_paid if registration.user.profile.paid \ + else kfet.membership_fee_unpaid + if not context["bde_member"]: + fee += bde.membership_fee_paid if registration.user.profile.paid \ + else bde.membership_fee_unpaid + + context["fee"] = fee + + form = context["form"] + if registration.soge_credit: + form.fields["credit_amount"].initial = fee + else: + form.fields["credit_amount"].initial = max(0, fee - registration.user.note.balance) + return context def get_form(self, form_class=None): form = super().get_form(form_class) registration = WEIRegistration.objects.get(pk=self.kwargs["pk"]) + form.fields["last_name"].initial = registration.user.last_name + form.fields["first_name"].initial = registration.user.first_name + + if registration.soge_credit: + form.fields["credit_type"].disabled = True + form.fields["credit_type"].initial = NoteSpecial.objects.get(special_type="Virement bancaire") + form.fields["credit_amount"].disabled = True + form.fields["last_name"].disabled = True + form.fields["first_name"].disabled = True + 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 @@ -750,7 +796,7 @@ class WEIValidateRegistrationView(ProtectQuerysetMixin, LoginRequiredMixin, Crea 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 = Bus.objects.get(pk=information["preferred_team_pk"][0]) + 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") @@ -770,38 +816,80 @@ class WEIValidateRegistrationView(ProtectQuerysetMixin, LoginRequiredMixin, Crea membership.club = club membership.date_start = min(date.today(), club.date_start) membership.registration = registration + # Force the membership of the clubs BDE and Kfet + membership._force_renew_parent = True if user.profile.paid: fee = club.membership_fee_paid else: fee = club.membership_fee_unpaid - if not registration.soge_credit and user.note.balance < fee: + kfet = club.parent_club + bde = kfet.parent_club + + kfet_member = Membership.objects.filter( + club__name=kfet.name, + user=registration.user, + date_start__gte=kfet.membership_start, + ).exists() + bde_member = Membership.objects.filter( + club__name=bde.name, + user=registration.user, + date_start__gte=bde.membership_start, + ).exists() + + if not kfet_member: + fee += kfet.membership_fee_paid if registration.user.profile.paid else kfet.membership_fee_unpaid + if not bde_member: + fee += bde.membership_fee_paid if registration.user.profile.paid else bde.membership_fee_unpaid + + credit_type = form.cleaned_data["credit_type"] + credit_amount = form.cleaned_data["credit_amount"] + last_name = form.cleaned_data["last_name"] + first_name = form.cleaned_data["first_name"] + bank = form.cleaned_data["bank"] + + if credit_type is None or registration.soge_credit: + credit_amount = 0 + + if not registration.caution_check and not registration.first_year: + form.add_error('bus', _("This user didn't give her/his caution check.")) + return super().form_invalid(form) + + if not registration.soge_credit and user.note.balance < fee + credit_amount: # Users must have money before registering to the WEI. - # TODO Send a notification to the user (with a mail?) to tell her/him to credit her/his note form.add_error('bus', _("This user don't have enough money to join this club, and can't have a negative balance.")) return super().form_invalid(form) - if not registration.caution_check and not registration.first_year: - form.add_error('bus', _("This user didn't give her/his caution check.")) - return super().form_invalid(form) + if credit_amount: + if not last_name: + form.add_error('last_name', _("This field is required.")) + return super().form_invalid(form) - if club.parent_club is not None: # parent_club is never None: this is Kfet. - # We want that the user is member of the Kfet club *of this year*: the Kfet membership is included - # in the WEI registration. - if not Membership.objects.filter( - user=form.instance.user, - club=club.parent_club, # Kfet - date_start__gte=club.parent_club.membership_start, - ).exists(): - form.add_error('bus', _('User is not a member of the parent club') + ' ' + club.parent_club.name) + if not first_name: + form.add_error('first_name', _("This field is required.")) return super().form_invalid(form) + # Credit note before adding the membership + SpecialTransaction.objects.create( + source=credit_type, + destination=registration.user.note, + amount=credit_amount, + reason="Crédit " + str(credit_type) + " (WEI)", + last_name=last_name, + first_name=first_name, + bank=bank, + ) + # Now, all is fine, the membership can be created. + if registration.soge_credit: + form.instance._soge = True + if registration.first_year: membership = form.instance + # If the user is not a member of the club Kfet, then the membership is created. membership.save() membership.refresh_from_db() membership.roles.set(WEIRole.objects.filter(name="1A").all()) diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index fa49f7ccd59435be4c0252bc7122611cbecd7c68..6875a00da3768f67686604548cf2d978d9ad4f58 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-03 23:53+0200\n" +"POT-Creation-Date: 2020-08-04 20:03+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: LANGUAGE <LL@li.org>\n" @@ -45,7 +45,7 @@ msgid "You can't invite more than 3 people to this activity." msgstr "Vous ne pouvez pas inviter plus de 3 personnes à cette activité." #: apps/activity/models.py:24 apps/activity/models.py:49 -#: apps/member/models.py:158 apps/note/models/notes.py:212 +#: apps/member/models.py:159 apps/note/models/notes.py:212 #: apps/note/models/transactions.py:25 apps/note/models/transactions.py:45 #: apps/note/models/transactions.py:268 apps/permission/models.py:339 #: apps/wei/models.py:65 apps/wei/models.py:117 @@ -84,7 +84,7 @@ msgstr "description" msgid "type" msgstr "type" -#: apps/activity/models.py:67 apps/logs/models.py:22 apps/member/models.py:266 +#: apps/activity/models.py:67 apps/logs/models.py:22 apps/member/models.py:267 #: apps/note/models/notes.py:126 apps/treasury/models.py:222 #: apps/wei/models.py:159 templates/treasury/sogecredit_detail.html:14 #: templates/wei/survey.html:16 @@ -189,12 +189,13 @@ msgstr "Type" #: apps/activity/tables.py:77 apps/member/forms.py:103 #: apps/registration/forms.py:70 apps/treasury/forms.py:120 +#: apps/wei/forms/registration.py:95 msgid "Last name" msgstr "Nom de famille" #: apps/activity/tables.py:79 apps/member/forms.py:108 #: apps/registration/forms.py:75 apps/treasury/forms.py:122 -#: templates/note/transaction_form.html:129 +#: apps/wei/forms/registration.py:100 templates/note/transaction_form.html:129 msgid "First name" msgstr "Prénom" @@ -268,7 +269,7 @@ msgid "edit" msgstr "Modifier" #: apps/logs/models.py:63 apps/note/tables.py:137 apps/note/tables.py:165 -#: apps/permission/models.py:137 apps/wei/tables.py:65 +#: apps/permission/models.py:137 apps/wei/tables.py:73 msgid "delete" msgstr "Supprimer" @@ -292,25 +293,25 @@ msgstr "journal de modification" msgid "changelogs" msgstr "journaux de modifications" -#: apps/member/admin.py:52 apps/member/models.py:185 +#: apps/member/admin.py:52 apps/member/models.py:186 #: templates/member/club_info.html:41 msgid "membership fee (paid students)" msgstr "cotisation pour adhérer (normalien élève)" -#: apps/member/admin.py:53 apps/member/models.py:190 +#: apps/member/admin.py:53 apps/member/models.py:191 #: templates/member/club_info.html:44 msgid "membership fee (unpaid students)" msgstr "cotisation pour adhérer (normalien étudiant)" -#: apps/member/admin.py:67 apps/member/models.py:277 +#: apps/member/admin.py:67 apps/member/models.py:278 msgid "roles" msgstr "rôles" -#: apps/member/admin.py:68 apps/member/models.py:291 +#: apps/member/admin.py:68 apps/member/models.py:292 msgid "fee" msgstr "cotisation" -#: apps/member/apps.py:14 apps/wei/tables.py:150 apps/wei/tables.py:181 +#: apps/member/apps.py:14 apps/wei/tables.py:179 apps/wei/tables.py:210 msgid "member" msgstr "adhérent" @@ -328,10 +329,12 @@ msgid "Check this case is the Société Générale paid the inscription." msgstr "Cochez cette case si la Société Générale a payé l'inscription." #: apps/member/forms.py:89 apps/registration/forms.py:57 +#: apps/wei/forms/registration.py:82 msgid "Credit type" msgstr "Type de rechargement" #: apps/member/forms.py:90 apps/registration/forms.py:58 +#: apps/wei/forms/registration.py:83 msgid "No credit" msgstr "Pas de rechargement" @@ -340,11 +343,13 @@ msgid "You can credit the note of the user." msgstr "Vous pouvez créditer la note de l'utisateur avant l'adhésion." #: apps/member/forms.py:96 apps/registration/forms.py:63 +#: apps/wei/forms/registration.py:88 msgid "Credit amount" msgstr "Montant à créditer" #: apps/member/forms.py:113 apps/registration/forms.py:80 -#: apps/treasury/forms.py:124 templates/note/transaction_form.html:135 +#: apps/treasury/forms.py:124 apps/wei/forms/registration.py:105 +#: templates/note/transaction_form.html:135 msgid "Bank" msgstr "Banque" @@ -356,171 +361,171 @@ msgstr "Utilisateur" msgid "Roles" msgstr "Rôles" -#: apps/member/models.py:34 +#: apps/member/models.py:35 #: templates/registration/future_profile_detail.html:40 #: templates/wei/weimembership_form.html:48 msgid "phone number" msgstr "numéro de téléphone" -#: apps/member/models.py:41 templates/member/profile_info.html:29 +#: apps/member/models.py:42 templates/member/profile_info.html:29 #: templates/registration/future_profile_detail.html:34 #: templates/wei/weimembership_form.html:42 msgid "section" msgstr "section" -#: apps/member/models.py:42 +#: apps/member/models.py:43 msgid "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\"" msgstr "e.g. \"1A0\", \"9A♥\", \"SAPHIRE\"" -#: apps/member/models.py:50 templates/wei/weimembership_form.html:36 +#: apps/member/models.py:51 templates/wei/weimembership_form.html:36 msgid "department" msgstr "département" -#: apps/member/models.py:52 +#: apps/member/models.py:53 msgid "Informatics (A0)" msgstr "Informatique (A0)" -#: apps/member/models.py:53 +#: apps/member/models.py:54 msgid "Mathematics (A1)" msgstr "Mathématiques (A1)" -#: apps/member/models.py:54 +#: apps/member/models.py:55 msgid "Physics (A2)" msgstr "Physique (A2)" -#: apps/member/models.py:55 +#: apps/member/models.py:56 msgid "Applied physics (A'2)" msgstr "Physique appliquée (A'2)" -#: apps/member/models.py:56 +#: apps/member/models.py:57 msgid "Chemistry (A''2)" msgstr "Chimie (A''2)" -#: apps/member/models.py:57 +#: apps/member/models.py:58 msgid "Biology (A3)" msgstr "Biologie (A3)" -#: apps/member/models.py:58 +#: apps/member/models.py:59 msgid "SAPHIRE (B1234)" msgstr "SAPHIRE (B1234)" -#: apps/member/models.py:59 +#: apps/member/models.py:60 msgid "Mechanics (B1)" msgstr "Mécanique (B1)" -#: apps/member/models.py:60 +#: apps/member/models.py:61 msgid "Civil engineering (B2)" msgstr "Génie civil (B2)" -#: apps/member/models.py:61 +#: apps/member/models.py:62 msgid "Mechanical engineering (B3)" msgstr "Génie mécanique (B3)" -#: apps/member/models.py:62 +#: apps/member/models.py:63 msgid "EEA (B4)" msgstr "EEA (B4)" -#: apps/member/models.py:63 +#: apps/member/models.py:64 msgid "Design (C)" msgstr "Design (C)" -#: apps/member/models.py:64 +#: apps/member/models.py:65 msgid "Economy-management (D2)" msgstr "Économie-gestion (D2)" -#: apps/member/models.py:65 +#: apps/member/models.py:66 msgid "Social sciences (D3)" msgstr "Sciences sociales (D3)" -#: apps/member/models.py:66 +#: apps/member/models.py:67 msgid "English (E)" msgstr "Anglais (E)" -#: apps/member/models.py:67 +#: apps/member/models.py:68 msgid "External (EXT)" msgstr "Externe (EXT)" -#: apps/member/models.py:74 +#: apps/member/models.py:75 msgid "promotion" msgstr "promotion" -#: apps/member/models.py:75 +#: apps/member/models.py:76 msgid "Year of entry to the school (None if not ENS student)" msgstr "Année d'entrée dans l'école (None si non-étudiant·e de l'ENS)" -#: apps/member/models.py:79 templates/member/profile_info.html:32 +#: apps/member/models.py:80 templates/member/profile_info.html:32 #: templates/registration/future_profile_detail.html:37 #: templates/wei/weimembership_form.html:45 msgid "address" msgstr "adresse" -#: apps/member/models.py:86 +#: apps/member/models.py:87 #: templates/registration/future_profile_detail.html:43 #: templates/wei/weimembership_form.html:51 msgid "paid" msgstr "payé" -#: apps/member/models.py:87 +#: apps/member/models.py:88 msgid "Tells if the user receive a salary." msgstr "Indique si l'utilisateur perçoit un salaire." -#: apps/member/models.py:92 +#: apps/member/models.py:93 msgid "email confirmed" msgstr "adresse email confirmée" -#: apps/member/models.py:97 +#: apps/member/models.py:98 msgid "registration valid" msgstr "inscription valid" -#: apps/member/models.py:126 apps/member/models.py:127 +#: apps/member/models.py:127 apps/member/models.py:128 msgid "user profile" msgstr "profil utilisateur" -#: apps/member/models.py:134 +#: apps/member/models.py:135 msgid "Activate your Note Kfet account" msgstr "Activez votre compte Note Kfet" -#: apps/member/models.py:163 templates/member/club_info.html:57 +#: apps/member/models.py:164 templates/member/club_info.html:57 #: templates/registration/future_profile_detail.html:22 #: templates/wei/weiclub_info.html:52 templates/wei/weimembership_form.html:24 msgid "email" msgstr "courriel" -#: apps/member/models.py:170 +#: apps/member/models.py:171 msgid "parent club" msgstr "club parent" -#: apps/member/models.py:179 +#: apps/member/models.py:180 msgid "require memberships" msgstr "nécessite des adhésions" -#: apps/member/models.py:180 +#: apps/member/models.py:181 msgid "Uncheck if this club don't require memberships." msgstr "Décochez si ce club n'utilise pas d'adhésions." -#: apps/member/models.py:196 templates/member/club_info.html:33 +#: apps/member/models.py:197 templates/member/club_info.html:33 msgid "membership duration" msgstr "durée de l'adhésion" -#: apps/member/models.py:197 +#: apps/member/models.py:198 msgid "The longest time (in days) a membership can last (NULL = infinite)." msgstr "La durée maximale (en jours) d'une adhésion (NULL = infinie)." -#: apps/member/models.py:204 templates/member/club_info.html:23 +#: apps/member/models.py:205 templates/member/club_info.html:23 msgid "membership start" msgstr "début de l'adhésion" -#: apps/member/models.py:205 +#: apps/member/models.py:206 msgid "How long after January 1st the members can renew their membership." msgstr "" "Combien de temps après le 1er Janvier les adhérents peuvent renouveler leur " "adhésion." -#: apps/member/models.py:212 templates/member/club_info.html:28 +#: apps/member/models.py:213 templates/member/club_info.html:28 msgid "membership end" msgstr "fin de l'adhésion" -#: apps/member/models.py:213 +#: apps/member/models.py:214 msgid "" "How long the membership can last after January 1st of the next year after " "members can renew their membership." @@ -528,46 +533,46 @@ msgstr "" "Combien de temps l'adhésion peut durer après le 1er Janvier de l'année " "suivante avant que les adhérents peuvent renouveler leur adhésion." -#: apps/member/models.py:247 apps/member/models.py:272 +#: apps/member/models.py:248 apps/member/models.py:273 #: apps/note/models/notes.py:163 msgid "club" msgstr "club" -#: apps/member/models.py:248 +#: apps/member/models.py:249 msgid "clubs" msgstr "clubs" -#: apps/member/models.py:282 +#: apps/member/models.py:283 msgid "membership starts on" msgstr "l'adhésion commence le" -#: apps/member/models.py:286 +#: apps/member/models.py:287 msgid "membership ends on" msgstr "l'adhésion finit le" -#: apps/member/models.py:310 apps/member/views.py:540 apps/wei/views.py:798 -msgid "User is not a member of the parent club" -msgstr "L'utilisateur n'est pas membre du club parent" - -#: apps/member/models.py:317 +#: apps/member/models.py:339 #, python-brace-format msgid "The role {role} does not apply to the club {club}." msgstr "Le rôle {role} ne s'applique pas au club {club}." -#: apps/member/models.py:328 apps/member/views.py:549 +#: apps/member/models.py:350 apps/member/views.py:583 msgid "User is already a member of the club" msgstr "L'utilisateur est déjà membre du club" -#: apps/member/models.py:379 +#: apps/member/models.py:386 +msgid "User is not a member of the parent club" +msgstr "L'utilisateur n'est pas membre du club parent" + +#: apps/member/models.py:439 #, python-brace-format msgid "Membership of {user} for the club {club}" msgstr "Adhésion de {user} pour le club {club}" -#: apps/member/models.py:382 +#: apps/member/models.py:442 msgid "membership" msgstr "adhésion" -#: apps/member/models.py:383 +#: apps/member/models.py:443 msgid "memberships" msgstr "adhésions" @@ -625,7 +630,7 @@ msgstr "Modifier le club" msgid "Add new member to the club" msgstr "Ajouter un nouveau membre au club" -#: apps/member/views.py:530 apps/wei/views.py:783 +#: apps/member/views.py:574 apps/wei/views.py:862 msgid "" "This user don't have enough money to join this club, and can't have a " "negative balance." @@ -633,25 +638,25 @@ msgstr "" "Cet utilisateur n'a pas assez d'argent pour rejoindre ce club et ne peut pas " "avoir un solde négatif." -#: apps/member/views.py:553 +#: apps/member/views.py:587 msgid "The membership must start after {:%m-%d-%Y}." msgstr "L'adhésion doit commencer après le {:%d/%m/%Y}." -#: apps/member/views.py:558 +#: apps/member/views.py:592 msgid "The membership must begin before {:%m-%d-%Y}." msgstr "L'adhésion doit commencer avant le {:%d/%m/%Y}." -#: apps/member/views.py:575 apps/member/views.py:577 apps/member/views.py:579 +#: apps/member/views.py:609 apps/member/views.py:611 apps/member/views.py:613 #: apps/registration/views.py:290 apps/registration/views.py:292 -#: apps/registration/views.py:294 +#: apps/registration/views.py:294 apps/wei/views.py:867 apps/wei/views.py:871 msgid "This field is required." msgstr "Ce champ est requis." -#: apps/member/views.py:647 +#: apps/member/views.py:690 msgid "Manage roles of an user in the club" msgstr "Gérer les rôles d'un utilisateur dans le club" -#: apps/member/views.py:672 +#: apps/member/views.py:715 msgid "Members of the club" msgstr "Membres du club" @@ -950,13 +955,13 @@ msgstr "Cliquez pour valider" msgid "No reason specified" msgstr "Pas de motif spécifié" -#: apps/note/tables.py:139 apps/note/tables.py:167 apps/wei/tables.py:66 -#: templates/treasury/sogecredit_detail.html:59 +#: apps/note/tables.py:139 apps/note/tables.py:167 apps/wei/tables.py:74 +#: apps/wei/tables.py:100 templates/treasury/sogecredit_detail.html:59 #: templates/wei/weiregistration_confirm_delete.html:32 msgid "Delete" msgstr "Supprimer" -#: apps/note/tables.py:162 apps/wei/tables.py:42 apps/wei/tables.py:43 +#: apps/note/tables.py:162 apps/wei/tables.py:46 apps/wei/tables.py:47 #: templates/member/club_info.html:67 templates/note/conso_form.html:128 #: templates/wei/bus_tables.html:15 templates/wei/busteam_tables.html:15 #: templates/wei/busteam_tables.html:33 templates/wei/weiclub_info.html:68 @@ -1190,7 +1195,7 @@ msgstr "Trésorerie" #: templates/activity/activity_form.html:9 #: templates/activity/activity_invite.html:8 #: templates/django_filters/rest_framework/form.html:5 -#: templates/member/add_members.html:14 templates/member/club_form.html:9 +#: templates/member/add_members.html:31 templates/member/club_form.html:9 #: templates/note/transactiontemplate_form.html:15 #: templates/treasury/invoice_form.html:46 templates/wei/bus_form.html:13 #: templates/wei/busteam_form.html:13 templates/wei/weiclub_form.html:15 @@ -1410,7 +1415,7 @@ msgstr "Joindre une transaction à une remise" msgid "List of credits from the Société générale" msgstr "Liste des crédits de la Société générale" -#: apps/treasury/views.py:384 +#: apps/treasury/views.py:379 msgid "Manage credits from the Société générale" msgstr "Gérer les crédits de la Société générale" @@ -1419,12 +1424,12 @@ msgstr "Gérer les crédits de la Société générale" msgid "WEI" msgstr "WEI" -#: apps/wei/forms/registration.py:48 apps/wei/models.py:112 +#: apps/wei/forms/registration.py:50 apps/wei/models.py:112 #: apps/wei/models.py:297 msgid "bus" msgstr "Bus" -#: apps/wei/forms/registration.py:49 +#: apps/wei/forms/registration.py:51 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." @@ -1433,11 +1438,11 @@ msgstr "" "attribuer un bus et une équipe, en particulier si vous êtes un électron " "libre." -#: apps/wei/forms/registration.py:56 +#: apps/wei/forms/registration.py:58 msgid "Team" msgstr "Équipe" -#: apps/wei/forms/registration.py:58 +#: apps/wei/forms/registration.py:60 msgid "" "Leave this field empty if you won't be in a team (staff, bus chief, free " "electron)" @@ -1445,16 +1450,16 @@ msgstr "" "Laissez ce champ vide si vous ne serez pas dans une équipe (staff, chef de " "bus ou électron libre)" -#: apps/wei/forms/registration.py:64 apps/wei/forms/registration.py:74 +#: apps/wei/forms/registration.py:66 apps/wei/forms/registration.py:76 #: apps/wei/models.py:147 msgid "WEI Roles" msgstr "Rôles au WEI" -#: apps/wei/forms/registration.py:65 +#: apps/wei/forms/registration.py:67 msgid "Select the roles that you are interested in." msgstr "Sélectionnez les rôles qui vous intéressent." -#: apps/wei/forms/registration.py:81 +#: apps/wei/forms/registration.py:112 msgid "This team doesn't belong to the given bus." msgstr "Cette équipe n'appartient pas à ce bus." @@ -1624,97 +1629,97 @@ msgstr "adhésion au WEI" msgid "WEI memberships" msgstr "adhésions au WEI" -#: apps/wei/tables.py:53 apps/wei/tables.py:54 +#: apps/wei/tables.py:57 apps/wei/tables.py:58 apps/wei/tables.py:95 #: templates/treasury/sogecredit_detail.html:57 msgid "Validate" msgstr "Valider" -#: apps/wei/tables.py:96 +#: apps/wei/tables.py:125 msgid "Year" msgstr "Année" -#: apps/wei/tables.py:134 templates/wei/bus_tables.html:26 +#: apps/wei/tables.py:163 templates/wei/bus_tables.html:26 #: templates/wei/busteam_tables.html:43 msgid "Teams" msgstr "Équipes" -#: apps/wei/tables.py:143 apps/wei/tables.py:184 +#: apps/wei/tables.py:172 apps/wei/tables.py:213 msgid "Members count" msgstr "Nombre de membres" -#: apps/wei/tables.py:150 apps/wei/tables.py:181 +#: apps/wei/tables.py:179 apps/wei/tables.py:210 msgid "members" msgstr "adhérents" -#: apps/wei/views.py:56 +#: apps/wei/views.py:57 msgid "Search WEI" msgstr "Chercher un WEI" -#: apps/wei/views.py:74 templates/wei/weiclub_list.html:10 +#: apps/wei/views.py:75 templates/wei/weiclub_list.html:10 msgid "Create WEI" msgstr "Créer un WEI" -#: apps/wei/views.py:94 +#: apps/wei/views.py:95 msgid "WEI Detail" msgstr "Détails du WEI" -#: apps/wei/views.py:189 +#: apps/wei/views.py:190 msgid "View members of the WEI" msgstr "Voir les membres du WEI" -#: apps/wei/views.py:217 +#: apps/wei/views.py:218 msgid "Find WEI Membership" msgstr "Trouver une adhésion au WEI" -#: apps/wei/views.py:227 +#: apps/wei/views.py:228 msgid "View registrations to the WEI" msgstr "Voir les inscriptions au WEI" -#: apps/wei/views.py:251 +#: apps/wei/views.py:252 msgid "Find WEI Registration" msgstr "Trouver une inscription au WEI" -#: apps/wei/views.py:262 +#: apps/wei/views.py:263 msgid "Update the WEI" msgstr "Modifier le WEI" -#: apps/wei/views.py:283 +#: apps/wei/views.py:284 msgid "Create new bus" msgstr "Ajouter un nouveau bus" -#: apps/wei/views.py:314 +#: apps/wei/views.py:315 msgid "Update bus" msgstr "Modifier le bus" -#: apps/wei/views.py:344 +#: apps/wei/views.py:345 msgid "Manage bus" msgstr "Gérer le bus" -#: apps/wei/views.py:371 +#: apps/wei/views.py:372 msgid "Create new team" msgstr "Créer une nouvelle équipe" -#: apps/wei/views.py:403 +#: apps/wei/views.py:404 msgid "Update team" msgstr "Modifier l'équipe" -#: apps/wei/views.py:434 +#: apps/wei/views.py:435 msgid "Manage WEI team" msgstr "Gérer l'équipe WEI" -#: apps/wei/views.py:456 +#: apps/wei/views.py:457 msgid "Register first year student to the WEI" msgstr "Inscrire un 1A au WEI" -#: apps/wei/views.py:468 templates/wei/weiclub_info.html:62 +#: apps/wei/views.py:469 templates/wei/weiclub_info.html:62 msgid "Register 1A" msgstr "Inscrire un 1A" -#: apps/wei/views.py:489 apps/wei/views.py:560 +#: apps/wei/views.py:490 apps/wei/views.py:561 msgid "This user is already registered to this WEI." msgstr "Cette personne est déjà inscrite au WEI." -#: apps/wei/views.py:494 +#: apps/wei/views.py:495 msgid "" "This user can't be in her/his first year since he/she has already participed " "to a WEI." @@ -1722,39 +1727,39 @@ msgstr "" "Cet utilisateur ne peut pas être en première année puisqu'iel a déjà " "participé à un WEI." -#: apps/wei/views.py:511 +#: apps/wei/views.py:512 msgid "Register old student to the WEI" msgstr "Inscrire un 2A+ au WEI" -#: apps/wei/views.py:523 templates/wei/weiclub_info.html:65 +#: apps/wei/views.py:524 templates/wei/weiclub_info.html:65 msgid "Register 2A+" msgstr "Inscrire un 2A+" -#: apps/wei/views.py:542 apps/wei/views.py:627 +#: apps/wei/views.py:543 apps/wei/views.py:628 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:590 +#: apps/wei/views.py:591 msgid "Update WEI Registration" msgstr "Modifier l'inscription WEI" -#: apps/wei/views.py:677 +#: apps/wei/views.py:687 msgid "Delete WEI registration" msgstr "Supprimer l'inscription WEI" -#: apps/wei/views.py:688 +#: apps/wei/views.py:698 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:707 +#: apps/wei/views.py:717 msgid "Validate WEI registration" msgstr "Valider l'inscription WEI" -#: apps/wei/views.py:787 +#: apps/wei/views.py:856 msgid "This user didn't give her/his caution check." msgstr "Cet utilisateur n'a pas donné son chèque de caution." -#: apps/wei/views.py:830 apps/wei/views.py:883 apps/wei/views.py:893 +#: apps/wei/views.py:918 apps/wei/views.py:971 apps/wei/views.py:981 #: templates/wei/survey.html:12 templates/wei/survey_closed.html:12 #: templates/wei/survey_end.html:12 msgid "Survey WEI" @@ -1807,7 +1812,7 @@ msgstr "Page inexistante" msgid "" "The requested path <code>%(request_path)s</code> was not found on the server." msgstr "" -"The chemin demandé <code>%(request_path)s</code> n'a pas été trouvé sur le " +"Le chemin demandé <code>%(request_path)s</code> n'a pas été trouvé sur le " "serveur." #: templates/500.html:6 @@ -1926,13 +1931,33 @@ msgstr "" msgid "Field filters" msgstr "" +#: templates/member/add_members.html:15 +#, python-format +msgid "" +"The user is not a member of the club·s %(clubs)s. An additional fee of " +"%(pretty_fee)s will be charged to renew automatically the membership in this/" +"these club·s." +msgstr "" +"Cet utilisateur n'est pas membre du/des club·s parent·s %(clubs)s. Un " +"montant supplémentaire de%(pretty_fee)s sera débitée afin de renouveler " +"automatiquement l'adhésion dans ce·s club·s." + +#: templates/member/add_members.html:20 +#, python-format +msgid "" +"This club has parents %(clubs)s. An additional fee of %(pretty_fee)s will be " +"charged to adhere automatically to this/these club·s." +msgstr "" +"Ce club a pour parent·s %(clubs)s. Un coût supplémentaire de %(pretty_fee)s " +"peut être ajouté pour adhérer automatiquement à ce·s club·s." + #: templates/member/alias_update.html:5 msgid "Add alias" msgstr "Ajouter un alias" #: templates/member/autocomplete_model.html:11 msgid "Reset" -msgstr "" +msgstr "Réinitialiser" #: templates/member/club_info.html:17 msgid "Club Parent" @@ -2478,7 +2503,7 @@ msgid "" "validated, but no credit will be operated." msgstr "" "Si vous supprimez cette demande de crédit, alors toutes les transactions " -"d'adhésion seront aussi validées, but il n'y aura pas de transaction de " +"d'adhésion seront aussi validées, mais il n'y aura pas de transaction de " "crédit créée." #: templates/treasury/sogecredit_detail.html:37 @@ -2678,6 +2703,7 @@ msgstr "" "aura validé la création du compte, ou bien changer de moyen de paiement." #: templates/wei/weimembership_form.html:162 +#, python-format msgid "" "The note don't have enough money (%(balance)s, %(pretty_fee)s required). The " "registration may fail." @@ -2686,25 +2712,29 @@ msgstr "" "L'inscription va échouer." #: templates/wei/weimembership_form.html:169 -msgid "The note has enough money, the registration is possible." +#, fuzzy, python-format +#| msgid "The note has enough money, the registration is possible." +msgid "" +"The note has enough money (%(pretty_fee)s required), the registration is " +"possible." msgstr "La note a assez d'argent, l'inscription est possible." -#: templates/wei/weimembership_form.html:176 +#: templates/wei/weimembership_form.html:178 msgid "The user didn't give her/his caution check." msgstr "L'utilisateur n'a pas donné son chèque de caution." -#: templates/wei/weimembership_form.html:184 +#: templates/wei/weimembership_form.html:186 +#, fuzzy +#| msgid "" +#| "You must also go to the Kfet to pay your membership. The WEI registration " +#| "includes the BDE membership." msgid "" -"This user is not a member of the Kfet club for the comming year. Please " -"adhere <a href=\"%(future_user_detail)s\">here if he/she is in her/his first " -"year</a> or <a href=\"%(club_detail)s\">here if he/she was an old member</a> " -"before you validate the registration of the WEI." +"This user is not a member of the Kfet club for the coming year. The " +"membership will be processed automatically, the WEI registration includes " +"the membership fee." msgstr "" -"Cet utilisateur n'est pas membre du club Kfet pour l'année à venir. Merci de le faire adhérer\n" -"<a href=\"%(future_user_detail)s\">ici s'iel est en première année</a>\n" -"ou <a href=\"%(club_detail)s\">ici s'iel est un ancien membre</a> avant de " -"valider\n" -"l'inscription au WEI." +"Vous devrez également vous rendre à la Kfet pour payer votre adhésion. " +"L'inscription au WEI inclut l'adhésion au BDE." #: templates/wei/weimembership_list.html:24 msgid "View unvalidated registrations..." @@ -2730,3 +2760,16 @@ msgstr "Il n'y a pas de pré-inscription en attente avec cette entrée." #: templates/wei/weiregistration_list.html:24 msgid "View validated memberships..." msgstr "Voir les adhésions validées ..." + +#~ msgid "" +#~ "This user is not a member of the Kfet club for the comming year. Please " +#~ "adhere <a href=\"%(future_user_detail)s\">here if he/she is in her/his " +#~ "first year</a> or <a href=\"%(club_detail)s\">here if he/she was an old " +#~ "member</a> before you validate the registration of the WEI." +#~ msgstr "" +#~ "Cet utilisateur n'est pas membre du club Kfet pour l'année à venir. Merci " +#~ "de le faire adhérer\n" +#~ "<a href=\"%(future_user_detail)s\">ici s'iel est en première année</a>\n" +#~ "ou <a href=\"%(club_detail)s\">ici s'iel est un ancien membre</a> avant " +#~ "de valider\n" +#~ "l'inscription au WEI." diff --git a/templates/base.html b/templates/base.html index 9b1f463e803136a9e6d49bbb3dfddb4c231900ee..8b45d914d096acce9043575c591ef70df09dca2e 100644 --- a/templates/base.html +++ b/templates/base.html @@ -124,27 +124,27 @@ SPDX-License-Identifier: GPL-3.0-or-later <a class="nav-link" href="{% url 'wei:current_wei_detail' %}"><i class="fas fa-bus"></i> {% trans 'WEI' %}</a> </li> {% endif %} - {% if user.is_authenticated %} + {% if request.user.is_authenticated %} <li class="nav-item active"> <a class="nav-link" href="{% url 'permission:rights' %}"><i class="fas fa-balance-scale"></i> {% trans 'Rights' %}</a> </li> {% endif %} - {% if user.is_staff and ""|has_perm:user %} + {% if request.user.is_staff and ""|has_perm:user %} <li class="nav-item active"> <a data-turbolinks="false" class="nav-link" href="{% url 'admin:index' %}"><i class="fas fa-user-cog"></i> {% trans 'Admin' %}</a> </li> {% endif %} </ul> <ul class="navbar-nav ml-auto"> - {% if user.is_authenticated %} + {% if request.user.is_authenticated %} <li class="dropdown"> <a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <i class="fas fa-user"></i> - <span id="user_balance">{{ user.username }} ({{ user.note.balance | pretty_money }})</span> + <span id="user_balance">{{ request.user.username }} ({{ request.user.note.balance | pretty_money }})</span> </a> <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarDropdownMenuLink"> - <a class="dropdown-item" href="{% url 'member:user_detail' pk=user.pk %}"> + <a class="dropdown-item" href="{% url 'member:user_detail' pk=request.user.pk %}"> <i class="fas fa-user"></i> Mon compte </a> <a class="dropdown-item" href="{% url 'logout' %}"> @@ -168,7 +168,7 @@ SPDX-License-Identifier: GPL-3.0-or-later </div> </nav> <div class="container-fluid my-3" style="max-width: 1600px;"> - {% if user.is_authenticated and not user.profile.email_confirmed %} + {% if request.user.is_authenticated and not request.user.profile.email_confirmed %} <div class="alert alert-warning"> {% trans "Your e-mail address is not validated. Please check your mail inbox and click on the validation link." %} </div> diff --git a/templates/member/add_members.html b/templates/member/add_members.html index ad6f1f297a77ec7e2d58e401405fd0414f4a61ce..8f429541dbf8e6999a764f63e1c0b98510b17b64 100644 --- a/templates/member/add_members.html +++ b/templates/member/add_members.html @@ -2,17 +2,34 @@ {% load crispy_forms_tags %} {% load static %} {% load i18n %} +{% load pretty_money %} {% block profile_info %} {% include "member/club_info.html" %} {% endblock %} {% block profile_content %} -<form method="post" action=""> - {% csrf_token %} - {{ form|crispy }} - <button class="btn btn-primary" type="submit">{% trans "Submit" %}</button> -</form> + {% if additional_fee_renewal %} + <div class="alert alert-warning"> + {% if renewal %} + {% blocktrans trimmed with clubs=clubs_renewal|join:", " pretty_fee=additional_fee_renewal|pretty_money %} + The user is not a member of the club·s {{ clubs }}. An additional fee of {{ pretty_fee }} + will be charged to renew automatically the membership in this/these club·s. + {% endblocktrans %} + {% else %} + {% blocktrans trimmed with clubs=clubs_renewal|join:", " pretty_fee=additional_fee_renewal|pretty_money %} + This club has parents {{ clubs }}. An additional fee of {{ pretty_fee }} + will be charged to adhere automatically to this/these club·s. + {% endblocktrans %} + {% endif %} + </div> + {% endif %} + + <form method="post" action=""> + {% csrf_token %} + {{ form|crispy }} + <button class="btn btn-primary" type="submit">{% trans "Submit" %}</button> + </form> {% endblock %} {% block extrajavascript %} diff --git a/templates/member/club_detail.html b/templates/member/club_detail.html index fedd43fa85e392dd0d1015474b23bb607389fe6e..451e4d76090bc41b746a0ca061a5f8719a6881a9 100644 --- a/templates/member/club_detail.html +++ b/templates/member/club_detail.html @@ -14,7 +14,5 @@ $("#history_list").load("{% url 'member:club_detail' pk=object.pk %} #history_list"); $("#profile_infos").load("{% url 'member:club_detail' pk=object.pk %} #profile_infos"); } - - window.history.replaceState({}, document.title, location.pathname); </script> {% endblock %} diff --git a/templates/member/profile_detail.html b/templates/member/profile_detail.html index 04b15d3bdab67e6c375a956461b0b094a99140f1..297af21ca4214fd7d1c08c59de98ad9d4aa0c983 100644 --- a/templates/member/profile_detail.html +++ b/templates/member/profile_detail.html @@ -11,10 +11,8 @@ {% block extrajavascript %} <script> function refreshHistory() { - $("#history_list").load("{% url 'member:user_detail' pk=object.pk %} #history_list"); - $("#profile_infos").load("{% url 'member:user_detail' pk=object.pk %} #profile_infos"); + $("#history_list").load("{% url 'member:user_detail' pk=user_object.pk %} #history_list"); + $("#profile_infos").load("{% url 'member:user_detail' pk=user_object.pk %} #profile_infos"); } - - window.history.replaceState({}, document.title, location.pathname); </script> {% endblock %} diff --git a/templates/member/profile_info.html b/templates/member/profile_info.html index 35d3e4eaad15632003dfbe83c13ba8e3f01591e6..3694fde32a27ab2a43ffa7b7331ba113da28ef93 100644 --- a/templates/member/profile_info.html +++ b/templates/member/profile_info.html @@ -2,22 +2,22 @@ <div class="card bg-light shadow"> <div class="card-header text-center" > - <h4> {% trans "Account #" %} {{ user.pk }}</h4> + <h4> {% trans "Account #" %} {{ user_object.pk }}</h4> </div> <div class="card-top text-center"> - <a href="{% url 'member:user_update_pic' user.pk %}"> - <img src="{{ user.note.display_image.url }}" class="img-thumbnail mt-2" > + <a href="{% url 'member:user_update_pic' user_object.pk %}"> + <img src="{{ user_object.note.display_image.url }}" class="img-thumbnail mt-2" > </a> </div> <div class="card-body" id="profile_infos"> <dl class="row"> <dt class="col-xl-6">{% trans 'name'|capfirst %}, {% trans 'first name' %}</dt> - <dd class="col-xl-6">{{ user.last_name }} {{ user.first_name }}</dd> + <dd class="col-xl-6">{{ user_object.last_name }} {{ user_object.first_name }}</dd> <dt class="col-xl-6">{% trans 'username'|capfirst %}</dt> - <dd class="col-xl-6">{{ user.username }}</dd> + <dd class="col-xl-6">{{ user_object.username }}</dd> - {% if user.pk == user.pk %} + {% if user_object.pk == user_object.pk %} <dt class="col-xl-6">{% trans 'password'|capfirst %}</dt> <dd class="col-xl-6"> <a class="small" href="{% url 'password_change' %}"> @@ -27,25 +27,25 @@ {% endif %} <dt class="col-xl-6">{% trans 'section'|capfirst %}</dt> - <dd class="col-xl-6">{{ user.profile.section }}</dd> + <dd class="col-xl-6">{{ user_object.profile.section }}</dd> <dt class="col-xl-6">{% trans 'address'|capfirst %}</dt> - <dd class="col-xl-6">{{ user.profile.address }}</dd> + <dd class="col-xl-6">{{ user_object.profile.address }}</dd> <dt class="col-xl-6">{% trans 'balance'|capfirst %}</dt> - <dd class="col-xl-6">{{ user.note.balance | pretty_money }}</dd> + <dd class="col-xl-6">{{ user_object.note.balance | pretty_money }}</dd> - <dt class="col-xl-6"> <a href="{% url 'member:user_alias' user.pk %}">{% trans 'aliases'|capfirst %}</a></dt> - <dd class="col-xl-6 text-truncate">{{ user.note.alias_set.all|join:", " }}</dd> + <dt class="col-xl-6"> <a href="{% url 'member:user_alias' user_object.pk %}">{% trans 'aliases'|capfirst %}</a></dt> + <dd class="col-xl-6 text-truncate">{{ user_object.note.alias_set.all|join:", " }}</dd> </dl> - {% if user.pk == user.pk %} + {% if user_object.pk == user_object.pk %} <a class="small" href="{% url 'member:auth_token' %}">{% trans 'Manage auth token' %}</a> {% endif %} </div> <div class="card-footer text-center"> - <a class="btn btn-primary btn-sm" href="{% url 'member:user_update_profile' user.pk %}">{% trans 'Update Profile' %}</a> - {% url 'member:user_detail' user.pk as user_profile_url %} + <a class="btn btn-primary btn-sm" href="{% url 'member:user_update_profile' user_object.pk %}">{% trans 'Update Profile' %}</a> + {% url 'member:user_detail' user_object.pk as user_profile_url %} {%if request.path_info != user_profile_url %} <a class="btn btn-primary btn-sm" href="{{ user_profile_url }}">{% trans 'View Profile' %}</a> {% endif %} diff --git a/templates/member/profile_tables.html b/templates/member/profile_tables.html index ff66155a1b158f51fd7c849d240697cb46cbe7e4..6c4cf662bfe7a06420b519763c64331fa35d9d3e 100644 --- a/templates/member/profile_tables.html +++ b/templates/member/profile_tables.html @@ -2,10 +2,10 @@ {% load i18n %} {% load perms %} -{% if not object.profile.email_confirmed and "member.change_profile_email_confirmed"|has_perm:user.profile %} +{% if not object.profile.email_confirmed and "member.change_profile_email_confirmed"|has_perm:user_object.profile %} <div class="alert alert-warning"> {% trans "This user doesn't have confirmed his/her e-mail address." %} - <a href="{% url "registration:email_validation_resend" pk=user.pk %}">{% trans "Click here to resend a validation link." %}</a> + <a href="{% url "registration:email_validation_resend" pk=user_object.pk %}">{% trans "Click here to resend a validation link." %}</a> </div> {% endif %} @@ -22,7 +22,7 @@ <div class="card"> <div class="card-header position-relative" id="historyListHeading"> - <a class="stretched-link font-weight-bold" {% if "note.view_note"|has_perm:user.note %} href="{% url 'note:transactions' pk=user.note.pk %}" {% endif %}> + <a class="stretched-link font-weight-bold" {% if "note.view_note"|has_perm:user_object.note %} href="{% url 'note:transactions' pk=user_object.note.pk %}" {% endif %}> <i class="fa fa-euro"></i> {% trans "Transaction history" %} </a> </div> diff --git a/templates/wei/weiclub_detail.html b/templates/wei/weiclub_detail.html index 72c70aa5ee9344aeb401e72f0e033b1b53772131..d0e8f8e90313e0201c2883f5e8b90a50ea669d02 100644 --- a/templates/wei/weiclub_detail.html +++ b/templates/wei/weiclub_detail.html @@ -15,6 +15,16 @@ $("#profile_infos").load("{% url 'wei:wei_detail' pk=object.pk %} #profile_infos"); } - window.history.replaceState({}, document.title, location.pathname); + $(document).ready(function() { + $(".no-perm").parent().addClass("d-none"); + if ($("a[data-type='validate-membership']:not(.d-none)").length === 0) { + $("a[data-type='validate-membership']").parent().addClass("d-none"); + $("#validate-membership-header").addClass("d-none"); + } + if ($("a[data-type='delete-membership']:not(.d-none)").length === 0) { + $("a[data-type='delete-membership']").parent().addClass("d-none"); + $("#delete-membership-header").addClass("d-none"); + } + }); </script> {% endblock %} diff --git a/templates/wei/weimembership_form.html b/templates/wei/weimembership_form.html index 7c74457b1231db86ddc1f0472143da0648ec0e2c..1e26414babdfb6035842aa8fea053fdfd50cec05 100644 --- a/templates/wei/weimembership_form.html +++ b/templates/wei/weimembership_form.html @@ -166,7 +166,9 @@ </div> {% else %} <div class="alert alert-success"> - {% trans "The note has enough money, the registration is possible." %} + {% blocktrans trimmed with pretty_fee=fee|pretty_money %} + The note has enough money ({{ pretty_fee }} required), the registration is possible. + {% endblocktrans %} </div> {% endif %} {% endif %} @@ -178,14 +180,12 @@ {% endif %} {% if not kfet_member %} - <div class="alert alert-danger"> + <div class="alert alert-warning"> {% url 'registration:future_user_detail' pk=registration.user.pk as future_user_detail %} {% url 'member:club_detail' pk=club.parent_club.parent_club.pk as club_detail %} {% blocktrans trimmed %} - This user is not a member of the Kfet club for the comming year. Please adhere - <a href="{{ future_user_detail }}">here if he/she is in her/his first year</a> - or <a href="{{ club_detail }}">here if he/she was an old member</a> before you validate - the registration of the WEI. + This user is not a member of the Kfet club for the coming year. The membership will be + processed automatically, the WEI registration includes the membership fee. {% endblocktrans %} </div> {% endif %} diff --git a/templates/wei/weiregistration_list.html b/templates/wei/weiregistration_list.html index 05626dd20061b78034218146dfd3f54b1279f972..88c217aa44f6428b3a36e6195f7fecde10034d27 100644 --- a/templates/wei/weiregistration_list.html +++ b/templates/wei/weiregistration_list.html @@ -41,6 +41,16 @@ } searchbar_obj.keyup(reloadTable); + + $(".no-perm").parent().addClass("d-none"); + if ($("a[data-type='validate-membership']:not(.d-none)").length === 0) { + $("a[data-type='validate-membership']").parent().addClass("d-none"); + $("#validate-membership-header").addClass("d-none"); + } + if ($("a[data-type='delete-membership']:not(.d-none)").length === 0) { + $("a[data-type='delete-membership']").parent().addClass("d-none"); + $("#delete-membership-header").addClass("d-none"); + } }); </script> {% endblock %}