8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-11-27 07:02:26 +00:00

Translation: Marking of strings in cotisations app

This commit is contained in:
Maël Kervella 2018-03-31 13:43:46 +00:00
parent 99928c885b
commit a7d47b972d
5 changed files with 481 additions and 190 deletions

View file

@ -25,6 +25,7 @@
Here are defined some functions to check acl on the application. Here are defined some functions to check acl on the application.
""" """
from django.utils.translation import ugettext as _
def can_view(user): def can_view(user):
"""Check if an user can view the application. """Check if an user can view the application.
@ -37,4 +38,4 @@ def can_view(user):
viewing is granted and msg is a message (can be None). viewing is granted and msg is a message (can be None).
""" """
can = user.has_module_perms('cotisations') can = user.has_module_perms('cotisations')
return can, None if can else "Vous ne pouvez pas voir cette application." return can, None if can else _("You don't have the rights to see this application.")

View file

@ -40,6 +40,8 @@ from django import forms
from django.db.models import Q from django.db.models import Q
from django.forms import ModelForm, Form from django.forms import ModelForm, Form
from django.core.validators import MinValueValidator,MaxValueValidator from django.core.validators import MinValueValidator,MaxValueValidator
from django.utils.translation import ugettext as _
from .models import Article, Paiement, Facture, Banque from .models import Article, Paiement, Facture, Banque
from preferences.models import OptionalUser from preferences.models import OptionalUser
from users.models import User from users.models import User
@ -50,15 +52,18 @@ from re2o.mixins import FormRevMixin
class NewFactureForm(FormRevMixin, ModelForm): class NewFactureForm(FormRevMixin, ModelForm):
"""Creation d'une facture, moyen de paiement, banque et numero """Creation d'une facture, moyen de paiement, banque et numero
de cheque""" de cheque"""
# TODO : translate doc string in English
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(NewFactureForm, self).__init__(*args, prefix=prefix, **kwargs) 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
self.fields['cheque'].required = False self.fields['cheque'].required = False
self.fields['banque'].required = False self.fields['banque'].required = False
self.fields['cheque'].label = 'Numero de chèque' self.fields['cheque'].label = _("Cheque number")
self.fields['banque'].empty_label = "Non renseigné" self.fields['banque'].empty_label = _("Not specified")
self.fields['paiement'].empty_label = "Séléctionner\ self.fields['paiement'].empty_label = \
un moyen de paiement" _("Select a payment method")
paiement_list = Paiement.objects.filter(type_paiement=1) paiement_list = Paiement.objects.filter(type_paiement=1)
if paiement_list: if paiement_list:
self.fields['paiement'].widget\ self.fields['paiement'].widget\
@ -70,41 +75,47 @@ class NewFactureForm(FormRevMixin, ModelForm):
def clean(self): def clean(self):
cleaned_data = super(NewFactureForm, self).clean() cleaned_data = super(NewFactureForm, self).clean()
paiement = cleaned_data.get("paiement") paiement = cleaned_data.get('paiement')
cheque = cleaned_data.get("cheque") cheque = cleaned_data.get('cheque')
banque = cleaned_data.get("banque") banque = cleaned_data.get('banque')
if not paiement: if not paiement:
raise forms.ValidationError("Le moyen de paiement est obligatoire") raise forms.ValidationError(
elif paiement.type_paiement == "check" and not (cheque and banque): _("A payment method must be specified")
raise forms.ValidationError("Le numéro de chèque et\ )
la banque sont obligatoires.") 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 return cleaned_data
class CreditSoldeForm(NewFactureForm): class CreditSoldeForm(NewFactureForm):
"""Permet de faire des opérations sur le solde si il est activé""" """Permet de faire des opérations sur le solde si il est activé"""
# TODO : translate docstring to English
class Meta(NewFactureForm.Meta): class Meta(NewFactureForm.Meta):
model = Facture model = Facture
fields = ['paiement', 'banque', 'cheque'] fields = ['paiement', 'banque', 'cheque']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(CreditSoldeForm, self).__init__(*args, **kwargs) super(CreditSoldeForm, self).__init__(*args, **kwargs)
# TODO : change solde to balance
self.fields['paiement'].queryset = Paiement.objects.exclude( self.fields['paiement'].queryset = Paiement.objects.exclude(
moyen='solde' moyen='solde'
).exclude(moyen="Solde") ).exclude(moyen='Solde')
montant = forms.DecimalField(max_digits=5, decimal_places=2, required=True) montant = forms.DecimalField(max_digits=5, decimal_places=2, required=True)
class SelectUserArticleForm(FormRevMixin, Form): class SelectUserArticleForm(FormRevMixin, Form):
"""Selection d'un article lors de la creation d'une facture""" """Selection d'un article lors de la creation d'une facture"""
# TODO : translate docstring to English
article = forms.ModelChoiceField( article = forms.ModelChoiceField(
queryset=Article.objects.filter(Q(type_user='All') | Q(type_user='Adherent')), queryset=Article.objects.filter(Q(type_user='All') | Q(type_user='Adherent')),
label="Article", label=_("Article"),
required=True required=True
) )
quantity = forms.IntegerField( quantity = forms.IntegerField(
label="Quantité", label=_("Quantity"),
validators=[MinValueValidator(1)], validators=[MinValueValidator(1)],
required=True required=True
) )
@ -112,54 +123,63 @@ class SelectUserArticleForm(FormRevMixin, Form):
class SelectClubArticleForm(Form): class SelectClubArticleForm(Form):
"""Selection d'un article lors de la creation d'une facture""" """Selection d'un article lors de la creation d'une facture"""
# TODO : translate docstring to English
article = forms.ModelChoiceField( article = forms.ModelChoiceField(
queryset=Article.objects.filter(Q(type_user='All') | Q(type_user='Club')), queryset=Article.objects.filter(Q(type_user='All') | Q(type_user='Club')),
label="Article", label=_("Article"),
required=True required=True
) )
quantity = forms.IntegerField( quantity = forms.IntegerField(
label="Quantité", label=_("Quantity"),
validators=[MinValueValidator(1)], validators=[MinValueValidator(1)],
required=True required=True
) )
# TODO : change Facture to Invoice
class NewFactureFormPdf(Form): class NewFactureFormPdf(Form):
"""Creation d'un pdf facture par le trésorier""" """Creation d'un pdf facture par le trésorier"""
# TODO : translate docstring to English
article = forms.ModelMultipleChoiceField( article = forms.ModelMultipleChoiceField(
queryset=Article.objects.all(), queryset=Article.objects.all(),
label="Article" label=_("Article")
) )
number = forms.IntegerField( number = forms.IntegerField(
label="Quantité", label=_("Quantity"),
validators=[MinValueValidator(1)] validators=[MinValueValidator(1)]
) )
paid = forms.BooleanField(label="Payé", required=False) paid = forms.BooleanField(label=_("Paid"), required=False)
dest = forms.CharField(required=True, max_length=255, label="Destinataire") # TODO : change dest field to recipient
chambre = forms.CharField(required=False, max_length=10, label="Adresse") dest = forms.CharField(required=True, max_length=255, label=_("Recipient"))
# TODO : change chambre field to address
chambre = forms.CharField(required=False, max_length=10, label=_("Address"))
# TODO : change fid field to invoice_id
fid = forms.CharField( fid = forms.CharField(
required=True, required=True,
max_length=10, max_length=10,
label="Numéro de la facture" label=_("Invoice number")
) )
# TODO : change Facture to Invoice
class EditFactureForm(FieldPermissionFormMixin, NewFactureForm): class EditFactureForm(FieldPermissionFormMixin, NewFactureForm):
"""Edition d'une facture : moyen de paiement, banque, user parent""" """Edition d'une facture : moyen de paiement, banque, user parent"""
# TODO : translate docstring to English
class Meta(NewFactureForm.Meta): class Meta(NewFactureForm.Meta):
# TODO : change Facture to Invoice
model = Facture model = Facture
fields = '__all__' fields = '__all__'
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
# TODO : change Facture to Invoice
super(EditFactureForm, self).__init__(*args, **kwargs) super(EditFactureForm, self).__init__(*args, **kwargs)
self.fields['user'].label = 'Adherent' self.fields['user'].label = _("Member")
self.fields['user'].empty_label = "Séléctionner\ self.fields['user'].empty_label = \
l'adhérent propriétaire" _("Select the proprietary member")
self.fields['valid'].label = 'Validité de la facture' self.fields['valid'].label = _("Validated invoice")
class ArticleForm(FormRevMixin, ModelForm): class ArticleForm(FormRevMixin, ModelForm):
"""Creation d'un article. Champs : nom, cotisation, durée""" """Creation d'un article. Champs : nom, cotisation, durée"""
# TODO : translate docstring to English
class Meta: class Meta:
model = Article model = Article
fields = '__all__' fields = '__all__'
@ -167,15 +187,16 @@ class ArticleForm(FormRevMixin, ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(ArticleForm, self).__init__(*args, prefix=prefix, **kwargs) super(ArticleForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['name'].label = "Désignation de l'article" self.fields['name'].label = _("Article name")
class DelArticleForm(FormRevMixin, Form): class DelArticleForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs articles en vente. Choix """Suppression d'un ou plusieurs articles en vente. Choix
parmis les modèles""" parmis les modèles"""
# TODO : translate docstring to English
articles = forms.ModelMultipleChoiceField( articles = forms.ModelMultipleChoiceField(
queryset=Article.objects.none(), queryset=Article.objects.none(),
label="Articles actuels", label=_("Existing articles"),
widget=forms.CheckboxSelectMultiple widget=forms.CheckboxSelectMultiple
) )
@ -188,26 +209,36 @@ class DelArticleForm(FormRevMixin, Form):
self.fields['articles'].queryset = Article.objects.all() self.fields['articles'].queryset = Article.objects.all()
# TODO : change Paiement to Payment
class PaiementForm(FormRevMixin, ModelForm): class PaiementForm(FormRevMixin, ModelForm):
"""Creation d'un moyen de paiement, champ text moyen et type """Creation d'un moyen de paiement, champ text moyen et type
permettant d'indiquer si il s'agit d'un chèque ou non pour le form""" permettant d'indiquer si il s'agit d'un chèque ou non pour le form"""
# TODO : translate docstring to English
class Meta: class Meta:
model = Paiement model = Paiement
# TODO : change moyen to method and type_paiement to payment_type
fields = ['moyen', 'type_paiement'] fields = ['moyen', 'type_paiement']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(PaiementForm, self).__init__(*args, prefix=prefix, **kwargs) super(PaiementForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['moyen'].label = 'Moyen de paiement à ajouter' self.fields['moyen'].label = _("Payment method name")
self.fields['type_paiement'].label = 'Type de paiement à ajouter' self.fields['type_paiement'].label = _("Payment type")
self.fields['type_paiement'].help_text = \
_("The payement type is use for specific behaviour.\
The \"cheque\" type means a cheque number and a bank name\
may be added when using this payment method.")
# TODO : change paiement to payment
class DelPaiementForm(FormRevMixin, Form): class DelPaiementForm(FormRevMixin, Form):
"""Suppression d'un ou plusieurs moyens de paiements, selection """Suppression d'un ou plusieurs moyens de paiements, selection
parmis les models""" parmis les models"""
# TODO : translate docstring to English
# TODO : change paiement to payment
paiements = forms.ModelMultipleChoiceField( paiements = forms.ModelMultipleChoiceField(
queryset=Paiement.objects.none(), queryset=Paiement.objects.none(),
label="Moyens de paiement actuels", label=_("Existing payment method"),
widget=forms.CheckboxSelectMultiple widget=forms.CheckboxSelectMultiple
) )
@ -220,23 +251,29 @@ class DelPaiementForm(FormRevMixin, Form):
self.fields['paiements'].queryset = Paiement.objects.all() self.fields['paiements'].queryset = Paiement.objects.all()
# TODO : change banque to bank
class BanqueForm(FormRevMixin, ModelForm): class BanqueForm(FormRevMixin, ModelForm):
"""Creation d'une banque, field name""" """Creation d'une banque, field name"""
# TODO : translate docstring to Englishh
class Meta: class Meta:
# TODO : change banque to bank
model = Banque model = Banque
fields = ['name'] fields = ['name']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop('prefix', self.Meta.model.__name__)
super(BanqueForm, self).__init__(*args, prefix=prefix, **kwargs) super(BanqueForm, self).__init__(*args, prefix=prefix, **kwargs)
self.fields['name'].label = 'Banque à ajouter' self.fields['name'].label = _("Bank name")
# TODO : change banque to bank
class DelBanqueForm(FormRevMixin, Form): class DelBanqueForm(FormRevMixin, Form):
"""Selection d'une ou plusieurs banques, pour suppression""" """Selection d'une ou plusieurs banques, pour suppression"""
# TODO : translate docstrign to English
# TODO : change banque to bank
banques = forms.ModelMultipleChoiceField( banques = forms.ModelMultipleChoiceField(
queryset=Banque.objects.none(), queryset=Banque.objects.none(),
label="Banques actuelles", label=_("Existing banks"),
widget=forms.CheckboxSelectMultiple widget=forms.CheckboxSelectMultiple
) )
@ -249,43 +286,56 @@ class DelBanqueForm(FormRevMixin, Form):
self.fields['banques'].queryset = Banque.objects.all() self.fields['banques'].queryset = Banque.objects.all()
# TODO : change facture to Invoice
class NewFactureSoldeForm(NewFactureForm): class NewFactureSoldeForm(NewFactureForm):
"""Creation d'une facture, moyen de paiement, banque et numero """Creation d'une facture, moyen de paiement, banque et numero
de cheque""" de cheque"""
# TODO : translate docstring to English
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
prefix = kwargs.pop('prefix', self.Meta.model.__name__) prefix = kwargs.pop('prefix', self.Meta.model.__name__)
self.fields['cheque'].required = False self.fields['cheque'].required = False
self.fields['banque'].required = False self.fields['banque'].required = False
self.fields['cheque'].label = 'Numero de chèque' self.fields['cheque'].label = _('Cheque number')
self.fields['banque'].empty_label = "Non renseigné" self.fields['banque'].empty_label = _("Not specified")
self.fields['paiement'].empty_label = "Séléctionner\ self.fields['paiement'].empty_label = \
une bite de paiement" _("Select a payment method")
# TODO : change paiement to payment
paiement_list = Paiement.objects.filter(type_paiement=1) paiement_list = Paiement.objects.filter(type_paiement=1)
if paiement_list: if paiement_list:
self.fields['paiement'].widget\ self.fields['paiement'].widget\
.attrs['data-cheque'] = paiement_list.first().id .attrs['data-cheque'] = paiement_list.first().id
class Meta: class Meta:
# TODO : change facture to invoice
model = Facture model = Facture
# TODO : change paiement to payment and baque to bank
fields = ['paiement', 'banque'] fields = ['paiement', 'banque']
def clean(self): def clean(self):
cleaned_data = super(NewFactureSoldeForm, self).clean() cleaned_data = super(NewFactureSoldeForm, self).clean()
# TODO : change paiement to payment
paiement = cleaned_data.get("paiement") paiement = cleaned_data.get("paiement")
cheque = cleaned_data.get("cheque") cheque = cleaned_data.get("cheque")
# TODO : change banque to bank
banque = cleaned_data.get("banque") banque = cleaned_data.get("banque")
# TODO : change paiement to payment
if not paiement: if not paiement:
raise forms.ValidationError("Le moyen de paiement est obligatoire") raise forms.ValidationError(
_("A payment method must be specified.")
)
# TODO : change paiement and banque to payment and bank
elif paiement.type_paiement == "check" and not (cheque and banque): elif paiement.type_paiement == "check" and not (cheque and banque):
raise forms.ValidationError("Le numéro de chèque et\ raise forms.ValidationError(
la banque sont obligatoires.") _("A cheque number and a bank must be specified.")
)
return cleaned_data return cleaned_data
# TODO : Better name and docstring
class RechargeForm(FormRevMixin, Form): class RechargeForm(FormRevMixin, Form):
value = forms.FloatField( value = forms.FloatField(
label='Valeur', label=_("Amount"),
min_value=0.01, min_value=0.01,
validators = [] validators = []
) )
@ -297,7 +347,21 @@ class RechargeForm(FormRevMixin, Form):
def clean_value(self): def clean_value(self):
value = self.cleaned_data['value'] value = self.cleaned_data['value']
if value < OptionalUser.get_cached_value('min_online_payment'): if value < OptionalUser.get_cached_value('min_online_payment'):
raise forms.ValidationError("Montant inférieur au montant minimal de paiement en ligne (%s) €" % OptionalUser.get_cached_value('min_online_payment')) raise forms.ValidationError(
_("Requested amount is too small. Minimum amount possible : \
%(min_online_amount)s ") % {
min_online_amount: OptionalUser.get_cached_value(
'min_online_payment'
)
}
)
if value + self.user.solde > OptionalUser.get_cached_value('max_solde'): if value + self.user.solde > OptionalUser.get_cached_value('max_solde'):
raise forms.ValidationError("Le solde ne peux excéder %s " % OptionalUser.get_cached_value('max_solde')) raise forms.ValidationError(
_("Requested amount is too high. Your balance can't exceed \
%(max_online_balance)s ") % {
max_online_balance: OptionalUser.get_cached_value(
'max_solde'
)
}
)
return value return value

View file

@ -42,6 +42,7 @@ Post_save et Post_delete : sychronisation des services et régénération
des services d'accès réseau (ex dhcp) lors de la vente d'une cotisation des services d'accès réseau (ex dhcp) lors de la vente d'une cotisation
par exemple par exemple
""" """
# TODO : translate docstring to English
from __future__ import unicode_literals from __future__ import unicode_literals
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
@ -55,55 +56,86 @@ from django.core.validators import MinValueValidator
from django.db.models import Max from django.db.models import Max
from django.utils import timezone from django.utils import timezone
from machines.models import regen from machines.models import regen
from django.utils.translation import ugettext as _
from re2o.field_permissions import FieldPermissionModelMixin from re2o.field_permissions import FieldPermissionModelMixin
from re2o.mixins import AclMixin, RevMixin from re2o.mixins import AclMixin, RevMixin
# TODO : change facture to invoice
class Facture(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model): class Facture(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
""" Définition du modèle des factures. Une facture regroupe une ou """ Définition du modèle des factures. Une facture regroupe une ou
plusieurs ventes, rattachée à un user, et reliée à un moyen de paiement plusieurs ventes, rattachée à un user, et reliée à un moyen de paiement
et si il y a lieu un numero pour les chèques. Possède les valeurs et si il y a lieu un numero pour les chèques. Possède les valeurs
valides et controle (trésorerie)""" valides et controle (trésorerie)"""
PRETTY_NAME = "Factures émises" # TODO : translate docstrign to English
user = models.ForeignKey('users.User', on_delete=models.PROTECT) user = models.ForeignKey('users.User', on_delete=models.PROTECT)
# TODO : change paiement to payment
paiement = models.ForeignKey('Paiement', on_delete=models.PROTECT) paiement = models.ForeignKey('Paiement', on_delete=models.PROTECT)
# TODO : change banque to bank
banque = models.ForeignKey( banque = models.ForeignKey(
'Banque', 'Banque',
on_delete=models.PROTECT, on_delete=models.PROTECT,
blank=True, blank=True,
null=True) null=True
cheque = models.CharField(max_length=255, blank=True) )
date = models.DateTimeField(auto_now_add=True) # TODO : maybe change to cheque nummber because not evident
valid = models.BooleanField(default=True) cheque = models.CharField(
control = models.BooleanField(default=False) max_length=255,
blank=True,
verbose_name=_("Cheque number")
)
date = models.DateTimeField(
auto_now_add=True,
verbose_name=_("Date")
)
# TODO : change name to validity for clarity
valid = models.BooleanField(
default=True,
verbose_name=_("Validated")
)
# TODO : changed name to controlled for clarity
control = models.BooleanField(
default=False,
verbose_name=_("Controlled")
)
class Meta: class Meta:
abstract = False abstract = False
permissions = ( permissions = (
("change_facture_control", "Peut changer l'etat de controle"), # TODO : change facture to invoice
("change_facture_pdf", "Peut éditer une facture pdf"), ('change_facture_control', _("Can change the controlled state")),
("view_facture", "Peut voir un objet facture"), # TODO : seems more likely to be call create_facture_pdf or create_invoice_pdf
("change_all_facture", "Superdroit, peut modifier toutes les factures"), ('change_facture_pdf', _("Can create a custom PDF invoice")),
('view_facture', _("Can see an invoice's details")),
('change_all_facture', _("Can edit all the previous invoices")),
) )
verbose_name = _("Invoice")
verbose_name_plural = _("Invoices")
def linked_objects(self): def linked_objects(self):
"""Return linked objects : machine and domain. """Return linked objects : machine and domain.
Usefull in history display""" Usefull in history display"""
return self.vente_set.all() return self.vente_set.all()
# TODO : change prix to price
def prix(self): def prix(self):
"""Renvoie le prix brut sans les quantités. Méthode """Renvoie le prix brut sans les quantités. Méthode
dépréciée""" dépréciée"""
# TODO : translate docstring to English
# TODO : change prix to price
prix = Vente.objects.filter( prix = Vente.objects.filter(
facture=self facture=self
).aggregate(models.Sum('prix'))['prix__sum'] ).aggregate(models.Sum('prix'))['prix__sum']
return prix return prix
# TODO : change prix to price
def prix_total(self): def prix_total(self):
"""Prix total : somme des produits prix_unitaire et quantité des """Prix total : somme des produits prix_unitaire et quantité des
ventes de l'objet""" ventes de l'objet"""
# TODO : translate docstrign to English
# TODO : change Vente to somethingelse
return Vente.objects.filter( return Vente.objects.filter(
facture=self facture=self
).aggregate( ).aggregate(
@ -115,6 +147,7 @@ class Facture(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
def name(self): def name(self):
"""String, somme des name des ventes de self""" """String, somme des name des ventes de self"""
# TODO : translate docstring to English
name = ' - '.join(Vente.objects.filter( name = ' - '.join(Vente.objects.filter(
facture=self facture=self
).values_list('name', flat=True)) ).values_list('name', flat=True))
@ -122,44 +155,41 @@ class Facture(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
def can_edit(self, user_request, *args, **kwargs): def can_edit(self, user_request, *args, **kwargs):
if not user_request.has_perm('cotisations.change_facture'): if not user_request.has_perm('cotisations.change_facture'):
return False, u"Vous n'avez pas le droit d'éditer les factures" return False, _("You don't have the right to edit an invoice.")
elif not user_request.has_perm('cotisations.change_all_facture') and not self.user.can_edit(user_request, *args, **kwargs)[0]: elif not user_request.has_perm('cotisations.change_all_facture') and not self.user.can_edit(user_request, *args, **kwargs)[0]:
return False, u"Vous ne pouvez pas éditer les factures de cet user protégé" return False, _("You don't have the right to edit this user's invoices.")
elif not user_request.has_perm('cotisations.change_all_facture') and\ elif not user_request.has_perm('cotisations.change_all_facture') and\
(self.control or not self.valid): (self.control or not self.valid):
return False, u"Vous n'avez pas le droit d'éditer une facture\ return False, _("You don't have the right to edit an invoice already controlled or invalidated.")
controlée ou invalidée par un trésorier"
else: else:
return True, None return True, None
def can_delete(self, user_request, *args, **kwargs): def can_delete(self, user_request, *args, **kwargs):
if not user_request.has_perm('cotisations.delete_facture'): if not user_request.has_perm('cotisations.delete_facture'):
return False, u"Vous n'avez pas le droit de supprimer une facture" return False, _("You don't have the right to delete an invoice.")
if not self.user.can_edit(user_request, *args, **kwargs)[0]: if not self.user.can_edit(user_request, *args, **kwargs)[0]:
return False, u"Vous ne pouvez pas éditer les factures de cet user protégé" return False, _("You don't have the right to delete this user's invoices.")
if self.control or not self.valid: if self.control or not self.valid:
return False, u"Vous ne pouvez pas supprimer une facture\ return False, _("You don't have the right to delete an invoice already controlled or invalidated.")
contrôlée ou invalidée par un trésorier"
else: else:
return True, None return True, None
def can_view(self, user_request, *args, **kwargs): def can_view(self, user_request, *args, **kwargs):
if not user_request.has_perm('cotisations.view_facture') and\ if not user_request.has_perm('cotisations.view_facture') and\
self.user != user_request: self.user != user_request:
return False, u"Vous ne pouvez pas afficher l'historique d'une\ return False, _("You don't have the right to see someone else's invoices history.")
facture d'un autre user que vous sans droit cableur"
elif not self.valid: elif not self.valid:
return False, u"La facture est invalidée et ne peut être affichée" return False, _("The invoice has been invalidated.")
else: else:
return True, None return True, None
@staticmethod @staticmethod
def can_change_control(user_request, *args, **kwargs): def can_change_control(user_request, *args, **kwargs):
return user_request.has_perm('cotisations.change_facture_control'), "Vous ne pouvez pas éditer le controle sans droit trésorier" return user_request.has_perm('cotisations.change_facture_control'), _("You don't have the right to edit the controlled state.")
@staticmethod @staticmethod
def can_change_pdf(user_request, *args, **kwargs): def can_change_pdf(user_request, *args, **kwargs):
return user_request.has_perm('cotisations.change_facture_pdf'), "Vous ne pouvez pas éditer une facture sans droit trésorier" return user_request.has_perm('cotisations.change_facture_pdf'), _("You don't have the right to edit an invoice.")
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(Facture, self).__init__(*args, **kwargs) super(Facture, self).__init__(*args, **kwargs)
@ -174,6 +204,7 @@ class Facture(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
@receiver(post_save, sender=Facture) @receiver(post_save, sender=Facture)
def facture_post_save(sender, **kwargs): def facture_post_save(sender, **kwargs):
"""Post save d'une facture, synchronise l'user ldap""" """Post save d'une facture, synchronise l'user ldap"""
# TODO : translate docstrign into English
facture = kwargs['instance'] facture = kwargs['instance']
user = facture.user user = facture.user
user.ldap_sync(base=False, access_refresh=True, mac_refresh=False) user.ldap_sync(base=False, access_refresh=True, mac_refresh=False)
@ -182,51 +213,82 @@ def facture_post_save(sender, **kwargs):
@receiver(post_delete, sender=Facture) @receiver(post_delete, sender=Facture)
def facture_post_delete(sender, **kwargs): def facture_post_delete(sender, **kwargs):
"""Après la suppression d'une facture, on synchronise l'user ldap""" """Après la suppression d'une facture, on synchronise l'user ldap"""
# TODO : translate docstring into English
user = kwargs['instance'].user user = kwargs['instance'].user
user.ldap_sync(base=False, access_refresh=True, mac_refresh=False) user.ldap_sync(base=False, access_refresh=True, mac_refresh=False)
# TODO : change Vente to Purchase
class Vente(RevMixin, AclMixin, models.Model): class Vente(RevMixin, AclMixin, models.Model):
"""Objet vente, contient une quantité, une facture parente, un nom, """Objet vente, contient une quantité, une facture parente, un nom,
un prix. Peut-être relié à un objet cotisation, via le boolean un prix. Peut-être relié à un objet cotisation, via le boolean
iscotisation""" iscotisation"""
PRETTY_NAME = "Ventes effectuées" # TODO : translate docstring into English
# TODO : change this to English
COTISATION_TYPE = ( COTISATION_TYPE = (
('Connexion', 'Connexion'), ('Connexion', _("Connexion")),
('Adhesion', 'Adhesion'), ('Adhesion', _("Membership")),
('All', 'All'), ('All', _("Both of them")),
) )
facture = models.ForeignKey('Facture', on_delete=models.CASCADE) # TODO : change facture to invoice
number = models.IntegerField(validators=[MinValueValidator(1)]) facture = models.ForeignKey(
name = models.CharField(max_length=255) 'Facture',
prix = models.DecimalField(max_digits=5, decimal_places=2) on_delete=models.CASCADE,
verbose_name=_("Invoice")
)
# TODO : change number to amount for clarity
number = models.IntegerField(
validators=[MinValueValidator(1)],
verbose_name=_("Amount")
)
# TODO : change this field for a ForeinKey to Article
name = models.CharField(
max_length=255,
verbose_name=_("Article")
)
# TODO : change prix to price
# TODO : this field is not needed if you use Article ForeignKey
prix = models.DecimalField(
max_digits=5,
decimal_places=2,
verbose_name=_("Price"))
# TODO : this field is not needed if you use Article ForeignKey
duration = models.PositiveIntegerField( duration = models.PositiveIntegerField(
help_text="Durée exprimée en mois entiers",
blank=True, blank=True,
null=True) null=True,
verbose_name=_("Duration (in whole month)")
)
# TODO : this field is not needed if you use Article ForeignKey
type_cotisation = models.CharField( type_cotisation = models.CharField(
choices=COTISATION_TYPE, choices=COTISATION_TYPE,
blank=True, blank=True,
null=True, null=True,
max_length=255 max_length=255,
verbose_name=_("Type of cotisation")
) )
class Meta: class Meta:
permissions = ( permissions = (
("view_vente", "Peut voir un objet vente"), ('view_vente', _("Can see a purchase's details")),
("change_all_vente", "Superdroit, peut modifier toutes les ventes"), ('change_all_vente', _("Can edit all the previous purchases")),
) )
verbose_name = _("Purchase")
verbose_name_plural = _("Purchases")
# TODO : change prix_total to total_price
def prix_total(self): def prix_total(self):
"""Renvoie le prix_total de self (nombre*prix)""" """Renvoie le prix_total de self (nombre*prix)"""
# TODO : translate docstring to english
return self.prix*self.number return self.prix*self.number
def update_cotisation(self): def update_cotisation(self):
"""Mets à jour l'objet related cotisation de la vente, si """Mets à jour l'objet related cotisation de la vente, si
il existe : update la date de fin à partir de la durée de il existe : update la date de fin à partir de la durée de
la vente""" la vente"""
# TODO : translate docstring to English
if hasattr(self, 'cotisation'): if hasattr(self, 'cotisation'):
cotisation = self.cotisation cotisation = self.cotisation
cotisation.date_end = cotisation.date_start + relativedelta( cotisation.date_end = cotisation.date_start + relativedelta(
@ -237,6 +299,7 @@ class Vente(RevMixin, AclMixin, models.Model):
"""Update et crée l'objet cotisation associé à une facture, prend """Update et crée l'objet cotisation associé à une facture, prend
en argument l'user, la facture pour la quantitéi, et l'article pour en argument l'user, la facture pour la quantitéi, et l'article pour
la durée""" la durée"""
# TODO : translate docstring to English
if not hasattr(self, 'cotisation') and self.type_cotisation: if not hasattr(self, 'cotisation') and self.type_cotisation:
cotisation = Cotisation(vente=self) cotisation = Cotisation(vente=self)
cotisation.type_cotisation = self.type_cotisation cotisation.type_cotisation = self.type_cotisation
@ -264,41 +327,40 @@ class Vente(RevMixin, AclMixin, models.Model):
return return
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
# TODO : ecrire une docstring
# On verifie que si iscotisation, duration est présent # On verifie que si iscotisation, duration est présent
if self.type_cotisation and not self.duration: if self.type_cotisation and not self.duration:
raise ValidationError("Cotisation et durée doivent être présents\ raise ValidationError(
ensembles") _("A cotisation should always have a duration.")
)
self.update_cotisation() self.update_cotisation()
super(Vente, self).save(*args, **kwargs) super(Vente, self).save(*args, **kwargs)
def can_edit(self, user_request, *args, **kwargs): def can_edit(self, user_request, *args, **kwargs):
if not user_request.has_perm('cotisations.change_vente'): if not user_request.has_perm('cotisations.change_vente'):
return False, u"Vous n'avez pas le droit d'éditer les ventes" return False, _("You don't have the rights to edit the purchases.")
elif not user_request.has_perm('cotisations.change_all_facture') and not self.facture.user.can_edit(user_request, *args, **kwargs)[0]: elif not user_request.has_perm('cotisations.change_all_facture') and not self.facture.user.can_edit(user_request, *args, **kwargs)[0]:
return False, u"Vous ne pouvez pas éditer les factures de cet user protégé" return False, _("You don't have the right to edit this user's purchases.")
elif not user_request.has_perm('cotisations.change_all_vente') and\ elif not user_request.has_perm('cotisations.change_all_vente') and\
(self.facture.control or not self.facture.valid): (self.facture.control or not self.facture.valid):
return False, u"Vous n'avez pas le droit d'éditer une vente\ return False, _("You don't have the right to edit a purchase already controlled or invalidated.")
controlée ou invalidée par un trésorier"
else: else:
return True, None return True, None
def can_delete(self, user_request, *args, **kwargs): def can_delete(self, user_request, *args, **kwargs):
if not user_request.has_perm('cotisations.delete_vente'): if not user_request.has_perm('cotisations.delete_vente'):
return False, u"Vous n'avez pas le droit de supprimer une vente" return False, _("You don't have the right to delete a purchase.")
if not self.facture.user.can_edit(user_request, *args, **kwargs)[0]: if not self.facture.user.can_edit(user_request, *args, **kwargs)[0]:
return False, u"Vous ne pouvez pas éditer les factures de cet user protégé" return False, _("You don't have the right to delete this user's purchases.")
if self.facture.control or not self.facture.valid: if self.facture.control or not self.facture.valid:
return False, u"Vous ne pouvez pas supprimer une vente\ return False, _("You don't have the right to delete a purchase already controlled or invalidated.")
contrôlée ou invalidée par un trésorier"
else: else:
return True, None return True, None
def can_view(self, user_request, *args, **kwargs): def can_view(self, user_request, *args, **kwargs):
if not user_request.has_perm('cotisations.view_vente') and\ if not user_request.has_perm('cotisations.view_vente') and\
self.facture.user != user_request: self.facture.user != user_request:
return False, u"Vous ne pouvez pas afficher l'historique d'une\ return False, _("You don't have the right to see someone else's purchase history.")
facture d'un autre user que vous sans droit cableur"
else: else:
return True, None return True, None
@ -306,10 +368,13 @@ class Vente(RevMixin, AclMixin, models.Model):
return str(self.name) + ' ' + str(self.facture) return str(self.name) + ' ' + str(self.facture)
# TODO : change vente to purchase
@receiver(post_save, sender=Vente) @receiver(post_save, sender=Vente)
def vente_post_save(sender, **kwargs): def vente_post_save(sender, **kwargs):
"""Post save d'une vente, déclencge la création de l'objet cotisation """Post save d'une vente, déclencge la création de l'objet cotisation
si il y a lieu(si iscotisation) """ si il y a lieu(si iscotisation) """
# TODO : translate docstring to English
# TODO : change vente to purchase
vente = kwargs['instance'] vente = kwargs['instance']
if hasattr(vente, 'cotisation'): if hasattr(vente, 'cotisation'):
vente.cotisation.vente = vente vente.cotisation.vente = vente
@ -321,10 +386,13 @@ def vente_post_save(sender, **kwargs):
user.ldap_sync(base=False, access_refresh=True, mac_refresh=False) user.ldap_sync(base=False, access_refresh=True, mac_refresh=False)
# TODO : change vente to purchase
@receiver(post_delete, sender=Vente) @receiver(post_delete, sender=Vente)
def vente_post_delete(sender, **kwargs): def vente_post_delete(sender, **kwargs):
"""Après suppression d'une vente, on synchronise l'user ldap (ex """Après suppression d'une vente, on synchronise l'user ldap (ex
suppression d'une cotisation""" suppression d'une cotisation"""
# TODO : translate docstring to English
# TODO : change vente to purchase
vente = kwargs['instance'] vente = kwargs['instance']
if vente.type_cotisation: if vente.type_cotisation:
user = vente.facture.user user = vente.facture.user
@ -334,53 +402,69 @@ def vente_post_delete(sender, **kwargs):
class Article(RevMixin, AclMixin, models.Model): class Article(RevMixin, AclMixin, models.Model):
"""Liste des articles en vente : prix, nom, et attribut iscotisation """Liste des articles en vente : prix, nom, et attribut iscotisation
et duree si c'est une cotisation""" et duree si c'est une cotisation"""
PRETTY_NAME = "Articles en vente" # TODO : translate docstring to English
# TODO : Either use TYPE or TYPES in both choices but not both
USER_TYPES = ( USER_TYPES = (
('Adherent', 'Adherent'), ('Adherent', _("Member")),
('Club', 'Club'), ('Club', _("Club")),
('All', 'All'), ('All', _("Both of them")),
) )
COTISATION_TYPE = ( COTISATION_TYPE = (
('Connexion', 'Connexion'), ('Connexion', _("Connexion")),
('Adhesion', 'Adhesion'), ('Adhesion', _("Membership")),
('All', 'All'), ('All', _("Both of them")),
) )
name = models.CharField(max_length=255) name = models.CharField(
prix = models.DecimalField(max_digits=5, decimal_places=2) max_length=255,
verbose_name=_("Designation")
)
# TODO : change prix to price
prix = models.DecimalField(
max_digits=5,
decimal_places=2,
verbose_name=_("Unitary price")
)
duration = models.PositiveIntegerField( duration = models.PositiveIntegerField(
help_text="Durée exprimée en mois entiers",
blank=True, blank=True,
null=True, null=True,
validators=[MinValueValidator(0)]) validators=[MinValueValidator(0)],
verbose_name=_("Duration (in whole month)")
)
type_user = models.CharField( type_user = models.CharField(
choices=USER_TYPES, choices=USER_TYPES,
default='All', default='All',
max_length=255 max_length=255,
verbose_name=_("Type of users concerned")
) )
type_cotisation = models.CharField( type_cotisation = models.CharField(
choices=COTISATION_TYPE, choices=COTISATION_TYPE,
default=None, default=None,
blank=True, blank=True,
null=True, null=True,
max_length=255 max_length=255,
verbose_name=_("Type of cotisation")
) )
unique_together = ('name', 'type_user') unique_together = ('name', 'type_user')
class Meta: class Meta:
permissions = ( permissions = (
("view_article", "Peut voir un objet article"), ('view_article', _("Can see an article's details")),
) )
verbose_name = "Article"
verbose_name_plural = "Articles"
def clean(self): def clean(self):
if self.name.lower() == "solde": if self.name.lower() == 'solde':
raise ValidationError("Solde est un nom d'article invalide") raise ValidationError(
_("Solde is a reserved article name")
)
if self.type_cotisation and not self.duration: if self.type_cotisation and not self.duration:
raise ValidationError( raise ValidationError(
"La durée est obligatoire si il s'agit d'une cotisation" _("Duration must be specified for a cotisation")
) )
def __str__(self): def __str__(self):
@ -389,34 +473,51 @@ class Article(RevMixin, AclMixin, models.Model):
class Banque(RevMixin, AclMixin, models.Model): class Banque(RevMixin, AclMixin, models.Model):
"""Liste des banques""" """Liste des banques"""
PRETTY_NAME = "Banques enregistrées" # TODO : translate docstring to English
name = models.CharField(max_length=255) name = models.CharField(
max_length=255,
verbose_name=_("Name")
)
class Meta: class Meta:
permissions = ( permissions = (
("view_banque", "Peut voir un objet banque"), ('view_banque', _("Can see a bank's details")),
) )
verbose_name=_("Bank")
verbose_name_plural=_("Banks")
def __str__(self): def __str__(self):
return self.name return self.name
# TODO : change Paiement to Payment
class Paiement(RevMixin, AclMixin, models.Model): class Paiement(RevMixin, AclMixin, models.Model):
"""Moyens de paiement""" """Moyens de paiement"""
PRETTY_NAME = "Moyens de paiement" # TODO : translate docstring to English
PAYMENT_TYPES = ( PAYMENT_TYPES = (
(0, 'Autre'), (0, _("Standard")),
(1, 'Chèque'), (1, _("Cheque")),
) )
moyen = models.CharField(max_length=255) # TODO : change moyen to method
type_paiement = models.IntegerField(choices=PAYMENT_TYPES, default=0) moyen = models.CharField(
max_length=255,
verbose_name=_("Method")
)
type_paiement = models.IntegerField(
choices=PAYMENT_TYPES,
default=0,
verbose_name=_("Payment type")
)
class Meta: class Meta:
permissions = ( permissions = (
("view_paiement", "Peut voir un objet paiement"), ('view_paiement', _("Can see a payement's details")),
) )
verbose_name = _("Payment method")
verbose_name_plural = _("Payment methods")
def __str__(self): def __str__(self):
return self.moyen return self.moyen
@ -426,61 +527,71 @@ class Paiement(RevMixin, AclMixin, models.Model):
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
"""Un seul type de paiement peut-etre cheque...""" """Un seul type de paiement peut-etre cheque..."""
# TODO : translate docstring to English
if Paiement.objects.filter(type_paiement=1).count() > 1: if Paiement.objects.filter(type_paiement=1).count() > 1:
raise ValidationError("On ne peut avoir plusieurs mode de paiement\ raise ValidationError(
chèque") _("You cannot have multiple payment method of type cheque")
)
super(Paiement, self).save(*args, **kwargs) super(Paiement, self).save(*args, **kwargs)
class Cotisation(RevMixin, AclMixin, models.Model): class Cotisation(RevMixin, AclMixin, models.Model):
"""Objet cotisation, debut et fin, relié en onetoone à une vente""" """Objet cotisation, debut et fin, relié en onetoone à une vente"""
PRETTY_NAME = "Cotisations" # TODO : translate docstring to English
COTISATION_TYPE = ( COTISATION_TYPE = (
('Connexion', 'Connexion'), ('Connexion', _("Connexion")),
('Adhesion', 'Adhesion'), ('Adhesion', _("Adhesion")),
('All', 'All'), ('All', _("Both of them")),
) )
vente = models.OneToOneField('Vente', on_delete=models.CASCADE, null=True) # TODO : change vente to purchase
vente = models.OneToOneField(
'Vente',
on_delete=models.CASCADE,
null=True,
verbose_name=_("Purchase")
)
type_cotisation = models.CharField( type_cotisation = models.CharField(
choices=COTISATION_TYPE, choices=COTISATION_TYPE,
max_length=255, max_length=255,
default='All', default='All',
verbose_name=_("Type of cotisation")
)
date_start = models.DateTimeField(
verbose_name=_("Starting date")
)
date_end = models.DateTimeField(
verbose_name=_("Ending date")
) )
date_start = models.DateTimeField()
date_end = models.DateTimeField()
class Meta: class Meta:
permissions = ( permissions = (
("view_cotisation", "Peut voir un objet cotisation"), ('view_cotisation', _("Can see a cotisation's details")),
("change_all_cotisation", "Superdroit, peut modifier toutes les cotisations"), ('change_all_cotisation', _("Can edit the previous cotisations")),
) )
def can_edit(self, user_request, *args, **kwargs): def can_edit(self, user_request, *args, **kwargs):
if not user_request.has_perm('cotisations.change_cotisation'): if not user_request.has_perm('cotisations.change_cotisation'):
return False, u"Vous n'avez pas le droit d'éditer les cotisations" return False, _("You don't have the right to edit a cotisation.")
elif not user_request.has_perm('cotisations.change_all_cotisation') and\ elif not user_request.has_perm('cotisations.change_all_cotisation') and\
(self.vente.facture.control or not self.vente.facture.valid): (self.vente.facture.control or not self.vente.facture.valid):
return False, u"Vous n'avez pas le droit d'éditer une cotisation\ return False, _("You don't have the right to edit a cotisation already controlled or invalidated.")
controlée ou invalidée par un trésorier"
else: else:
return True, None return True, None
def can_delete(self, user_request, *args, **kwargs): def can_delete(self, user_request, *args, **kwargs):
if not user_request.has_perm('cotisations.delete_cotisation'): if not user_request.has_perm('cotisations.delete_cotisation'):
return False, u"Vous n'avez pas le droit de supprimer une cotisations" return False, _("You don't have the right to delete a cotisation.")
if self.vente.facture.control or not self.vente.facture.valid: if self.vente.facture.control or not self.vente.facture.valid:
return False, u"Vous ne pouvez pas supprimer une cotisations\ return False, _("You don't have the right to delete a cotisation already controlled or invalidated.")
contrôlée ou invalidée par un trésorier"
else: else:
return True, None return True, None
def can_view(self, user_request, *args, **kwargs): def can_view(self, user_request, *args, **kwargs):
if not user_request.has_perm('cotisations.view_cotisation') and\ if not user_request.has_perm('cotisations.view_cotisation') and\
self.vente.facture.user != user_request: self.vente.facture.user != user_request:
return False, u"Vous ne pouvez pas afficher l'historique d'une\ return False, _("You don't have the right to display someone else's cotisation history.")
cotisation d'un autre user que vous sans droit cableur"
else: else:
return True, None return True, None
@ -491,15 +602,18 @@ class Cotisation(RevMixin, AclMixin, models.Model):
@receiver(post_save, sender=Cotisation) @receiver(post_save, sender=Cotisation)
def cotisation_post_save(sender, **kwargs): def cotisation_post_save(sender, **kwargs):
"""Après modification d'une cotisation, regeneration des services""" """Après modification d'une cotisation, regeneration des services"""
# TODO : translate docstring to English
regen('dns') regen('dns')
regen('dhcp') regen('dhcp')
regen('mac_ip_list') regen('mac_ip_list')
regen('mailing') regen('mailing')
# TODO : should be name cotisation_post_delete
@receiver(post_delete, sender=Cotisation) @receiver(post_delete, sender=Cotisation)
def vente_post_delete(sender, **kwargs): def vente_post_delete(sender, **kwargs):
"""Après suppression d'une vente, régénération des services""" """Après suppression d'une vente, régénération des services"""
# TODO : translate docstring to English
cotisation = kwargs['instance'] cotisation = kwargs['instance']
regen('mac_ip_list') regen('mac_ip_list')
regen('mailing') regen('mailing')

View file

@ -8,6 +8,7 @@ from django.contrib.auth.decorators import login_required
from django.contrib import messages from django.contrib import messages
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.utils.datastructures import MultiValueDictKeyError from django.utils.datastructures import MultiValueDictKeyError
from django.utils.translation import ugettext as _
from django.http import HttpResponse, HttpResponseBadRequest from django.http import HttpResponse, HttpResponseBadRequest
from collections import OrderedDict from collections import OrderedDict
@ -22,7 +23,9 @@ def accept_payment(request, factureid):
facture = get_object_or_404(Facture, id=factureid) facture = get_object_or_404(Facture, id=factureid)
messages.success( messages.success(
request, request,
"Le paiement de {} € a été accepté.".format(facture.prix()) _("The payment of %(amount)s € has been accepted.") % {
amount: facture.prix()
}
) )
return redirect(reverse('users:profil', kwargs={'userid':request.user.id})) return redirect(reverse('users:profil', kwargs={'userid':request.user.id}))
@ -32,7 +35,7 @@ def accept_payment(request, factureid):
def refuse_payment(request): def refuse_payment(request):
messages.error( messages.error(
request, request,
"Le paiement a été refusé." _("The payment has been refused.")
) )
return redirect(reverse('users:profil', kwargs={'userid':request.user.id})) return redirect(reverse('users:profil', kwargs={'userid':request.user.id}))
@ -53,6 +56,7 @@ def ipn(request):
idTransaction = request.POST['idTransaction'] idTransaction = request.POST['idTransaction']
# On vérifie que le paiement nous est destiné # On vérifie que le paiement nous est destiné
# TODO : translate comment to English
if not idTpe == AssoOption.get_cached_value('payment_id'): if not idTpe == AssoOption.get_cached_value('payment_id'):
return HttpResponseBadRequest("HTTP/1.1 400 Bad Request") return HttpResponseBadRequest("HTTP/1.1 400 Bad Request")
@ -63,6 +67,7 @@ def ipn(request):
facture = get_object_or_404(Facture, id=factureid) facture = get_object_or_404(Facture, id=factureid)
# TODO : translate comments to English
# On vérifie que le paiement est valide # On vérifie que le paiement est valide
if not result: if not result:
# Le paiement a échoué : on effectue les actions nécessaires (On indique qu'elle a échoué) # Le paiement a échoué : on effectue les actions nécessaires (On indique qu'elle a échoué)

View file

@ -36,6 +36,7 @@ from django.db import transaction
from django.db.models import Q from django.db.models import Q
from django.forms import modelformset_factory, formset_factory from django.forms import modelformset_factory, formset_factory
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext as _
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.debug import sensitive_variables from django.views.decorators.debug import sensitive_variables
# Import des models, forms et fonctions re2o # Import des models, forms et fonctions re2o
@ -88,12 +89,16 @@ def new_facture(request, user, userid):
enfin sauve la facture parente. enfin sauve la facture parente.
TODO : simplifier cette fonction, déplacer l'intelligence coté models TODO : simplifier cette fonction, déplacer l'intelligence coté models
Facture et Vente.""" Facture et Vente."""
# TODO : translate docstring to English
# TODO : change facture to invoice
facture = Facture(user=user) facture = Facture(user=user)
# TODO : change comment to English
# Le template a besoin de connaitre les articles pour le js # Le template a besoin de connaitre les articles pour le js
article_list = Article.objects.filter( article_list = Article.objects.filter(
Q(type_user='All') | Q(type_user=request.user.class_name) Q(type_user='All') | Q(type_user=request.user.class_name)
) )
# On envoie la form fature et un formset d'articles # On envoie la form fature et un formset d'articles
# TODO : change facture to invoice
facture_form = NewFactureForm(request.POST or None, instance=facture) facture_form = NewFactureForm(request.POST or None, instance=facture)
if request.user.is_class_club: if request.user.is_class_club:
article_formset = formset_factory(SelectClubArticleForm)(request.POST or None) article_formset = formset_factory(SelectClubArticleForm)(request.POST or None)
@ -104,22 +109,27 @@ def new_facture(request, user, userid):
articles = article_formset articles = article_formset
# Si au moins un article est rempli # Si au moins un article est rempli
if any(art.cleaned_data for art in articles): if any(art.cleaned_data for art in articles):
# TODO : change solde to balance
user_solde = OptionalUser.get_cached_value('user_solde') user_solde = OptionalUser.get_cached_value('user_solde')
solde_negatif = OptionalUser.get_cached_value('solde_negatif') solde_negatif = OptionalUser.get_cached_value('solde_negatif')
# Si on paye par solde, que l'option est activée, # Si on paye par solde, que l'option est activée,
# on vérifie que le négatif n'est pas atteint # on vérifie que le négatif n'est pas atteint
if user_solde: if user_solde:
# TODO : change Paiement to Payment
if new_facture_instance.paiement == Paiement.objects.get_or_create( if new_facture_instance.paiement == Paiement.objects.get_or_create(
moyen='solde' moyen='solde'
)[0]: )[0]:
prix_total = 0 prix_total = 0
for art_item in articles: for art_item in articles:
if art_item.cleaned_data: if art_item.cleaned_data:
# change prix to price
prix_total += art_item.cleaned_data['article']\ prix_total += art_item.cleaned_data['article']\
.prix*art_item.cleaned_data['quantity'] .prix*art_item.cleaned_data['quantity']
if float(user.solde) - float(prix_total) < solde_negatif: if float(user.solde) - float(prix_total) < solde_negatif:
messages.error(request, "Le solde est insuffisant pour\ messages.error(
effectuer l'opération") request,
_("Your balance is too low for this operation.")
)
return redirect(reverse( return redirect(reverse(
'users:profil', 'users:profil',
kwargs={'userid': userid} kwargs={'userid': userid}
@ -142,34 +152,43 @@ def new_facture(request, user, userid):
for art_item in articles if art_item.cleaned_data): for art_item in articles if art_item.cleaned_data):
messages.success( messages.success(
request, request,
"La cotisation a été prolongée\ _("The cotisation of %(member_name)s has been \
pour l'adhérent %s jusqu'au %s" % ( extended to %(end_date)s.") % {
user.pseudo, user.end_adhesion() member_name: user.pseudo,
) end_date: user.end_adhesion()
}
) )
else: else:
messages.success(request, "La facture a été crée") messages.success(
request,
_("The invoice has been created.")
)
return redirect(reverse( return redirect(reverse(
'users:profil', 'users:profil',
kwargs={'userid': userid} kwargs={'userid': userid}
)) ))
messages.error( messages.error(
request, request,
u"Il faut au moins un article valide pour créer une facture" _("You need to choose at least one article.")
) )
return form({ return form(
{
'factureform': facture_form, 'factureform': facture_form,
'venteform': article_formset, 'venteform': article_formset,
'articlelist': article_list 'articlelist': article_list
}, 'cotisations/new_facture.html', request) },
'cotisations/new_facture.html', request
)
# TODO : change facture to invoice
@login_required @login_required
@can_change(Facture, 'pdf') @can_change(Facture, 'pdf')
def new_facture_pdf(request): def new_facture_pdf(request):
"""Permet de générer un pdf d'une facture. Réservée """Permet de générer un pdf d'une facture. Réservée
au trésorier, permet d'emettre des factures sans objet au trésorier, permet d'emettre des factures sans objet
Vente ou Facture correspondant en bdd""" Vente ou Facture correspondant en bdd"""
# TODO : translate docstring to English
facture_form = NewFactureFormPdf(request.POST or None) facture_form = NewFactureFormPdf(request.POST or None)
if facture_form.is_valid(): if facture_form.is_valid():
tbl = [] tbl = []
@ -204,6 +223,7 @@ def new_facture_pdf(request):
}, 'cotisations/facture.html', request) }, 'cotisations/facture.html', request)
# TODO : change facture to invoice
@login_required @login_required
@can_view(Facture) @can_view(Facture)
def facture_pdf(request, facture, factureid): def facture_pdf(request, facture, factureid):
@ -211,7 +231,8 @@ def facture_pdf(request, facture, factureid):
et génére une facture avec le total, le moyen de paiement, l'adresse et génére une facture avec le total, le moyen de paiement, l'adresse
de l'adhérent, etc. Réservée à self pour un user sans droits, de l'adhérent, etc. Réservée à self pour un user sans droits,
les droits cableurs permettent d'afficher toute facture""" les droits cableurs permettent d'afficher toute facture"""
# TODO : translate docstring to English
# TODO : change vente to purchase
ventes_objects = Vente.objects.all().filter(facture=facture) ventes_objects = Vente.objects.all().filter(facture=facture)
ventes = [] ventes = []
for vente in ventes_objects: for vente in ventes_objects:
@ -233,12 +254,14 @@ def facture_pdf(request, facture, factureid):
}) })
# TODO : change facture to invoice
@login_required @login_required
@can_edit(Facture) @can_edit(Facture)
def edit_facture(request, facture, factureid): def edit_facture(request, facture, factureid):
"""Permet l'édition d'une facture. On peut y éditer les ventes """Permet l'édition d'une facture. On peut y éditer les ventes
déjà effectuer, ou rendre une facture invalide (non payées, chèque déjà effectuer, ou rendre une facture invalide (non payées, chèque
en bois etc). Mets à jour les durée de cotisation attenantes""" en bois etc). Mets à jour les durée de cotisation attenantes"""
# TODO : translate docstring to English
facture_form = EditFactureForm(request.POST or None, instance=facture, user=request.user) facture_form = EditFactureForm(request.POST or None, instance=facture, user=request.user)
ventes_objects = Vente.objects.filter(facture=facture) ventes_objects = Vente.objects.filter(facture=facture)
vente_form_set = modelformset_factory( vente_form_set = modelformset_factory(
@ -252,7 +275,10 @@ def edit_facture(request, facture, factureid):
if facture_form.changed_data: if facture_form.changed_data:
facture_form.save() facture_form.save()
vente_form.save() vente_form.save()
messages.success(request, "La facture a bien été modifiée") messages.success(
request,
_("The invoice has been successfully edited.")
)
return redirect(reverse('cotisations:index')) return redirect(reverse('cotisations:index'))
return form({ return form({
'factureform': facture_form, 'factureform': facture_form,
@ -260,14 +286,18 @@ def edit_facture(request, facture, factureid):
}, 'cotisations/edit_facture.html', request) }, 'cotisations/edit_facture.html', request)
# TODO : change facture to invoice
@login_required @login_required
@can_delete(Facture) @can_delete(Facture)
def del_facture(request, facture, factureid): def del_facture(request, facture, factureid):
"""Suppression d'une facture. Supprime en cascade les ventes """Suppression d'une facture. Supprime en cascade les ventes
et cotisations filles""" et cotisations filles"""
# TODO : translate docstring to English
if request.method == "POST": if request.method == "POST":
facture.delete() messages.success(
messages.success(request, "La facture a été détruite") request,
_("The invoice has been successfully deleted")
)
return redirect(reverse('cotisations:index')) return redirect(reverse('cotisations:index'))
return form({ return form({
'objet': facture, 'objet': facture,
@ -275,11 +305,14 @@ def del_facture(request, facture, factureid):
}, 'cotisations/delete.html', request) }, 'cotisations/delete.html', request)
# TODO : change solde to balance
@login_required @login_required
@can_create(Facture) @can_create(Facture)
@can_edit(User) @can_edit(User)
def credit_solde(request, user, userid): def credit_solde(request, user, userid):
""" Credit ou débit de solde """ """ Credit ou débit de solde """
# TODO : translate docstring to English
# TODO : change facture to invoice
facture = CreditSoldeForm(request.POST or None) facture = CreditSoldeForm(request.POST or None)
if facture.is_valid(): if facture.is_valid():
facture_instance = facture.save(commit=False) facture_instance = facture.save(commit=False)
@ -292,7 +325,10 @@ def credit_solde(request, user, userid):
number=1 number=1
) )
new_vente.save() new_vente.save()
messages.success(request, "Solde modifié") messages.success(
request,
_("Banlance successfully updated.")
)
return redirect(reverse('cotisations:index')) return redirect(reverse('cotisations:index'))
return form({'factureform': facture, 'action_name' : 'Créditer'}, 'cotisations/facture.html', request) return form({'factureform': facture, 'action_name' : 'Créditer'}, 'cotisations/facture.html', request)
@ -307,10 +343,14 @@ def add_article(request):
aux articles en vente. La désignation, le prix... sont aux articles en vente. La désignation, le prix... sont
copiés à la création de la facture. Un changement de prix n'a copiés à la création de la facture. Un changement de prix n'a
PAS de conséquence sur les ventes déjà faites""" PAS de conséquence sur les ventes déjà faites"""
# TODO : translate docstring to English
article = ArticleForm(request.POST or None) article = ArticleForm(request.POST or None)
if article.is_valid(): if article.is_valid():
article.save() article.save()
messages.success(request, "L'article a été ajouté") messages.success(
request,
_("The article has been successfully created.")
)
return redirect(reverse('cotisations:index-article')) return redirect(reverse('cotisations:index-article'))
return form({'factureform': article, 'action_name' : 'Ajouter'}, 'cotisations/facture.html', request) return form({'factureform': article, 'action_name' : 'Ajouter'}, 'cotisations/facture.html', request)
@ -320,11 +360,15 @@ def add_article(request):
def edit_article(request, article_instance, articleid): def edit_article(request, article_instance, articleid):
"""Edition d'un article (designation, prix, etc) """Edition d'un article (designation, prix, etc)
Réservé au trésorier""" Réservé au trésorier"""
# TODO : translate dosctring to English
article = ArticleForm(request.POST or None, instance=article_instance) article = ArticleForm(request.POST or None, instance=article_instance)
if article.is_valid(): if article.is_valid():
if article.changed_data: if article.changed_data:
article.save() article.save()
messages.success(request, "Type d'article modifié") messages.success(
request,
_("The article has been successfully edited.")
)
return redirect(reverse('cotisations:index-article')) return redirect(reverse('cotisations:index-article'))
return form({'factureform': article, 'action_name' : 'Editer'}, 'cotisations/facture.html', request) return form({'factureform': article, 'action_name' : 'Editer'}, 'cotisations/facture.html', request)
@ -333,45 +377,62 @@ def edit_article(request, article_instance, articleid):
@can_delete_set(Article) @can_delete_set(Article)
def del_article(request, instances): def del_article(request, instances):
"""Suppression d'un article en vente""" """Suppression d'un article en vente"""
# TODO : translate docstring to English
article = DelArticleForm(request.POST or None, instances=instances) article = DelArticleForm(request.POST or None, instances=instances)
if article.is_valid(): if article.is_valid():
article_del = article.cleaned_data['articles'] article_del = article.cleaned_data['articles']
article_del.delete() article_del.delete()
messages.success(request, "Le/les articles ont été supprimé") messages.success(
request,
_("The article(s) have been successfully deleted.")
)
return redirect(reverse('cotisations:index-article')) return redirect(reverse('cotisations:index-article'))
return form({'factureform': article, 'action_name' : 'Supprimer'}, 'cotisations/facture.html', request) return form({'factureform': article, 'action_name' : 'Supprimer'}, 'cotisations/facture.html', request)
# TODO : change paiement to payment
@login_required @login_required
@can_create(Paiement) @can_create(Paiement)
def add_paiement(request): def add_paiement(request):
"""Ajoute un moyen de paiement. Relié aux factures """Ajoute un moyen de paiement. Relié aux factures
via foreign key""" via foreign key"""
# TODO : translate docstring to English
# TODO : change paiement to Payment
paiement = PaiementForm(request.POST or None) paiement = PaiementForm(request.POST or None)
if paiement.is_valid(): if paiement.is_valid():
paiement.save() paiement.save()
messages.success(request, "Le moyen de paiement a été ajouté") messages.success(
request,
_("The payment method has been successfully created.")
)
return redirect(reverse('cotisations:index-paiement')) return redirect(reverse('cotisations:index-paiement'))
return form({'factureform': paiement, 'action_name' : 'Ajouter'}, 'cotisations/facture.html', request) return form({'factureform': paiement, 'action_name' : 'Ajouter'}, 'cotisations/facture.html', request)
# TODO : chnage paiement to Payment
@login_required @login_required
@can_edit(Paiement) @can_edit(Paiement)
def edit_paiement(request, paiement_instance, paiementid): def edit_paiement(request, paiement_instance, paiementid):
"""Edition d'un moyen de paiement""" """Edition d'un moyen de paiement"""
# TODO : translate docstring to English
paiement = PaiementForm(request.POST or None, instance=paiement_instance) paiement = PaiementForm(request.POST or None, instance=paiement_instance)
if paiement.is_valid(): if paiement.is_valid():
if paiement.changed_data: if paiement.changed_data:
paiement.save() paiement.save()
messages.success(request, "Type de paiement modifié") messages.success(
request,
_("The payement method has been successfully edited.")
)
return redirect(reverse('cotisations:index-paiement')) return redirect(reverse('cotisations:index-paiement'))
return form({'factureform': paiement, 'action_name' : 'Editer'}, 'cotisations/facture.html', request) return form({'factureform': paiement, 'action_name' : 'Editer'}, 'cotisations/facture.html', request)
# TODO : change paiement to payment
@login_required @login_required
@can_delete_set(Paiement) @can_delete_set(Paiement)
def del_paiement(request, instances): def del_paiement(request, instances):
"""Suppression d'un moyen de paiement""" """Suppression d'un moyen de paiement"""
# TODO : translate docstring to English
paiement = DelPaiementForm(request.POST or None, instances=instances) paiement = DelPaiementForm(request.POST or None, instances=instances)
if paiement.is_valid(): if paiement.is_valid():
paiement_dels = paiement.cleaned_data['paiements'] paiement_dels = paiement.cleaned_data['paiements']
@ -380,67 +441,97 @@ def del_paiement(request, instances):
paiement_del.delete() paiement_del.delete()
messages.success( messages.success(
request, request,
"Le moyen de paiement a été supprimé" _("The payment method %(method_name)s has been \
successfully deleted") % {
method_name: paiement_del
}
) )
except ProtectedError: except ProtectedError:
messages.error( messages.error(
request, request,
"Le moyen de paiement %s est affecté à au moins une\ _("The payment method %(method_name) can't be deleted \
facture, vous ne pouvez pas le supprimer" % paiement_del because there are invoices using it.") % {
method_name: paiement_del
}
) )
return redirect(reverse('cotisations:index-paiement')) return redirect(reverse('cotisations:index-paiement'))
return form({'factureform': paiement, 'action_name' : 'Supprimer'}, 'cotisations/facture.html', request) return form({'factureform': paiement, 'action_name' : 'Supprimer'}, 'cotisations/facture.html', request)
# TODO : change banque to bank
@login_required @login_required
@can_create(Banque) @can_create(Banque)
def add_banque(request): def add_banque(request):
"""Ajoute une banque à la liste des banques""" """Ajoute une banque à la liste des banques"""
# TODO : tranlate docstring to English
banque = BanqueForm(request.POST or None) banque = BanqueForm(request.POST or None)
if banque.is_valid(): if banque.is_valid():
banque.save() banque.save()
messages.success(request, "La banque a été ajoutée") messages.success(
request,
_("The bank has been successfully created.")
)
return redirect(reverse('cotisations:index-banque')) return redirect(reverse('cotisations:index-banque'))
return form({'factureform': banque, 'action_name' : 'Ajouter'}, 'cotisations/facture.html', request) return form({'factureform': banque, 'action_name' : 'Ajouter'}, 'cotisations/facture.html', request)
# TODO : change banque to bank
@login_required @login_required
@can_edit(Banque) @can_edit(Banque)
def edit_banque(request, banque_instance, banqueid): def edit_banque(request, banque_instance, banqueid):
"""Edite le nom d'une banque""" """Edite le nom d'une banque"""
# TODO : translate docstring to English
banque = BanqueForm(request.POST or None, instance=banque_instance) banque = BanqueForm(request.POST or None, instance=banque_instance)
if banque.is_valid(): if banque.is_valid():
if banque.changed_data: if banque.changed_data:
banque.save() banque.save()
messages.success(request, "Banque modifiée") messages.success(
request,
_("The bank has been successfully edited")
)
return redirect(reverse('cotisations:index-banque')) return redirect(reverse('cotisations:index-banque'))
return form({'factureform': banque, 'action_name' : 'Editer'}, 'cotisations/facture.html', request) return form({'factureform': banque, 'action_name' : 'Editer'}, 'cotisations/facture.html', request)
# TODO : chnage banque to bank
@login_required @login_required
@can_delete_set(Banque) @can_delete_set(Banque)
def del_banque(request, instances): def del_banque(request, instances):
"""Supprime une banque""" """Supprime une banque"""
# TODO : translate docstring to English
banque = DelBanqueForm(request.POST or None, instances=instances) banque = DelBanqueForm(request.POST or None, instances=instances)
if banque.is_valid(): if banque.is_valid():
banque_dels = banque.cleaned_data['banques'] banque_dels = banque.cleaned_data['banques']
for banque_del in banque_dels: for banque_del in banque_dels:
try: try:
banque_del.delete() banque_del.delete()
messages.success(request, "La banque a été supprimée") messages.success(
request,
_("The bank %(bank_name)s has been successfully \
deleted.") % {
bank_name: banque_del
}
)
except ProtectedError: except ProtectedError:
messages.error(request, "La banque %s est affectée à au moins\ messages.error(
une facture, vous ne pouvez pas la supprimer" % banque_del) request,
_("The bank %(bank_name)s can't be deleted \
because there are invoices using it.") % {
bank_name: banque_del
}
)
return redirect(reverse('cotisations:index-banque')) return redirect(reverse('cotisations:index-banque'))
return form({'factureform': banque, 'action_name' : 'Supprimer'}, 'cotisations/facture.html', request) return form({'factureform': banque, 'action_name' : 'Supprimer'}, 'cotisations/facture.html', request)
# TODO : change facture to invoice
@login_required @login_required
@can_view_all(Facture) @can_view_all(Facture)
@can_change(Facture, 'control') @can_change(Facture, 'control')
def control(request): def control(request):
"""Pour le trésorier, vue pour controler en masse les """Pour le trésorier, vue pour controler en masse les
factures.Case à cocher, pratique""" factures.Case à cocher, pratique"""
# TODO : translate docstring to English
pagination_number = GeneralOption.get_cached_value('pagination_number') pagination_number = GeneralOption.get_cached_value('pagination_number')
facture_list = Facture.objects.select_related('user').select_related('paiement') facture_list = Facture.objects.select_related('user').select_related('paiement')
facture_list = SortTable.sort( facture_list = SortTable.sort(
@ -470,26 +561,31 @@ def control(request):
@can_view_all(Article) @can_view_all(Article)
def index_article(request): def index_article(request):
"""Affiche l'ensemble des articles en vente""" """Affiche l'ensemble des articles en vente"""
# TODO : translate docstrign to English
article_list = Article.objects.order_by('name') article_list = Article.objects.order_by('name')
return render(request, 'cotisations/index_article.html', { return render(request, 'cotisations/index_article.html', {
'article_list': article_list 'article_list': article_list
}) })
# TODO : change paiement to payment
@login_required @login_required
@can_view_all(Paiement) @can_view_all(Paiement)
def index_paiement(request): def index_paiement(request):
"""Affiche l'ensemble des moyens de paiement en vente""" """Affiche l'ensemble des moyens de paiement en vente"""
# TODO : translate docstring to English
paiement_list = Paiement.objects.order_by('moyen') paiement_list = Paiement.objects.order_by('moyen')
return render(request, 'cotisations/index_paiement.html', { return render(request, 'cotisations/index_paiement.html', {
'paiement_list': paiement_list 'paiement_list': paiement_list
}) })
# TODO : change banque to bank
@login_required @login_required
@can_view_all(Banque) @can_view_all(Banque)
def index_banque(request): def index_banque(request):
"""Affiche l'ensemble des banques""" """Affiche l'ensemble des banques"""
# TODO : translate docstring to English
banque_list = Banque.objects.order_by('name') banque_list = Banque.objects.order_by('name')
return render(request, 'cotisations/index_banque.html', { return render(request, 'cotisations/index_banque.html', {
'banque_list': banque_list 'banque_list': banque_list
@ -500,6 +596,7 @@ def index_banque(request):
@can_view_all(Facture) @can_view_all(Facture)
def index(request): def index(request):
"""Affiche l'ensemble des factures, pour les cableurs et +""" """Affiche l'ensemble des factures, pour les cableurs et +"""
# TODO : translate docstring to English
pagination_number = GeneralOption.get_cached_value('pagination_number') pagination_number = GeneralOption.get_cached_value('pagination_number')
facture_list = Facture.objects.select_related('user')\ facture_list = Facture.objects.select_related('user')\
.select_related('paiement').prefetch_related('vente_set') .select_related('paiement').prefetch_related('vente_set')
@ -515,6 +612,7 @@ def index(request):
}) })
# TODO : change facture to invoice
@login_required @login_required
def new_facture_solde(request, userid): def new_facture_solde(request, userid):
"""Creation d'une facture pour un user. Renvoie la liste des articles """Creation d'une facture pour un user. Renvoie la liste des articles
@ -524,10 +622,12 @@ def new_facture_solde(request, userid):
enfin sauve la facture parente. enfin sauve la facture parente.
TODO : simplifier cette fonction, déplacer l'intelligence coté models TODO : simplifier cette fonction, déplacer l'intelligence coté models
Facture et Vente.""" Facture et Vente."""
# TODO : translate docstring to English
user = request.user user = request.user
facture = Facture(user=user) facture = Facture(user=user)
paiement, _created = Paiement.objects.get_or_create(moyen='Solde') paiement, _created = Paiement.objects.get_or_create(moyen='Solde')
facture.paiement = paiement facture.paiement = paiement
# TODO : translate comments to English
# Le template a besoin de connaitre les articles pour le js # Le template a besoin de connaitre les articles pour le js
article_list = Article.objects.filter( article_list = Article.objects.filter(
Q(type_user='All') | Q(type_user=request.user.class_name) Q(type_user='All') | Q(type_user=request.user.class_name)
@ -551,8 +651,10 @@ def new_facture_solde(request, userid):
prix_total += art_item.cleaned_data['article']\ prix_total += art_item.cleaned_data['article']\
.prix*art_item.cleaned_data['quantity'] .prix*art_item.cleaned_data['quantity']
if float(user.solde) - float(prix_total) < solde_negatif: if float(user.solde) - float(prix_total) < solde_negatif:
messages.error(request, "Le solde est insuffisant pour\ messages.error(
effectuer l'opération") request,
_("The balance is too low for this operation.")
)
return redirect(reverse( return redirect(reverse(
'users:profil', 'users:profil',
kwargs={'userid': userid} kwargs={'userid': userid}
@ -575,20 +677,24 @@ def new_facture_solde(request, userid):
for art_item in articles if art_item.cleaned_data): for art_item in articles if art_item.cleaned_data):
messages.success( messages.success(
request, request,
"La cotisation a été prolongée\ _("The balance of %(member_name)s has been successfully \
pour l'adhérent %s jusqu'au %s" % ( extended to %(end_date)s") % {
user.pseudo, user.end_adhesion() member_name: user.pseudo,
) end_date: user.end_adhesion()
}
) )
else: else:
messages.success(request, "La facture a été crée") messages.success(
request,
_("The invoice has been successuflly created.")
)
return redirect(reverse( return redirect(reverse(
'users:profil', 'users:profil',
kwargs={'userid': userid} kwargs={'userid': userid}
)) ))
messages.error( messages.error(
request, request,
u"Il faut au moins un article valide pour créer une facture" _("You need to choose at least one article.")
) )
return redirect(reverse( return redirect(reverse(
'users:profil', 'users:profil',
@ -601,12 +707,13 @@ def new_facture_solde(request, userid):
}, 'cotisations/new_facture_solde.html', request) }, 'cotisations/new_facture_solde.html', request)
# TODO : change recharge to reload
@login_required @login_required
def recharge(request): def recharge(request):
if AssoOption.get_cached_value('payment') == 'NONE': if AssoOption.get_cached_value('payment') == 'NONE':
messages.error( messages.error(
request, request,
"Le paiement en ligne est désactivé." _("Online payment is disabled.")
) )
return redirect(reverse( return redirect(reverse(
'users:profil', 'users:profil',