diff --git a/apps/member/fixtures/initial.json b/apps/member/fixtures/initial.json index 649cbbc1..094d2c3f 100644 --- a/apps/member/fixtures/initial.json +++ b/apps/member/fixtures/initial.json @@ -7,9 +7,9 @@ "email": "tresorerie.bde@example.com", "require_memberships": true, "membership_fee": 500, - "membership_duration": "396 00:00:00", - "membership_start": "213 00:00:00", - "membership_end": "273 00:00:00" + "membership_duration": 396, + "membership_start": "2019-08-31", + "membership_end": "2020-09-30" } }, { @@ -20,9 +20,9 @@ "email": "tresorerie.bde@example.com", "require_memberships": true, "membership_fee": 3500, - "membership_duration": "396 00:00:00", - "membership_start": "213 00:00:00", - "membership_end": "273 00:00:00" + "membership_duration": 396, + "membership_start": "2019-08-31", + "membership_end": "2020-09-30" } } ] diff --git a/apps/member/forms.py b/apps/member/forms.py index 80c2b49e..9ac4ffa9 100644 --- a/apps/member/forms.py +++ b/apps/member/forms.py @@ -1,13 +1,10 @@ # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later -from crispy_forms.bootstrap import Div -from crispy_forms.helper import FormHelper -from crispy_forms.layout import Layout from django import forms from django.contrib.auth.forms import UserCreationForm, AuthenticationForm from django.contrib.auth.models import User -from note_kfet.inputs import Autocomplete, AmountInput +from note_kfet.inputs import Autocomplete, AmountInput, DatePickerInput from permission.models import PermissionMask from .models import Profile, Club, Membership @@ -55,6 +52,8 @@ class ClubForm(forms.ModelForm): 'api_url': '/api/members/club/', } ), + "membership_start": DatePickerInput(), + "membership_end": DatePickerInput(), } @@ -80,28 +79,5 @@ class MembershipForm(forms.ModelForm): 'placeholder': 'Nom ...', }, ), + 'date_start': DatePickerInput(), } - - -MemberFormSet = forms.modelformset_factory( - Membership, - form=MembershipForm, - extra=2, - can_delete=True, -) - - -class FormSetHelper(FormHelper): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.form_tag = False - self.form_method = 'POST' - self.form_class = 'form-inline' - # self.template = 'bootstrap/table_inline_formset.html' - self.layout = Layout( - Div( - Div('user', css_class='col-sm-2'), - Div('roles', css_class='col-sm-2'), - Div('date_start', css_class='col-sm-2'), - css_class="row formset-row", - )) diff --git a/apps/member/models.py b/apps/member/models.py index 377cc010..8906af9c 100644 --- a/apps/member/models.py +++ b/apps/member/models.py @@ -83,27 +83,31 @@ class Club(models.Model): require_memberships = models.BooleanField( default=True, verbose_name=_("require memberships"), + help_text=_("Uncheck if this club don't require memberships."), ) membership_fee = models.PositiveIntegerField( default=0, verbose_name=_('membership fee'), ) - membership_duration = models.DurationField( + + membership_duration = models.IntegerField( blank=True, null=True, verbose_name=_('membership duration'), - help_text=_('The longest time a membership can last ' + help_text=_('The longest time (in days) a membership can last ' '(NULL = infinite).'), ) - membership_start = models.DurationField( + + membership_start = models.DateField( blank=True, null=True, verbose_name=_('membership start'), help_text=_('How long after January 1st the members can renew ' 'their membership.'), ) - membership_end = models.DurationField( + + membership_end = models.DateField( blank=True, null=True, verbose_name=_('membership end'), @@ -112,6 +116,20 @@ class Club(models.Model): 'membership.'), ) + def update_membership_dates(self): + """ + This function is called each time the club detail view is displayed. + Update the year of the membership dates. + """ + today = datetime.date.today() + + if (today - self.membership_start).days >= 365: + self.membership_start = datetime.date(self.membership_start.year + 1, + self.membership_start.month, self.membership_start.day) + self.membership_end = datetime.date(self.membership_end.year + 1, + self.membership_end.month, self.membership_end.day) + self.save(force_update=True) + def save(self, force_insert=False, force_update=False, using=None, update_fields=None): if not self.require_memberships: @@ -135,9 +153,6 @@ class Club(models.Model): class Role(models.Model): """ Role that an :model:`auth.User` can have in a :model:`member.Club` - - TODO: Integrate the right management, and create some standard Roles at the - creation of the club. """ name = models.CharField( verbose_name=_('name'), @@ -162,21 +177,25 @@ class Membership(models.Model): settings.AUTH_USER_MODEL, on_delete=models.PROTECT, ) + club = models.ForeignKey( Club, on_delete=models.PROTECT, ) - roles = models.ForeignKey( + + roles = models.ManyToManyField( Role, - on_delete=models.PROTECT, ) + date_start = models.DateField( verbose_name=_('membership starts on'), ) + date_end = models.DateField( verbose_name=_('membership ends on'), null=True, ) + fee = models.PositiveIntegerField( verbose_name=_('fee'), ) @@ -189,8 +208,16 @@ class Membership(models.Model): def save(self, *args, **kwargs): if self.club.parent_club is not None: - if not Membership.objects.filter(user=self.user, club=self.club.parent_club): + 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')) + + created = not self.pk + if created: + self.fee = self.club.membership_fee + self.date_end = self.date_start + datetime.timedelta(days=self.club.membership_duration) + if self.date_end > self.club.membership_end: + self.date_end = self.club.membership_end + super().save(*args, **kwargs) class Meta: diff --git a/apps/member/views.py b/apps/member/views.py index 9ca7d76a..651dfc35 100644 --- a/apps/member/views.py +++ b/apps/member/views.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: GPL-3.0-or-later import io +from datetime import datetime from PIL import Image from django.conf import settings @@ -24,8 +25,7 @@ from permission.backends import PermissionBackend from permission.views import ProtectQuerysetMixin from .filters import UserFilter, UserFilterFormHelper -from .forms import SignUpForm, ProfileForm, ClubForm, MembershipForm, MemberFormSet, FormSetHelper, \ - CustomAuthenticationForm +from .forms import SignUpForm, ProfileForm, ClubForm, MembershipForm, CustomAuthenticationForm from .models import Club, Membership from .tables import ClubTable, UserTable @@ -281,13 +281,19 @@ class ClubDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) + club = context["club"] + if PermissionBackend().has_perm(self.request.user, "member.change_club_membership_start", club): + club.update_membership_dates() + club_transactions = Transaction.objects.all().filter(Q(source=club.note) | Q(destination=club.note))\ .filter(PermissionBackend.filter_queryset(self.request.user, Transaction, "view")).order_by('-id') context['history_list'] = HistoryTable(club_transactions) - club_member = Membership.objects.filter(club=club)\ - .filter(PermissionBackend.filter_queryset(self.request.user, Membership, "view")).all() - # TODO: consider only valid Membership + club_member = Membership.objects.filter( + club=club, + date_start__lte=datetime.now().date(), + date_end__gte=datetime.now().date(), + ).filter(PermissionBackend.filter_queryset(self.request.user, Membership, "view")).all() context['member_list'] = club_member return context @@ -328,31 +334,20 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView): form_class = MembershipForm template_name = 'member/add_members.html' - def get_queryset(self, **kwargs): - return super().get_queryset().filter(PermissionBackend.filter_queryset(self.request.user, Membership, "view") - | PermissionBackend.filter_queryset(self.request.user, Membership, - "change")) - def get_context_data(self, **kwargs): club = Club.objects.filter(PermissionBackend.filter_queryset(self.request.user, Club, "view"))\ .get(pk=self.kwargs["pk"]) context = super().get_context_data(**kwargs) - context['formset'] = MemberFormSet() - context['helper'] = FormSetHelper() context['club'] = club context['no_cache'] = True return context - def post(self, request, *args, **kwargs): - return - # TODO: Implement POST - # formset = MembershipFormset(request.POST) - # if formset.is_valid(): - # return self.form_valid(formset) - # else: - # return self.form_invalid(formset) + def form_valid(self, form): + club = Club.objects.filter(PermissionBackend.filter_queryset(self.request.user, Club, "view"))\ + .get(pk=self.kwargs["pk"]) + form.instance.club = club + return super().form_valid(form) - def form_valid(self, formset): - formset.save() - return super().form_valid(formset) + def get_success_url(self): + return reverse_lazy('member:club_detail', kwargs={'pk': self.object.club.id}) diff --git a/apps/permission/backends.py b/apps/permission/backends.py index 30a273cc..f478cd5d 100644 --- a/apps/permission/backends.py +++ b/apps/permission/backends.py @@ -32,6 +32,7 @@ class PermissionBackend(ModelBackend): for permission in Permission.objects.annotate(club=F("rolepermissions__role__membership__club")) \ .filter( rolepermissions__role__membership__user=user, + rolepermissions__role__membership__valid=True, model__app_label=model.app_label, # For polymorphic models, we don't filter on model type type=type, ).all(): diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index 695bdf95..a4bfb939 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/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-03-31 04:16+0200\n" +"POT-Creation-Date: 2020-03-31 23:49+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -44,11 +44,10 @@ msgid "You can't invite more than 3 people to this activity." msgstr "" #: apps/activity/models.py:23 apps/activity/models.py:48 -#: apps/member/models.py:64 apps/member/models.py:122 -#: apps/note/models/notes.py:186 apps/note/models/notes.py:224 -#: apps/note/models/transactions.py:24 apps/note/models/transactions.py:44 -#: apps/note/models/transactions.py:231 templates/member/club_info.html:13 -#: templates/member/profile_info.html:14 +#: apps/member/models.py:64 apps/member/models.py:158 +#: apps/note/models/notes.py:188 apps/note/models/transactions.py:24 +#: apps/note/models/transactions.py:44 apps/note/models/transactions.py:231 +#: templates/member/club_info.html:13 templates/member/profile_info.html:14 msgid "name" msgstr "" @@ -73,14 +72,14 @@ msgstr "" msgid "description" msgstr "" -#: apps/activity/models.py:60 apps/note/models/notes.py:166 +#: apps/activity/models.py:60 apps/note/models/notes.py:164 #: apps/note/models/transactions.py:62 #: templates/activity/activity_detail.html:19 msgid "type" msgstr "" #: apps/activity/models.py:66 apps/logs/models.py:21 -#: apps/note/models/notes.py:119 +#: apps/note/models/notes.py:117 msgid "user" msgstr "" @@ -89,7 +88,7 @@ msgid "organizer" msgstr "" #: apps/activity/models.py:82 apps/activity/models.py:131 apps/note/apps.py:14 -#: apps/note/models/notes.py:60 +#: apps/note/models/notes.py:58 msgid "note" msgstr "" @@ -179,7 +178,7 @@ msgstr "" msgid "First name" msgstr "" -#: apps/activity/tables.py:81 apps/note/models/notes.py:69 +#: apps/activity/tables.py:81 apps/note/models/notes.py:67 msgid "Note" msgstr "" @@ -227,12 +226,12 @@ msgstr "" msgid "create" msgstr "" -#: apps/logs/models.py:61 apps/note/tables.py:160 +#: apps/logs/models.py:61 apps/note/tables.py:142 #: templates/activity/activity_detail.html:67 msgid "edit" msgstr "" -#: apps/logs/models.py:62 apps/note/tables.py:120 apps/note/tables.py:164 +#: apps/logs/models.py:62 apps/note/tables.py:120 apps/note/tables.py:146 msgid "delete" msgstr "" @@ -276,7 +275,7 @@ msgstr "" msgid "user profile" msgstr "" -#: apps/member/models.py:69 templates/member/club_info.html:36 +#: apps/member/models.py:69 templates/member/club_info.html:38 msgid "email" msgstr "" @@ -284,90 +283,97 @@ msgstr "" msgid "parent club" msgstr "" -#: apps/member/models.py:81 templates/member/club_info.html:30 -msgid "membership fee" -msgstr "" - -#: apps/member/models.py:85 templates/member/club_info.html:27 -msgid "membership duration" +#: apps/member/models.py:85 +msgid "require memberships" msgstr "" #: apps/member/models.py:86 -msgid "The longest time a membership can last (NULL = infinite)." +msgid "Uncheck if this club don't require memberships." msgstr "" -#: apps/member/models.py:91 templates/member/club_info.html:21 -msgid "membership start" +#: apps/member/models.py:91 templates/member/club_info.html:31 +msgid "membership fee" msgstr "" -#: apps/member/models.py:92 -msgid "How long after January 1st the members can renew their membership." -msgstr "" - -#: apps/member/models.py:97 templates/member/club_info.html:24 -msgid "membership end" +#: apps/member/models.py:97 templates/member/club_info.html:28 +msgid "membership duration" msgstr "" #: apps/member/models.py:98 +msgid "The longest time (in days) a membership can last (NULL = infinite)." +msgstr "" + +#: apps/member/models.py:105 templates/member/club_info.html:22 +msgid "membership start" +msgstr "" + +#: apps/member/models.py:106 +msgid "How long after January 1st the members can renew their membership." +msgstr "" + +#: apps/member/models.py:113 templates/member/club_info.html:25 +msgid "membership end" +msgstr "" + +#: apps/member/models.py:114 msgid "" "How long the membership can last after January 1st of the next year after " "members can renew their membership." msgstr "" -#: apps/member/models.py:104 apps/note/models/notes.py:141 -#: apps/note/models/notes.py:195 +#: apps/member/models.py:143 apps/note/models/notes.py:139 msgid "club" msgstr "" -#: apps/member/models.py:105 +#: apps/member/models.py:144 msgid "clubs" msgstr "" -#: apps/member/models.py:128 apps/permission/models.py:284 +#: apps/member/models.py:164 apps/permission/models.py:284 msgid "role" msgstr "" -#: apps/member/models.py:129 +#: apps/member/models.py:165 msgid "roles" msgstr "" -#: apps/member/models.py:153 +#: apps/member/models.py:191 msgid "membership starts on" msgstr "" -#: apps/member/models.py:156 +#: apps/member/models.py:195 msgid "membership ends on" msgstr "" -#: apps/member/models.py:160 +#: apps/member/models.py:200 msgid "fee" msgstr "" -#: apps/member/models.py:172 +#: apps/member/models.py:212 msgid "User is not a member of the parent club" msgstr "" -#: apps/member/models.py:176 +#: apps/member/models.py:224 msgid "membership" msgstr "" -#: apps/member/models.py:177 +#: apps/member/models.py:225 msgid "memberships" msgstr "" -#: apps/member/views.py:78 templates/member/profile_info.html:45 +#: apps/member/views.py:77 templates/member/profile_info.html:45 msgid "Update Profile" msgstr "" -#: apps/member/views.py:91 +#: apps/member/views.py:90 msgid "An alias with a similar name already exists." msgstr "" -#: apps/note/admin.py:128 apps/note/models/transactions.py:94 +#: apps/note/admin.py:120 apps/note/models/transactions.py:94 msgid "source" msgstr "" -#: apps/note/admin.py:136 apps/note/admin.py:164 +#: apps/note/admin.py:128 apps/note/admin.py:156 #: apps/note/models/transactions.py:53 apps/note/models/transactions.py:107 msgid "destination" msgstr "" @@ -380,104 +386,104 @@ msgstr "" msgid "Maximal size: 2MB" msgstr "" -#: apps/note/models/notes.py:29 +#: apps/note/models/notes.py:27 msgid "account balance" msgstr "" -#: apps/note/models/notes.py:30 +#: apps/note/models/notes.py:28 msgid "in centimes, money credited for this instance" msgstr "" -#: apps/note/models/notes.py:34 +#: apps/note/models/notes.py:32 msgid "last negative date" msgstr "" -#: apps/note/models/notes.py:35 +#: apps/note/models/notes.py:33 msgid "last time the balance was negative" msgstr "" -#: apps/note/models/notes.py:40 +#: apps/note/models/notes.py:38 msgid "active" msgstr "" -#: apps/note/models/notes.py:43 +#: apps/note/models/notes.py:41 msgid "" "Designates whether this note should be treated as active. Unselect this " "instead of deleting notes." msgstr "" -#: apps/note/models/notes.py:47 +#: apps/note/models/notes.py:45 msgid "display image" msgstr "" -#: apps/note/models/notes.py:55 apps/note/models/transactions.py:117 +#: apps/note/models/notes.py:53 apps/note/models/transactions.py:117 msgid "created at" msgstr "" -#: apps/note/models/notes.py:61 +#: apps/note/models/notes.py:59 msgid "notes" msgstr "" -#: apps/note/models/notes.py:79 apps/note/models/notes.py:103 +#: apps/note/models/notes.py:77 apps/note/models/notes.py:101 msgid "This alias is already taken." msgstr "" -#: apps/note/models/notes.py:123 +#: apps/note/models/notes.py:121 msgid "one's note" msgstr "" -#: apps/note/models/notes.py:124 +#: apps/note/models/notes.py:122 msgid "users note" msgstr "" -#: apps/note/models/notes.py:130 +#: apps/note/models/notes.py:128 #, python-format msgid "%(user)s's note" msgstr "" -#: apps/note/models/notes.py:145 +#: apps/note/models/notes.py:143 msgid "club note" msgstr "" -#: apps/note/models/notes.py:146 +#: apps/note/models/notes.py:144 msgid "clubs notes" msgstr "" -#: apps/note/models/notes.py:152 +#: apps/note/models/notes.py:150 #, python-format msgid "Note of %(club)s club" msgstr "" -#: apps/note/models/notes.py:172 +#: apps/note/models/notes.py:170 msgid "special note" msgstr "" -#: apps/note/models/notes.py:173 +#: apps/note/models/notes.py:171 msgid "special notes" msgstr "" -#: apps/note/models/notes.py:230 +#: apps/note/models/notes.py:194 msgid "Invalid alias" msgstr "" -#: apps/note/models/notes.py:246 +#: apps/note/models/notes.py:210 msgid "alias" msgstr "" -#: apps/note/models/notes.py:247 templates/member/club_info.html:33 +#: apps/note/models/notes.py:211 templates/member/club_info.html:35 #: templates/member/profile_info.html:36 msgid "aliases" msgstr "" -#: apps/note/models/notes.py:269 +#: apps/note/models/notes.py:233 msgid "Alias is too long." msgstr "" -#: apps/note/models/notes.py:274 +#: apps/note/models/notes.py:238 msgid "An alias with a similar name already exists: {} " msgstr "" -#: apps/note/models/notes.py:287 +#: apps/note/models/notes.py:251 msgid "You can't delete your main alias." msgstr "" @@ -614,7 +620,7 @@ msgstr "" #: templates/activity/activity_form.html:9 #: templates/activity/activity_invite.html:8 #: templates/django_filters/rest_framework/form.html:5 -#: templates/member/club_form.html:9 +#: templates/member/add_members.html:14 templates/member/club_form.html:9 #: templates/treasury/invoice_form.html:46 msgid "Submit" msgstr "" @@ -882,23 +888,23 @@ msgstr "" msgid "Club Parent" msgstr "" -#: templates/member/club_info.html:39 -msgid "linked notes" +#: templates/member/club_info.html:29 +msgid "days" msgstr "" -#: templates/member/club_info.html:44 +#: templates/member/club_info.html:43 msgid "Add member" msgstr "" -#: templates/member/club_info.html:45 templates/note/conso_form.html:121 +#: templates/member/club_info.html:44 templates/note/conso_form.html:121 msgid "Edit" msgstr "" -#: templates/member/club_info.html:46 +#: templates/member/club_info.html:45 msgid "Add roles" msgstr "" -#: templates/member/club_info.html:49 templates/member/profile_info.html:48 +#: templates/member/club_info.html:48 templates/member/profile_info.html:48 msgid "View Profile" msgstr "" diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po index d2a78d06..f4568da4 100644 --- a/locale/fr/LC_MESSAGES/django.po +++ b/locale/fr/LC_MESSAGES/django.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-03-31 04:16+0200\n" +"POT-Creation-Date: 2020-03-31 23:49+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -40,11 +40,10 @@ 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:23 apps/activity/models.py:48 -#: apps/member/models.py:64 apps/member/models.py:122 -#: apps/note/models/notes.py:186 apps/note/models/notes.py:224 -#: apps/note/models/transactions.py:24 apps/note/models/transactions.py:44 -#: apps/note/models/transactions.py:231 templates/member/club_info.html:13 -#: templates/member/profile_info.html:14 +#: apps/member/models.py:64 apps/member/models.py:158 +#: apps/note/models/notes.py:188 apps/note/models/transactions.py:24 +#: apps/note/models/transactions.py:44 apps/note/models/transactions.py:231 +#: templates/member/club_info.html:13 templates/member/profile_info.html:14 msgid "name" msgstr "nom" @@ -69,14 +68,14 @@ msgstr "types d'activité" msgid "description" msgstr "description" -#: apps/activity/models.py:60 apps/note/models/notes.py:166 +#: apps/activity/models.py:60 apps/note/models/notes.py:164 #: apps/note/models/transactions.py:62 #: templates/activity/activity_detail.html:19 msgid "type" msgstr "type" #: apps/activity/models.py:66 apps/logs/models.py:21 -#: apps/note/models/notes.py:119 +#: apps/note/models/notes.py:117 msgid "user" msgstr "utilisateur" @@ -85,7 +84,7 @@ msgid "organizer" msgstr "organisateur" #: apps/activity/models.py:82 apps/activity/models.py:131 apps/note/apps.py:14 -#: apps/note/models/notes.py:60 +#: apps/note/models/notes.py:58 msgid "note" msgstr "note" @@ -175,7 +174,7 @@ msgstr "Nom de famille" msgid "First name" msgstr "Prénom" -#: apps/activity/tables.py:81 apps/note/models/notes.py:69 +#: apps/activity/tables.py:81 apps/note/models/notes.py:67 msgid "Note" msgstr "Note" @@ -223,12 +222,12 @@ msgstr "Nouvelles données" msgid "create" msgstr "Créer" -#: apps/logs/models.py:61 apps/note/tables.py:160 +#: apps/logs/models.py:61 apps/note/tables.py:142 #: templates/activity/activity_detail.html:67 msgid "edit" msgstr "Modifier" -#: apps/logs/models.py:62 apps/note/tables.py:120 apps/note/tables.py:164 +#: apps/logs/models.py:62 apps/note/tables.py:120 apps/note/tables.py:146 msgid "delete" msgstr "Supprimer" @@ -272,7 +271,7 @@ msgstr "payé" msgid "user profile" msgstr "profil utilisateur" -#: apps/member/models.py:69 templates/member/club_info.html:36 +#: apps/member/models.py:69 templates/member/club_info.html:38 msgid "email" msgstr "courriel" @@ -280,33 +279,41 @@ msgstr "courriel" msgid "parent club" msgstr "club parent" -#: apps/member/models.py:81 templates/member/club_info.html:30 +#: apps/member/models.py:85 +msgid "require memberships" +msgstr "nécessite des adhésions" + +#: apps/member/models.py:86 +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:91 templates/member/club_info.html:31 msgid "membership fee" msgstr "cotisation pour adhérer" -#: apps/member/models.py:85 templates/member/club_info.html:27 +#: apps/member/models.py:97 templates/member/club_info.html:28 msgid "membership duration" msgstr "durée de l'adhésion" -#: apps/member/models.py:86 -msgid "The longest time a membership can last (NULL = infinite)." -msgstr "La durée maximale d'une adhésion (NULL = infinie)." +#: apps/member/models.py:98 +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:91 templates/member/club_info.html:21 +#: apps/member/models.py:105 templates/member/club_info.html:22 msgid "membership start" msgstr "début de l'adhésion" -#: apps/member/models.py:92 +#: apps/member/models.py:106 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:97 templates/member/club_info.html:24 +#: apps/member/models.py:113 templates/member/club_info.html:25 msgid "membership end" msgstr "fin de l'adhésion" -#: apps/member/models.py:98 +#: apps/member/models.py:114 msgid "" "How long the membership can last after January 1st of the next year after " "members can renew their membership." @@ -314,60 +321,59 @@ 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:104 apps/note/models/notes.py:141 -#: apps/note/models/notes.py:195 +#: apps/member/models.py:143 apps/note/models/notes.py:139 msgid "club" msgstr "club" -#: apps/member/models.py:105 +#: apps/member/models.py:144 msgid "clubs" msgstr "clubs" -#: apps/member/models.py:128 apps/permission/models.py:284 +#: apps/member/models.py:164 apps/permission/models.py:284 msgid "role" msgstr "rôle" -#: apps/member/models.py:129 +#: apps/member/models.py:165 msgid "roles" msgstr "rôles" -#: apps/member/models.py:153 +#: apps/member/models.py:191 msgid "membership starts on" msgstr "l'adhésion commence le" -#: apps/member/models.py:156 +#: apps/member/models.py:195 msgid "membership ends on" msgstr "l'adhésion finie le" -#: apps/member/models.py:160 +#: apps/member/models.py:200 msgid "fee" msgstr "cotisation" -#: apps/member/models.py:172 +#: apps/member/models.py:212 msgid "User is not a member of the parent club" msgstr "L'utilisateur n'est pas membre du club parent" -#: apps/member/models.py:176 +#: apps/member/models.py:224 msgid "membership" msgstr "adhésion" -#: apps/member/models.py:177 +#: apps/member/models.py:225 msgid "memberships" msgstr "adhésions" -#: apps/member/views.py:78 templates/member/profile_info.html:45 +#: apps/member/views.py:77 templates/member/profile_info.html:45 msgid "Update Profile" msgstr "Modifier le profil" -#: apps/member/views.py:91 +#: apps/member/views.py:90 msgid "An alias with a similar name already exists." msgstr "Un alias avec un nom similaire existe déjà." -#: apps/note/admin.py:128 apps/note/models/transactions.py:94 +#: apps/note/admin.py:120 apps/note/models/transactions.py:94 msgid "source" msgstr "source" -#: apps/note/admin.py:136 apps/note/admin.py:164 +#: apps/note/admin.py:128 apps/note/admin.py:156 #: apps/note/models/transactions.py:53 apps/note/models/transactions.py:107 msgid "destination" msgstr "destination" @@ -380,105 +386,105 @@ msgstr "Choisissez une image" msgid "Maximal size: 2MB" msgstr "Taille maximale : 2 Mo" -#: apps/note/models/notes.py:29 +#: apps/note/models/notes.py:27 msgid "account balance" msgstr "solde du compte" -#: apps/note/models/notes.py:30 +#: apps/note/models/notes.py:28 msgid "in centimes, money credited for this instance" msgstr "en centimes, argent crédité pour cette instance" -#: apps/note/models/notes.py:34 +#: apps/note/models/notes.py:32 msgid "last negative date" msgstr "dernier date de négatif" -#: apps/note/models/notes.py:35 +#: apps/note/models/notes.py:33 msgid "last time the balance was negative" msgstr "dernier instant où la note était en négatif" -#: apps/note/models/notes.py:40 +#: apps/note/models/notes.py:38 msgid "active" msgstr "actif" -#: apps/note/models/notes.py:43 +#: apps/note/models/notes.py:41 msgid "" "Designates whether this note should be treated as active. Unselect this " "instead of deleting notes." msgstr "" "Indique si la note est active. Désactiver cela plutôt que supprimer la note." -#: apps/note/models/notes.py:47 +#: apps/note/models/notes.py:45 msgid "display image" msgstr "image affichée" -#: apps/note/models/notes.py:55 apps/note/models/transactions.py:117 +#: apps/note/models/notes.py:53 apps/note/models/transactions.py:117 msgid "created at" msgstr "créée le" -#: apps/note/models/notes.py:61 +#: apps/note/models/notes.py:59 msgid "notes" msgstr "notes" -#: apps/note/models/notes.py:79 apps/note/models/notes.py:103 +#: apps/note/models/notes.py:77 apps/note/models/notes.py:101 msgid "This alias is already taken." msgstr "Cet alias est déjà pris." -#: apps/note/models/notes.py:123 +#: apps/note/models/notes.py:121 msgid "one's note" msgstr "note d'un utilisateur" -#: apps/note/models/notes.py:124 +#: apps/note/models/notes.py:122 msgid "users note" msgstr "notes des utilisateurs" -#: apps/note/models/notes.py:130 +#: apps/note/models/notes.py:128 #, python-format msgid "%(user)s's note" msgstr "Note de %(user)s" -#: apps/note/models/notes.py:145 +#: apps/note/models/notes.py:143 msgid "club note" msgstr "note d'un club" -#: apps/note/models/notes.py:146 +#: apps/note/models/notes.py:144 msgid "clubs notes" msgstr "notes des clubs" -#: apps/note/models/notes.py:152 +#: apps/note/models/notes.py:150 #, python-format msgid "Note of %(club)s club" msgstr "Note du club %(club)s" -#: apps/note/models/notes.py:172 +#: apps/note/models/notes.py:170 msgid "special note" msgstr "note spéciale" -#: apps/note/models/notes.py:173 +#: apps/note/models/notes.py:171 msgid "special notes" msgstr "notes spéciales" -#: apps/note/models/notes.py:230 +#: apps/note/models/notes.py:194 msgid "Invalid alias" msgstr "Alias invalide" -#: apps/note/models/notes.py:246 +#: apps/note/models/notes.py:210 msgid "alias" msgstr "alias" -#: apps/note/models/notes.py:247 templates/member/club_info.html:33 +#: apps/note/models/notes.py:211 templates/member/club_info.html:35 #: templates/member/profile_info.html:36 msgid "aliases" msgstr "alias" -#: apps/note/models/notes.py:269 +#: apps/note/models/notes.py:233 msgid "Alias is too long." msgstr "L'alias est trop long." -#: apps/note/models/notes.py:274 +#: apps/note/models/notes.py:238 msgid "An alias with a similar name already exists: {} " msgstr "Un alias avec un nom similaire existe déjà : {}" -#: apps/note/models/notes.py:287 +#: apps/note/models/notes.py:251 msgid "You can't delete your main alias." msgstr "Vous ne pouvez pas supprimer votre alias principal." @@ -615,7 +621,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/club_form.html:9 +#: templates/member/add_members.html:14 templates/member/club_form.html:9 #: templates/treasury/invoice_form.html:46 msgid "Submit" msgstr "Envoyer" @@ -885,23 +891,23 @@ msgstr "Ajouter un alias" msgid "Club Parent" msgstr "Club parent" -#: templates/member/club_info.html:39 -msgid "linked notes" -msgstr "notes liées" +#: templates/member/club_info.html:29 +msgid "days" +msgstr "jours" -#: templates/member/club_info.html:44 +#: templates/member/club_info.html:43 msgid "Add member" msgstr "Ajouter un membre" -#: templates/member/club_info.html:45 templates/note/conso_form.html:121 +#: templates/member/club_info.html:44 templates/note/conso_form.html:121 msgid "Edit" msgstr "Éditer" -#: templates/member/club_info.html:46 +#: templates/member/club_info.html:45 msgid "Add roles" msgstr "Ajouter des rôles" -#: templates/member/club_info.html:49 templates/member/profile_info.html:48 +#: templates/member/club_info.html:48 templates/member/profile_info.html:48 msgid "View Profile" msgstr "Voir le profil" @@ -1210,3 +1216,6 @@ msgstr "Il n'y a pas de transaction associée à une remise ouverte." #: templates/treasury/remittance_list.html:54 msgid "Closed remittances" msgstr "Remises fermées" + +#~ msgid "linked notes" +#~ msgstr "notes liées" diff --git a/note_kfet/inputs.py b/note_kfet/inputs.py index a3170007..81f55dee 100644 --- a/note_kfet/inputs.py +++ b/note_kfet/inputs.py @@ -1,6 +1,7 @@ # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later +import datetime from json import dumps as json_dumps from django.forms.widgets import DateTimeBaseInput, NumberInput, TextInput @@ -299,4 +300,4 @@ class YearPickerInput(BasePickerInput): def _link_to(self, linked_picker): """Customize the options when linked with other date-time input""" yformat = self.config['options']['format'].replace('-01-01', '-12-31') - self.config['options']['format'] = yformat \ No newline at end of file + self.config['options']['format'] = yformat diff --git a/templates/member/add_members.html b/templates/member/add_members.html index 8b57e7d4..c44440bf 100644 --- a/templates/member/add_members.html +++ b/templates/member/add_members.html @@ -1,29 +1,21 @@ {% extends "member/noteowner_detail.html" %} {% load crispy_forms_tags %} {% load static %} +{% load i18n %} {% block profile_info %} {% include "member/club_info.html" %} {% endblock %} -{% block profile_content %} +{% block profile_content %}
{% csrf_token %} - {% crispy formset helper %} -
- -
+ {{ form|crispy }} +
{% endblock %} {% block extrajavascript %} - {% endblock %} diff --git a/templates/member/club_info.html b/templates/member/club_info.html index 039583c5..da747ccd 100644 --- a/templates/member/club_info.html +++ b/templates/member/club_info.html @@ -26,7 +26,7 @@
{{ club.membership_end }}
{% trans 'membership duration'|capfirst %}
-
{{ club.membership_duration }}
+
{{ club.membership_duration }} {% trans "days" %}
{% trans 'membership fee'|capfirst %}
{{ club.membership_fee|pretty_money }}