1
0
mirror of https://gitlab.crans.org/bde/nk20 synced 2025-06-21 01:48:21 +02:00

Full membership support

This commit is contained in:
Yohann D'ANELLO
2020-04-01 03:42:19 +02:00
parent bf9789bd9e
commit d5b010980b
14 changed files with 186 additions and 46 deletions

View File

@ -18,6 +18,7 @@
"fields": {
"name": "Kfet",
"email": "tresorerie.bde@example.com",
"parent_club": 1,
"require_memberships": true,
"membership_fee": 3500,
"membership_duration": 396,

View File

@ -4,6 +4,7 @@
from django import forms
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.contrib.auth.models import User
from django.utils.translation import gettext_lazy as _
from note_kfet.inputs import Autocomplete, AmountInput, DatePickerInput
from permission.models import PermissionMask
@ -57,11 +58,6 @@ class ClubForm(forms.ModelForm):
}
class AddMembersForm(forms.Form):
class Meta:
fields = ('',)
class MembershipForm(forms.ModelForm):
class Meta:
model = Membership

View File

@ -4,11 +4,14 @@
import datetime
from django.conf import settings
from django.core.exceptions import ValidationError
from django.contrib.auth.models import User
from django.core.exceptions import ValidationError, PermissionDenied
from django.db import models
from django.urls import reverse, reverse_lazy
from django.utils.translation import gettext_lazy as _
from note.models import MembershipTransaction
class Profile(models.Model):
"""
@ -91,7 +94,7 @@ class Club(models.Model):
verbose_name=_('membership fee'),
)
membership_duration = models.IntegerField(
membership_duration = models.PositiveIntegerField(
blank=True,
null=True,
verbose_name=_('membership duration'),
@ -174,7 +177,7 @@ class Membership(models.Model):
"""
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
User,
on_delete=models.PROTECT,
)
@ -185,6 +188,7 @@ class Membership(models.Model):
roles = models.ManyToManyField(
Role,
verbose_name=_("roles"),
)
date_start = models.DateField(
@ -209,17 +213,41 @@ 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).exists():
raise ValidationError(_('User is not a member of the parent club'))
raise ValidationError(_('User is not a member of the parent club') + ' ' + self.club.parent_club.name)
created = not self.pk
if created:
if Membership.objects.filter(
user=self.user,
club=self.club,
date_start__lte=datetime.datetime.now().date(),
date_end__gte=datetime.datetime.now().date(),
).exists():
raise ValidationError(_('User is already a member of the club'))
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:
if self.club.membership_duration is not None:
self.date_end = self.date_start + datetime.timedelta(days=self.club.membership_duration)
else:
self.date_end = self.date_start + datetime.timedelta(days=0x7FFFFFFF)
if self.club.membership_end is not None and self.date_end > self.club.membership_end:
self.date_end = self.club.membership_end
super().save(*args, **kwargs)
if created and self.fee:
try:
MembershipTransaction.objects.create(
membership=self,
source=self.user.note,
destination=self.club.note,
quantity=1,
amount=self.fee,
reason="Adhésion",
)
except PermissionDenied:
self.delete()
class Meta:
verbose_name = _('membership')
verbose_name_plural = _('memberships')

View File

@ -3,8 +3,14 @@
import django_tables2 as tables
from django.contrib.auth.models import User
from django.urls import reverse_lazy
from django.utils.html import format_html
from django_tables2 import A
from .models import Club
from note.templatetags.pretty_money import pretty_money
from note_kfet.middlewares import get_current_authenticated_user
from permission.backends import PermissionBackend
from .models import Club, Membership
class ClubTable(tables.Table):
@ -33,3 +39,33 @@ class UserTable(tables.Table):
template_name = 'django_tables2/bootstrap4.html'
fields = ('last_name', 'first_name', 'username', 'email')
model = User
class MembershipTable(tables.Table):
roles = tables.Column(
attrs={
"td": {
"class": "text-truncate",
}
}
)
def render_fee(self, value):
return pretty_money(value)
def render_roles(self, record):
roles = record.roles.all()
s = ", ".join(str(role) for role in roles)
if PermissionBackend().has_perm(get_current_authenticated_user(), "member.change_membership_roles", record):
s = format_html("<a href='" + str(reverse_lazy("member:club_manage_roles", kwargs={"pk": record.pk}))
+ "'>" + s + "</a>")
return s
class Meta:
attrs = {
'class': 'table table-condensed table-striped table-hover',
'style': 'table-layout: fixed;'
}
template_name = 'django_tables2/bootstrap4.html'
fields = ('user', 'club', 'date_start', 'date_end', 'roles', 'fee', )
model = Membership

