style(piaf): passage sélectif de black ./piaf/ -l 80 -S
Parent
c7b4b210ab
révision
cd565703f1
|
@ -3,8 +3,7 @@ import os
|
|||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE',
|
||||
'piaf.settings.development')
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'piaf.settings.development')
|
||||
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
|
|
|
@ -21,9 +21,14 @@ import inspect
|
|||
|
||||
from piaf.base import checks
|
||||
|
||||
|
||||
class BaseConfig(AppConfig):
|
||||
name = 'piaf.base'
|
||||
verbose_name = "PIAF"
|
||||
|
||||
def ready(self):
|
||||
[register(c, Tags.models) for _,c in checks.__dict__.items() if
|
||||
inspect.isfunction(c) and c.__name__.startswith('check_')]
|
||||
[
|
||||
register(c, Tags.models)
|
||||
for _, c in checks.__dict__.items()
|
||||
if inspect.isfunction(c) and c.__name__.startswith('check_')
|
||||
]
|
||||
|
|
|
@ -19,16 +19,18 @@ from django.core.checks import Warning
|
|||
from piaf.base import resthys
|
||||
|
||||
|
||||
def check_resthys_connection (app_configs, **kwargs):
|
||||
def check_resthys_connection(app_configs, **kwargs):
|
||||
try:
|
||||
r = resthys.get('factures')
|
||||
r.raise_for_status()
|
||||
return []
|
||||
except:
|
||||
return [Warning ("Unable to connect to Resthys.",
|
||||
hint='Verify your settings and the reachability of the server. '
|
||||
'After double checking, report an issue to <tech@cliss21.org>.',
|
||||
obj='piaf.base',
|
||||
id='piaf.W001',
|
||||
)]
|
||||
|
||||
return [
|
||||
Warning(
|
||||
"Unable to connect to Resthys.",
|
||||
hint='Verify your settings and the reachability of the server. '
|
||||
'After double checking, report an issue to <tech@cliss21.org>.',
|
||||
obj='piaf.base',
|
||||
id='piaf.W001',
|
||||
)
|
||||
]
|
||||
|
|
|
@ -24,37 +24,49 @@ from piaf.base import resthys
|
|||
class BootstrapErrorList(ErrorList):
|
||||
def __str__(self):
|
||||
return self.as_p()
|
||||
def as_p(self):
|
||||
if not self: return ''
|
||||
return '<div class="errorlist">{}</div>'.format(''.join(['<div '
|
||||
'role="error" class="alert alert-danger">{}</div>'.format(
|
||||
e) for e in self]))
|
||||
|
||||
class RetrieveInvoiceForm (forms.Form):
|
||||
def as_p(self):
|
||||
if not self:
|
||||
return ''
|
||||
return '<div class="errorlist">{}</div>'.format(
|
||||
''.join(
|
||||
[
|
||||
'<div '
|
||||
'role="error" class="alert alert-danger">{}</div>'.format(e)
|
||||
for e in self
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class RetrieveInvoiceForm(forms.Form):
|
||||
numero = forms.IntegerField(label='Numéro de facture', min_value=0)
|
||||
nom = forms.CharField(label='Destinataire de la facture', max_length=50)
|
||||
|
||||
def __init__ (self, **kwargs):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(error_class=BootstrapErrorList, **kwargs)
|
||||
|
||||
def clean(self):
|
||||
super().clean()
|
||||
try:
|
||||
r = resthys.get('factures', params=self.cleaned_data)
|
||||
f= r.json()
|
||||
f = r.json()
|
||||
if not isinstance(f, list) or len(f) > 1:
|
||||
raise ValueError
|
||||
except:
|
||||
raise forms.ValidationError(
|
||||
'Le système a subit une erreur interne. '
|
||||
'Merci de ressayer ultérieurement.')
|
||||
'Le système a subit une erreur interne. '
|
||||
'Merci de ressayer ultérieurement.'
|
||||
)
|
||||
if f == []:
|
||||
raise forms.ValidationError(
|
||||
'Facture inconnue. Vérifiez que les données sont bien '
|
||||
'remplies, sinon, merci de prendre contact avec '
|
||||
'l\'émetteur de la facture.')
|
||||
'Facture inconnue. Vérifiez que les données sont bien '
|
||||
'remplies, sinon, merci de prendre contact avec '
|
||||
'l\'émetteur de la facture.'
|
||||
)
|
||||
else:
|
||||
self.facture= f[0]
|
||||
self.facture = f[0]
|
||||
|
||||
class EmptyForm (forms.Form):
|
||||
|
||||
class EmptyForm(forms.Form):
|
||||
pass
|
||||
|
|
|
@ -21,22 +21,30 @@ from django.conf import settings
|
|||
|
||||
class TokenAuth(requests.auth.AuthBase):
|
||||
def __init__(self):
|
||||
self.token= settings.RESTHYS_AUTHKEY
|
||||
self.token = settings.RESTHYS_AUTHKEY
|
||||
|
||||
def __call__(self, r):
|
||||
r.headers['Authorization'] = 'Token {}'.format(self.token)
|
||||
return r
|
||||
|
||||
def get (uri, **kwargs):
|
||||
|
||||
def get(uri, **kwargs):
|
||||
r = requests.get(
|
||||
'{}{}'.format(settings.RESTHYS_BASEURL, uri),
|
||||
auth= TokenAuth(), timeout=5, **kwargs)
|
||||
'{}{}'.format(settings.RESTHYS_BASEURL, uri),
|
||||
auth=TokenAuth(),
|
||||
timeout=5,
|
||||
**kwargs
|
||||
)
|
||||
r.raise_for_status()
|
||||
return r
|
||||
|
||||
def put (uri, **kwargs):
|
||||
|
||||
def put(uri, **kwargs):
|
||||
r = requests.put(
|
||||
'{}{}'.format(settings.RESTHYS_BASEURL, uri),
|
||||
auth= TokenAuth(), timeout=5, **kwargs)
|
||||
'{}{}'.format(settings.RESTHYS_BASEURL, uri),
|
||||
auth=TokenAuth(),
|
||||
timeout=5,
|
||||
**kwargs
|
||||
)
|
||||
r.raise_for_status()
|
||||
return r
|
||||
|
|
|
@ -23,6 +23,7 @@ from django.utils.safestring import mark_safe
|
|||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.filter
|
||||
def parsedate(s):
|
||||
try:
|
||||
|
@ -30,15 +31,17 @@ def parsedate(s):
|
|||
except:
|
||||
return ''
|
||||
|
||||
|
||||
@register.filter
|
||||
def money(s):
|
||||
try:
|
||||
return mark_safe(
|
||||
'{:.2f} €'.format(decimal.Decimal(s)).replace('.', ',')
|
||||
)
|
||||
'{:.2f} €'.format(decimal.Decimal(s)).replace('.', ',')
|
||||
)
|
||||
except:
|
||||
return s
|
||||
|
||||
|
||||
@register.filter(name='sum')
|
||||
def mysum(l, key=None):
|
||||
return sum(l) if key == None else sum([p[key] for p in l])
|
||||
|
|
|
@ -20,16 +20,21 @@ from django.urls import reverse
|
|||
from bs4 import BeautifulSoup as bs
|
||||
from django.test.utils import override_settings
|
||||
|
||||
|
||||
class Constance(TestCase):
|
||||
def setUp(self):
|
||||
self.client = Client()
|
||||
|
||||
def test_fetch_home(self):
|
||||
response = self.client.get(reverse('home'))
|
||||
self.assertContains(response, 'payez vos activités périscolaires sur le portail familial')
|
||||
self.assertContains(
|
||||
response,
|
||||
'payez vos activités périscolaires sur le portail familial',
|
||||
)
|
||||
self.assertContains(response, 'Pole Scolarité Jeunesse')
|
||||
self.assertContains(response, 'contact@cliss21.com')
|
||||
|
||||
|
||||
class ForbidPrepareInvoice(TestCase):
|
||||
def setUp(self):
|
||||
self.client = Client()
|
||||
|
@ -40,6 +45,7 @@ class ForbidPrepareInvoice(TestCase):
|
|||
response = self.client.get(reverse('prepare_invoice'), follow=True)
|
||||
self.assertContains(response, 'Une erreur est survenue.')
|
||||
|
||||
|
||||
class PrepareInvoice(TestCase):
|
||||
def setUp(self):
|
||||
self.client = Client()
|
||||
|
@ -47,11 +53,21 @@ class PrepareInvoice(TestCase):
|
|||
def test_fetch_invoice(self):
|
||||
response = self.client.get(reverse('retrieve_invoice'))
|
||||
self.assertContains(response, 'Numéro de facture')
|
||||
response = self.client.post(reverse('retrieve_invoice'), {'numero': '540', 'nom': 'PoluX'})
|
||||
response = self.client.post(
|
||||
reverse('retrieve_invoice'), {'numero': '540', 'nom': 'PoluX'}
|
||||
)
|
||||
self.assertContains(response, 'Facture inconnue.')
|
||||
response = self.client.post(reverse('retrieve_invoice'), {'numero': '54', 'nom': 'PoluX'}, follow=True)
|
||||
response = self.client.post(
|
||||
reverse('retrieve_invoice'),
|
||||
{'numero': '54', 'nom': 'PoluX'},
|
||||
follow=True,
|
||||
)
|
||||
self.assertContains(response, 'Facture inconnue.')
|
||||
response = self.client.post(reverse('retrieve_invoice'), {'numero': '54', 'nom': 'Isabelle Merignac'}, follow=True)
|
||||
response = self.client.post(
|
||||
reverse('retrieve_invoice'),
|
||||
{'numero': '54', 'nom': 'Isabelle Merignac'},
|
||||
follow=True,
|
||||
)
|
||||
self.assertContains(response, 'Facture n° 54.')
|
||||
self.assertContains(response, 'Marc et Isabelle MERIGNAC')
|
||||
self.assertContains(response, 'Payer la facture (33,00')
|
||||
|
@ -60,7 +76,11 @@ class PrepareInvoice(TestCase):
|
|||
def test_fetch_invoice_with_merge_modal(self):
|
||||
response = self.client.get(reverse('retrieve_invoice'))
|
||||
self.assertContains(response, 'Numéro de facture')
|
||||
response = self.client.post(reverse('retrieve_invoice'), {'numero': '34', 'nom': 'Raphael Leroy'}, follow=True)
|
||||
response = self.client.post(
|
||||
reverse('retrieve_invoice'),
|
||||
{'numero': '34', 'nom': 'Raphael Leroy'},
|
||||
follow=True,
|
||||
)
|
||||
self.assertContains(response, 'Facture n° 34.')
|
||||
self.assertContains(response, 'Payer la facture (140,00')
|
||||
self.assertContains(response, 'merge_invoices')
|
||||
|
@ -68,32 +88,46 @@ class PrepareInvoice(TestCase):
|
|||
self.assertContains(response, 'Factures n° 34, 53.')
|
||||
self.assertContains(response, 'Payer les factures (176,00')
|
||||
|
||||
|
||||
class ForbidUnpayInvoice(TestCase):
|
||||
def setUp(self):
|
||||
self.client = Client()
|
||||
|
||||
def test_forbid_unpay_invoice(self):
|
||||
response = self.client.post(reverse('retrieve_invoice'), {'numero': '54', 'nom': 'Isabelle Merignac'}, follow=True)
|
||||
response = self.client.post(
|
||||
reverse('retrieve_invoice'),
|
||||
{'numero': '54', 'nom': 'Isabelle Merignac'},
|
||||
follow=True,
|
||||
)
|
||||
response = self.client.get(reverse('unpay_invoice'))
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
|
||||
@override_settings(DEBUG=True)
|
||||
class PayInvoice(TestCase):
|
||||
def setUp(self):
|
||||
self.client = Client()
|
||||
self.tearDown()
|
||||
|
||||
def clean_timestamp (self, s):
|
||||
s= re.sub(r'objet=[^&]*&', '', s)
|
||||
def clean_timestamp(self, s):
|
||||
s = re.sub(r'objet=[^&]*&', '', s)
|
||||
return s
|
||||
|
||||
def test_pay_unpay_invoice(self):
|
||||
response = self.client.post(reverse('retrieve_invoice'), {'numero': '54', 'nom': 'Isabelle Merignac'}, follow=True)
|
||||
response = self.client.post(
|
||||
reverse('retrieve_invoice'),
|
||||
{'numero': '54', 'nom': 'Isabelle Merignac'},
|
||||
follow=True,
|
||||
)
|
||||
self.assertContains(response, 'Payer la facture')
|
||||
self.before= self.clean_timestamp(response.content.decode())
|
||||
pay_link= bs(response.content, 'html.parser').find("a", id="payment_ok").get('href')
|
||||
self.before = self.clean_timestamp(response.content.decode())
|
||||
pay_link = (
|
||||
bs(response.content, 'html.parser')
|
||||
.find("a", id="payment_ok")
|
||||
.get('href')
|
||||
)
|
||||
|
||||
nopay_link= str.replace(pay_link, 'resultrans=P', 'resultrans=A')
|
||||
nopay_link = str.replace(pay_link, 'resultrans=P', 'resultrans=A')
|
||||
response = self.client.get(nopay_link, follow=False)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
response = self.client.get(reverse('prepare_invoice'))
|
||||
|
@ -109,7 +143,7 @@ class PayInvoice(TestCase):
|
|||
response = self.client.get(reverse('prepare_invoice'))
|
||||
response = self.client.get(reverse('prepare_invoice'))
|
||||
self.assertContains(response, 'Payer la facture')
|
||||
self.after= self.clean_timestamp(response.content.decode())
|
||||
self.after = self.clean_timestamp(response.content.decode())
|
||||
with open('/tmp/before.txt', 'w') as f:
|
||||
f.write(self.before)
|
||||
with open('/tmp/after.txt', 'w') as f:
|
||||
|
@ -117,24 +151,33 @@ class PayInvoice(TestCase):
|
|||
self.assertEqual(self.before, self.after)
|
||||
|
||||
def tearDown(self):
|
||||
response = self.client.post(reverse('retrieve_invoice'), {'numero': '54', 'nom': 'Isabelle Merignac'}, follow=True)
|
||||
response = self.client.post(
|
||||
reverse('retrieve_invoice'),
|
||||
{'numero': '54', 'nom': 'Isabelle Merignac'},
|
||||
follow=True,
|
||||
)
|
||||
self.client.get(reverse('unpay_invoice'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
# flush messages
|
||||
response = self.client.get(reverse('prepare_invoice'))
|
||||
|
||||
|
||||
@override_settings(DEBUG=True)
|
||||
class PayMergedInvoice(TestCase):
|
||||
def setUp(self):
|
||||
self.client = Client()
|
||||
self.tearDown()
|
||||
|
||||
def clean_timestamp (self, s):
|
||||
s= re.sub(r'objet=[^&]*&', '', s)
|
||||
def clean_timestamp(self, s):
|
||||
s = re.sub(r'objet=[^&]*&', '', s)
|
||||
return s
|
||||
|
||||
def test_pay_unpay_merged_invoices(self):
|
||||
response = self.client.post(reverse('retrieve_invoice'), {'numero': '34', 'nom': 'Raphael Leroy'}, follow=True)
|
||||
response = self.client.post(
|
||||
reverse('retrieve_invoice'),
|
||||
{'numero': '34', 'nom': 'Raphael Leroy'},
|
||||
follow=True,
|
||||
)
|
||||
self.assertContains(response, 'Payer la facture')
|
||||
self.assertContains(response, 'Facture n° 34.')
|
||||
self.assertContains(response, 'Payer la facture (140,00')
|
||||
|
@ -142,10 +185,14 @@ class PayMergedInvoice(TestCase):
|
|||
response = self.client.post(reverse('prepare_invoice'), {}, follow=True)
|
||||
self.assertContains(response, 'Factures n° 34, 53.')
|
||||
self.assertContains(response, 'Payer les factures (176,00')
|
||||
self.before= self.clean_timestamp(response.content.decode())
|
||||
self.before = self.clean_timestamp(response.content.decode())
|
||||
|
||||
pay_link= bs(response.content, 'html.parser').find("a", id="payment_ok").get('href')
|
||||
nopay_link= str.replace(pay_link, 'resultrans=P', 'resultrans=A')
|
||||
pay_link = (
|
||||
bs(response.content, 'html.parser')
|
||||
.find("a", id="payment_ok")
|
||||
.get('href')
|
||||
)
|
||||
nopay_link = str.replace(pay_link, 'resultrans=P', 'resultrans=A')
|
||||
response = self.client.get(nopay_link, follow=False)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
response = self.client.get(reverse('prepare_merged_invoices'))
|
||||
|
@ -161,17 +208,29 @@ class PayMergedInvoice(TestCase):
|
|||
response = self.client.get(reverse('prepare_merged_invoices'))
|
||||
response = self.client.get(reverse('prepare_merged_invoices'))
|
||||
self.assertContains(response, 'Payer les factures (176,00')
|
||||
self.after= self.clean_timestamp(response.content.decode())
|
||||
self.after = self.clean_timestamp(response.content.decode())
|
||||
self.assertMultiLineEqual(self.before, self.after)
|
||||
|
||||
def tearDown(self):
|
||||
response = self.client.post(reverse('retrieve_invoice'), {'numero': '54', 'nom': 'Isabelle Merignac'}, follow=True)
|
||||
response = self.client.post(
|
||||
reverse('retrieve_invoice'),
|
||||
{'numero': '54', 'nom': 'Isabelle Merignac'},
|
||||
follow=True,
|
||||
)
|
||||
self.client.get(reverse('unpay_invoice'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
response = self.client.post(reverse('retrieve_invoice'), {'numero': '34', 'nom': 'Raphael Leroy'}, follow=True)
|
||||
response = self.client.post(
|
||||
reverse('retrieve_invoice'),
|
||||
{'numero': '34', 'nom': 'Raphael Leroy'},
|
||||
follow=True,
|
||||
)
|
||||
self.client.get(reverse('unpay_invoice'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
response = self.client.post(reverse('retrieve_invoice'), {'numero': '53', 'nom': 'Raphael Leroy'}, follow=True)
|
||||
response = self.client.post(
|
||||
reverse('retrieve_invoice'),
|
||||
{'numero': '53', 'nom': 'Raphael Leroy'},
|
||||
follow=True,
|
||||
)
|
||||
self.client.get(reverse('unpay_invoice'))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
# flush messages
|
||||
|
|
|
@ -3,16 +3,24 @@ from django.views.generic import TemplateView
|
|||
from piaf.base import views
|
||||
|
||||
urlpatterns = [
|
||||
path('', TemplateView.as_view(template_name='pages/home.html'),
|
||||
name='home'),
|
||||
path('retrieve_invoice', views.RetrieveInvoice.as_view(),
|
||||
name='retrieve_invoice'),
|
||||
path('prepare_invoice', views.PrepareInvoice.as_view(),
|
||||
name='prepare_invoice'),
|
||||
path('prepare_merged_invoices', views.PrepareMergedInvoices.as_view(),
|
||||
name='prepare_merged_invoices'),
|
||||
path('paid_invoice', views.PaidInvoice.as_view(),
|
||||
name='paid_invoice'),
|
||||
path('unpay_invoice', views.UnpayInvoice.as_view(),
|
||||
name='unpay_invoice'),
|
||||
]
|
||||
path(
|
||||
'', TemplateView.as_view(template_name='pages/home.html'), name='home'
|
||||
),
|
||||
path(
|
||||
'retrieve_invoice',
|
||||
views.RetrieveInvoice.as_view(),
|
||||
name='retrieve_invoice',
|
||||
),
|
||||
path(
|
||||
'prepare_invoice',
|
||||
views.PrepareInvoice.as_view(),
|
||||
name='prepare_invoice',
|
||||
),
|
||||
path(
|
||||
'prepare_merged_invoices',
|
||||
views.PrepareMergedInvoices.as_view(),
|
||||
name='prepare_merged_invoices',
|
||||
),
|
||||
path('paid_invoice', views.PaidInvoice.as_view(), name='paid_invoice'),
|
||||
path('unpay_invoice', views.UnpayInvoice.as_view(), name='unpay_invoice'),
|
||||
]
|
||||
|
|
|
@ -21,44 +21,51 @@ from functools import reduce
|
|||
Regroup prestation set by indivudal and by activity.
|
||||
Compute the sum by individual.
|
||||
"""
|
||||
def regroup_prestations (prestation_set):
|
||||
r= {}
|
||||
|
||||
def sort_regroup (l, k):
|
||||
def lazy_id (x):
|
||||
|
||||
def regroup_prestations(prestation_set):
|
||||
r = {}
|
||||
|
||||
def sort_regroup(l, k):
|
||||
def lazy_id(x):
|
||||
return x[k]['id'] if x[k] != None and 'id' in x[k] else 0
|
||||
def lazy_object (id, l):
|
||||
|
||||
def lazy_object(id, l):
|
||||
return l[0][k] if l else None
|
||||
grouped= groupby(sorted(l, key=lazy_id), key=lazy_id)
|
||||
listed= [(id, list(l)) for id, l in grouped]
|
||||
|
||||
grouped = groupby(sorted(l, key=lazy_id), key=lazy_id)
|
||||
listed = [(id, list(l)) for id, l in grouped]
|
||||
return [(lazy_object(id, l), l) for id, l in listed]
|
||||
|
||||
r= []
|
||||
for ind,ps in sort_regroup (prestation_set, 'individu'):
|
||||
ps= sort_regroup (ps, 'activite')
|
||||
total= sum([sum([p['montant'] for p in l]) for _, l in ps])
|
||||
r = []
|
||||
for ind, ps in sort_regroup(prestation_set, 'individu'):
|
||||
ps = sort_regroup(ps, 'activite')
|
||||
total = sum([sum([p['montant'] for p in l]) for _, l in ps])
|
||||
r.append([ind, ps, total])
|
||||
return [p for p in r if p[0] != None] + [p for p in r if p[0] == None]
|
||||
|
||||
|
||||
"""
|
||||
Merge invoices into a single one.
|
||||
"""
|
||||
def merge_invoices (l):
|
||||
r= {}
|
||||
|
||||
|
||||
def merge_invoices(l):
|
||||
r = {}
|
||||
if l:
|
||||
for k,v in l[0].items():
|
||||
for k, v in l[0].items():
|
||||
if k == "autres_factures":
|
||||
continue
|
||||
elif k == "numero":
|
||||
r['numeros']= sorted([f[k] for f in l])
|
||||
elif k == "date_debut" :
|
||||
r[k]= min([f[k] for f in l])
|
||||
elif k == "date_fin" :
|
||||
r[k]= max([f[k] for f in l])
|
||||
elif k in ["montant", "regle", "solde"] :
|
||||
r[k]= sum([f[k] for f in l])
|
||||
r['numeros'] = sorted([f[k] for f in l])
|
||||
elif k == "date_debut":
|
||||
r[k] = min([f[k] for f in l])
|
||||
elif k == "date_fin":
|
||||
r[k] = max([f[k] for f in l])
|
||||
elif k in ["montant", "regle", "solde"]:
|
||||
r[k] = sum([f[k] for f in l])
|
||||
elif k == "prestations_set":
|
||||
r[k]= reduce(lambda x,y:x+y, [f[k] for f in l])
|
||||
r[k] = reduce(lambda x, y: x + y, [f[k] for f in l])
|
||||
else:
|
||||
r[k]= v
|
||||
r[k] = v
|
||||
return r
|
||||
|
|
|
@ -28,63 +28,72 @@ from piaf.base import forms, utils, resthys
|
|||
from eopayment import tipi
|
||||
|
||||
|
||||
class RetrieveInvoice (generic.edit.FormView):
|
||||
class RetrieveInvoice(generic.edit.FormView):
|
||||
template_name = 'pages/retrieve_invoice.html'
|
||||
success_url= reverse_lazy('prepare_invoice')
|
||||
success_url = reverse_lazy('prepare_invoice')
|
||||
form_class = forms.RetrieveInvoiceForm
|
||||
context= {}
|
||||
context = {}
|
||||
|
||||
def form_valid (self, form):
|
||||
def form_valid(self, form):
|
||||
r = resthys.get('factures/{}'.format(form.facture['numero']))
|
||||
|
||||
self.context['invoice']= r.json()
|
||||
self.request.session['invoice']= self.context['invoice']
|
||||
self.context['invoice'] = r.json()
|
||||
self.request.session['invoice'] = self.context['invoice']
|
||||
|
||||
return super().form_valid (form)
|
||||
return super().form_valid(form)
|
||||
|
||||
class PrepareInvoice (generic.edit.FormView):
|
||||
|
||||
class PrepareInvoice(generic.edit.FormView):
|
||||
template_name = 'pages/prepare_invoice.html'
|
||||
success_url= reverse_lazy('prepare_merged_invoices')
|
||||
form_class= forms.EmptyForm
|
||||
success_url = reverse_lazy('prepare_merged_invoices')
|
||||
form_class = forms.EmptyForm
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context= super().get_context_data(**kwargs)
|
||||
f= self.request.session.get('invoice')
|
||||
context = super().get_context_data(**kwargs)
|
||||
f = self.request.session.get('invoice')
|
||||
|
||||
# refresh
|
||||
r = resthys.get('factures/{}'.format(f['numero']))
|
||||
|
||||
context['invoice']= r.json()
|
||||
self.request.session['invoice']= context['invoice']
|
||||
context['invoice'] = r.json()
|
||||
self.request.session['invoice'] = context['invoice']
|
||||
|
||||
# pay link
|
||||
p = tipi.Payment({'numcli': '000001'}) # FIXME: it is the regie number
|
||||
p = tipi.Payment({'numcli': '000001'}) # FIXME: it is the regie number
|
||||
context['tipi'] = p.request(
|
||||
amount=decimal.Decimal('111.11'),
|
||||
exer=9999,
|
||||
refdet=999999990000000000000,
|
||||
objet='Facture no {}'.format(context['invoice']['numero']),
|
||||
email='info@example.com',
|
||||
urlcl=self.request.build_absolute_uri(reverse('paid_invoice')),
|
||||
saisie='T')
|
||||
amount=decimal.Decimal('111.11'),
|
||||
exer=9999,
|
||||
refdet=999999990000000000000,
|
||||
objet='Facture no {}'.format(context['invoice']['numero']),
|
||||
email='info@example.com',
|
||||
urlcl=self.request.build_absolute_uri(reverse('paid_invoice')),
|
||||
saisie='T',
|
||||
)
|
||||
|
||||
# prestations
|
||||
context['prestations']= utils.regroup_prestations (
|
||||
context['invoice']['prestations_set']
|
||||
)
|
||||
context['prestations'] = utils.regroup_prestations(
|
||||
context['invoice']['prestations_set']
|
||||
)
|
||||
|
||||
# FIXME to be removed
|
||||
context['paid_link'] = reverse ('paid_invoice') + '?' + '&'.join(
|
||||
"{}={}".format(k,v) for k,v in {
|
||||
'objet': 'Facture no {}'.format(context['invoice']['numero']),
|
||||
'montant': decimal.Decimal('111.11'),
|
||||
context['paid_link'] = (
|
||||
reverse('paid_invoice')
|
||||
+ '?'
|
||||
+ '&'.join(
|
||||
"{}={}".format(k, v)
|
||||
for k, v in {
|
||||
'objet': 'Facture no {}'.format(
|
||||
context['invoice']['numero']
|
||||
),
|
||||
'montant': decimal.Decimal('111.11'),
|
||||
'mel': 'info@example.com',
|
||||
'numcli': '000001',
|
||||
'exer': '9999',
|
||||
'refdet': '999999990000000000000',
|
||||
'resultrans': 'P',
|
||||
}.items()
|
||||
)
|
||||
}.items()
|
||||
)
|
||||
)
|
||||
return context
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
|
@ -93,22 +102,25 @@ class PrepareInvoice (generic.edit.FormView):
|
|||
except Exception as e:
|
||||
if settings.DEBUG:
|
||||
raise e
|
||||
messages.error(self.request,
|
||||
"Une erreur est survenue. Merci de ressayer.")
|
||||
messages.error(
|
||||
self.request, "Une erreur est survenue. Merci de ressayer."
|
||||
)
|
||||
return HttpResponseRedirect(reverse('retrieve_invoice'))
|
||||
|
||||
class PrepareMergedInvoices (PrepareInvoice):
|
||||
http_method_names= ['get']
|
||||
|
||||
class PrepareMergedInvoices(PrepareInvoice):
|
||||
http_method_names = ['get']
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context= super().get_context_data(**kwargs)
|
||||
context = super().get_context_data(**kwargs)
|
||||
if 'merged_invoices' in self.request.session:
|
||||
f= self.request.session['merged_invoices']
|
||||
numeros= f['numeros']
|
||||
invoices=[]
|
||||
f = self.request.session['merged_invoices']
|
||||
numeros = f['numeros']
|
||||
invoices = []
|
||||
else:
|
||||
f= self.request.session.get('invoice')
|
||||
numeros= [dic['numero'] for dic in f['autres_factures']]
|
||||
invoices=[f]
|
||||
f = self.request.session.get('invoice')
|
||||
numeros = [dic['numero'] for dic in f['autres_factures']]
|
||||
invoices = [f]
|
||||
|
||||
# refresh
|
||||
for n in numeros:
|
||||
|
@ -116,97 +128,116 @@ class PrepareMergedInvoices (PrepareInvoice):
|
|||
invoices.append(r.json())
|
||||
|
||||
# merging
|
||||
context['invoice']= utils.merge_invoices(invoices)
|
||||
self.request.session['merged_invoices']= context['invoice']
|
||||
context['invoice'] = utils.merge_invoices(invoices)
|
||||
self.request.session['merged_invoices'] = context['invoice']
|
||||
|
||||
context['prestations']= utils.regroup_prestations (
|
||||
context['invoice']['prestations_set']
|
||||
)
|
||||
context['prestations'] = utils.regroup_prestations(
|
||||
context['invoice']['prestations_set']
|
||||
)
|
||||
|
||||
# pay link
|
||||
p = tipi.Payment({'numcli': '000001'}) # FIXME: it is the regie number
|
||||
p = tipi.Payment({'numcli': '000001'}) # FIXME: it is the regie number
|
||||
context['tipi'] = p.request(
|
||||
amount=decimal.Decimal('111.11'),
|
||||
exer=9999,
|
||||
refdet=999999990000000000000,
|
||||
objet='Factures no {}'.format(' '.join(
|
||||
[str(n) for n in context['invoice']['numeros']]
|
||||
)),
|
||||
email='info@example.com',
|
||||
urlcl=self.request.build_absolute_uri(reverse('paid_invoice')),
|
||||
saisie='T')
|
||||
amount=decimal.Decimal('111.11'),
|
||||
exer=9999,
|
||||
refdet=999999990000000000000,
|
||||
objet='Factures no {}'.format(
|
||||
' '.join([str(n) for n in context['invoice']['numeros']])
|
||||
),
|
||||
email='info@example.com',
|
||||
urlcl=self.request.build_absolute_uri(reverse('paid_invoice')),
|
||||
saisie='T',
|
||||
)
|
||||
|
||||
# prestations
|
||||
context['prestations']= utils.regroup_prestations (
|
||||
context['invoice']['prestations_set']
|
||||
)
|
||||
context['prestations'] = utils.regroup_prestations(
|
||||
context['invoice']['prestations_set']
|
||||
)
|
||||
|
||||
# FIXME to be removed
|
||||
context['paid_link'] = reverse ('paid_invoice') + '?' + '&'.join(
|
||||
"{}={}".format(k,v) for k,v in {
|
||||
'objet': 'Factures no {}'.format(' '.join(
|
||||
[str(n) for n in context['invoice']['numeros']]
|
||||
)),
|
||||
'montant': decimal.Decimal('111.11'),
|
||||
context['paid_link'] = (
|
||||
reverse('paid_invoice')
|
||||
+ '?'
|
||||
+ '&'.join(
|
||||
"{}={}".format(k, v)
|
||||
for k, v in {
|
||||
'objet': 'Factures no {}'.format(
|
||||
' '.join(
|
||||
[str(n) for n in context['invoice']['numeros']]
|
||||
)
|
||||
),
|
||||
'montant': decimal.Decimal('111.11'),
|
||||
'mel': 'info@example.com',
|
||||
'numcli': '000001',
|
||||
'exer': '9999',
|
||||
'refdet': '999999990000000000000',
|
||||
'resultrans': 'P',
|
||||
}.items()
|
||||
)
|
||||
}.items()
|
||||
)
|
||||
)
|
||||
return context
|
||||
|
||||
class PaidInvoice (generic.RedirectView):
|
||||
url= reverse_lazy('prepare_invoice')
|
||||
http_method_names= ['get']
|
||||
|
||||
def get (self, request, *args, **kwargs):
|
||||
class PaidInvoice(generic.RedirectView):
|
||||
url = reverse_lazy('prepare_invoice')
|
||||
http_method_names = ['get']
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
|
||||
# This view isn't for luser; any error can raise http 500.
|
||||
p = tipi.Payment({'numcli': '000001'}) # FIXME: it is the regie number
|
||||
payment= p.response('&'.join(
|
||||
"{}={}".format(k,v) for k,v in request.GET.items()))
|
||||
p = tipi.Payment({'numcli': '000001'}) # FIXME: it is the regie number
|
||||
payment = p.response(
|
||||
'&'.join("{}={}".format(k, v) for k, v in request.GET.items())
|
||||
)
|
||||
|
||||
#FIXME: this cannot be got from the session!
|
||||
# FIXME: this cannot be got from the session!
|
||||
if 'merged_invoices' in request.session:
|
||||
l= request.session.get('merged_invoices')['numeros']
|
||||
self.url= reverse_lazy('prepare_merged_invoices')
|
||||
l = request.session.get('merged_invoices')['numeros']
|
||||
self.url = reverse_lazy('prepare_merged_invoices')
|
||||
else:
|
||||
l=[request.session.get('invoice')['numero']]
|
||||
l = [request.session.get('invoice')['numero']]
|
||||
|
||||
# FIXME: we have to verify that the refdet is known by us (and deduce numeros !!!)
|
||||
for n in l:
|
||||
if payment.is_paid():
|
||||
r = resthys.put('paiement/{}'.format(n),
|
||||
# FIXME: interface to be redesigned
|
||||
data={'solde':'0.00'})
|
||||
r = resthys.put(
|
||||
'paiement/{}'.format(n),
|
||||
# FIXME: interface to be redesigned
|
||||
data={'solde': '0.00'},
|
||||
)
|
||||
|
||||
messages.success(self.request, "Paiement reçu pour la facture "
|
||||
"n° {}".format(n))
|
||||
messages.success(
|
||||
self.request,
|
||||
"Paiement reçu pour la facture " "n° {}".format(n),
|
||||
)
|
||||
else:
|
||||
messages.warning(self.request, "Paiement annulé pour la facture"
|
||||
" n° {}".format(n))
|
||||
messages.warning(
|
||||
self.request,
|
||||
"Paiement annulé pour la facture" " n° {}".format(n),
|
||||
)
|
||||
|
||||
# FIXME: we dont need redirect here. What we need is to notify
|
||||
# update to the browser when we got tipi feedback
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
class UnpayInvoice (generic.RedirectView):
|
||||
url= reverse_lazy('prepare_invoice')
|
||||
http_method_names= ['get']
|
||||
|
||||
def get (self, request, *args, **kwargs):
|
||||
class UnpayInvoice(generic.RedirectView):
|
||||
url = reverse_lazy('prepare_invoice')
|
||||
http_method_names = ['get']
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if not settings.DEBUG:
|
||||
raise Http404
|
||||
if 'merged_invoices' in request.session:
|
||||
l= request.session.get('merged_invoices')['numeros']
|
||||
self.url= reverse_lazy('prepare_merged_invoices')
|
||||
l = request.session.get('merged_invoices')['numeros']
|
||||
self.url = reverse_lazy('prepare_merged_invoices')
|
||||
else:
|
||||
l=[request.session.get('invoice')['numero']]
|
||||
l = [request.session.get('invoice')['numero']]
|
||||
|
||||
for n in l:
|
||||
r = resthys.put('unpay/{}'.format(n))
|
||||
messages.success(self.request, "Paiement reverté pour la facture "
|
||||
"n° {}".format(n))
|
||||
messages.success(
|
||||
self.request,
|
||||
"Paiement reverté pour la facture " "n° {}".format(n),
|
||||
)
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
|
|
@ -1 +1 @@
|
|||
from .base import * # noqa
|
||||
from .base import * # noqa
|
||||
|
|
|
@ -71,9 +71,10 @@ USE_TZ = True
|
|||
# https://docs.djangoproject.com/en/stable/ref/settings/#databases
|
||||
# https://django-environ.readthedocs.io/en/stable/#supported-types
|
||||
DATABASES = {
|
||||
'default': env.db('DJANGO_DATABASE_URL', default='sqlite:///{}'.format(
|
||||
base_dir('sqlite.db')
|
||||
)),
|
||||
'default': env.db(
|
||||
'DJANGO_DATABASE_URL',
|
||||
default='sqlite:///{}'.format(base_dir('sqlite.db')),
|
||||
)
|
||||
}
|
||||
|
||||
# URLS
|
||||
|
@ -274,7 +275,7 @@ MESSAGE_TAGS = {
|
|||
RESTHYS_BASEURL = 'http://127.0.0.1:8080/'
|
||||
|
||||
# API key for connection to Resthys. To generate one, create an user and call
|
||||
#./manage.py drf_create_token <username>
|
||||
# ./manage.py drf_create_token <username>
|
||||
# on resthys.
|
||||
RESTHYS_AUTHKEY = "10005d7bfbe9d9005b9af07763396d002522422b"
|
||||
|
||||
|
@ -282,22 +283,23 @@ RESTHYS_AUTHKEY = "10005d7bfbe9d9005b9af07763396d002522422b"
|
|||
# ------------------------------------------------------------------------------
|
||||
CONSTANCE_BACKEND = 'constance.backends.database.DatabaseBackend'
|
||||
|
||||
CONSTANCE_CONFIG = OrderedDict([
|
||||
('SITE_OWNER_NAME',
|
||||
( 'Cliss XXI', "Nom de l'exploitant")),
|
||||
('SITE_OWNER_URL',
|
||||
("//cliss21.org", "Lien vers l'exploitant")),
|
||||
('SITE_WELCOME',
|
||||
( 'Bienvenue', "Mot d'accueil")),
|
||||
('SITE_DESCRIPTION',
|
||||
('Inscrivez, réservez, payez vos activités périscolaires sur le '
|
||||
'portail familial de de Cliss 21',
|
||||
"Description du site sur la page d'accueil")),
|
||||
('SITE_CONTACT_ADDRESS',
|
||||
( 'contact@cliss21.com', "Adresse de contact")),
|
||||
('SITE_CONTACT_NAME',
|
||||
( 'le Pole Scolarité Jeunesse', "Nom du contact")),
|
||||
])
|
||||
CONSTANCE_CONFIG = OrderedDict(
|
||||
[
|
||||
('SITE_OWNER_NAME', ('Cliss XXI', "Nom de l'exploitant")),
|
||||
('SITE_OWNER_URL', ("//cliss21.org", "Lien vers l'exploitant")),
|
||||
('SITE_WELCOME', ('Bienvenue', "Mot d'accueil")),
|
||||
(
|
||||
'SITE_DESCRIPTION',
|
||||
(
|
||||
'Inscrivez, réservez, payez vos activités périscolaires sur le '
|
||||
'portail familial de de Cliss 21',
|
||||
"Description du site sur la page d'accueil",
|
||||
),
|
||||
),
|
||||
('SITE_CONTACT_ADDRESS', ('contact@cliss21.com', "Adresse de contact")),
|
||||
('SITE_CONTACT_NAME', ('le Pole Scolarité Jeunesse', "Nom du contact")),
|
||||
]
|
||||
)
|
||||
|
||||
CONSTANCE_CONFIG_FIELDSETS = {
|
||||
'Options générales': (
|
||||
|
@ -307,5 +309,5 @@ CONSTANCE_CONFIG_FIELDSETS = {
|
|||
'SITE_DESCRIPTION',
|
||||
'SITE_CONTACT_ADDRESS',
|
||||
'SITE_CONTACT_NAME',
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
Chargement…
Référencer dans un nouveau ticket