diff --git a/cotisations/migrations/0039_documenttemplate.py b/cotisations/migrations/0039_documenttemplate.py index f07506e0..ee93da92 100644 --- a/cotisations/migrations/0039_documenttemplate.py +++ b/cotisations/migrations/0039_documenttemplate.py @@ -1,31 +1,11 @@ # -*- coding: utf-8 -*- # Generated by Django 1.10.7 on 2019-01-03 16:48 from __future__ import unicode_literals -import os from django.db import migrations, models -from django.core.files import File -from django.conf import settings import re2o.mixins -def create_default_templates(apps, schema_editor): - DocumentTemplate = apps.get_model('cotisations', 'DocumentTemplate') - invoice_path = os.path.join( - settings.BASE_DIR, - "cotisations", - "templates", - "cotisations", - "factures.tex" - ) - with open(invoice_path) as f: - tpl, _ = DocumentTemplate.objects.get_or_create( - name="Re2o default invoice", - ) - tpl.template.save('default_invoice.tex', File(f)) - tpl.save() - - class Migration(migrations.Migration): dependencies = [ @@ -46,5 +26,4 @@ class Migration(migrations.Migration): }, bases=(re2o.mixins.RevMixin, re2o.mixins.AclMixin, models.Model), ), - migrations.RunPython(create_default_templates), ] diff --git a/cotisations/models.py b/cotisations/models.py index 7ca4d4a9..42d76a08 100644 --- a/cotisations/models.py +++ b/cotisations/models.py @@ -50,7 +50,9 @@ from machines.models import regen from re2o.field_permissions import FieldPermissionModelMixin from re2o.mixins import AclMixin, RevMixin -from cotisations.utils import find_payment_method, send_mail_invoice +from cotisations.utils import ( + find_payment_method, send_mail_invoice, send_mail_voucher +) from cotisations.validators import check_no_balance @@ -238,20 +240,22 @@ class Facture(BaseInvoice): self.__original_valid = self.valid self.__original_control = self.control - def get_subscribtion(self): - return self.vent_set.filter( - Q(type_cotisation='All') | - Q(type_cotisation='Cotisation') + def get_subscription(self): + return Cotisation.objects.filter( + vente__in=self.vente_set.filter( + Q(type_cotisation='All') | + Q(type_cotisation='Cotisation') + ) ) - def is_subscribtion(self): - return bool(self.get_subscribtion()) + def is_subscription(self): + return bool(self.get_subscription()) def save(self, *args, **kwargs): super(Facture, self).save(*args, **kwargs) if not self.__original_valid and self.valid: send_mail_invoice(self) - if self.is_subscribtion() and not self.__original_control and self.control: + if self.is_subscription() and not self.__original_control and self.control: send_mail_voucher(self) def __str__(self): @@ -267,10 +271,6 @@ def facture_post_save(**kwargs): user = facture.user user.set_active() user.ldap_sync(base=False, access_refresh=True, mac_refresh=False) - if facture.control: - user = facture.user - if user.is_adherent(): - user.notif_subscription_accepted() @receiver(post_delete, sender=Facture) @@ -955,7 +955,7 @@ def cotisation_post_delete(**_kwargs): class DocumentTemplate(RevMixin, AclMixin, models.Model): """Represent a template in order to create documents such as invoice or - subscribtion voucher. + subscription voucher. """ template = models.FileField( upload_to='templates/', @@ -972,18 +972,3 @@ class DocumentTemplate(RevMixin, AclMixin, models.Model): def __str__(self): return str(self.name) - - -class Voucher(RevMixin, AclMixin, models.Model): - """A Subscription Voucher.""" - user = models.ForeignKey( - 'users.User', - on_delete=models.CASCADE, - verbose_name=_("user") - ) - - class Meta: - verbose_name = _("subscription voucher") - - def __str__(self): - return "voucher {} {}".format(self.user, self.date) diff --git a/cotisations/templates/cotisations/aff_cost_estimate.html b/cotisations/templates/cotisations/aff_cost_estimate.html index e591a5fe..eb040dce 100644 --- a/cotisations/templates/cotisations/aff_cost_estimate.html +++ b/cotisations/templates/cotisations/aff_cost_estimate.html @@ -75,7 +75,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% if estimate.final_invoice %} {% else %} - ' + {% endif %} diff --git a/cotisations/templates/cotisations/aff_cotisations.html b/cotisations/templates/cotisations/aff_cotisations.html index 7dd64395..e27ae8c7 100644 --- a/cotisations/templates/cotisations/aff_cotisations.html +++ b/cotisations/templates/cotisations/aff_cotisations.html @@ -48,7 +48,7 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "Date" as tr_date %} {% include 'buttons/sort.html' with prefix='cotis' col='date' text=tr_date %} - + {% trans "Invoice ID" as tr_invoice_id %} {% include 'buttons/sort.html' with prefix='cotis' col='id' text=tr_invoice_id %} @@ -63,17 +63,17 @@ with this program; if not, write to the Free Software Foundation, Inc., {{ facture.prix_total }} {{ facture.paiement }} {{ facture.date }} - {{ facture.id }} + {{ facture.id }} {% can_edit facture %} - {% include 'buttons/edit.html' with href='cotisations:edit-facture' id=facture.id %} + {% include 'buttons/edit.html' with href='cotisations:edit-facture' id=facture.id %} {% acl_else %} {% trans "Controlled invoice" %} {% acl_end %} {% can_delete facture %} - {% include 'buttons/suppr.html' with href='cotisations:del-facture' id=facture.id %} + {% include 'buttons/suppr.html' with href='cotisations:del-facture' id=facture.id %} {% acl_end %} - {% history_button facture %} + {% history_button facture %} {% if facture.valid %} @@ -83,13 +83,18 @@ with this program; if not, write to the Free Software Foundation, Inc., {% else %} {% trans "Invalidated invoice" %} {% endif %} + {% if facture.control and facture.is_subscription %} + + {% trans "Voucher" %} + + {% endif %} {% endfor %} -{% if facture_list.paginator %} + {% if facture_list.paginator %} {% include 'pagination.html' with list=facture_list %} -{% endif %} + {% endif %} diff --git a/cotisations/templates/cotisations/email_subscription_accepted b/cotisations/templates/cotisations/email_subscription_accepted new file mode 100644 index 00000000..58027cec --- /dev/null +++ b/cotisations/templates/cotisations/email_subscription_accepted @@ -0,0 +1,22 @@ +Bonjour {{name}} ! + +Nous vous informons que votre cotisation auprès de {{asso_name}} a été acceptée. Vous voilà donc membre de l'association. + +Vous trouverez en pièce jointe un reçu. + +Pour nous faire part de toute remarque, suggestion ou problème vous pouvez nous envoyer un mail à {{asso_email}}. + +À bientôt, +L'équipe de {{asso_name}}. + +--- + +Your subscription to {{asso_name}} has just been accepted. You are now a full member of {{asso_name}}. + +You will find with this email a subscription voucher. + +For any information, suggestion or problem, you can contact us via email at +{{asso_email}}. + +Regards, +The {{asso_name}} team. diff --git a/cotisations/templates/cotisations/voucher.tex b/cotisations/templates/cotisations/voucher.tex new file mode 100644 index 00000000..aeebc187 --- /dev/null +++ b/cotisations/templates/cotisations/voucher.tex @@ -0,0 +1,87 @@ +{% load i18n %} +{% language 'fr' %} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% 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[letterpaper,hmargin=0.79in,vmargin=0.79in]{geometry} +\usepackage{longtable} +\usepackage{graphicx} +\usepackage{tabularx} +\usepackage{eurosym} +\usepackage{multicol} + +\pagestyle{empty} % No page numbers + +\linespread{1.5} + +\newcommand{\doublehline}{\noalign{\hrule height 1pt}} +\setlength{\parindent}{0cm} + + +\begin{document} + + %---------------------------------------------------------------------------------------- + % HEADING SECTION + %---------------------------------------------------------------------------------------- + \begin{center} + {\Huge\bf Reçu d'adhésion \\ {{asso_name|safe}} } % Company providing the invoice + \end{center} + + \bigskip + \hrule + \bigskip + + \vfill + + Je sousigné, {{pres_name|safe}}, déclare par la présente avoir reçu le bulletin d'adhésion de: + + \begin{center} + \setlength{\tabcolsep}{10pt} % Make table columns tighter, usefull for postionning + \begin{tabular}{r l r l} + {\bf Prénom :}~ & {{firstname|safe}} & {% if phone %}{\bf Téléphone :}~ & {{phone}}{% else %} & {% endif %} \\ + {\bf Nom :}~ & {{lastname|safe}} & {\bf Mail :}~ & {{email|safe}} \\ + \end{tabular} + \end{center} + \bigskip + + ainsi que sa cotisation. + + Le postulant, déclare reconnaître l'objet de l'association, et en a accepté les statuts ainsi que le règlement intérieur qui sont mis à sa disposition dans les locaux de l'association. L'adhésion du membre sus-nommé est ainsi validée. Ce reçu confirme la qualité de membre du postulant, et ouvre droit à la participation à l'assemblée générale de l'association jusqu'au {{date_end|date:"d F Y"}}. + + \bigskip + + Validé électroniquement par {{pres_name|safe}}, le {{date_begin|date:"d/m/Y"}}. + + \vfill + \hrule + \smallskip + \footnotesize + Les informations recueillies sont nécessaires pour votre adhésion. Conformément à la loi "Informatique et Libertés" du 6 janvier 1978, vous disposez d'un droit d'accès et de rectification aux données personnelles vous concernant. Pour l'exercer, adressez-vous au secrétariat de l'association. + + +\end{document} +{% endlanguage %} diff --git a/cotisations/tex.py b/cotisations/tex.py index 0d6dc31f..1ab964ba 100644 --- a/cotisations/tex.py +++ b/cotisations/tex.py @@ -79,13 +79,14 @@ def render_voucher(_request, ctx={}): filename = '_'.join([ 'voucher', slugify(ctx.get('asso_name', "")), - slugify(ctx.get('recipient_name', "")), - str(ctx.get('DATE', datetime.now()).year), - str(ctx.get('DATE', datetime.now()).month), - str(ctx.get('DATE', datetime.now()).day), + slugify(ctx.get('firstname', "")), + slugify(ctx.get('lastname', "")), + str(ctx.get('date_begin', datetime.now()).year), + str(ctx.get('date_begin', datetime.now()).month), + str(ctx.get('date_begin', datetime.now()).day), ]) templatename = options.voucher_template.template.name.split('/')[-1] - r = create_pdf(templatename, ctx) + r = render_tex(_request, templatename, ctx) r['Content-Disposition'] = 'attachment; filename="{name}.pdf"'.format( name=filename ) @@ -110,12 +111,13 @@ def create_pdf(template, ctx={}): with tempfile.TemporaryDirectory() as tempdir: for _ in range(2): - process = Popen( - ['pdflatex', '-output-directory', tempdir], - stdin=PIPE, - stdout=PIPE, - ) - process.communicate(rendered_tpl) + with open("/var/www/re2o/out.log", "w") as f: + process = Popen( + ['pdflatex', '-output-directory', tempdir], + stdin=PIPE, + stdout=f,#PIPE, + ) + process.communicate(rendered_tpl) with open(os.path.join(tempdir, 'texput.pdf'), 'rb') as f: pdf = f.read() diff --git a/cotisations/urls.py b/cotisations/urls.py index 380052e8..8dbb84ec 100644 --- a/cotisations/urls.py +++ b/cotisations/urls.py @@ -51,6 +51,11 @@ urlpatterns = [ views.facture_pdf, name='facture-pdf' ), + url( + r'^voucher_pdf/(?P[0-9]+)$', + views.voucher_pdf, + name='voucher-pdf' + ), url( r'^new_cost_estimate/$', views.new_cost_estimate, diff --git a/cotisations/utils.py b/cotisations/utils.py index a7856540..4715338b 100644 --- a/cotisations/utils.py +++ b/cotisations/utils.py @@ -25,7 +25,7 @@ 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 preferences.models import AssoOption, GeneralOption, CotisationsOption from re2o.settings import LOGO_PATH from re2o import settings @@ -97,52 +97,34 @@ def send_mail_invoice(invoice): def send_mail_voucher(invoice): """Creates a voucher from an 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) + 'pres_name': AssoOption.get_cached_value('pres_name'), + 'firstname': invoice.user.name, + 'lastname': invoice.user.surname, + 'email': invoice.user.email, + 'phone': invoice.user.telephone, + 'date_end': invoice.get_subscription().latest('date_end').date_end, + 'date_begin': invoice.get_subscription().earliest('date_start').date_start } - - pdf = create_pdf('cotisations/factures.tex', ctx) - template = get_template('cotisations/email_invoice') + templatename = CotisationsOption.get_cached_value('voucher_template').template.name.split('/')[-1] + pdf = create_pdf(templatename, ctx) + template = get_template('cotisations/email_subscription_accepted') ctx = { 'name': "{} {}".format( invoice.user.name, invoice.user.surname ), - 'contact_mail': AssoOption.get_cached_value('contact'), + 'asso_email': AssoOption.get_cached_value('contact'), 'asso_name': AssoOption.get_cached_value('name') } mail = EmailMessage( - 'Votre facture / Your invoice', + 'Votre reçu / Your voucher', template.render(ctx), GeneralOption.get_cached_value('email_from'), [invoice.user.get_mail], - attachments=[('invoice.pdf', pdf, 'application/pdf')] + attachments=[('voucher.pdf', pdf, 'application/pdf')] ) mail.send() diff --git a/cotisations/views.py b/cotisations/views.py index 38609305..98157210 100644 --- a/cotisations/views.py +++ b/cotisations/views.py @@ -88,7 +88,7 @@ from .forms import ( DocumentTemplateForm, DelDocumentTemplateForm ) -from .tex import render_invoice, escape_chars +from .tex import render_invoice, render_voucher, escape_chars from .payment_methods.forms import payment_method_factory from .utils import find_payment_method @@ -220,6 +220,7 @@ def new_cost_estimate(request): number=quantity ) discount_form.apply_to_invoice(cost_estimate_instance) + messages.success( request, _("The cost estimate was created.") @@ -485,7 +486,6 @@ def cost_estimate_pdf(request, invoice, **_kwargs): invoice with the total price, the payment method, the address and the legal information for the user. """ - # TODO : change vente to purchase purchases_objects = Vente.objects.all().filter(facture=invoice) # Get the article list and build an list out of it # contiaining (article_name, article_price, quantity, total_price) @@ -1145,3 +1145,30 @@ def index_document_template(request): return render(request, 'cotisations/index_document_template.html', { 'document_template_list': document_template_list }) + + +@login_required +@can_view(Facture) +def voucher_pdf(request, invoice, **_kwargs): + """ + View used to generate a PDF file from a controlled invoice + Creates a line for each Purchase (thus article sold) and generate the + invoice with the total price, the payment method, the address and the + legal information for the user. + """ + if not invoice.control: + messages.error( + request, + _("Could not find a voucher for that invoice.") + ) + return redirect(reverse('cotisations:index')) + return render_voucher(request, { + 'asso_name': AssoOption.get_cached_value('name'), + 'pres_name': AssoOption.get_cached_value('pres_name'), + 'firstname': invoice.user.name, + 'lastname': invoice.user.surname, + 'email': invoice.user.email, + 'phone': invoice.user.telephone, + 'date_end': invoice.get_subscription().latest('date_end').date_end, + 'date_begin': invoice.get_subscription().earliest('date_start').date_start + }) diff --git a/install_re2o.sh b/install_re2o.sh index 3c32cf4d..d64cdb50 100755 --- a/install_re2o.sh +++ b/install_re2o.sh @@ -331,7 +331,8 @@ copy_templates_files() { echo "Copying LaTeX templates ..." mkdir -p media/templates/ - cp cotisations/templates/cotisations/factures.tex media/templates + cp cotisations/templates/cotisations/factures.tex media/templates/default_invoice.tex + cp cotisations/templates/cotisations/voucher.tex media/templates/default_voucher.tex echo "Copying LaTeX templates: Done" } diff --git a/preferences/forms.py b/preferences/forms.py index d8e762e1..b1902d8d 100644 --- a/preferences/forms.py +++ b/preferences/forms.py @@ -183,9 +183,6 @@ class EditAssoOptionForm(ModelForm): self.fields['pseudo'].label = _("Usual name") self.fields['utilisateur_asso'].label = _("Account used for editing" " from /admin") - self.fields['payment'].label = _("Payment") - self.fields['payment_id'].label = _("Payment ID") - self.fields['payment_pass'].label = _("Payment password") self.fields['description'].label = _("Description") diff --git a/preferences/migrations/0057_cotisationsoption.py b/preferences/migrations/0057_cotisationsoption.py index d02d9c28..99c8bcc2 100644 --- a/preferences/migrations/0057_cotisationsoption.py +++ b/preferences/migrations/0057_cotisationsoption.py @@ -1,17 +1,47 @@ # -*- coding: utf-8 -*- # Generated by Django 1.10.7 on 2019-01-03 19:56 from __future__ import unicode_literals +import os from django.db import migrations, models import django.db.models.deletion +from django.core.files import File +from django.conf import settings import re2o.mixins def initialize_invoice_template(apps, schema_editor): CotisationsOption = apps.get_model('preferences', 'CotisationsOption') DocumentTemplate = apps.get_model('cotisations', 'DocumentTemplate') + invoice_path = os.path.join( + settings.BASE_DIR, + "cotisations", + "templates", + "cotisations", + "factures.tex" + ) + voucher_path = os.path.join( + settings.BASE_DIR, + "cotisations", + "templates", + "cotisations", + "voucher.tex" + ) + with open(invoice_path) as f: + tpl_invoice, _ = DocumentTemplate.objects.get_or_create( + name="Re2o default invoice", + ) + tpl_invoice.template.save('default_invoice.tex', File(f)) + tpl_invoice.save() + with open(voucher_path) as f: + tpl_voucher, _ = DocumentTemplate.objects.get_or_create( + name="Re2o default voucher", + ) + tpl_voucher.template.save('default_voucher.tex', File(f)) + tpl_voucher.save() CotisationsOption.objects.create( - invoice_template=DocumentTemplate.objects.first() + invoice_template=tpl_invoice, + voucher_template=tpl_voucher, ) @@ -28,6 +58,7 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('invoice_template', models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, related_name='invoice_template', to='cotisations.DocumentTemplate', verbose_name='Template for invoices')), + ('voucher_template', models.OneToOneField(on_delete=django.db.models.deletion.PROTECT, related_name='voucher_template', to='cotisations.DocumentTemplate', verbose_name='Template for subscription voucher')), ], options={ 'verbose_name': 'cotisations options', diff --git a/preferences/migrations/0058_assooption_pres_name.py b/preferences/migrations/0058_assooption_pres_name.py new file mode 100644 index 00000000..bcc480af --- /dev/null +++ b/preferences/migrations/0058_assooption_pres_name.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10.7 on 2019-01-10 22:13 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('preferences', '0057_cotisationsoption'), + ] + + operations = [ + migrations.AddField( + model_name='assooption', + name='pres_name', + field=models.CharField(default='', help_text='Displayed on subscription vouchers', max_length=255, verbose_name='President of the association'), + ), + ] diff --git a/preferences/models.py b/preferences/models.py index 99750850..f03a6719 100644 --- a/preferences/models.py +++ b/preferences/models.py @@ -521,6 +521,12 @@ class AssoOption(AclMixin, PreferencesModel): null=True, blank=True, ) + pres_name = models.CharField( + max_length=255, + default="", + verbose_name=_("President of the association"), + help_text=_("Displayed on subscription vouchers") + ) class Meta: permissions = ( diff --git a/preferences/templates/preferences/display_preferences.html b/preferences/templates/preferences/display_preferences.html index b0fd8dd8..92ac0915 100644 --- a/preferences/templates/preferences/display_preferences.html +++ b/preferences/templates/preferences/display_preferences.html @@ -343,6 +343,10 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "Description of the organisation" %} {{ assooptions.description|safe }} + + {% trans "President of the association"%} + {{ assooptions.pres_name }} + @@ -361,6 +365,10 @@ with this program; if not, write to the Free Software Foundation, Inc., {% trans "Invoices' template" %} {{ cotisationsoptions.invoice_template }} + + {% trans "Vouchers' template" %} + {{ cotisationsoptions.voucher_template }} + diff --git a/users/models.py b/users/models.py index 7d91b2b5..c1d0789a 100755 --- a/users/models.py +++ b/users/models.py @@ -663,26 +663,7 @@ class User(RevMixin, FieldPermissionModelMixin, AbstractBaseUser, ) return - def notif_subscription_accepted(self): - """Send an email when the subscription has been accepted""" - template = loader.get_template('users/email_subscription_accepted') - mailmessageoptions, _created = MailMessageOption\ - .objects.get_or_create() - context = Context({ - 'nom': self.get_full_name(), - 'asso_name': AssoOption.get_cached_value('name'), - 'asso_email': AssoOption.get_cached_value('contact'), - }) - send_mail( - 'Votre inscription a été validée / Your subscription has been accepted', - '', - GeneralOption.get_cached_value('email_from'), - [self.email], - html_message=template.render(context) - ) - return - - def reset_passwd_mail(self, request): + def reset_passwd_mail(self, request): """ Prend en argument un request, envoie un mail de réinitialisation de mot de pass """ req = Request() diff --git a/users/templates/users/email_subscription_accepted b/users/templates/users/email_subscription_accepted deleted file mode 100644 index 2ce5c839..00000000 --- a/users/templates/users/email_subscription_accepted +++ /dev/null @@ -1,22 +0,0 @@ -

Bonjour {{nom}} !

- -

Nous vous informons que votre cotisation auprès de {{asso_name}} a été acceptée. Vous voilà donc membre de l'association.

- -

Vous trouverez en pièce jointe un reçu.

- -

Pour nous faire part de toute remarque, suggestion ou problème vous pouvez nous envoyer un mail à {{asso_email}}.

- -

À bientôt,
-L'équipe de {{asso_name}}.

- -

---

- -

Your subscription to {{asso_name}} has just been accepted. You are now a full member of {{asso_name}}. - -

You will find with this email a subscription voucher.

- -

For any information, suggestion or problem, you can contact us via email at
-{{asso_email}}.

- -

Regards,
-The {{asso_name}} team.