View File

@ -12,15 +12,16 @@ urlpatterns = [
path('club/', views.ClubListView.as_view(), name="club_list"),
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/<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"),
path('user/', views.UserListView.as_view(), name="user_list"),
path('user/<int:pk>', views.UserDetailView.as_view(), name="user_detail"),
path('user/<int:pk>/update', views.UserUpdateView.as_view(), name="user_update_profile"),
path('user/<int:pk>/update_pic', views.ProfilePictureUpdateView.as_view(), name="user_update_pic"),
path('user/<int:pk>/aliases', views.ProfileAliasView.as_view(), name="user_alias"),
path('user/<int:pk>/', views.UserDetailView.as_view(), name="user_detail"),
path('user/<int:pk>/update/', views.UserUpdateView.as_view(), name="user_update_profile"),
path('user/<int:pk>/update_pic/', views.ProfilePictureUpdateView.as_view(), name="user_update_pic"),
path('user/<int:pk>/aliases/', views.ProfileAliasView.as_view(), name="user_alias"),
path('manage-auth-token/', views.ManageAuthTokens.as_view(), name='auth_token'),
]

View File

@ -10,6 +10,7 @@ from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.models import User
from django.contrib.auth.views import LoginView
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 _
@ -27,7 +28,7 @@ from permission.views import ProtectQuerysetMixin
from .filters import UserFilter, UserFilterFormHelper
from .forms import SignUpForm, ProfileForm, ClubForm, MembershipForm, CustomAuthenticationForm
from .models import Club, Membership
from .tables import ClubTable, UserTable
from .tables import ClubTable, UserTable, MembershipTable
class CustomLoginView(LoginView):
@ -138,7 +139,7 @@ class UserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
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")
context['club_list'] = ClubTable(club_list)
context['club_list'] = MembershipTable(data=club_list)
return context
@ -294,7 +295,19 @@ class ClubDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
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
context['member_list'] = MembershipTable(data=club_member)
empty_membership = Membership(
club=club,
user=User.objects.first(),
date_start=datetime.now().date(),
date_end=datetime.now().date(),
fee=0,
)
context["can_add_members"] = PermissionBackend()\
.has_perm(self.request.user, "member.add_membership", empty_membership)
return context
@ -339,7 +352,6 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
.get(pk=self.kwargs["pk"])
context = super().get_context_data(**kwargs)
context['club'] = club
context['no_cache'] = True
return context
@ -347,6 +359,63 @@ class ClubAddMemberView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
club = Club.objects.filter(PermissionBackend.filter_queryset(self.request.user, Club, "view"))\
.get(pk=self.kwargs["pk"])
form.instance.club = club
if club.parent_club is not None:
if not Membership.objects.filter(user=form.instance.user, club=club.parent_club).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,
date_start__lte=datetime.now().date(),
date_end__gte=datetime.now().date(),
).exists():
form.add_error('user', _('User is already a member of the club'))
return super().form_invalid(form)
if form.instance.date_start < form.instance.club.membership_start:
form.add_error('user', _("The membership must start after {:%m-%d-%Y}.")
.format(form.instance.club.membership_start))
return super().form_invalid(form)
if form.instance.date_start > form.instance.club.membership_end:
form.add_error('user', _("The membership must end before {:%m-%d-%Y}.")
.format(form.instance.club.membership_start))
return super().form_invalid(form)
return super().form_valid(form)
def get_success_url(self):
return reverse_lazy('member:club_detail', kwargs={'pk': self.object.club.id})
class ClubManageRolesView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
model = Membership
form_class = MembershipForm
template_name = 'member/add_members.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
club = self.object.club
context['club'] = club
form = context['form']
form.fields['user'].disabled = True
form.fields['date_start'].widget = HiddenInput()
return context
def form_valid(self, form):
if form.instance.date_start < form.instance.club.membership_start:
form.add_error('user', _("The membership must start after {:%m-%d-%Y}.")
.format(form.instance.club.membership_start))
return super().form_invalid(form)
if form.instance.date_start > form.instance.club.membership_end:
form.add_error('user', _("The membership must end before {:%m-%d-%Y}.")
.format(form.instance.club.membership_start))
return super().form_invalid(form)
return super().form_valid(form)
def get_success_url(self):