Commit f024a7d6 authored by Antoine Bernard's avatar Antoine Bernard

Merge branch 'readhesion_online'

parents 0f1bcefc 5bbe1c19
......@@ -11,7 +11,7 @@
{% if cablage %}
<h2>{% trans "Prolonger la connexion d'un adhérent, effectue la réadhésion si nécessaire" %}</h2>
{% else %}
<h2>{% trans "Prolonger la connexion" %}</h2>
<h2>{% trans "Prolonger votre connexion, en réadhérent si nécéssaire" %}</h2>
{% endif %}
<div class="row">
<div class="six columns{% if form.nbrmois.errors %} error{% endif %}">
......@@ -28,7 +28,26 @@
{% if confirm %}
<h2>{% trans "Récapitulatif" %}</h2>
<div>{% blocktrans %} Une prolongation de la connexion de {{ nbrmois }} mois va être effectuée. {% endblocktrans %} </div>
<div>{% blocktrans %} Une facture de {{ prix }} € va être créée, elle comprend la connexion {% endblocktrans %} {% if readhesion %} {% blocktrans %} et la réadhésion. (10 € pour les personnes, gratuit pour les clubs){% endblocktrans %}{% endif %}</div>
<div>{% blocktrans %} Une facture de {{ prix }} € va être créée, elle comprend la connexion {% endblocktrans %} {% if readhesion %} {% blocktrans %} et la réadhésion. {% endblocktrans %}{% endif %}</div>
{% if not cablage and readhesion %}
<h2>{% trans "Engagement" %}</h2>
<div> L’adhésion au Cr@ns nécessite ton acceptation d’un certain nombre de documents :
<ul>
<li> <a href="http://www.crans.org/CransAdministratif/StatutsDuCrans"> Les statuts de l’association </a>
<li> <a href="http://www.crans.org/CransAdministratif/CharteDuCrans"> La charte </a>
<li> <a href="http://www.crans.org/CransAdministratif/ReglementInterieur"> Le règlement intérieur </a>
<li> <a href="http://www.renater.fr/chartes"> La charte Renater </a>
</ul>
Le non respect de ces documents peut entraîner ta déconnexion temporaire ou définitive du réseau.</br>
</div>
<label> J’ai bien pris connaissance des documents cités et approuve leur contenu. Je m’engage de plus à aller les
consulter en cas de changements. <input type="checkbox" required> </label>
{% endif %}
{% endif %}
<footer>
<a href="{% if ptype == "club" %} {% url 'compte:afficher_club' ide %} {% else %} {% url 'compte:afficher' ide %} {% endif %}" class="button-cancel">{% trans "Retour à mon compte" %}</a>
......
......@@ -455,7 +455,9 @@ class AdhesionView(CableurOrSelfMixin, RedirectHomeMixin, View):
)
def post(self, request, uid, ptype, cablage, next='/compte/', *args, **kwargs):
"""
Si on est dans une requête POST
"""
def connexion_possible(nbrmois, luser):
# Determine le nombre de mois possible avant la readhesion
try:
......@@ -478,16 +480,15 @@ class AdhesionView(CableurOrSelfMixin, RedirectHomeMixin, View):
readhesion = False
now = lc_ldap.crans_utils.localized_datetime()
prix = min(nbrmois * cotisation.contribution, cotisation.plafond_contribution)
if cablage:
try:
delta = luser.fin_adhesion().value - now
delta = delta.days
# Si il n'y a pas de fin adh, on renvoie 0
except AttributeError:
delta = 0
if delta < cotisation.delai_readh_jour:
prix += cotisation.cotisation
readhesion = True
try:
delta = luser.fin_adhesion().value - now
delta = delta.days
# Si il n'y a pas de fin adh, on renvoie 0
except AttributeError:
delta = 0
if delta < cotisation.delai_readh_jour:
prix += cotisation.cotisation
readhesion = True
# Pour les clubs, c'est gratuit
if ptype == 'club':
prix = 0
......@@ -502,11 +503,6 @@ class AdhesionView(CableurOrSelfMixin, RedirectHomeMixin, View):
if 'confirm' in request.POST.keys():
######## Facturation de la connexion ########
mois = form.cleaned_data['nbrmois']
if not cablage:
mois = connexion_possible(mois, luser)
if mois == 0:
messages.error(request, u"Impossible de prolonger la connexion, merci de passer en permanence pour prolonger l'adhesion")
return redirect(next)
mois, prix, readhesion = prix(mois, luser, ptype, cablage)
fact_cotis = cotisation.dico_cotis(mois)
# On evite de créer des factures de 0 mois de connexions, pour les clubs, on ne fait pas de connexion
......@@ -560,20 +556,46 @@ class AdhesionView(CableurOrSelfMixin, RedirectHomeMixin, View):
adh['debutAdhesion'].append(debut_adh)
adh.history_gen()
adh.save()
messages.success(request, _(u"""Vente effectuée, fid=%s (à conserver)""") % (fid))
messages.success(
request,
_(u"""Vente effectuée, fid=%s (à conserver)""") % (fid)
)
return redirect(next)
else:
mois = form.cleaned_data['nbrmois']
if not cablage:
mois = connexion_possible(mois, luser)
if mois == 0:
messages.error(request, u"Impossible de prolonger la connexion au delà de la fin d'adhésion, merci de passer en permanence pour prolonger l'adhesion")
return redirect(next)
mois, prix, readhesion = prix(mois, luser, ptype, cablage)
if not readhesion:
messages.error(request, _(u"Attention, la réadhésion ne sera pas effectuée, merci de repasser un mois avant la fin d'adhésion pour réadhérer. Si la connexion se termine après la fin d'adhésion, il faudra réadhérer"))
return render(request, self.template_name, {'form': form, 'ptype': ptype, 'ide': uid, 'confirm': True, 'prix': prix, 'readhesion': readhesion, 'nbrmois': mois, 'cablage': cablage})
return render(request, self.template_name, {'form': form, 'ptype': ptype, 'ide': uid, 'cablage': cablage})
if not readhesion and mois == 0:
messages.error(
request,
_(u"La réadhésion est impossible plus d'un mois avant la fin de l'adhésion. Vous pouvez soit prolonger votre connexion jusqu'à la fin de votre adhésion, soit revenir un mois avant la fin votre adhésion.")
)
return render(
request,
self.template_name,
{'form': form,
'ptype': ptype,
'ide': uid},
)
return render(
request,
self.template_name,
{'form': form,
'ptype': ptype,
'ide': uid,
'confirm': True,
'prix': prix,
'readhesion': readhesion,
'nbrmois': mois,
'cablage': cablage},
)
return render(
request,
self.template_name,
{'form': form,
'ptype': ptype,
'ide': uid,
'cablage': cablage},
)
@method_decorator(login_required)
......
% Quelle annee ?
\newcounter{annee}
\setcounter{annee}{2014}
\newcounter{nannee}
\setcounter{nannee}{\value{annee}+1}
% Exemplaire cableur ou non ?
\newboolean{cableur}
\setboolean{cableur}{false}
% Une réadhésion ?
\newboolean{re}
\setboolean{re}{false}
% Une adhésion ?
\newboolean{adh}
\setboolean{adh}{true}
% Pour un club ?
\newboolean{club}
\setboolean{club}{false}
% Pour une connexion non étudiante (personnels ens)
\newboolean{persoens}
\setboolean{persoens}{false}
% Pour avoir juste le formulaire de câblage
\newboolean{cablageOnly}
\setboolean{cablageOnly}{false}
% Nombres de machines autorisées
\newcounter{nbMacFixes}
\setcounter{nbMacFixes}{1}
\newcounter{nbMacWifi}
\setcounter{nbMacWifi}{2} % en théorie \infty
This diff is collapsed.
......@@ -8,6 +8,32 @@
{% block title %} {% trans "Mes factures" %} {% endblock %}
{% block h1 %}{% trans "Mes factures" %} {% endblock %}
{% block content %}
<h2>{% trans "Certificats d'adhésion" %}</h2>
<table class="mobile-friendly">
<thead>
<tr>
{% blocktrans %}
<th>Reçue le</th>
<th>Type d'achat</th>
<th>Télécharger le pdf</th>
{% endblocktrans %}
</tr>
</thead>
<tbody>
{% for f in luser.factures %}
{% for art in f.article %}
{% if 'ADH' == art.code %}
<tr>
<td mobile-header="{% trans "Paiement reçu le" %}">{{ f.recuPaiement.0.value|date:"DATETIME_FORMAT" }}</td>
<td mobile-header="{% trans "Type d'achat" %}">{% for art in f.article %}{{ art.designation }}{% if not forloop.last %}, {%endif %}{% endfor %}</td>
<td mobile-header="{% trans "Télécharger" %}"><a href="formulaire_{{ f.fid.0 }}.pdf"><img src="{% static 'img/download_white.svg' %}" class="icone_tab" alt="{% trans "Télécharger" %}" /></a>
</tr>
{% endif %}
{% endfor %}
{% endfor %}
</tbody>
</table>
<h2>{% trans "Factures" %}</h2>
<table class="mobile-friendly">
<thead>
<tr>
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
# -*- coding: utf-8 -*
from django.template.loader import get_template
from django.template import TemplateDoesNotExist, Context
from django.http import HttpResponse, Http404, HttpResponseNotModified
......@@ -20,7 +22,10 @@ def render_tex(request, template, ctx={}):
doc = template.rsplit('/', 1)[-1].rsplit('.', 1)[0]
# Utile ? Parfois il faut le chemin absolu pour retrouver les images
ctx.setdefault('tpl_path', os.path.join(settings.BASE_DIR, 'factures/templates/factures'))
ctx.setdefault(
'tpl_path',
os.path.join(settings.BASE_DIR, 'factures/templates/factures')
)
try:
body = get_template(template).render(Context(ctx)).encode("utf-8")
......@@ -33,6 +38,7 @@ def render_tex(request, template, ctx={}):
cache_key = "%s:%s:%s" % (CACHE_PREFIX, template, etag)
pdf = cache.get(cache_key)
# Si le pdf N'est PAS déjà présent sur le serveur.
if pdf is None:
if '\\nonstopmode' not in body:
raise ValueError("\\nonstopmode not present in document, cowardly refusing to process.")
......@@ -52,14 +58,14 @@ def render_tex(request, template, ctx={}):
).wait()
if error:
if request.user.is_superuser:
if request.user.is_superuser: # Si l'utilisateur est nounou
log = open("%s/%s.log" % (tmp, doc)).read()
return HttpResponse(log, content_type="text/plain")
else:
else: # Sinon, on renvoie une page d'erreur
raise RuntimeError("pdflatex error (code %s) in %s/%s" % (error, tmp, doc))
pdf = open("%s/%s.pdf" % (tmp, doc)).read()
finally:
finally: # Quoi qu'il arrive, on supprime le dossier temporaire
shutil.rmtree(tmp)
pass
......
......@@ -6,7 +6,25 @@ urlpatterns = [
url('^$', views.index, name='index'),
url('^liste/(?P<ptype>club)/(?P<cid>[0-9]+)/$', views.index, name='liste'),
url('^liste/(?P<ptype>adh)/(?P<aid>[0-9]+)/$', views.index, name='liste'),
url('(?P<fid>[0-9]+).pdf', views.facture, name='facture'),
url('^liste/(?P<ptype>adh)/(?P<aid>[0-9]+)/(?P<fid>[0-9]+).pdf/$', views.facture, name='facture'),
url('^liste/(?P<ptype>club)/(?P<cid>[0-9]+)/(?P<fid>[0-9]+).pdf/$', views.facture, name='facture')
url('^(?P<fid>[0-9]+).pdf', views.facture, name='facture'),
url('^liste/(?P<ptype>adh)/(?P<aid>[0-9]+)/(?P<fid>[0-9]+).pdf/$',
views.facture,
name='facture'
),
url('^liste/(?P<ptype>club)/(?P<cid>[0-9]+)/(?P<fid>[0-9]+).pdf/$',
views.facture,
name='facture'
),
url('formulaire_(?P<fid>[0-9]+).pdf',
views.formulaire,
name='formulaire'
),
url('^liste/(?P<ptype>adh)/(?P<aid>[0-9]+)/formulaire_(?P<fid>[0-9]+).pdf/$',
views.formulaire,
name='formulaire'
),
url('^liste/(?P<ptype>club)/(?P<cid>[0-9]+)/formulaire_(?P<fid>[0-9]+).pdf/$',
views.formulaire,
name='formulaire',
),
]
# -*- coding: utf-8 -*
import os
from subprocess import call
from tempfile import mkdtemp, mkstemp
......@@ -33,7 +34,11 @@ class IndexView(CableurOrSelfMixin, View):
luser = conn_pool.get_conn(request.user).search(u'aid=%s' % aid)[0]
elif ptype=="club":
luser = conn_pool.get_conn(request.user).search(u'cid=%s' % cid)[0]
return render(request, self.template_name, {'luser': luser})
return render(
request,
self.template_name,
{'luser': luser,},
)
@method_decorator(login_required)
def dispatch(self, request, aid=None, cid=None, ptype=None, *args, **kwargs):
......@@ -49,35 +54,115 @@ class IndexView(CableurOrSelfMixin, View):
index = IndexView.as_view()
class FactureView(View):
class PDFView(View):
"""
Classe de view servant de base à la génération de PDF pour les
adhérents.
"""
tex_template = '404.tex'
context = {}
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(FactureView, self).dispatch(*args, **kwargs)
return super(PDFView, self).dispatch(*args, **kwargs)
def get(self, request):
return render_tex(
request,
self.tex_template,
self.context,
)
class FactureView(PDFView):
"""
View générant le fichier PDF d'une facture.
"""
tex_template = 'factures/facture.tex'
def get(self, request, fid):
luser = conn_pool.get_user(request.user)
f = conn_pool.get_conn(request.user).search(u"fid=%s" % int(fid))
if not f:
if not f: # Si la facture n'existe pas
return redirect('factures:index')
else:
else: # Sinon, le premier élément de f est la facture.
f = f[0]
if not f.dn in [fac.dn for fac in luser.factures()] and not request.user.has_perm('auth.crans_cableur'):
# On vérifie que l'utilisateur demande une facture dont il est le
# propriétaire, ou que l'utilisateur est un câbleur.
if not f.dn in [fac.dn for fac in luser.factures()] \
and not request.user.has_perm('auth.crans_cableur'):
return redirect('factures:index')
# On commence le traitement des données à générer.
total = 0
for i in range(0,len(f['article'])):
f['article'][i].value['ptotal']=int(f['article'][i]['nombre']) * float(f['article'][i]['pu'])
f['article'][i].value['ptotal'] = int(f['article'][i]['nombre']) * float(f['article'][i]['pu'])
total += f['article'][i].value['ptotal']
if f.get('recuPaiement', []):
paid = total
else:
paid = 0
# On récupère la date et l'heure de la facture
(jour, heure) = f['historique'][0].value.split(',')[0].split(" ")
date = u"Le %s à %s" % (jour, heure.replace(":", "h"))
# On récupère le montant restant à payer
topay = total - paid
return render_tex(request, 'factures/facture.tex', {'total':total, 'paid':paid, 'topay':topay, 'DATE':date, 'f':f, 'fid':fid})
self.context = {
'total':total,
'paid':paid,
'topay':topay,
'DATE':date,
'f':f,
'fid':fid,
}
return super(FactureView, self).get(request)
facture = FactureView.as_view()
class FormulaireView(PDFView):
"""
View générant le fichier PDF d'un formulaire d'adhésion ou de
réadhésion.
"""
tex_template = 'factures/formulaire-adhesion.tex' # Dans usr/scripts ?
def get(self, request, fid):
luser = conn_pool.get_user(request.user)
f = conn_pool.get_conn(request.user).search(u"fid=%s" % int(fid))
if not f: # Si la facture n'existe pas
return redirect('factures:index')
else: # Sinon, le premier élément de f est la facture.
f = f[0]
# On vérifie que l'utilisateur demande une facture dont il est le
# propriétaire, ou que l'utilisateur est un câbleur.
if not f.dn in [fac.dn for fac in luser.factures()] \
and not request.user.has_perm('auth.crans_cableur'):
return redirect('factures:index')
total = 0
for i in range(0,len(f['article'])):
f['article'][i].value['ptotal'] = int(f['article'][i]['nombre']) * float(f['article'][i]['pu'])
total += f['article'][i].value['ptotal']
if f.get('recuPaiement', []):
paid = total
else:
paid = 0
# On récupère la date et l'heure de la facture
(jour, heure) = f['historique'][0].value.split(',')[0].split(" ")
date = u"Le %s à %s" % (jour, heure.replace(":", "h"))
self.context = {
'paid': paid,
'DATE': date,
'f': f,
'fid': fid,
}
return super(FormulaireView, self).get(request)
formulaire = FormulaireView.as_view()
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