Renew memberships

This commit is contained in:
Yohann D'ANELLO 2020-04-01 18:47:56 +02:00
parent 356c8588e7
commit 2853fe252b
7 changed files with 172 additions and 66 deletions

View File

@ -187,11 +187,13 @@ class Membership(models.Model):
user = models.ForeignKey(
User,
on_delete=models.PROTECT,
verbose_name=_("user"),
)
club = models.ForeignKey(
Club,
on_delete=models.PROTECT,
verbose_name=_("club"),
)
roles = models.ManyToManyField(
@ -237,6 +239,7 @@ class Membership(models.Model):
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:

View File

@ -1,8 +1,10 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from datetime import datetime
import django_tables2 as tables
from django.contrib.auth.models import User
from django.utils.translation import gettext_lazy as _
from django.urls import reverse_lazy
from django.utils.html import format_html
from note.templatetags.pretty_money import pretty_money
@ -49,8 +51,39 @@ class MembershipTable(tables.Table):
}
)
def render_fee(self, value):
return pretty_money(value)
def render_club(self, value):
s = value.name
if PermissionBackend().has_perm(get_current_authenticated_user(), "member.view_club", value):
s = format_html("<a href={url}>{name}</a>",
url=reverse_lazy('member:club_detail', kwargs={"pk": value.pk}), name=s)
return s
def render_fee(self, value, record):
t = pretty_money(value)
# If it is required and if the user has the right, the renew button is displayed.
if record.club.membership_start is not None:
if record.date_start < record.club.membership_start: # If the renew is available
if not Membership.objects.filter(
club=record.club,
user=record.user,
date_start__gte=record.club.membership_start,
date_end__lte=record.club.membership_end,
).exists(): # If the renew is not yet performed
empty_membership = Membership(
club=record.club,
user=record.user,
date_start=datetime.now().date(),
date_end=datetime.now().date(),
fee=0,
)
if PermissionBackend().has_perm(get_current_authenticated_user(),
"member:add_membership", empty_membership): # If the user has right
t = format_html(t + ' <a class="btn btn-warning" href="{url}">{text}</a>',
url=reverse_lazy('member:club_renew_membership',
kwargs={"pk": record.pk}), text=_("Renew"))
return t
def render_roles(self, record):
roles = record.roles.all()

View File

