From d9c42e89db11916ce614f769d104131cc2e6f5cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Kervella?= Date: Wed, 11 Apr 2018 17:20:40 +0000 Subject: [PATCH 1/4] Fix 81 and Strip out facture.tex for readability --- cotisations/forms.py | 6 - .../templates/cotisations/factures.tex | 126 ++++++++++-------- cotisations/tex.py | 2 +- cotisations/views.py | 22 +-- 4 files changed, 87 insertions(+), 69 deletions(-) diff --git a/cotisations/forms.py b/cotisations/forms.py index 696f1f5c..554e402e 100644 --- a/cotisations/forms.py +++ b/cotisations/forms.py @@ -158,12 +158,6 @@ class NewFactureFormPdf(Form): 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")) - # TODO : change fid field to invoice_id - fid = forms.CharField( - required=True, - max_length=10, - label=_l("Invoice number") - ) # TODO : change Facture to Invoice class EditFactureForm(FieldPermissionFormMixin, NewFactureForm): diff --git a/cotisations/templates/cotisations/factures.tex b/cotisations/templates/cotisations/factures.tex index 1619ea5e..4751edc1 100644 --- a/cotisations/templates/cotisations/factures.tex +++ b/cotisations/templates/cotisations/factures.tex @@ -32,76 +32,98 @@ \usepackage{graphicx} \usepackage{tabularx} \usepackage{eurosym} +\usepackage{multicol} \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 \setlength{\parindent}{0cm} \begin{document} -%\newcommand{\product}[5][0][0][0][0][0]{ -%\setlength{ptotal}{#3*\real{#4}} -%\addtolength{total}{#3*\real{#4}} + + %---------------------------------------------------------------------------------------- + % HEADING SECTION + %---------------------------------------------------------------------------------------- + \begin{center} + {\Huge\bf {{asso_name|safe}} } % Company providing the invoice + \end{center} -%---------------------------------------------------------------------------------------- -% HEADING SECTION -%---------------------------------------------------------------------------------------- -%\includegraphics[width=3.5cm]{% templatetag openbrace %}{{ tpl_path }}} -\tab \tab \tab \tab \tab {\Huge\bf {{asso_name|safe}} }\hfil % Company providing the invoice -\bigskip\break % Whitespace -\hrule % Horizontal line \\ -\vspace{0.5cm} -{\bf Adresse :} \tab \parbox [t] {0.5\textwidth}{ {{line1|safe}} \\ {{line2|safe}} } \hfill \parbox [t] {0.3\textwidth}{ {\bf Téléphone :} {{phone}} \\ {\bf Mail :} {{email|safe}} } \\ % Your address and contact information -\\ -{\bf Siret :} \tab{{siret}} -\\ \\ \\ -\\ -\parbox [t] {0.5\textwidth}{ {\bf Pour :} {{dest.name|safe}} {{dest.surname|safe}} \\ {\bf Adresse :} \tab {% if dest.room == None %} Aucune adresse renseignée {% else %}{{dest.room}}{% endif %} } \hfill \parbox [t] {0.3\textwidth}{ {\bf Date :} {{DATE}} } -\\ \\ + \bigskip + \hrule + \smallskip -{\bf Facture \no :} \tab {{ fid }} \\\\ -%---------------------------------------------------------------------------------------- -% TABLE OF EXPENSES -%---------------------------------------------------------------------------------------- + \begin{multicols}{2} + \begin{tabular}{@{\extracolsep{\fill}}l r} + {\bf Adresse :} & {{line1|safe}} \\ + & {{line2|safe}} \\ + \end{tabular} + \columnbreak + \\ + {\bf Téléphone :} {{phone}} \\ + {\bf Mail :} {{email|safe}} + \end{multicols} -\begin{tabularx}{\textwidth}{|X|r|r|r|} -\hline - \textbf{Désignation} & \textbf{Prix Unit.} \euro & \textbf{Quantité} & \textbf{Prix total} \euro\\ -\hline + {\bf Siret :} {{siret|safe}} + + \vspace{2cm} + + \begin{tabular*}{\textwidth}{@{\extracolsep{\fill}} l r} + {\bf Pour :} {{recipient_name|safe}} & {\bf Date :} {{DATE}} \\ + {\bf Adresse :} {% if address is None %}Aucune adresse renseignée{% else %}{{address}}{% endif %} & \\ + \end{tabular*} + {% if fid is not None %} + {\bf Facture n\textsuperscript{o} :} {{ fid }} \\ + {% endif %} -{% for a in article %} -\hline - {{a.0.name}} & {{a.0.prix}} \euro & {{a.1}} & {{a.2}} \euro\\ -\hline -{% endfor %} + %---------------------------------------------------------------------------------------- + % TABLE OF EXPENSES + %---------------------------------------------------------------------------------------- + + \begin{tabularx}{\textwidth}{|X|r|r|r|} - \hline -\end{tabularx} + \hline + \textbf{Désignation} & \textbf{Prix Unit.} \euro & \textbf{Quantité} & \textbf{Prix total} \euro\\ + \hline + \hline + + {% for a in article %} + {{a.0.name}} & {{a.0.prix}} \euro & {{a.1}} & {{a.2}} \euro\\ + \hline + {% endfor %} + + \hline + \end{tabularx} + + \vspace{1cm} -\vspace{1cm} -\hfill -\begin{tabular}{|l|r|} -\hline -\textbf{Total} & {{total|floatformat:2}} \euro \\ -\textbf{Votre règlement} & {% if paid %}{{total|floatformat:2}}{% else %} 00,00 {% endif %} \euro \\ -\hline -\textbf{À PAYER} & {% if not paid %}{{total|floatformat:2}}{% else %} 00,00 {% endif %} \euro\\ -\hline -\hline + \hfill + \begin{tabular}{|l|r|} + \hline + \textbf{Total} & {{total|floatformat:2}} \euro \\ + \textbf{Votre règlement} & {% if paid %}{{total|floatformat:2}}{% else %} 00,00 {% endif %} \euro \\ + \hline + \textbf{À PAYER} & {% if not paid %}{{total|floatformat:2}}{% else %} 00,00 {% endif %} \euro\\ + \hline + \hline + \end{tabular} + + \vfill -\end{tabular} -\vspace{1.5cm} % Whitespace -\hrule % Horizontal line -\vspace{0.25cm} -\footnotesize{TVA non applicable, art. 293 B du CGI} - -{% endlanguage %} -%---------------------------------------------------------------------------------------- + %---------------------------------------------------------------------------------------- + % FOOTNOTE + %---------------------------------------------------------------------------------------- + + \hrule + \smallskip + \footnotesize{TVA non applicable, art. 293 B du CGI} + + %---------------------------------------------------------------------------------------- \end{document} + +{% endlanguage %} diff --git a/cotisations/tex.py b/cotisations/tex.py index e3bf62f5..fb50d05b 100644 --- a/cotisations/tex.py +++ b/cotisations/tex.py @@ -48,7 +48,7 @@ def render_invoice(request, ctx={}): filename = '_'.join([ 'invoice', slugify(ctx['asso_name']), - slugify(ctx['dest'].pseudo), + slugify(ctx['recipient_name']), str(ctx['DATE'].year), str(ctx['DATE'].month), str(ctx['DATE'].day), diff --git a/cotisations/views.py b/cotisations/views.py index f99ff93e..517644b0 100644 --- a/cotisations/views.py +++ b/cotisations/views.py @@ -201,20 +201,18 @@ def new_facture_pdf(request): invoice_form = NewFactureFormPdf(request.POST or None) if invoice_form.is_valid(): tbl = [] - article = facture_form.cleaned_data['article'] - quantity = facture_form.cleaned_data['number'] - paid = facture_form.cleaned_data['paid'] - recipient = facture_form.cleaned_data['dest'] - room = facture_form.cleaned_data['chambre'] - invoice_id = facture_form.cleaned_data['fid'] + article = invoice_form.cleaned_data['article'] + quantity = invoice_form.cleaned_data['number'] + paid = invoice_form.cleaned_data['paid'] + recipient = invoice_form.cleaned_data['dest'] + address = invoice_form.cleaned_data['chambre'] for art in article: tbl.append([art, quantity, art.prix * quantity]) total_price = sum(a[2] for a in tbl) - user = {'name': recipient, 'room': room} return render_invoice(request, { 'DATE': timezone.now(), - 'dest': user, - 'fid': invoice_id, + 'recipient_name': recipient, + 'address': address, 'article': tbl, 'total': total_price, 'paid': paid, @@ -251,7 +249,11 @@ def facture_pdf(request, facture, factureid): 'paid': True, 'fid': facture.id, 'DATE': facture.date, - 'dest': facture.user, + 'recipient_name': "{} {}".format( + facture.user.name, + facture.user.surname + ), + 'addresse': facture.user.room, 'article': purchases, 'total': facture.prix_total(), 'asso_name': AssoOption.get_cached_value('name'), From 9232282cdf9e8511e5dc6189d8a5b3e8463bcb51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Kervella?= Date: Wed, 11 Apr 2018 18:38:07 +0000 Subject: [PATCH 2/4] Align PDF invoice info and better hline for tables --- .../templates/cotisations/factures.tex | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/cotisations/templates/cotisations/factures.tex b/cotisations/templates/cotisations/factures.tex index 4751edc1..1f1fe0cf 100644 --- a/cotisations/templates/cotisations/factures.tex +++ b/cotisations/templates/cotisations/factures.tex @@ -37,7 +37,7 @@ \pagestyle{empty} % No page numbers \linespread{1.5} % Line spacing -\setlength{\doublerulesep}{\arrayrulewidth} % Double rules look like one thick one +\newcommand{\doublehline}{\noalign{\hrule height 1pt}} \setlength{\parindent}{0cm} @@ -55,28 +55,30 @@ \hrule \smallskip - \begin{multicols}{2} - \begin{tabular}{@{\extracolsep{\fill}}l r} - {\bf Adresse :} & {{line1|safe}} \\ - & {{line2|safe}} \\ + {\setlength{\tabcolsep}{0pt} % Make table columns tighter, usefull for postionning + \begin{tabular}{l l} + {\bf Adresse :}~ & {{line1|safe}} \\ + & {{line2|safe}} \\ \end{tabular} - \columnbreak - \\ - {\bf Téléphone :} {{phone}} \\ - {\bf Mail :} {{email|safe}} - \end{multicols} - + \hfill + \begin{tabular}{r} + {\bf Téléphone :} {{phone}} \\ + {\bf Mail :} {{email|safe}} \\ + \end{tabular} + } + \\ {\bf Siret :} {{siret|safe}} - - \vspace{2cm} + \vspace{2cm} + \begin{tabular*}{\textwidth}{@{\extracolsep{\fill}} l r} {\bf Pour :} {{recipient_name|safe}} & {\bf Date :} {{DATE}} \\ {\bf Adresse :} {% if address is None %}Aucune adresse renseignée{% else %}{{address}}{% endif %} & \\ + {% if fid is not None %} + {\bf Facture n\textsuperscript{o} :} {{ fid }} & \\ + {% endif %} \end{tabular*} - {% if fid is not None %} - {\bf Facture n\textsuperscript{o} :} {{ fid }} \\ - {% endif %} + \\ %---------------------------------------------------------------------------------------- @@ -87,15 +89,13 @@ \hline \textbf{Désignation} & \textbf{Prix Unit.} \euro & \textbf{Quantité} & \textbf{Prix total} \euro\\ - \hline - \hline + \doublehline {% for a in article %} {{a.0.name}} & {{a.0.prix}} \euro & {{a.1}} & {{a.2}} \euro\\ \hline {% endfor %} - \hline \end{tabularx} \vspace{1cm} @@ -105,10 +105,9 @@ \hline \textbf{Total} & {{total|floatformat:2}} \euro \\ \textbf{Votre règlement} & {% if paid %}{{total|floatformat:2}}{% else %} 00,00 {% endif %} \euro \\ - \hline + \doublehline \textbf{À PAYER} & {% if not paid %}{{total|floatformat:2}}{% else %} 00,00 {% endif %} \euro\\ \hline - \hline \end{tabular} \vfill From 11ed8b6afe01015e380f840eb2448a6a336b89c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Kervella?= Date: Wed, 11 Apr 2018 18:40:59 +0000 Subject: [PATCH 3/4] Fix trailing 'e' --- cotisations/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cotisations/views.py b/cotisations/views.py index 517644b0..5ac27fae 100644 --- a/cotisations/views.py +++ b/cotisations/views.py @@ -253,7 +253,7 @@ def facture_pdf(request, facture, factureid): facture.user.name, facture.user.surname ), - 'addresse': facture.user.room, + 'address': facture.user.room, 'article': purchases, 'total': facture.prix_total(), 'asso_name': AssoOption.get_cached_value('name'), From 1447d7b173fa608512b4a843cf378888ec33050b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ma=C3=ABl=20Kervella?= Date: Wed, 11 Apr 2018 19:53:54 +0000 Subject: [PATCH 4/4] Added choice for multiple articles in new PDF invoice --- cotisations/forms.py | 8 -- .../templates/cotisations/control.html | 8 +- .../templates/cotisations/facture.html | 97 +++++++++++++++++++ .../templates/cotisations/factures.tex | 2 +- cotisations/views.py | 51 +++++++--- 5 files changed, 141 insertions(+), 25 deletions(-) diff --git a/cotisations/forms.py b/cotisations/forms.py index 554e402e..524e878f 100644 --- a/cotisations/forms.py +++ b/cotisations/forms.py @@ -145,14 +145,6 @@ class NewFactureFormPdf(Form): """ Form used to create a custom PDF invoice. """ - article = forms.ModelMultipleChoiceField( - queryset=Article.objects.all(), - label=_l("Article") - ) - number = forms.IntegerField( - label=_l("Quantity"), - validators=[MinValueValidator(1)] - ) 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")) diff --git a/cotisations/templates/cotisations/control.html b/cotisations/templates/cotisations/control.html index cdd212e3..bb3a06b6 100644 --- a/cotisations/templates/cotisations/control.html +++ b/cotisations/templates/cotisations/control.html @@ -65,12 +65,12 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "Date" as tr_date %} - {% include 'buttons/sort.html' with prefix='control' col='date' text=tr_date %}< - /th> + {% include 'buttons/sort.html' with prefix='control' col='date' text=tr_date %}i + {% trans "Validated" as tr_validated %} - {% include 'buttons/sort.html' with prefix='control' col='valid' text=tr_validated %}< - /th> + {% include 'buttons/sort.html' with prefix='control' col='valid' text=tr_validated %} + {% trans "Controlled" as tr_controlled %} {% include 'buttons/sort.html' with prefix='control' col='control' text=tr_controlled %} diff --git a/cotisations/templates/cotisations/facture.html b/cotisations/templates/cotisations/facture.html index 2b0cd456..d708b407 100644 --- a/cotisations/templates/cotisations/facture.html +++ b/cotisations/templates/cotisations/facture.html @@ -34,8 +34,105 @@ with this program; if not, write to the Free Software Foundation, Inc.,
{% csrf_token %} +

{% trans "Invoice's articles" %}

+
+ {{ articlesformset.management_form }} + {% for articlesform in articlesformset.forms %} +
+ {% trans "Article" %} :   + {% bootstrap_form articlesform label_class='sr-only' %} +   + +
+ {% endfor %} +
+ +

+ {% blocktrans %} + Total price : 0,00 € + {% endblocktrans %} +

{% bootstrap_form factureform %} {% bootstrap_button action_name button_type='submit' icon='star' %}
+ + + + {% endblock %} diff --git a/cotisations/templates/cotisations/factures.tex b/cotisations/templates/cotisations/factures.tex index 1f1fe0cf..3f2ebedc 100644 --- a/cotisations/templates/cotisations/factures.tex +++ b/cotisations/templates/cotisations/factures.tex @@ -92,7 +92,7 @@ \doublehline {% for a in article %} - {{a.0.name}} & {{a.0.prix}} \euro & {{a.1}} & {{a.2}} \euro\\ + {{a.name}} & {{a.price}} \euro & {{a.quantity}} & {{a.total_price}} \euro\\ \hline {% endfor %} diff --git a/cotisations/views.py b/cotisations/views.py index 5ac27fae..b946c3d6 100644 --- a/cotisations/views.py +++ b/cotisations/views.py @@ -198,22 +198,40 @@ def new_facture_pdf(request): get invoices that are not taken into account, for the administrative point of view. """ + # The template needs the list of articles (for the JS part) + articles = Article.objects.filter( + Q(type_user='All') | Q(type_user=request.user.class_name) + ) + # Building the invocie form and the article formset invoice_form = NewFactureFormPdf(request.POST or None) - if invoice_form.is_valid(): - tbl = [] - article = invoice_form.cleaned_data['article'] - quantity = invoice_form.cleaned_data['number'] + if request.user.is_class_club: + articles_formset = formset_factory(SelectClubArticleForm)(request.POST or None) + else: + 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) + articles_info = [] + for articles_form in articles_formset: + if articles_form.cleaned_data: + article = articles_form.cleaned_data['article'] + quantity = articles_form.cleaned_data['quantity'] + articles_info.append({ + 'name': article.name, + 'price': article.prix, + 'quantity': quantity, + 'total_price': article.prix * quantity + }) paid = invoice_form.cleaned_data['paid'] recipient = invoice_form.cleaned_data['dest'] address = invoice_form.cleaned_data['chambre'] - for art in article: - tbl.append([art, quantity, art.prix * quantity]) - total_price = sum(a[2] for a in tbl) + total_price = sum(a['total_price'] for a in articles_info) + return render_invoice(request, { 'DATE': timezone.now(), 'recipient_name': recipient, 'address': address, - 'article': tbl, + 'article': articles_info, 'total': total_price, 'paid': paid, 'asso_name': AssoOption.get_cached_value('name'), @@ -226,7 +244,9 @@ def new_facture_pdf(request): }) return form({ 'factureform': invoice_form, - 'action_name': _("Edit") + 'action_name': _("Create"), + 'articlesformset': articles_formset, + 'articles': articles }, 'cotisations/facture.html', request) @@ -242,9 +262,16 @@ def facture_pdf(request, facture, factureid): """ # TODO : change vente to purchase purchases_objects = Vente.objects.all().filter(facture=facture) - purchases = [] + # Get the article list and build an list out of it + # contiaining (article_name, article_price, quantity, total_price) + purchases_info = [] for purchase in purchases_objects: - purchases.append([purchase, purchase.number, purchase.prix_total]) + purchases_info.append({ + 'name': purchase.name, + 'price': purchase.prix, + 'quantity': purchase.number, + 'total_price': purchase.prix_total + }) return render_invoice(request, { 'paid': True, 'fid': facture.id, @@ -254,7 +281,7 @@ def facture_pdf(request, facture, factureid): facture.user.surname ), 'address': facture.user.room, - 'article': purchases, + 'article': purchases_info, 'total': facture.prix_total(), 'asso_name': AssoOption.get_cached_value('name'), 'line1': AssoOption.get_cached_value('adresse1'),