From 0eedc3ecf94486a23b299c80d674ac45c75c6a89 Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Sat, 3 May 2025 19:14:34 +0200 Subject: [PATCH] feat(finance): send statement summary to finance office --- jdav_web/finance/admin.py | 5 +++- .../finance/locale/de/LC_MESSAGES/django.po | 27 +++++++++++++++---- jdav_web/finance/models.py | 27 +++++++++++++++++++ .../templates/admin/confirmed_statement.html | 3 ++- .../jdav_web/settings/components/texts.py | 8 ++++++ jdav_web/jdav_web/settings/local.py | 1 + 6 files changed, 64 insertions(+), 7 deletions(-) diff --git a/jdav_web/finance/admin.py b/jdav_web/finance/admin.py index f9a9e2a..d11b233 100644 --- a/jdav_web/finance/admin.py +++ b/jdav_web/finance/admin.py @@ -219,7 +219,7 @@ class StatementSubmittedAdmin(admin.ModelAdmin): messages.error(request, _("%(name)s is not yet submitted.") % {'name': str(statement)}) return HttpResponseRedirect(reverse('admin:%s_%s_change' % (self.opts.app_label, self.opts.model_name), args=(statement.pk,))) - if "transaction_execution_confirm" in request.POST: + if "transaction_execution_confirm" in request.POST or "transaction_execution_confirm_and_send" in request.POST: res = statement.confirm(confirmer=get_member(request)) if not res: # this should NOT happen! @@ -227,6 +227,9 @@ class StatementSubmittedAdmin(admin.ModelAdmin): _("An error occured while trying to confirm %(name)s. Please try again.") % {'name': str(statement)}) return HttpResponseRedirect(reverse('admin:%s_%s_overview' % (self.opts.app_label, self.opts.model_name))) + if "transaction_execution_confirm_and_send" in request.POST: + statement.send_summary(cc=[request.user.member.email] if hasattr(request.user, 'member') else []) + messages.success(request, _("Successfully sent receipt to the office.")) messages.success(request, _("Successfully confirmed %(name)s. I hope you executed the associated transactions, I wont remind you again.") % {'name': str(statement)}) diff --git a/jdav_web/finance/locale/de/LC_MESSAGES/django.po b/jdav_web/finance/locale/de/LC_MESSAGES/django.po index df726c6..24fed2d 100644 --- a/jdav_web/finance/locale/de/LC_MESSAGES/django.po +++ b/jdav_web/finance/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-04-27 23:00+0200\n" +"POT-Creation-Date: 2025-05-03 19:06+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -64,6 +64,10 @@ msgstr "" "Beim Abwickeln von %(name)s ist ein Fehler aufgetreten. Bitte versuche es " "erneut." +#: finance/admin.py +msgid "Successfully sent receipt to the office." +msgstr "Abrechnungsbeleg an die Geschäftsstelle gesendet." + #: finance/admin.py #, python-format msgid "" @@ -283,6 +287,10 @@ msgstr "Abrechnungen" msgid "Statement: %(excursion)s" msgstr "Abrechnung: %(excursion)s" +#: finance/models.py +msgid "Excursion %(excursion)s" +msgstr "Ausfahrt %(excursion)s" + #: finance/models.py msgid "Ready to confirm" msgstr "Bereit zur Abwicklung" @@ -310,6 +318,11 @@ msgstr "LJP-Zuschuss %(excu)s" msgid "Total" msgstr "Gesamtbetrag" +#: finance/models.py +#, python-format +msgid "Statement summary for %(title)s" +msgstr "Abrechnung für %(title)s" + #: finance/models.py msgid "Statement in preparation" msgstr "Abrechnung in Vorbereitung" @@ -433,8 +446,12 @@ msgid "I did execute the listed transactions." msgstr "Ich habe die aufgeführten Überweisungen ausgeführt." #: finance/templates/admin/confirmed_statement.html -msgid "Confirm" -msgstr "Bestätigen" +msgid "Confirm only" +msgstr "Nur bestätigen" + +#: finance/templates/admin/confirmed_statement.html +msgid "Confirm and send receipt to office" +msgstr "Bestätigen und Beleg an die Geschäftsstelle senden" #: finance/templates/admin/overview_submitted_statement.html msgid "Overview" @@ -558,8 +575,8 @@ msgid "" "against allowances and subsidies." msgstr "" "Da Personen über 27 an der Ausfahrt teilnehommen haben, wird ein " -"Organisationsbeitrag von %(org_fee)s€ pro Person und Tag fällig. Der Gesamtbetrag " -"von %(total_org_fee_theoretical)s€ wird mit Zuschüssen und " +"Organisationsbeitrag von %(org_fee)s€ pro Person und Tag fällig. Der " +"Gesamtbetrag von %(total_org_fee_theoretical)s€ wird mit Zuschüssen und " "Aufwandsentschädigungen verrechnet." #: finance/templates/admin/overview_submitted_statement.html diff --git a/jdav_web/finance/models.py b/jdav_web/finance/models.py index 2e4b3e1..c09cf22 100644 --- a/jdav_web/finance/models.py +++ b/jdav_web/finance/models.py @@ -15,6 +15,9 @@ import rules from contrib.models import CommonModel from contrib.rules import has_global_perm from utils import cvt_to_decimal, RestrictedFileField +from members.pdf import render_tex_with_attachments +from mailer.mailutils import send as send_mail +from contrib.media import media_path from schwifty import IBAN import re @@ -121,6 +124,13 @@ class Statement(CommonModel): else: return self.short_description + @property + def title(self): + if self.excursion is not None: + return _('Excursion %(excursion)s') % {'excursion': str(self.excursion)} + else: + return self.short_description + def submit(self, submitter=None): self.submitted = True self.submitted_date = timezone.now() @@ -534,6 +544,23 @@ class Statement(CommonModel): .order_by('short_description')\ .annotate(amount=Sum('amount')) + def send_summary(self, cc=None): + """ + Sends a summary of the statement to the central office of the association. + """ + excursion = self.excursion + context = dict(statement=self.template_context(), excursion=excursion, settings=settings) + pdf_filename = f"{excursion.code}_{excursion.name}_Zuschussbeleg" if excursion else f"Abrechnungsbeleg" + attachments = [bill.proof.path for bill in self.bills_covered if bill.proof] + filename = render_tex_with_attachments(pdf_filename, 'finance/statement_summary.tex', + context, attachments, save_only=True) + send_mail(_('Statement summary for %(title)s') % { 'title': self.title }, + settings.SEND_STATEMENT_SUMMARY.format(statement=self.title), + sender=settings.DEFAULT_SENDING_MAIL, + recipients=[settings.SEKTION_FINANCE_MAIL], + cc=cc, + attachments=[media_path(filename)]) + class StatementUnSubmittedManager(models.Manager): def get_queryset(self): diff --git a/jdav_web/finance/templates/admin/confirmed_statement.html b/jdav_web/finance/templates/admin/confirmed_statement.html index 3d35418..23e0c2c 100644 --- a/jdav_web/finance/templates/admin/confirmed_statement.html +++ b/jdav_web/finance/templates/admin/confirmed_statement.html @@ -110,6 +110,7 @@ links.forEach(link => { {% blocktrans %}I did execute the listed transactions.{% endblocktrans %}

