gestioCOF/kfet/forms.py
Aurélien Delobelle 85657591f5 Fix fields cleaning with unreachable items when…
… object is being created.
2017-10-12 11:10:30 +02:00

582 lines
19 KiB
Python

# -*- coding: utf-8 -*-
from datetime import timedelta
from decimal import Decimal
from django import forms
from django.core.exceptions import ValidationError
from django.contrib.auth.models import User, Group, Permission
from django.contrib.contenttypes.models import ContentType
from django.forms import modelformset_factory, widgets
from django.utils import timezone
from djconfig.forms import ConfigForm
from kfet.models import (
Account, Checkout, Article, OperationGroup, Operation,
CheckoutStatement, ArticleCategory, AccountNegative, Transfer,
TransferGroup, Supplier)
from gestioncof.models import CofProfile
# -----
# Widgets
# -----
class DateTimeWidget(forms.DateTimeInput):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.attrs['format'] = '%Y-%m-%d %H:%M'
class Media:
css = {
'all': ('kfet/css/bootstrap-datetimepicker.min.css',)
}
js = ('kfet/js/bootstrap-datetimepicker.min.js',)
# -----
# Account forms
# -----
class AccountForm(forms.ModelForm):
# Surcharge pour passer data à Account.save()
def save(self, data = {}, *args, **kwargs):
obj = super(AccountForm, self).save(commit = False, *args, **kwargs)
obj.save(data = data)
return obj
class Meta:
model = Account
fields = ['trigramme', 'promo', 'nickname', 'is_frozen']
widgets = {
'trigramme': forms.TextInput(attrs={'autocomplete': 'off'}),
}
class AccountBalanceForm(forms.ModelForm):
class Meta:
model = Account
fields = ['balance']
class AccountTriForm(AccountForm):
def clean_trigramme(self):
trigramme = self.cleaned_data['trigramme']
return trigramme.upper()
class Meta(AccountForm.Meta):
fields = ['trigramme']
class AccountNoTriForm(AccountForm):
class Meta(AccountForm.Meta):
exclude = ['trigramme']
class AccountRestrictForm(AccountForm):
class Meta(AccountForm.Meta):
fields = ['is_frozen']
class AccountPwdForm(forms.Form):
pwd1 = forms.CharField(
label="Mot de passe K-Fêt",
help_text="Le mot de passe doit contenir au moins huit caractères",
widget=forms.PasswordInput)
pwd2 = forms.CharField(
label="Confirmer le mot de passe",
widget=forms.PasswordInput)
def clean(self):
pwd1 = self.cleaned_data.get('pwd1', '')
pwd2 = self.cleaned_data.get('pwd2', '')
if len(pwd1) < 8:
raise ValidationError("Mot de passe trop court")
if pwd1 != pwd2:
raise ValidationError("Les mots de passes sont différents")
super(AccountPwdForm, self).clean()
class CofForm(forms.ModelForm):
def clean_is_cof(self):
instance = getattr(self, 'instance', None)
if instance and instance.pk:
return instance.is_cof
else:
return False
class Meta:
model = CofProfile
fields = ['login_clipper', 'is_cof', 'departement']
class CofRestrictForm(CofForm):
class Meta(CofForm.Meta):
fields = ['departement']
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ['username', 'first_name', 'last_name', 'email']
help_texts = {
'username': ''
}
class UserRestrictForm(UserForm):
class Meta(UserForm.Meta):
fields = ['first_name', 'last_name']
class UserRestrictTeamForm(UserForm):
class Meta(UserForm.Meta):
fields = ['first_name', 'last_name', 'email']
class UserGroupForm(forms.ModelForm):
groups = forms.ModelMultipleChoiceField(
Group.objects.filter(name__icontains='K-Fêt'),
label='Statut équipe',
required=False)
def clean_groups(self):
kfet_groups = self.cleaned_data.get('groups')
if self.instance.pk is None:
return kfet_groups
other_groups = self.instance.groups.exclude(name__icontains='K-Fêt')
return list(kfet_groups) + list(other_groups)
class Meta:
model = User
fields = ['groups']
class KFetPermissionsField(forms.ModelMultipleChoiceField):
def __init__(self, *args, **kwargs):
queryset = Permission.objects.filter(
content_type__in=ContentType.objects.filter(app_label="kfet"),
)
super().__init__(
queryset=queryset,
widget=widgets.CheckboxSelectMultiple,
*args, **kwargs
)
def label_from_instance(self, obj):
return obj.name
class GroupForm(forms.ModelForm):
permissions = KFetPermissionsField()
def clean_name(self):
name = self.cleaned_data['name']
return 'K-Fêt %s' % name
def clean_permissions(self):
kfet_perms = self.cleaned_data['permissions']
# TODO: With Django >=1.11, the QuerySet method 'difference' can be used.
# other_groups = self.instance.permissions.difference(
# self.fields['permissions'].queryset
# )
if self.instance.pk is None:
return kfet_perms
other_perms = self.instance.permissions.exclude(
pk__in=[p.pk for p in self.fields['permissions'].queryset],
)
return list(kfet_perms) + list(other_perms)
class Meta:
model = Group
fields = ['name', 'permissions']
class AccountNegativeForm(forms.ModelForm):
class Meta:
model = AccountNegative
fields = ['authz_overdraft_amount', 'authz_overdraft_until',
'balance_offset', 'comment']
widgets = {
'authz_overdraft_until': DateTimeWidget(),
}
# -----
# Checkout forms
# -----
class CheckoutForm(forms.ModelForm):
class Meta:
model = Checkout
fields = ['name', 'valid_from', 'valid_to', 'balance', 'is_protected']
widgets = {
'valid_from': DateTimeWidget(),
'valid_to' : DateTimeWidget(),
}
class CheckoutRestrictForm(CheckoutForm):
class Meta(CheckoutForm.Meta):
fields = ['name', 'valid_from', 'valid_to']
class CheckoutStatementCreateForm(forms.ModelForm):
balance_001 = forms.IntegerField(min_value=0, initial=0, required=False)
balance_002 = forms.IntegerField(min_value=0, initial=0, required=False)
balance_005 = forms.IntegerField(min_value=0, initial=0, required=False)
balance_01 = forms.IntegerField(min_value=0, initial=0, required=False)
balance_02 = forms.IntegerField(min_value=0, initial=0, required=False)
balance_05 = forms.IntegerField(min_value=0, initial=0, required=False)
balance_1 = forms.IntegerField(min_value=0, initial=0, required=False)
balance_2 = forms.IntegerField(min_value=0, initial=0, required=False)
balance_5 = forms.IntegerField(min_value=0, initial=0, required=False)
balance_10 = forms.IntegerField(min_value=0, initial=0, required=False)
balance_20 = forms.IntegerField(min_value=0, initial=0, required=False)
balance_50 = forms.IntegerField(min_value=0, initial=0, required=False)
balance_100 = forms.IntegerField(min_value=0, initial=0, required=False)
balance_200 = forms.IntegerField(min_value=0, initial=0, required=False)
balance_500 = forms.IntegerField(min_value=0, initial=0, required=False)
class Meta:
model = CheckoutStatement
exclude = ['by', 'at', 'checkout', 'amount_error', 'amount_taken',
'balance_old', 'balance_new']
def clean(self):
not_count = self.cleaned_data['not_count']
if not not_count and (
self.cleaned_data['balance_001'] is None
or self.cleaned_data['balance_002'] is None
or self.cleaned_data['balance_005'] is None
or self.cleaned_data['balance_01'] is None
or self.cleaned_data['balance_02'] is None
or self.cleaned_data['balance_05'] is None
or self.cleaned_data['balance_1'] is None
or self.cleaned_data['balance_2'] is None
or self.cleaned_data['balance_5'] is None
or self.cleaned_data['balance_10'] is None
or self.cleaned_data['balance_20'] is None
or self.cleaned_data['balance_50'] is None
or self.cleaned_data['balance_100'] is None
or self.cleaned_data['balance_200'] is None
or self.cleaned_data['balance_500'] is None):
raise ValidationError("Y'a un problème. Si tu comptes la caisse, mets au moins des 0 stp (et t'as pas idée de comment c'est long de vérifier que t'as mis des valeurs de partout...)")
super(CheckoutStatementCreateForm, self).clean()
class CheckoutStatementUpdateForm(forms.ModelForm):
class Meta:
model = CheckoutStatement
exclude = ['by', 'at', 'checkout', 'amount_error', 'amount_taken']
# -----
# Category
# -----
class CategoryForm(forms.ModelForm):
class Meta:
model = ArticleCategory
fields = ['name', 'has_addcost']
# -----
# Article forms
# -----
class ArticleForm(forms.ModelForm):
category_new = forms.CharField(
label="Créer une catégorie",
max_length=45,
required = False)
category = forms.ModelChoiceField(
label="Catégorie",
queryset = ArticleCategory.objects.all(),
required = False)
suppliers = forms.ModelMultipleChoiceField(
label="Fournisseurs",
queryset = Supplier.objects.all(),
required = False)
supplier_new = forms.CharField(
label="Créer un fournisseur",
max_length = 45,
required = False)
def __init__(self, *args, **kwargs):
super(ArticleForm, self).__init__(*args, **kwargs)
if self.instance.pk:
self.initial['suppliers'] = self.instance.suppliers.values_list('pk', flat=True)
def clean(self):
category = self.cleaned_data.get('category')
category_new = self.cleaned_data.get('category_new')
if not category and not category_new:
raise ValidationError('Sélectionnez une catégorie ou créez en une')
elif not category:
category, _ = ArticleCategory.objects.get_or_create(name=category_new)
self.cleaned_data['category'] = category
super(ArticleForm, self).clean()
class Meta:
model = Article
fields = ['name', 'is_sold', 'hidden', 'price', 'stock', 'category', 'box_type',
'box_capacity']
class ArticleRestrictForm(ArticleForm):
class Meta(ArticleForm.Meta):
fields = ['name', 'is_sold', 'hidden', 'price', 'category', 'box_type',
'box_capacity']
# -----
# K-Psul forms
# -----
class KPsulOperationGroupForm(forms.ModelForm):
checkout = forms.ModelChoiceField(
queryset = Checkout.objects.filter(
is_protected=False, valid_from__lte=timezone.now(),
valid_to__gte=timezone.now()),
widget = forms.HiddenInput())
on_acc = forms.ModelChoiceField(
queryset = Account.objects.exclude(trigramme='GNR'),
widget = forms.HiddenInput())
class Meta:
model = OperationGroup
fields = ['on_acc', 'checkout', 'comment']
class KPsulAccountForm(forms.ModelForm):
class Meta:
model = Account
fields = ['trigramme']
widgets = {
'trigramme': forms.TextInput(
attrs={
'autocomplete': 'off',
'spellcheck': 'false',
}),
}
class KPsulCheckoutForm(forms.Form):
checkout = forms.ModelChoiceField(
queryset=(
Checkout.objects
.filter(
is_protected=False,
valid_from__lte=timezone.now(),
valid_to__gte=timezone.now(),
)
),
widget=forms.Select(attrs={'id': 'id_checkout_select'}),
)
class KPsulOperationForm(forms.ModelForm):
article = forms.ModelChoiceField(
queryset=Article.objects.select_related('category').all(),
required=False,
widget = forms.HiddenInput())
class Meta:
model = Operation
fields = ['type', 'amount', 'article', 'article_nb']
widgets = {
'type': forms.HiddenInput(),
'amount': forms.HiddenInput(),
'article_nb': forms.HiddenInput(),
}
def clean(self):
super(KPsulOperationForm, self).clean()
type_ope = self.cleaned_data.get('type')
amount = self.cleaned_data.get('amount')
article = self.cleaned_data.get('article')
article_nb = self.cleaned_data.get('article_nb')
if type_ope and type_ope == Operation.PURCHASE:
if not article or not article_nb:
raise ValidationError(
"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]:
if not amount or article or article_nb:
raise ValidationError("Bad request")
if type_ope == Operation.DEPOSIT and amount <= 0:
raise ValidationError("Charge non positive")
if type_ope == Operation.WITHDRAW and amount >= 0:
raise ValidationError("Retrait non négatif")
self.cleaned_data['article'] = None
self.cleaned_data['article_nb'] = None
KPsulOperationFormSet = modelformset_factory(
Operation,
form = KPsulOperationForm,
can_delete = True,
extra = 0,
min_num = 1, validate_min = True)
class AddcostForm(forms.Form):
trigramme = forms.CharField(required = False)
amount = forms.DecimalField(
required = False,
max_digits=6,decimal_places=2,min_value=Decimal(0))
def clean(self):
trigramme = self.cleaned_data.get('trigramme')
if trigramme:
try:
Account.objects.get(trigramme=trigramme)
except Account.DoesNotExist:
raise ValidationError('Compte invalide')
else:
self.cleaned_data['amount'] = 0
super(AddcostForm, self).clean()
# -----
# Settings forms
# -----
class KFetConfigForm(ConfigForm):
kfet_reduction_cof = forms.DecimalField(
label='Réduction COF', initial=Decimal('20'),
max_digits=6, decimal_places=2,
help_text="Réduction, à donner en pourcentage, appliquée lors d'un "
"achat par un-e membre du COF sur le montant en euros.",
)
kfet_addcost_amount = forms.DecimalField(
label='Montant de la majoration (en €)', initial=Decimal('0'),
required=False,
max_digits=6, decimal_places=2,
)
kfet_addcost_for = forms.ModelChoiceField(
label='Destinataire de la majoration', initial=None, required=False,
help_text='Laissez vide pour désactiver la majoration.',
queryset=(Account.objects
.select_related('cofprofile', 'cofprofile__user')
.all()),
)
kfet_overdraft_duration = forms.DurationField(
label='Durée du découvert autorisé par défaut',
initial=timedelta(days=1),
)
kfet_overdraft_amount = forms.DecimalField(
label='Montant du découvert autorisé par défaut (en €)',
initial=Decimal('20'),
max_digits=6, decimal_places=2,
)
kfet_cancel_duration = forms.DurationField(
label='Durée pour annuler une commande sans mot de passe',
initial=timedelta(minutes=5),
)
class FilterHistoryForm(forms.Form):
checkouts = forms.ModelMultipleChoiceField(queryset=Checkout.objects.all())
accounts = forms.ModelMultipleChoiceField(queryset=Account.objects.all())
from_date = forms.DateTimeField(widget=DateTimeWidget)
to_date = forms.DateTimeField(widget=DateTimeWidget)
# -----
# Transfer forms
# -----
class TransferGroupForm(forms.ModelForm):
class Meta:
model = TransferGroup
fields = ['comment']
class TransferForm(forms.ModelForm):
from_acc = forms.ModelChoiceField(
queryset = Account.objects.exclude(trigramme__in=['LIQ', '#13', 'GNR']),
widget = forms.HiddenInput()
)
to_acc = forms.ModelChoiceField(
queryset = Account.objects.exclude(trigramme__in=['LIQ', '#13', 'GNR']),
widget = forms.HiddenInput()
)
def clean_amount(self):
amount = self.cleaned_data['amount']
if amount <= 0:
raise forms.ValidationError("Montant invalide")
return amount
class Meta:
model = Transfer
fields = ['from_acc', 'to_acc', 'amount']
TransferFormSet = modelformset_factory(
Transfer,
form = TransferForm,
min_num = 1, validate_min = True,
extra = 9,
)
# -----
# Inventory forms
# -----
class InventoryArticleForm(forms.Form):
article = forms.ModelChoiceField(
queryset = Article.objects.all(),
widget = forms.HiddenInput(),
)
stock_new = forms.IntegerField(required=False)
def __init__(self, *args, **kwargs):
super(InventoryArticleForm, self).__init__(*args, **kwargs)
if 'initial' in kwargs:
self.name = kwargs['initial']['name']
self.stock_old = kwargs['initial']['stock_old']
self.category = kwargs['initial']['category']
self.category_name = kwargs['initial']['category__name']
self.box_capacity = kwargs['initial']['box_capacity']
# -----
# Order forms
# -----
class OrderArticleForm(forms.Form):
article = forms.ModelChoiceField(
queryset=Article.objects.all(),
widget=forms.HiddenInput(),
)
quantity_ordered = forms.IntegerField(required=False)
def __init__(self, *args, **kwargs):
super(OrderArticleForm, self).__init__(*args, **kwargs)
if 'initial' in kwargs:
self.name = kwargs['initial']['name']
self.stock = kwargs['initial']['stock']
self.category = kwargs['initial']['category']
self.category_name = kwargs['initial']['category__name']
self.box_capacity = kwargs['initial']['box_capacity']
self.v_all = kwargs['initial']['v_all']
self.v_moy = kwargs['initial']['v_moy']
self.v_et = kwargs['initial']['v_et']
self.v_prev = kwargs['initial']['v_prev']
self.c_rec = kwargs['initial']['c_rec']
class OrderArticleToInventoryForm(forms.Form):
article = forms.ModelChoiceField(
queryset = Article.objects.all(),
widget = forms.HiddenInput(),
)
price_HT = forms.DecimalField(
max_digits = 7, decimal_places = 4,
required = False)
TVA = forms.DecimalField(
max_digits = 7, decimal_places = 2,
required = False)
rights = forms.DecimalField(
max_digits = 7, decimal_places = 4,
required = False)
quantity_received = forms.IntegerField()
def __init__(self, *args, **kwargs):
super(OrderArticleToInventoryForm, self).__init__(*args, **kwargs)
if 'initial' in kwargs:
self.name = kwargs['initial']['name']
self.category = kwargs['initial']['category']
self.category_name = kwargs['initial']['category__name']
self.quantity_ordered = kwargs['initial']['quantity_ordered']