Merge branch 'aureplop/kfet-tests_perform_operations' into 'master'

kfet.tests -- Add tests for perform_operations view + small things

See merge request cof-geek/gestioCOF!313
This commit is contained in:
Martin Pepin 2018-10-04 23:59:30 +02:00
commit 39abfceb76
4 changed files with 1482 additions and 23 deletions

View file

@ -1,25 +1,39 @@
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import models from django.db import models
from djconfig import config import djconfig
class KFetConfig(object): class KFetConfig(object):
"""kfet app configuration. """kfet app configuration.
Enhance isolation with backend used to store config. Enhance isolation with backend used to store config.
Usable after DjConfig middleware was called.
""" """
prefix = 'kfet_' prefix = 'kfet_'
def __init__(self):
# Set this to False again to reload the config, e.g for testing
# purposes.
self._conf_init = False
def _check_init(self):
# For initialization purposes, we call 'reload_maybe' directly
# (normaly done once per request in middleware).
# Note it should be called only once across requests, if you use
# kfet_config instance below.
if not self._conf_init:
djconfig.reload_maybe()
self._conf_init = True
def __getattr__(self, key): def __getattr__(self, key):
self._check_init()
if key == 'subvention_cof': if key == 'subvention_cof':
# Allows accessing to the reduction as a subvention # Allows accessing to the reduction as a subvention
# Other reason: backward compatibility # Other reason: backward compatibility
reduction_mult = 1 - self.reduction_cof/100 reduction_mult = 1 - self.reduction_cof/100
return (1/reduction_mult - 1) * 100 return (1/reduction_mult - 1) * 100
return getattr(config, self._get_dj_key(key)) return getattr(djconfig.config, self._get_dj_key(key))
def list(self): def list(self):
"""Get list of kfet app configuration. """Get list of kfet app configuration.
@ -30,7 +44,8 @@ class KFetConfig(object):
""" """
# prevent circular imports # prevent circular imports
from kfet.forms import KFetConfigForm from kfet.forms import KFetConfigForm
return [(field.label, getattr(config, name), ) self._check_init()
return [(field.label, getattr(djconfig.config, name), )
for name, field in KFetConfigForm.base_fields.items()] for name, field in KFetConfigForm.base_fields.items()]
def _get_dj_key(self, key): def _get_dj_key(self, key):
@ -47,6 +62,7 @@ class KFetConfig(object):
# prevent circular imports # prevent circular imports
from kfet.forms import KFetConfigForm from kfet.forms import KFetConfigForm
self._check_init()
# get old config # get old config
new_cfg = KFetConfigForm().initial new_cfg = KFetConfigForm().initial
# update to new config # update to new config

View file

