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(
default=datetime.date.today,
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.transactions import Transaction, TemplateCategory, TransactionTemplate, \
RecurrentTransaction, MembershipTransaction
RecurrentTransaction, MembershipTransaction, SpecialTransaction
class AliasInlines(admin.TabularInline):
@ -102,7 +102,7 @@ class TransactionAdmin(PolymorphicParentModelAdmin):
"""
Admin customisation for Transaction
"""
child_models = (RecurrentTransaction, MembershipTransaction)
child_models = (RecurrentTransaction, MembershipTransaction, SpecialTransaction)
list_display = ('created_at', 'poly_source', 'poly_destination',
'quantity', 'amount', 'valid')
list_filter = ('valid',)
@ -141,7 +141,14 @@ class TransactionAdmin(PolymorphicParentModelAdmin):
@admin.register(MembershipTransaction)
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
# SPDX-License-Identifier: GPL-3.0-or-later
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django.utils.translation import gettext_lazy as _
from note.models import NoteSpecial
from note_kfet.inputs import AmountInput
class SignUpForm(UserCreationForm):
@ -19,3 +22,46 @@ class SignUpForm(UserCreationForm):
class Meta:
model = User
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.views import View
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 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.views import ProtectQuerysetMixin
from .forms import SignUpForm
from .forms import SignUpForm, ValidationForm
from .tables import FutureUserTable
from .tokens import account_activation_token
@ -138,11 +140,12 @@ class FutureUserListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableVi
return context
class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView, FormView):
"""
Affiche les informations sur un utilisateur, sa note, ses clubs...
"""
model = User
form_class = ValidationForm
context_object_name = "user_object"
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)
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):
"""

View File

@ -13,7 +13,7 @@ class AmountInput(NumberInput):
template_name = "note/amount_input.html"
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):
val = super().value_from_datadict(data, files, name)

View File

@ -1,54 +1,65 @@
{% extends "base.html" %}
{% load static %}
{% load i18n %}
{% load render_table from django_tables2 %}
{% load crispy_forms_tags %}
{% load pretty_money %}
{% block content %}
<div class="card bg-light shadow">
<div class="card-header text-center" >
<h4> {% trans "Account #" %} {{ object.pk }}</h4>
</div>
<div class="card-body" id="profile_infos">
<dl class="row">
<dt class="col-xl-6">{% trans 'name'|capfirst %}, {% trans 'first name' %}</dt>
<dd class="col-xl-6">{{ object.last_name }} {{ object.first_name }}</dd>
<div class="card bg-light shadow">
<div class="card-header text-center" >
<h4> {% trans "Account #" %} {{ object.pk }}</h4>
<dt class="col-xl-6">{% trans 'username'|capfirst %}</dt>
<dd class="col-xl-6">{{ object.username }}</dd>
<dt class="col-xl-6">{% trans 'email'|capfirst %}</dt>
<dd class="col-xl-6"><a href="mailto:{{ object.email }}">{{ object.email }}</a></dd>
<dt class="col-xl-6">{% trans 'password'|capfirst %}</dt>
<dd class="col-xl-6">
<a class="small" href="{% url 'password_change' %}">
{% trans 'Change password' %}
</a>
</dd>
<dt class="col-xl-6">{% trans 'section'|capfirst %}</dt>
<dd class="col-xl-6">{{ object.profile.section }}</dd>
<dt class="col-xl-6">{% trans 'address'|capfirst %}</dt>
<dd class="col-xl-6">{{ object.profile.address }}</dd>
<dt class="col-xl-6">{% trans 'phone number'|capfirst %}</dt>
<dd class="col-xl-6">{{ object.profile.phone_number }}</dd>
<dt class="col-xl-6">{% trans 'paid'|capfirst %}</dt>
<dd class="col-xl-6">{{ object.profile.paid|yesno }}</dd>
</dl>
</div>
<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-danger btn-sm" href="{% url 'registration:future_user_invalidate' object.pk %}">{% trans 'Delete registration' %}</a>
</div>
</div>
<div class="card-body" id="profile_infos">
<dl class="row">
<dt class="col-xl-6">{% trans 'name'|capfirst %}, {% trans 'first name' %}</dt>
<dd class="col-xl-6">{{ object.last_name }} {{ object.first_name }}</dd>
<dt class="col-xl-6">{% trans 'username'|capfirst %}</dt>
<dd class="col-xl-6">{{ object.username }}</dd>
<hr>
<dt class="col-xl-6">{% trans 'email'|capfirst %}</dt>
<dd class="col-xl-6"><a href="mailto:{{ object.email }}">{{ object.email }}</a></dd>
<dt class="col-xl-6">{% trans 'password'|capfirst %}</dt>
<dd class="col-xl-6">
<a class="small" href="{% url 'password_change' %}">
{% trans 'Change password' %}
</a>
</dd>
<dt class="col-xl-6">{% trans 'section'|capfirst %}</dt>
<dd class="col-xl-6">{{ object.profile.section }}</dd>
<dt class="col-xl-6">{% trans 'address'|capfirst %}</dt>
<dd class="col-xl-6">{{ object.profile.address }}</dd>
<dt class="col-xl-6">{% trans 'phone number'|capfirst %}</dt>
<dd class="col-xl-6">{{ object.profile.phone_number }}</dd>
<dt class="col-xl-6">{% trans 'paid'|capfirst %}</dt>
<dd class="col-xl-6">{{ object.profile.paid|yesno }}</dd>
</dl>
{% if object.pk == user.pk %}
<a class="small" href="{% url 'member:auth_token' %}">{% trans 'Manage auth token' %}</a>
{% endif %}
<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>
<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-danger btn-sm" href="{% url 'registration:future_user_invalidate' object.pk %}">{% trans 'Delete registration' %}</a>
</div>
</div>
{% endblock %}