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
Q+Cv8N0)({sg1@!?9|@?4wg3PC
literal 0
HcmV?d00001
diff --git a/jdav_web/members/templates/members/LJP_VBK_3-2.xlsx b/jdav_web/members/templates/members/LJP_VBK_3-2.xlsx
new file mode 100644
index 0000000000000000000000000000000000000000..1b21d3d986d922702d20540d68237edfc7fa789e
GIT binary patch
literal 17648
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
+
+
+
+
-
-
-
-
-
- {% translate "Cancel" %}
-
+
+{% translate "Back" %}
+
{% endblock %}
diff --git a/jdav_web/members/templates/members/seminar_report_docx.tex b/jdav_web/members/templates/members/seminar_report_docx.tex
new file mode 100644
index 0000000..d5f666b
--- /dev/null
+++ b/jdav_web/members/templates/members/seminar_report_docx.tex
@@ -0,0 +1,71 @@
+{% load tex_extras %}
+
+\documentclass[a4paper]{article}
+
+\usepackage[utf8]{inputenc}
+\usepackage{booktabs}
+\usepackage{amssymb}
+\usepackage{cmbright}
+\usepackage{graphicx}
+\usepackage{textpos}
+\usepackage[colorlinks, breaklinks]{hyperref}
+\usepackage{float}
+\usepackage[margin=1in]{geometry}
+\usepackage{array}
+\usepackage{ragged2e}
+\usepackage{tabularx}
+\usepackage{titlesec}
+
+\titleformat{\section}
+ {\Large\slshape}{\thesection\;}
+ {0em}{}
+
+\title{Seminarbericht}
+
+\begin{document}
+
+\maketitle
+
+% DESCRIPTION TABLE
+\begin{table}[H]
+ \begin{tabular}{ll}
+ \textbf{Sektion:} & {{ settings.SEKTION }} \\
+ \textbf{Titel der Maßnahme:} & {% if not memberlist.ljpproposal %}{{ memberlist.name|esc_all }}{% else %}{{ memberlist.ljpproposal.title }} {% endif %} \\
+ \textbf{Anzahl der durchgeführten Lehrgangstage:} & {{ memberlist.duration }} \\
+ \end{tabular}
+\end{table}
+
+\section{Bildungsziel}
+
+\begin{table}[H]
+ \begin{tabular}{ccllllllllllll}
+ {% if memberlist.ljpproposal.goal == 1 %}x{% endif %}& 1 & \multicolumn{12}{l}{Ehrenamtliche qualifizieren und stärken} \\
+ {% if memberlist.ljpproposal.goal == 2 %}x{% endif %}& 2 & \multicolumn{12}{l}{Erleben von demokratischen Prozessen. Entwickeln und Stärken eines Demokratieverständnisses.} \\
+ {% if memberlist.ljpproposal.goal == 3 %}x{% endif %}& 3 & \multicolumn{12}{l}{Entwicklung der Persönlichkeit und Erweiterung des sozialen Handlungsrepertoires.} \\
+ {% if memberlist.ljpproposal.goal == 4 %}x{% endif %}& 4 & \multicolumn{12}{l}{Bewusstsein schaffen einer Verantwortung für Natur, Umwelt und zukünftige Generationen.} \\
+ \end{tabular}
+\end{table}
+
+\section{Zielverfolgung- und Erreichung}
+
+{{ memberlist.ljpproposal.goals|esc_all }}
+
+\section{Zeitlicher Ablauf}
+
+\begin{table}[H]
+ \begin{tabular}{lllllll}
+ \toprule
+ \textbf{Datum} & \textbf{Uhrzeit} & \multicolumn{4}{l}{\textbf{Art der Aktion}} & \textbf{Dauer} \\
+ \midrule
+ {% for intervention in memberlist.ljpproposal.intervention_set.all %}
+ {{ intervention.date_start|date_short }}
+ & {{ intervention.date_start|time_short }}
+ & \multicolumn{4}{l}{ {{ intervention.activity|esc_all }} }
+ & {{ intervention.duration }} h \\
+ {% endfor %}
+ \bottomrule
+ & & \multicolumn{4}{l}{} & Summe: {{ memberlist.total_intervention_hours }} h \\
+ \end{tabular}
+\end{table}
+
+\end{document}
diff --git a/jdav_web/members/templatetags/tex_extras.py b/jdav_web/members/templatetags/tex_extras.py
index ac9b4ef..beb678d 100644
--- a/jdav_web/members/templatetags/tex_extras.py
+++ b/jdav_web/members/templatetags/tex_extras.py
@@ -18,3 +18,13 @@ def esc_all(val):
@register.filter
def datetime_short(date):
return date.strftime('%d.%m.%Y %H:%M')
+
+
+@register.filter
+def date_short(date):
+ return date.strftime('%d.%m.%y')
+
+
+@register.filter
+def time_short(date):
+ return date.strftime('%H:%M')
diff --git a/jdav_web/templates/admin/members/freizeit/change_form_object_tools.html b/jdav_web/templates/admin/members/freizeit/change_form_object_tools.html
index c52ac75..f27115c 100644
--- a/jdav_web/templates/admin/members/freizeit/change_form_object_tools.html
+++ b/jdav_web/templates/admin/members/freizeit/change_form_object_tools.html
@@ -24,13 +24,6 @@
-
-
-
-
-
-
-
-
- {% translate "Cancel" %}
-
-
-{% endblock %}
--
2.38.4
From 6b187812bb6c3693a6bf275babade63a43b90d23 Mon Sep 17 00:00:00 2001
From: Christian Merten
Date: Sun, 2 Feb 2025 18:22:10 +0100
Subject: [PATCH 04/12] more cleanup
---
jdav_web/members/admin.py | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/jdav_web/members/admin.py b/jdav_web/members/admin.py
index aed2fd9..5abb944 100644
--- a/jdav_web/members/admin.py
+++ b/jdav_web/members/admin.py
@@ -1124,15 +1124,6 @@ class FreizeitAdmin(CommonAdminMixin, nested_admin.NestedModelAdmin):
return render_tex(memberlist.name + "_Notizen", 'members/notes_list.tex', context)
notes_list.short_description = _('Generate overview')
- def render_seminar_vbk_options(self, request, memberlist, form):
- context = dict(self.admin_site.each_context(request),
- title=_('Generate LJP V-BK form'),
- opts=self.opts,
- memberlist=memberlist,
- form=form,
- object=memberlist)
- return render(request, 'admin/generate_seminar_vbk.html', context=context)
-
@decorate_download
def download_seminar_vbk(self, request, memberlist):
fp = generate_ljp_vbk(memberlist)
--
2.38.4
From 0edd7df8432239ba987909f04a7b3f9ebb7e769b Mon Sep 17 00:00:00 2001
From: Christian Merten
Date: Sun, 2 Feb 2025 18:37:59 +0100
Subject: [PATCH 05/12] update dockerfiles
---
docker/production/Dockerfile | 4 ++--
docker/test/Dockerfile | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/docker/production/Dockerfile b/docker/production/Dockerfile
index bf51753..47f31d4 100644
--- a/docker/production/Dockerfile
+++ b/docker/production/Dockerfile
@@ -1,7 +1,7 @@
-FROM python:3.9-bullseye
+FROM python:3.9-bookworm
# install additional dependencies
-RUN apt-get update && apt-get install -y gettext texlive texlive-fonts-extra
+RUN apt-get update && apt-get install -y gettext texlive texlive-fonts-extra pandoc
# create user
RUN groupadd -g 501 app && useradd -g 501 -u 501 -m -d /app app
diff --git a/docker/test/Dockerfile b/docker/test/Dockerfile
index a4de64d..3005167 100644
--- a/docker/test/Dockerfile
+++ b/docker/test/Dockerfile
@@ -1,7 +1,7 @@
-FROM python:3.9-bullseye
+FROM python:3.9-bookworm
# install additional dependencies
-RUN apt-get update && apt-get install -y gettext texlive texlive-fonts-extra
+RUN apt-get update && apt-get install -y gettext texlive texlive-fonts-extra pandoc
# create user
RUN groupadd -g 501 app && useradd -g 501 -u 501 -m -d /app app
--
2.38.4
From 4f0e9435e991795d6b2fa6b1cad1f353fc288f60 Mon Sep 17 00:00:00 2001
From: Christian Merten
Date: Wed, 5 Feb 2025 00:23:02 +0100
Subject: [PATCH 06/12] fixes
---
jdav_web/members/templates/members/seminar_report.tex | 2 +-
jdav_web/members/templates/members/seminar_report_docx.tex | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/jdav_web/members/templates/members/seminar_report.tex b/jdav_web/members/templates/members/seminar_report.tex
index f7ffa2c..9098150 100644
--- a/jdav_web/members/templates/members/seminar_report.tex
+++ b/jdav_web/members/templates/members/seminar_report.tex
@@ -59,7 +59,7 @@
{{ settings.SEKTION_TOWN }} \\
Tel.: {{ settings.SEKTION_TELEPHONE }} \\
Fax: {{ settings.SEKTION_TELEFAX }} \\
- {{ settings.SEKTION_CONTACT_MAIL }} \\
+ {{ settings.RESPONSIBLE_MAIL }} \\
\end{flushright}
\end{textblock*}
diff --git a/jdav_web/members/templates/members/seminar_report_docx.tex b/jdav_web/members/templates/members/seminar_report_docx.tex
index d5f666b..ac72022 100644
--- a/jdav_web/members/templates/members/seminar_report_docx.tex
+++ b/jdav_web/members/templates/members/seminar_report_docx.tex
@@ -46,9 +46,9 @@
\end{tabular}
\end{table}
-\section{Zielverfolgung- und Erreichung}
+\section{Zielverfolgung und -Erreichung}
-{{ memberlist.ljpproposal.goals|esc_all }}
+{{ memberlist.ljpproposal.goal_strategy|esc_all }}
\section{Zeitlicher Ablauf}
--
2.38.4
From 582dd81465a9a5251b2b69924c84eaff6b7a46d8 Mon Sep 17 00:00:00 2001
From: Christian Merten
Date: Thu, 6 Feb 2025 00:35:30 +0100
Subject: [PATCH 07/12] add postcode and not bw reason
---
jdav_web/members/admin.py | 4 +-
jdav_web/members/excel.py | 13 +-
.../members/locale/de/LC_MESSAGES/django.po | 117 +++++++++++-------
.../0036_ljpproposal_not_bw_reason.py | 18 +++
...eit_postal_code_alter_ljpproposal_title.py | 23 ++++
..._freizeit_postal_code_freizeit_postcode.py | 22 ++++
jdav_web/members/models.py | 17 ++-
7 files changed, 162 insertions(+), 52 deletions(-)
create mode 100644 jdav_web/members/migrations/0036_ljpproposal_not_bw_reason.py
create mode 100644 jdav_web/members/migrations/0037_freizeit_postal_code_alter_ljpproposal_title.py
create mode 100644 jdav_web/members/migrations/0038_remove_freizeit_postal_code_freizeit_postcode.py
diff --git a/jdav_web/members/admin.py b/jdav_web/members/admin.py
index 5abb944..3dead73 100644
--- a/jdav_web/members/admin.py
+++ b/jdav_web/members/admin.py
@@ -1073,8 +1073,8 @@ class FreizeitAdmin(CommonAdminMixin, nested_admin.NestedModelAdmin):
view_on_site = False
fieldsets = (
(None, {
- 'fields': ('name', 'place', 'destination', 'date', 'end', 'description', 'groups', 'jugendleiter',
- 'approved_extra_youth_leader_count',
+ 'fields': ('name', 'place', 'postcode', 'destination', 'date', 'end', 'description', 'groups',
+ 'jugendleiter', 'approved_extra_youth_leader_count',
'tour_type', 'tour_approach', 'kilometers_traveled', 'activity', 'difficulty'),
'description': _('General information on your excursion. These are partly relevant for the amount of financial compensation (means of transport, travel distance, etc.).')
}),
diff --git a/jdav_web/members/excel.py b/jdav_web/members/excel.py
index 0780652..393e962 100644
--- a/jdav_web/members/excel.py
+++ b/jdav_web/members/excel.py
@@ -75,6 +75,13 @@ VBK_TEMPLATES = {
LJPProposal.LJP_EDUCATIONAL: 'members/LJP_VBK_3-2.xlsx',
}
+NOT_BW_REASONS = {
+ LJPProposal.NOT_BW_CONTENT: 'aufgrund der Lehrgangsinhalte',
+ LJPProposal.NOT_BW_ROOMS: 'trägereigene Räumlichkeiten',
+ LJPProposal.NOT_BW_CLOSE_BORDER: 'Grenznähe',
+ LJPProposal.NOT_BW_ECONOMIC: 'wirtschaftliche Sparsamkeit',
+}
+
def generate_ljp_vbk(excursion):
"""
@@ -87,7 +94,7 @@ def generate_ljp_vbk(excursion):
workbook = openpyxl.load_workbook(path)
sheet = workbook.active
- title = excursion.ljpproposal.title if hasattr(excursion, 'ljpproposal') else excursion.name
+ title = excursion.ljpproposal.title
sheet['I6'] = settings.SEKTION_IBAN
sheet['I8'] = settings.SEKTION_ACCOUNT_HOLDER
@@ -104,7 +111,9 @@ def generate_ljp_vbk(excursion):
sheet['J19'] = f"{excursion.duration}"
sheet['L19'] = f"{excursion.ljp_participant_count}"
sheet['H19'] = excursion.get_ljp_activity_category()
- sheet['M19'] = excursion.place
+ sheet['M19'] = f"{excursion.postcode}, {excursion.place}"
+ sheet['N19'] = f"{NOT_BW_REASONS[excursion.ljpproposal.not_bw_reason]}"\
+ if not excursion.ljpproposal.not_bw_reason is None else ""
if hasattr(excursion, 'statement'):
sheet['Q19'] = f"{excursion.statement.total_theoretic}"
diff --git a/jdav_web/members/locale/de/LC_MESSAGES/django.po b/jdav_web/members/locale/de/LC_MESSAGES/django.po
index f65e3de..c0adc32 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-02-02 18:06+0100\n"
+"POT-Creation-Date: 2025-02-06 00:32+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
@@ -374,25 +374,10 @@ msgstr "Kriseninterventionsliste erstellen"
msgid "Generate overview"
msgstr "Hinweise für Jugendleiter erstellen"
-#: members/admin.py members/templates/admin/generate_seminar_vbk.html
-msgid "Generate LJP V-BK form"
-msgstr "Erzeuge LJP V-BK Formular"
-
#: members/admin.py members/templates/admin/generate_seminar_report.html
msgid "Generate seminar report"
msgstr "Landesjugendplan Antrag erstellen"
-#: members/admin.py members/tests.py
-msgid "Please select a mode."
-msgstr "Bitte wähle einen Modus aus."
-
-#: members/admin.py members/tests.py
-msgid ""
-"Full mode is only available, if the seminar report section is filled out."
-msgstr ""
-"Der vollständiger Modus ist nur verfügbar, wenn der Seminarbericht "
-"ausgefüllt ist. "
-
#: members/admin.py members/templates/admin/generate_sjr_application.html
msgid "Generate SJR application"
msgstr "SJR Antrag erstellen"
@@ -1008,6 +993,34 @@ msgstr ""
"Wie wolltet ihr das Bildungsziel erreichen? Ist das Ziel so erreicht worden? "
"Wenn nicht, warum nicht? Wenn ja, was hat geholfen, das Ziel zu erreichen?"
+#: members/models.py
+msgid "Course content"
+msgstr "aufgrund der Lehrgangsinhalte"
+
+#: members/models.py
+msgid "Available rooms"
+msgstr "trägereigene Räumlichkeiten"
+
+#: members/models.py
+msgid "Close to the border"
+msgstr "Grenznähe"
+
+#: members/models.py
+msgid "Economic reasons"
+msgstr "wirtschaftliche Sparsamkeit"
+
+#: members/models.py
+msgid "Explanation if excursion not in Baden-Württemberg"
+msgstr "Begründung, falls Kursort nicht in Baden-Württemberg"
+
+#: members/models.py
+msgid ""
+"If the excursion takes place outside of Baden-Württemberg, please explain. "
+"Otherwise, leave this empty."
+msgstr ""
+"Falls die Ausfahrt außerhalb von Baden-Württemberg stattfindet, gib bitte "
+"eine Begründung an. Sonst lass dieses Feld frei."
+
#: members/models.py
msgid "LJP Proposal"
msgstr "Seminarbericht"
@@ -1107,7 +1120,6 @@ 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_seminar_vbk.html
#: members/templates/admin/generate_sjr_application.html
#: members/templates/admin/invite_as_user.html
#: members/templates/admin/invite_for_group.html
@@ -1132,7 +1144,6 @@ 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_vbk.html
#: members/templates/admin/generate_sjr_application.html
#: members/templates/admin/invite_as_user.html
#: members/templates/admin/invite_for_group.html
@@ -1425,35 +1436,6 @@ msgstr ""
"Eine Kosten- und Teilnehmendenübersicht. Dies ist nicht notwendig für den "
"eigentlichen Bericht, muss aber langfristig aufbewahrt werden."
-#: members/templates/admin/generate_seminar_vbk.html
-msgid ""
-"Every LJP application needs a V-BK form containing the most important facts "
-"about the seminar.\n"
-"Here you can automatically generate such a form in Excel format."
-msgstr ""
-"Jeder LJP Antrag benötigt ein V-BK Formular, das die wichtigsten Randdaten "
-"des Seminars enthält. Hier kannst du automatisch ein solches Formular im "
-"Excel Format erstellen."
-
-#: members/templates/admin/generate_seminar_vbk.html
-msgid ""
-"Your excursion currently has no cost-plan attached, hence the total costs "
-"can't be automatically\n"
-"calculated and added to the form."
-msgstr ""
-"Deine Ausfahrt hat zur Zeit keinen Kostenplan. Daher können die Gesamtkosten "
-"nicht automatisch berechnet und dem Formular hinzugefügt werden."
-
-#: members/templates/admin/generate_seminar_vbk.html
-msgid ""
-"Depending on the type of seminar, please select one of the two options below."
-msgstr "Bitte wähle aus, um welche Art von Seminar es sich handelt."
-
-#: members/templates/admin/generate_seminar_vbk.html
-#: members/templates/admin/generate_sjr_application.html
-msgid "Generate"
-msgstr "Erstellen"
-
#: members/templates/admin/generate_sjr_application.html members/tests.py
msgid "Here you can generate an allowance application for the SJR."
msgstr "Hier kannst du einen SJR-Zuschussantrag erstellen."
@@ -1471,6 +1453,10 @@ 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/generate_sjr_application.html
+msgid "Generate"
+msgstr "Erstellen"
+
#: members/templates/admin/invite_as_user.html
#, python-format
msgid ""
@@ -2001,6 +1987,17 @@ msgstr ""
"vorausfüllen lassen und dem Antrag hinzufügen. Bitte fülle die verbleibenden "
"Felder im Formblatt selbst aus und unterschreibe das PDF."
+#: members/tests.py
+msgid "Please select a mode."
+msgstr "Bitte wähle einen Modus aus."
+
+#: members/tests.py
+msgid ""
+"Full mode is only available, if the seminar report section is filled out."
+msgstr ""
+"Der vollständiger Modus ist nur verfügbar, wenn der Seminarbericht "
+"ausgefüllt ist. "
+
#: members/tests.py
msgid "This field is required."
msgstr ""
@@ -2043,6 +2040,32 @@ msgstr "Optionale zusätzliche E-Mailadresse"
msgid "Invalid emergency contacts"
msgstr "Ungültige Notfallkontakte"
+#~ msgid "Generate LJP V-BK form"
+#~ msgstr "Erzeuge LJP V-BK Formular"
+
+#~ msgid ""
+#~ "Every LJP application needs a V-BK form containing the most important "
+#~ "facts about the seminar.\n"
+#~ "Here you can automatically generate such a form in Excel format."
+#~ msgstr ""
+#~ "Jeder LJP Antrag benötigt ein V-BK Formular, das die wichtigsten "
+#~ "Randdaten des Seminars enthält. Hier kannst du automatisch ein solches "
+#~ "Formular im Excel Format erstellen."
+
+#~ msgid ""
+#~ "Your excursion currently has no cost-plan attached, hence the total costs "
+#~ "can't be automatically\n"
+#~ "calculated and added to the form."
+#~ msgstr ""
+#~ "Deine Ausfahrt hat zur Zeit keinen Kostenplan. Daher können die "
+#~ "Gesamtkosten nicht automatisch berechnet und dem Formular hinzugefügt "
+#~ "werden."
+
+#~ msgid ""
+#~ "Depending on the type of seminar, please select one of the two options "
+#~ "below."
+#~ msgstr "Bitte wähle aus, um welche Art von Seminar es sich handelt."
+
#~ msgid "Full report"
#~ msgstr "Vollständiger Seminarbericht"
diff --git a/jdav_web/members/migrations/0036_ljpproposal_not_bw_reason.py b/jdav_web/members/migrations/0036_ljpproposal_not_bw_reason.py
new file mode 100644
index 0000000..e4efdfd
--- /dev/null
+++ b/jdav_web/members/migrations/0036_ljpproposal_not_bw_reason.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.0.1 on 2025-02-05 23:18
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('members', '0035_ljpproposal_redo'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='ljpproposal',
+ name='not_bw_reason',
+ field=models.IntegerField(blank=True, choices=[(1, 'Course content'), (2, 'Available rooms'), (3, 'Close to the border'), (4, 'Economic reasons')], default=None, help_text='If the excursion takes place outside of Baden-Württemberg, please explain. Otherwise, leave this empty.', null=True, verbose_name='Explanation if excursion not in Baden-Württemberg'),
+ ),
+ ]
diff --git a/jdav_web/members/migrations/0037_freizeit_postal_code_alter_ljpproposal_title.py b/jdav_web/members/migrations/0037_freizeit_postal_code_alter_ljpproposal_title.py
new file mode 100644
index 0000000..95b741f
--- /dev/null
+++ b/jdav_web/members/migrations/0037_freizeit_postal_code_alter_ljpproposal_title.py
@@ -0,0 +1,23 @@
+# Generated by Django 4.0.1 on 2025-02-05 23:29
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('members', '0036_ljpproposal_not_bw_reason'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='freizeit',
+ name='postal_code',
+ field=models.CharField(default='', max_length=30, verbose_name='Postal code'),
+ ),
+ migrations.AlterField(
+ model_name='ljpproposal',
+ name='title',
+ field=models.CharField(blank=True, default='', help_text='Official title of your seminar, this can differ from the informal title. Use e.g. sports climbing course instead of climbing weekend for fun.', max_length=100, verbose_name='Title'),
+ ),
+ ]
diff --git a/jdav_web/members/migrations/0038_remove_freizeit_postal_code_freizeit_postcode.py b/jdav_web/members/migrations/0038_remove_freizeit_postal_code_freizeit_postcode.py
new file mode 100644
index 0000000..e487458
--- /dev/null
+++ b/jdav_web/members/migrations/0038_remove_freizeit_postal_code_freizeit_postcode.py
@@ -0,0 +1,22 @@
+# Generated by Django 4.0.1 on 2025-02-05 23:31
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('members', '0037_freizeit_postal_code_alter_ljpproposal_title'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='freizeit',
+ name='postal_code',
+ ),
+ migrations.AddField(
+ model_name='freizeit',
+ name='postcode',
+ field=models.CharField(default='', max_length=30, verbose_name='Postcode'),
+ ),
+ ]
diff --git a/jdav_web/members/models.py b/jdav_web/members/models.py
index a7dd713..0d1f99c 100644
--- a/jdav_web/members/models.py
+++ b/jdav_web/members/models.py
@@ -1058,6 +1058,7 @@ class Freizeit(CommonModel):
name = models.CharField(verbose_name=_('Activity'), default='',
max_length=50)
place = models.CharField(verbose_name=_('Place'), default='', max_length=50)
+ postcode = models.CharField(verbose_name=_('Postcode'), default='', max_length=30)
destination = models.CharField(verbose_name=_('Destination (optional)'),
default='', max_length=50, blank=True,
help_text=_('e.g. a peak'))
@@ -1478,7 +1479,7 @@ class RegistrationPassword(models.Model):
class LJPProposal(CommonModel):
"""A proposal for LJP"""
- title = models.CharField(verbose_name=_('Title'), max_length=30,
+ title = models.CharField(verbose_name=_('Title'), max_length=100,
blank=True, default='',
help_text=_('Official title of your seminar, this can differ from the informal title. Use e.g. sports climbing course instead of climbing weekend for fun.'))
@@ -1506,6 +1507,20 @@ class LJPProposal(CommonModel):
help_text=_('How do you want to reach the learning goal? Has the goal been reached? If not, why not? If yes, what helped you to reach the goal?'),
blank=True, default='')
+ NOT_BW_CONTENT, NOT_BW_ROOMS, NOT_BW_CLOSE_BORDER, NOT_BW_ECONOMIC = 1, 2, 3, 4
+ NOT_BW_REASONS = [
+ (NOT_BW_CONTENT, _('Course content')),
+ (NOT_BW_ROOMS, _('Available rooms')),
+ (NOT_BW_CLOSE_BORDER, _('Close to the border')),
+ (NOT_BW_ECONOMIC, _('Economic reasons')),
+ ]
+ not_bw_reason = models.IntegerField(verbose_name=_('Explanation if excursion not in Baden-Württemberg'),
+ choices=NOT_BW_REASONS,
+ default=None,
+ blank=True,
+ null=True,
+ help_text=_('If the excursion takes place outside of Baden-Württemberg, please explain. Otherwise, leave this empty.'))
+
excursion = models.OneToOneField(Freizeit,
verbose_name=_('Excursion'),
blank=True,
--
2.38.4
From 0daafdd5d7e4e02f72fbe43312de18ca5795c50f Mon Sep 17 00:00:00 2001
From: Christian Merten
Date: Thu, 6 Feb 2025 00:51:32 +0100
Subject: [PATCH 08/12] fix
---
jdav_web/members/excel.py | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/jdav_web/members/excel.py b/jdav_web/members/excel.py
index 393e962..3f4c154 100644
--- a/jdav_web/members/excel.py
+++ b/jdav_web/members/excel.py
@@ -82,6 +82,13 @@ NOT_BW_REASONS = {
LJPProposal.NOT_BW_ECONOMIC: 'wirtschaftliche Sparsamkeit',
}
+LJP_GOALS = {
+ LJPProposal.LJP_QUALIFICATION: 'Qualifizierung',
+ LJPProposal.LJP_PARTICIPATION: 'Partizipation',
+ LJPProposal.LJP_DEVELOPMENT: 'Persönlichkeitsentwicklung',
+ LJPProposal.LJP_ENVIRONMENT: 'Umwelt',
+}
+
def generate_ljp_vbk(excursion):
"""
@@ -105,10 +112,11 @@ def generate_ljp_vbk(excursion):
sheet['B7'] = settings.RESPONSIBLE_MAIL
sheet['B36'] = f"{settings.SEKTION}, {datetime.today():%d.%m.%Y}"
sheet['F19'] = f"B {excursion.date:%y}-{excursion.pk}"
+ sheet['C19'] = LJP_GOALS[excursion.ljpproposal.goal] if excursion.ljpproposal.goal in LJP_GOALS else ""
sheet['D19'] = settings.SEKTION
sheet['G19'] = title
sheet['I19'] = f"von {excursion.date:%d.%m.%y} bis {excursion.end:%d.%m.%y}"
- sheet['J19'] = f"{excursion.duration}"
+ sheet['J19'] = excursion.duration
sheet['L19'] = f"{excursion.ljp_participant_count}"
sheet['H19'] = excursion.get_ljp_activity_category()
sheet['M19'] = f"{excursion.postcode}, {excursion.place}"
--
2.38.4
From 7f3fa1c1bb7b573c64e2e7d14e59e1ac80f87fe0 Mon Sep 17 00:00:00 2001
From: Christian Merten
Date: Thu, 6 Feb 2025 22:19:16 +0100
Subject: [PATCH 09/12] squash migrations
---
.../migrations/0035_ljp_application_rework.py | 70 +++++++++++++++++++
1 file changed, 70 insertions(+)
create mode 100644 jdav_web/members/migrations/0035_ljp_application_rework.py
diff --git a/jdav_web/members/migrations/0035_ljp_application_rework.py b/jdav_web/members/migrations/0035_ljp_application_rework.py
new file mode 100644
index 0000000..89818d7
--- /dev/null
+++ b/jdav_web/members/migrations/0035_ljp_application_rework.py
@@ -0,0 +1,70 @@
+# Generated by Django 4.0.1 on 2025-02-06 21:17
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ replaces = [('members', '0035_ljpproposal_redo'), ('members', '0036_ljpproposal_not_bw_reason'), ('members', '0037_freizeit_postal_code_alter_ljpproposal_title'), ('members', '0038_remove_freizeit_postal_code_freizeit_postcode')]
+
+ dependencies = [
+ ('members', '0034_activitycategory_ljp_category'),
+ ]
+
+ operations = [
+ migrations.RemoveField(
+ model_name='ljpproposal',
+ name='evaluation',
+ ),
+ migrations.RemoveField(
+ model_name='ljpproposal',
+ name='experiences',
+ ),
+ migrations.RemoveField(
+ model_name='ljpproposal',
+ name='goals_alpinistic',
+ ),
+ migrations.RemoveField(
+ model_name='ljpproposal',
+ name='goals_pedagogic',
+ ),
+ migrations.RemoveField(
+ model_name='ljpproposal',
+ name='methods',
+ ),
+ migrations.AddField(
+ model_name='ljpproposal',
+ name='goal',
+ field=models.IntegerField(choices=[(1, 'Qualification'), (2, 'Participation'), (3, 'Personality development'), (4, 'Environment')], default=1, help_text='Official learning goal according to LJP regulations.', verbose_name='Learning goal'),
+ ),
+ migrations.AddField(
+ model_name='ljpproposal',
+ name='goal_strategy',
+ field=models.TextField(blank=True, default='', help_text='How do you want to reach the learning goal? Has the goal been reached? If not, why not? If yes, what helped you to reach the goal?', verbose_name='Strategy'),
+ ),
+ migrations.AlterField(
+ model_name='ljpproposal',
+ name='title',
+ field=models.CharField(blank=True, default='', help_text='Official title of your seminar, this can differ from the informal title. Use e.g. sports climbing course instead of climbing weekend for fun.', max_length=30, verbose_name='Title'),
+ ),
+ migrations.AddField(
+ model_name='ljpproposal',
+ name='category',
+ field=models.IntegerField(choices=[(2, 'Educational programme'), (1, 'Staff training')], default=2, help_text='Type of seminar. Usually the correct choice is educational programme.', verbose_name='Category'),
+ ),
+ migrations.AddField(
+ model_name='ljpproposal',
+ name='not_bw_reason',
+ field=models.IntegerField(blank=True, choices=[(1, 'Course content'), (2, 'Available rooms'), (3, 'Close to the border'), (4, 'Economic reasons')], default=None, help_text='If the excursion takes place outside of Baden-Württemberg, please explain. Otherwise, leave this empty.', null=True, verbose_name='Explanation if excursion not in Baden-Württemberg'),
+ ),
+ migrations.AlterField(
+ model_name='ljpproposal',
+ name='title',
+ field=models.CharField(blank=True, default='', help_text='Official title of your seminar, this can differ from the informal title. Use e.g. sports climbing course instead of climbing weekend for fun.', max_length=100, verbose_name='Title'),
+ ),
+ migrations.AddField(
+ model_name='freizeit',
+ name='postcode',
+ field=models.CharField(default='', max_length=30, verbose_name='Postcode'),
+ ),
+ ]
--
2.38.4
From a9bd5d59d66c47f509f550156a761bc740b2c6cc Mon Sep 17 00:00:00 2001
From: Christian Merten
Date: Thu, 6 Feb 2025 22:22:44 +0100
Subject: [PATCH 10/12] remove old migrations
---
.../migrations/0035_ljp_application_rework.py | 2 -
.../migrations/0035_ljpproposal_redo.py | 53 -------------------
.../0036_ljpproposal_not_bw_reason.py | 18 -------
...eit_postal_code_alter_ljpproposal_title.py | 23 --------
..._freizeit_postal_code_freizeit_postcode.py | 22 --------
5 files changed, 118 deletions(-)
delete mode 100644 jdav_web/members/migrations/0035_ljpproposal_redo.py
delete mode 100644 jdav_web/members/migrations/0036_ljpproposal_not_bw_reason.py
delete mode 100644 jdav_web/members/migrations/0037_freizeit_postal_code_alter_ljpproposal_title.py
delete mode 100644 jdav_web/members/migrations/0038_remove_freizeit_postal_code_freizeit_postcode.py
diff --git a/jdav_web/members/migrations/0035_ljp_application_rework.py b/jdav_web/members/migrations/0035_ljp_application_rework.py
index 89818d7..7a6037c 100644
--- a/jdav_web/members/migrations/0035_ljp_application_rework.py
+++ b/jdav_web/members/migrations/0035_ljp_application_rework.py
@@ -5,8 +5,6 @@ from django.db import migrations, models
class Migration(migrations.Migration):
- replaces = [('members', '0035_ljpproposal_redo'), ('members', '0036_ljpproposal_not_bw_reason'), ('members', '0037_freizeit_postal_code_alter_ljpproposal_title'), ('members', '0038_remove_freizeit_postal_code_freizeit_postcode')]
-
dependencies = [
('members', '0034_activitycategory_ljp_category'),
]
diff --git a/jdav_web/members/migrations/0035_ljpproposal_redo.py b/jdav_web/members/migrations/0035_ljpproposal_redo.py
deleted file mode 100644
index ffb6e2e..0000000
--- a/jdav_web/members/migrations/0035_ljpproposal_redo.py
+++ /dev/null
@@ -1,53 +0,0 @@
-# Generated by Django 4.0.1 on 2025-02-02 17:08
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('members', '0034_activitycategory_ljp_category'),
- ]
-
- operations = [
- migrations.RemoveField(
- model_name='ljpproposal',
- name='evaluation',
- ),
- migrations.RemoveField(
- model_name='ljpproposal',
- name='experiences',
- ),
- migrations.RemoveField(
- model_name='ljpproposal',
- name='goals_alpinistic',
- ),
- migrations.RemoveField(
- model_name='ljpproposal',
- name='goals_pedagogic',
- ),
- migrations.RemoveField(
- model_name='ljpproposal',
- name='methods',
- ),
- migrations.AddField(
- model_name='ljpproposal',
- name='goal',
- field=models.IntegerField(choices=[(1, 'Qualification'), (2, 'Participation'), (3, 'Personality development'), (4, 'Environment')], default=1, help_text='Official learning goal according to LJP regulations.', verbose_name='Learning goal'),
- ),
- migrations.AddField(
- model_name='ljpproposal',
- name='goal_strategy',
- field=models.TextField(blank=True, default='', help_text='How do you want to reach the learning goal? Has the goal been reached? If not, why not? If yes, what helped you to reach the goal?', verbose_name='Strategy'),
- ),
- migrations.AlterField(
- model_name='ljpproposal',
- name='title',
- field=models.CharField(blank=True, default='', help_text='Official title of your seminar, this can differ from the informal title. Use e.g. sports climbing course instead of climbing weekend for fun.', max_length=30, verbose_name='Title'),
- ),
- migrations.AddField(
- model_name='ljpproposal',
- name='category',
- field=models.IntegerField(choices=[(2, 'Educational programme'), (1, 'Staff training')], default=2, help_text='Type of seminar. Usually the correct choice is educational programme.', verbose_name='Category'),
- ),
- ]
diff --git a/jdav_web/members/migrations/0036_ljpproposal_not_bw_reason.py b/jdav_web/members/migrations/0036_ljpproposal_not_bw_reason.py
deleted file mode 100644
index e4efdfd..0000000
--- a/jdav_web/members/migrations/0036_ljpproposal_not_bw_reason.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# Generated by Django 4.0.1 on 2025-02-05 23:18
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('members', '0035_ljpproposal_redo'),
- ]
-
- operations = [
- migrations.AddField(
- model_name='ljpproposal',
- name='not_bw_reason',
- field=models.IntegerField(blank=True, choices=[(1, 'Course content'), (2, 'Available rooms'), (3, 'Close to the border'), (4, 'Economic reasons')], default=None, help_text='If the excursion takes place outside of Baden-Württemberg, please explain. Otherwise, leave this empty.', null=True, verbose_name='Explanation if excursion not in Baden-Württemberg'),
- ),
- ]
diff --git a/jdav_web/members/migrations/0037_freizeit_postal_code_alter_ljpproposal_title.py b/jdav_web/members/migrations/0037_freizeit_postal_code_alter_ljpproposal_title.py
deleted file mode 100644
index 95b741f..0000000
--- a/jdav_web/members/migrations/0037_freizeit_postal_code_alter_ljpproposal_title.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# Generated by Django 4.0.1 on 2025-02-05 23:29
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('members', '0036_ljpproposal_not_bw_reason'),
- ]
-
- operations = [
- migrations.AddField(
- model_name='freizeit',
- name='postal_code',
- field=models.CharField(default='', max_length=30, verbose_name='Postal code'),
- ),
- migrations.AlterField(
- model_name='ljpproposal',
- name='title',
- field=models.CharField(blank=True, default='', help_text='Official title of your seminar, this can differ from the informal title. Use e.g. sports climbing course instead of climbing weekend for fun.', max_length=100, verbose_name='Title'),
- ),
- ]
diff --git a/jdav_web/members/migrations/0038_remove_freizeit_postal_code_freizeit_postcode.py b/jdav_web/members/migrations/0038_remove_freizeit_postal_code_freizeit_postcode.py
deleted file mode 100644
index e487458..0000000
--- a/jdav_web/members/migrations/0038_remove_freizeit_postal_code_freizeit_postcode.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# Generated by Django 4.0.1 on 2025-02-05 23:31
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- dependencies = [
- ('members', '0037_freizeit_postal_code_alter_ljpproposal_title'),
- ]
-
- operations = [
- migrations.RemoveField(
- model_name='freizeit',
- name='postal_code',
- ),
- migrations.AddField(
- model_name='freizeit',
- name='postcode',
- field=models.CharField(default='', max_length=30, verbose_name='Postcode'),
- ),
- ]
--
2.38.4
From e0f20c9ca160b19ea7562f67866dbe33289b027f Mon Sep 17 00:00:00 2001
From: Christian Merten
Date: Thu, 6 Feb 2025 22:25:22 +0100
Subject: [PATCH 11/12] revert
---
jdav_web/locale/de/LC_MESSAGES/django.po | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/jdav_web/locale/de/LC_MESSAGES/django.po b/jdav_web/locale/de/LC_MESSAGES/django.po
index 4005714..cafea14 100644
--- a/jdav_web/locale/de/LC_MESSAGES/django.po
+++ b/jdav_web/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-02-02 18:06+0100\n"
+"POT-Creation-Date: 2025-02-01 14:54+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
--
2.38.4
From 48f1bde59dfdd458f75263f11440a593e5fe079a Mon Sep 17 00:00:00 2001
From: Christian Merten
Date: Fri, 7 Feb 2025 22:00:08 +0100
Subject: [PATCH 12/12] adapt tests
---
jdav_web/members/tests.py | 61 ++++++++++++++++++++++++++++++---------
1 file changed, 47 insertions(+), 14 deletions(-)
diff --git a/jdav_web/members/tests.py b/jdav_web/members/tests.py
index 8966cb5..7e4b3b3 100644
--- a/jdav_web/members/tests.py
+++ b/jdav_web/members/tests.py
@@ -17,7 +17,7 @@ from unittest import skip, mock
from .models import Member, Group, PermissionMember, PermissionGroup, Freizeit, GEMEINSCHAFTS_TOUR, MUSKELKRAFT_ANREISE,\
MemberNoteList, NewMemberOnList, confirm_mail_by_key, EmergencyContact, MemberWaitingList,\
RegistrationPassword, MemberUnconfirmedProxy, InvitationToGroup, DIVERSE, MALE, FEMALE,\
- Klettertreff, KlettertreffAttendee
+ Klettertreff, KlettertreffAttendee, LJPProposal
from .admin import MemberWaitingListAdmin, MemberAdmin, FreizeitAdmin, MemberNoteListAdmin,\
MemberUnconfirmedAdmin, RegistrationFilter, FilteredMemberFieldMixin,\
MemberAdminForm, StatementOnListForm, KlettertreffAdmin, GroupAdmin
@@ -671,6 +671,16 @@ class FreizeitAdminTestCase(AdminTestCase, PDFActionMixin):
self.bill = Bill.objects.create(statement=self.st, short_description='bla', explanation='bli',
amount=42.69, costs_covered=True, paid_by=fr,
proof=file)
+ self.ex2 = Freizeit.objects.create(name='Wild trip 2', kilometers_traveled=0,
+ tour_type=GEMEINSCHAFTS_TOUR,
+ tour_approach=MUSKELKRAFT_ANREISE,
+ difficulty=1)
+ self.ljpproposal = LJPProposal.objects.create(title='My seminar',
+ category=LJPProposal.LJP_STAFF_TRAINING,
+ goal=LJPProposal.LJP_ENVIRONMENT,
+ goal_strategy='my strategy',
+ not_bw_reason=LJPProposal.NOT_BW_ROOMS,
+ excursion=self.ex2)
def test_changelist(self):
c = self._login('superuser')
@@ -746,27 +756,50 @@ class FreizeitAdminTestCase(AdminTestCase, PDFActionMixin):
c = self._login('superuser')
url = reverse('admin:members_freizeit_action', args=(self.ex.pk,))
- response = c.post(url, data={'seminar_report': ''})
+ response = c.post(url, data={'seminar_report': ''}, follow=True)
self.assertEqual(response.status_code, HTTPStatus.OK)
- self.assertContains(response, _('You may also choose to include the V32 attachment.'))
+ self.assertContains(response,
+ _('This excursion does not have a LJP proposal. Please add one and try again.'))
+ url = reverse('admin:members_freizeit_action', args=(self.ex2.pk,))
response = c.post(url, data={'seminar_report': '', 'apply': ''})
self.assertEqual(response.status_code, HTTPStatus.OK)
- self.assertContains(response, _('Please select a mode.'))
+ self.assertContains(response, _('A seminar report consists of multiple components:'))
+
+ def test_invalid_download(self):
+ url = reverse('admin:members_freizeit_download_ljp_vbk', args=(self.ex.pk,))
+ c = self._login('standard')
+ response = c.get(url, follow=True)
+ self.assertEqual(response.status_code, HTTPStatus.OK)
+ self.assertContains(response, _("You are not allowed to view all members on excursion %(name)s.") % {'name': self.ex.name})
- response = c.post(url, data={'seminar_report': '',
- 'apply': '',
- 'mode': 'full',
- 'prepend_v32': 'true'})
+ c = self._login('superuser')
+ response = c.get(url, follow=True)
+ self.assertEqual(response.status_code, HTTPStatus.OK)
+ self.assertContains(response, _('This excursion does not have a LJP proposal. Please add one and try again.'))
+
+ url = reverse('admin:members_freizeit_download_ljp_vbk', args=(123456789,))
+ response = c.get(url, follow=True)
self.assertEqual(response.status_code, HTTPStatus.OK)
- self.assertContains(response, _('Full mode is only available, if the seminar report section is filled out.'))
+ self.assertContains(response, _('Excursion not found.'))
- response = c.post(url, data={'seminar_report': '',
- 'apply': '',
- 'mode': 'basic',
- 'prepend_v32': 'true'})
+ def test_download_seminar_vbk(self):
+ url = reverse('admin:members_freizeit_download_ljp_vbk', args=(self.ex2.pk,))
+ c = self._login('superuser')
+ response = c.get(url)
+ self.assertEqual(response.status_code, HTTPStatus.OK)
+
+ def test_download_seminar_report_docx(self):
+ url = reverse('admin:members_freizeit_download_ljp_report_docx', args=(self.ex2.pk,))
+ c = self._login('superuser')
+ response = c.get(url)
+ self.assertEqual(response.status_code, HTTPStatus.OK)
+
+ def test_download_seminar_report_costs_and_participants(self):
+ url = reverse('admin:members_freizeit_download_ljp_costs_participants', args=(self.ex2.pk,))
+ c = self._login('superuser')
+ response = c.get(url)
self.assertEqual(response.status_code, HTTPStatus.OK)
- print(mocked_fun.call_count)
@mock.patch('members.pdf.fill_pdf_form')
def test_sjr_application_post(self, mocked_fun):
--
2.38.4