From 904c7b279baea4bcf418af15c3c14033a7795ed3 Mon Sep 17 00:00:00 2001 From: Delphine SALVY Date: Wed, 18 Jul 2018 02:08:03 +0200 Subject: [PATCH 1/3] POC de l'envoi de facture par mail. --- .../templates/cotisations/email_invoice | 8 ++++ cotisations/tex.py | 17 +++++-- cotisations/views.py | 47 ++++++++++++++++++- 3 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 cotisations/templates/cotisations/email_invoice diff --git a/cotisations/templates/cotisations/email_invoice b/cotisations/templates/cotisations/email_invoice new file mode 100644 index 00000000..71459733 --- /dev/null +++ b/cotisations/templates/cotisations/email_invoice @@ -0,0 +1,8 @@ +Dear {{name}}, + +Thank you for your purchase. Here is your invoice. + +Should you need extra information, you can email us at {{contact_mail}}. + +Best regards, + {{ asso_name }}'s team diff --git a/cotisations/tex.py b/cotisations/tex.py index f456fe8a..4487d5b8 100644 --- a/cotisations/tex.py +++ b/cotisations/tex.py @@ -61,11 +61,9 @@ def render_invoice(_request, ctx={}): return r -def render_tex(_request, template, ctx={}): +def create_pdf(template, ctx={}): """ - Creates a PDF from a LaTex templates using pdflatex. - Writes it in a temporary directory and send back an HTTP response for - accessing this file. + Creates and returns a PDF from a LaTeX template using pdflatex. """ context = Context(ctx) template = get_template(template) @@ -81,6 +79,17 @@ def render_tex(_request, template, ctx={}): process.communicate(rendered_tpl) with open(os.path.join(tempdir, 'texput.pdf'), 'rb') as f: pdf = f.read() + + return pdf + + +def render_tex(_request, template, ctx={}): + """ + Creates a PDF from a LaTex templates using pdflatex. + Writes it in a temporary directory and send back an HTTP response for + accessing this file. + """ + pdf = create_pdf(template, ctx={}) r = HttpResponse(content_type='application/pdf') r.write(pdf) return r diff --git a/cotisations/views.py b/cotisations/views.py index 8b9fe79e..5ac55324 100644 --- a/cotisations/views.py +++ b/cotisations/views.py @@ -40,6 +40,8 @@ from django.db.models import Q from django.forms import modelformset_factory, formset_factory from django.utils import timezone from django.utils.translation import ugettext as _ +from django.core.mail import EmailMessage +from django.template.loader import get_template # Import des models, forms et fonctions re2o from reversion import revisions as reversion @@ -72,7 +74,7 @@ from .forms import ( SelectClubArticleForm, RechargeForm ) -from .tex import render_invoice +from .tex import create_pdf, render_invoice from .payment_methods.forms import payment_method_factory from .utils import find_payment_method @@ -147,6 +149,48 @@ def new_facture(request, user, userid): p.facture = new_invoice_instance p.save() + facture = new_invoice_instance # BErk + purchases_info = [] + for purchase in facture.vente_set.all(): + purchases_info.append({ + 'name': purchase.name, + 'price': purchase.prix, + 'quantity': purchase.number, + 'total_price': purchase.prix_total + }) + ctx = { + 'paid': True, + 'fid': facture.id, + 'DATE': facture.date, + 'recipient_name': "{} {}".format( + facture.user.name, + facture.user.surname + ), + 'address': facture.user.room, + 'article': purchases_info, + 'total': facture.prix_total(), + 'asso_name': AssoOption.get_cached_value('name'), + 'line1': AssoOption.get_cached_value('adresse1'), + 'line2': AssoOption.get_cached_value('adresse2'), + 'siret': AssoOption.get_cached_value('siret'), + 'email': AssoOption.get_cached_value('contact'), + 'phone': AssoOption.get_cached_value('telephone'), + 'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH) + } + + pdf = create_pdf('cotisations/factures.tex', ctx) + + template = get_template('cotisations/email_invoice') + + mail = EmailMessage( + _('Your invoice'), + template.render(ctx), + GeneralOption.get_cached_value('email_from'), + [new_invoice_instance.user.email], + attachments = [('invoice.pdf', pdf, 'application/pdf')] + ) + mail.send() + return new_invoice_instance.paiement.end_payment( new_invoice_instance, request @@ -161,6 +205,7 @@ def new_facture(request, user, userid): balance = user.solde else: balance = None + return form( { 'factureform': invoice_form, From 9dd54a99a5b9fba1970d1b69008763d7062a7468 Mon Sep 17 00:00:00 2001 From: Delphine SALVY Date: Mon, 23 Jul 2018 00:13:25 +0200 Subject: [PATCH 2/3] Fix 141 : envoi des factures par mail --- .../templates/cotisations/email_invoice | 14 +++++ cotisations/utils.py | 63 +++++++++++++++++++ cotisations/views.py | 51 ++------------- 3 files changed, 83 insertions(+), 45 deletions(-) diff --git a/cotisations/templates/cotisations/email_invoice b/cotisations/templates/cotisations/email_invoice index 71459733..8d6b2cc2 100644 --- a/cotisations/templates/cotisations/email_invoice +++ b/cotisations/templates/cotisations/email_invoice @@ -1,3 +1,17 @@ +=== English version below === + +Bonjour {{name}}, + +Nous vous remercions pour votre achat auprès de {{asso_name}} et nous vous en joignons la facture. + +En cas de question, n’hésitez pas à nous contacter par mail à {{contact_mail}}. + +Cordialement, +L’équipe de {{asso_name}} + + +=== English version === + Dear {{name}}, Thank you for your purchase. Here is your invoice. diff --git a/cotisations/utils.py b/cotisations/utils.py index f36b376f..0211dd40 100644 --- a/cotisations/utils.py +++ b/cotisations/utils.py @@ -19,6 +19,16 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +import os + +from django.template.loader import get_template +from django.core.mail import EmailMessage + +from .tex import create_pdf +from preferences.models import AssoOption, GeneralOption +from re2o.settings import LOGO_PATH +from re2o import settings + def find_payment_method(payment): """Finds the payment method associated to the payment if it exists.""" @@ -30,3 +40,56 @@ def find_payment_method(payment): except method.PaymentMethod.DoesNotExist: pass return None + + +def send_mail_invoice(invoice): + """Creates the pdf of the invoice and sends it by email to the client""" + purchases_info = [] + for purchase in invoice.vente_set.all(): + purchases_info.append({ + 'name': purchase.name, + 'price': purchase.prix, + 'quantity': purchase.number, + 'total_price': purchase.prix_total + }) + + ctx = { + 'paid': True, + 'fid': invoice.id, + 'DATE': invoice.date, + 'recipient_name': "{} {}".format( + invoice.user.name, + invoice.user.surname + ), + 'address': invoice.user.room, + 'article': purchases_info, + 'total': invoice.prix_total(), + 'asso_name': AssoOption.get_cached_value('name'), + 'line1': AssoOption.get_cached_value('adresse1'), + 'line2': AssoOption.get_cached_value('adresse2'), + 'siret': AssoOption.get_cached_value('siret'), + 'email': AssoOption.get_cached_value('contact'), + 'phone': AssoOption.get_cached_value('telephone'), + 'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH) + } + + pdf = create_pdf('cotisations/factures.tex', ctx) + template = get_template('cotisations/email_invoice') + + ctx = { + 'name': "{} {}".format( + invoice.user.name, + invoice.user.surname + ), + 'contact_mail': AssoOption.get_cached_value('contact'), + 'asso_name': AssoOption.get_cached_value('name') + } + + mail = EmailMessage( + 'Votre facture / Your invoice', + template.render(ctx), + GeneralOption.get_cached_value('email_from'), + [invoice.user.email], + attachments=[('invoice.pdf', pdf, 'application/pdf')] + ) + mail.send() diff --git a/cotisations/views.py b/cotisations/views.py index 5ac55324..66eb66f5 100644 --- a/cotisations/views.py +++ b/cotisations/views.py @@ -40,8 +40,6 @@ from django.db.models import Q from django.forms import modelformset_factory, formset_factory from django.utils import timezone from django.utils.translation import ugettext as _ -from django.core.mail import EmailMessage -from django.template.loader import get_template # Import des models, forms et fonctions re2o from reversion import revisions as reversion @@ -74,9 +72,9 @@ from .forms import ( SelectClubArticleForm, RechargeForm ) -from .tex import create_pdf, render_invoice +from .tex import render_invoice from .payment_methods.forms import payment_method_factory -from .utils import find_payment_method +from .utils import find_payment_method, send_mail_invoice @login_required @@ -149,47 +147,7 @@ def new_facture(request, user, userid): p.facture = new_invoice_instance p.save() - facture = new_invoice_instance # BErk - purchases_info = [] - for purchase in facture.vente_set.all(): - purchases_info.append({ - 'name': purchase.name, - 'price': purchase.prix, - 'quantity': purchase.number, - 'total_price': purchase.prix_total - }) - ctx = { - 'paid': True, - 'fid': facture.id, - 'DATE': facture.date, - 'recipient_name': "{} {}".format( - facture.user.name, - facture.user.surname - ), - 'address': facture.user.room, - 'article': purchases_info, - 'total': facture.prix_total(), - 'asso_name': AssoOption.get_cached_value('name'), - 'line1': AssoOption.get_cached_value('adresse1'), - 'line2': AssoOption.get_cached_value('adresse2'), - 'siret': AssoOption.get_cached_value('siret'), - 'email': AssoOption.get_cached_value('contact'), - 'phone': AssoOption.get_cached_value('telephone'), - 'tpl_path': os.path.join(settings.BASE_DIR, LOGO_PATH) - } - - pdf = create_pdf('cotisations/factures.tex', ctx) - - template = get_template('cotisations/email_invoice') - - mail = EmailMessage( - _('Your invoice'), - template.render(ctx), - GeneralOption.get_cached_value('email_from'), - [new_invoice_instance.user.email], - attachments = [('invoice.pdf', pdf, 'application/pdf')] - ) - mail.send() + send_mail_invoice(new_invoice_instance) return new_invoice_instance.paiement.end_payment( new_invoice_instance, @@ -791,6 +749,9 @@ def credit_solde(request, user, **_kwargs): prix=refill_form.cleaned_data['value'], number=1 ) + + send_mail_invoice(invoice) + return invoice.paiement.end_payment(invoice, request) p = get_object_or_404(Paiement, is_balance=True) return form({ From 4ab0dad146161afbe870a92d13cddc66364fbbf7 Mon Sep 17 00:00:00 2001 From: Hugo LEVY-FALK Date: Wed, 15 Aug 2018 23:56:34 +0200 Subject: [PATCH 3/3] Documentation propre de render_tex et create_pdf --- cotisations/tex.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/cotisations/tex.py b/cotisations/tex.py index 4487d5b8..f3f8601b 100644 --- a/cotisations/tex.py +++ b/cotisations/tex.py @@ -62,15 +62,23 @@ def render_invoice(_request, ctx={}): def create_pdf(template, ctx={}): - """ - Creates and returns a PDF from a LaTeX template using pdflatex. + """Creates and returns a PDF from a LaTeX template using pdflatex. + + It create a temporary file for the PDF then read it to return its content. + + Args: + template: Path to the LaTeX template. + ctx: Dict with the context for rendering the template. + + Returns: + The content of the temporary PDF file generated. """ context = Context(ctx) template = get_template(template) rendered_tpl = template.render(context).encode('utf-8') with tempfile.TemporaryDirectory() as tempdir: - for i in range(2): + for _ in range(2): process = Popen( ['pdflatex', '-output-directory', tempdir], stdin=PIPE, @@ -84,10 +92,18 @@ def create_pdf(template, ctx={}): def render_tex(_request, template, ctx={}): - """ - Creates a PDF from a LaTex templates using pdflatex. - Writes it in a temporary directory and send back an HTTP response for + """Creates a PDF from a LaTex templates using pdflatex. + + Calls `create_pdf` and send back an HTTP response for accessing this file. + + Args: + _request: Unused, but allow using this function as a Django view. + template: Path to the LaTeX template. + ctx: Dict with the context for rendering the template. + + Returns: + An HttpResponse with type `application/pdf` containing the PDF file. """ pdf = create_pdf(template, ctx={}) r = HttpResponse(content_type='application/pdf')