kpsul/kfet/forms.py
2017-06-23 02:53:05 +02:00

573 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.core.validators import MinLengthValidator
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):
def __init__(self, *args, **kwargs):
from_clipper = kwargs.pop('from_clipper', False)
new_user = kwargs.get('instance') is None and not from_clipper
super(UserForm, self).__init__(*args, **kwargs)
if new_user:
self.fields['username'].validators = [MinLengthValidator(9)]
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')
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
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']