The BDE offers 80 € to each new member that registers to the Société générale

This commit is contained in:
Yohann D'ANELLO 2020-09-07 21:33:23 +02:00
parent dc6a5f56f6
commit fa3c723140
10 changed files with 60 additions and 32 deletions

View File

@ -27,8 +27,8 @@ def create_bde_and_kfet(apps, schema_editor):
parent_club_id=1, parent_club_id=1,
email="tresorerie.bde@example.com", email="tresorerie.bde@example.com",
require_memberships=True, require_memberships=True,
membership_fee_paid=500, membership_fee_paid=3500,
membership_fee_unpaid=500, membership_fee_unpaid=3500,
membership_duration=396, membership_duration=396,
membership_start="2020-08-01", membership_start="2020-08-01",
membership_end="2021-09-30", membership_end="2021-09-30",

View File

@ -138,7 +138,7 @@ class UserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
""" """
We can't display information of a not registered user. We can't display information of a not registered user.
""" """
return super().get_queryset().filter(profile__registration_valid=True) return super().get_queryset(**kwargs).filter(profile__registration_valid=True)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
""" """

View File

@ -175,7 +175,7 @@ class Transaction(PolymorphicModel):
created = self.pk is None created = self.pk is None
to_transfer = self.amount * self.quantity to_transfer = self.amount * self.quantity
if not created: if not created and not self.valid and not hasattr(self, "_force_save"):
# Revert old transaction # Revert old transaction
old_transaction = Transaction.objects.get(pk=self.pk) old_transaction = Transaction.objects.get(pk=self.pk)
# Check that nothing important changed # Check that nothing important changed

View File

@ -8,6 +8,7 @@ from django.contrib.auth.models import User
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.db.models import Q from django.db.models import Q
from django.forms import HiddenInput from django.forms import HiddenInput
from django.http import Http404
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.views.generic import UpdateView, TemplateView, CreateView from django.views.generic import UpdateView, TemplateView, CreateView
from member.models import Membership from member.models import Membership
@ -24,9 +25,20 @@ class ProtectQuerysetMixin:
Display 404 error if the user can't see an object, remove the fields the user can't Display 404 error if the user can't see an object, remove the fields the user can't
update on an update form (useful if the user can't change only specified fields). update on an update form (useful if the user can't change only specified fields).
""" """
def get_queryset(self, **kwargs): def get_queryset(self, filter_permissions=True, **kwargs):
qs = super().get_queryset(**kwargs) qs = super().get_queryset(**kwargs)
return qs.filter(PermissionBackend.filter_queryset(self.request.user, qs.model, "view")).distinct() return qs.filter(PermissionBackend.filter_queryset(self.request.user, qs.model, "view")).distinct()\
if filter_permissions else qs
def get_object(self, queryset=None):
try:
return super().get_object(queryset)
except Http404 as e:
try:
super().get_object(self.get_queryset(filter_permissions=False))
raise PermissionDenied()
except Http404:
raise e
def get_form(self, form_class=None): def get_form(self, form_class=None):
form = super().get_form(form_class) form = super().get_form(form_class)

View File

@ -364,7 +364,7 @@ class TestValidateRegistration(TestCase):
self.assertTrue(Membership.objects.filter(club__name="Kfet", user=self.user).exists()) self.assertTrue(Membership.objects.filter(club__name="Kfet", user=self.user).exists())
self.assertTrue(SogeCredit.objects.filter(user=self.user).exists()) self.assertTrue(SogeCredit.objects.filter(user=self.user).exists())
self.assertEqual(Transaction.objects.filter( self.assertEqual(Transaction.objects.filter(
Q(source=self.user.note) | Q(destination=self.user.note)).count(), 2) Q(source=self.user.note) | Q(destination=self.user.note)).count(), 3)
self.assertFalse(Transaction.objects.filter(valid=True).exists()) self.assertFalse(Transaction.objects.filter(valid=True).exists())
response = self.client.get(self.user.profile.get_absolute_url()) response = self.client.get(self.user.profile.get_absolute_url())