- + + {% endblock %} diff --git a/jdav_web/jdav_web/settings/components/texts.py b/jdav_web/jdav_web/settings/components/texts.py index e70e3c5..43bc197 100644 --- a/jdav_web/jdav_web/settings/components/texts.py +++ b/jdav_web/jdav_web/settings/components/texts.py @@ -273,3 +273,11 @@ Im Anhang findet ihr die Kriseninterventionsliste. Viele Grüße Euer KOMPASS""") + +SEND_STATEMENT_SUMMARY = get_text('send_statement_summary', default="""Hallo zusammen, + +anbei findet ihr die Abrechnung inklusive Belege für {statement}. Die Überweisungen +wurden wie beschrieben ausgeführt. + +Viele Grüße +Euer KOMPASS""") diff --git a/jdav_web/jdav_web/settings/local.py b/jdav_web/jdav_web/settings/local.py index 34dbe5c..71e260c 100644 --- a/jdav_web/jdav_web/settings/local.py +++ b/jdav_web/jdav_web/settings/local.py @@ -9,6 +9,7 @@ SEKTION_CONTACT_MAIL = get_var('section', 'contact_mail', default='info@example. SEKTION_BOARD_MAIL = get_var('section', 'board_mail', default=SEKTION_CONTACT_MAIL) SEKTION_CRISIS_INTERVENTION_MAIL = get_var('section', 'crisis_intervention_mail', default=SEKTION_BOARD_MAIL) +SEKTION_FINANCE_MAIL = get_var('section', 'finance_mail', default=SEKTION_CONTACT_MAIL) SEKTION_IBAN = get_var('section', 'iban', default='Foo 123') SEKTION_ACCOUNT_HOLDER = get_var('section', 'account_holder', default='Foo')