mirror of https://gitlab.federez.net/re2o/re2o
12 changed files with 302 additions and 88 deletions
@ -0,0 +1,116 @@ |
|||
{% load i18n %} |
|||
{% language 'fr' %} |
|||
|
|||
\nonstopmode |
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
|||
% Invoice Template |
|||
% LaTeX Template |
|||
% Version 1.0 (3/11/12) |
|||
%% This template has been downloaded from: |
|||
% http://www.LaTeXTemplates.com |
|||
% |
|||
% Original author: |
|||
% Trey Hunner (http://www.treyhunner.com/) |
|||
% |
|||
% License: |
|||
% CC BY-NC-SA 3.0 (http://creativecommons.org/licenses/by-nc-sa/3.0/) |
|||
% |
|||
% Important note: |
|||
% This template requires the invoice.cls file to be in the same directory as |
|||
% the .tex file. The invoice.cls file provides the style used for structuring the |
|||
% document. |
|||
% |
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
|||
|
|||
%---------------------------------------------------------------------------------------- |
|||
% DOCUMENT CONFIGURATION |
|||
%---------------------------------------------------------------------------------------- |
|||
|
|||
\documentclass[12pt]{article} % Use the custom invoice class (invoice.cls) |
|||
\usepackage[utf8]{inputenc} |
|||
\usepackage[frenchb]{babel} |
|||
\usepackage{tabularx} |
|||
\usepackage[letterpaper,hmargin=0.79in,vmargin=0.79in]{geometry} |
|||
\usepackage{calc} % Counters for totaling hours and cost |
|||
\usepackage{longtable} |
|||
\usepackage{graphicx} |
|||
\usepackage{calc} |
|||
|
|||
\pagestyle{empty} % No page numbers |
|||
\linespread{1.5} % Line spacing |
|||
|
|||
\setlength{\doublerulesep}{\arrayrulewidth} % Double rules look like one thick one |
|||
\def \tab {\hspace*{3ex}} % Define \tab to create some horizontal white space |
|||
|
|||
|
|||
|
|||
|
|||
\begin{document} |
|||
%\newcommand{\product}[5][0][0][0][0][0]{ |
|||
%\setlength{ptotal}{#3*\real{#4}} |
|||
%\addtolength{total}{#3*\real{#4}} |
|||
\DeclareDocumentCommand{\product}{ O{0} O{0} O{0} O{0} O{0} }{ |
|||
#1 & #2 & #3 & #4 & #5 \\ |
|||
\hline |
|||
} |
|||
|
|||
%---------------------------------------------------------------------------------------- |
|||
% HEADING SECTION |
|||
%---------------------------------------------------------------------------------------- |
|||
\begin{titlepage} |
|||
\begin{textblock*}{4cm}(20mm,5mm) |
|||
%\includegraphics[scale=0.3]{% templatetag openbrace %}{{tpl_path}}/logo.png} |
|||
\end{textblock*} |
|||
\end{titlepage} |
|||
\hfil{\Huge\bf ReZo Metz}\hfil % Company providing the invoice |
|||
\bigskip\break % Whitespace |
|||
\hrule % Horizontal line |
|||
2 rue Edouard Belin \\ % Your address and contact information |
|||
57070 Metz \hfill augustin.lemesle@supelec.fr \\ |
|||
Siret : |
|||
\\ \\ |
|||
{\bf À :} \tab {{f.user.name}} {{f.user.surname}} \\ % Invoice recipient |
|||
|
|||
{\bf Date:} \tab {{DATE}} \\ % Invoice date |
|||
|
|||
{\bf Facture \no:} \tab {{fid}} \\ % Invoice number |
|||
|
|||
%---------------------------------------------------------------------------------------- |
|||
% TABLE OF EXPENSES |
|||
%---------------------------------------------------------------------------------------- |
|||
|
|||
\begin{tabularx}{\textwidth}{|l|X|r|r|r|} |
|||
\hline |
|||
\textbf{Code} & \textbf{Désignation} & \textbf{Qté.} & \textbf{Prix Unit.} \euro & \textbf{Prix Tot.} \euro\\ |
|||
\hline |
|||
|
|||
{% for a in f.article %} |
|||
\product[{{a.code}}][{{a.designation}}][{{a.nombre}}][{{a.pu|floatformat:2}}][{{a.ptotal|floatformat:2}}] |
|||
{% endfor %} |
|||
|
|||
\hline |
|||
\end{tabularx} |
|||
|
|||
%\setcounter{paid}{0} |
|||
%\setcounter{topay}{\real{\value{total}}-\value{paid}} |
|||
|
|||
\hfill |
|||
\begin{tabular}{|l|r|} |
|||
\hline |
|||
\textbf{Total} & {{total|floatformat:2}}\euro \\ |
|||
\textbf{Votre règlement} & {{paid|floatformat:2}}\euro \\ |
|||
\hline |
|||
\textbf{À PAYER} & {{topay|floatformat:2}}\euro \\ |
|||
\hline |
|||
\hline |
|||
|
|||
\end{tabular} |
|||
|
|||
\vspace{1.5cm} % Whitespace |
|||
\hrule % Horizontal line |
|||
\footnotesize{TVA non applicable, art. 293 B du CGI} |
|||
|
|||
{% endlanguage %} |
|||
%---------------------------------------------------------------------------------------- |
|||
|
|||
\end{document} |
|||
@ -0,0 +1,71 @@ |
|||
from django.template.loader import get_template |
|||
from django.template import TemplateDoesNotExist, Context |
|||
from django.http import HttpResponse, Http404, HttpResponseNotModified |
|||
from django.core.cache import cache |
|||
from django.conf import settings |
|||
from django.shortcuts import redirect |
|||
|
|||
from tempfile import mkdtemp |
|||
import subprocess |
|||
import os |
|||
import shutil |
|||
from hashlib import md5 |
|||
|
|||
|
|||
TEMP_PREFIX = getattr(settings, 'TEX_TEMP_PREFIX', 'render_tex-') |
|||
CACHE_PREFIX = getattr(settings, 'TEX_CACHE_PREFIX', 'render-tex') |
|||
CACHE_TIMEOUT = getattr(settings, 'TEX_CACHE_TIMEOUT', 86400) # 1 day |
|||
|
|||
|
|||
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')) |
|||
|
|||
try: |
|||
body = get_template(template).render(Context(ctx)).encode('utf-8') |
|||
except TemplateDoesNotExist: |
|||
raise Http404() |
|||
|
|||
etag = md5(body).hexdigest() |
|||
if request.META.get('HTTP_IF_NONE_MATCH', '') == etag: |
|||
return HttpResponseNotModified() |
|||
|
|||
cache_key = "%s:%s:%s" % (CACHE_PREFIX, template, etag) |
|||
pdf = cache.get(cache_key) |
|||
if pdf is None: |
|||
if b'\\nonstopmode' not in body: |
|||
raise ValueError("\\nonstopmode not present in document, cowardly refusing to process.") |
|||
|
|||
tmp = mkdtemp(prefix=TEMP_PREFIX) |
|||
try: |
|||
with open("%s/%s.tex" % (tmp, doc), "w") as f: |
|||
f.write(str(body)) |
|||
del body |
|||
|
|||
error = subprocess.Popen( |
|||
["pdflatex", "%s.tex" % doc], |
|||
cwd=tmp, |
|||
stdin=open(os.devnull, "r"), |
|||
stderr=open(os.devnull, "wb"), |
|||
stdout=open(os.devnull, "wb") |
|||
).wait() |
|||
|
|||
if error: |
|||
log = open("%s/%s.log" % (tmp, doc)).read() |
|||
return HttpResponse(log, content_type="text/plain") |
|||
|
|||
pdf = open("%s/%s.pdf" % (tmp, doc)).read() |
|||
finally: |
|||
shutil.rmtree(tmp) |
|||
pass |
|||
|
|||
if pdf: |
|||
cache.set(cache_key, pdf, CACHE_TIMEOUT) |
|||
|
|||
res = HttpResponse(pdf, content_type="application/pdf") |
|||
res['ETag'] = etag |
|||
return res |
|||
|
|||
|
|||
Loading…
Reference in new issue