diff --git a/jdav_web/members/admin.py b/jdav_web/members/admin.py index 56ca9c0..83f9517 100644 --- a/jdav_web/members/admin.py +++ b/jdav_web/members/admin.py @@ -981,6 +981,15 @@ class GenerateSeminarReportForm(forms.Form): widget=CheckboxInput(attrs={'style': 'display: inherit'}), required=False) +class GenerateSjrForm(forms.Form): + + def __init__(self, *args, **kwargs): + self.attachments = kwargs.pop('attachments') + + super(GenerateSjrForm,self).__init__(*args,**kwargs) + self.fields['invoice'] = forms.ChoiceField(choices=self.attachments, label=_('Invoice')) + + class FreizeitAdmin(CommonAdminMixin, nested_admin.NestedModelAdmin): #inlines = [MemberOnListInline, LJPOnListInline, StatementOnListInline] @@ -1077,17 +1086,41 @@ class FreizeitAdmin(CommonAdminMixin, nested_admin.NestedModelAdmin): return serve_pdf(fp) return self.render_seminar_report_options(request, memberlist, GenerateSeminarReportForm()) seminar_report.short_description = _('Generate seminar report') - + + def render_sjr_options(self, request, memberlist, form): + context = dict(self.admin_site.each_context(request), + title=_('Generate SJR application'), + opts=self.opts, + memberlist=memberlist, + form=form, + object=memberlist) + return render(request, 'admin/generate_sjr_application.html', context=context) + def sjr_application(self, request, memberlist): - if not self.may_view_excursion(request, memberlist): - return self.not_allowed_view(request, memberlist) - context = memberlist.sjr_application_fields() if hasattr(memberlist, 'statement'): - attachments = [b.proof.path for b in memberlist.statement.bill_set.all() if b.proof] + attachment_names = [f"{b.short_description}: {b.explanation} ({b.amount:.2f}€)" for b in memberlist.statement.bill_set.all() if b.proof] + attachment_paths = [b.proof.path for b in memberlist.statement.bill_set.all() if b.proof] else: - attachments = [] - title = memberlist.ljpproposal.title if hasattr(memberlist, 'ljpproposal') else memberlist.name - return fill_pdf_form(title + "_SJR_Antrag", 'members/sjr_template.pdf', context, attachments) + attachment_names = [] + attachment_paths = [] + attachments = zip(attachment_paths, attachment_names) + + if not self.may_view_excursion(request, memberlist): + return self.not_allowed_view(request, memberlist) + if "apply" in request.POST: + form = GenerateSjrForm(request.POST, attachments=attachments) + if not form.is_valid(): + messages.error(request, _('Please select an invoice.')) + return self.render_sjr_options(request, memberlist, form) + + selected_attachments = [form.cleaned_data['invoice']] + context = memberlist.sjr_application_fields() + title = memberlist.ljpproposal.title if hasattr(memberlist, 'ljpproposal') else memberlist.name + + return fill_pdf_form(title + "_SJR_Antrag", 'members/sjr_template.pdf', context, selected_attachments) + + return self.render_sjr_options(request, memberlist, GenerateSjrForm(attachments=attachments)) + sjr_application.short_description = _('Generate SJR application') def finance_overview(self, request, memberlist): diff --git a/jdav_web/members/locale/de/LC_MESSAGES/django.po b/jdav_web/members/locale/de/LC_MESSAGES/django.po index f52f21e..f50cb29 100644 --- a/jdav_web/members/locale/de/LC_MESSAGES/django.po +++ b/jdav_web/members/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-01-18 23:22+0100\n" +"POT-Creation-Date: 2025-01-19 10:08+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -341,6 +341,10 @@ msgstr "Modus" msgid "Prepend V32" msgstr "V32 Formblatt einfügen" +#: members/admin.py +msgid "Invoice" +msgstr "Beleg" + #: members/admin.py msgid "" "General information on your excursion. These are partly relevant for the " @@ -380,10 +384,14 @@ msgstr "" "Der vollständiger Modus ist nur verfügbar, wenn der Seminarbericht " "ausgefüllt ist. " -#: members/admin.py +#: members/admin.py members/templates/admin/generate_sjr_application.html msgid "Generate SJR application" msgstr "SJR Antrag erstellen" +#: members/admin.py +msgid "Please select an invoice." +msgstr "Bitte wähle einen Beleg aus." + #: members/admin.py msgid "No statement found. Please add a statement and then retry." msgstr "" @@ -1021,6 +1029,7 @@ msgstr "Fortbildungen" #: members/templates/admin/demote_to_waiter.html #: members/templates/admin/freizeit_finance_overview.html #: members/templates/admin/generate_seminar_report.html +#: members/templates/admin/generate_sjr_application.html #: members/templates/admin/invite_as_user.html #: members/templates/admin/invite_for_group.html #: members/templates/admin/invite_for_group_text.html @@ -1045,6 +1054,7 @@ msgstr "Zurück auf die Warteliste setzen" #: members/templates/admin/demote_to_waiter.html #: members/templates/admin/freizeit_finance_overview.html #: members/templates/admin/generate_seminar_report.html +#: members/templates/admin/generate_sjr_application.html #: members/templates/admin/invite_as_user.html #: members/templates/admin/invite_for_group.html #: members/templates/admin/invite_selected_as_user.html @@ -1301,9 +1311,27 @@ msgstr "" "Felder im Formblatt selbst aus und unterschreibe das PDF." #: members/templates/admin/generate_seminar_report.html +#: members/templates/admin/generate_sjr_application.html msgid "Generate" msgstr "Erstellen" +#: members/templates/admin/generate_sjr_application.html +msgid "Here you can generate an allowance application for the SJR." +msgstr "Hier kannst du einen SJR-Zuschussantrag erstellen." + +#: members/templates/admin/generate_sjr_application.html +msgid "" +"The application needs to be complemented with an invoice from the trip as " +"proof." +msgstr "" +"An den Antrag muss ein Ausgabenbeleg angehängt werden, der beweist, dass die " +"Aktivität stattgefunden hat." + +#: members/templates/admin/generate_sjr_application.html +msgid "" +"Please send this application form to the jdav finance officer via email." +msgstr "Bitte sende diesen Antrag an den/die JDAV-Finanzwart*in per E-Mail." + #: members/templates/admin/invite_as_user.html #, python-format msgid "" diff --git a/jdav_web/members/pdf.py b/jdav_web/members/pdf.py index a273b95..00a9877 100644 --- a/jdav_web/members/pdf.py +++ b/jdav_web/members/pdf.py @@ -100,12 +100,18 @@ def fill_pdf_form(name, template_path, fields, attachments=[], save_only=False): for fp in attachments: try: - img = Image.open(fp) - img_pdf = BytesIO() - img.save(img_pdf, "pdf") + if fp.endswith(".pdf"): + # append pdf directly + img_pdf = PdfReader(fp) + else: + # convert ensures that png files with an alpha channel can be appended + img = Image.open(fp).convert("RGB") + img_pdf = BytesIO() + img.save(img_pdf, "pdf") writer.append(img_pdf) - except: + except Exception as e: print("Could not add image", fp) + print(e) with open(media_path(filename_pdf), 'wb') as output_stream: writer.write(output_stream) diff --git a/jdav_web/members/templates/admin/generate_sjr_application.html b/jdav_web/members/templates/admin/generate_sjr_application.html new file mode 100644 index 0000000..98f6f53 --- /dev/null +++ b/jdav_web/members/templates/admin/generate_sjr_application.html @@ -0,0 +1,52 @@ +{% extends "admin/base_site.html" %} +{% load i18n admin_urls static %} + +{% block extrahead %} + {{ block.super }} + {{ media }} + + + +{% endblock %} + +{% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} invite-waiter +{% endblock %} + +{% block breadcrumbs %} + +{% endblock %} + +{% block content %} +

+{% blocktrans %}Here you can generate an allowance application for the SJR.{% endblocktrans %} +

+

+{% blocktrans %}The application needs to be complemented with an invoice from the trip as proof.{% endblocktrans %} +

+ +
+ {% csrf_token %} +

+ + {{ form }} +
+

+

+ {% blocktrans %}Please send this application form to the jdav finance officer via email.{% endblocktrans %} +

+
+ + + + {% translate "Cancel" %} +
+ + +{% endblock %}