Validate registrations, closes #14, #18, #19

This commit is contained in:
Yohann D'ANELLO 2020-04-05 09:09:21 +02:00
parent b1cd46bf7d
commit fbc25240e6
6 changed files with 204 additions and 50 deletions

View File

@ -230,6 +230,7 @@ class Membership(models.Model):
) )
date_start = models.DateField( date_start = models.DateField(
default=datetime.date.today,
verbose_name=_('membership starts on'), verbose_name=_('membership starts on'),
) )

View File

@ -8,7 +8,7 @@ from polymorphic.admin import PolymorphicChildModelAdmin, \
from .models.notes import Alias, Note, NoteClub, NoteSpecial, NoteUser from .models.notes import Alias, Note, NoteClub, NoteSpecial, NoteUser
from .models.transactions import Transaction, TemplateCategory, TransactionTemplate, \ from .models.transactions import Transaction, TemplateCategory, TransactionTemplate, \
RecurrentTransaction, MembershipTransaction RecurrentTransaction, MembershipTransaction, SpecialTransaction
class AliasInlines(admin.TabularInline): class AliasInlines(admin.TabularInline):
@ -102,7 +102,7 @@ class TransactionAdmin(PolymorphicParentModelAdmin):
""" """
Admin customisation for Transaction Admin customisation for Transaction
""" """
child_models = (RecurrentTransaction, MembershipTransaction) child_models = (RecurrentTransaction, MembershipTransaction, SpecialTransaction)
list_display = ('created_at', 'poly_source', 'poly_destination', list_display = ('created_at', 'poly_source', 'poly_destination',
'quantity', 'amount', 'valid') 'quantity', 'amount', 'valid')
list_filter = ('valid',) list_filter = ('valid',)
@ -141,7 +141,14 @@ class TransactionAdmin(PolymorphicParentModelAdmin):
@admin.register(MembershipTransaction) @admin.register(MembershipTransaction)
class MembershipTransactionAdmin(PolymorphicChildModelAdmin): class MembershipTransactionAdmin(PolymorphicChildModelAdmin):
""" """
Admin customisation for Transaction Admin customisation for MembershipTransaction
"""
@admin.register(SpecialTransaction)
class SpecialTransactionAdmin(PolymorphicChildModelAdmin):
"""
Admin customisation for SpecialTransaction
""" """

View File

@ -1,9 +1,12 @@
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
from django import forms
from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from note.models import NoteSpecial
from note_kfet.inputs import AmountInput
class SignUpForm(UserCreationForm): class SignUpForm(UserCreationForm):
@ -19,3 +22,46 @@ class SignUpForm(UserCreationForm):
class Meta: class Meta:
model = User model = User
fields = ('first_name', 'last_name', 'username', 'email', ) fields = ('first_name', 'last_name', 'username', 'email', )
class ValidationForm(forms.Form):
credit_type = forms.ModelChoiceField(
queryset=NoteSpecial.objects,
label=_("Credit type"),
empty_label=_("No credit"),
required=False,
)
credit_amount = forms.IntegerField(
label=_("Credit amount"),
required=False,
initial=0,
widget=AmountInput(),
)
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,
)
join_BDE = forms.BooleanField(
label=_("Join BDE"),
required=False,
initial=True,
)
join_Kfet = forms.BooleanField(
label=_("Join Kfet"),
required=False,
initial=True,
)

View File

