Commit b25137ac authored by Maël Kervella's avatar Maël Kervella
Browse files

Pep8 compliance on cotisations

parent e56c80b7
......@@ -27,6 +27,7 @@ Here are defined some functions to check acl on the application.
"""
from django.utils.translation import ugettext as _
def can_view(user):
"""Check if an user can view the application.
......@@ -38,4 +39,7 @@ def can_view(user):
viewing is granted and msg is a message (can be None).
"""
can = user.has_module_perms('cotisations')
return can, None if can else _("You don't have the rights to see this application.")
if can:
return can, None
else:
return can, _("You don't have the rights to see this application.")
......@@ -20,7 +20,7 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""
Forms for the 'cotisation' app of re2o. It highly depends on
Forms for the 'cotisation' app of re2o. It highly depends on
:cotisations:models and is mainly used by :cotisations:views.
The following forms are mainly used to create, edit or delete
......@@ -38,7 +38,7 @@ from __future__ import unicode_literals
from django import forms
from django.db.models import Q
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 django.utils.translation import ugettext_lazy as _l
......@@ -47,7 +47,8 @@ from preferences.models import OptionalUser
from users.models import User
from re2o.field_permissions import FieldPermissionFormMixin
from re2o.mixins import FormRevMixin
from re2o.mixins import FormRevMixin
class NewFactureForm(FormRevMixin, ModelForm):
"""
......@@ -109,12 +110,16 @@ class CreditSoldeForm(NewFactureForm):
montant = forms.DecimalField(max_digits=5, decimal_places=2, required=True)
class SelectUserArticleForm(FormRevMixin, Form):
class SelectUserArticleForm(
FormRevMixin, Form):
"""
Form used to select an article during the creation of an invoice for a member.
Form used to select an article during the creation of an invoice for a
member.
"""
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=_l("Article"),
required=True
)
......@@ -127,10 +132,13 @@ class SelectUserArticleForm(FormRevMixin, Form):
class SelectClubArticleForm(Form):
"""
Form used to select an article during the creation of an invoice for a club.
Form used to select an article during the creation of an invoice for a
club.
"""
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=_l("Article"),
required=True
)
......@@ -140,6 +148,7 @@ class SelectClubArticleForm(Form):
required=True
)
# TODO : change Facture to Invoice
class NewFactureFormPdf(Form):
"""
......@@ -147,9 +156,18 @@ class NewFactureFormPdf(Form):
"""
paid = forms.BooleanField(label=_l("Paid"), required=False)
# TODO : change dest field to recipient
dest = forms.CharField(required=True, max_length=255, label=_l("Recipient"))
dest = forms.CharField(
required=True,
max_length=255,
label=_l("Recipient")
)
# TODO : change chambre field to address
chambre = forms.CharField(required=False, max_length=10, label=_l("Address"))
chambre = forms.CharField(
required=False,
max_length=10,
label=_l("Address")
)
# TODO : change Facture to Invoice
class EditFactureForm(FieldPermissionFormMixin, NewFactureForm):
......@@ -313,7 +331,6 @@ class NewFactureSoldeForm(NewFactureForm):
# TODO : change paiement to payment and baque to bank
fields = ['paiement', 'banque']
def clean(self):
cleaned_data = super(NewFactureSoldeForm, self).clean()
# TODO : change paiement to payment
......@@ -342,7 +359,7 @@ class RechargeForm(FormRevMixin, Form):
value = forms.FloatField(
label=_l("Amount"),
min_value=0.01,
validators = []
validators=[]
)
def __init__(self, *args, **kwargs):
......@@ -360,7 +377,8 @@ class RechargeForm(FormRevMixin, Form):
)
}
)
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(
_("Requested amount is too high. Your balance can't exceed \
%(max_online_balance)s €.") % {
......
......@@ -54,7 +54,7 @@ class Facture(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
"""
The model for an invoice. It reprensents the fact that a user paid for
something (it can be multiple article paid at once).
An invoice is linked to :
* one or more purchases (one for each article sold that time)
* a user (the one who bought those articles)
......@@ -105,11 +105,16 @@ class Facture(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
abstract = False
permissions = (
# TODO : change facture to invoice
('change_facture_control', _l("Can change the \"controlled\" state")),
# TODO : seems more likely to be call create_facture_pdf or create_invoice_pdf
('change_facture_pdf', _l("Can create a custom PDF invoice")),
('view_facture', _l("Can see an invoice's details")),
('change_all_facture', _l("Can edit all the previous invoices")),
('change_facture_control',
_l("Can change the \"controlled\" state")),
# TODO : seems more likely to be call create_facture_pdf
# or create_invoice_pdf
('change_facture_pdf',
_l("Can create a custom PDF invoice")),
('view_facture',
_l("Can see an invoice's details")),
('change_all_facture',
_l("Can edit all the previous invoices")),
)
verbose_name = _l("Invoice")
verbose_name_plural = _l("Invoices")
......@@ -159,11 +164,14 @@ class Facture(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
def can_edit(self, user_request, *args, **kwargs):
if not user_request.has_perm('cotisations.change_facture'):
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]:
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\
(self.control or not self.valid):
return False, _("You don't have the right to edit an invoice already controlled or invalidated.")
elif not user_request.has_perm('cotisations.change_all_facture') and \
not self.user.can_edit(user_request, *args, **kwargs)[0]:
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 \
(self.control or not self.valid):
return False, _("You don't have the right to edit an invoice "
"already controlled or invalidated.")
else:
return True, None
......@@ -171,16 +179,19 @@ class Facture(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
if not user_request.has_perm('cotisations.delete_facture'):
return False, _("You don't have the right to delete an invoice.")
if not self.user.can_edit(user_request, *args, **kwargs)[0]:
return False, _("You don't have the right to delete this user's invoices.")
return False, _("You don't have the right to delete this user's "
"invoices.")
if self.control or not self.valid:
return False, _("You don't have the right to delete an invoice already controlled or invalidated.")
return False, _("You don't have the right to delete an invoice "
"already controlled or invalidated.")
else:
return True, None
def can_view(self, user_request, *args, **kwargs):
if not user_request.has_perm('cotisations.view_facture') and\
self.user != user_request:
return False, _("You don't have the right to see someone else's invoices history.")
if not user_request.has_perm('cotisations.view_facture') and \
self.user != user_request:
return False, _("You don't have the right to see someone else's "
"invoices history.")
elif not self.valid:
return False, _("The invoice has been invalidated.")
else:
......@@ -188,16 +199,22 @@ class Facture(RevMixin, AclMixin, FieldPermissionModelMixin, models.Model):
@staticmethod
def can_change_control(user_request, *args, **kwargs):
return user_request.has_perm('cotisations.change_facture_control'), _("You don't have the right to edit the \"controlled\" state.")
return (
user_request.has_perm('cotisations.change_facture_control'),
_("You don't have the right to edit the \"controlled\" state.")
)
@staticmethod
def can_change_pdf(user_request, *args, **kwargs):
return user_request.has_perm('cotisations.change_facture_pdf'), _("You don't have the right to edit an invoice.")
return (
user_request.has_perm('cotisations.change_facture_pdf'),
_("You don't have the right to edit an invoice.")
)
def __init__(self, *args, **kwargs):
super(Facture, self).__init__(*args, **kwargs)
self.field_permissions = {
'control' : self.can_change_control,
'control': self.can_change_control,
}
def __str__(self):
......@@ -228,7 +245,7 @@ class Vente(RevMixin, AclMixin, models.Model):
"""
The model defining a purchase. It consist of one type of article being
sold. In particular there may be multiple purchases in a single invoice.
It's reprensentated by:
* an amount (the number of items sold)
* an invoice (whose the purchase is part of)
......@@ -289,7 +306,6 @@ class Vente(RevMixin, AclMixin, models.Model):
verbose_name = _l("Purchase")
verbose_name_plural = _l("Purchases")
# TODO : change prix_total to total_price
def prix_total(self):
"""
......@@ -323,11 +339,13 @@ class Vente(RevMixin, AclMixin, models.Model):
facture__in=Facture.objects.filter(
user=self.facture.user
).exclude(valid=False))
).filter(Q(type_cotisation='All') | Q(type_cotisation=self.type_cotisation)
).filter(
Q(type_cotisation='All') |
Q(type_cotisation=self.type_cotisation)
).filter(
date_start__lt=date_start
).aggregate(Max('date_end'))['date_end__max']
elif self.type_cotisation=="Adhesion":
elif self.type_cotisation == "Adhesion":
end_cotisation = self.facture.user.end_adhesion()
else:
end_cotisation = self.facture.user.end_connexion()
......@@ -357,11 +375,15 @@ class Vente(RevMixin, AclMixin, models.Model):
def can_edit(self, user_request, *args, **kwargs):
if not user_request.has_perm('cotisations.change_vente'):
return False, _("You don't have the right 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]:
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\
(self.facture.control or not self.facture.valid):
return False, _("You don't have the right to edit a purchase already controlled or invalidated.")
elif not user_request.has_perm('cotisations.change_all_facture') and \
not self.facture.user.can_edit(
user_request, *args, **kwargs)[0]:
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 \
(self.facture.control or not self.facture.valid):
return False, _("You don't have the right to edit a purchase "
"already controlled or invalidated.")
else:
return True, None
......@@ -369,16 +391,19 @@ class Vente(RevMixin, AclMixin, models.Model):
if not user_request.has_perm('cotisations.delete_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]:
return False, _("You don't have the right to delete this user's purchases.")
return False, _("You don't have the right to delete this user's "
"purchases.")
if self.facture.control or not self.facture.valid:
return False, _("You don't have the right to delete a purchase already controlled or invalidated.")
return False, _("You don't have the right to delete a purchase "
"already controlled or invalidated.")
else:
return True, None
def can_view(self, user_request, *args, **kwargs):
if not user_request.has_perm('cotisations.view_vente') and\
self.facture.user != user_request:
return False, _("You don't have the right to see someone else's purchase history.")
if not user_request.has_perm('cotisations.view_vente') and \
self.facture.user != user_request:
return False, _("You don't have the right to see someone "
"else's purchase history.")
else:
return True, None
......@@ -418,12 +443,14 @@ def vente_post_delete(sender, **kwargs):
class Article(RevMixin, AclMixin, models.Model):
"""
The definition of an article model. It represents an type of object that can be sold to the user.
The definition of an article model. It represents a type of object
that can be sold to the user.
It's represented by:
* a name
* a price
* a cotisation type (indicating if this article reprensents a cotisation or not)
* a cotisation type (indicating if this article reprensents a
cotisation or not)
* a duration (if it is a cotisation)
* a type of user (indicating what kind of user can buy this article)
"""
......@@ -513,8 +540,8 @@ class Banque(RevMixin, AclMixin, models.Model):
permissions = (
('view_banque', _l("Can see a bank's details")),
)
verbose_name=_l("Bank")
verbose_name_plural=_l("Banks")
verbose_name = _l("Bank")
verbose_name_plural = _l("Banks")
def __str__(self):
return self.name
......@@ -530,7 +557,7 @@ class Paiement(RevMixin, AclMixin, models.Model):
* a type (used for the type 'cheque' which implies the use of a bank
and an account number in related models)
"""
PAYMENT_TYPES = (
(0, _l("Standard")),
(1, _l("Cheque")),
......@@ -622,24 +649,29 @@ class Cotisation(RevMixin, AclMixin, models.Model):
def can_edit(self, user_request, *args, **kwargs):
if not user_request.has_perm('cotisations.change_cotisation'):
return False, _("You don't have the right to edit a cotisation.")
elif not user_request.has_perm('cotisations.change_all_cotisation') and\
(self.vente.facture.control or not self.vente.facture.valid):
return False, _("You don't have the right to edit a cotisation already controlled or invalidated.")
elif not user_request.has_perm('cotisations.change_all_cotisation') \
and (self.vente.facture.control or
not self.vente.facture.valid):
return False, _("You don't have the right to edit a cotisation "
"already controlled or invalidated.")
else:
return True, None
def can_delete(self, user_request, *args, **kwargs):
if not user_request.has_perm('cotisations.delete_cotisation'):
return False, _("You don't have the right to delete a cotisation.")
return False, _("You don't have the right to delete a "
"cotisation.")
if self.vente.facture.control or not self.vente.facture.valid:
return False, _("You don't have the right to delete a cotisation already controlled or invalidated.")
return False, _("You don't have the right to delete a cotisation "
"already controlled or invalidated.")
else:
return True, None
def can_view(self, user_request, *args, **kwargs):
if not user_request.has_perm('cotisations.view_cotisation') and\
self.vente.facture.user != user_request:
return False, _("You don't have the right to see someone else's cotisation history.")
self.vente.facture.user != user_request:
return False, _("You don't have the right to see someone else's "
"cotisation history.")
else:
return True, None
......
......@@ -17,6 +17,7 @@ from preferences.models import AssoOption
from .models import Facture
from .payment_utils.comnpay import Payment as ComnpayPayment
@csrf_exempt
@login_required
def accept_payment(request, factureid):
......@@ -30,7 +31,10 @@ def accept_payment(request, factureid):
'amount': facture.prix()
}
)
return redirect(reverse('users:profil', kwargs={'userid':request.user.id}))
return redirect(reverse(
'users:profil',
kwargs={'userid': request.user.id}
))
@csrf_exempt
......@@ -43,7 +47,11 @@ def refuse_payment(request):
request,
_("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}
))
@csrf_exempt
def ipn(request):
......@@ -105,7 +113,7 @@ def comnpay(facture, request):
str(AssoOption.get_cached_value('payment_pass')),
'https://' + host + reverse(
'cotisations:accept_payment',
kwargs={'factureid':facture.id}
kwargs={'factureid': facture.id}
),
'https://' + host + reverse('cotisations:refuse_payment'),
'https://' + host + reverse('cotisations:ipn'),
......@@ -113,20 +121,20 @@ def comnpay(facture, request):
"D"
)
r = {
'action' : 'https://secure.homologation.comnpay.com',
'method' : 'POST',
'content' : p.buildSecretHTML(
'action': 'https://secure.homologation.comnpay.com',
'method': 'POST',
'content': p.buildSecretHTML(
"Rechargement du solde",
facture.prix(),
idTransaction=str(facture.id)
),
'amount' : facture.prix,
'amount': facture.prix,
}
return r
# The payment systems supported by re2o
PAYMENT_SYSTEM = {
'COMNPAY' : comnpay,
'NONE' : None
'COMNPAY': comnpay,
'NONE': None
}
......@@ -5,6 +5,7 @@ import hashlib
from collections import OrderedDict
from itertools import chain
class Payment():
vad_number = ""
......@@ -15,7 +16,8 @@ class Payment():
source = ""
typeTr = "D"
def __init__(self, vad_number = "", secret_key = "", urlRetourOK = "", urlRetourNOK = "", urlIPN = "", source="", typeTr="D"):
def __init__(self, vad_number="", secret_key="", urlRetourOK="",
urlRetourNOK="", urlIPN="", source="", typeTr="D"):
self.vad_number = vad_number
self.secret_key = secret_key
self.urlRetourOK = urlRetourOK
......@@ -24,36 +26,45 @@ class Payment():
self.source = source
self.typeTr = typeTr
def buildSecretHTML(self, produit="Produit", montant="0.00", idTransaction=""):
def buildSecretHTML(self, produit="Produit", montant="0.00",
idTransaction=""):
if idTransaction == "":
self.idTransaction = str(time.time())+self.vad_number+str(randrange(999))
self.idTransaction = str(time.time())
self.idTransaction += self.vad_number
self.idTransaction += str(randrange(999))
else:
self.idTransaction = idTransaction
array_tpe = OrderedDict(
montant= str(montant),
idTPE= self.vad_number,
idTransaction= self.idTransaction,
devise= "EUR",
lang= 'fr',
nom_produit= produit,
source= self.source,
urlRetourOK= self.urlRetourOK,
urlRetourNOK= self.urlRetourNOK,
typeTr= str(self.typeTr)
array_tpe = OrderedDict(
montant=str(montant),
idTPE=self.vad_number,
idTransaction=self.idTransaction,
devise="EUR",
lang='fr',
nom_produit=produit,
source=self.source,
urlRetourOK=self.urlRetourOK,
urlRetourNOK=self.urlRetourNOK,
typeTr=str(self.typeTr)
)
if self.urlIPN!="":
if self.urlIPN != "":
array_tpe['urlIPN'] = self.urlIPN
array_tpe['key'] = self.secret_key;
strWithKey = base64.b64encode(bytes('|'.join(array_tpe.values()), 'utf-8'))
array_tpe['key'] = self.secret_key
strWithKey = base64.b64encode(bytes(
'|'.join(array_tpe.values()),
'utf-8'
))
del array_tpe["key"]
array_tpe['sec'] = hashlib.sha512(strWithKey).hexdigest()
ret = ""
for key in array_tpe:
ret += '<input type="hidden" name="'+key+'" value="'+array_tpe[key]+'"/>'
ret += '<input type="hidden" name="{k}" value="{v}"/>'.format(
'k'=key,
'v'=array_type[key]
)
return ret
......@@ -61,8 +72,10 @@ class Payment():
if "sec" in values:
sec = values['sec']
del values["sec"]
strWithKey = hashlib.sha512(base64.b64encode(bytes('|'.join(values.values()) +"|"+secret_key, 'utf-8'))).hexdigest()
strWithKey = hashlib.sha512(base64.b64encode(bytes(
'|'.join(values.values()) + "|" + secret_key,
'utf-8'
))).hexdigest()
return strWithKey.upper() == sec.upper()
else:
return False
......@@ -46,7 +46,7 @@ def render_invoice(request, ctx={}):
date, the user, the articles, the prices, ...
"""
filename = '_'.join([
'invoice',
'invoice',
slugify(ctx['asso_name']),
slugify(ctx['recipient_name']),
str(ctx['DATE'].year),
......@@ -54,9 +54,12 @@ def render_invoice(request, ctx={}):
str(ctx['DATE'].day),
])
r = render_tex(request, 'cotisations/factures.tex', ctx)
r['Content-Disposition'] = ''.join(['attachment; filename="',filename,'.pdf"'])
r['Content-Disposition'] = 'attachment; filename="{name}.pdf"'.format(
name=filename
)
return r
def render_tex(request, template, ctx={}):
"""
Creates a PDF from a LaTex templates using pdflatex.
......@@ -66,13 +69,13 @@ def render_tex(request, template, ctx={}):
context = Context(ctx)
template = get_template(template)
rendered_tpl = template.render(context).encode('utf-8')
with tempfile.TemporaryDirectory() as tempdir:
for i in range(2):
process = Popen(
['pdflatex', '-output-directory', tempdir],
stdin = PIPE,
stdout = PIPE,
stdin=PIPE,
stdout=PIPE,
)
process.communicate(rendered_tpl)
with open(os.path.join(tempdir, 'texput.pdf'), 'rb') as f:
......
......@@ -101,12 +101,11 @@ urlpatterns = [
views.index_paiement,
name='index-paiement'
),
url(
r'history/(?P<object_name>\w+)/(?P<object_id>[0-9]+)$',
url(r'history/(?P<object_name>\w+)/(?P<object_id>[0-9]+)$',
re2o.views.history,
name='history',
kwargs={'application':'cotisations'},
),
kwargs={'application': 'cotisations'},
),
url(r'^control/$',
views.control,
name='control'
......@@ -122,14 +121,14 @@ urlpatterns = [
url(r'^payment/accept/(?P<factureid>[0-9]+)$',
payment.accept_payment,
name='accept_payment'
),
),
url(r'^payment/refuse/$',
payment.refuse_payment,
name='refuse_payment'
),
),
url(r'^payment/ipn/$',
payment.ipn,