Adhere to parent clubs automatically, adhere to Kfet automatically when registering to the WEI

This commit is contained in:
Yohann D'ANELLO 2020-08-04 20:04:41 +02:00
parent 358691aaa9
commit a096dc4427
16 changed files with 588 additions and 266 deletions

View File

@ -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,6 +349,43 @@ class Membership(models.Model):
).exists():
raise ValidationError(_('User is already a member of the club'))
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:
@ -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

View File

@ -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,25 +464,53 @@ 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")
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")
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, )
@ -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,22 +639,29 @@ 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
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__name="Kfet",
club=club,
user=user,
date_start__lte=datetime.today(),
date_end__gte=datetime.today(),
)
).order_by("-date_start")
if old_membership.filter(date_start__gte=club.membership_start).exists():
# Membership is already renewed
continue
membership = Membership(
club=kfet,
club=club,
user=user,
fee=kfet_fee,
date_start=old_membership.get().date_end + timedelta(days=1)
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

View File

@ -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()
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))
)
else:
qs = qs.none()
if "valid" in self.request.GET:
q = Q(credit_transaction=None)

View File

@ -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"]:

View File

@ -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'

View File

@ -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=registration.wei.parent_club.membership_start,
date_start__gte=kfet.membership_start,
).exists()
context["bde_member"] = Membership.objects.filter(
club__name=bde.name,
user=registration.user,
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:
# 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)
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 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 registration.soge_credit and user.note.balance < fee + credit_amount:
# Users must have money before registering to the WEI.
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 credit_amount:
if not last_name:
form.add_error('last_name', _("This field is required."))
return super().form_invalid(form)
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())

View File

@ -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."

View File

@ -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>

View File

@ -2,12 +2,29 @@
{% load crispy_forms_tags %}
{% load static %}
{% load i18n %}
{% load pretty_money %}
{% block profile_info %}
{% include "member/club_info.html" %}
{% endblock %}
{% block profile_content %}
{% 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 }}

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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>

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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 %}