@ -12,14 +12,16 @@ from django.utils.http import urlsafe_base64_decode
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.views import View from django.views import View
from django.views.decorators.csrf import csrf_protect from django.views.decorators.csrf import csrf_protect
from django.views.generic import CreateView, TemplateView, DetailView from django.views.generic import CreateView, TemplateView, DetailView, FormView
from django_tables2 import SingleTableView from django_tables2 import SingleTableView
from member.forms import ProfileForm from member.forms import ProfileForm
from member.models import Profile from member.models import Membership, Club
from note.models import SpecialTransaction
from note.templatetags.pretty_money import pretty_money
from permission.backends import PermissionBackend from permission.backends import PermissionBackend
from permission.views import ProtectQuerysetMixin from permission.views import ProtectQuerysetMixin
from .forms import SignUpForm from .forms import SignUpForm, ValidationForm
from .tables import FutureUserTable from .tables import FutureUserTable
from .tokens import account_activation_token from .tokens import account_activation_token
@ -138,11 +140,12 @@ class FutureUserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableVi
return context return context
class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView): class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView, FormView):
""" """
Affiche les informations sur un utilisateur, sa note, ses clubs... Affiche les informations sur un utilisateur, sa note, ses clubs...
""" """
model = User model = User
form_class = ValidationForm
context_object_name = "user_object" context_object_name = "user_object"
template_name = "registration/future_profile_detail.html" template_name = "registration/future_profile_detail.html"
@ -152,6 +155,92 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView)
""" """
return super().get_queryset().filter(profile__registration_valid=False) return super().get_queryset().filter(profile__registration_valid=False)
def get_form(self, form_class=None):
form = super().get_form(form_class)
user = self.get_object()
form.fields["last_name"].initial = user.last_name
form.fields["first_name"].initial = user.first_name
return form
def form_valid(self, form):
user = self.object = self.get_object()
print(form.cleaned_data)
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"]
join_BDE = form.cleaned_data["join_BDE"]
join_Kfet = form.cleaned_data["join_Kfet"]
fee = 0
bde = Club.objects.get(name="BDE")
bde_fee = bde.membership_fee_paid if user.profile.paid else bde.membership_fee_unpaid
if join_BDE:
fee += bde_fee
kfet = Club.objects.get(name="Kfet")
kfet_fee = kfet.membership_fee_paid if user.profile.paid else kfet.membership_fee_unpaid
if join_Kfet:
fee += kfet_fee
if join_Kfet and not join_BDE:
form.add_error('join_Kfet', _("You must join BDE club before joining Kfet club."))
if fee > credit_amount:
form.add_error('credit_type',
_("The entered amount is not enough for the memberships, should be at least {}")
.format(pretty_money(fee)))
return self.form_invalid(form)
if credit_type is not None and credit_amount > 0:
if not last_name or not first_name or not bank:
if not last_name:
form.add_error('last_name', _("This field is required."))
if not first_name:
form.add_error('first_name', _("This field is required."))
if not bank:
form.add_error('bank', _("This field is required."))
return self.form_invalid(form)
ret = super().form_valid(form)
user.is_active = True
user.profile.registration_valid = True
user.save()
user.profile.save()
if credit_type is not None and credit_amount > 0:
SpecialTransaction.objects.create(
source=credit_type,
destination=user.note,
quantity=1,
amount=credit_amount,
reason="Crédit " + credit_type.special_type + " (Inscription)",
last_name=last_name,
first_name=first_name,
bank=bank,
valid=True,
)
if join_BDE:
Membership.objects.create(
club=bde,
user=user,
fee=bde_fee,
)
if join_Kfet:
Membership.objects.create(
club=kfet,
user=user,
fee=kfet_fee,
)
return ret
def get_success_url(self):
return reverse_lazy('member:user_detail', args=(self.get_object().pk, ))
class FutureUserInvalidateView(ProtectQuerysetMixin, LoginRequiredMixin, View): class FutureUserInvalidateView(ProtectQuerysetMixin, LoginRequiredMixin, View):
""" """

View File

@ -13,7 +13,7 @@ class AmountInput(NumberInput):
template_name = "note/amount_input.html" template_name = "note/amount_input.html"
def format_value(self, value): def format_value(self, value):
return None if value is None or value == "" else "{:.02f}".format(value / 100, ) return None if value is None or value == "" else "{:.02f}".format(int(value) / 100, )
def value_from_datadict(self, data, files, name): def value_from_datadict(self, data, files, name):
val = super().value_from_datadict(data, files, name) val = super().value_from_datadict(data, files, name)

View File

@ -1,12 +1,11 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load static %} {% load static %}
{% load i18n %} {% load i18n %}
{% load render_table from django_tables2 %} {% load crispy_forms_tags %}
{% load pretty_money %} {% load pretty_money %}
{% block content %} {% block content %}
<div class="card bg-light shadow">
<div class="card bg-light shadow">
<div class="card-header text-center" > <div class="card-header text-center" >
<h4> {% trans "Account #" %} {{ object.pk }}</h4> <h4> {% trans "Account #" %} {{ object.pk }}</h4>
</div> </div>
@ -40,15 +39,27 @@
<dt class="col-xl-6">{% trans 'paid'|capfirst %}</dt> <dt class="col-xl-6">{% trans 'paid'|capfirst %}</dt>
<dd class="col-xl-6">{{ object.profile.paid|yesno }}</dd> <dd class="col-xl-6">{{ object.profile.paid|yesno }}</dd>
</dl> </dl>
{% if object.pk == user.pk %}
<a class="small" href="{% url 'member:auth_token' %}">{% trans 'Manage auth token' %}</a>
{% endif %}
</div> </div>
<div class="card-footer text-center"> <div class="card-footer text-center">
<a class="btn btn-primary btn-sm" href="{% url 'member:user_update_profile' object.pk %}">{% trans 'Update Profile' %}</a> <a class="btn btn-primary btn-sm" href="{% url 'member:user_update_profile' object.pk %}">{% trans 'Update Profile' %}</a>
<a class="btn btn-danger btn-sm" href="{% url 'registration:future_user_invalidate' object.pk %}">{% trans 'Delete registration' %}</a> <a class="btn btn-danger btn-sm" href="{% url 'registration:future_user_invalidate' object.pk %}">{% trans 'Delete registration' %}</a>
</div> </div>
</div> </div>
<hr>
<div class="card bg-light shadow">
<form method="post">
<div class="card-header text-center" >
<h4> {% trans "Validate account" %}</h4>
</div>
<div class="card-body" id="profile_infos">
{% csrf_token %}
{{ form|crispy }}
</div>
<div class="card-footer text-center">
<button class="btn btn-success btn-sm">{% trans 'Validate registration' %}</button>
</div>
</form>
</div>
{% endblock %} {% endblock %}