View File

@ -21,6 +21,7 @@ from note.templatetags.pretty_money import pretty_money
from permission.backends import PermissionBackend from permission.backends import PermissionBackend
from permission.models import Role from permission.models import Role
from permission.views import ProtectQuerysetMixin from permission.views import ProtectQuerysetMixin
from treasury.models import SogeCredit
from .forms import SignUpForm, ValidationForm from .forms import SignUpForm, ValidationForm
from .tables import FutureUserTable from .tables import FutureUserTable
@ -219,6 +220,9 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin,
fee += bde.membership_fee_paid if user.profile.paid else bde.membership_fee_unpaid fee += bde.membership_fee_paid if user.profile.paid else bde.membership_fee_unpaid
kfet = Club.objects.get(name="Kfet") kfet = Club.objects.get(name="Kfet")
fee += kfet.membership_fee_paid if user.profile.paid else kfet.membership_fee_unpaid fee += kfet.membership_fee_paid if user.profile.paid else kfet.membership_fee_unpaid
# In 2020, for COVID-19 reasons, the BDE offered 80 € to each new member that opens a Sogé account,
# since there is no WEI.
fee += 8000
ctx["total_fee"] = "{:.02f}".format(fee / 100, ) ctx["total_fee"] = "{:.02f}".format(fee / 100, )
return ctx return ctx
@ -342,6 +346,11 @@ class FutureUserDetailView(ProtectQuerysetMixin, LoginRequiredMixin, FormMixin,
membership.roles.add(Role.objects.get(name="Adhérent Kfet")) membership.roles.add(Role.objects.get(name="Adhérent Kfet"))
membership.save() membership.save()
if soge:
soge_credit = SogeCredit.objects.get(user=user)
# Update the credit transaction amount
soge_credit.save()
return ret return ret
def get_success_url(self): def get_success_url(self):

View File

@ -291,11 +291,11 @@ class SogeCredit(models.Model):
@property @property
def valid(self): def valid(self):
return self.credit_transaction is not None return self.credit_transaction.valid
@property @property
def amount(self): def amount(self):
return sum(transaction.total for transaction in self.transactions.all()) return sum(transaction.total for transaction in self.transactions.all()) + 8000
def invalidate(self): def invalidate(self):
""" """
@ -304,11 +304,7 @@ class SogeCredit(models.Model):
""" """
if self.valid: if self.valid:
self.credit_transaction.valid = False self.credit_transaction.valid = False
self.credit_transaction._force_save = True
self.credit_transaction.save() self.credit_transaction.save()
self.credit_transaction._force_delete = True
self.credit_transaction.delete()
self.credit_transaction = None
for transaction in self.transactions.all(): for transaction in self.transactions.all():
transaction.valid = False transaction.valid = False
transaction._force_save = True transaction._force_save = True
@ -321,17 +317,10 @@ class SogeCredit(models.Model):
# First invalidate all transaction and delete the credit if already did (and force mode) # First invalidate all transaction and delete the credit if already did (and force mode)
self.invalidate() self.invalidate()
self.credit_transaction = SpecialTransaction.objects.create( # Refresh credit amount
source=NoteSpecial.objects.get(special_type="Virement bancaire"), self.save()
destination=self.user.note, self.credit_transaction.valid = True
quantity=1, self.credit_transaction.save()
amount=self.amount,
reason="Crédit société générale",
last_name=self.user.last_name,
first_name=self.user.first_name,
bank="Société générale",
created_at=self.transactions.order_by("-created_at").first().created_at,
)
self.save() self.save()
for transaction in self.transactions.all(): for transaction in self.transactions.all():
@ -340,6 +329,25 @@ class SogeCredit(models.Model):
transaction.created_at = timezone.now() transaction.created_at = timezone.now()
transaction.save() transaction.save()
def save(self, *args, **kwargs):
if not self.credit_transaction:
self.credit_transaction = SpecialTransaction.objects.create(
source=NoteSpecial.objects.get(special_type="Virement bancaire"),
destination=self.user.note,
quantity=1,
amount=0,
reason="Crédit société générale",
last_name=self.user.last_name,
first_name=self.user.first_name,
bank="Société générale",
valid=False,
)
elif not self.valid:
self.credit_transaction.amount = self.amount
self.credit_transaction._force_save = True
self.credit_transaction.save()
super().save(*args, **kwargs)
def delete(self, **kwargs): def delete(self, **kwargs):
""" """
Deleting a SogeCredit is equivalent to say that the Société générale didn't pay. Deleting a SogeCredit is equivalent to say that the Société générale didn't pay.
@ -358,6 +366,9 @@ class SogeCredit(models.Model):
transaction.valid = True transaction.valid = True
transaction.created_at = timezone.now() transaction.created_at = timezone.now()
transaction.save() transaction.save()
self.credit_transaction.valid = False
self.credit_transaction.reason += " (invalide)"
self.credit_transaction.save()
super().delete(**kwargs) super().delete(**kwargs)
class Meta: class Meta:

View File

@ -30,7 +30,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
<input id="searchbar" type="text" class="form-control" placeholder="Nom/prénom/note ..."> <input id="searchbar" type="text" class="form-control" placeholder="Nom/prénom/note ...">
<div class="form-check"> <div class="form-check">
<label for="invalid_only" class="form-check-label"> <label for="invalid_only" class="form-check-label">
<input id="invalid_only" name="invalid_only" type="checkbox" class="checkboxinput form-check-input"> <input id="invalid_only" name="invalid_only" type="checkbox" class="checkboxinput form-check-input" checked>
{% trans "Filter with unvalidated credits only" %} {% trans "Filter with unvalidated credits only" %}
</label> </label>
</div> </div>

View File

@ -353,7 +353,6 @@ class TestSogeCredits(TestCase):
soge_credit.refresh_from_db() soge_credit.refresh_from_db()
self.assertTrue(soge_credit.valid) self.assertTrue(soge_credit.valid)
self.user.note.refresh_from_db() self.user.note.refresh_from_db()
self.assertEqual(self.user.note.balance, 0)
self.assertEqual( self.assertEqual(
Transaction.objects.filter(Q(source=self.user.note) | Q(destination=self.user.note)).count(), 3) Transaction.objects.filter(Q(source=self.user.note) | Q(destination=self.user.note)).count(), 3)
self.assertTrue(self.user.profile.soge) self.assertTrue(self.user.profile.soge)
@ -391,7 +390,7 @@ class TestSogeCredits(TestCase):
self.user.note.refresh_from_db() self.user.note.refresh_from_db()
self.assertEqual(self.user.note.balance, 0) self.assertEqual(self.user.note.balance, 0)
self.assertEqual( self.assertEqual(
Transaction.objects.filter(Q(source=self.user.note) | Q(destination=self.user.note)).count(), 3) Transaction.objects.filter(Q(source=self.user.note) | Q(destination=self.user.note)).count(), 4)
self.assertFalse(self.user.profile.soge) self.assertFalse(self.user.profile.soge)
def test_invoice_api(self): def test_invoice_api(self):

View File

@ -425,11 +425,8 @@ class SogeCreditListView(LoginRequiredMixin, ProtectQuerysetMixin, SingleTableVi
| Q(user__note__alias__normalized_name__iregex="^" + Alias.normalize(pattern)) | Q(user__note__alias__normalized_name__iregex="^" + Alias.normalize(pattern))
) )
if "valid" in self.request.GET: if "valid" not in self.request.GET or not self.request.GET["valid"]:
q = Q(credit_transaction=None) qs = qs.filter(credit_transaction__valid=False)
if not self.request.GET["valid"]:
q = ~q
qs = qs.filter(q)
return qs[:20] return qs[:20]