8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-12-23 15:33:45 +00:00

ACL sur les paiements.

This commit is contained in:
Hugo LEVY-FALK 2018-07-03 18:53:44 +02:00
parent 5f1e2380c8
commit 5887eb68ae
6 changed files with 141 additions and 59 deletions

View file

@ -94,3 +94,14 @@ If you to restrict the IP which can see the debug, use the `INTERNAL_IPS` option
```
INTERNAL_IPS = ["10.0.0.1", "10.0.0.2"]
```
## MR 174 : Fix online payment + allow users to pay their subscription
Add the possibility to use custom payment methods. There is also a boolean field on the
Payments allowing every user to use some kinds of payment. You have to add the rights `cotisations.use_every_payment` and `cotisations.buy_every_article`
to the staff members so they can use every type of payment to buy anything.
Don't forget to run migrations, several settings previously in the `preferences` app ar now
in their own Payment models.
To have a closer look on how the payments works, pleas go to the wiki.

View file

@ -53,16 +53,16 @@ class NewFactureForm(FormRevMixin, ModelForm):
Form used to create a new invoice by using a payment method, a bank and a
cheque number.
"""
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
allowed_payment = kwargs.pop('allowed_payment', None)
super(NewFactureForm, self).__init__(*args, prefix=prefix, **kwargs)
# TODO : remove the use of cheque and banque and paiement
# for something more generic or at least in English
if allowed_payment:
self.fields['paiement'].queryset = allowed_payment
self.fields['paiement'].empty_label = \
_("Select a payment method")
self.fields['paiement'].queryset = Paiement.objects.filter(
pk__in=map(lambda x: x.pk, Paiement.find_allowed_payments(user))
)
class Meta:
model = Facture
@ -71,16 +71,10 @@ class NewFactureForm(FormRevMixin, ModelForm):
def clean(self):
cleaned_data = super(NewFactureForm, self).clean()
paiement = cleaned_data.get('paiement')
cheque = cleaned_data.get('cheque')
banque = cleaned_data.get('banque')
if not paiement:
raise forms.ValidationError(
_("A payment method must be specified.")
)
elif paiement.type_paiement == 'check' and not (cheque and banque):
raise forms.ValidationError(
_("A cheque number and a bank must be specified.")
)
return cleaned_data
@ -103,8 +97,7 @@ class CreditSoldeForm(NewFactureForm):
montant = forms.DecimalField(max_digits=5, decimal_places=2, required=True)
class SelectUserArticleForm(
FormRevMixin, Form):
class SelectUserArticleForm(FormRevMixin, Form):
"""
Form used to select an article during the creation of an invoice for a
member.
@ -123,12 +116,11 @@ class SelectUserArticleForm(
)
def __init__(self, *args, **kwargs):
self_subscription = kwargs.pop('is_self_subscription', False)
user = kwargs.pop('user')
super(SelectUserArticleForm, self).__init__(*args, **kwargs)
if self_subscription:
self.fields['article'].queryset = Article.objects.filter(
Q(type_user='All') | Q(type_user='Adherent')
).filter(allow_self_subscription=True)
self.fields['article'].queryset = Article.objects.filter(
pk__in=map(lambda x: x.pk, Article.find_allowed_articles(user))
)
class SelectClubArticleForm(Form):
@ -150,12 +142,11 @@ class SelectClubArticleForm(Form):
)
def __init__(self, *args, **kwargs):
self_subscription = kwargs.pop('is_self_subscription', False)
user = kwargs.pop('user')
super(SelectClubArticleForm, self).__init__(*args, **kwargs)
if self_subscription:
self.fields['article'].queryset = Article.objects.filter(
Q(type_user='All') | Q(type_user='Club')
).filter(allow_self_subscription=True)
self.fields['article'].queryset = Article.objects.filter(
pk__in=map(lambda x: x.pk, Article.find_allowed_articles(user))
)
# TODO : change Facture to Invoice
@ -242,7 +233,7 @@ class PaiementForm(FormRevMixin, ModelForm):
class Meta:
model = Paiement
# TODO : change moyen to method and type_paiement to payment_type
fields = ['moyen', 'allow_self_subscription']
fields = ['moyen', 'available_for_everyone']
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
@ -315,6 +306,7 @@ class NewFactureSoldeForm(NewFactureForm):
"""
Form used to create an invoice
"""
def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(NewFactureSoldeForm, self).__init__(

View file

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-07-03 15:05
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cotisations', '0034_auto_20180703_0929'),
]
operations = [
migrations.AlterModelOptions(
name='paiement',
options={'permissions': (('view_paiement', "Can see a payement's details"), ('use', 'Can use a payement')), 'verbose_name': 'Payment method', 'verbose_name_plural': 'Payment methods'},
),
migrations.RemoveField(
model_name='paiement',
name='allow_self_subscription',
),
migrations.AddField(
model_name='paiement',
name='available_for_everyone',
field=models.BooleanField(default=False, verbose_name='Is available for every user'),
),
]

View file

@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.7 on 2018-07-03 15:56
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cotisations', '0035_auto_20180703_1005'),
]
operations = [
migrations.AlterModelOptions(
name='article',
options={'permissions': (('view_article', "Can see an article's details"), ('buy_every_article', 'Can buy every_article')), 'verbose_name': 'Article', 'verbose_name_plural': 'Articles'},
),
migrations.RemoveField(
model_name='article',
name='allow_self_subscription',
),
migrations.AddField(
model_name='article',
name='available_for_everyone',
field=models.BooleanField(default=False, verbose_name='Is available for every user'),
),
]

