mirror of
https://gitlab.crans.org/bde/nk20
synced 2025-06-21 18:08:21 +02:00
Full membership support
This commit is contained in:
@ -18,6 +18,7 @@
|
||||
"fields": {
|
||||
"name": "Kfet",
|
||||
"email": "tresorerie.bde@example.com",
|
||||
"parent_club": 1,
|
||||
"require_memberships": true,
|
||||
"membership_fee": 3500,
|
||||
"membership_duration": 396,
|
||||
|
@ -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
|
||||
|
@ -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')
|
||||
|
@ -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
|
||||
|
@ -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'),
|
||||
]
|
||||
|
@ -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):
|
||||
|
Reference in New Issue
Block a user