@ -10,10 +10,11 @@ urlpatterns = [
path('signup/', views.UserCreateView.as_view(), name="signup"),
path('club/', views.ClubListView.as_view(), name="club_list"),
path('club/create/', views.ClubCreateView.as_view(), name="club_create"),
path('club/<int:pk>/', views.ClubDetailView.as_view(), name="club_detail"),
path('club/<int:pk>/add_member/', views.ClubAddMemberView.as_view(), name="club_add_member"),
path('club/manage_roles/<int:pk>/', views.ClubManageRolesView.as_view(), name="club_manage_roles"),
path('club/create/', views.ClubCreateView.as_view(), name="club_create"),
path('club/renew_membership/<int:pk>/', views.ClubRenewMembershipView.as_view(), name="club_renew_membership"),
path('club/<int:pk>/update/', views.ClubUpdateView.as_view(), name="club_update"),
path('club/<int:pk>/update_pic/', views.ClubPictureUpdateView.as_view(), name="club_update_pic"),
path('club/<int:pk>/aliases/', views.ClubAliasView.as_view(), name="club_alias"),

View File

@ -2,19 +2,21 @@
# SPDX-License-Identifier: GPL-3.0-or-later
import io
from datetime import datetime
from datetime import datetime, timedelta
from PIL import Image
from django.conf import settings
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.models import User
from django.contrib.auth.views import LoginView
from django.core.exceptions import ValidationError
from django.db.models import Q
from django.forms import HiddenInput
from django.shortcuts import redirect
from django.urls import reverse_lazy
from django.utils.translation import gettext_lazy as _
from django.views.generic import CreateView, DetailView, UpdateView, TemplateView
from django.views.generic.base import View
from django.views.generic.edit import FormMixin
from django_tables2.views import SingleTableView
from rest_framework.authtoken.models import Token
@ -137,8 +139,8 @@ class UserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
Transaction.objects.all().filter(Q(source=user.note) | Q(destination=user.note)).order_by("-id")\
.filter(PermissionBackend.filter_queryset(self.request.user, Transaction, "view"))
context['history_list'] = HistoryTable(history_list)
club_list = Membership.objects.all().filter(user=user)\
.filter(PermissionBackend.filter_queryset(self.request.user, Membership, "view")).only("club")
club_list = Membership.objects.filter(user=user, date_end__gte=datetime.today())\
.filter(PermissionBackend.filter_queryset(self.request.user, Membership, "view"))
context['club_list'] = MembershipTable(data=club_list)
return context
@ -292,9 +294,8 @@ class ClubDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
context['history_list'] = HistoryTable(club_transactions)
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()
date_end__gte=datetime.today(),
).filter(PermissionBackend.filter_queryset(self.request.user, Membership, "view"))
context['member_list'] = MembershipTable(data=club_member)
@ -366,7 +367,7 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
else:
fee = club.membership_fee_unpaid
if user.note.balance < fee and not Membership.objects.filter(
club=2,
club__name="Kfet",
user=user,
date_start__lte=datetime.now().date(),
date_end__gte=datetime.now().date(),
@ -437,3 +438,28 @@ class ClubManageRolesView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
def get_success_url(self):
return reverse_lazy('member:club_detail', kwargs={'pk': self.object.club.id})
class ClubRenewMembershipView(ProtectQuerysetMixin, LoginRequiredMixin, View):
def get(self, *args, **kwargs):
user = self.request.user
membership = Membership.objects.filter(PermissionBackend.filter_queryset(user, Membership, "change"))\
.filter(pk=self.kwargs["pk"]).get()
if Membership.objects.filter(
club=membership.club,
user=membership.user,
date_start__gte=membership.club.membership_start,
date_end__lte=membership.club.membership_end,
).exists():
raise ValidationError(_("This membership is already renewed"))
new_membership = Membership.objects.create(
user=user,
club=membership.club,
date_start=membership.date_end + timedelta(days=1),
)
new_membership.roles.set(membership.roles.all())
new_membership.save()
return redirect(reverse_lazy('member:club_detail', kwargs={'pk': membership.club.pk}))

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-04-01 04:12+0200\n"
"POT-Creation-Date: 2020-04-01 18:39+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"
@ -44,7 +44,7 @@ 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:66 apps/member/models.py:166
#: apps/member/models.py:66 apps/member/models.py:169
#: apps/note/models/notes.py:188 apps/note/models/transactions.py:24
#: apps/note/models/transactions.py:44 apps/note/models/transactions.py:232
#: templates/member/club_info.html:13 templates/member/profile_info.html:14
@ -78,7 +78,7 @@ msgstr ""
msgid "type"
msgstr ""
#: apps/activity/models.py:66 apps/logs/models.py:21
#: apps/activity/models.py:66 apps/logs/models.py:21 apps/member/models.py:190
#: apps/note/models/notes.py:117
msgid "user"
msgstr ""
@ -275,7 +275,7 @@ msgstr ""
msgid "user profile"
msgstr ""
#: apps/member/models.py:71 templates/member/club_info.html:41
#: apps/member/models.py:71 templates/member/club_info.html:46
msgid "email"
msgstr ""
@ -291,11 +291,11 @@ msgstr ""
msgid "Uncheck if this club don't require memberships."
msgstr ""
#: apps/member/models.py:93 templates/member/club_info.html:31
#: apps/member/models.py:93 templates/member/club_info.html:35
msgid "membership fee (paid students)"
msgstr ""
#: apps/member/models.py:98 templates/member/club_info.html:34
#: apps/member/models.py:98 templates/member/club_info.html:38
msgid "membership fee (unpaid students)"
msgstr ""
@ -325,71 +325,86 @@ msgid ""
"members can renew their membership."
msgstr ""
#: apps/member/models.py:151 apps/note/models/notes.py:139
#: apps/member/models.py:154 apps/member/models.py:196
#: apps/note/models/notes.py:139
msgid "club"
msgstr ""
#: apps/member/models.py:152
#: apps/member/models.py:155
msgid "clubs"
msgstr ""
#: apps/member/models.py:172 apps/permission/models.py:288
#: apps/member/models.py:175 apps/permission/models.py:288
msgid "role"
msgstr ""
#: apps/member/models.py:173 apps/member/models.py:196
#: apps/member/models.py:176 apps/member/models.py:201
msgid "roles"
msgstr ""
#: apps/member/models.py:200
#: apps/member/models.py:205
msgid "membership starts on"
msgstr ""
#: apps/member/models.py:204
#: apps/member/models.py:209
msgid "membership ends on"
msgstr ""
#: apps/member/models.py:209
#: apps/member/models.py:214
msgid "fee"
msgstr ""
#: apps/member/models.py:221 apps/member/views.py:365
#: apps/member/models.py:226 apps/member/views.py:383
msgid "User is not a member of the parent club"
msgstr ""
#: apps/member/models.py:231 apps/member/views.py:374
#: apps/member/models.py:236 apps/member/views.py:392
msgid "User is already a member of the club"
msgstr ""
#: apps/member/models.py:265
#: apps/member/models.py:271
#, python-brace-format
msgid "Membership of {user} for the club {club}"
msgstr ""
#: apps/member/models.py:268
#: apps/member/models.py:274
msgid "membership"
msgstr ""
#: apps/member/models.py:269
#: apps/member/models.py:275
msgid "memberships"
msgstr ""
#: apps/member/views.py:78 templates/member/profile_info.html:45
#: apps/member/tables.py:73
msgid "Renew"
msgstr ""
#: apps/member/views.py:80 templates/member/profile_info.html:45
msgid "Update Profile"
msgstr ""
#: apps/member/views.py:91
#: apps/member/views.py:93
msgid "An alias with a similar name already exists."
msgstr ""
#: apps/member/views.py:378 apps/member/views.py:410
#: apps/member/views.py:379
msgid ""
"This user don't have enough money to join this club, and can't have a "
"negative balance."
msgstr ""
#: apps/member/views.py:396 apps/member/views.py:428
msgid "The membership must start after {:%m-%d-%Y}."
msgstr ""
#: apps/member/views.py:383 apps/member/views.py:415
#: apps/member/views.py:401 apps/member/views.py:433
msgid "The membership must begin before {:%m-%d-%Y}."
msgstr ""
#: apps/member/views.py:455
msgid "This membership is already renewed"
msgstr ""
#: apps/note/admin.py:120 apps/note/models/transactions.py:94
msgid "source"
msgstr ""
@ -491,7 +506,7 @@ msgstr ""
msgid "alias"
msgstr ""
#: apps/note/models/notes.py:211 templates/member/club_info.html:38
#: apps/note/models/notes.py:211 templates/member/club_info.html:43
#: templates/member/profile_info.html:36
msgid "aliases"
msgstr ""
@ -913,15 +928,19 @@ msgstr ""
msgid "days"
msgstr ""
#: templates/member/club_info.html:47
#: templates/member/club_info.html:32
msgid "membership fee"
msgstr ""
#: templates/member/club_info.html:52
msgid "Add member"
msgstr ""
#: templates/member/club_info.html:50 templates/note/conso_form.html:121
#: templates/member/club_info.html:55 templates/note/conso_form.html:121
msgid "Edit"
msgstr ""
#: templates/member/club_info.html:54 templates/member/profile_info.html:48
#: templates/member/club_info.html:59 templates/member/profile_info.html:48
msgid "View Profile"
msgstr ""

View File

@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-04-01 04:12+0200\n"
"POT-Creation-Date: 2020-04-01 18:39+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"
@ -40,7 +40,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:23 apps/activity/models.py:48
#: apps/member/models.py:66 apps/member/models.py:166
#: apps/member/models.py:66 apps/member/models.py:169
#: apps/note/models/notes.py:188 apps/note/models/transactions.py:24
#: apps/note/models/transactions.py:44 apps/note/models/transactions.py:232
#: templates/member/club_info.html:13 templates/member/profile_info.html:14
@ -74,7 +74,7 @@ msgstr "description"
msgid "type"
msgstr "type"
#: apps/activity/models.py:66 apps/logs/models.py:21
#: apps/activity/models.py:66 apps/logs/models.py:21 apps/member/models.py:190
#: apps/note/models/notes.py:117
msgid "user"
msgstr "utilisateur"
@ -271,7 +271,7 @@ msgstr "payé"
msgid "user profile"
msgstr "profil utilisateur"
#: apps/member/models.py:71 templates/member/club_info.html:41
#: apps/member/models.py:71 templates/member/club_info.html:46
msgid "email"
msgstr "courriel"
@ -287,11 +287,11 @@ msgstr "nécessite des adhésions"
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:93 templates/member/club_info.html:31
#: apps/member/models.py:93 templates/member/club_info.html:35
msgid "membership fee (paid students)"
msgstr "cotisation pour adhérer (normalien élève)"
#: apps/member/models.py:98 templates/member/club_info.html:34
#: apps/member/models.py:98 templates/member/club_info.html:38
msgid "membership fee (unpaid students)"
msgstr "cotisation pour adhérer (normalien étudiant)"
@ -325,71 +325,86 @@ 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:151 apps/note/models/notes.py:139
#: apps/member/models.py:154 apps/member/models.py:196
#: apps/note/models/notes.py:139
msgid "club"
msgstr "club"
#: apps/member/models.py:152
#: apps/member/models.py:155
msgid "clubs"
msgstr "clubs"
#: apps/member/models.py:172 apps/permission/models.py:288
#: apps/member/models.py:175 apps/permission/models.py:288
msgid "role"
msgstr "rôle"
#: apps/member/models.py:173 apps/member/models.py:196
#: apps/member/models.py:176 apps/member/models.py:201
msgid "roles"
msgstr "rôles"
#: apps/member/models.py:200
#: apps/member/models.py:205
msgid "membership starts on"
msgstr "l'adhésion commence le"
#: apps/member/models.py:204
#: apps/member/models.py:209
msgid "membership ends on"
msgstr "l'adhésion finit le"
#: apps/member/models.py:209
#: apps/member/models.py:214
msgid "fee"
msgstr "cotisation"
#: apps/member/models.py:221 apps/member/views.py:365
#: apps/member/models.py:226 apps/member/views.py:383
msgid "User is not a member of the parent club"
msgstr "L'utilisateur n'est pas membre du club parent"
#: apps/member/models.py:231 apps/member/views.py:374
#: apps/member/models.py:236 apps/member/views.py:392
msgid "User is already a member of the club"
msgstr "L'utilisateur est déjà membre du club"
#: apps/member/models.py:265
#: apps/member/models.py:271
#, python-brace-format
msgid "Membership of {user} for the club {club}"
msgstr "Adhésion de {user} pour le club {club}"
#: apps/member/models.py:268
#: apps/member/models.py:274
msgid "membership"
msgstr "adhésion"
#: apps/member/models.py:269
#: apps/member/models.py:275
msgid "memberships"
msgstr "adhésions"
#: apps/member/views.py:78 templates/member/profile_info.html:45
#: apps/member/tables.py:73
msgid "Renew"
msgstr ""
#: apps/member/views.py:80 templates/member/profile_info.html:45
msgid "Update Profile"
msgstr "Modifier le profil"
#: apps/member/views.py:91
#: apps/member/views.py:93
msgid "An alias with a similar name already exists."
msgstr "Un alias avec un nom similaire existe déjà."
#: apps/member/views.py:378 apps/member/views.py:410
#: apps/member/views.py:379
msgid ""
"This user don't have enough money to join this club, and can't have a "
"negative balance."
msgstr ""
#: apps/member/views.py:396 apps/member/views.py:428
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:383 apps/member/views.py:415
#: apps/member/views.py:401 apps/member/views.py:433
msgid "The membership must begin before {:%m-%d-%Y}."
msgstr "L'adhésion doit commencer avant le {:%d/%m/%Y}."
#: apps/member/views.py:455
msgid "This membership is already renewed"
msgstr "Cette adhésion est déjà renouvelée"
#: apps/note/admin.py:120 apps/note/models/transactions.py:94
msgid "source"
msgstr "source"
@ -492,7 +507,7 @@ msgstr "Alias invalide"
msgid "alias"
msgstr "alias"
#: apps/note/models/notes.py:211 templates/member/club_info.html:38
#: apps/note/models/notes.py:211 templates/member/club_info.html:43
#: templates/member/profile_info.html:36
msgid "aliases"
msgstr "alias"
@ -916,15 +931,19 @@ msgstr "Club parent"
msgid "days"
msgstr "jours"
#: templates/member/club_info.html:47
#: templates/member/club_info.html:32
msgid "membership fee"
msgstr "cotisation pour adhérer"
#: templates/member/club_info.html:52
msgid "Add member"
msgstr "Ajouter un membre"
#: templates/member/club_info.html:50 templates/note/conso_form.html:121
#: templates/member/club_info.html:55 templates/note/conso_form.html:121
msgid "Edit"
msgstr "Éditer"
#: templates/member/club_info.html:54 templates/member/profile_info.html:48
#: templates/member/club_info.html:59 templates/member/profile_info.html:48
msgid "View Profile"
msgstr "Voir le profil"

View File

@ -28,11 +28,16 @@
<dt class="col-xl-6">{% trans 'membership duration'|capfirst %}</dt>
<dd class="col-xl-6">{{ club.membership_duration }} {% trans "days" %}</dd>
<dt class="col-xl-6">{% trans 'membership fee (paid students)'|capfirst %}</dt>
<dd class="col-xl-6">{{ club.membership_fee_paid|pretty_money }}</dd>
{% if club.membership_fee_paid == club.membership_fee_unpaid %}
<dt class="col-xl-6">{% trans 'membership fee'|capfirst %}</dt>
<dd class="col-xl-6">{{ club.membership_fee_paid|pretty_money }}</dd>
{% else %}
<dt class="col-xl-6">{% trans 'membership fee (paid students)'|capfirst %}</dt>
<dd class="col-xl-6">{{ club.membership_fee_paid|pretty_money }}</dd>
<dt class="col-xl-6">{% trans 'membership fee (unpaid students)'|capfirst %}</dt>
<dd class="col-xl-6">{{ club.membership_fee_unpaid|pretty_money }}</dd>
<dt class="col-xl-6">{% trans 'membership fee (unpaid students)'|capfirst %}</dt>
<dd class="col-xl-6">{{ club.membership_fee_unpaid|pretty_money }}</dd>
{% endif %}
{% endif %}
<dt class="col-xl-6"><a href="{% url 'member:club_alias' club.pk %}">{% trans 'aliases'|capfirst %}</a></dt>