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

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 €.") % {
......
This diff is collapsed.
......@@ -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,
name='ipn'
),
),
url(r'^$', views.index, name='index'),
]
......@@ -77,7 +77,6 @@ from . import payment as online_payment
from .tex import render_invoice
@login_required
@can_create(Facture)
@can_edit(User)
......@@ -102,9 +101,13 @@ def new_facture(request, user, userid):
# Building the invocie form and the article formset
invoice_form = NewFactureForm(request.POST or None, instance=invoice)
if request.user.is_class_club:
article_formset = formset_factory(SelectClubArticleForm)(request.POST or None)
article_formset = formset_factory(SelectClubArticleForm)(
request.POST or None
)
else:
article_formset = formset_factory(SelectUserArticleForm)(request.POST or None)
article_formset = formset_factory(SelectUserArticleForm)(
request.POST or None
)
if invoice_form.is_valid() and article_formset.is_valid():
new_invoice_instance = invoice_form.save(commit=False)
......@@ -118,15 +121,18 @@ def new_facture(request, user, userid):
# the authorized minimum (negative_balance)
if user_balance:
# TODO : change Paiement to Payment
if new_invoice_instance.paiement == Paiement.objects.get_or_create(
moyen='solde'
)[0]:
if new_invoice_instance.paiement == (
Paiement.objects.get_or_create(moyen='solde')[0]
):
total_price = 0
for art_item in articles:
if art_item.cleaned_data:
total_price += art_item.cleaned_data['article']\
.prix*art_item.cleaned_data['quantity']
if float(user.solde) - float(total_price) < negative_balance:
total_price += (
art_item.cleaned_data['article'].prix *
art_item.cleaned_data['quantity']
)
if (float(user.solde) - float(total_price)
< negative_balance):
messages.error(
request,
_("Your balance is too low for this operation.")
......@@ -194,7 +200,7 @@ def new_facture(request, user, userid):
@can_change(Facture, 'pdf')
def new_facture_pdf(request):
"""
View used to generate a custom PDF invoice. It's mainly used to
View used to generate a custom PDF invoice. It's mainly used to
get invoices that are not taken into account, for the administrative
point of view.
"""
......@@ -205,9 +211,13 @@ def new_facture_pdf(request):
# Building the invocie form and the article formset
invoice_form = NewFactureFormPdf(request.POST or None)
if request.user.is_class_club:
articles_formset = formset_factory(SelectClubArticleForm)(request.POST or None)
articles_formset = formset_factory(SelectClubArticleForm)(
request.POST or None
)
else:
articles_formset = formset_factory(SelectUserArticleForm)(request.POST or None)
articles_formset = formset_factory(SelectUserArticleForm)(
request.POST or None
)
if invoice_form.is_valid() and articles_formset.is_valid():
# Get the article list and build an list out of it
# contiaining (article_name, article_price, quantity, total_price)
......@@ -303,7 +313,11 @@ def edit_facture(request, facture, factureid):
can be set as desired. This is also the view used to invalidate
an invoice.
"""
invoice_form = EditFactureForm(request.POST or None, instance=facture, user=request.user)
invoice_form = EditFactureForm(
request.POST or None,
instance=facture,
user=request.user
)
purchases_objects = Vente.objects.filter(facture=facture)
purchase_form_set = modelformset_factory(
Vente,
......@@ -311,7 +325,10 @@ def edit_facture(request, facture, factureid):
extra=0,
max_num=len(purchases_objects)
)
purchase_form = purchase_form_set(request.POST or None, queryset=purchases_objects)
purchase_form = purchase_form_set(
request.POST or None,
queryset=purchases_objects
)
if invoice_form.is_valid() and purchase_form.is_valid():
if invoice_form.changed_data:
invoice_form.save()
......@@ -385,7 +402,7 @@ def credit_solde(request, user, userid):
def add_article(request):
"""
View used to add an article.
.. note:: If a purchase has already been sold, the price are calculated
once and for all. That means even if the price of an article is edited
later, it won't change the invoice. That is really important to keep
......@@ -613,7 +630,8 @@ def control(request):
View used to control the invoices all at once.
"""
pagination_number = GeneralOption.get_cached_value('pagination_number')
invoice_list = Facture.objects.select_related('user').select_related('paiement')
invoice_list = (Facture.objects.select_related('user').
select_related('paiement'))
invoice_list = SortTable.sort(
invoice_list,
request.GET.get('col'),
......@@ -725,9 +743,13 @@ def new_facture_solde(request, userid):
Q(type_user='All') | Q(type_user=request.user.class_name)
)
if request.user.is_class_club:
article_formset = formset_factory(SelectClubArticleForm)(request.POST or None)
article_formset = formset_factory(SelectClubArticleForm)(
request.POST or None
)
else:
article_formset = formset_factory(SelectUserArticleForm)(request.POST or None)
article_formset = formset_factory(SelectUserArticleForm)(
request.POST or None
)
if article_formset.is_valid():
articles = article_formset
......@@ -826,7 +848,9 @@ def recharge(request):
refill_form = RechargeForm(request.POST or None, user=request.user)
if refill_form.is_valid():
invoice = Facture(user=request.user)
payment, _created = Paiement.objects.get_or_create(moyen='Rechargement en ligne')
payment, _created = Paiement.objects.get_or_create(
moyen='Rechargement en ligne'
)
invoice.paiement = payment
invoice.valid = False
invoice.save()
......@@ -837,7 +861,9 @@ def recharge(request):
number=1
)
purchase.save()
content = online_payment.PAYMENT_SYSTEM[AssoOption.get_cached_value('payment')](invoice, request)
content = online_payment.PAYMENT_SYSTEM[
AssoOption.get_cached_value('payment')
](invoice, request)
return render(request, 'cotisations/payment.html', content)
return form({
'rechargeform': refill_form
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment