diff --git a/Dockerfile b/Dockerfile index d42bdd1f..26046a9e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,6 +9,11 @@ RUN apt update && \ apt install -y gettext nginx uwsgi uwsgi-plugin-python3 && \ rm -rf /var/lib/apt/lists/* +# Install LaTeX requirements +RUN apt update && \ + apt install -y texlive-latex-extra textlive-fonts-extra && \ + rm -rf /var/lib/apt/lists/* + COPY . /code/ # Comment what is not needed diff --git a/apps/treasury/views.py b/apps/treasury/views.py index 380b8fd7..1844167b 100644 --- a/apps/treasury/views.py +++ b/apps/treasury/views.py @@ -1,10 +1,18 @@ # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later +import os +import shutil +import subprocess +from tempfile import mkdtemp + from django.contrib.auth.mixins import LoginRequiredMixin +from django.http import HttpResponse +from django.template.loader import render_to_string from django.views.generic import CreateView, UpdateView from django.views.generic.base import View from django_tables2 import SingleTableView +from note_kfet.settings.base import BASE_DIR from .models import Billing from .tables import BillingTable @@ -36,7 +44,48 @@ class BillingUpdateView(LoginRequiredMixin, UpdateView): # form_class = BillingForm -class BillingRenderView(View): +class BillingRenderView(LoginRequiredMixin, View): """ - Render Billing + Render Billing as generated PDF """ + + def get(self, request, **kwargs): + pk = kwargs["pk"] + billing = Billing.objects.get(pk=pk) + + billing.description = billing.description.replace("\n", "\\newline\n") + billing.address = billing.address.replace("\n", "\\newline\n") + tex = render_to_string("treasury/billing_sample.tex", dict(obj=billing)) + try: + os.mkdir(BASE_DIR + "/tmp") + except FileExistsError: + pass + tmp_dir = mkdtemp(prefix=BASE_DIR + "/tmp/") + + with open("{}/billing-{:d}.tex".format(tmp_dir, pk), "wb") as f: + f.write(tex.encode("UTF-8")) + del tex + + error = subprocess.Popen( + ["pdflatex", "billing-{}.tex".format(pk)], + cwd=tmp_dir, + stdin=open(os.devnull, "r"), + stderr=open(os.devnull, "wb"), + stdout=open(os.devnull, "wb") + ).wait() + + error = subprocess.Popen( + ["pdflatex", "billing-{}.tex".format(pk)], + cwd=tmp_dir, + stdin=open(os.devnull, "r"), + stderr=open(os.devnull, "wb"), + stdout=open(os.devnull, "wb") + ).wait() + + pdf = open("{}/billing-{}.pdf".format(tmp_dir, pk), 'rb').read() + shutil.rmtree(tmp_dir) + + response = HttpResponse(pdf, content_type="application/pdf") + response['Content-Disposition'] = "inline;filename=billing-{:d}.pdf".format(pk) + + return response diff --git a/templates/treasury/billing_sample.tex b/templates/treasury/billing_sample.tex new file mode 100644 index 00000000..5f477ed1 --- /dev/null +++ b/templates/treasury/billing_sample.tex @@ -0,0 +1,186 @@ +\nonstopmode +\documentclass[11pt]{article} + +\usepackage[french]{babel} +\usepackage[T1]{fontenc} +\usepackage[utf8]{inputenc} +\usepackage[a4paper]{geometry} +\usepackage{units} +\usepackage{bera} +\usepackage{graphicx} +\usepackage{fancyhdr} +\usepackage{fp} +\usepackage{transparent} +\usepackage{eso-pic} + +\def\TVA{0} % Taux de la TVA + +\def\TotalHT{0} +\def\TotalTVA{0} + +\newcommand{\AjouterProduit}[4]{% Arguments : Désignation, quantité, prix unitaire HT, prix total HT + \FPround{\prix}{#3}{2} + \FPround{\montant}{#4}{2} + \FPadd{\TotalHT}{\TotalHT}{\montant} + + \eaddto\ListeProduits{#1 & \prix & #2 & \montant \cr} +} + +\newcommand{\AfficheResultat}{% + \ListeProduits + + \FPeval{\TotalTVA}{\TotalHT * \TVA / 100} + \FPadd{\TotalTTC}{\TotalHT}{\TotalTVA} + \FPround{\TotalHT}{\TotalHT}{2} + \FPround{\TotalTVA}{\TotalTVA}{2} + \FPround{\TotalTTC}{\TotalTTC}{2} + \global\let\TotalHT\TotalHT + \global\let\TotalTVA\TotalTVA + \global\let\TotalTTC\TotalTTC + + \cr \hline + Total HT & & & \TotalHT \cr + TVA \TVA~\% & & & \TotalTVA \cr + \hline \hline + \textbf{Total TTC} & & & \TotalTTC +} + +\newcommand*\eaddto[2]{% version développée de \addto + \edef\tmp{#2}% + \expandafter\addto + \expandafter#1% + \expandafter{\tmp}% +} + +\newcommand {\ListeProduits}{} + +% Logo du BDE +\AddToShipoutPicture*{ + \put(0,0){ + \parbox[b][\paperheight]{\paperwidth}{% + \vfill + \centering + {\transparent{0.1}\includegraphics[width=\textwidth]{../../static/img/{{ obj.bde }}}}% + \vfill + } + } +} + + +%%%%%%%%%%%%%%%%%%%%% A MODIFIER DANS LA FACTURE %%%%%%%%%%%%%%%%%%%%% +% Infos Association +\def\MonNom{{"{"}}{{ obj.my_name }}} % Nom de l'association +\def\MonAdresseRue{{"{"}}{{ obj.my_address_street }}} % Adresse de l'association +\def\MonAdresseVille{{"{"}}{{ obj.my_city }}} + +% Informations bancaires de l'association +\def\CodeBanque{{"{"}}{{ obj.bank_code|stringformat:".05d" }}} +\def\CodeGuichet{{"{"}}{{ obj.desk_code|stringformat:".05d" }}} +\def\NCompte{{"{"}}{{ obj.account_number|stringformat:".011d" }}} +\def\CleRib{{"{"}}{{ obj.rib_key|stringformat:".02d" }}} +\def\IBAN{FR76\CodeBanque\CodeGuichet\NCompte\CleRib} +\def\CodeBic{{"{"}}{{ obj.bic }}} + +\def\FactureNum {{"{"}}{{obj.id}}} % Numéro de facture +\def\FactureAcquittee {% if obj.acquitted %} {oui} {% else %} {non} {% endif %} % Facture acquittée : oui/non +\def\FactureLieu {{"{"}}{{ obj.place }}} % Lieu de l'édition de la facture +\def\FactureDate {{"{"}}{{ obj.date }}} % Date de l'édition de la facture +\def\FactureObjet {{"{"}}{{ obj.subject|safe }} } % Objet du document +% Description de la facture +\def\FactureDescr {{"{"}}{{ obj.description|safe }}} + +% Infos Client +\def\ClientNom{{"{"}}{{obj.name|safe}}} % Nom du client +\def\ClientAdresse{{"{"}}{{ obj.address|safe }}} % Adresse du client + +% Liste des produits facturés : Désignation, quantité, prix unitaire HT + +{% for product in obj.products %} +\AjouterProduit{ {{product.designation|safe}} } { {{product.quantity|safe}} } { {{product.amount|safe}}} { {{product.total|safe}}} +{% endfor %} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\geometry{verbose,tmargin=4em,bmargin=8em,lmargin=6em,rmargin=6em} +\setlength{\parindent}{1pt} +\setlength{\parskip}{1ex plus 0.5ex minus 0.2ex} + +\thispagestyle{fancy} +\pagestyle{fancy} +\setlength{\parindent}{0pt} + +\renewcommand{\headrulewidth}{0pt} +\cfoot{ + \small{\MonNom ~--~ \MonAdresseRue \MonAdresseVille ~--~ Telephone : +33(0)6 89 88 56 50\newline + Site web : bde.ens-cachan.fr ~--~ E-mail : tresorerie.bde@lists.crans.org \newline Numéro SIRET : 399 485 838 00011 + } +} + +\begin{document} + +% Logo de la société +% \includegraphics{logo.jpg} + +% Nom et adresse de la société +\MonNom \\ +\MonAdresseRue \\ +\MonAdresseVille + +Facture n°\FactureNum + + +{\addtolength{\leftskip}{10.5cm} %in ERT + \ClientNom \\ + \ClientAdresse \\ + +} %in ERT + + +\hspace*{10.5cm} +\FactureLieu, le \FactureDate + +~\\~\\ + +\textbf{Objet : \FactureObjet \\} + +\textnormal{\FactureDescr} + +~\\ + +\begin{center} + \begin{tabular}{lrrr} + \textbf{Désignation ~~~~~~} & \textbf{Prix unitaire} & \textbf{Quantité} & \textbf{Montant (EUR)} \\ + \hline + \AfficheResultat{} + \end{tabular} +\end{center} + +~\\ + +\ifthenelse{\equal{\FactureAcquittee}{oui}}{ + Facture acquittée. +}{ + + À régler par chèque ou par virement bancaire : + + \begin{center} + \begin{tabular}{|c c c c|} + \hline + \textbf{Code banque} & \textbf{Code guichet} & \textbf{N° de Compte} & \textbf{Clé RIB}\\ + \CodeBanque & \CodeGuichet & \NCompte & \CleRib \\ + \hline + \textbf{IBAN N°} & \multicolumn{3}{|l|} \IBAN \\ + \hline + \textbf{Code BIC} & \multicolumn{3}{|l|}\CodeBic \\ + \hline + \end{tabular} + \end{center} + +} + +\begin{center} +TVA non applicable, article 293 B du CGI. +\end{center} + +\end{document}