View file

@ -49,7 +49,6 @@ from django.contrib import messages
from machines.models import regen
from re2o.field_permissions import FieldPermissionModelMixin
from re2o.mixins import AclMixin, RevMixin
from preferences.models import OptionalUser
from cotisations.utils import find_payment_method
@ -227,10 +226,11 @@ class Facture(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
:return: a message and a boolean which is True if the user can create
an invoice or if the `options.allow_self_subscription` is set.
"""
if OptionalUser.get_cached_value('allow_self_subscription'):
return True, None
nb_payments = len(Paiement.find_allowed_payments(user_request))
nb_articles = len(Article.find_allowed_articles(user_request))
return (
user_request.has_perm('cotisations.add_facture'),
user_request.has_perm('cotisations.add_facture')
or (nb_payments*nb_articles),
_("You don't have the right to create an invoice.")
)
@ -522,9 +522,9 @@ class Article(RevMixin, AclMixin, models.Model):
max_length=255,
verbose_name=_l("Type of cotisation")
)
allow_self_subscription = models.BooleanField(
available_for_everyone = models.BooleanField(
default=False,
verbose_name=_l("Is available for self subscription")
verbose_name=_l("Is available for every user")
)
unique_together = ('name', 'type_user')
@ -532,6 +532,7 @@ class Article(RevMixin, AclMixin, models.Model):
class Meta:
permissions = (
('view_article', _l("Can see an article's details")),
('buy_every_article', _l("Can buy every_article"))
)
verbose_name = "Article"
verbose_name_plural = "Articles"
@ -549,6 +550,24 @@ class Article(RevMixin, AclMixin, models.Model):
def __str__(self):
return self.name
def can_buy_article(self, user, *_args, **_kwargs):
"""Check if a user can buy this article.
:param self: The article
:param user: The user requesting buying
:returns: A boolean stating if usage is granted and an explanation
message if the boolean is `False`.
"""
return (
self.available_for_everyone
or user.has_perm('cotisations.buy_every_article'),
_("You cannot use this Payment.")
)
@classmethod
def find_allowed_articles(cls, user):
return [p for p in cls.objects.all() if p.can_buy_article(user)[0]]
class Banque(RevMixin, AclMixin, models.Model):
"""
@ -601,14 +620,15 @@ class Paiement(RevMixin, AclMixin, models.Model):
default=0,
verbose_name=_l("Payment type")
)
allow_self_subscription = models.BooleanField(
available_for_everyone = models.BooleanField(
default=False,
verbose_name=_l("Is available for self subscription")
verbose_name=_l("Is available for every user")
)
class Meta:
permissions = (
('view_paiement', _l("Can see a payement's details")),
('use_every_payment', _l("Can use every payement")),
)
verbose_name = _l("Payment method")
verbose_name_plural = _l("Payment methods")
@ -671,6 +691,24 @@ class Paiement(RevMixin, AclMixin, models.Model):
kwargs={'userid': invoice.user.pk}
))
def can_use_payment(self, user, *_args, **_kwargs):
"""Check if a user can use this payment.
:param self: The payment
:param user: The user requesting usage
:returns: A boolean stating if usage is granted and an explanation
message if the boolean is `False`.
"""
return (
self.available_for_everyone
or user.has_perm('cotisations.use_every_payment'),
_("You cannot use this Payment.")
)
@classmethod
def find_allowed_payments(cls, user):
return [p for p in cls.objects.all() if p.can_use_payment(user)[0]]
class Cotisation(RevMixin, AclMixin, models.Model):
"""

View file

@ -98,40 +98,22 @@ def new_facture(request, user, userid):
article_list = Article.objects.filter(
Q(type_user='All') | Q(type_user=request.user.class_name)
)
# Building the invocie form and the article formset
is_self_subscription = False
can_create_invoice = request.user.has_perm('cotisations.add_facture')
allow_self_subscription = OptionalUser.get_cached_value(
'allow_self_subscription')
if not can_create_invoice:
if allow_self_subscription:
is_self_subscription = True
article_list = article_list.filter(allow_self_subscription=True)
allowed_payment = Paiement.objects.filter(
allow_self_subscription=True)
invoice_form = NewFactureForm(
request.POST or None, instance=invoice, allowed_payment=allowed_payment)
else:
messages.error(
request,
_("You cannot subscribe. Please ask to the staff.")
)
return redirect(reverse(
'users:profil',
kwargs={'userid': userid}
))
else:
invoice_form = NewFactureForm(request.POST or None, instance=invoice)
# Building the invoice form and the article formset
invoice_form = NewFactureForm(
request.POST or None,
instance=invoice,
user=request.user
)
if request.user.is_class_club:
article_formset = formset_factory(SelectClubArticleForm)(
request.POST or None,
form_kwargs={'is_self_subscription': is_self_subscription}
form_kwargs={'user': request.user}
)
else:
article_formset = formset_factory(SelectUserArticleForm)(
request.POST or None,
form_kwargs={'is_self_subscription': is_self_subscription}
form_kwargs={'user': request.user}
)
if invoice_form.is_valid() and article_formset.is_valid():
@ -156,7 +138,10 @@ def new_facture(request, user, userid):
)
new_purchase.save()
return new_invoice_instance.paiement.end_payment(new_invoice_instance, request)
return new_invoice_instance.paiement.end_payment(
new_invoice_instance,
request
)
messages.error(
request,