@ -3,6 +3,7 @@ from decimal import Decimal
from django import forms from django import forms
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core import validators
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.forms import modelformset_factory from django.forms import modelformset_factory
from django.utils import timezone from django.utils import timezone
@ -273,6 +274,10 @@ class ArticleRestrictForm(ArticleForm):
# ----- # -----
class KPsulOperationGroupForm(forms.ModelForm): class KPsulOperationGroupForm(forms.ModelForm):
# FIXME(AD): Use timezone.now instead of timezone.now() to avoid using a
# fixed datetime (application boot here).
# One may even use: Checkout.objects.is_valid() if changing
# to now = timezone.now is ok in 'is_valid' definition.
checkout = forms.ModelChoiceField( checkout = forms.ModelChoiceField(
queryset = Checkout.objects.filter( queryset = Checkout.objects.filter(
is_protected=False, valid_from__lte=timezone.now(), is_protected=False, valid_from__lte=timezone.now(),
@ -317,13 +322,18 @@ class KPsulOperationForm(forms.ModelForm):
queryset=Article.objects.select_related('category').all(), queryset=Article.objects.select_related('category').all(),
required=False, required=False,
widget = forms.HiddenInput()) widget = forms.HiddenInput())
article_nb = forms.IntegerField(
required=False,
initial=None,
validators=[validators.MinValueValidator(1)],
widget=forms.HiddenInput(),
)
class Meta: class Meta:
model = Operation model = Operation
fields = ['type', 'amount', 'article', 'article_nb'] fields = ['type', 'amount', 'article', 'article_nb']
widgets = { widgets = {
'type': forms.HiddenInput(), 'type': forms.HiddenInput(),
'amount': forms.HiddenInput(), 'amount': forms.HiddenInput(),
'article_nb': forms.HiddenInput(),
} }
def clean(self): def clean(self):
@ -332,22 +342,26 @@ class KPsulOperationForm(forms.ModelForm):
amount = self.cleaned_data.get('amount') amount = self.cleaned_data.get('amount')
article = self.cleaned_data.get('article') article = self.cleaned_data.get('article')
article_nb = self.cleaned_data.get('article_nb') article_nb = self.cleaned_data.get('article_nb')
errors = []
if type_ope and type_ope == Operation.PURCHASE: if type_ope and type_ope == Operation.PURCHASE:
if not article or not article_nb: if not article or article_nb is None or article_nb < 1:
raise ValidationError( errors.append(ValidationError(
"Un achat nécessite un article et une quantité") "Un achat nécessite un article et une quantité"))
if article_nb < 1:
raise ValidationError("Impossible d'acheter moins de 1 article")
elif type_ope and type_ope in [Operation.DEPOSIT, Operation.WITHDRAW]: elif type_ope and type_ope in [Operation.DEPOSIT, Operation.WITHDRAW]:
if not amount or article or article_nb: if not amount or article or article_nb:
raise ValidationError("Bad request") errors.append(ValidationError("Bad request"))
if type_ope == Operation.DEPOSIT and amount <= 0: else:
raise ValidationError("Charge non positive") if type_ope == Operation.DEPOSIT and amount <= 0:
if type_ope == Operation.WITHDRAW and amount >= 0: errors.append(ValidationError("Charge non positive"))
raise ValidationError("Retrait non négatif") elif type_ope == Operation.WITHDRAW and amount >= 0:
errors.append(ValidationError("Retrait non négatif"))
self.cleaned_data['article'] = None self.cleaned_data['article'] = None
self.cleaned_data['article_nb'] = None self.cleaned_data['article_nb'] = None
if errors:
raise ValidationError(errors)
KPsulOperationFormSet = modelformset_factory( KPsulOperationFormSet = modelformset_factory(
Operation, Operation,
form = KPsulOperationForm, form = KPsulOperationForm,

File diff suppressed because it is too large Load diff

View file

@ -178,7 +178,9 @@ class ViewTestCaseMixin(TestCaseMixin):
During setup, three users are created with their kfet account: During setup, three users are created with their kfet account:
- 'user': a basic user without any permission, account trigramme: 000, - 'user': a basic user without any permission, account trigramme: 000,
- 'team': a user with kfet.is_team permission, account trigramme: 100, - 'team': a user with kfet.is_team permission, account trigramme: 100,
- 'root': a superuser, account trigramme: 200. - 'root': a superuser, account trigramme: 200,
- 'liq': if class attribute 'with_liq' is 'True', account
trigramme: LIQ.
Their password is their username. Their password is their username.
One can create additionnal users with 'get_users_extra' method, or prevent One can create additionnal users with 'get_users_extra' method, or prevent
@ -221,6 +223,8 @@ class ViewTestCaseMixin(TestCaseMixin):
auth_user = None auth_user = None
auth_forbidden = [] auth_forbidden = []
with_liq = False
def setUp(self): def setUp(self):
""" """
Warning: Do not forget to call super().setUp() in subclasses. Warning: Do not forget to call super().setUp() in subclasses.
@ -262,7 +266,7 @@ class ViewTestCaseMixin(TestCaseMixin):
""" """
# Format desc: username, password, trigramme # Format desc: username, password, trigramme
return { users_base = {
# user, user, 000 # user, user, 000
'user': create_user(), 'user': create_user(),
# team, team, 100 # team, team, 100
@ -270,6 +274,9 @@ class ViewTestCaseMixin(TestCaseMixin):
# root, root, 200 # root, root, 200
'root': create_root(), 'root': create_root(),
} }
if self.with_liq:
users_base['liq'] = create_user('liq', 'LIQ')
return users_base
@cached_property @cached_property
def users_base(self): def users_base(self):