From 284f0b2420050f4b45e1dfb7f07823033e8d7ae4 Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Sun, 24 Nov 2024 20:09:34 +0100 Subject: [PATCH 01/56] members: make email field in emergency contact optional --- .../0026_alter_emergencycontact_email.py | 18 ++++++++++++++++++ jdav_web/members/models.py | 1 + .../members/crisis_intervention_list.tex | 3 +-- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 jdav_web/members/migrations/0026_alter_emergencycontact_email.py diff --git a/jdav_web/members/migrations/0026_alter_emergencycontact_email.py b/jdav_web/members/migrations/0026_alter_emergencycontact_email.py new file mode 100644 index 0000000..3adfa23 --- /dev/null +++ b/jdav_web/members/migrations/0026_alter_emergencycontact_email.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.1 on 2024-11-24 19:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('members', '0025_alter_member_options'), + ] + + operations = [ + migrations.AlterField( + model_name='emergencycontact', + name='email', + field=models.EmailField(blank=True, default='', max_length=100), + ), + ] diff --git a/jdav_web/members/models.py b/jdav_web/members/models.py index 92cf9fb..f85cb3a 100644 --- a/jdav_web/members/models.py +++ b/jdav_web/members/models.py @@ -681,6 +681,7 @@ class EmergencyContact(ContactWithPhoneNumber): Emergency contact of a member """ member = models.ForeignKey(Member, verbose_name=_('Member'), on_delete=models.CASCADE) + email = models.EmailField(max_length=100, default='', blank=True) def __str__(self): return str(self.member) diff --git a/jdav_web/members/templates/members/crisis_intervention_list.tex b/jdav_web/members/templates/members/crisis_intervention_list.tex index 2481209..5dfd6d9 100644 --- a/jdav_web/members/templates/members/crisis_intervention_list.tex +++ b/jdav_web/members/templates/members/crisis_intervention_list.tex @@ -89,8 +89,7 @@ {{ m.member.contact_phone_number|esc_all }} & {% for c in m.member.emergencycontact_set.all %} {{ c.name }} \newline - Tel.: {{ c.phone_number }} \newline - Email: \href{mailto:{{ c.email }}}{ {{c.email}}} + Tel.: {{ c.phone_number }} {% endfor %} \\ {% endfor %} \bottomrule From 1f75d627e08f3c9e80240f4049535c30b83f44f3 Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Sun, 24 Nov 2024 20:14:32 +0100 Subject: [PATCH 02/56] members: skip empty email addresses when requesting confirmation --- jdav_web/members/models.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jdav_web/members/models.py b/jdav_web/members/models.py index f85cb3a..4775e38 100644 --- a/jdav_web/members/models.py +++ b/jdav_web/members/models.py @@ -130,6 +130,8 @@ class Contact(CommonModel): for email_fd, confirmed_email_fd, confirm_mail_key_fd in self.email_fields: if getattr(self, confirmed_email_fd) and not rerequest: continue + if not getattr(self, email_fd): + continue requested_confirmation = True setattr(self, confirmed_email_fd, False) confirm_mail_key = uuid.uuid4().hex From 90f4ac88fc2f8da38758cd3a1707da29cd296cee Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Sun, 24 Nov 2024 20:45:06 +0100 Subject: [PATCH 03/56] members: make email field not required for emergency contacts in forms --- jdav_web/members/templates/members/member_form.html | 4 +++- jdav_web/members/views.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/jdav_web/members/templates/members/member_form.html b/jdav_web/members/templates/members/member_form.html index f0664d3..6969e50 100644 --- a/jdav_web/members/templates/members/member_form.html +++ b/jdav_web/members/templates/members/member_form.html @@ -47,7 +47,9 @@ function addRequired(element) { var inputs = element.getElementsByTagName('input'); for (var i = 0; i < inputs.length; i++) { - inputs[i].setAttribute('required', 'required'); + if (inputs[i].getAttribute('type') != 'email') { + inputs[i].setAttribute('required', 'required'); + } } } function removeRequired(element) { diff --git a/jdav_web/members/views.py b/jdav_web/members/views.py index b96e130..0bb9cdc 100644 --- a/jdav_web/members/views.py +++ b/jdav_web/members/views.py @@ -72,7 +72,7 @@ class EmergencyContactForm(ModelForm): class Meta: model = EmergencyContact fields = ['prename', 'lastname', 'email', 'phone_number'] - required = ['prename', 'lastname', 'email', 'phone_number'] + required = ['prename', 'lastname', 'phone_number'] class BaseEmergencyContactsFormSet(BaseInlineFormSet): From 3087b8f8ee45b8564f876c6915ef0101134d3fda Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Sun, 24 Nov 2024 22:26:48 +0100 Subject: [PATCH 04/56] members/admin: add help texts to excursion --- jdav_web/locale/de/LC_MESSAGES/django.po | 44 ++- jdav_web/members/admin.py | 10 + .../members/locale/de/LC_MESSAGES/django.po | 344 ++++++++++-------- .../templates/admin/edit_inline/stacked.html | 1 + .../templates/admin/edit_inline/tabular.html | 78 ++++ .../nesting/admin/inlines/stacked.html | 95 +++++ 6 files changed, 413 insertions(+), 159 deletions(-) create mode 100644 jdav_web/templates/admin/edit_inline/stacked.html create mode 100644 jdav_web/templates/admin/edit_inline/tabular.html create mode 100644 jdav_web/templates/nesting/admin/inlines/stacked.html diff --git a/jdav_web/locale/de/LC_MESSAGES/django.po b/jdav_web/locale/de/LC_MESSAGES/django.po index 27b06a5..0517c44 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: 2024-11-24 18:18+0100\n" +"POT-Creation-Date: 2024-11-24 22:24+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -142,9 +142,9 @@ msgid "" "related objects, but your account doesn't have permission to delete the " "following types of objects:" msgstr "" -"Löschen von %(object_name)s '%(escaped_object)s' würde zur Löschung der folgenden " -"verknüpften Objekte führen, aber du hast nicht die Berechtigung die folgenden Typen " -"von Objekten zu löschen:" +"Löschen von %(object_name)s '%(escaped_object)s' würde zur Löschung der " +"folgenden verknüpften Objekte führen, aber du hast nicht die Berechtigung " +"die folgenden Typen von Objekten zu löschen:" #: templates/admin/delete_confirmation.html:12 #, python-format @@ -152,16 +152,16 @@ msgid "" "Deleting the %(object_name)s '%(escaped_object)s' would require deleting the " "following protected related objects:" msgstr "" -"Löschen von %(object_name)s '%(escaped_object)s' würde zur Löschung der folgenden " -"geschützten verknüpften Objekte führen:" +"Löschen von %(object_name)s '%(escaped_object)s' würde zur Löschung der " +"folgenden geschützten verknüpften Objekte führen:" #: templates/admin/delete_confirmation.html:17 #, python-format msgid "" "Are you sure you want to delete the %(object_name)s \"%(escaped_object)s\"?" msgstr "" -"Bist du sicher, dass du %(object_name)s \"%(escaped_object)s\" und alle davon abhängigen " -"Objekte löschen möchtest? " +"Bist du sicher, dass du %(object_name)s \"%(escaped_object)s\" und alle " +"davon abhängigen Objekte löschen möchtest? " #: templates/admin/delete_confirmation.html:29 #: templates/admin/delete_selected_confirmation.html:34 @@ -181,8 +181,8 @@ msgid "" "types of objects:" msgstr "" "Löschen der ausgewählten %(objects_name)s würde zur Löschung der folgenden " -"verknüpften Objekte führen, aber du hast nicht die Berechtigung die folgenden Typen " -"von Objekten zu löschen:" +"verknüpften Objekte führen, aber du hast nicht die Berechtigung die " +"folgenden Typen von Objekten zu löschen:" #: templates/admin/delete_selected_confirmation.html:9 #, python-format @@ -210,6 +210,25 @@ msgstr "Zusammenfassung" msgid "Objects" msgstr "Objekte" +#: templates/admin/edit_inline/tabular.html:33 +msgid "Delete?" +msgstr "Löschen?" + +#: templates/admin/edit_inline/tabular.html:47 +#: templates/nesting/admin/inlines/stacked.html:42 +msgid "Change" +msgstr "Ändern" + +#: templates/admin/edit_inline/tabular.html:47 +#: templates/nesting/admin/inlines/stacked.html:42 +msgid "View" +msgstr "Anzeigen" + +#: templates/admin/edit_inline/tabular.html:49 +#: templates/nesting/admin/inlines/stacked.html:44 +msgid "View on site" +msgstr "Auf der Website anzeigen" + #: templates/admin/finance/statementconfirmed/change_form_object_tools.html:8 msgid "Unconfirm" msgstr "Bestätigung zurücknehmen" @@ -255,6 +274,11 @@ msgstr "Als Kompassbenutzer:in einladen" msgid "Invite to group" msgstr "Zu Gruppe einladen" +#: templates/nesting/admin/inlines/stacked.html:87 +#, python-format +msgid "Add another %(verbose_name)s" +msgstr "Weiteren %(verbose_name)s hinzufügen" + #: utils.py:14 msgid "Please keep filesize under {} MiB. Current filesize: {:10.2f} MiB." msgstr "Maximale Dateigröße {} MiB. Aktuelle Dateigröße: {:10.2f} MiB." diff --git a/jdav_web/members/admin.py b/jdav_web/members/admin.py index eacf19f..9da53d4 100644 --- a/jdav_web/members/admin.py +++ b/jdav_web/members/admin.py @@ -681,6 +681,7 @@ class BillOnExcursionInline(CommonAdminInlineMixin, admin.TabularInline): class StatementOnListInline(CommonAdminInlineMixin, nested_admin.NestedStackedInline): model = Statement extra = 1 + description = _('Please list here all expenses in relation with this excursion and upload relevant bills. These have to be permanently stored for the application of LJP contributions. The short descriptions are used in the seminar report cost overview (possible descriptions are e.g. food, material, etc.).') sortable_options = [] fields = ['night_cost'] inlines = [BillOnExcursionInline] @@ -698,6 +699,7 @@ class InterventionOnLJPInline(CommonAdminInlineMixin, admin.TabularInline): class LJPOnListInline(CommonAdminInlineMixin, nested_admin.NestedStackedInline): model = LJPProposal extra = 1 + description = _('Here you can work on a seminar report for applying for financial contributions from Landesjugendplan (LJP). More information on creating a seminar report can be found in the wiki. The seminar report or only a participant list and cost overview can be consequently downloaded.') sortable_options = [] inlines = [InterventionOnLJPInline] @@ -705,6 +707,7 @@ class LJPOnListInline(CommonAdminInlineMixin, nested_admin.NestedStackedInline): class MemberOnListInline(CommonAdminInlineMixin, GenericTabularInline): model = NewMemberOnList extra = 0 + description = _('Please list all participants (also youth leaders) of this excursion. Here you can still make changes just before departure and hence generate the latest participant list for crisis intervention at all times.') formfield_overrides = { TextField: {'widget': Textarea(attrs={'rows': 1, 'cols': 40})} } @@ -776,6 +779,13 @@ class FreizeitAdmin(CommonAdminMixin, nested_admin.NestedModelAdmin): search_fields = ('name',) ordering = ('-date',) view_on_site = False + fieldsets = ( + (None, { + 'fields': ('name', 'place', 'destination', 'date', 'end', 'description', 'groups', 'jugendleiter', + '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.).') + }), + ) #formfield_overrides = { # ManyToManyField: {'widget': forms.CheckboxSelectMultiple}, # ForeignKey: {'widget': apply_select2(forms.Select)} diff --git a/jdav_web/members/locale/de/LC_MESSAGES/django.po b/jdav_web/members/locale/de/LC_MESSAGES/django.po index 5e81b32..eb91978 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: 2024-11-24 02:47+0100\n" +"POT-Creation-Date: 2024-11-24 22:24+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,7 +18,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: members/admin.py:126 members/models.py:371 +#: members/admin.py:126 members/models.py:373 msgid "Registration complete" msgstr "Anmeldung vollständig" @@ -109,7 +109,7 @@ msgstr "" msgid "activity" msgstr "Aktivität" -#: members/admin.py:373 members/models.py:53 members/models.py:1379 +#: members/admin.py:373 members/models.py:53 members/models.py:1390 msgid "Name" msgstr "Name" @@ -155,8 +155,8 @@ msgstr "%(name)s zurück auf die Warteliste gesetzt." msgid "Demote selected registrations to waiters." msgstr "Ausgewählte Registrierungen zurück auf die Warteliste setzen." -#: members/admin.py:496 members/models.py:378 members/models.py:718 -#: members/models.py:1124 +#: members/admin.py:496 members/models.py:380 members/models.py:729 +#: members/models.py:1135 msgid "Group" msgstr "Gruppe" @@ -189,73 +189,119 @@ msgstr "Wähle Gruppe für Einladung aus" msgid "Offer waiter a place in a group." msgstr "Personen auf der Warteliste einen Gruppenplatz anbieten." -#: members/admin.py:651 +#: members/admin.py:652 msgid "Difficulty" msgstr "Schwierigkeit" -#: members/admin.py:654 +#: members/admin.py:655 msgid "Tour type" msgstr "Art der Tour" -#: members/admin.py:657 members/models.py:934 +#: members/admin.py:658 members/models.py:945 msgid "Means of transportation" msgstr "Verkehrsmittel" -#: members/admin.py:752 +#: members/admin.py:684 +msgid "" +"Please list here all expenses in relation with this excursion and upload " +"relevant bills. These have to be permanently stored for the application of " +"LJP contributions. The short descriptions are used in the seminar report " +"cost overview (possible descriptions are e.g. food, material, etc.)." +msgstr "" +"Gib hier bitte alle deine Ausgaben in Zusammenhang mit der Ausfahrt an und " +"lade entsprechende Belege/Quittungen hoch. Diese müssen für die Beantragung " +"von LJP-Zuschüssen langfristig aufbewahrt werden. Die Kurzbeschreibung der " +"einzelnen Posten wird dabei auf der LJP-Kostenübersicht angezeigt (sinnvoll " +"wären z.B. Anreise, Verpflegung, Material etc.)." + +#: members/admin.py:702 +msgid "" +"Here you can work on a seminar report for applying for financial " +"contributions from Landesjugendplan (LJP). More information on creating a " +"seminar report can be found in the wiki. The seminar report or only a " +"participant list and cost overview can be consequently downloaded." +msgstr "" +"Hier kannst du an einem Seminarbericht für die Beantragung von Zuschüssen " +"des Landesjugendplans (LJP) arbeiten. Weitere Informationen zur Gestaltung " +"von Seminarberichten findest du im JL-Wiki. Den Seminarbericht oder " +"wahlweise nur TN-Liste und Kostenübersicht kannst du anschließend " +"herunterladen." + +#: members/admin.py:710 +msgid "" +"Please list all participants (also youth leaders) of this excursion. Here " +"you can still make changes just before departure and hence generate the " +"latest participant list for crisis intervention at all times." +msgstr "" +"Gib hier bitte alle Personen an, die bei der Ausfahrt dabei sind (auch JL). " +"Hier kannst du auch spontan kurz vor Abfahrt noch Änderungen machen und so " +"jederzeit die aktuelle Teilnehmer:innenliste für die Krisenintervention " +"generieren." + +#: members/admin.py:756 #, python-format msgid "You are not allowed to view all members on note list %(name)s." msgstr "" "Du hast nicht die nötigen Rechte um alle Teilnehmer:innen der Notizliste " "%(name)s anzusehen." -#: members/admin.py:762 +#: members/admin.py:766 msgid "Generate PDF summary" msgstr "Übersicht erstellen" -#: members/admin.py:766 +#: members/admin.py:770 msgid "Full report" msgstr "Vollständiger Seminarbericht" -#: members/admin.py:767 +#: members/admin.py:771 msgid "Costs and participants only" msgstr "Nur Kosten und Teilnehmende" -#: members/admin.py:768 +#: members/admin.py:772 msgid "Mode" msgstr "Modus" -#: members/admin.py:805 +#: members/admin.py:786 +msgid "" +"General information on your excursion. These are partly relevant for the " +"amount of financial compensation (means of transport, travel distance, etc.)." +msgstr "" +"Hier kannst du allgemein Angaben zu deiner Ausfahrt machen. Diese sind " +"teilweise relevant für die Zuschüsse aus dem Jugendetat (Verkehrsmittel, " +"Fahrstrecke in km)." + +#: members/admin.py:816 #, python-format msgid "You are not allowed to view all members on excursion %(name)s." msgstr "" "Du hast nicht die nötigen Rechte um alle Teilnehmer:innen der Ausfahrt " "%(name)s anzusehen." -#: members/admin.py:813 +#: members/admin.py:824 msgid "Generate crisis intervention list" msgstr "Kriseninterventionsliste erstellen" -#: members/admin.py:821 +#: members/admin.py:832 msgid "Generate overview" msgstr "Hinweise für Jugendleiter erstellen" -#: members/admin.py:825 members/admin.py:848 +#: members/admin.py:836 members/admin.py:859 #: members/templates/admin/generate_seminar_report.html:21 msgid "Generate seminar report" msgstr "Seminarbericht erstellen" -#: members/admin.py:838 +#: members/admin.py:849 msgid "Please select a mode." msgstr "Bitte wähle einen Modus aus." -#: members/admin.py:842 +#: members/admin.py:853 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:860 +#: members/admin.py:871 msgid "Generate SJR application" msgstr "SJR Antrag erstellen" @@ -291,11 +337,11 @@ msgstr "Samstag" msgid "Sunday" msgstr "Sonntag" -#: members/models.py:54 members/models.py:920 +#: members/models.py:54 members/models.py:931 msgid "Description" msgstr "Beschreibung" -#: members/models.py:60 members/models.py:912 +#: members/models.py:60 members/models.py:923 #: members/templates/members/change_member.html:18 msgid "Activity" msgstr "Aktivität" @@ -328,7 +374,7 @@ msgstr "Bis Jahrgang" msgid "youth leaders" msgstr "Jugendleiter" -#: members/models.py:77 members/models.py:1206 +#: members/models.py:77 members/models.py:1217 msgid "Starting time" msgstr "Zeitpunkt" @@ -336,7 +382,7 @@ msgstr "Zeitpunkt" msgid "Ending time" msgstr "Endzeitpunkt" -#: members/models.py:85 members/models.py:247 +#: members/models.py:85 members/models.py:249 msgid "group" msgstr "Gruppe" @@ -356,478 +402,478 @@ msgstr "Nachname" msgid "Email confirmed" msgstr "Emailadresse bestätigt" -#: members/models.py:137 +#: members/models.py:139 msgid "Email confirmation needed" msgstr "Email Bestätigung erforderlich" -#: members/models.py:177 members/models.py:221 +#: members/models.py:179 members/models.py:223 msgid "phone number" msgstr "Telefonnummer (mobil)" -#: members/models.py:187 +#: members/models.py:189 msgid "birth date" msgstr "Geburtsdatum" -#: members/models.py:193 +#: members/models.py:195 msgid "Gender" msgstr "Gender" -#: members/models.py:194 +#: members/models.py:196 msgid "comments" msgstr "Kommentare" -#: members/models.py:218 +#: members/models.py:220 msgid "Alternative email confirmed" msgstr "Alternative E-Mail Adresse bestätigt" -#: members/models.py:222 +#: members/models.py:224 msgid "street and house number" msgstr "Straße und Hausnummer" -#: members/models.py:223 +#: members/models.py:225 msgid "Postcode" msgstr "PLZ" -#: members/models.py:225 +#: members/models.py:227 msgid "town" msgstr "Stadt" -#: members/models.py:226 +#: members/models.py:228 msgid "Address extra" msgstr "Adress-Zusatz" -#: members/models.py:227 +#: members/models.py:229 msgid "Country" msgstr "Land" -#: members/models.py:229 +#: members/models.py:231 msgid "Good conduct certificate presented on" msgstr "Führungszeugnis vorgelegt am" -#: members/models.py:230 +#: members/models.py:232 msgid "Joined on" msgstr "Eintritt" -#: members/models.py:231 +#: members/models.py:233 msgid "Left on" msgstr "Austritt" -#: members/models.py:232 +#: members/models.py:234 msgid "Has key" msgstr "Hat Jugendraumschlüssel" -#: members/models.py:233 +#: members/models.py:235 msgid "Has a free ticket for the climbing gym" msgstr "Hat Freikarte für Kletterhalle" -#: members/models.py:234 +#: members/models.py:236 msgid "DAV badge number" msgstr "DAV Mitgliedsnummer" -#: members/models.py:235 +#: members/models.py:237 msgid "Knows how to swim" msgstr "Kann schwimmen" -#: members/models.py:236 +#: members/models.py:238 msgid "Climbing badge" msgstr "Kletterschein" -#: members/models.py:237 +#: members/models.py:239 msgid "Alpine experience" msgstr "Alpine Erfahrung" -#: members/models.py:238 +#: members/models.py:240 msgid "Allergies" msgstr "Allergieen" -#: members/models.py:239 +#: members/models.py:241 msgid "Medication" msgstr "Medikamente" -#: members/models.py:240 +#: members/models.py:242 msgid "Tetanus vaccination" msgstr "Tetanusimpfung" -#: members/models.py:241 +#: members/models.py:243 msgid "Photos may be taken" msgstr "Fotoerlaubnis" -#: members/models.py:242 +#: members/models.py:244 msgid "Legal guardians" msgstr "Erziehungsberechtigte" -#: members/models.py:244 +#: members/models.py:246 msgid "May cancel a group appointment independently" msgstr "Darf sich allein von der Gruppenstunde abmelden" -#: members/models.py:251 +#: members/models.py:253 msgid "receives newsletter" msgstr "Erhält den Newsletter" -#: members/models.py:255 +#: members/models.py:257 msgid "created" msgstr "erstellt" -#: members/models.py:256 +#: members/models.py:258 msgid "Active" msgstr "Aktiv" -#: members/models.py:257 +#: members/models.py:259 msgid "registration form" msgstr "Anmeldeformular" -#: members/models.py:265 +#: members/models.py:267 msgid "image" msgstr "Bild" -#: members/models.py:274 +#: members/models.py:276 msgid "Echoed" msgstr "Rückgemeldet" -#: members/models.py:275 +#: members/models.py:277 msgid "Confirmed" msgstr "Bestätigt" -#: members/models.py:277 +#: members/models.py:279 msgid "Login data" msgstr "Zugangsdaten" -#: members/models.py:307 +#: members/models.py:309 msgid "Good conduct certificate valid" msgstr "Führungszeugnis gültig" -#: members/models.py:381 +#: members/models.py:383 msgid "member" msgstr "Teilnehmer" -#: members/models.py:382 +#: members/models.py:384 msgid "members" msgstr "Teilnehmer" -#: members/models.py:455 +#: members/models.py:457 #, python-format msgid "New unconfirmed registration for group %(group)s" msgstr "Neue unbestätigte Registrierung für Gruppe %(group)s" -#: members/models.py:666 +#: members/models.py:668 msgid "Set login data for Kompass" msgstr "Zugangsdaten für Kompass wählen" -#: members/models.py:675 members/models.py:868 members/models.py:879 -#: members/models.py:1155 members/models.py:1162 +#: members/models.py:685 members/models.py:879 members/models.py:890 +#: members/models.py:1166 members/models.py:1173 msgid "Member" msgstr "Teilnehmer" -#: members/models.py:681 +#: members/models.py:692 msgid "Emergency contact" msgstr "Notfallkontakt" -#: members/models.py:682 +#: members/models.py:693 msgid "Emergency contacts" msgstr "Notfallkontakte" -#: members/models.py:702 +#: members/models.py:713 msgid "Unconfirmed registration" msgstr "Unbestätigte Registrierung" -#: members/models.py:703 +#: members/models.py:714 msgid "Unconfirmed registrations" msgstr "Unbestätigte Registrierungen" -#: members/models.py:717 members/models.py:762 +#: members/models.py:728 members/models.py:773 msgid "Waiter" msgstr "Wartende Person" -#: members/models.py:719 +#: members/models.py:730 msgid "Invitation date" msgstr "Einladungsdatum" -#: members/models.py:720 members/templates/members/reject_success.html:6 +#: members/models.py:731 members/templates/members/reject_success.html:6 #: members/templates/members/reject_success.html:11 msgid "Invitation rejected" msgstr "Einladung abgelehnt" -#: members/models.py:724 +#: members/models.py:735 msgid "Invitation to group" msgstr "Gruppeneinladung" -#: members/models.py:725 +#: members/models.py:736 msgid "Invitations to groups" msgstr "Gruppeneinladungen" -#: members/models.py:732 +#: members/models.py:743 msgid "Rejected" msgstr "Abgelehnt" -#: members/models.py:734 +#: members/models.py:745 msgid "Expired" msgstr "Abgelaufen" -#: members/models.py:736 +#: members/models.py:747 msgid "Undecided" msgstr "Ausstehend" -#: members/models.py:737 +#: members/models.py:748 msgid "Status" msgstr "Status" -#: members/models.py:748 +#: members/models.py:759 msgid "Do you want to tell us something else?" msgstr "Möchtest du uns noch etwas mitteilen?" -#: members/models.py:749 +#: members/models.py:760 msgid "application date" msgstr "Bewerbungsdatum" -#: members/models.py:751 +#: members/models.py:762 msgid "Last wait confirmation" msgstr "Letzte Wartebestätigung" -#: members/models.py:755 +#: members/models.py:766 msgid "Last reminder" msgstr "Letzte Erinnerung" -#: members/models.py:756 +#: members/models.py:767 msgid "Missed reminders" msgstr "Verpasste Erinnerungen" -#: members/models.py:763 +#: members/models.py:774 msgid "Waiters" msgstr "Warteliste" -#: members/models.py:787 +#: members/models.py:798 msgid "Waiting status confirmed" msgstr "Wartelistenplatz bestätigt" -#: members/models.py:794 +#: members/models.py:805 msgid "Waiting confirmation needed" msgstr "Wartelistenplatzbestätigung erforderlich" -#: members/models.py:847 +#: members/models.py:858 msgid "Invitation to trial group meeting" msgstr "Einladung zu Schnupperstunde" -#: members/models.py:859 +#: members/models.py:870 msgid "Unregistered from waiting list" msgstr "Von der Warteliste abgemeldet" -#: members/models.py:873 +#: members/models.py:884 msgid "Comment" msgstr "Kommentar" -#: members/models.py:880 members/models.py:1163 +#: members/models.py:891 members/models.py:1174 msgid "Members" msgstr "Teilnehmer" -#: members/models.py:914 +#: members/models.py:925 msgid "Place" msgstr "Stützpunkt / Ort" -#: members/models.py:915 +#: members/models.py:926 msgid "Destination (optional)" msgstr "ggf. Ziel" -#: members/models.py:917 +#: members/models.py:928 msgid "e.g. a peak" msgstr "z.B. ein Gipfel" -#: members/models.py:918 +#: members/models.py:929 msgid "Begin" msgstr "Anfang" -#: members/models.py:919 +#: members/models.py:930 msgid "End (optional)" msgstr "Ende" -#: members/models.py:922 +#: members/models.py:933 msgid "Groups" msgstr "Gruppen" -#: members/models.py:935 +#: members/models.py:946 msgid "Kilometers traveled" msgstr "Fahrstrecke in Kilometer" -#: members/models.py:938 +#: members/models.py:949 msgid "Categories" msgstr "Kategorien" -#: members/models.py:939 +#: members/models.py:950 msgid "easy" msgstr "leicht" -#: members/models.py:939 +#: members/models.py:950 msgid "medium" msgstr "mittel" -#: members/models.py:939 +#: members/models.py:950 msgid "hard" msgstr "schwer" -#: members/models.py:949 members/models.py:1186 +#: members/models.py:960 members/models.py:1197 msgid "Excursion" msgstr "Ausfahrt" -#: members/models.py:950 +#: members/models.py:961 msgid "Excursions" msgstr "Ausfahrten" -#: members/models.py:1101 members/models.py:1177 members/models.py:1393 +#: members/models.py:1112 members/models.py:1188 members/models.py:1404 msgid "Title" msgstr "Titel" -#: members/models.py:1102 members/models.py:1120 members/models.py:1394 +#: members/models.py:1113 members/models.py:1131 members/models.py:1405 msgid "Date" msgstr "Datum" -#: members/models.py:1121 +#: members/models.py:1132 msgid "Location" msgstr "Ort" -#: members/models.py:1122 +#: members/models.py:1133 msgid "Topic" msgstr "Thema" -#: members/models.py:1146 +#: members/models.py:1157 msgid "Jugendleiter" msgstr "Jugendleiter" -#: members/models.py:1149 +#: members/models.py:1160 msgid "Klettertreff" msgstr "Klettertreff" -#: members/models.py:1150 +#: members/models.py:1161 msgid "Klettertreffs" msgstr "Klettertreffs" -#: members/models.py:1168 +#: members/models.py:1179 msgid "Password" msgstr "Passwort" -#: members/models.py:1171 +#: members/models.py:1182 msgid "registration password" msgstr "Registrierungspassort" -#: members/models.py:1172 +#: members/models.py:1183 msgid "registration passwords" msgstr "Registrierungspasswörter" -#: members/models.py:1179 +#: members/models.py:1190 msgid "Alpinistic goals" msgstr "Alpintechnische Ziele" -#: members/models.py:1180 +#: members/models.py:1191 msgid "Pedagogic goals" msgstr "Pädagogische Ziele" -#: members/models.py:1181 +#: members/models.py:1192 msgid "Content and methods" msgstr "Inhalte und Methoden" -#: members/models.py:1182 +#: members/models.py:1193 msgid "Evaluation" msgstr "Wertung" -#: members/models.py:1183 +#: members/models.py:1194 msgid "Experiences and possible improvements" msgstr "Erfahrungen und Verbesserungsvorschläge" -#: members/models.py:1192 members/models.py:1213 +#: members/models.py:1203 members/models.py:1224 msgid "LJP Proposal" msgstr "Seminarbericht" -#: members/models.py:1193 +#: members/models.py:1204 msgid "LJP Proposals" msgstr "Seminarberichte" -#: members/models.py:1207 +#: members/models.py:1218 msgid "Duration in hours" msgstr "Dauer in Stunden" -#: members/models.py:1210 +#: members/models.py:1221 msgid "Activity and method" msgstr "Art der Aktion inkl. Methode" -#: members/models.py:1218 +#: members/models.py:1229 msgid "Intervention" msgstr "Aktion" -#: members/models.py:1219 +#: members/models.py:1230 msgid "Interventions" msgstr "Aktionen" -#: members/models.py:1321 members/models.py:1351 +#: members/models.py:1332 members/models.py:1362 msgid "May list members" msgstr "Darf folgende Teilnehmer:innen listen" -#: members/models.py:1323 members/models.py:1353 +#: members/models.py:1334 members/models.py:1364 msgid "May view members" msgstr "Darf folgende Teilnehmer:innen anzeigen" -#: members/models.py:1325 members/models.py:1355 +#: members/models.py:1336 members/models.py:1366 msgid "May change members" msgstr "Darf folgende Teilnehmer:innen ändern" -#: members/models.py:1327 members/models.py:1357 +#: members/models.py:1338 members/models.py:1368 msgid "May delete members" msgstr "Darf folgende Teilnehmer:innen löschen" -#: members/models.py:1331 members/models.py:1361 +#: members/models.py:1342 members/models.py:1372 msgid "May list members of groups" msgstr "Darf Teilnehmer:innen folgender Gruppen listen" -#: members/models.py:1333 members/models.py:1363 +#: members/models.py:1344 members/models.py:1374 msgid "May view members of groups" msgstr "Darf Teilnehmer:innen folgender Gruppen anzeigen" -#: members/models.py:1335 members/models.py:1365 +#: members/models.py:1346 members/models.py:1376 msgid "May change members of groups" msgstr "Darf Teilnehmer:innen folgender Gruppen ändern" -#: members/models.py:1337 members/models.py:1367 +#: members/models.py:1348 members/models.py:1378 msgid "May delete members of groups" msgstr "Darf Teilnehmer:innen folgender Gruppen löschen" -#: members/models.py:1340 members/models.py:1341 members/models.py:1344 +#: members/models.py:1351 members/models.py:1352 members/models.py:1355 msgid "Permissions" msgstr "Berechtigungen" -#: members/models.py:1370 members/models.py:1371 members/models.py:1374 +#: members/models.py:1381 members/models.py:1382 members/models.py:1385 msgid "Group permissions" msgstr "Gruppenberechtigungen" -#: members/models.py:1380 +#: members/models.py:1391 msgid "Permission needed" msgstr "Freigabe erforderlich" -#: members/models.py:1383 +#: members/models.py:1394 msgid "Training category" msgstr "Fortbildungstyp" -#: members/models.py:1384 +#: members/models.py:1395 msgid "Training categories" msgstr "Fortbildungstypen" -#: members/models.py:1395 +#: members/models.py:1406 msgid "Category" msgstr "Kategorien" -#: members/models.py:1396 +#: members/models.py:1407 msgid "Comments" msgstr "Kommentar" -#: members/models.py:1397 +#: members/models.py:1408 msgid "Participated" msgstr "Teilgenommmen" -#: members/models.py:1398 +#: members/models.py:1409 msgid "Passed" msgstr "Bestanden" -#: members/models.py:1401 +#: members/models.py:1412 msgid "Training" msgstr "Fortbildung" -#: members/models.py:1402 +#: members/models.py:1413 msgid "Trainings" msgstr "Fortbildungen" @@ -844,8 +890,8 @@ msgid "" "Here you can generate a seminar report suitable for the LJP. A report\n" "always contains a head page with the basic information on the seminar." msgstr "" -"Hier kannst du einen Seminarbericht für den Landesjugendplan erstellen. " -"Ein Bericht enthält immer einen Kopf mit den Stammdaten des Seminars." +"Hier kannst du einen Seminarbericht für den Landesjugendplan erstellen. Ein " +"Bericht enthält immer einen Kopf mit den Stammdaten des Seminars." #: members/templates/admin/generate_seminar_report.html:32 msgid "" @@ -853,9 +899,9 @@ msgid "" "schedule. This requires\n" "the seminar report section to be filled out." msgstr "" -"Vollständiger Bericht: Stelle Lernziele und einen detaillierte, " -"tabellierten Zeitplan dar. Dies benötigt, dass der Seminarbericht " -"in der Ausfahrt ausgefüllt ist." +"Vollständiger Bericht: Stelle Lernziele und einen detaillierte, tabellierten " +"Zeitplan dar. Dies benötigt, dass der Seminarbericht in der Ausfahrt " +"ausgefüllt ist." #: members/templates/admin/generate_seminar_report.html:36 msgid "" @@ -1122,7 +1168,7 @@ msgstr "" "Ich bin einverstanden, dass meine Daten auf dem Server der JDAV %(sektion)s " "gespeichert und verarbeitet werden." -#: members/templates/members/member_form.html:101 +#: members/templates/members/member_form.html:103 msgid "This file is bigger than the maximal allowed file size of 5 MiB." msgstr "Diese Datei ist größer als die maximal erlaubte Dateigröße von 5 MiB." diff --git a/jdav_web/templates/admin/edit_inline/stacked.html b/jdav_web/templates/admin/edit_inline/stacked.html new file mode 100644 index 0000000..f797e82 --- /dev/null +++ b/jdav_web/templates/admin/edit_inline/stacked.html @@ -0,0 +1 @@ +{% load i18n admin_urls %} diff --git a/jdav_web/templates/admin/edit_inline/tabular.html b/jdav_web/templates/admin/edit_inline/tabular.html new file mode 100644 index 0000000..42bb07f --- /dev/null +++ b/jdav_web/templates/admin/edit_inline/tabular.html @@ -0,0 +1,78 @@ +{% load i18n admin_urls static admin_modify %} +
+ +
diff --git a/jdav_web/templates/nesting/admin/inlines/stacked.html b/jdav_web/templates/nesting/admin/inlines/stacked.html new file mode 100644 index 0000000..58fac04 --- /dev/null +++ b/jdav_web/templates/nesting/admin/inlines/stacked.html @@ -0,0 +1,95 @@ +{% load i18n nested_admin admin_urls %} +{% with inline_admin_formset.formset.is_nested as is_nested %} + +{% with inline_admin_formset.opts as inline_opts %} +
+ + {% ifinlineclasses %}
{% endifinlineclasses %} + {% if inline_admin_formset.is_collapsible %}
{% endif %} +

+ {% if inline_admin_formset.opts.title %}{{ inline_admin_formset.opts.title }}{% else %}{{ inline_admin_formset.opts.verbose_name_plural|capfirst }}{% endif %} +

+ {% if inline_admin_formset.is_collapsible %}
{% endif %} + + {{ inline_admin_formset.formset.management_form }} + {{ inline_admin_formset.formset.non_form_errors }} + {% if inline_admin_formset.opts.description %} +
+

+ {{ inline_admin_formset.opts.description }} +

+
+ {% endif %} +
+ + {% with inline_admin_formset.opts.sortable_field_name|default:"" as sortable_field_name %} + {% for inline_admin_form in inline_admin_formset|formsetsort:sortable_field_name %} + {% if forloop.first %} +
+ {% endif %} + + {% endfor %} + {% endwith %} +
+ + {% if inline_admin_formset.is_collapsible %}
{% endif %} + {% ifinlineclasses %}
{% endifinlineclasses %} +
+{% endwith %}{# ends with inline_admin_formset.opts as inline_opts #} + +{% endwith %}{# ends {% with inline_admin_formset.formset.is_nested as is_nested %} #} From 67e019073a68a01755c2d3fddd569f386f3a3839 Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Sun, 24 Nov 2024 22:38:44 +0100 Subject: [PATCH 05/56] finance: fix allowance per day and rounding --- jdav_web/finance/models.py | 2 +- jdav_web/jdav_web/settings/local.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/jdav_web/finance/models.py b/jdav_web/finance/models.py index 91f0a6c..1cfc2a4 100644 --- a/jdav_web/finance/models.py +++ b/jdav_web/finance/models.py @@ -283,7 +283,7 @@ class Statement(CommonModel): if self.excursion is None: return 0 - return self.total_staff / self.excursion.staff_count + return cvt_to_decimal(self.total_staff / self.excursion.staff_count) @property def total_staff(self): diff --git a/jdav_web/jdav_web/settings/local.py b/jdav_web/jdav_web/settings/local.py index 2e68dfd..4e3d49e 100644 --- a/jdav_web/jdav_web/settings/local.py +++ b/jdav_web/jdav_web/settings/local.py @@ -22,7 +22,7 @@ MAX_AGE_GOOD_CONDUCT_CERTIFICATE_MONTHS = 24 # finance -ALLOWANCE_PER_DAY = 10 +ALLOWANCE_PER_DAY = 22 MAX_NIGHT_COST = 11 CLOUD_LINK = 'https://nc.cloud-jdav-hd.de' From 520dc1d3d2b9c5eee9e92a14b43f8cfc405f1dc4 Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Wed, 27 Nov 2024 22:22:28 +0100 Subject: [PATCH 06/56] members/admin: fix inlines --- .../templates/admin/edit_inline/stacked.html | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/jdav_web/templates/admin/edit_inline/stacked.html b/jdav_web/templates/admin/edit_inline/stacked.html index f797e82..a6939f4 100644 --- a/jdav_web/templates/admin/edit_inline/stacked.html +++ b/jdav_web/templates/admin/edit_inline/stacked.html @@ -1 +1,38 @@ {% load i18n admin_urls %} +
+
+ {% if inline_admin_formset.is_collapsible %}
{% endif %} +

+ {% if inline_admin_formset.formset.max_num == 1 %} + {{ inline_admin_formset.opts.verbose_name|capfirst }} + {% else %} + {{ inline_admin_formset.opts.verbose_name_plural|capfirst }} + {% endif %} +

+ {% if inline_admin_formset.is_collapsible %}
{% endif %} +{{ inline_admin_formset.formset.management_form }} +{{ inline_admin_formset.formset.non_form_errors }} + +{% for inline_admin_form in inline_admin_formset %}
+

{{ inline_admin_formset.opts.verbose_name|capfirst }}: {% if inline_admin_form.original %}{{ inline_admin_form.original }}{% if inline_admin_form.model_admin.show_change_link and inline_admin_form.model_admin.has_registered_model %} {% if inline_admin_formset.has_change_permission %}{% translate "Change" %}{% else %}{% translate "View" %}{% endif %}{% endif %} +{% else %}#{{ forloop.counter }}{% endif %} + {% if inline_admin_form.show_url %}{% translate "View on site" %}{% endif %} + {% if inline_admin_formset.formset.can_delete and inline_admin_formset.has_delete_permission and inline_admin_form.original %}{{ inline_admin_form.deletion_field.field }} {{ inline_admin_form.deletion_field.label_tag }}{% endif %} +

+ {% if inline_admin_form.form.non_field_errors %}{{ inline_admin_form.form.non_field_errors }}{% endif %} + + {% with parent_counter=forloop.counter0 %} + {% for fieldset in inline_admin_form %} + {% include "admin/includes/fieldset.html" with heading_level=4 prefix=fieldset.formset.prefix id_prefix=parent_counter id_suffix=forloop.counter0 %} + {% endfor %} + {% endwith %} + + {% if inline_admin_form.needs_explicit_pk_field %}{{ inline_admin_form.pk_field.field }}{% endif %} + {% if inline_admin_form.fk_field %}{{ inline_admin_form.fk_field.field }}{% endif %} +
{% endfor %} + {% if inline_admin_formset.is_collapsible %}
{% endif %} +
+
From 8dafe01de05006040eeb59fcdedc7cb905d2735d Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Wed, 27 Nov 2024 22:26:24 +0100 Subject: [PATCH 07/56] templates: purge more ludwigsburg email addresses --- jdav_web/logindata/templates/logindata/register_failed.html | 2 +- jdav_web/members/templates/members/echo_failed.html | 2 +- .../members/templates/members/invited_registration_failed.html | 2 +- jdav_web/members/templates/members/register_failed.html | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/jdav_web/logindata/templates/logindata/register_failed.html b/jdav_web/logindata/templates/logindata/register_failed.html index 433815a..b04b8f9 100644 --- a/jdav_web/logindata/templates/logindata/register_failed.html +++ b/jdav_web/logindata/templates/logindata/register_failed.html @@ -12,6 +12,6 @@

{% trans "Something went wrong. The registration key is invalid or has expired." %}

-

{% trans "If you think this is a mistake, please" %} {% trans "contact us." %}

+

{% trans "If you think this is a mistake, please" %} {% trans "contact us." %}

{% endblock %} diff --git a/jdav_web/members/templates/members/echo_failed.html b/jdav_web/members/templates/members/echo_failed.html index 8e7ee67..f65550f 100644 --- a/jdav_web/members/templates/members/echo_failed.html +++ b/jdav_web/members/templates/members/echo_failed.html @@ -12,6 +12,6 @@

{% trans "Something went wrong. The key you supplied is" %} {{ reason }}.

-

{% trans "If you think this is a mistake, please" %} {% trans "contact us." %}

+

{% trans "If you think this is a mistake, please" %} {% trans "contact us." %}

{% endblock %} diff --git a/jdav_web/members/templates/members/invited_registration_failed.html b/jdav_web/members/templates/members/invited_registration_failed.html index 619f534..a68a610 100644 --- a/jdav_web/members/templates/members/invited_registration_failed.html +++ b/jdav_web/members/templates/members/invited_registration_failed.html @@ -12,6 +12,6 @@

{% trans "Something went wrong. The key you supplied is" %} {{ reason }}.

-

{% trans "If you think this is a mistake, please" %} {% trans "contact us." %}

+

{% trans "If you think this is a mistake, please" %} {% trans "contact us." %}

{% endblock %} diff --git a/jdav_web/members/templates/members/register_failed.html b/jdav_web/members/templates/members/register_failed.html index 49af016..92b4319 100644 --- a/jdav_web/members/templates/members/register_failed.html +++ b/jdav_web/members/templates/members/register_failed.html @@ -12,6 +12,6 @@

{% trans "Something went wrong while processing your registration." %}

-

{% trans "If you think this is a mistake, please" %} {% trans "contact us." %}

+

{% trans "If you think this is a mistake, please" %} {% trans "contact us." %}

{% endblock %} From 5205caa6a6a195f4e248ae648c6204ac979f6db1 Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Wed, 27 Nov 2024 23:11:10 +0100 Subject: [PATCH 08/56] chore: add read_settings templatetag --- jdav_web/contrib/templatetags/common.py | 9 +++++++++ .../logindata/templates/logindata/register_failed.html | 5 ++--- jdav_web/members/templates/members/echo_failed.html | 6 +++--- .../templates/members/invited_registration_failed.html | 5 ++--- jdav_web/members/templates/members/register_failed.html | 6 +++--- jdav_web/templates/admin/index.html | 8 ++++---- 6 files changed, 23 insertions(+), 16 deletions(-) create mode 100644 jdav_web/contrib/templatetags/common.py diff --git a/jdav_web/contrib/templatetags/common.py b/jdav_web/contrib/templatetags/common.py new file mode 100644 index 0000000..4e2b350 --- /dev/null +++ b/jdav_web/contrib/templatetags/common.py @@ -0,0 +1,9 @@ +from django import template +from django.conf import settings + +register = template.Library() + +# settings value +@register.simple_tag +def settings_value(name): + return getattr(settings, name, "") diff --git a/jdav_web/logindata/templates/logindata/register_failed.html b/jdav_web/logindata/templates/logindata/register_failed.html index b04b8f9..5484579 100644 --- a/jdav_web/logindata/templates/logindata/register_failed.html +++ b/jdav_web/logindata/templates/logindata/register_failed.html @@ -1,6 +1,5 @@ {% extends "members/base.html" %} -{% load i18n %} -{% load static %} +{% load i18n static common %} {% block title %} {% trans "Registration" %} @@ -12,6 +11,6 @@

{% trans "Something went wrong. The registration key is invalid or has expired." %}

-

{% trans "If you think this is a mistake, please" %} {% trans "contact us." %}

+

{% trans "If you think this is a mistake, please" %} {% trans "contact us." %}

{% endblock %} diff --git a/jdav_web/members/templates/members/echo_failed.html b/jdav_web/members/templates/members/echo_failed.html index f65550f..be66343 100644 --- a/jdav_web/members/templates/members/echo_failed.html +++ b/jdav_web/members/templates/members/echo_failed.html @@ -1,6 +1,5 @@ {% extends "members/base.html" %} -{% load i18n %} -{% load static %} +{% load i18n static common %} {% block title %} {% trans "Echo failed" %} @@ -12,6 +11,7 @@

{% trans "Something went wrong. The key you supplied is" %} {{ reason }}.

-

{% trans "If you think this is a mistake, please" %} {% trans "contact us." %}

+

{% trans "If you think this is a mistake, please" %} +{% trans "contact us." %}

{% endblock %} diff --git a/jdav_web/members/templates/members/invited_registration_failed.html b/jdav_web/members/templates/members/invited_registration_failed.html index a68a610..393307f 100644 --- a/jdav_web/members/templates/members/invited_registration_failed.html +++ b/jdav_web/members/templates/members/invited_registration_failed.html @@ -1,6 +1,5 @@ {% extends "members/base.html" %} -{% load i18n %} -{% load static %} +{% load i18n static common %} {% block title %} {% trans "Registration failed" %} @@ -12,6 +11,6 @@

{% trans "Something went wrong. The key you supplied is" %} {{ reason }}.

-

{% trans "If you think this is a mistake, please" %} {% trans "contact us." %}

+

{% trans "If you think this is a mistake, please" %} {% trans "contact us." %}

{% endblock %} diff --git a/jdav_web/members/templates/members/register_failed.html b/jdav_web/members/templates/members/register_failed.html index 92b4319..c1371c8 100644 --- a/jdav_web/members/templates/members/register_failed.html +++ b/jdav_web/members/templates/members/register_failed.html @@ -1,6 +1,5 @@ {% extends "members/base.html" %} -{% load i18n %} -{% load static %} +{% load i18n static common %} {% block title %} {% trans "Registration failed" %} @@ -12,6 +11,7 @@

{% trans "Something went wrong while processing your registration." %}

-

{% trans "If you think this is a mistake, please" %} {% trans "contact us." %}

+

{% trans "If you think this is a mistake, please" %} +{% trans "contact us." %}

{% endblock %} diff --git a/jdav_web/templates/admin/index.html b/jdav_web/templates/admin/index.html index e498037..5ee62a8 100644 --- a/jdav_web/templates/admin/index.html +++ b/jdav_web/templates/admin/index.html @@ -1,5 +1,5 @@ {% extends "admin/index.html" %} -{% load i18n static %} +{% load i18n static common %} {% block content %} @@ -67,7 +67,7 @@ Hier siehst du alle von dir geleiteten Ausfahrten. @@ -111,7 +147,7 @@ weiterweißt oder sonst der Schuh drückt, schreibe eine E-Mail an eine der folg Fragen zum Kompass
- Nextcloud + Nextcloud Hier liegen Vorlagen für Formulare und nützliche Handbücher. @@ -75,7 +75,7 @@ Hier siehst du alle von dir geleiteten Ausfahrten.
- DAV 360 + DAV 360 Zugriff zu Online Office, Teams und deinem DAV Mailaccount. @@ -83,7 +83,7 @@ Hier siehst du alle von dir geleiteten Ausfahrten.
- Julei-Wiki + Julei-Wiki Informationen zum Jugendleiter:in-sein. From 7ef55738a5998e715238d158f6b4f58425fb4ec0 Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Thu, 28 Nov 2024 00:00:50 +0100 Subject: [PATCH 09/56] members: provide contact info in waitinglist invitation --- .../jdav_web/settings/components/texts.py | 11 +- jdav_web/mailer/mailutils.py | 8 +- jdav_web/members/admin.py | 13 +- .../members/locale/de/LC_MESSAGES/django.po | 138 +++++++++--------- .../migrations/0027_alter_group_weekday.py | 18 +++ .../migrations/0028_group_contact_email.py | 20 +++ jdav_web/members/models.py | 39 +++-- 7 files changed, 161 insertions(+), 86 deletions(-) create mode 100644 jdav_web/members/migrations/0027_alter_group_weekday.py create mode 100644 jdav_web/members/migrations/0028_group_contact_email.py diff --git a/jdav_web/jdav_web/settings/components/texts.py b/jdav_web/jdav_web/settings/components/texts.py index 6371e57..0bb3ad3 100644 --- a/jdav_web/jdav_web/settings/components/texts.py +++ b/jdav_web/jdav_web/settings/components/texts.py @@ -22,12 +22,19 @@ der Registrierung kommst du hier: Viele Grüße Dein KOMPASS""" +GROUP_TIME_AVAILABLE_TEXT = """Die Gruppenstunde findet jeden {weekday} von {start_time} bis {end_time} Uhr statt.""" + +GROUP_TIME_UNAVAILABLE_TEXT = """Bitte erfrage die Gruppenzeiten bei der Gruppenleitung ({contact_email}).""" + INVITE_TEXT = """Hallo {name}, wir haben gute Neuigkeiten für dich. Es ist ein Platz in der Jugendgruppe {group_name} {group_link}freigeworden. -Wir treffen uns jeden {weekday} von {start_time} bis {end_time} Uhr. +{group_time} + +Bitte kontaktiere die Gruppenleitung ({contact_email}) für alle weiteren Absprachen. -Wir brauchen jetzt noch ein paar Informationen von dir und deine Anmeldebestätigung. Die lädst du herunter +Wenn du nach der Schnupperstunde beschließt der Gruppe beizutreten, benötigen wir noch ein paar +Informationen und deine Anmeldebestätigung von dir. Die lädst du herunter (siehe %(REGISTRATION_FORM_DOWNLOAD_LINK)s), lässt sie von deinen Eltern ausfüllen, unterschreiben und lädst ein Foto davon in unserem Anmeldeformular hoch. Das kannst du alles über folgenden Link erledigen: diff --git a/jdav_web/mailer/mailutils.py b/jdav_web/mailer/mailutils.py index 701de61..c9478de 100644 --- a/jdav_web/mailer/mailutils.py +++ b/jdav_web/mailer/mailutils.py @@ -7,10 +7,14 @@ import os NOT_SENT, SENT, PARTLY_SENT = 0, 1, 2 def send(subject, content, sender, recipients, message_id=None, reply_to=None, - attachments=None): + attachments=None, cc=None): failed, succeeded = False, False if type(recipients) != list: recipients = [recipients] + if not cc: + cc = [] + elif type(cc) != list: + cc = [cc] if reply_to is not None: kwargs = {"reply_to": reply_to} else: @@ -23,7 +27,7 @@ def send(subject, content, sender, recipients, message_id=None, reply_to=None, # construct mails mails = [] for recipient in set(recipients): - email = EmailMessage(subject, content, sender, [recipient], + email = EmailMessage(subject, content, sender, [recipient], cc=cc, headers=headers, **kwargs) if attachments is not None: for attach in attachments: diff --git a/jdav_web/members/admin.py b/jdav_web/members/admin.py index 9da53d4..de8128f 100644 --- a/jdav_web/members/admin.py +++ b/jdav_web/members/admin.py @@ -170,6 +170,7 @@ class MemberAdmin(CommonAdminMixin, admin.ModelAdmin): ('email', 'alternative_email'), 'phone_number', 'birth_date', + 'gender', 'group', 'registration_form', 'image', ('join_date', 'leave_date'), 'comments', @@ -382,6 +383,7 @@ class MemberUnconfirmedAdmin(admin.ModelAdmin): ('email', 'alternative_email'), 'phone_number', 'birth_date', + 'gender', 'group', 'registration_form', 'image', ('join_date', 'leave_date'), 'comments', @@ -539,6 +541,10 @@ class MemberWaitingListAdmin(CommonAdminMixin, admin.ModelAdmin): messages.error(request, _("An error occurred while trying to invite said members. Please try again.")) return HttpResponseRedirect(request.get_full_path()) + if not group.contact_email: + messages.error(request, + _('The selected group does not have a contact email. Please first set a contact email and then try again.')) + return HttpResponseRedirect(request.get_full_path()) for waiter in queryset: waiter.invited_for_group = group @@ -596,6 +602,11 @@ class MemberWaitingListAdmin(CommonAdminMixin, admin.ModelAdmin): _("An error occurred while trying to invite said members. Please try again.")) return HttpResponseRedirect(request.get_full_path()) + if not group.contact_email: + messages.error(request, + _('The selected group does not have a contact email. Please first set a contact email and then try again.')) + return HttpResponseRedirect(request.get_full_path()) + waiter.invited_for_group = group waiter.save() waiter.invite_to_group(group) @@ -634,7 +645,7 @@ class GroupAdminForm(forms.ModelForm): class GroupAdmin(CommonAdminMixin, admin.ModelAdmin): - fields = ['name', 'description', 'year_from', 'year_to', 'leiters', 'show_website', + fields = ['name', 'description', 'year_from', 'year_to', 'leiters', 'contact_email', 'show_website', 'weekday', ('start_time', 'end_time')] form = GroupAdminForm list_display = ('name', 'year_from', 'year_to') diff --git a/jdav_web/members/locale/de/LC_MESSAGES/django.po b/jdav_web/members/locale/de/LC_MESSAGES/django.po index eb91978..57f0cbd 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: 2024-11-24 22:24+0100\n" +"POT-Creation-Date: 2024-11-27 23:16+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -34,174 +34,174 @@ msgstr "Nein" msgid "All" msgstr "Alle" -#: members/admin.py:183 members/admin.py:395 +#: members/admin.py:184 members/admin.py:397 msgid "Contact information" msgstr "Kontaktinformationen" -#: members/admin.py:188 members/admin.py:400 +#: members/admin.py:189 members/admin.py:402 msgid "Skills" msgstr "Fähigkeiten" -#: members/admin.py:193 members/admin.py:405 +#: members/admin.py:194 members/admin.py:407 msgid "Others" msgstr "Sonstiges" -#: members/admin.py:199 members/admin.py:410 +#: members/admin.py:200 members/admin.py:412 msgid "Organizational" msgstr "Organisatorisches" -#: members/admin.py:280 +#: members/admin.py:281 msgid "Compose new mail to selected members" msgstr "Neue Nachricht an ausgewählte Teilnehmer verfassen" -#: members/admin.py:286 +#: members/admin.py:287 msgid "Echo required" msgstr "Rückmeldung erforderlich" -#: members/admin.py:288 +#: members/admin.py:289 msgid "Successfully requested echo from selected members." msgstr "" "Rückmeldungsaufforderung erfolgreich an ausgewählte Teilnehmer verschickt." -#: members/admin.py:289 +#: members/admin.py:290 msgid "Request echo from selected members" msgstr "Rückmeldungsaufforderung an ausgewählte Teilnehmer verschicken" -#: members/admin.py:295 +#: members/admin.py:296 #, python-format msgid "Successfully invited %(name)s as user." msgstr "Erfolgreich %(name)s aufgefordert Zugangsdaten zu wählen." -#: members/admin.py:297 +#: members/admin.py:298 msgid "Successfully invited selected members to join as users." msgstr "" "Erfolgreich ausgewählte Teilnehmer:innen aufgefordert Zugangsdaten zu wählen." -#: members/admin.py:304 members/admin.py:321 +#: members/admin.py:305 members/admin.py:322 msgid "Permission denied." msgstr "Fehlende Berechtigungen." -#: members/admin.py:311 members/admin.py:340 +#: members/admin.py:312 members/admin.py:341 #: members/templates/admin/invite_as_user.html:21 msgid "Invite as user" msgstr "Kompass Zugangsdaten wählen lassen" -#: members/admin.py:316 +#: members/admin.py:317 msgid "Invite selected members to join Kompass as users." msgstr "Ausgewählte Teilnehmer:innen Kompass Zugangsdaten wählen lassen." -#: members/admin.py:327 +#: members/admin.py:328 msgid "Member not found." msgstr "Teilnehmer:in nicht gefunden." -#: members/admin.py:331 +#: members/admin.py:332 #, python-format msgid "%(name)s already has login data." msgstr "%(name)s hat schon Zugangsdaten." -#: members/admin.py:345 +#: members/admin.py:346 #, python-format msgid "%(name)s already has a pending invitation as user." msgstr "" "%(name)s hat bereits eine ausstehende Aufforderung Zugangsdaten zu wählen." -#: members/admin.py:363 +#: members/admin.py:364 msgid "activity" msgstr "Aktivität" -#: members/admin.py:373 members/models.py:53 members/models.py:1390 +#: members/admin.py:374 members/models.py:53 members/models.py:1390 msgid "Name" msgstr "Name" -#: members/admin.py:444 +#: members/admin.py:446 msgid "Successfully requested mail confirmation from selected registrations." msgstr "Aufforderung zur Bestätigung der Email Adresse versendet." -#: members/admin.py:445 +#: members/admin.py:447 msgid "Request mail confirmation from selected registrations" msgstr "Aufforderung zur Bestätigung der Email Adresse versenden" -#: members/admin.py:452 members/admin.py:486 +#: members/admin.py:454 members/admin.py:488 #, python-format msgid "Successfully confirmed %(name)s." msgstr "Registrierung von %(name)s erfolgreich bestätigt." -#: members/admin.py:456 members/admin.py:489 +#: members/admin.py:458 members/admin.py:491 #, python-format msgid "Can't confirm. %(name)s has unconfirmed email addresses." msgstr "Bestätigung nicht möglich. %(name)s hat unbestätigte Emailadressen." -#: members/admin.py:461 +#: members/admin.py:463 msgid "Successfully confirmed multiple registrations." msgstr "Erfolgreich mehrere Registrierungen bestätigt." -#: members/admin.py:463 +#: members/admin.py:465 msgid "" "Failed to confirm some registrations because of unconfirmed email addresses." msgstr "" "Einige Bestätigungen fehlgeschlagen, weil Emailadressen noch nicht bestätigt " "sind." -#: members/admin.py:464 +#: members/admin.py:466 msgid "Confirm selected registrations" msgstr "Ausgewählte Registrierungen bestätigen" -#: members/admin.py:480 +#: members/admin.py:482 #, python-format msgid "Successfully demoted %(name)s to waiter." msgstr "%(name)s zurück auf die Warteliste gesetzt." -#: members/admin.py:481 +#: members/admin.py:483 msgid "Demote selected registrations to waiters." msgstr "Ausgewählte Registrierungen zurück auf die Warteliste setzen." -#: members/admin.py:496 members/models.py:380 members/models.py:729 +#: members/admin.py:498 members/models.py:380 members/models.py:729 #: members/models.py:1135 msgid "Group" msgstr "Gruppe" -#: members/admin.py:530 +#: members/admin.py:532 #, python-format msgid "Successfully asked %(name)s to confirm their waiting status." msgstr "Erfolgreich %(name)s aufgefordert den Wartelistenplatz zu bestätigen." -#: members/admin.py:531 +#: members/admin.py:533 msgid "Ask selected waiters to confirm their waiting status" msgstr "Wartende auffordern den Wartelistenplatz zu bestätigen" -#: members/admin.py:540 members/admin.py:596 +#: members/admin.py:542 members/admin.py:598 msgid "" "An error occurred while trying to invite said members. Please try again." msgstr "" "Beim Einladen dieser Personen ist ein Fehler aufgetreten. Bitte versuche es " "nochmal. " -#: members/admin.py:548 members/admin.py:603 +#: members/admin.py:550 members/admin.py:605 #, python-format msgid "Successfully invited %(name)s to %(group)s." msgstr "Erfolgreich %(name)s zu Gruppe %(group)s eingeladen." -#: members/admin.py:552 members/admin.py:609 +#: members/admin.py:554 members/admin.py:611 msgid "Select group for invitation" msgstr "Wähle Gruppe für Einladung aus" -#: members/admin.py:559 +#: members/admin.py:561 msgid "Offer waiter a place in a group." msgstr "Personen auf der Warteliste einen Gruppenplatz anbieten." -#: members/admin.py:652 +#: members/admin.py:654 msgid "Difficulty" msgstr "Schwierigkeit" -#: members/admin.py:655 +#: members/admin.py:657 msgid "Tour type" msgstr "Art der Tour" -#: members/admin.py:658 members/models.py:945 +#: members/admin.py:660 members/models.py:945 msgid "Means of transportation" msgstr "Verkehrsmittel" -#: members/admin.py:684 +#: members/admin.py:686 msgid "" "Please list here all expenses in relation with this excursion and upload " "relevant bills. These have to be permanently stored for the application of " @@ -214,7 +214,7 @@ msgstr "" "einzelnen Posten wird dabei auf der LJP-Kostenübersicht angezeigt (sinnvoll " "wären z.B. Anreise, Verpflegung, Material etc.)." -#: members/admin.py:702 +#: members/admin.py:704 msgid "" "Here you can work on a seminar report for applying for financial " "contributions from Landesjugendplan (LJP). More information on creating a " @@ -227,7 +227,7 @@ msgstr "" "wahlweise nur TN-Liste und Kostenübersicht kannst du anschließend " "herunterladen." -#: members/admin.py:710 +#: members/admin.py:712 msgid "" "Please list all participants (also youth leaders) of this excursion. Here " "you can still make changes just before departure and hence generate the " @@ -238,30 +238,30 @@ msgstr "" "jederzeit die aktuelle Teilnehmer:innenliste für die Krisenintervention " "generieren." -#: members/admin.py:756 +#: members/admin.py:758 #, python-format msgid "You are not allowed to view all members on note list %(name)s." msgstr "" "Du hast nicht die nötigen Rechte um alle Teilnehmer:innen der Notizliste " "%(name)s anzusehen." -#: members/admin.py:766 +#: members/admin.py:768 msgid "Generate PDF summary" msgstr "Übersicht erstellen" -#: members/admin.py:770 +#: members/admin.py:772 msgid "Full report" msgstr "Vollständiger Seminarbericht" -#: members/admin.py:771 +#: members/admin.py:773 msgid "Costs and participants only" msgstr "Nur Kosten und Teilnehmende" -#: members/admin.py:772 +#: members/admin.py:774 msgid "Mode" msgstr "Modus" -#: members/admin.py:786 +#: members/admin.py:788 msgid "" "General information on your excursion. These are partly relevant for the " "amount of financial compensation (means of transport, travel distance, etc.)." @@ -270,38 +270,38 @@ msgstr "" "teilweise relevant für die Zuschüsse aus dem Jugendetat (Verkehrsmittel, " "Fahrstrecke in km)." -#: members/admin.py:816 +#: members/admin.py:818 #, python-format msgid "You are not allowed to view all members on excursion %(name)s." msgstr "" "Du hast nicht die nötigen Rechte um alle Teilnehmer:innen der Ausfahrt " "%(name)s anzusehen." -#: members/admin.py:824 +#: members/admin.py:826 msgid "Generate crisis intervention list" msgstr "Kriseninterventionsliste erstellen" -#: members/admin.py:832 +#: members/admin.py:834 msgid "Generate overview" msgstr "Hinweise für Jugendleiter erstellen" -#: members/admin.py:836 members/admin.py:859 +#: members/admin.py:838 members/admin.py:861 #: members/templates/admin/generate_seminar_report.html:21 msgid "Generate seminar report" msgstr "Seminarbericht erstellen" -#: members/admin.py:849 +#: members/admin.py:851 msgid "Please select a mode." msgstr "Bitte wähle einen Modus aus." -#: members/admin.py:853 +#: members/admin.py:855 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:871 +#: members/admin.py:873 msgid "Generate SJR application" msgstr "SJR Antrag erstellen" @@ -374,6 +374,10 @@ msgstr "Bis Jahrgang" msgid "youth leaders" msgstr "Jugendleiter" +#: members/models.py:76 +msgid "week day" +msgstr "Wochentag" + #: members/models.py:77 members/models.py:1217 msgid "Starting time" msgstr "Zeitpunkt" @@ -1022,7 +1026,7 @@ msgid "Save and confirm registration" msgstr "Speichern und Registrierung bestätigen" #: members/templates/members/echo.html:6 members/templates/members/echo.html:13 -#: members/templates/members/echo_failed.html:11 +#: members/templates/members/echo_failed.html:10 #: members/templates/members/echo_password.html:6 #: members/templates/members/echo_password.html:11 #: members/templates/members/echo_success.html:10 @@ -1037,23 +1041,23 @@ msgstr "" "Vielen Dank, dass du dich rückmeldest. Hier siehst du deine aktuellen Daten. " "Falls sich etwas geändert hat, trage das bitte hier ein." -#: members/templates/members/echo_failed.html:6 +#: members/templates/members/echo_failed.html:5 msgid "Echo failed" msgstr "Rückmeldung fehlgeschlagen" -#: members/templates/members/echo_failed.html:13 -#: members/templates/members/invited_registration_failed.html:13 +#: members/templates/members/echo_failed.html:12 +#: members/templates/members/invited_registration_failed.html:12 msgid "Something went wrong. The key you supplied is" msgstr "Etwas ist schief gegangen. Der verwendete Code ist" -#: members/templates/members/echo_failed.html:15 -#: members/templates/members/invited_registration_failed.html:15 -#: members/templates/members/register_failed.html:15 +#: members/templates/members/echo_failed.html:14 +#: members/templates/members/invited_registration_failed.html:14 +#: members/templates/members/register_failed.html:14 msgid "If you think this is a mistake, please" msgstr "Wenn du denkst, dass das ein Fehler ist, " #: members/templates/members/echo_failed.html:15 -#: members/templates/members/invited_registration_failed.html:15 +#: members/templates/members/invited_registration_failed.html:14 #: members/templates/members/register_failed.html:15 msgid "contact us." msgstr "kontaktiere uns." @@ -1091,14 +1095,14 @@ msgstr "" "Du hast zu oft ein falsches Passwort eingegeben. Bitte frage deinen " "Jugendleiter nach einem korrekten Passwort." -#: members/templates/members/invited_registration_failed.html:6 -#: members/templates/members/register_failed.html:6 +#: members/templates/members/invited_registration_failed.html:5 +#: members/templates/members/register_failed.html:5 msgid "Registration failed" msgstr "Registrierung fehlgeschlagen" -#: members/templates/members/invited_registration_failed.html:11 +#: members/templates/members/invited_registration_failed.html:10 #: members/templates/members/register.html:6 -#: members/templates/members/register_failed.html:11 +#: members/templates/members/register_failed.html:10 #: members/templates/members/register_password.html:6 #: members/templates/members/register_success.html:6 #: members/templates/members/register_wrong_password.html:6 @@ -1183,7 +1187,7 @@ msgstr "Registrieren" msgid "Here you can register for group" msgstr "Hier kannst du dich registrieren für die Gruppe" -#: members/templates/members/register_failed.html:13 +#: members/templates/members/register_failed.html:12 msgid "Something went wrong while processing your registration." msgstr "Etwas ist schief gelaufen, bei der Verarbeitung deiner Registrierung." diff --git a/jdav_web/members/migrations/0027_alter_group_weekday.py b/jdav_web/members/migrations/0027_alter_group_weekday.py new file mode 100644 index 0000000..1713448 --- /dev/null +++ b/jdav_web/members/migrations/0027_alter_group_weekday.py @@ -0,0 +1,18 @@ +# Generated by Django 4.0.1 on 2024-11-27 22:16 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('members', '0026_alter_emergencycontact_email'), + ] + + operations = [ + migrations.AlterField( + model_name='group', + name='weekday', + field=models.IntegerField(blank=True, choices=[(0, 'Monday'), (1, 'Tuesday'), (2, 'Wednesday'), (3, 'Thursday'), (4, 'Friday'), (5, 'Saturday'), (6, 'Sunday')], null=True, verbose_name='week day'), + ), + ] diff --git a/jdav_web/members/migrations/0028_group_contact_email.py b/jdav_web/members/migrations/0028_group_contact_email.py new file mode 100644 index 0000000..3f8d948 --- /dev/null +++ b/jdav_web/members/migrations/0028_group_contact_email.py @@ -0,0 +1,20 @@ +# Generated by Django 4.0.1 on 2024-11-27 22:40 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('mailer', '0005_alter_emailaddress_name'), + ('members', '0027_alter_group_weekday'), + ] + + operations = [ + migrations.AddField( + model_name='group', + name='contact_email', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='mailer.emailaddress', verbose_name='Contact email'), + ), + ] diff --git a/jdav_web/members/models.py b/jdav_web/members/models.py index 4775e38..ebe3f47 100644 --- a/jdav_web/members/models.py +++ b/jdav_web/members/models.py @@ -73,9 +73,14 @@ class Group(models.Model): year_to = models.IntegerField(verbose_name=_('highest year'), default=2011) leiters = models.ManyToManyField('members.Member', verbose_name=_('youth leaders'), related_name='leited_groups', blank=True) - weekday = models.IntegerField(choices=WEEKDAYS, null=True, blank=True) + weekday = models.IntegerField(verbose_name=_('week day'), choices=WEEKDAYS, null=True, blank=True) start_time = models.TimeField(verbose_name=_('Starting time'), null=True, blank=True) end_time = models.TimeField(verbose_name=_('Ending time'), null=True, blank=True) + contact_email = models.ForeignKey('mailer.EmailAddress', + verbose_name=_('Contact email'), + null=True, + blank=True, + on_delete=models.SET_NULL) def __str__(self): """String representation""" @@ -85,6 +90,10 @@ class Group(models.Model): verbose_name = _('group') verbose_name_plural = _('groups') + def has_time_info(self): + # return if the group has all relevant time slot information filled + return self.weekday and self.start_time and self.end_time + class MemberManager(models.Manager): def get_queryset(self): @@ -154,9 +163,9 @@ class Contact(CommonModel): return getattr(self, email_fd) return None - def send_mail(self, subject, content): + def send_mail(self, subject, content, cc=None): send_mail(subject, content, settings.DEFAULT_SENDING_MAIL, - [getattr(self, email_fd) for email_fd, _, _ in self.email_fields]) + [getattr(self, email_fd) for email_fd, _, _ in self.email_fields], cc=cc) def confirm_mail_by_key(key): @@ -849,21 +858,23 @@ class MemberWaitingList(Person): group_link = '({url}) '.format(url=prepend_base_url(reverse('startpage:gruppe_detail', args=[group.name]))) else: group_link = '' - # TODO: inform the user that the group has no configured weekday, start_time or end_time - weekday = WEEKDAYS[group.weekday][1] if group.weekday != None else WEEKDAYS[0][1] - start_time = group.start_time.strftime('%H:%M') if group.start_time != None else "14:00" - end_time = group.end_time.strftime('%H:%M') if group.end_time != None else "16:00" + if group.has_time_info(): + group_time = settings.GROUP_TIME_AVAILABLE_TEXT.format(weekday=WEEKDAYS[group.weekday][1], + start_time=group.start_time.strftime('%H:%M'), + end_time=group.end_time.strftime('%H:%M')) + else: + group_time = settings.GROUP_TIME_UNAVAILABLE_TEXT.format(contact_email=group.contact_email) invitation = InvitationToGroup(group=group, waiter=self) invitation.save() self.send_mail(_("Invitation to trial group meeting"), settings.INVITE_TEXT.format(name=self.prename, - weekday=weekday, - start_time=start_time, - end_time=end_time, - group_name=group.name, - group_link=group_link, - link=get_registration_link(invitation.key), - invitation_reject_link=get_invitation_reject_link(invitation.key))) + group_time=group_time, + group_name=group.name, + group_link=group_link, + contact_email=group.contact_email, + link=get_registration_link(invitation.key), + invitation_reject_link=get_invitation_reject_link(invitation.key)), + cc=group.contact_email.email) def unregister(self): """Delete the waiter and inform them about the deletion via email.""" From b22a891157ecaec7cb9043c800cc8b39f0f564df Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Thu, 28 Nov 2024 00:01:48 +0100 Subject: [PATCH 10/56] chore: update translations --- jdav_web/locale/de/LC_MESSAGES/django.po | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/jdav_web/locale/de/LC_MESSAGES/django.po b/jdav_web/locale/de/LC_MESSAGES/django.po index 0517c44..d83aa2c 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: 2024-11-24 22:24+0100\n" +"POT-Creation-Date: 2024-11-27 23:16+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -67,28 +67,28 @@ msgstr "Aktives Registrierungspasswort" msgid "Active registration passwords" msgstr "Aktive Registrierungspasswörter" -#: logindata/templates/logindata/register_failed.html:6 +#: logindata/templates/logindata/register_failed.html:5 msgid "Registration" msgstr "Registrierung" -#: logindata/templates/logindata/register_failed.html:11 +#: logindata/templates/logindata/register_failed.html:10 #: logindata/templates/logindata/register_form.html:13 #: logindata/templates/logindata/register_password.html:11 #: logindata/templates/logindata/register_success.html:10 msgid "Set login data" msgstr "Zugangsdaten wählen" -#: logindata/templates/logindata/register_failed.html:13 +#: logindata/templates/logindata/register_failed.html:12 msgid "Something went wrong. The registration key is invalid or has expired." msgstr "" "Etwas ist schief gegangen. Der Registrierungscode ist ungültig oder ist " "abgelaufen." -#: logindata/templates/logindata/register_failed.html:15 +#: logindata/templates/logindata/register_failed.html:14 msgid "If you think this is a mistake, please" msgstr "Falls du denkst, dass das ein Fehler ist, bitte" -#: logindata/templates/logindata/register_failed.html:15 +#: logindata/templates/logindata/register_failed.html:14 msgid "contact us." msgstr "kontaktiere uns." @@ -210,25 +210,28 @@ msgstr "Zusammenfassung" msgid "Objects" msgstr "Objekte" -#: templates/admin/edit_inline/tabular.html:33 -msgid "Delete?" -msgstr "Löschen?" - +#: templates/admin/edit_inline/stacked.html:20 #: templates/admin/edit_inline/tabular.html:47 #: templates/nesting/admin/inlines/stacked.html:42 msgid "Change" msgstr "Ändern" +#: templates/admin/edit_inline/stacked.html:20 #: templates/admin/edit_inline/tabular.html:47 #: templates/nesting/admin/inlines/stacked.html:42 msgid "View" msgstr "Anzeigen" +#: templates/admin/edit_inline/stacked.html:22 #: templates/admin/edit_inline/tabular.html:49 #: templates/nesting/admin/inlines/stacked.html:44 msgid "View on site" msgstr "Auf der Website anzeigen" +#: templates/admin/edit_inline/tabular.html:33 +msgid "Delete?" +msgstr "Löschen?" + #: templates/admin/finance/statementconfirmed/change_form_object_tools.html:8 msgid "Unconfirm" msgstr "Bestätigung zurücknehmen" From ed445a9bc679ff3ed1d61d4ed2c5eb3c6717f20c Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Thu, 28 Nov 2024 00:09:09 +0100 Subject: [PATCH 11/56] members: update translations --- .../members/locale/de/LC_MESSAGES/django.po | 324 +++++++++--------- 1 file changed, 169 insertions(+), 155 deletions(-) diff --git a/jdav_web/members/locale/de/LC_MESSAGES/django.po b/jdav_web/members/locale/de/LC_MESSAGES/django.po index 57f0cbd..6e0fabd 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: 2024-11-27 23:16+0100\n" +"POT-Creation-Date: 2024-11-28 00:04+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,7 +18,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: members/admin.py:126 members/models.py:373 +#: members/admin.py:126 members/models.py:382 msgid "Registration complete" msgstr "Anmeldung vollständig" @@ -109,7 +109,7 @@ msgstr "" msgid "activity" msgstr "Aktivität" -#: members/admin.py:374 members/models.py:53 members/models.py:1390 +#: members/admin.py:374 members/models.py:53 members/models.py:1401 msgid "Name" msgstr "Name" @@ -155,8 +155,8 @@ msgstr "%(name)s zurück auf die Warteliste gesetzt." msgid "Demote selected registrations to waiters." msgstr "Ausgewählte Registrierungen zurück auf die Warteliste setzen." -#: members/admin.py:498 members/models.py:380 members/models.py:729 -#: members/models.py:1135 +#: members/admin.py:498 members/models.py:389 members/models.py:738 +#: members/models.py:1146 msgid "Group" msgstr "Gruppe" @@ -169,39 +169,47 @@ msgstr "Erfolgreich %(name)s aufgefordert den Wartelistenplatz zu bestätigen." msgid "Ask selected waiters to confirm their waiting status" msgstr "Wartende auffordern den Wartelistenplatz zu bestätigen" -#: members/admin.py:542 members/admin.py:598 +#: members/admin.py:542 members/admin.py:602 msgid "" "An error occurred while trying to invite said members. Please try again." msgstr "" "Beim Einladen dieser Personen ist ein Fehler aufgetreten. Bitte versuche es " "nochmal. " -#: members/admin.py:550 members/admin.py:605 +#: members/admin.py:546 members/admin.py:607 +msgid "" +"The selected group does not have a contact email. Please first set a contact " +"email and then try again." +msgstr "" +"Die ausgewählte Gruppe hat keine Kontakt E-Mail Adresse. Bitte stelle eine " +"Kontakt E-Mail Adresse ein und versuche es erneut." + +#: members/admin.py:554 members/admin.py:614 #, python-format msgid "Successfully invited %(name)s to %(group)s." msgstr "Erfolgreich %(name)s zu Gruppe %(group)s eingeladen." -#: members/admin.py:554 members/admin.py:611 +#: members/admin.py:558 members/admin.py:620 msgid "Select group for invitation" msgstr "Wähle Gruppe für Einladung aus" -#: members/admin.py:561 +#: members/admin.py:565 msgid "Offer waiter a place in a group." msgstr "Personen auf der Warteliste einen Gruppenplatz anbieten." -#: members/admin.py:654 +#: members/admin.py:663 msgid "Difficulty" msgstr "Schwierigkeit" -#: members/admin.py:657 +#: members/admin.py:666 msgid "Tour type" msgstr "Art der Tour" -#: members/admin.py:660 members/models.py:945 +#: members/admin.py:669 members/models.py:956 msgid "Means of transportation" msgstr "Verkehrsmittel" -#: members/admin.py:686 +#: members/admin.py:695 msgid "" "Please list here all expenses in relation with this excursion and upload " "relevant bills. These have to be permanently stored for the application of " @@ -214,7 +222,7 @@ msgstr "" "einzelnen Posten wird dabei auf der LJP-Kostenübersicht angezeigt (sinnvoll " "wären z.B. Anreise, Verpflegung, Material etc.)." -#: members/admin.py:704 +#: members/admin.py:713 msgid "" "Here you can work on a seminar report for applying for financial " "contributions from Landesjugendplan (LJP). More information on creating a " @@ -227,7 +235,7 @@ msgstr "" "wahlweise nur TN-Liste und Kostenübersicht kannst du anschließend " "herunterladen." -#: members/admin.py:712 +#: members/admin.py:721 msgid "" "Please list all participants (also youth leaders) of this excursion. Here " "you can still make changes just before departure and hence generate the " @@ -238,30 +246,30 @@ msgstr "" "jederzeit die aktuelle Teilnehmer:innenliste für die Krisenintervention " "generieren." -#: members/admin.py:758 +#: members/admin.py:767 #, python-format msgid "You are not allowed to view all members on note list %(name)s." msgstr "" "Du hast nicht die nötigen Rechte um alle Teilnehmer:innen der Notizliste " "%(name)s anzusehen." -#: members/admin.py:768 +#: members/admin.py:777 msgid "Generate PDF summary" msgstr "Übersicht erstellen" -#: members/admin.py:772 +#: members/admin.py:781 msgid "Full report" msgstr "Vollständiger Seminarbericht" -#: members/admin.py:773 +#: members/admin.py:782 msgid "Costs and participants only" msgstr "Nur Kosten und Teilnehmende" -#: members/admin.py:774 +#: members/admin.py:783 msgid "Mode" msgstr "Modus" -#: members/admin.py:788 +#: members/admin.py:797 msgid "" "General information on your excursion. These are partly relevant for the " "amount of financial compensation (means of transport, travel distance, etc.)." @@ -270,38 +278,38 @@ msgstr "" "teilweise relevant für die Zuschüsse aus dem Jugendetat (Verkehrsmittel, " "Fahrstrecke in km)." -#: members/admin.py:818 +#: members/admin.py:827 #, python-format msgid "You are not allowed to view all members on excursion %(name)s." msgstr "" "Du hast nicht die nötigen Rechte um alle Teilnehmer:innen der Ausfahrt " "%(name)s anzusehen." -#: members/admin.py:826 +#: members/admin.py:835 msgid "Generate crisis intervention list" msgstr "Kriseninterventionsliste erstellen" -#: members/admin.py:834 +#: members/admin.py:843 msgid "Generate overview" msgstr "Hinweise für Jugendleiter erstellen" -#: members/admin.py:838 members/admin.py:861 +#: members/admin.py:847 members/admin.py:870 #: members/templates/admin/generate_seminar_report.html:21 msgid "Generate seminar report" msgstr "Seminarbericht erstellen" -#: members/admin.py:851 +#: members/admin.py:860 msgid "Please select a mode." msgstr "Bitte wähle einen Modus aus." -#: members/admin.py:855 +#: members/admin.py:864 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:873 +#: members/admin.py:882 msgid "Generate SJR application" msgstr "SJR Antrag erstellen" @@ -337,11 +345,11 @@ msgstr "Samstag" msgid "Sunday" msgstr "Sonntag" -#: members/models.py:54 members/models.py:931 +#: members/models.py:54 members/models.py:942 msgid "Description" msgstr "Beschreibung" -#: members/models.py:60 members/models.py:923 +#: members/models.py:60 members/models.py:934 #: members/templates/members/change_member.html:18 msgid "Activity" msgstr "Aktivität" @@ -378,7 +386,7 @@ msgstr "Jugendleiter" msgid "week day" msgstr "Wochentag" -#: members/models.py:77 members/models.py:1217 +#: members/models.py:77 members/models.py:1228 msgid "Starting time" msgstr "Zeitpunkt" @@ -386,498 +394,504 @@ msgstr "Zeitpunkt" msgid "Ending time" msgstr "Endzeitpunkt" -#: members/models.py:85 members/models.py:249 +#: members/models.py:80 +#, fuzzy +#| msgid "Contact information" +msgid "Contact email" +msgstr "Kontaktinformationen" + +#: members/models.py:90 members/models.py:258 msgid "group" msgstr "Gruppe" -#: members/models.py:86 +#: members/models.py:91 msgid "groups" msgstr "Gruppen" -#: members/models.py:98 +#: members/models.py:107 msgid "prename" msgstr "Vorname" -#: members/models.py:99 +#: members/models.py:108 msgid "last name" msgstr "Nachname" -#: members/models.py:102 +#: members/models.py:111 msgid "Email confirmed" msgstr "Emailadresse bestätigt" -#: members/models.py:139 +#: members/models.py:148 msgid "Email confirmation needed" msgstr "Email Bestätigung erforderlich" -#: members/models.py:179 members/models.py:223 +#: members/models.py:188 members/models.py:232 msgid "phone number" msgstr "Telefonnummer (mobil)" -#: members/models.py:189 +#: members/models.py:198 msgid "birth date" msgstr "Geburtsdatum" -#: members/models.py:195 +#: members/models.py:204 msgid "Gender" msgstr "Gender" -#: members/models.py:196 +#: members/models.py:205 msgid "comments" msgstr "Kommentare" -#: members/models.py:220 +#: members/models.py:229 msgid "Alternative email confirmed" msgstr "Alternative E-Mail Adresse bestätigt" -#: members/models.py:224 +#: members/models.py:233 msgid "street and house number" msgstr "Straße und Hausnummer" -#: members/models.py:225 +#: members/models.py:234 msgid "Postcode" msgstr "PLZ" -#: members/models.py:227 +#: members/models.py:236 msgid "town" msgstr "Stadt" -#: members/models.py:228 +#: members/models.py:237 msgid "Address extra" msgstr "Adress-Zusatz" -#: members/models.py:229 +#: members/models.py:238 msgid "Country" msgstr "Land" -#: members/models.py:231 +#: members/models.py:240 msgid "Good conduct certificate presented on" msgstr "Führungszeugnis vorgelegt am" -#: members/models.py:232 +#: members/models.py:241 msgid "Joined on" msgstr "Eintritt" -#: members/models.py:233 +#: members/models.py:242 msgid "Left on" msgstr "Austritt" -#: members/models.py:234 +#: members/models.py:243 msgid "Has key" msgstr "Hat Jugendraumschlüssel" -#: members/models.py:235 +#: members/models.py:244 msgid "Has a free ticket for the climbing gym" msgstr "Hat Freikarte für Kletterhalle" -#: members/models.py:236 +#: members/models.py:245 msgid "DAV badge number" msgstr "DAV Mitgliedsnummer" -#: members/models.py:237 +#: members/models.py:246 msgid "Knows how to swim" msgstr "Kann schwimmen" -#: members/models.py:238 +#: members/models.py:247 msgid "Climbing badge" msgstr "Kletterschein" -#: members/models.py:239 +#: members/models.py:248 msgid "Alpine experience" msgstr "Alpine Erfahrung" -#: members/models.py:240 +#: members/models.py:249 msgid "Allergies" msgstr "Allergieen" -#: members/models.py:241 +#: members/models.py:250 msgid "Medication" msgstr "Medikamente" -#: members/models.py:242 +#: members/models.py:251 msgid "Tetanus vaccination" msgstr "Tetanusimpfung" -#: members/models.py:243 +#: members/models.py:252 msgid "Photos may be taken" msgstr "Fotoerlaubnis" -#: members/models.py:244 +#: members/models.py:253 msgid "Legal guardians" msgstr "Erziehungsberechtigte" -#: members/models.py:246 +#: members/models.py:255 msgid "May cancel a group appointment independently" msgstr "Darf sich allein von der Gruppenstunde abmelden" -#: members/models.py:253 +#: members/models.py:262 msgid "receives newsletter" msgstr "Erhält den Newsletter" -#: members/models.py:257 +#: members/models.py:266 msgid "created" msgstr "erstellt" -#: members/models.py:258 +#: members/models.py:267 msgid "Active" msgstr "Aktiv" -#: members/models.py:259 +#: members/models.py:268 msgid "registration form" msgstr "Anmeldeformular" -#: members/models.py:267 +#: members/models.py:276 msgid "image" msgstr "Bild" -#: members/models.py:276 +#: members/models.py:285 msgid "Echoed" msgstr "Rückgemeldet" -#: members/models.py:277 +#: members/models.py:286 msgid "Confirmed" msgstr "Bestätigt" -#: members/models.py:279 +#: members/models.py:288 msgid "Login data" msgstr "Zugangsdaten" -#: members/models.py:309 +#: members/models.py:318 msgid "Good conduct certificate valid" msgstr "Führungszeugnis gültig" -#: members/models.py:383 +#: members/models.py:392 msgid "member" msgstr "Teilnehmer" -#: members/models.py:384 +#: members/models.py:393 msgid "members" msgstr "Teilnehmer" -#: members/models.py:457 +#: members/models.py:466 #, python-format msgid "New unconfirmed registration for group %(group)s" msgstr "Neue unbestätigte Registrierung für Gruppe %(group)s" -#: members/models.py:668 +#: members/models.py:677 msgid "Set login data for Kompass" msgstr "Zugangsdaten für Kompass wählen" -#: members/models.py:685 members/models.py:879 members/models.py:890 -#: members/models.py:1166 members/models.py:1173 +#: members/models.py:694 members/models.py:890 members/models.py:901 +#: members/models.py:1177 members/models.py:1184 msgid "Member" msgstr "Teilnehmer" -#: members/models.py:692 +#: members/models.py:701 msgid "Emergency contact" msgstr "Notfallkontakt" -#: members/models.py:693 +#: members/models.py:702 msgid "Emergency contacts" msgstr "Notfallkontakte" -#: members/models.py:713 +#: members/models.py:722 msgid "Unconfirmed registration" msgstr "Unbestätigte Registrierung" -#: members/models.py:714 +#: members/models.py:723 msgid "Unconfirmed registrations" msgstr "Unbestätigte Registrierungen" -#: members/models.py:728 members/models.py:773 +#: members/models.py:737 members/models.py:782 msgid "Waiter" msgstr "Wartende Person" -#: members/models.py:730 +#: members/models.py:739 msgid "Invitation date" msgstr "Einladungsdatum" -#: members/models.py:731 members/templates/members/reject_success.html:6 +#: members/models.py:740 members/templates/members/reject_success.html:6 #: members/templates/members/reject_success.html:11 msgid "Invitation rejected" msgstr "Einladung abgelehnt" -#: members/models.py:735 +#: members/models.py:744 msgid "Invitation to group" msgstr "Gruppeneinladung" -#: members/models.py:736 +#: members/models.py:745 msgid "Invitations to groups" msgstr "Gruppeneinladungen" -#: members/models.py:743 +#: members/models.py:752 msgid "Rejected" msgstr "Abgelehnt" -#: members/models.py:745 +#: members/models.py:754 msgid "Expired" msgstr "Abgelaufen" -#: members/models.py:747 +#: members/models.py:756 msgid "Undecided" msgstr "Ausstehend" -#: members/models.py:748 +#: members/models.py:757 msgid "Status" msgstr "Status" -#: members/models.py:759 +#: members/models.py:768 msgid "Do you want to tell us something else?" msgstr "Möchtest du uns noch etwas mitteilen?" -#: members/models.py:760 +#: members/models.py:769 msgid "application date" msgstr "Bewerbungsdatum" -#: members/models.py:762 +#: members/models.py:771 msgid "Last wait confirmation" msgstr "Letzte Wartebestätigung" -#: members/models.py:766 +#: members/models.py:775 msgid "Last reminder" msgstr "Letzte Erinnerung" -#: members/models.py:767 +#: members/models.py:776 msgid "Missed reminders" msgstr "Verpasste Erinnerungen" -#: members/models.py:774 +#: members/models.py:783 msgid "Waiters" msgstr "Warteliste" -#: members/models.py:798 +#: members/models.py:807 msgid "Waiting status confirmed" msgstr "Wartelistenplatz bestätigt" -#: members/models.py:805 +#: members/models.py:814 msgid "Waiting confirmation needed" msgstr "Wartelistenplatzbestätigung erforderlich" -#: members/models.py:858 +#: members/models.py:869 msgid "Invitation to trial group meeting" msgstr "Einladung zu Schnupperstunde" -#: members/models.py:870 +#: members/models.py:881 msgid "Unregistered from waiting list" msgstr "Von der Warteliste abgemeldet" -#: members/models.py:884 +#: members/models.py:895 msgid "Comment" msgstr "Kommentar" -#: members/models.py:891 members/models.py:1174 +#: members/models.py:902 members/models.py:1185 msgid "Members" msgstr "Teilnehmer" -#: members/models.py:925 +#: members/models.py:936 msgid "Place" msgstr "Stützpunkt / Ort" -#: members/models.py:926 +#: members/models.py:937 msgid "Destination (optional)" msgstr "ggf. Ziel" -#: members/models.py:928 +#: members/models.py:939 msgid "e.g. a peak" msgstr "z.B. ein Gipfel" -#: members/models.py:929 +#: members/models.py:940 msgid "Begin" msgstr "Anfang" -#: members/models.py:930 +#: members/models.py:941 msgid "End (optional)" msgstr "Ende" -#: members/models.py:933 +#: members/models.py:944 msgid "Groups" msgstr "Gruppen" -#: members/models.py:946 +#: members/models.py:957 msgid "Kilometers traveled" msgstr "Fahrstrecke in Kilometer" -#: members/models.py:949 +#: members/models.py:960 msgid "Categories" msgstr "Kategorien" -#: members/models.py:950 +#: members/models.py:961 msgid "easy" msgstr "leicht" -#: members/models.py:950 +#: members/models.py:961 msgid "medium" msgstr "mittel" -#: members/models.py:950 +#: members/models.py:961 msgid "hard" msgstr "schwer" -#: members/models.py:960 members/models.py:1197 +#: members/models.py:971 members/models.py:1208 msgid "Excursion" msgstr "Ausfahrt" -#: members/models.py:961 +#: members/models.py:972 msgid "Excursions" msgstr "Ausfahrten" -#: members/models.py:1112 members/models.py:1188 members/models.py:1404 +#: members/models.py:1123 members/models.py:1199 members/models.py:1415 msgid "Title" msgstr "Titel" -#: members/models.py:1113 members/models.py:1131 members/models.py:1405 +#: members/models.py:1124 members/models.py:1142 members/models.py:1416 msgid "Date" msgstr "Datum" -#: members/models.py:1132 +#: members/models.py:1143 msgid "Location" msgstr "Ort" -#: members/models.py:1133 +#: members/models.py:1144 msgid "Topic" msgstr "Thema" -#: members/models.py:1157 +#: members/models.py:1168 msgid "Jugendleiter" msgstr "Jugendleiter" -#: members/models.py:1160 +#: members/models.py:1171 msgid "Klettertreff" msgstr "Klettertreff" -#: members/models.py:1161 +#: members/models.py:1172 msgid "Klettertreffs" msgstr "Klettertreffs" -#: members/models.py:1179 +#: members/models.py:1190 msgid "Password" msgstr "Passwort" -#: members/models.py:1182 +#: members/models.py:1193 msgid "registration password" msgstr "Registrierungspassort" -#: members/models.py:1183 +#: members/models.py:1194 msgid "registration passwords" msgstr "Registrierungspasswörter" -#: members/models.py:1190 +#: members/models.py:1201 msgid "Alpinistic goals" msgstr "Alpintechnische Ziele" -#: members/models.py:1191 +#: members/models.py:1202 msgid "Pedagogic goals" msgstr "Pädagogische Ziele" -#: members/models.py:1192 +#: members/models.py:1203 msgid "Content and methods" msgstr "Inhalte und Methoden" -#: members/models.py:1193 +#: members/models.py:1204 msgid "Evaluation" msgstr "Wertung" -#: members/models.py:1194 +#: members/models.py:1205 msgid "Experiences and possible improvements" msgstr "Erfahrungen und Verbesserungsvorschläge" -#: members/models.py:1203 members/models.py:1224 +#: members/models.py:1214 members/models.py:1235 msgid "LJP Proposal" msgstr "Seminarbericht" -#: members/models.py:1204 +#: members/models.py:1215 msgid "LJP Proposals" msgstr "Seminarberichte" -#: members/models.py:1218 +#: members/models.py:1229 msgid "Duration in hours" msgstr "Dauer in Stunden" -#: members/models.py:1221 +#: members/models.py:1232 msgid "Activity and method" msgstr "Art der Aktion inkl. Methode" -#: members/models.py:1229 +#: members/models.py:1240 msgid "Intervention" msgstr "Aktion" -#: members/models.py:1230 +#: members/models.py:1241 msgid "Interventions" msgstr "Aktionen" -#: members/models.py:1332 members/models.py:1362 +#: members/models.py:1343 members/models.py:1373 msgid "May list members" msgstr "Darf folgende Teilnehmer:innen listen" -#: members/models.py:1334 members/models.py:1364 +#: members/models.py:1345 members/models.py:1375 msgid "May view members" msgstr "Darf folgende Teilnehmer:innen anzeigen" -#: members/models.py:1336 members/models.py:1366 +#: members/models.py:1347 members/models.py:1377 msgid "May change members" msgstr "Darf folgende Teilnehmer:innen ändern" -#: members/models.py:1338 members/models.py:1368 +#: members/models.py:1349 members/models.py:1379 msgid "May delete members" msgstr "Darf folgende Teilnehmer:innen löschen" -#: members/models.py:1342 members/models.py:1372 +#: members/models.py:1353 members/models.py:1383 msgid "May list members of groups" msgstr "Darf Teilnehmer:innen folgender Gruppen listen" -#: members/models.py:1344 members/models.py:1374 +#: members/models.py:1355 members/models.py:1385 msgid "May view members of groups" msgstr "Darf Teilnehmer:innen folgender Gruppen anzeigen" -#: members/models.py:1346 members/models.py:1376 +#: members/models.py:1357 members/models.py:1387 msgid "May change members of groups" msgstr "Darf Teilnehmer:innen folgender Gruppen ändern" -#: members/models.py:1348 members/models.py:1378 +#: members/models.py:1359 members/models.py:1389 msgid "May delete members of groups" msgstr "Darf Teilnehmer:innen folgender Gruppen löschen" -#: members/models.py:1351 members/models.py:1352 members/models.py:1355 +#: members/models.py:1362 members/models.py:1363 members/models.py:1366 msgid "Permissions" msgstr "Berechtigungen" -#: members/models.py:1381 members/models.py:1382 members/models.py:1385 +#: members/models.py:1392 members/models.py:1393 members/models.py:1396 msgid "Group permissions" msgstr "Gruppenberechtigungen" -#: members/models.py:1391 +#: members/models.py:1402 msgid "Permission needed" msgstr "Freigabe erforderlich" -#: members/models.py:1394 +#: members/models.py:1405 msgid "Training category" msgstr "Fortbildungstyp" -#: members/models.py:1395 +#: members/models.py:1406 msgid "Training categories" msgstr "Fortbildungstypen" -#: members/models.py:1406 +#: members/models.py:1417 msgid "Category" msgstr "Kategorien" -#: members/models.py:1407 +#: members/models.py:1418 msgid "Comments" msgstr "Kommentar" -#: members/models.py:1408 +#: members/models.py:1419 msgid "Participated" msgstr "Teilgenommmen" -#: members/models.py:1409 +#: members/models.py:1420 msgid "Passed" msgstr "Bestanden" -#: members/models.py:1412 +#: members/models.py:1423 msgid "Training" msgstr "Fortbildung" -#: members/models.py:1413 +#: members/models.py:1424 msgid "Trainings" msgstr "Fortbildungen" From 02db0669cd77eb1b2d83193c4d1d1b575912081c Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Thu, 28 Nov 2024 00:12:21 +0100 Subject: [PATCH 12/56] members: don't request mail confirmation of emergency contacts --- jdav_web/members/admin.py | 3 +-- jdav_web/members/models.py | 5 ----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/jdav_web/members/admin.py b/jdav_web/members/admin.py index de8128f..31de6a6 100644 --- a/jdav_web/members/admin.py +++ b/jdav_web/members/admin.py @@ -112,8 +112,7 @@ class EmergencyContactInline(CommonAdminInlineMixin, admin.TabularInline): formfield_overrides = { TextField: {'widget': Textarea(attrs={'rows': 1, 'cols': 40})} } - fields = ['prename', 'lastname', 'email', 'phone_number', 'confirmed_mail'] - readonly_fields = ['confirmed_mail'] + fields = ['prename', 'lastname', 'email', 'phone_number'] extra = 0 diff --git a/jdav_web/members/models.py b/jdav_web/members/models.py index ebe3f47..d15664f 100644 --- a/jdav_web/members/models.py +++ b/jdav_web/members/models.py @@ -445,11 +445,6 @@ class Member(Person): return not self.confirmed and self.confirmed_alternative_mail and self.confirmed_mail and\ all([emc.confirmed_mail for emc in self.emergencycontact_set.all()]) - def request_mail_confirmation(self, rerequest=False): - ret = super().request_mail_confirmation(rerequest) - rets = [emc.request_mail_confirmation(rerequest) for emc in self.emergencycontact_set.all()] - return ret or any(rets) - def confirm_mail(self, key): ret = super().confirm_mail(key) if self.registration_ready(): From bb91d77cfc168d3915ebfcb08947afd6b8140edf Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Thu, 28 Nov 2024 00:23:00 +0100 Subject: [PATCH 13/56] members/views: fix prefilling of date inputs --- jdav_web/members/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdav_web/members/views.py b/jdav_web/members/views.py index 0bb9cdc..f737976 100644 --- a/jdav_web/members/views.py +++ b/jdav_web/members/views.py @@ -29,7 +29,7 @@ class MemberRegistrationForm(ModelForm): 'phone_number', 'birth_date', 'gender', 'email', 'alternative_email', 'registration_form'] widgets = { - 'birth_date': DateInput(format='%d.%m.%Y', attrs={'type': 'date'}), + 'birth_date': DateInput(format='%Y-%m-%d', attrs={'type': 'date'}), 'registration_form': FileInput(attrs={'accept': 'application/pdf,image/jpeg,image/png'}), } help_texts = { @@ -53,7 +53,7 @@ class MemberRegistrationWaitingListForm(ModelForm): model = MemberWaitingList fields = ['prename', 'lastname', 'birth_date', 'gender', 'email', 'application_text'] widgets = { - 'birth_date': DateInput(format='%d.%m.%Y', attrs={'type': 'date'}) + 'birth_date': DateInput(format='%Y-%m-%d', attrs={'type': 'date'}) } help_texts = { 'prename': _('Prename of the member.'), From 18d5f5e9899eff38bce3e37d5d70826e62c02c01 Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Thu, 28 Nov 2024 00:53:57 +0100 Subject: [PATCH 14/56] dashboard: add mailer section --- jdav_web/jdav_web/settings/local.py | 1 + jdav_web/mailer/admin.py | 1 + jdav_web/templates/admin/index.html | 60 +++++++++++++++---- .../templates/admin/mailer/app_index.html | 55 +++++++++++++++++ 4 files changed, 105 insertions(+), 12 deletions(-) create mode 100644 jdav_web/templates/admin/mailer/app_index.html diff --git a/jdav_web/jdav_web/settings/local.py b/jdav_web/jdav_web/settings/local.py index 4e3d49e..d873429 100644 --- a/jdav_web/jdav_web/settings/local.py +++ b/jdav_web/jdav_web/settings/local.py @@ -10,6 +10,7 @@ SEKTION_BOARD_MAIL = "vorstand@alpenverein-heidelberg.de" SEKTION_CRISIS_INTERVENTION_MAIL = "krisenmanagement@alpenverein-heidelberg.de" RESPONSIBLE_MAIL = "jugendreferat@jdav-hd.de" +DIGITAL_MAIL = "digitales@jdav-hd.de" # echo diff --git a/jdav_web/mailer/admin.py b/jdav_web/mailer/admin.py index 6fc2a3f..780302f 100644 --- a/jdav_web/mailer/admin.py +++ b/jdav_web/mailer/admin.py @@ -36,6 +36,7 @@ class MessageAdmin(FilteredMemberFieldMixin, CommonAdminMixin, ObjectPermissions exclude = ('created_by',) list_display = ('subject', 'get_recipients', 'sent') search_fields = ('subject',) + list_filter = ('sent',) change_form_template = "mailer/change_form.html" readonly_fields = ('sent',) #formfield_overrides = { diff --git a/jdav_web/templates/admin/index.html b/jdav_web/templates/admin/index.html index 5ee62a8..aee2fbf 100644 --- a/jdav_web/templates/admin/index.html +++ b/jdav_web/templates/admin/index.html @@ -19,45 +19,81 @@ auf deine {% if user.member %} -
-

+

Deine Jugendgruppen

+

Hier siehst du alle von dir geleiteten Jugendgruppen.

{% for group in user.member.led_groups %} - + + + {% endfor %}
- {{ group.name }} - + {{ group.name }} +

-
-

+

Deine letzten Ausfahrten

+

Hier siehst du alle von dir geleiteten Ausfahrten.

{% for freizeit in user.member.led_freizeiten %} - + + {% endfor %}
+ {{freizeit.name}} - +

-
{% endif %} +
+ +

E-Mail Verteiler

+

+Hier kannst du E-Mails an deine Gruppe oder an andere Menschen in der JDAV Heidelberg schicken. +

+ + + + + + + + + + + + + + + + +
+ Verfassen +
+ Gesendet +
+ Entwürfe +
+ +
+
+ {% endblock %} {% block sidebar %} @@ -103,7 +139,7 @@ weiterweißt oder sonst der Schuh drückt, schreibe eine E-Mail an eine der folg Jugendreferat
- jugendreferat@jdav-hd.de + jugendreferat@jdav-hd.de
- digitales@jdav-hd.de + digitales@jdav-hd.de
diff --git a/jdav_web/templates/admin/mailer/app_index.html b/jdav_web/templates/admin/mailer/app_index.html new file mode 100644 index 0000000..a764c6b --- /dev/null +++ b/jdav_web/templates/admin/mailer/app_index.html @@ -0,0 +1,55 @@ +{% extends "admin/app_index.html" %} + +{% block content %} +
+
+

E-Mail Verteiler

+

+Hier kannst du E-Mails an deine Gruppe oder an andere Menschen in der JDAV Heidelberg schicken. +

+ + + + + + + + + + + + + + + + +
+ Verfassen +
+ Gesendet +
+ Entwürfe +
+ +{% if perms.mailer.change_emailaddress %} +
+
+

Weiterleitungen

+

+Hier kannst du E-Mail Adressen, also Weiterleitungen, konfigurieren. +

+ + + + + + +
+ E-Mail Adressen +
+ +
+
+{% endif %} + +{% endblock %} From fcfd1b0a9dd44a200f6bafda402668b663a33980 Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Thu, 28 Nov 2024 01:15:47 +0100 Subject: [PATCH 15/56] members: remove default from gender field --- ...r_gender_alter_memberwaitinglist_gender.py | 23 +++++++++++++++++++ jdav_web/members/models.py | 1 - 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 jdav_web/members/migrations/0029_alter_member_gender_alter_memberwaitinglist_gender.py diff --git a/jdav_web/members/migrations/0029_alter_member_gender_alter_memberwaitinglist_gender.py b/jdav_web/members/migrations/0029_alter_member_gender_alter_memberwaitinglist_gender.py new file mode 100644 index 0000000..3cee52d --- /dev/null +++ b/jdav_web/members/migrations/0029_alter_member_gender_alter_memberwaitinglist_gender.py @@ -0,0 +1,23 @@ +# Generated by Django 4.0.1 on 2024-11-28 00:16 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('members', '0028_group_contact_email'), + ] + + operations = [ + migrations.AlterField( + model_name='member', + name='gender', + field=models.IntegerField(choices=[(0, 'Männlich'), (1, 'Weiblich'), (2, 'Divers')], verbose_name='Gender'), + ), + migrations.AlterField( + model_name='memberwaitinglist', + name='gender', + field=models.IntegerField(choices=[(0, 'Männlich'), (1, 'Weiblich'), (2, 'Divers')], verbose_name='Gender'), + ), + ] diff --git a/jdav_web/members/models.py b/jdav_web/members/models.py index d15664f..6e302c7 100644 --- a/jdav_web/members/models.py +++ b/jdav_web/members/models.py @@ -200,7 +200,6 @@ class Person(Contact): (FEMALE, 'Weiblich'), (DIVERSE, 'Divers')) gender = models.IntegerField(choices=gender_choices, - default=DIVERSE, verbose_name=_('Gender')) comments = models.TextField(_('comments'), default='', blank=True) From 7b5c16f6b754cb39a5bd69dd40fa3ddd5ca76cea Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Thu, 28 Nov 2024 01:16:46 +0100 Subject: [PATCH 16/56] mailer: remove send to note list field --- jdav_web/mailer/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jdav_web/mailer/admin.py b/jdav_web/mailer/admin.py index 780302f..e59a3b5 100644 --- a/jdav_web/mailer/admin.py +++ b/jdav_web/mailer/admin.py @@ -33,7 +33,7 @@ class EmailAddressAdmin(FilteredMemberFieldMixin, admin.ModelAdmin): class MessageAdmin(FilteredMemberFieldMixin, CommonAdminMixin, ObjectPermissionsModelAdmin): """Message creation view""" - exclude = ('created_by',) + exclude = ('created_by', 'to_notelist') list_display = ('subject', 'get_recipients', 'sent') search_fields = ('subject',) list_filter = ('sent',) From d1db0b833f9acc2c03094252e39c448445ccbecc Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Fri, 29 Nov 2024 23:13:46 +0100 Subject: [PATCH 17/56] startpage: sort recent posts and reports --- jdav_web/startpage/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jdav_web/startpage/views.py b/jdav_web/startpage/views.py index dd84dc7..d7f6eba 100644 --- a/jdav_web/startpage/views.py +++ b/jdav_web/startpage/views.py @@ -22,8 +22,8 @@ def render(request, template_path, context={}): def index(request): context = { - 'recent_posts': Post.objects.filter(section__urlname=settings.RECENT_SECTION), - 'reports': Post.objects.filter(section__urlname=settings.REPORTS_SECTION), + 'recent_posts': Post.objects.filter(section__urlname=settings.RECENT_SECTION).order_by('-date'), + 'reports': Post.objects.filter(section__urlname=settings.REPORTS_SECTION).order_by('-date'), } return render(request, 'startpage/index.html', context) From d19da71fef0235d02413cda5c107c3bb3bd9ee60 Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Sat, 30 Nov 2024 01:25:28 +0100 Subject: [PATCH 18/56] members: add demote to waiter button and confirmation --- jdav_web/locale/de/LC_MESSAGES/django.po | 6 +- jdav_web/members/admin.py | 56 ++- .../members/locale/de/LC_MESSAGES/django.po | 409 +++++++++--------- .../templates/admin/demote_to_waiter.html | 48 ++ .../change_form_object_tools.html | 13 + 5 files changed, 330 insertions(+), 202 deletions(-) create mode 100644 jdav_web/members/templates/admin/demote_to_waiter.html create mode 100644 jdav_web/templates/admin/members/memberunconfirmedproxy/change_form_object_tools.html diff --git a/jdav_web/locale/de/LC_MESSAGES/django.po b/jdav_web/locale/de/LC_MESSAGES/django.po index d83aa2c..49905e1 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: 2024-11-27 23:16+0100\n" +"POT-Creation-Date: 2024-11-30 01:22+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -272,6 +272,10 @@ msgstr "Abrechnung einreichen" msgid "Invite as user" msgstr "Als Kompassbenutzer:in einladen" +#: templates/admin/members/memberunconfirmedproxy/change_form_object_tools.html:8 +msgid "Demote to waiter" +msgstr "Zurück auf die Warteliste setzen" + #: templates/admin/members/memberwaitinglist/change_form_object_tools.html:8 #: templates/admin/members/memberwaitinglist/submit_line.html:9 msgid "Invite to group" diff --git a/jdav_web/members/admin.py b/jdav_web/members/admin.py index 31de6a6..ed28f4d 100644 --- a/jdav_web/members/admin.py +++ b/jdav_web/members/admin.py @@ -374,7 +374,11 @@ class MemberAdmin(CommonAdminMixin, admin.ModelAdmin): name_text_or_link.admin_order_field = 'lastname' -class MemberUnconfirmedAdmin(admin.ModelAdmin): +class DemoteToWaiterForm(forms.Form): + _selected_action = forms.CharField(widget=forms.MultipleHiddenInput) + + +class MemberUnconfirmedAdmin(CommonAdminMixin, admin.ModelAdmin): fieldsets = [ (None, { @@ -422,7 +426,7 @@ class MemberUnconfirmedAdmin(admin.ModelAdmin): list_filter = ('group', 'confirmed_mail', 'confirmed_alternative_mail') readonly_fields = ['confirmed_mail', 'confirmed_alternative_mail', 'good_conduct_certificate_valid'] - actions = ['request_mail_confirmation', 'confirm', 'demote_to_waiter'] + actions = ['request_mail_confirmation', 'confirm', 'demote_to_waiter_action'] inlines = [EmergencyContactInline] change_form_template = "members/change_member_unconfirmed.html" @@ -464,22 +468,62 @@ class MemberUnconfirmedAdmin(admin.ModelAdmin): messages.error(request, _("Failed to confirm some registrations because of unconfirmed email addresses.")) confirm.short_description = _('Confirm selected registrations') + def get_urls(self): + urls = super().get_urls() + + def wrap(view): + def wrapper(*args, **kwargs): + return self.admin_site.admin_view(view)(*args, **kwargs) + + wrapper.model_admin = self + return update_wrapper(wrapper, view) + + custom_urls = [ + path( + "/demote/", + wrap(self.demote_to_waiter_view), + name="%s_%s_demote" % (self.opts.app_label, self.opts.model_name), + ), + ] + return custom_urls + urls + + def demote_to_waiter_action(self, request, queryset): + return self.demote_to_waiter_view(request, queryset) + demote_to_waiter_action.short_description = _('Demote selected registrations to waiters.') + + def demote_to_waiter_view(self, request, object_id): + if type(object_id) == str: + member = MemberUnconfirmedProxy.objects.get(pk=object_id) + queryset = [member] + form = None + else: + queryset = object_id + form = DemoteToWaiterForm(initial={'_selected_action': queryset.values_list('id', flat=True)}) + + if "apply" in request.POST: + self.demote_to_waiter(request, queryset) + return HttpResponseRedirect(reverse('admin:members_memberunconfirmedproxy_changelist')) + + context = dict(self.admin_site.each_context(request), + title=_('Demote member to waiter'), + opts=self.opts, + queryset=queryset, + form=form) + return render(request, 'admin/demote_to_waiter.html', context=context) + def demote_to_waiter(self, request, queryset): for member in queryset: - #mem_as_dict = member.__dict__ - #del mem_as_dict['_state'] - #del mem_as_dict['id'] waiter = MemberWaitingList(prename=member.prename, lastname=member.lastname, email=member.email, birth_date=member.birth_date, + gender=member.gender, comments=member.comments, confirmed_mail=member.confirmed_mail, confirm_mail_key=member.confirm_mail_key) waiter.save() member.delete() messages.success(request, _("Successfully demoted %(name)s to waiter.") % {'name': waiter.name}) - demote_to_waiter.short_description = _('Demote selected registrations to waiters.') def response_change(self, request, member): if "_confirm" in request.POST: diff --git a/jdav_web/members/locale/de/LC_MESSAGES/django.po b/jdav_web/members/locale/de/LC_MESSAGES/django.po index 6e0fabd..04677ac 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: 2024-11-28 00:04+0100\n" +"POT-Creation-Date: 2024-11-30 01:22+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,165 +18,169 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: members/admin.py:126 members/models.py:382 +#: members/admin.py:125 members/models.py:381 msgid "Registration complete" msgstr "Anmeldung vollständig" -#: members/admin.py:132 +#: members/admin.py:131 msgid "True" msgstr "Ja" -#: members/admin.py:133 +#: members/admin.py:132 msgid "False" msgstr "Nein" -#: members/admin.py:134 +#: members/admin.py:133 msgid "All" msgstr "Alle" -#: members/admin.py:184 members/admin.py:397 +#: members/admin.py:183 members/admin.py:400 msgid "Contact information" msgstr "Kontaktinformationen" -#: members/admin.py:189 members/admin.py:402 +#: members/admin.py:188 members/admin.py:405 msgid "Skills" msgstr "Fähigkeiten" -#: members/admin.py:194 members/admin.py:407 +#: members/admin.py:193 members/admin.py:410 msgid "Others" msgstr "Sonstiges" -#: members/admin.py:200 members/admin.py:412 +#: members/admin.py:199 members/admin.py:415 msgid "Organizational" msgstr "Organisatorisches" -#: members/admin.py:281 +#: members/admin.py:280 msgid "Compose new mail to selected members" msgstr "Neue Nachricht an ausgewählte Teilnehmer verfassen" -#: members/admin.py:287 +#: members/admin.py:286 msgid "Echo required" msgstr "Rückmeldung erforderlich" -#: members/admin.py:289 +#: members/admin.py:288 msgid "Successfully requested echo from selected members." msgstr "" "Rückmeldungsaufforderung erfolgreich an ausgewählte Teilnehmer verschickt." -#: members/admin.py:290 +#: members/admin.py:289 msgid "Request echo from selected members" msgstr "Rückmeldungsaufforderung an ausgewählte Teilnehmer verschicken" -#: members/admin.py:296 +#: members/admin.py:295 #, python-format msgid "Successfully invited %(name)s as user." msgstr "Erfolgreich %(name)s aufgefordert Zugangsdaten zu wählen." -#: members/admin.py:298 +#: members/admin.py:297 msgid "Successfully invited selected members to join as users." msgstr "" "Erfolgreich ausgewählte Teilnehmer:innen aufgefordert Zugangsdaten zu wählen." -#: members/admin.py:305 members/admin.py:322 +#: members/admin.py:304 members/admin.py:321 msgid "Permission denied." msgstr "Fehlende Berechtigungen." -#: members/admin.py:312 members/admin.py:341 +#: members/admin.py:311 members/admin.py:340 #: members/templates/admin/invite_as_user.html:21 msgid "Invite as user" msgstr "Kompass Zugangsdaten wählen lassen" -#: members/admin.py:317 +#: members/admin.py:316 msgid "Invite selected members to join Kompass as users." msgstr "Ausgewählte Teilnehmer:innen Kompass Zugangsdaten wählen lassen." -#: members/admin.py:328 +#: members/admin.py:327 msgid "Member not found." msgstr "Teilnehmer:in nicht gefunden." -#: members/admin.py:332 +#: members/admin.py:331 #, python-format msgid "%(name)s already has login data." msgstr "%(name)s hat schon Zugangsdaten." -#: members/admin.py:346 +#: members/admin.py:345 #, python-format msgid "%(name)s already has a pending invitation as user." msgstr "" "%(name)s hat bereits eine ausstehende Aufforderung Zugangsdaten zu wählen." -#: members/admin.py:364 +#: members/admin.py:363 msgid "activity" msgstr "Aktivität" -#: members/admin.py:374 members/models.py:53 members/models.py:1401 +#: members/admin.py:373 members/models.py:53 members/models.py:1395 msgid "Name" msgstr "Name" -#: members/admin.py:446 +#: members/admin.py:449 msgid "Successfully requested mail confirmation from selected registrations." msgstr "Aufforderung zur Bestätigung der Email Adresse versendet." -#: members/admin.py:447 +#: members/admin.py:450 msgid "Request mail confirmation from selected registrations" msgstr "Aufforderung zur Bestätigung der Email Adresse versenden" -#: members/admin.py:454 members/admin.py:488 +#: members/admin.py:457 members/admin.py:531 #, python-format msgid "Successfully confirmed %(name)s." msgstr "Registrierung von %(name)s erfolgreich bestätigt." -#: members/admin.py:458 members/admin.py:491 +#: members/admin.py:461 members/admin.py:534 #, python-format msgid "Can't confirm. %(name)s has unconfirmed email addresses." msgstr "Bestätigung nicht möglich. %(name)s hat unbestätigte Emailadressen." -#: members/admin.py:463 +#: members/admin.py:466 msgid "Successfully confirmed multiple registrations." msgstr "Erfolgreich mehrere Registrierungen bestätigt." -#: members/admin.py:465 +#: members/admin.py:468 msgid "" "Failed to confirm some registrations because of unconfirmed email addresses." msgstr "" "Einige Bestätigungen fehlgeschlagen, weil Emailadressen noch nicht bestätigt " "sind." -#: members/admin.py:466 +#: members/admin.py:469 msgid "Confirm selected registrations" msgstr "Ausgewählte Registrierungen bestätigen" -#: members/admin.py:482 +#: members/admin.py:492 +msgid "Demote selected registrations to waiters." +msgstr "Ausgewählte Registrierungen zurück auf die Warteliste setzen." + +#: members/admin.py:508 +msgid "Demote member to waiter" +msgstr "Ausgewählte Registrierung zurück auf die Warteliste setzen." + +#: members/admin.py:526 #, python-format msgid "Successfully demoted %(name)s to waiter." msgstr "%(name)s zurück auf die Warteliste gesetzt." -#: members/admin.py:483 -msgid "Demote selected registrations to waiters." -msgstr "Ausgewählte Registrierungen zurück auf die Warteliste setzen." - -#: members/admin.py:498 members/models.py:389 members/models.py:738 -#: members/models.py:1146 +#: members/admin.py:541 members/models.py:388 members/models.py:732 +#: members/models.py:1140 msgid "Group" msgstr "Gruppe" -#: members/admin.py:532 +#: members/admin.py:575 #, python-format msgid "Successfully asked %(name)s to confirm their waiting status." msgstr "Erfolgreich %(name)s aufgefordert den Wartelistenplatz zu bestätigen." -#: members/admin.py:533 +#: members/admin.py:576 msgid "Ask selected waiters to confirm their waiting status" msgstr "Wartende auffordern den Wartelistenplatz zu bestätigen" -#: members/admin.py:542 members/admin.py:602 +#: members/admin.py:585 members/admin.py:645 msgid "" "An error occurred while trying to invite said members. Please try again." msgstr "" "Beim Einladen dieser Personen ist ein Fehler aufgetreten. Bitte versuche es " "nochmal. " -#: members/admin.py:546 members/admin.py:607 +#: members/admin.py:589 members/admin.py:650 msgid "" "The selected group does not have a contact email. Please first set a contact " "email and then try again." @@ -184,32 +188,32 @@ msgstr "" "Die ausgewählte Gruppe hat keine Kontakt E-Mail Adresse. Bitte stelle eine " "Kontakt E-Mail Adresse ein und versuche es erneut." -#: members/admin.py:554 members/admin.py:614 +#: members/admin.py:597 members/admin.py:657 #, python-format msgid "Successfully invited %(name)s to %(group)s." msgstr "Erfolgreich %(name)s zu Gruppe %(group)s eingeladen." -#: members/admin.py:558 members/admin.py:620 +#: members/admin.py:601 members/admin.py:663 msgid "Select group for invitation" msgstr "Wähle Gruppe für Einladung aus" -#: members/admin.py:565 +#: members/admin.py:608 msgid "Offer waiter a place in a group." msgstr "Personen auf der Warteliste einen Gruppenplatz anbieten." -#: members/admin.py:663 +#: members/admin.py:706 msgid "Difficulty" msgstr "Schwierigkeit" -#: members/admin.py:666 +#: members/admin.py:709 msgid "Tour type" msgstr "Art der Tour" -#: members/admin.py:669 members/models.py:956 +#: members/admin.py:712 members/models.py:950 msgid "Means of transportation" msgstr "Verkehrsmittel" -#: members/admin.py:695 +#: members/admin.py:738 msgid "" "Please list here all expenses in relation with this excursion and upload " "relevant bills. These have to be permanently stored for the application of " @@ -222,7 +226,7 @@ msgstr "" "einzelnen Posten wird dabei auf der LJP-Kostenübersicht angezeigt (sinnvoll " "wären z.B. Anreise, Verpflegung, Material etc.)." -#: members/admin.py:713 +#: members/admin.py:756 msgid "" "Here you can work on a seminar report for applying for financial " "contributions from Landesjugendplan (LJP). More information on creating a " @@ -235,7 +239,7 @@ msgstr "" "wahlweise nur TN-Liste und Kostenübersicht kannst du anschließend " "herunterladen." -#: members/admin.py:721 +#: members/admin.py:764 msgid "" "Please list all participants (also youth leaders) of this excursion. Here " "you can still make changes just before departure and hence generate the " @@ -246,30 +250,30 @@ msgstr "" "jederzeit die aktuelle Teilnehmer:innenliste für die Krisenintervention " "generieren." -#: members/admin.py:767 +#: members/admin.py:810 #, python-format msgid "You are not allowed to view all members on note list %(name)s." msgstr "" "Du hast nicht die nötigen Rechte um alle Teilnehmer:innen der Notizliste " "%(name)s anzusehen." -#: members/admin.py:777 +#: members/admin.py:820 msgid "Generate PDF summary" msgstr "Übersicht erstellen" -#: members/admin.py:781 +#: members/admin.py:824 msgid "Full report" msgstr "Vollständiger Seminarbericht" -#: members/admin.py:782 +#: members/admin.py:825 msgid "Costs and participants only" msgstr "Nur Kosten und Teilnehmende" -#: members/admin.py:783 +#: members/admin.py:826 msgid "Mode" msgstr "Modus" -#: members/admin.py:797 +#: members/admin.py:840 msgid "" "General information on your excursion. These are partly relevant for the " "amount of financial compensation (means of transport, travel distance, etc.)." @@ -278,38 +282,38 @@ msgstr "" "teilweise relevant für die Zuschüsse aus dem Jugendetat (Verkehrsmittel, " "Fahrstrecke in km)." -#: members/admin.py:827 +#: members/admin.py:870 #, python-format msgid "You are not allowed to view all members on excursion %(name)s." msgstr "" "Du hast nicht die nötigen Rechte um alle Teilnehmer:innen der Ausfahrt " "%(name)s anzusehen." -#: members/admin.py:835 +#: members/admin.py:878 msgid "Generate crisis intervention list" msgstr "Kriseninterventionsliste erstellen" -#: members/admin.py:843 +#: members/admin.py:886 msgid "Generate overview" msgstr "Hinweise für Jugendleiter erstellen" -#: members/admin.py:847 members/admin.py:870 +#: members/admin.py:890 members/admin.py:913 #: members/templates/admin/generate_seminar_report.html:21 msgid "Generate seminar report" msgstr "Seminarbericht erstellen" -#: members/admin.py:860 +#: members/admin.py:903 msgid "Please select a mode." msgstr "Bitte wähle einen Modus aus." -#: members/admin.py:864 +#: members/admin.py:907 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:882 +#: members/admin.py:925 msgid "Generate SJR application" msgstr "SJR Antrag erstellen" @@ -345,11 +349,11 @@ msgstr "Samstag" msgid "Sunday" msgstr "Sonntag" -#: members/models.py:54 members/models.py:942 +#: members/models.py:54 members/models.py:936 msgid "Description" msgstr "Beschreibung" -#: members/models.py:60 members/models.py:934 +#: members/models.py:60 members/models.py:928 #: members/templates/members/change_member.html:18 msgid "Activity" msgstr "Aktivität" @@ -386,7 +390,7 @@ msgstr "Jugendleiter" msgid "week day" msgstr "Wochentag" -#: members/models.py:77 members/models.py:1228 +#: members/models.py:77 members/models.py:1222 msgid "Starting time" msgstr "Zeitpunkt" @@ -395,12 +399,10 @@ msgid "Ending time" msgstr "Endzeitpunkt" #: members/models.py:80 -#, fuzzy -#| msgid "Contact information" msgid "Contact email" -msgstr "Kontaktinformationen" +msgstr "Kontakt Email" -#: members/models.py:90 members/models.py:258 +#: members/models.py:90 members/models.py:257 msgid "group" msgstr "Gruppe" @@ -424,7 +426,7 @@ msgstr "Emailadresse bestätigt" msgid "Email confirmation needed" msgstr "Email Bestätigung erforderlich" -#: members/models.py:188 members/models.py:232 +#: members/models.py:188 members/models.py:231 msgid "phone number" msgstr "Telefonnummer (mobil)" @@ -432,469 +434,470 @@ msgstr "Telefonnummer (mobil)" msgid "birth date" msgstr "Geburtsdatum" -#: members/models.py:204 +#: members/models.py:203 msgid "Gender" msgstr "Gender" -#: members/models.py:205 +#: members/models.py:204 msgid "comments" msgstr "Kommentare" -#: members/models.py:229 +#: members/models.py:228 msgid "Alternative email confirmed" msgstr "Alternative E-Mail Adresse bestätigt" -#: members/models.py:233 +#: members/models.py:232 msgid "street and house number" msgstr "Straße und Hausnummer" -#: members/models.py:234 +#: members/models.py:233 msgid "Postcode" msgstr "PLZ" -#: members/models.py:236 +#: members/models.py:235 msgid "town" msgstr "Stadt" -#: members/models.py:237 +#: members/models.py:236 msgid "Address extra" msgstr "Adress-Zusatz" -#: members/models.py:238 +#: members/models.py:237 msgid "Country" msgstr "Land" -#: members/models.py:240 +#: members/models.py:239 msgid "Good conduct certificate presented on" msgstr "Führungszeugnis vorgelegt am" -#: members/models.py:241 +#: members/models.py:240 msgid "Joined on" msgstr "Eintritt" -#: members/models.py:242 +#: members/models.py:241 msgid "Left on" msgstr "Austritt" -#: members/models.py:243 +#: members/models.py:242 msgid "Has key" msgstr "Hat Jugendraumschlüssel" -#: members/models.py:244 +#: members/models.py:243 msgid "Has a free ticket for the climbing gym" msgstr "Hat Freikarte für Kletterhalle" -#: members/models.py:245 +#: members/models.py:244 msgid "DAV badge number" msgstr "DAV Mitgliedsnummer" -#: members/models.py:246 +#: members/models.py:245 msgid "Knows how to swim" msgstr "Kann schwimmen" -#: members/models.py:247 +#: members/models.py:246 msgid "Climbing badge" msgstr "Kletterschein" -#: members/models.py:248 +#: members/models.py:247 msgid "Alpine experience" msgstr "Alpine Erfahrung" -#: members/models.py:249 +#: members/models.py:248 msgid "Allergies" msgstr "Allergieen" -#: members/models.py:250 +#: members/models.py:249 msgid "Medication" msgstr "Medikamente" -#: members/models.py:251 +#: members/models.py:250 msgid "Tetanus vaccination" msgstr "Tetanusimpfung" -#: members/models.py:252 +#: members/models.py:251 msgid "Photos may be taken" msgstr "Fotoerlaubnis" -#: members/models.py:253 +#: members/models.py:252 msgid "Legal guardians" msgstr "Erziehungsberechtigte" -#: members/models.py:255 +#: members/models.py:254 msgid "May cancel a group appointment independently" msgstr "Darf sich allein von der Gruppenstunde abmelden" -#: members/models.py:262 +#: members/models.py:261 msgid "receives newsletter" msgstr "Erhält den Newsletter" -#: members/models.py:266 +#: members/models.py:265 msgid "created" msgstr "erstellt" -#: members/models.py:267 +#: members/models.py:266 msgid "Active" msgstr "Aktiv" -#: members/models.py:268 +#: members/models.py:267 msgid "registration form" msgstr "Anmeldeformular" -#: members/models.py:276 +#: members/models.py:275 msgid "image" msgstr "Bild" -#: members/models.py:285 +#: members/models.py:284 msgid "Echoed" msgstr "Rückgemeldet" -#: members/models.py:286 +#: members/models.py:285 msgid "Confirmed" msgstr "Bestätigt" -#: members/models.py:288 +#: members/models.py:287 msgid "Login data" msgstr "Zugangsdaten" -#: members/models.py:318 +#: members/models.py:317 msgid "Good conduct certificate valid" msgstr "Führungszeugnis gültig" -#: members/models.py:392 +#: members/models.py:391 msgid "member" msgstr "Teilnehmer" -#: members/models.py:393 +#: members/models.py:392 msgid "members" msgstr "Teilnehmer" -#: members/models.py:466 +#: members/models.py:460 #, python-format msgid "New unconfirmed registration for group %(group)s" msgstr "Neue unbestätigte Registrierung für Gruppe %(group)s" -#: members/models.py:677 +#: members/models.py:671 msgid "Set login data for Kompass" msgstr "Zugangsdaten für Kompass wählen" -#: members/models.py:694 members/models.py:890 members/models.py:901 -#: members/models.py:1177 members/models.py:1184 +#: members/models.py:688 members/models.py:884 members/models.py:895 +#: members/models.py:1171 members/models.py:1178 msgid "Member" msgstr "Teilnehmer" -#: members/models.py:701 +#: members/models.py:695 msgid "Emergency contact" msgstr "Notfallkontakt" -#: members/models.py:702 +#: members/models.py:696 msgid "Emergency contacts" msgstr "Notfallkontakte" -#: members/models.py:722 +#: members/models.py:716 msgid "Unconfirmed registration" msgstr "Unbestätigte Registrierung" -#: members/models.py:723 +#: members/models.py:717 msgid "Unconfirmed registrations" msgstr "Unbestätigte Registrierungen" -#: members/models.py:737 members/models.py:782 +#: members/models.py:731 members/models.py:776 msgid "Waiter" msgstr "Wartende Person" -#: members/models.py:739 +#: members/models.py:733 msgid "Invitation date" msgstr "Einladungsdatum" -#: members/models.py:740 members/templates/members/reject_success.html:6 +#: members/models.py:734 members/templates/members/reject_success.html:6 #: members/templates/members/reject_success.html:11 msgid "Invitation rejected" msgstr "Einladung abgelehnt" -#: members/models.py:744 +#: members/models.py:738 msgid "Invitation to group" msgstr "Gruppeneinladung" -#: members/models.py:745 +#: members/models.py:739 msgid "Invitations to groups" msgstr "Gruppeneinladungen" -#: members/models.py:752 +#: members/models.py:746 msgid "Rejected" msgstr "Abgelehnt" -#: members/models.py:754 +#: members/models.py:748 msgid "Expired" msgstr "Abgelaufen" -#: members/models.py:756 +#: members/models.py:750 msgid "Undecided" msgstr "Ausstehend" -#: members/models.py:757 +#: members/models.py:751 msgid "Status" msgstr "Status" -#: members/models.py:768 +#: members/models.py:762 msgid "Do you want to tell us something else?" msgstr "Möchtest du uns noch etwas mitteilen?" -#: members/models.py:769 +#: members/models.py:763 msgid "application date" msgstr "Bewerbungsdatum" -#: members/models.py:771 +#: members/models.py:765 msgid "Last wait confirmation" msgstr "Letzte Wartebestätigung" -#: members/models.py:775 +#: members/models.py:769 msgid "Last reminder" msgstr "Letzte Erinnerung" -#: members/models.py:776 +#: members/models.py:770 msgid "Missed reminders" msgstr "Verpasste Erinnerungen" -#: members/models.py:783 +#: members/models.py:777 msgid "Waiters" msgstr "Warteliste" -#: members/models.py:807 +#: members/models.py:801 msgid "Waiting status confirmed" msgstr "Wartelistenplatz bestätigt" -#: members/models.py:814 +#: members/models.py:808 msgid "Waiting confirmation needed" msgstr "Wartelistenplatzbestätigung erforderlich" -#: members/models.py:869 +#: members/models.py:863 msgid "Invitation to trial group meeting" msgstr "Einladung zu Schnupperstunde" -#: members/models.py:881 +#: members/models.py:875 msgid "Unregistered from waiting list" msgstr "Von der Warteliste abgemeldet" -#: members/models.py:895 +#: members/models.py:889 msgid "Comment" msgstr "Kommentar" -#: members/models.py:902 members/models.py:1185 +#: members/models.py:896 members/models.py:1179 msgid "Members" msgstr "Teilnehmer" -#: members/models.py:936 +#: members/models.py:930 msgid "Place" msgstr "Stützpunkt / Ort" -#: members/models.py:937 +#: members/models.py:931 msgid "Destination (optional)" msgstr "ggf. Ziel" -#: members/models.py:939 +#: members/models.py:933 msgid "e.g. a peak" msgstr "z.B. ein Gipfel" -#: members/models.py:940 +#: members/models.py:934 msgid "Begin" msgstr "Anfang" -#: members/models.py:941 +#: members/models.py:935 msgid "End (optional)" msgstr "Ende" -#: members/models.py:944 +#: members/models.py:938 msgid "Groups" msgstr "Gruppen" -#: members/models.py:957 +#: members/models.py:951 msgid "Kilometers traveled" msgstr "Fahrstrecke in Kilometer" -#: members/models.py:960 +#: members/models.py:954 msgid "Categories" msgstr "Kategorien" -#: members/models.py:961 +#: members/models.py:955 msgid "easy" msgstr "leicht" -#: members/models.py:961 +#: members/models.py:955 msgid "medium" msgstr "mittel" -#: members/models.py:961 +#: members/models.py:955 msgid "hard" msgstr "schwer" -#: members/models.py:971 members/models.py:1208 +#: members/models.py:965 members/models.py:1202 msgid "Excursion" msgstr "Ausfahrt" -#: members/models.py:972 +#: members/models.py:966 msgid "Excursions" msgstr "Ausfahrten" -#: members/models.py:1123 members/models.py:1199 members/models.py:1415 +#: members/models.py:1117 members/models.py:1193 members/models.py:1409 msgid "Title" msgstr "Titel" -#: members/models.py:1124 members/models.py:1142 members/models.py:1416 +#: members/models.py:1118 members/models.py:1136 members/models.py:1410 msgid "Date" msgstr "Datum" -#: members/models.py:1143 +#: members/models.py:1137 msgid "Location" msgstr "Ort" -#: members/models.py:1144 +#: members/models.py:1138 msgid "Topic" msgstr "Thema" -#: members/models.py:1168 +#: members/models.py:1162 msgid "Jugendleiter" msgstr "Jugendleiter" -#: members/models.py:1171 +#: members/models.py:1165 msgid "Klettertreff" msgstr "Klettertreff" -#: members/models.py:1172 +#: members/models.py:1166 msgid "Klettertreffs" msgstr "Klettertreffs" -#: members/models.py:1190 +#: members/models.py:1184 msgid "Password" msgstr "Passwort" -#: members/models.py:1193 +#: members/models.py:1187 msgid "registration password" msgstr "Registrierungspassort" -#: members/models.py:1194 +#: members/models.py:1188 msgid "registration passwords" msgstr "Registrierungspasswörter" -#: members/models.py:1201 +#: members/models.py:1195 msgid "Alpinistic goals" msgstr "Alpintechnische Ziele" -#: members/models.py:1202 +#: members/models.py:1196 msgid "Pedagogic goals" msgstr "Pädagogische Ziele" -#: members/models.py:1203 +#: members/models.py:1197 msgid "Content and methods" msgstr "Inhalte und Methoden" -#: members/models.py:1204 +#: members/models.py:1198 msgid "Evaluation" msgstr "Wertung" -#: members/models.py:1205 +#: members/models.py:1199 msgid "Experiences and possible improvements" msgstr "Erfahrungen und Verbesserungsvorschläge" -#: members/models.py:1214 members/models.py:1235 +#: members/models.py:1208 members/models.py:1229 msgid "LJP Proposal" msgstr "Seminarbericht" -#: members/models.py:1215 +#: members/models.py:1209 msgid "LJP Proposals" msgstr "Seminarberichte" -#: members/models.py:1229 +#: members/models.py:1223 msgid "Duration in hours" msgstr "Dauer in Stunden" -#: members/models.py:1232 +#: members/models.py:1226 msgid "Activity and method" msgstr "Art der Aktion inkl. Methode" -#: members/models.py:1240 +#: members/models.py:1234 msgid "Intervention" msgstr "Aktion" -#: members/models.py:1241 +#: members/models.py:1235 msgid "Interventions" msgstr "Aktionen" -#: members/models.py:1343 members/models.py:1373 +#: members/models.py:1337 members/models.py:1367 msgid "May list members" msgstr "Darf folgende Teilnehmer:innen listen" -#: members/models.py:1345 members/models.py:1375 +#: members/models.py:1339 members/models.py:1369 msgid "May view members" msgstr "Darf folgende Teilnehmer:innen anzeigen" -#: members/models.py:1347 members/models.py:1377 +#: members/models.py:1341 members/models.py:1371 msgid "May change members" msgstr "Darf folgende Teilnehmer:innen ändern" -#: members/models.py:1349 members/models.py:1379 +#: members/models.py:1343 members/models.py:1373 msgid "May delete members" msgstr "Darf folgende Teilnehmer:innen löschen" -#: members/models.py:1353 members/models.py:1383 +#: members/models.py:1347 members/models.py:1377 msgid "May list members of groups" msgstr "Darf Teilnehmer:innen folgender Gruppen listen" -#: members/models.py:1355 members/models.py:1385 +#: members/models.py:1349 members/models.py:1379 msgid "May view members of groups" msgstr "Darf Teilnehmer:innen folgender Gruppen anzeigen" -#: members/models.py:1357 members/models.py:1387 +#: members/models.py:1351 members/models.py:1381 msgid "May change members of groups" msgstr "Darf Teilnehmer:innen folgender Gruppen ändern" -#: members/models.py:1359 members/models.py:1389 +#: members/models.py:1353 members/models.py:1383 msgid "May delete members of groups" msgstr "Darf Teilnehmer:innen folgender Gruppen löschen" -#: members/models.py:1362 members/models.py:1363 members/models.py:1366 +#: members/models.py:1356 members/models.py:1357 members/models.py:1360 msgid "Permissions" msgstr "Berechtigungen" -#: members/models.py:1392 members/models.py:1393 members/models.py:1396 +#: members/models.py:1386 members/models.py:1387 members/models.py:1390 msgid "Group permissions" msgstr "Gruppenberechtigungen" -#: members/models.py:1402 +#: members/models.py:1396 msgid "Permission needed" msgstr "Freigabe erforderlich" -#: members/models.py:1405 +#: members/models.py:1399 msgid "Training category" msgstr "Fortbildungstyp" -#: members/models.py:1406 +#: members/models.py:1400 msgid "Training categories" msgstr "Fortbildungstypen" -#: members/models.py:1417 +#: members/models.py:1411 msgid "Category" msgstr "Kategorien" -#: members/models.py:1418 +#: members/models.py:1412 msgid "Comments" msgstr "Kommentar" -#: members/models.py:1419 +#: members/models.py:1413 msgid "Participated" msgstr "Teilgenommmen" -#: members/models.py:1420 +#: members/models.py:1414 msgid "Passed" msgstr "Bestanden" -#: members/models.py:1423 +#: members/models.py:1417 msgid "Training" msgstr "Fortbildung" -#: members/models.py:1424 +#: members/models.py:1418 msgid "Trainings" msgstr "Fortbildungen" +#: members/templates/admin/demote_to_waiter.html:17 #: members/templates/admin/generate_seminar_report.html:17 #: members/templates/admin/invite_as_user.html:17 #: members/templates/admin/invite_for_group.html:17 @@ -903,6 +906,30 @@ msgstr "Fortbildungen" msgid "Home" msgstr "Start" +#: members/templates/admin/demote_to_waiter.html:20 +#: members/templates/admin/demote_to_waiter.html:25 +msgid "Demote to waiter" +msgstr "Zurück auf die Warteliste setzen" + +#: members/templates/admin/demote_to_waiter.html:27 +msgid "" +"Do you want to demote the following unconfirmed registrations to waiters?" +msgstr "" +"Möchtest du die folgenden Personen zurück auf die Warteliste setzen?" + +#: members/templates/admin/demote_to_waiter.html:45 +msgid "Demote" +msgstr "Zurück auf die Warteliste setzen" + +#: members/templates/admin/demote_to_waiter.html:46 +#: members/templates/admin/generate_seminar_report.html:54 +#: members/templates/admin/invite_as_user.html:37 +#: members/templates/admin/invite_for_group.html:52 +#: members/templates/admin/invite_selected_as_user.html:49 +#: members/templates/admin/invite_selected_for_group.html:53 +msgid "Cancel" +msgstr "Abbrechen" + #: members/templates/admin/generate_seminar_report.html:27 msgid "" "Here you can generate a seminar report suitable for the LJP. A report\n" @@ -939,14 +966,6 @@ msgstr "Bitte wähle einen der obigen Modi." msgid "Generate" msgstr "Erstellen" -#: members/templates/admin/generate_seminar_report.html:54 -#: members/templates/admin/invite_as_user.html:37 -#: members/templates/admin/invite_for_group.html:52 -#: members/templates/admin/invite_selected_as_user.html:49 -#: members/templates/admin/invite_selected_for_group.html:53 -msgid "Cancel" -msgstr "Abbrechen" - #: members/templates/admin/invite_as_user.html:27 #, python-format msgid "" diff --git a/jdav_web/members/templates/admin/demote_to_waiter.html b/jdav_web/members/templates/admin/demote_to_waiter.html new file mode 100644 index 0000000..661ddef --- /dev/null +++ b/jdav_web/members/templates/admin/demote_to_waiter.html @@ -0,0 +1,48 @@ +{% 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 %} +

{% translate "Demote to waiter" %}

+

+{% trans "Do you want to demote the following unconfirmed registrations to waiters?" %} +

+

+

    + {% for member in queryset %} +
  • + {{ member }} +
  • + {% endfor %} +
+

+ +
+ {% csrf_token %} + {% if form %} + {{form}} + {% endif %} + + + {% translate "Cancel" %} +
+{% endblock %} diff --git a/jdav_web/templates/admin/members/memberunconfirmedproxy/change_form_object_tools.html b/jdav_web/templates/admin/members/memberunconfirmedproxy/change_form_object_tools.html new file mode 100644 index 0000000..c3fbe46 --- /dev/null +++ b/jdav_web/templates/admin/members/memberunconfirmedproxy/change_form_object_tools.html @@ -0,0 +1,13 @@ +{% extends "admin/change_form_object_tools.html" %} +{% load i18n admin_urls %} + +{% block object-tools-items %} + +
  • + {% url opts|admin_urlname:'demote' original.pk|admin_urlquote as demote_url %} + {% trans 'Demote to waiter' %} +
  • + +{{block.super}} + +{% endblock %} From 5734d41a239e19e7d1397f00a29e1f3e7989ff52 Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Sat, 30 Nov 2024 01:49:15 +0100 Subject: [PATCH 19/56] startpage: update impressum --- .../templates/startpage/impressum.html | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/jdav_web/startpage/templates/startpage/impressum.html b/jdav_web/startpage/templates/startpage/impressum.html index eb31dc1..78371b6 100644 --- a/jdav_web/startpage/templates/startpage/impressum.html +++ b/jdav_web/startpage/templates/startpage/impressum.html @@ -38,7 +38,7 @@ Der Deutsche Alpenverein Sektion Heidelberg 1869 e.V. ist im Vereinsregister des

    Jugendreferat

    -Leitung: Eva Engelmann und Robert Scheffler (kommissarisch)
    +Leitung: Eva Engelmann und Robert Scheffler
    E-Mail: jugend@alpenverein-heidelberg.de
    URL: www.jdav-hd.de ; www.jdav-heidelberg.de

    @@ -59,12 +59,13 @@ Diese Datenschutz-Information gilt für die Datenverarbeitung durch:

    Verantwortlicher: Deutscher Alpenverein Sektion Heidelberg 1869 e.V.
    Harbigweg 20, 69124 Heidelberg
    -Email: alpenverein-heidelberg@t-online.de
    +Email: geschaeftsstelle@alpenverein-heidelberg.de
    Telefon: +49 6221 484076

    -Zur Auftragsverarbeitung für die jdav Heidelberg ist die Firma reeweb AG Wettsteinplatz 74058 Basel Schweiz beauftragt. Die Datenverarbeitung erfolgt in Rechenzentren in der Schweiz oder Staaten des Europäischen Wirtschaftsraums (EWR). +Zur Auftragsverarbeitung für die jdav Heidelberg ist die Firma Contabo GmbH Aschauer Str. 32a 81549 München beauftragt. +Die Datenverarbeitung erfolgt in Rechenzentren in der Schweiz oder Staaten des Europäischen Wirtschaftsraums (EWR).

    @@ -72,7 +73,7 @@ Zur Auftragsverarbeitung für die jdav Heidelberg ist die Firma reeweb AG Wettst

    -Beim Aufrufen unserer Website jdav-hd.merten.dev werden durch den auf Ihrem Endgerät zum Einsatz kommenden Browser automatisch Informationen an den Server unserer Website gesendet. Diese Informationen werden temporär in einem sog. Logfile gespeichert. Folgende Informationen werden dabei ohne Ihr Zutun erfasst und bis zur automatischen Löschung gespeichert: +Beim Aufrufen unserer Website jdav-hd.de werden durch den auf Ihrem Endgerät zum Einsatz kommenden Browser automatisch Informationen an den Server unserer Website gesendet. Diese Informationen werden temporär in einem sog. Logfile gespeichert. Folgende Informationen werden dabei ohne Ihr Zutun erfasst und bis zur automatischen Löschung gespeichert:

    @@ -131,7 +132,8 @@ Zur Weitergabe der Daten im Rahmen einer Mitgliedschaft im Alpenverein Heidelber

    -Die jdav Heidelberg hat die Firma reeweb AG Wettsteinplatz 74058 Basel Schweiz beauftragt die Daten ihrer Mitglieder zu verwalten. Diese Datenverarbeitung erfolgt in Rechenzentren in der Schweiz oder Staaten des Europäischen Wirtschaftsraums (EWR). +Die jdav Heidelberg hat die Firma Contabo GmbH Aschauer Str. 32a 81549 München beauftragt die Daten ihrer Mitglieder zu +verwalten. Diese Datenverarbeitung erfolgt in Rechenzentren in der Schweiz oder Staaten des Europäischen Wirtschaftsraums (EWR).

    @@ -191,7 +193,10 @@ Die meisten Browser akzeptieren Cookies automatisch. Sie können Ihren Browser j

    -Auf unserer Internetseite sind Kontaktformulare vorhanden, welche für die elektronische Kontaktaufnahme genutzt werden können. Nimmt ein Nutzer diese Möglichkeit wahr, so werden die in der Eingabemaske eingegeben Daten an uns übermittelt und gespeichert. Diese Daten sind: +Auf unserer Internetseite sind Kontaktformulare vorhanden, welche für die elektronische Kontaktaufnahme genutzt werden können. +Nimmt ein Nutzer diese Möglichkeit wahr, so werden die in der Eingabemaske eingegeben Daten an uns übermittelt und gespeichert. +Für diese Datenverarbeitung ist die Firma Contabo GmbH Aschauer Str. 32a 81549 München beauftragt. +Diese Daten sind:

    @@ -258,7 +263,7 @@ Die während des Absendevorgangs zusätzlich erhobenen personenbezogenen Daten w

    6. Das geschieht, wenn Sie Online-Anmeldeformulare nutzen:

    -Auf unserer Internetseite sind Anmeldeformulare vorhanden, welches für die elektronische Anmeldung zu Jugendgruppen, Kursen und Veranstaltungen unseres Vereins genutzt werden kann. Nimmt ein Nutzer diese Möglichkeit wahr, so werden die in der Eingabemaske eingegeben Daten an uns übermittelt und gespeichert. Für diese Datenverarbeitung ist die Firma reeweb AG Wettsteinplatz 74058 Basel Schweiz beauftragt. Diese Daten sind: +Auf unserer Internetseite sind Anmeldeformulare vorhanden, welches für die elektronische Anmeldung zu Jugendgruppen, Kursen und Veranstaltungen unseres Vereins genutzt werden kann. Nimmt ein Nutzer diese Möglichkeit wahr, so werden die in der Eingabemaske eingegeben Daten an uns übermittelt und gespeichert.

    @@ -346,7 +351,7 @@ Sofern Ihre personenbezogenen Daten auf Grundlage von berechtigten Interessen ge

    Möchten Sie von Ihrem Widerrufs- oder Widerspruchsrecht Gebrauch machen, genügt eine Email an jugend@alpenverein-heidelberg.de oder -alpenverein-heidelberg@t-online.de. +geschaeftsstelle@alpenverein-heidelberg.de.

    10. Die Sicherheit Ihrer Daten:

    @@ -358,7 +363,7 @@ Wir bedienen uns geeigneter technischer und organisatorischer Sicherheitsmaßnah

    11. Aktualität und Änderung dieser Datenschutzerklärung

    -Diese Datenschutzerklärung ist aktuell gültig und hat den Stand April 2020. +Diese Datenschutzerklärung ist aktuell gültig und hat den Stand November 2024.

    From 79b538910795fa76c91bd420c1c9f4492067d484 Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Sat, 30 Nov 2024 03:56:23 +0100 Subject: [PATCH 20/56] members/excursion: add finance overview --- jdav_web/finance/admin.py | 26 +- .../finance/locale/de/LC_MESSAGES/django.po | 126 ++-- jdav_web/finance/models.py | 31 +- jdav_web/locale/de/LC_MESSAGES/django.po | 19 +- jdav_web/members/admin.py | 22 + .../members/locale/de/LC_MESSAGES/django.po | 611 ++++++++++++------ jdav_web/members/models.py | 14 + .../admin/freizeit_finance_overview.html | 166 +++++ .../freizeit/change_form_object_tools.html | 7 +- jdav_web/utils.py | 12 + 10 files changed, 726 insertions(+), 308 deletions(-) create mode 100644 jdav_web/members/templates/admin/freizeit_finance_overview.html diff --git a/jdav_web/finance/admin.py b/jdav_web/finance/admin.py index 442b0cc..a1c8e82 100644 --- a/jdav_web/finance/admin.py +++ b/jdav_web/finance/admin.py @@ -9,6 +9,7 @@ from django.shortcuts import render from django.conf import settings from contrib.admin import CommonAdminInlineMixin, CommonAdminMixin +from utils import get_member from rules.contrib.admin import ObjectPermissionsModelAdmin @@ -218,23 +219,7 @@ class StatementSubmittedAdmin(admin.ModelAdmin): opts=self.opts, statement=statement, transaction_issues=statement.transaction_issues, - total_bills=statement.total_bills, - total=statement.total) - if statement.excursion is not None: - context = dict(context, - nights=statement.excursion.night_count, - price_per_night=statement.real_night_cost, - duration=statement.excursion.duration, - staff_count=statement.real_staff_count, - kilometers_traveled=statement.excursion.kilometers_traveled, - means_of_transport=statement.excursion.get_tour_approach(), - euro_per_km=statement.euro_per_km, - allowance_per_day=settings.ALLOWANCE_PER_DAY, - nights_per_yl=statement.nights_per_yl, - allowance_per_yl=statement.allowance_per_yl, - transportation_per_yl=statement.transportation_per_yl, - total_per_yl=statement.total_per_yl, - total_staff=statement.total_staff) + **statement.template_context()) return render(request, 'admin/overview_submitted_statement.html', context=context) @@ -325,10 +310,3 @@ class BillAdmin(admin.ModelAdmin): list_display = ['__str__', 'statement', 'short_description', 'pretty_amount', 'paid_by', 'refunded'] list_filter = ('statement', 'paid_by', 'refunded') search_fields = ('reference', 'statement') - - -def get_member(request): - if not hasattr(request.user, 'member'): - return None - else: - return request.user.member diff --git a/jdav_web/finance/locale/de/LC_MESSAGES/django.po b/jdav_web/finance/locale/de/LC_MESSAGES/django.po index cbb5e02..1d0f727 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: 2024-11-24 01:34+0100\n" +"POT-Creation-Date: 2024-11-30 03:54+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,12 +18,12 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: finance/admin.py:75 +#: finance/admin.py:76 #, python-format msgid "%(name)s is already submitted." msgstr "%(name)s ist bereits eingereicht." -#: finance/admin.py:81 +#: finance/admin.py:82 #, python-format msgid "" "Successfully submited %(name)s. The finance department will notify the " @@ -32,23 +32,23 @@ msgstr "" "Rechnung %(name)s erfolgreich eingereicht. Das Finanzreferat wird auf dich " "sobald wie möglich zukommen." -#: finance/admin.py:84 +#: finance/admin.py:85 msgid "Submit statement" msgstr "Rechnung einreichen" -#: finance/admin.py:161 +#: finance/admin.py:162 #, python-format msgid "%(name)s is not yet submitted." msgstr "%(name)s ist noch nicht eingereicht." -#: finance/admin.py:168 +#: finance/admin.py:169 #, python-format msgid "An error occured while trying to confirm %(name)s. Please try again." msgstr "" "Beim Abwickeln von %(name)s ist ein Fehler aufgetreten. Bitte versuche es " "erneut." -#: finance/admin.py:172 +#: finance/admin.py:173 #, python-format msgid "" "Successfully confirmed %(name)s. I hope you executed the associated " @@ -57,11 +57,11 @@ msgstr "" "Erfolgreich %(name)s abgewickelt. Ich hoffe du hast die zugehörigen " "Überweisungen ausgeführt, ich werde dich nicht nochmal erinnern." -#: finance/admin.py:179 +#: finance/admin.py:180 msgid "Statement confirmed" msgstr "Abrechnung abgewickelt" -#: finance/admin.py:185 +#: finance/admin.py:186 msgid "" "Transactions do not match the covered expenses. Please correct the mistakes " "listed below." @@ -69,19 +69,19 @@ msgstr "" "Überweisungen stimmen nicht mit den übernommenen Kosten überein. Bitte " "korrigiere die unten aufgeführten Fehler." -#: finance/admin.py:190 +#: finance/admin.py:191 msgid "Some transactions have no ledger configured. Please fill in the gaps." msgstr "" "Manche Überweisungen haben kein Geldtopf eingestellt. Bitte trage das nach." -#: finance/admin.py:199 +#: finance/admin.py:200 #, python-format msgid "Successfully rejected %(name)s. The requestor can reapply, when needed." msgstr "" "Die Rechnung %(name)s wurde abgelehnt. Die Person kann die Rechnung erneut " "einstellen, wenn es benötigt wird." -#: finance/admin.py:206 +#: finance/admin.py:207 #, python-format msgid "" "%(name)s already has transactions. Please delete them first, if you want to " @@ -90,12 +90,12 @@ msgstr "" "%(name)s hat bereits Überweisungen. Bitte lösche diese zunächst, bevor du " "neue generierst." -#: finance/admin.py:211 +#: finance/admin.py:212 #, python-format msgid "Successfully generated transactions for %(name)s" msgstr "Automatisch Überweisungsträger für %(name)s generiert." -#: finance/admin.py:214 +#: finance/admin.py:215 #, python-format msgid "" "Error while generating transactions for %(name)s. Do all bills have a payer?" @@ -103,28 +103,28 @@ msgstr "" "Fehler beim Erzeugen der Überweisungsträger für %(name)s. Sind für alle " "Quittungen eine bezahlende Person eingestellt? " -#: finance/admin.py:217 +#: finance/admin.py:218 msgid "View submitted statement" msgstr "Eingereichte Abrechnung einsehen" -#: finance/admin.py:245 +#: finance/admin.py:230 #, python-format msgid "Successfully reduced transactions for %(name)s." msgstr "Überweisungsträger für %(name)s minimiert." -#: finance/admin.py:289 +#: finance/admin.py:274 #, python-format msgid "%(name)s is not yet confirmed." msgstr "%(name)s ist noch nicht bestätigt." -#: finance/admin.py:298 +#: finance/admin.py:283 #, python-format msgid "Successfully unconfirmed %(name)s. I hope you know what you are doing." msgstr "" "Erfolgreich die Bestätigung von %(name)s zurückgenommen. Ich hoffe du weißt " "was du machst." -#: finance/admin.py:303 finance/templates/admin/unconfirm_statement.html:26 +#: finance/admin.py:288 finance/templates/admin/unconfirm_statement.html:26 msgid "Unconfirm statement" msgstr "Bestätigung zurücknehmen" @@ -132,165 +132,165 @@ msgstr "Bestätigung zurücknehmen" msgid "Finance" msgstr "Finanzen" -#: finance/models.py:19 +#: finance/models.py:20 msgid "Name" msgstr "Name" -#: finance/models.py:25 finance/models.py:441 finance/models.py:465 +#: finance/models.py:26 finance/models.py:466 finance/models.py:490 #: finance/templates/admin/confirmed_statement.html:38 #: finance/templates/admin/overview_submitted_statement.html:100 msgid "Ledger" msgstr "Geldtopf" -#: finance/models.py:26 +#: finance/models.py:27 msgid "Ledgers" msgstr "Geldtöpfe" -#: finance/models.py:46 finance/models.py:384 finance/models.py:464 +#: finance/models.py:47 finance/models.py:409 finance/models.py:489 msgid "Short description" msgstr "Kurzbeschreibung" -#: finance/models.py:49 finance/models.py:385 +#: finance/models.py:50 finance/models.py:410 msgid "Explanation" msgstr "Erklärung" -#: finance/models.py:51 +#: finance/models.py:52 msgid "Associated excursion" msgstr "Zugehörige Ausfahrt" -#: finance/models.py:56 +#: finance/models.py:57 msgid "Price per night" msgstr "Preis pro Nacht" -#: finance/models.py:58 +#: finance/models.py:59 msgid "Submitted" msgstr "Eingericht" -#: finance/models.py:59 +#: finance/models.py:60 msgid "Submitted on" msgstr "Eingereicht am" -#: finance/models.py:60 +#: finance/models.py:61 msgid "Confirmed" msgstr "Abgewickelt" -#: finance/models.py:61 finance/models.py:448 +#: finance/models.py:62 finance/models.py:473 msgid "Paid on" msgstr "Bezahlt am" -#: finance/models.py:63 +#: finance/models.py:64 msgid "Created by" msgstr "Erstellt von" -#: finance/models.py:68 +#: finance/models.py:69 msgid "Submitted by" msgstr "Eingereicht bei" -#: finance/models.py:73 finance/models.py:449 +#: finance/models.py:74 finance/models.py:474 msgid "Authorized by" msgstr "Autorisiert von" -#: finance/models.py:80 finance/models.py:383 finance/models.py:444 +#: finance/models.py:81 finance/models.py:408 finance/models.py:469 msgid "Statement" msgstr "Abrechnung" -#: finance/models.py:81 +#: finance/models.py:82 msgid "Statements" msgstr "Abrechnungen" -#: finance/models.py:96 +#: finance/models.py:97 #, python-format msgid "Statement: %(excursion)s" msgstr "Abrechnung: %(excursion)s" -#: finance/models.py:148 +#: finance/models.py:149 msgid "Ready to confirm" msgstr "Bereit zur Abwicklung" -#: finance/models.py:192 +#: finance/models.py:193 #, python-format msgid "Compensation for %(excu)s" msgstr "Entschädigung für %(excu)s" -#: finance/models.py:325 +#: finance/models.py:326 #: finance/templates/admin/overview_submitted_statement.html:78 msgid "Total" msgstr "Gesamtbetrag" -#: finance/models.py:338 +#: finance/models.py:363 msgid "Statement in preparation" msgstr "Abrechnung in Vorbereitung" -#: finance/models.py:339 +#: finance/models.py:364 msgid "Statements in preparation" msgstr "Abrechnungen in Vorbereitung" -#: finance/models.py:358 +#: finance/models.py:383 msgid "Submitted statement" msgstr "Eingereichte Abrechnung" -#: finance/models.py:359 +#: finance/models.py:384 msgid "Submitted statements" msgstr "Eingereichte Abrechnungen" -#: finance/models.py:375 +#: finance/models.py:400 msgid "Paid statement" msgstr "Bezahlte Abrechnung" -#: finance/models.py:376 +#: finance/models.py:401 msgid "Paid statements" msgstr "Bezahlte Abrechnungen" -#: finance/models.py:388 +#: finance/models.py:412 finance/models.py:426 finance/models.py:463 +#: finance/templates/admin/confirmed_statement.html:36 +#: finance/templates/admin/overview_submitted_statement.html:31 +#: finance/templates/admin/overview_submitted_statement.html:98 +msgid "Amount" +msgstr "Betrag" + +#: finance/models.py:413 msgid "Paid by" msgstr "Bezahlt von" -#: finance/models.py:390 +#: finance/models.py:415 msgid "Covered" msgstr "Übernommen" -#: finance/models.py:391 +#: finance/models.py:416 msgid "Refunded" msgstr "Ausgezahlt" -#: finance/models.py:393 +#: finance/models.py:418 msgid "Proof" msgstr "Beleg" -#: finance/models.py:401 finance/models.py:438 -#: finance/templates/admin/confirmed_statement.html:36 -#: finance/templates/admin/overview_submitted_statement.html:31 -#: finance/templates/admin/overview_submitted_statement.html:98 -msgid "Amount" -msgstr "Betrag" - -#: finance/models.py:404 finance/models.py:411 finance/models.py:424 +#: finance/models.py:429 finance/models.py:436 finance/models.py:449 msgid "Bill" msgstr "Quittung" -#: finance/models.py:405 finance/models.py:412 finance/models.py:425 +#: finance/models.py:430 finance/models.py:437 finance/models.py:450 #: finance/templates/admin/overview_submitted_statement.html:26 msgid "Bills" msgstr "Quittungen" -#: finance/models.py:437 finance/templates/admin/confirmed_statement.html:37 +#: finance/models.py:462 finance/templates/admin/confirmed_statement.html:37 #: finance/templates/admin/overview_submitted_statement.html:99 msgid "Reference" msgstr "Verwendungszweck" -#: finance/models.py:439 +#: finance/models.py:464 msgid "Recipient" msgstr "Empfänger" -#: finance/models.py:447 +#: finance/models.py:472 msgid "Paid" msgstr "Bezahlt" -#: finance/models.py:459 +#: finance/models.py:484 msgid "Transaction" msgstr "Überweisung" -#: finance/models.py:460 +#: finance/models.py:485 #: finance/templates/admin/overview_submitted_statement.html:84 msgid "Transactions" msgstr "Überweisungen" diff --git a/jdav_web/finance/models.py b/jdav_web/finance/models.py index 1cfc2a4..5704f01 100644 --- a/jdav_web/finance/models.py +++ b/jdav_web/finance/models.py @@ -12,6 +12,7 @@ from django.conf import settings import rules from contrib.models import CommonModel from contrib.rules import has_global_perm +from utils import cvt_to_decimal # Create your models here. @@ -324,6 +325,30 @@ class Statement(CommonModel): return "{}€".format(self.total) total_pretty.short_description = _('Total') + def template_context(self): + context = { + 'total_bills': self.total_bills, + 'total_bills_theoretic': self.total_bills_theoretic, + 'total': self.total, + } + if self.excursion: + excursion_context = { + 'nights': self.excursion.night_count, + 'price_per_night': self.real_night_cost, + 'duration': self.excursion.duration, + 'staff_count': self.real_staff_count, + 'kilometers_traveled': self.excursion.kilometers_traveled, + 'means_of_transport': self.excursion.get_tour_approach(), + 'euro_per_km': self.euro_per_km, + 'allowance_per_day': settings.ALLOWANCE_PER_DAY, + 'nights_per_yl': self.nights_per_yl, + 'allowance_per_yl': self.allowance_per_yl, + 'transportation_per_yl': self.transportation_per_yl, + 'total_per_yl': self.total_per_yl, + 'total_staff': self.total_staff, + } + return dict(context, **excursion_context) + class StatementUnSubmittedManager(models.Manager): def get_queryset(self): @@ -384,7 +409,7 @@ class Bill(CommonModel): short_description = models.CharField(verbose_name=_('Short description'), max_length=30) explanation = models.TextField(verbose_name=_('Explanation'), blank=True) - amount = models.DecimalField(max_digits=6, decimal_places=2, default=0) + amount = models.DecimalField(verbose_name=_('Amount'), max_digits=6, decimal_places=2, default=0) paid_by = models.ForeignKey(Member, verbose_name=_('Paid by'), null=True, on_delete=models.SET_NULL) costs_covered = models.BooleanField(verbose_name=_('Covered'), default=False) @@ -466,7 +491,3 @@ class Receipt(models.Model): on_delete=models.CASCADE) amount = models.DecimalField(max_digits=6, decimal_places=2) comments = models.TextField() - - -def cvt_to_decimal(f): - return Decimal(f).quantize(Decimal('.01'), rounding=ROUND_HALF_DOWN) diff --git a/jdav_web/locale/de/LC_MESSAGES/django.po b/jdav_web/locale/de/LC_MESSAGES/django.po index 49905e1..7ed7671 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: 2024-11-30 01:22+0100\n" +"POT-Creation-Date: 2024-11-30 03:54+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -264,9 +264,11 @@ msgstr "Übersicht erstellen" msgid "Generate seminar report" msgstr "Seminarbericht erstellen" -#: templates/admin/members/freizeit/change_form_object_tools.html:36 -msgid "Submit statement" -msgstr "Abrechnung einreichen" +#: templates/admin/members/freizeit/change_form_object_tools.html:38 +#, fuzzy +#| msgid "Generate overview" +msgid "Finance overview" +msgstr "Übersicht erstellen" #: templates/admin/members/member/change_form_object_tools.html:8 msgid "Invite as user" @@ -286,14 +288,17 @@ msgstr "Zu Gruppe einladen" msgid "Add another %(verbose_name)s" msgstr "Weiteren %(verbose_name)s hinzufügen" -#: utils.py:14 +#: utils.py:15 msgid "Please keep filesize under {} MiB. Current filesize: {:10.2f} MiB." msgstr "Maximale Dateigröße {} MiB. Aktuelle Dateigröße: {:10.2f} MiB." -#: utils.py:42 +#: utils.py:43 msgid "Filetype not supported." msgstr "Dateityp nicht unterstützt." -#: utils.py:44 +#: utils.py:45 msgid "Please keep filesize under {}. Current filesize: {}" msgstr "Maximale Dateigröße {}. Aktuelle Dateigröße: {}." + +#~ msgid "Submit statement" +#~ msgstr "Abrechnung einreichen" diff --git a/jdav_web/members/admin.py b/jdav_web/members/admin.py index ed28f4d..0d24940 100644 --- a/jdav_web/members/admin.py +++ b/jdav_web/members/admin.py @@ -41,6 +41,7 @@ from .models import (Member, Group, Freizeit, MemberNoteList, NewMemberOnList, K from finance.models import Statement, BillOnExcursionProxy from mailer.mailutils import send as send_mail, get_echo_link from django.conf import settings +from utils import get_member #from easy_select2 import apply_select2 @@ -924,6 +925,25 @@ class FreizeitAdmin(CommonAdminMixin, nested_admin.NestedModelAdmin): return fill_pdf_form(title + "_SJR_Antrag", 'members/sjr_template.pdf', context, attachments) sjr_application.short_description = _('Generate SJR application') + def finance_overview(self, request, memberlist): + if not memberlist.statement: + messages.error(request, _("No statement found. Please add a statement and then retry.")) + if "apply" in request.POST: + memberlist.statement.submit(get_member(request)) + messages.success(request, + _("Successfully submited statement. The finance department will notify you as soon as possible.")) + return HttpResponseRedirect(reverse('admin:%s_%s_change' % (self.opts.app_label, self.opts.model_name), args=(memberlist.pk,))) + context = dict(self.admin_site.each_context(request), + title=_('Finance overview'), + opts=self.opts, + memberlist=memberlist, + object=memberlist, + participant_count=memberlist.participant_count, + ljp_contributions=memberlist.potential_ljp_contributions, + total_relative_costs=memberlist.total_relative_costs, + **memberlist.statement.template_context()) + return render(request, 'admin/freizeit_finance_overview.html', context=context) + def get_urls(self): urls = super().get_urls() @@ -952,6 +972,8 @@ class FreizeitAdmin(CommonAdminMixin, nested_admin.NestedModelAdmin): return self.notes_list(request, Freizeit.objects.get(pk=object_id)) if "crisis_intervention_list" in request.POST: return self.crisis_intervention_list(request, Freizeit.objects.get(pk=object_id)) + if "finance_overview" in request.POST: + return self.finance_overview(request, Freizeit.objects.get(pk=object_id)) return HttpResponseRedirect(reverse('admin:%s_%s_change' % (self.opts.app_label, self.opts.model_name), args=(object_id,))) diff --git a/jdav_web/members/locale/de/LC_MESSAGES/django.po b/jdav_web/members/locale/de/LC_MESSAGES/django.po index 04677ac..200a4bc 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: 2024-11-30 01:22+0100\n" +"POT-Creation-Date: 2024-11-30 03:54+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,169 +18,169 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: members/admin.py:125 members/models.py:381 +#: members/admin.py:126 members/models.py:382 msgid "Registration complete" msgstr "Anmeldung vollständig" -#: members/admin.py:131 +#: members/admin.py:132 msgid "True" msgstr "Ja" -#: members/admin.py:132 +#: members/admin.py:133 msgid "False" msgstr "Nein" -#: members/admin.py:133 +#: members/admin.py:134 msgid "All" msgstr "Alle" -#: members/admin.py:183 members/admin.py:400 +#: members/admin.py:184 members/admin.py:401 msgid "Contact information" msgstr "Kontaktinformationen" -#: members/admin.py:188 members/admin.py:405 +#: members/admin.py:189 members/admin.py:406 msgid "Skills" msgstr "Fähigkeiten" -#: members/admin.py:193 members/admin.py:410 +#: members/admin.py:194 members/admin.py:411 msgid "Others" msgstr "Sonstiges" -#: members/admin.py:199 members/admin.py:415 +#: members/admin.py:200 members/admin.py:416 msgid "Organizational" msgstr "Organisatorisches" -#: members/admin.py:280 +#: members/admin.py:281 msgid "Compose new mail to selected members" msgstr "Neue Nachricht an ausgewählte Teilnehmer verfassen" -#: members/admin.py:286 +#: members/admin.py:287 msgid "Echo required" msgstr "Rückmeldung erforderlich" -#: members/admin.py:288 +#: members/admin.py:289 msgid "Successfully requested echo from selected members." msgstr "" "Rückmeldungsaufforderung erfolgreich an ausgewählte Teilnehmer verschickt." -#: members/admin.py:289 +#: members/admin.py:290 msgid "Request echo from selected members" msgstr "Rückmeldungsaufforderung an ausgewählte Teilnehmer verschicken" -#: members/admin.py:295 +#: members/admin.py:296 #, python-format msgid "Successfully invited %(name)s as user." msgstr "Erfolgreich %(name)s aufgefordert Zugangsdaten zu wählen." -#: members/admin.py:297 +#: members/admin.py:298 msgid "Successfully invited selected members to join as users." msgstr "" "Erfolgreich ausgewählte Teilnehmer:innen aufgefordert Zugangsdaten zu wählen." -#: members/admin.py:304 members/admin.py:321 +#: members/admin.py:305 members/admin.py:322 msgid "Permission denied." msgstr "Fehlende Berechtigungen." -#: members/admin.py:311 members/admin.py:340 +#: members/admin.py:312 members/admin.py:341 #: members/templates/admin/invite_as_user.html:21 msgid "Invite as user" msgstr "Kompass Zugangsdaten wählen lassen" -#: members/admin.py:316 +#: members/admin.py:317 msgid "Invite selected members to join Kompass as users." msgstr "Ausgewählte Teilnehmer:innen Kompass Zugangsdaten wählen lassen." -#: members/admin.py:327 +#: members/admin.py:328 msgid "Member not found." msgstr "Teilnehmer:in nicht gefunden." -#: members/admin.py:331 +#: members/admin.py:332 #, python-format msgid "%(name)s already has login data." msgstr "%(name)s hat schon Zugangsdaten." -#: members/admin.py:345 +#: members/admin.py:346 #, python-format msgid "%(name)s already has a pending invitation as user." msgstr "" "%(name)s hat bereits eine ausstehende Aufforderung Zugangsdaten zu wählen." -#: members/admin.py:363 +#: members/admin.py:364 msgid "activity" msgstr "Aktivität" -#: members/admin.py:373 members/models.py:53 members/models.py:1395 +#: members/admin.py:374 members/models.py:54 members/models.py:1409 msgid "Name" msgstr "Name" -#: members/admin.py:449 +#: members/admin.py:450 msgid "Successfully requested mail confirmation from selected registrations." msgstr "Aufforderung zur Bestätigung der Email Adresse versendet." -#: members/admin.py:450 +#: members/admin.py:451 msgid "Request mail confirmation from selected registrations" msgstr "Aufforderung zur Bestätigung der Email Adresse versenden" -#: members/admin.py:457 members/admin.py:531 +#: members/admin.py:458 members/admin.py:532 #, python-format msgid "Successfully confirmed %(name)s." msgstr "Registrierung von %(name)s erfolgreich bestätigt." -#: members/admin.py:461 members/admin.py:534 +#: members/admin.py:462 members/admin.py:535 #, python-format msgid "Can't confirm. %(name)s has unconfirmed email addresses." msgstr "Bestätigung nicht möglich. %(name)s hat unbestätigte Emailadressen." -#: members/admin.py:466 +#: members/admin.py:467 msgid "Successfully confirmed multiple registrations." msgstr "Erfolgreich mehrere Registrierungen bestätigt." -#: members/admin.py:468 +#: members/admin.py:469 msgid "" "Failed to confirm some registrations because of unconfirmed email addresses." msgstr "" "Einige Bestätigungen fehlgeschlagen, weil Emailadressen noch nicht bestätigt " "sind." -#: members/admin.py:469 +#: members/admin.py:470 msgid "Confirm selected registrations" msgstr "Ausgewählte Registrierungen bestätigen" -#: members/admin.py:492 +#: members/admin.py:493 msgid "Demote selected registrations to waiters." msgstr "Ausgewählte Registrierungen zurück auf die Warteliste setzen." -#: members/admin.py:508 +#: members/admin.py:509 msgid "Demote member to waiter" msgstr "Ausgewählte Registrierung zurück auf die Warteliste setzen." -#: members/admin.py:526 +#: members/admin.py:527 #, python-format msgid "Successfully demoted %(name)s to waiter." msgstr "%(name)s zurück auf die Warteliste gesetzt." -#: members/admin.py:541 members/models.py:388 members/models.py:732 -#: members/models.py:1140 +#: members/admin.py:542 members/models.py:389 members/models.py:733 +#: members/models.py:1154 msgid "Group" msgstr "Gruppe" -#: members/admin.py:575 +#: members/admin.py:576 #, python-format msgid "Successfully asked %(name)s to confirm their waiting status." msgstr "Erfolgreich %(name)s aufgefordert den Wartelistenplatz zu bestätigen." -#: members/admin.py:576 +#: members/admin.py:577 msgid "Ask selected waiters to confirm their waiting status" msgstr "Wartende auffordern den Wartelistenplatz zu bestätigen" -#: members/admin.py:585 members/admin.py:645 +#: members/admin.py:586 members/admin.py:646 msgid "" "An error occurred while trying to invite said members. Please try again." msgstr "" "Beim Einladen dieser Personen ist ein Fehler aufgetreten. Bitte versuche es " "nochmal. " -#: members/admin.py:589 members/admin.py:650 +#: members/admin.py:590 members/admin.py:651 msgid "" "The selected group does not have a contact email. Please first set a contact " "email and then try again." @@ -188,32 +188,32 @@ msgstr "" "Die ausgewählte Gruppe hat keine Kontakt E-Mail Adresse. Bitte stelle eine " "Kontakt E-Mail Adresse ein und versuche es erneut." -#: members/admin.py:597 members/admin.py:657 +#: members/admin.py:598 members/admin.py:658 #, python-format msgid "Successfully invited %(name)s to %(group)s." msgstr "Erfolgreich %(name)s zu Gruppe %(group)s eingeladen." -#: members/admin.py:601 members/admin.py:663 +#: members/admin.py:602 members/admin.py:664 msgid "Select group for invitation" msgstr "Wähle Gruppe für Einladung aus" -#: members/admin.py:608 +#: members/admin.py:609 msgid "Offer waiter a place in a group." msgstr "Personen auf der Warteliste einen Gruppenplatz anbieten." -#: members/admin.py:706 +#: members/admin.py:707 msgid "Difficulty" msgstr "Schwierigkeit" -#: members/admin.py:709 +#: members/admin.py:710 msgid "Tour type" msgstr "Art der Tour" -#: members/admin.py:712 members/models.py:950 +#: members/admin.py:713 members/models.py:951 msgid "Means of transportation" msgstr "Verkehrsmittel" -#: members/admin.py:738 +#: members/admin.py:739 msgid "" "Please list here all expenses in relation with this excursion and upload " "relevant bills. These have to be permanently stored for the application of " @@ -226,7 +226,7 @@ msgstr "" "einzelnen Posten wird dabei auf der LJP-Kostenübersicht angezeigt (sinnvoll " "wären z.B. Anreise, Verpflegung, Material etc.)." -#: members/admin.py:756 +#: members/admin.py:757 msgid "" "Here you can work on a seminar report for applying for financial " "contributions from Landesjugendplan (LJP). More information on creating a " @@ -239,7 +239,7 @@ msgstr "" "wahlweise nur TN-Liste und Kostenübersicht kannst du anschließend " "herunterladen." -#: members/admin.py:764 +#: members/admin.py:765 msgid "" "Please list all participants (also youth leaders) of this excursion. Here " "you can still make changes just before departure and hence generate the " @@ -250,30 +250,30 @@ msgstr "" "jederzeit die aktuelle Teilnehmer:innenliste für die Krisenintervention " "generieren." -#: members/admin.py:810 +#: members/admin.py:811 #, python-format msgid "You are not allowed to view all members on note list %(name)s." msgstr "" "Du hast nicht die nötigen Rechte um alle Teilnehmer:innen der Notizliste " "%(name)s anzusehen." -#: members/admin.py:820 +#: members/admin.py:821 msgid "Generate PDF summary" msgstr "Übersicht erstellen" -#: members/admin.py:824 +#: members/admin.py:825 msgid "Full report" msgstr "Vollständiger Seminarbericht" -#: members/admin.py:825 +#: members/admin.py:826 msgid "Costs and participants only" msgstr "Nur Kosten und Teilnehmende" -#: members/admin.py:826 +#: members/admin.py:827 msgid "Mode" msgstr "Modus" -#: members/admin.py:840 +#: members/admin.py:841 msgid "" "General information on your excursion. These are partly relevant for the " "amount of financial compensation (means of transport, travel distance, etc.)." @@ -282,622 +282,643 @@ msgstr "" "teilweise relevant für die Zuschüsse aus dem Jugendetat (Verkehrsmittel, " "Fahrstrecke in km)." -#: members/admin.py:870 +#: members/admin.py:871 #, python-format msgid "You are not allowed to view all members on excursion %(name)s." msgstr "" "Du hast nicht die nötigen Rechte um alle Teilnehmer:innen der Ausfahrt " "%(name)s anzusehen." -#: members/admin.py:878 +#: members/admin.py:879 msgid "Generate crisis intervention list" msgstr "Kriseninterventionsliste erstellen" -#: members/admin.py:886 +#: members/admin.py:887 msgid "Generate overview" msgstr "Hinweise für Jugendleiter erstellen" -#: members/admin.py:890 members/admin.py:913 +#: members/admin.py:891 members/admin.py:914 #: members/templates/admin/generate_seminar_report.html:21 msgid "Generate seminar report" msgstr "Seminarbericht erstellen" -#: members/admin.py:903 +#: members/admin.py:904 msgid "Please select a mode." msgstr "Bitte wähle einen Modus aus." -#: members/admin.py:907 +#: members/admin.py:908 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:925 +#: members/admin.py:926 msgid "Generate SJR application" msgstr "SJR Antrag erstellen" +#: members/admin.py:930 +msgid "No statement found. Please add a statement and then retry." +msgstr "" +"Keine Abrechnung angelegt. Bitte lege eine Abrechnung and und versuche es " +"erneut." + +#: members/admin.py:934 +msgid "" +"Successfully submited statement. The finance department will notify you as " +"soon as possible." +msgstr "" +"Abrechnung erfolgreich eingericht. Die Finanzabteilung wird sich bei dir so " +"schnell wie möglich melden." + +#: members/admin.py:937 +#: members/templates/admin/freizeit_finance_overview.html:21 +msgid "Finance overview" +msgstr "Kostenübersicht" + #: members/apps.py:7 msgid "member administration" msgstr "Meine Jugendgruppe" -#: members/models.py:39 +#: members/models.py:40 msgid "Monday" msgstr "Montag" -#: members/models.py:40 +#: members/models.py:41 msgid "Tuesday" msgstr "Dienstag" -#: members/models.py:41 +#: members/models.py:42 msgid "Wednesday" msgstr "Mittwoch" -#: members/models.py:42 +#: members/models.py:43 msgid "Thursday" msgstr "Donnerstag" -#: members/models.py:43 +#: members/models.py:44 msgid "Friday" msgstr "Freitag" -#: members/models.py:44 +#: members/models.py:45 msgid "Saturday" msgstr "Samstag" -#: members/models.py:45 +#: members/models.py:46 msgid "Sunday" msgstr "Sonntag" -#: members/models.py:54 members/models.py:936 +#: members/models.py:55 members/models.py:937 msgid "Description" msgstr "Beschreibung" -#: members/models.py:60 members/models.py:928 +#: members/models.py:61 members/models.py:929 #: members/templates/members/change_member.html:18 msgid "Activity" msgstr "Aktivität" -#: members/models.py:61 +#: members/models.py:62 msgid "Activities" msgstr "Aktivitäten" -#: members/models.py:69 +#: members/models.py:70 msgid "name" msgstr "Name" -#: members/models.py:70 +#: members/models.py:71 msgid "description" msgstr "Beschreibung" -#: members/models.py:71 +#: members/models.py:72 msgid "show on website" msgstr "Auf der Webseite anzeigen" -#: members/models.py:72 +#: members/models.py:73 msgid "lowest year" msgstr "Ab Jahrgang" -#: members/models.py:73 +#: members/models.py:74 msgid "highest year" msgstr "Bis Jahrgang" -#: members/models.py:74 +#: members/models.py:75 msgid "youth leaders" msgstr "Jugendleiter" -#: members/models.py:76 +#: members/models.py:77 msgid "week day" msgstr "Wochentag" -#: members/models.py:77 members/models.py:1222 +#: members/models.py:78 members/models.py:1236 msgid "Starting time" msgstr "Zeitpunkt" -#: members/models.py:78 +#: members/models.py:79 msgid "Ending time" msgstr "Endzeitpunkt" -#: members/models.py:80 +#: members/models.py:81 msgid "Contact email" msgstr "Kontakt Email" -#: members/models.py:90 members/models.py:257 +#: members/models.py:91 members/models.py:258 msgid "group" msgstr "Gruppe" -#: members/models.py:91 +#: members/models.py:92 msgid "groups" msgstr "Gruppen" -#: members/models.py:107 +#: members/models.py:108 msgid "prename" msgstr "Vorname" -#: members/models.py:108 +#: members/models.py:109 msgid "last name" msgstr "Nachname" -#: members/models.py:111 +#: members/models.py:112 msgid "Email confirmed" msgstr "Emailadresse bestätigt" -#: members/models.py:148 +#: members/models.py:149 msgid "Email confirmation needed" msgstr "Email Bestätigung erforderlich" -#: members/models.py:188 members/models.py:231 +#: members/models.py:189 members/models.py:232 msgid "phone number" msgstr "Telefonnummer (mobil)" -#: members/models.py:198 +#: members/models.py:199 msgid "birth date" msgstr "Geburtsdatum" -#: members/models.py:203 +#: members/models.py:204 msgid "Gender" msgstr "Gender" -#: members/models.py:204 +#: members/models.py:205 msgid "comments" msgstr "Kommentare" -#: members/models.py:228 +#: members/models.py:229 msgid "Alternative email confirmed" msgstr "Alternative E-Mail Adresse bestätigt" -#: members/models.py:232 +#: members/models.py:233 msgid "street and house number" msgstr "Straße und Hausnummer" -#: members/models.py:233 +#: members/models.py:234 msgid "Postcode" msgstr "PLZ" -#: members/models.py:235 +#: members/models.py:236 msgid "town" msgstr "Stadt" -#: members/models.py:236 +#: members/models.py:237 msgid "Address extra" msgstr "Adress-Zusatz" -#: members/models.py:237 +#: members/models.py:238 msgid "Country" msgstr "Land" -#: members/models.py:239 +#: members/models.py:240 msgid "Good conduct certificate presented on" msgstr "Führungszeugnis vorgelegt am" -#: members/models.py:240 +#: members/models.py:241 msgid "Joined on" msgstr "Eintritt" -#: members/models.py:241 +#: members/models.py:242 msgid "Left on" msgstr "Austritt" -#: members/models.py:242 +#: members/models.py:243 msgid "Has key" msgstr "Hat Jugendraumschlüssel" -#: members/models.py:243 +#: members/models.py:244 msgid "Has a free ticket for the climbing gym" msgstr "Hat Freikarte für Kletterhalle" -#: members/models.py:244 +#: members/models.py:245 msgid "DAV badge number" msgstr "DAV Mitgliedsnummer" -#: members/models.py:245 +#: members/models.py:246 msgid "Knows how to swim" msgstr "Kann schwimmen" -#: members/models.py:246 +#: members/models.py:247 msgid "Climbing badge" msgstr "Kletterschein" -#: members/models.py:247 +#: members/models.py:248 msgid "Alpine experience" msgstr "Alpine Erfahrung" -#: members/models.py:248 +#: members/models.py:249 msgid "Allergies" msgstr "Allergieen" -#: members/models.py:249 +#: members/models.py:250 msgid "Medication" msgstr "Medikamente" -#: members/models.py:250 +#: members/models.py:251 msgid "Tetanus vaccination" msgstr "Tetanusimpfung" -#: members/models.py:251 +#: members/models.py:252 msgid "Photos may be taken" msgstr "Fotoerlaubnis" -#: members/models.py:252 +#: members/models.py:253 msgid "Legal guardians" msgstr "Erziehungsberechtigte" -#: members/models.py:254 +#: members/models.py:255 msgid "May cancel a group appointment independently" msgstr "Darf sich allein von der Gruppenstunde abmelden" -#: members/models.py:261 +#: members/models.py:262 msgid "receives newsletter" msgstr "Erhält den Newsletter" -#: members/models.py:265 +#: members/models.py:266 msgid "created" msgstr "erstellt" -#: members/models.py:266 +#: members/models.py:267 msgid "Active" msgstr "Aktiv" -#: members/models.py:267 +#: members/models.py:268 msgid "registration form" msgstr "Anmeldeformular" -#: members/models.py:275 +#: members/models.py:276 msgid "image" msgstr "Bild" -#: members/models.py:284 +#: members/models.py:285 msgid "Echoed" msgstr "Rückgemeldet" -#: members/models.py:285 +#: members/models.py:286 msgid "Confirmed" msgstr "Bestätigt" -#: members/models.py:287 +#: members/models.py:288 msgid "Login data" msgstr "Zugangsdaten" -#: members/models.py:317 +#: members/models.py:318 msgid "Good conduct certificate valid" msgstr "Führungszeugnis gültig" -#: members/models.py:391 +#: members/models.py:392 msgid "member" msgstr "Teilnehmer" -#: members/models.py:392 +#: members/models.py:393 msgid "members" msgstr "Teilnehmer" -#: members/models.py:460 +#: members/models.py:461 #, python-format msgid "New unconfirmed registration for group %(group)s" msgstr "Neue unbestätigte Registrierung für Gruppe %(group)s" -#: members/models.py:671 +#: members/models.py:672 msgid "Set login data for Kompass" msgstr "Zugangsdaten für Kompass wählen" -#: members/models.py:688 members/models.py:884 members/models.py:895 -#: members/models.py:1171 members/models.py:1178 +#: members/models.py:689 members/models.py:885 members/models.py:896 +#: members/models.py:1185 members/models.py:1192 msgid "Member" msgstr "Teilnehmer" -#: members/models.py:695 +#: members/models.py:696 msgid "Emergency contact" msgstr "Notfallkontakt" -#: members/models.py:696 +#: members/models.py:697 msgid "Emergency contacts" msgstr "Notfallkontakte" -#: members/models.py:716 +#: members/models.py:717 msgid "Unconfirmed registration" msgstr "Unbestätigte Registrierung" -#: members/models.py:717 +#: members/models.py:718 msgid "Unconfirmed registrations" msgstr "Unbestätigte Registrierungen" -#: members/models.py:731 members/models.py:776 +#: members/models.py:732 members/models.py:777 msgid "Waiter" msgstr "Wartende Person" -#: members/models.py:733 +#: members/models.py:734 msgid "Invitation date" msgstr "Einladungsdatum" -#: members/models.py:734 members/templates/members/reject_success.html:6 +#: members/models.py:735 members/templates/members/reject_success.html:6 #: members/templates/members/reject_success.html:11 msgid "Invitation rejected" msgstr "Einladung abgelehnt" -#: members/models.py:738 +#: members/models.py:739 msgid "Invitation to group" msgstr "Gruppeneinladung" -#: members/models.py:739 +#: members/models.py:740 msgid "Invitations to groups" msgstr "Gruppeneinladungen" -#: members/models.py:746 +#: members/models.py:747 msgid "Rejected" msgstr "Abgelehnt" -#: members/models.py:748 +#: members/models.py:749 msgid "Expired" msgstr "Abgelaufen" -#: members/models.py:750 +#: members/models.py:751 msgid "Undecided" msgstr "Ausstehend" -#: members/models.py:751 +#: members/models.py:752 msgid "Status" msgstr "Status" -#: members/models.py:762 +#: members/models.py:763 msgid "Do you want to tell us something else?" msgstr "Möchtest du uns noch etwas mitteilen?" -#: members/models.py:763 +#: members/models.py:764 msgid "application date" msgstr "Bewerbungsdatum" -#: members/models.py:765 +#: members/models.py:766 msgid "Last wait confirmation" msgstr "Letzte Wartebestätigung" -#: members/models.py:769 +#: members/models.py:770 msgid "Last reminder" msgstr "Letzte Erinnerung" -#: members/models.py:770 +#: members/models.py:771 msgid "Missed reminders" msgstr "Verpasste Erinnerungen" -#: members/models.py:777 +#: members/models.py:778 msgid "Waiters" msgstr "Warteliste" -#: members/models.py:801 +#: members/models.py:802 msgid "Waiting status confirmed" msgstr "Wartelistenplatz bestätigt" -#: members/models.py:808 +#: members/models.py:809 msgid "Waiting confirmation needed" msgstr "Wartelistenplatzbestätigung erforderlich" -#: members/models.py:863 +#: members/models.py:864 msgid "Invitation to trial group meeting" msgstr "Einladung zu Schnupperstunde" -#: members/models.py:875 +#: members/models.py:876 msgid "Unregistered from waiting list" msgstr "Von der Warteliste abgemeldet" -#: members/models.py:889 +#: members/models.py:890 msgid "Comment" msgstr "Kommentar" -#: members/models.py:896 members/models.py:1179 +#: members/models.py:897 members/models.py:1193 msgid "Members" msgstr "Teilnehmer" -#: members/models.py:930 +#: members/models.py:931 msgid "Place" msgstr "Stützpunkt / Ort" -#: members/models.py:931 +#: members/models.py:932 msgid "Destination (optional)" msgstr "ggf. Ziel" -#: members/models.py:933 +#: members/models.py:934 msgid "e.g. a peak" msgstr "z.B. ein Gipfel" -#: members/models.py:934 +#: members/models.py:935 msgid "Begin" msgstr "Anfang" -#: members/models.py:935 +#: members/models.py:936 msgid "End (optional)" msgstr "Ende" -#: members/models.py:938 +#: members/models.py:939 msgid "Groups" msgstr "Gruppen" -#: members/models.py:951 +#: members/models.py:952 msgid "Kilometers traveled" msgstr "Fahrstrecke in Kilometer" -#: members/models.py:954 +#: members/models.py:955 msgid "Categories" msgstr "Kategorien" -#: members/models.py:955 +#: members/models.py:956 msgid "easy" msgstr "leicht" -#: members/models.py:955 +#: members/models.py:956 msgid "medium" msgstr "mittel" -#: members/models.py:955 +#: members/models.py:956 msgid "hard" msgstr "schwer" -#: members/models.py:965 members/models.py:1202 +#: members/models.py:966 members/models.py:1216 +#: members/templates/admin/freizeit_finance_overview.html:26 msgid "Excursion" msgstr "Ausfahrt" -#: members/models.py:966 +#: members/models.py:967 msgid "Excursions" msgstr "Ausfahrten" -#: members/models.py:1117 members/models.py:1193 members/models.py:1409 +#: members/models.py:1131 members/models.py:1207 members/models.py:1423 msgid "Title" msgstr "Titel" -#: members/models.py:1118 members/models.py:1136 members/models.py:1410 +#: members/models.py:1132 members/models.py:1150 members/models.py:1424 msgid "Date" msgstr "Datum" -#: members/models.py:1137 +#: members/models.py:1151 msgid "Location" msgstr "Ort" -#: members/models.py:1138 +#: members/models.py:1152 msgid "Topic" msgstr "Thema" -#: members/models.py:1162 +#: members/models.py:1176 msgid "Jugendleiter" msgstr "Jugendleiter" -#: members/models.py:1165 +#: members/models.py:1179 msgid "Klettertreff" msgstr "Klettertreff" -#: members/models.py:1166 +#: members/models.py:1180 msgid "Klettertreffs" msgstr "Klettertreffs" -#: members/models.py:1184 +#: members/models.py:1198 msgid "Password" msgstr "Passwort" -#: members/models.py:1187 +#: members/models.py:1201 msgid "registration password" msgstr "Registrierungspassort" -#: members/models.py:1188 +#: members/models.py:1202 msgid "registration passwords" msgstr "Registrierungspasswörter" -#: members/models.py:1195 +#: members/models.py:1209 msgid "Alpinistic goals" msgstr "Alpintechnische Ziele" -#: members/models.py:1196 +#: members/models.py:1210 msgid "Pedagogic goals" msgstr "Pädagogische Ziele" -#: members/models.py:1197 +#: members/models.py:1211 msgid "Content and methods" msgstr "Inhalte und Methoden" -#: members/models.py:1198 +#: members/models.py:1212 msgid "Evaluation" msgstr "Wertung" -#: members/models.py:1199 +#: members/models.py:1213 msgid "Experiences and possible improvements" msgstr "Erfahrungen und Verbesserungsvorschläge" -#: members/models.py:1208 members/models.py:1229 +#: members/models.py:1222 members/models.py:1243 msgid "LJP Proposal" msgstr "Seminarbericht" -#: members/models.py:1209 +#: members/models.py:1223 msgid "LJP Proposals" msgstr "Seminarberichte" -#: members/models.py:1223 +#: members/models.py:1237 msgid "Duration in hours" msgstr "Dauer in Stunden" -#: members/models.py:1226 +#: members/models.py:1240 msgid "Activity and method" msgstr "Art der Aktion inkl. Methode" -#: members/models.py:1234 +#: members/models.py:1248 msgid "Intervention" msgstr "Aktion" -#: members/models.py:1235 +#: members/models.py:1249 msgid "Interventions" msgstr "Aktionen" -#: members/models.py:1337 members/models.py:1367 +#: members/models.py:1351 members/models.py:1381 msgid "May list members" msgstr "Darf folgende Teilnehmer:innen listen" -#: members/models.py:1339 members/models.py:1369 +#: members/models.py:1353 members/models.py:1383 msgid "May view members" msgstr "Darf folgende Teilnehmer:innen anzeigen" -#: members/models.py:1341 members/models.py:1371 +#: members/models.py:1355 members/models.py:1385 msgid "May change members" msgstr "Darf folgende Teilnehmer:innen ändern" -#: members/models.py:1343 members/models.py:1373 +#: members/models.py:1357 members/models.py:1387 msgid "May delete members" msgstr "Darf folgende Teilnehmer:innen löschen" -#: members/models.py:1347 members/models.py:1377 +#: members/models.py:1361 members/models.py:1391 msgid "May list members of groups" msgstr "Darf Teilnehmer:innen folgender Gruppen listen" -#: members/models.py:1349 members/models.py:1379 +#: members/models.py:1363 members/models.py:1393 msgid "May view members of groups" msgstr "Darf Teilnehmer:innen folgender Gruppen anzeigen" -#: members/models.py:1351 members/models.py:1381 +#: members/models.py:1365 members/models.py:1395 msgid "May change members of groups" msgstr "Darf Teilnehmer:innen folgender Gruppen ändern" -#: members/models.py:1353 members/models.py:1383 +#: members/models.py:1367 members/models.py:1397 msgid "May delete members of groups" msgstr "Darf Teilnehmer:innen folgender Gruppen löschen" -#: members/models.py:1356 members/models.py:1357 members/models.py:1360 +#: members/models.py:1370 members/models.py:1371 members/models.py:1374 msgid "Permissions" msgstr "Berechtigungen" -#: members/models.py:1386 members/models.py:1387 members/models.py:1390 +#: members/models.py:1400 members/models.py:1401 members/models.py:1404 msgid "Group permissions" msgstr "Gruppenberechtigungen" -#: members/models.py:1396 +#: members/models.py:1410 msgid "Permission needed" msgstr "Freigabe erforderlich" -#: members/models.py:1399 +#: members/models.py:1413 msgid "Training category" msgstr "Fortbildungstyp" -#: members/models.py:1400 +#: members/models.py:1414 msgid "Training categories" msgstr "Fortbildungstypen" -#: members/models.py:1411 +#: members/models.py:1425 msgid "Category" msgstr "Kategorien" -#: members/models.py:1412 +#: members/models.py:1426 msgid "Comments" msgstr "Kommentar" -#: members/models.py:1413 +#: members/models.py:1427 msgid "Participated" msgstr "Teilgenommmen" -#: members/models.py:1414 +#: members/models.py:1428 msgid "Passed" msgstr "Bestanden" -#: members/models.py:1417 +#: members/models.py:1431 msgid "Training" msgstr "Fortbildung" -#: members/models.py:1418 +#: members/models.py:1432 msgid "Trainings" msgstr "Fortbildungen" #: members/templates/admin/demote_to_waiter.html:17 +#: members/templates/admin/freizeit_finance_overview.html:17 #: members/templates/admin/generate_seminar_report.html:17 #: members/templates/admin/invite_as_user.html:17 #: members/templates/admin/invite_for_group.html:17 @@ -914,14 +935,14 @@ msgstr "Zurück auf die Warteliste setzen" #: members/templates/admin/demote_to_waiter.html:27 msgid "" "Do you want to demote the following unconfirmed registrations to waiters?" -msgstr "" -"Möchtest du die folgenden Personen zurück auf die Warteliste setzen?" +msgstr "Möchtest du die folgenden Personen zurück auf die Warteliste setzen?" #: members/templates/admin/demote_to_waiter.html:45 msgid "Demote" msgstr "Zurück auf die Warteliste setzen" #: members/templates/admin/demote_to_waiter.html:46 +#: members/templates/admin/freizeit_finance_overview.html:153 #: members/templates/admin/generate_seminar_report.html:54 #: members/templates/admin/invite_as_user.html:37 #: members/templates/admin/invite_for_group.html:52 @@ -930,6 +951,182 @@ msgstr "Zurück auf die Warteliste setzen" msgid "Cancel" msgstr "Abbrechen" +#: members/templates/admin/freizeit_finance_overview.html:29 +msgid "" +"\n" +"Here you see an estimate on the expected costs and contributions by the " +"association. This is not a guaranteed\n" +"cost plan!\n" +msgstr "" +"\n" +"Hier siehst du eine Schätzung der erwarteten Kosten und Zuschüsse. Dies ist " +"kein garantierter Kostenplan.\n" + +#: members/templates/admin/freizeit_finance_overview.html:34 +#: members/templates/admin/freizeit_finance_overview.html:99 +msgid "Expenses" +msgstr "Ausgaben" + +#: members/templates/admin/freizeit_finance_overview.html:35 +msgid "You listed the following expenses:" +msgstr "Du hast die folgenden Ausgaben angegeben:" + +#: members/templates/admin/freizeit_finance_overview.html:39 +msgid "Amount" +msgstr "Betrag" + +#: members/templates/admin/freizeit_finance_overview.html:57 +#, python-format +msgid "The total expected expenses are %(total_bills_theoretic)s €." +msgstr "" +"Insgesamt belaufen sich die geschätzten Ausgaben auf " +"%(total_bills_theoretic)s €." + +#: members/templates/admin/freizeit_finance_overview.html:59 +#: members/templates/admin/freizeit_finance_overview.html:107 +msgid "Contributions by the association" +msgstr "Sektionszuschüsse" + +#: members/templates/admin/freizeit_finance_overview.html:62 +#, python-format +msgid "" +"According to the contribution guidelines,\n" +"%(staff_count)s youth leader(s) receive contributions. Each of them receives" +msgstr "" +"Gemäß den Zuschussrichtlinien erhalten %(staff_count)s Jugendleiter:innen " +"Zuschüsse. Jeweils sind das" + +#: members/templates/admin/freizeit_finance_overview.html:68 +#, python-format +msgid "" +"%(nights)s nights for %(price_per_night)s€ per night making a total of " +"%(nights_per_yl)s€." +msgstr "" +"%(nights)s Nächte zum Preis von %(price_per_night)s€ pro Nacht. Das ergibt " +"eine Gesamtsumme von %(nights_per_yl)s€." + +#: members/templates/admin/freizeit_finance_overview.html:71 +#, python-format +msgid "" +"%(duration)s days for %(allowance_per_day)s€ per day making a total of " +"%(allowance_per_yl)s€." +msgstr "" +"%(duration)s Tage für %(allowance_per_day)s€ pro Tag. Das ergibt eine " +"Gesamtsumme von %(allowance_per_yl)s€." + +#: members/templates/admin/freizeit_finance_overview.html:74 +#, python-format +msgid "" +"%(kilometers_traveled)s km by %(means_of_transport)s (%(euro_per_km)s € / " +"km) making a total of %(transportation_per_yl)s€." +msgstr "" +"%(kilometers_traveled)s km mit %(means_of_transport)s (%(euro_per_km)s€ / " +"km). Das ergibt eine Gesamtsumme von %(transportation_per_yl)s€." + +#: members/templates/admin/freizeit_finance_overview.html:79 +#, python-format +msgid "" +"In total these are contributions of %(total_per_yl)s€ times %(staff_count)s, " +"giving %(total_staff)s€." +msgstr "" +"Insgesamt sind das Kosten von %(total_per_yl)s€ mal %(staff_count)s, " +"insgesamt also %(total_staff)s€." + +#: members/templates/admin/freizeit_finance_overview.html:82 +msgid "LJP contributions" +msgstr "LJP Zuschüsse" + +#: members/templates/admin/freizeit_finance_overview.html:85 +#, python-format +msgid "" +"By submitting a seminar report, you may apply for LJP contributions. In this " +"case,\n" +"you may obtain up to 25€ times %(duration)s days for %(participant_count)s " +"participants but only up to\n" +"90%% of the total costs. This results in a total of %(ljp_contributions)s€." +msgstr "" +"Indem du einen Seminarbericht anfertigst, kannst du Landesjugendplan (LJP) " +"Zuschüsse beantragen. In diesem Fall kannst du bis zu 25€ mal %(duration)s " +"Tage für %(participant_count)s Teilnehmende, aber nicht mehr als 90%% der " +"Gesamtausgaben erhalten. Das resultiert in einem Gesamtzuschuss von " +"%(ljp_contributions)s€." + +#: members/templates/admin/freizeit_finance_overview.html:90 +msgid "Summary" +msgstr "Zusammenfassung" + +#: members/templates/admin/freizeit_finance_overview.html:93 +msgid "This is the estimated cost and contribution summary:" +msgstr "Das ist die geschätzte Kosten- und Zuschussübersicht." + +#: members/templates/admin/freizeit_finance_overview.html:115 +msgid "Potential LJP contributions" +msgstr "Mögliche LJP Zuschüsse" + +#: members/templates/admin/freizeit_finance_overview.html:123 +msgid "Remaining costs" +msgstr "Verbleibende Kosten" + +#: members/templates/admin/freizeit_finance_overview.html:132 +msgid "" +"Positive remaining costs indicate that the estimated costs exceed the " +"estimated contributions, while negative\n" +"remaining costs indicate that the estimated contributions exceed the " +"estimated costs." +msgstr "" +"Positive verbleibende Kosten bedeuten, dass die geschätzten Kosten die " +"geschätzten Zuschüsse übersteigen, während negative Kosten\n" +" bedeuten, dass die geschätzten Zuschüsse die geschätzten Kosten übersteigen." + +#: members/templates/admin/freizeit_finance_overview.html:136 +msgid "" +"Note that this cost calculation expects you to apply for LJP contributions. " +"On the\n" +"excursions main page, you can generate a template for a seminar report." +msgstr "" +"Beachte dass diese Kostenkalkulation davon ausgeht, dass du LJP Zuschüsse " +"beantragst. Auf der Hauptseite dieser Ausfahrt kannst du dir eine Vorlage " +"und alle Formblätter für einen solchen Antrag erstellen lassen." + +#: members/templates/admin/freizeit_finance_overview.html:141 +msgid "Submit statement" +msgstr "Abrechnung einreichen" + +#: members/templates/admin/freizeit_finance_overview.html:143 +msgid "" +"Did you already complete this excursion? If yes, please check if all listed " +"expenses are correct\n" +"and then submit the statement for processing by the finance department. If " +"you proceed,\n" +"no further changes to the statement are possible." +msgstr "" +"Hat die Ausfahrt bereits stattgefunden? Wenn ja, prüfe bitte ob alle " +"aufgelisteten Kosten korrekt sind und reiche deine Abrechnung dann beim " +"Finanzreferat ein. Wenn du fortschreitest sind keine weiteren Änderungen an " +"der Abrechnung mehr möglich." + +#: members/templates/admin/freizeit_finance_overview.html:152 +msgid "Submit" +msgstr "Einreichen" + +#: members/templates/admin/freizeit_finance_overview.html:157 +msgid "Statement submitted" +msgstr "Abrechnung eingereicht" + +#: members/templates/admin/freizeit_finance_overview.html:159 +msgid "" +"The statement for this excursion was already submitted. The finance " +"department is currently processing your\n" +"data and you will receive a response shortly." +msgstr "" +"Die Abrechnung für diese Ausfahrt wurde bereits eingereicht. Das " +"Finanzreferat bearbeitet deine Abrechnung zur Zeit und kommt " +"schnellstmöglich auf dich zurück." + +#: members/templates/admin/freizeit_finance_overview.html:162 +msgid "Back" +msgstr "Zurück" + #: members/templates/admin/generate_seminar_report.html:27 msgid "" "Here you can generate a seminar report suitable for the LJP. A report\n" diff --git a/jdav_web/members/models.py b/jdav_web/members/models.py index 6e302c7..3b6739e 100644 --- a/jdav_web/members/models.py +++ b/jdav_web/members/models.py @@ -24,6 +24,7 @@ from .rules import may_view, may_change, may_delete, is_own_training, is_oneself import rules from contrib.models import CommonModel from contrib.rules import memberize_user, has_global_perm +from utils import cvt_to_decimal from dateutil.relativedelta import relativedelta @@ -1023,6 +1024,19 @@ class Freizeit(CommonModel): jls = set(self.jugendleiter.distinct()) return len(ps - jls) + @property + def potential_ljp_contributions(self): + return cvt_to_decimal(min(25 * self.participant_count * self.duration, + 0.9 * float(self.statement.total_bills_theoretic) + float(self.statement.total_staff))) + + @property + def total_relative_costs(self): + if not self.statement: + return 0 + total_costs = self.statement.total_bills_theoretic + total_contributions = self.statement.total_staff + self.potential_ljp_contributions + return total_costs - total_contributions + @property def time_period_str(self): time_period = self.date.strftime('%d.%m.%Y') diff --git a/jdav_web/members/templates/admin/freizeit_finance_overview.html b/jdav_web/members/templates/admin/freizeit_finance_overview.html new file mode 100644 index 0000000..9026873 --- /dev/null +++ b/jdav_web/members/templates/admin/freizeit_finance_overview.html @@ -0,0 +1,166 @@ +{% 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 %} +

    {% trans 'Excursion' %}: {{ memberlist.name }}

    + +

    +{% blocktrans %} +Here you see an estimate on the expected costs and contributions by the association. This is not a guaranteed +cost plan! +{% endblocktrans %} +

    +

    {% translate "Expenses" %}

    +{% blocktrans %}You listed the following expenses:{% endblocktrans %} +

    + + + + {% for bill in memberlist.statement.bill_set.all %} + + + + + + {% endfor %} +
    + {% trans "Amount" %}
    + {{bill.short_description}} + + {{bill.explanation}} + + {{ bill.amount }}€. +
    +

    + +

    {% blocktrans %}The total expected expenses are {{ total_bills_theoretic }} €.{% endblocktrans %}

    + +

    {% trans "Contributions by the association" %}

    + +

    +{% blocktrans %}According to the contribution guidelines, +{{ staff_count }} youth leader(s) receive contributions. Each of them receives{% endblocktrans %} +

    +

    +

      +
    • + {% blocktrans %}{{ nights }} nights for {{ price_per_night }}€ per night making a total of {{ nights_per_yl }}€.{% endblocktrans %} +
    • +
    • + {% blocktrans %}{{ duration }} days for {{ allowance_per_day }}€ per day making a total of {{ allowance_per_yl }}€.{% endblocktrans %} +
    • +
    • + {% blocktrans %}{{ kilometers_traveled }} km by {{ means_of_transport }} ({{euro_per_km}} € / km) making a total of {{ transportation_per_yl }}€.{% endblocktrans %} +
    • +
    +

    +

    +{% blocktrans %}In total these are contributions of {{ total_per_yl }}€ times {{ staff_count }}, giving {{ total_staff }}€.{% endblocktrans %} +

    + +

    {% trans "LJP contributions" %}

    + +

    +{% blocktrans %}By submitting a seminar report, you may apply for LJP contributions. In this case, +you may obtain up to 25€ times {{ duration }} days for {{ participant_count }} participants but only up to +90% of the total costs. This results in a total of {{ ljp_contributions }}€.{% endblocktrans %} +

    + +

    {% trans "Summary" %}

    + +

    +{% blocktrans %}This is the estimated cost and contribution summary:{% endblocktrans %} +

    + + + + + + + + + + + + + + + + + + +
    + {% trans "Expenses" %} + + {{ total_bills_theoretic }}€ +
    + {% trans "Contributions by the association" %} + + -{{ total_staff }}€ +
    + {% trans "Potential LJP contributions" %} + + -{{ ljp_contributions }}€ +
    + {% trans "Remaining costs" %} + + {{ total_relative_costs }}€ +
    +
    +

    +{% blocktrans %}Positive remaining costs indicate that the estimated costs exceed the estimated contributions, while negative +remaining costs indicate that the estimated contributions exceed the estimated costs.{% endblocktrans %} +

    +

    +{% blocktrans %}Note that this cost calculation expects you to apply for LJP contributions. On the +excursions main page, you can generate a template for a seminar report.{% endblocktrans %} +

    + +{% if not memberlist.statement.submitted %} +

    {% trans "Submit statement" %}

    +

    +{% blocktrans %}Did you already complete this excursion? If yes, please check if all listed expenses are correct +and then submit the statement for processing by the finance department. If you proceed, +no further changes to the statement are possible.{% endblocktrans %} +

    + +
    + {% csrf_token %} + + + + {% translate "Cancel" %} +
    +{% else %} +
    +

    {% trans "Statement submitted" %}

    +

    +{% blocktrans %}The statement for this excursion was already submitted. The finance department is currently processing your +data and you will receive a response shortly.{% endblocktrans %} +

    +{% translate "Back" %} + +{% endif %} + +{% endblock %} 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 99af802..7facebe 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 @@ -31,9 +31,12 @@ -{% if original.statement and not original.statement.submitted %} +{% if original.statement %}
  • -{% trans 'Submit statement' %} +
    + {% csrf_token %} + +
  • {% endif %} {{block.super}} diff --git a/jdav_web/utils.py b/jdav_web/utils.py index 9060743..b6131bc 100644 --- a/jdav_web/utils.py +++ b/jdav_web/utils.py @@ -1,6 +1,7 @@ from django.db import models from django.core.exceptions import ValidationError from django.utils.translation import gettext_lazy as _ +from decimal import Decimal, ROUND_HALF_DOWN def file_size_validator(max_upload_size): @@ -48,3 +49,14 @@ class RestrictedFileField(models.FileField): except AttributeError as e: print(e) return data + + +def cvt_to_decimal(f): + return Decimal(f).quantize(Decimal('.01'), rounding=ROUND_HALF_DOWN) + + +def get_member(request): + if not hasattr(request.user, 'member'): + return None + else: + return request.user.member From 302565d5f5c65afb31d9a08b7e6e9a0f9a21a51d Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Sat, 30 Nov 2024 04:00:50 +0100 Subject: [PATCH 21/56] finance/bill: rename --- jdav_web/finance/admin.py | 2 +- jdav_web/finance/locale/de/LC_MESSAGES/django.po | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/jdav_web/finance/admin.py b/jdav_web/finance/admin.py index a1c8e82..41468a0 100644 --- a/jdav_web/finance/admin.py +++ b/jdav_web/finance/admin.py @@ -307,6 +307,6 @@ class TransactionAdmin(admin.ModelAdmin): @admin.register(Bill) class BillAdmin(admin.ModelAdmin): - list_display = ['__str__', 'statement', 'short_description', 'pretty_amount', 'paid_by', 'refunded'] + list_display = ['__str__', 'statement', 'explanation', 'pretty_amount', 'paid_by', 'refunded'] list_filter = ('statement', 'paid_by', 'refunded') search_fields = ('reference', 'statement') diff --git a/jdav_web/finance/locale/de/LC_MESSAGES/django.po b/jdav_web/finance/locale/de/LC_MESSAGES/django.po index 1d0f727..8e561f5 100644 --- a/jdav_web/finance/locale/de/LC_MESSAGES/django.po +++ b/jdav_web/finance/locale/de/LC_MESSAGES/django.po @@ -266,12 +266,12 @@ msgstr "Beleg" #: finance/models.py:429 finance/models.py:436 finance/models.py:449 msgid "Bill" -msgstr "Quittung" +msgstr "Ausgabe" #: finance/models.py:430 finance/models.py:437 finance/models.py:450 #: finance/templates/admin/overview_submitted_statement.html:26 msgid "Bills" -msgstr "Quittungen" +msgstr "Ausgaben" #: finance/models.py:462 finance/templates/admin/confirmed_statement.html:37 #: finance/templates/admin/overview_submitted_statement.html:99 From eaccc5a5ef93ac88d9136cc840b7c6b61def5b4d Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Sat, 30 Nov 2024 04:22:48 +0100 Subject: [PATCH 22/56] members/excursion: group bills in seminar report --- jdav_web/finance/models.py | 6 ++ .../members/locale/de/LC_MESSAGES/django.po | 75 +++++++++++-------- .../admin/freizeit_finance_overview.html | 3 +- .../admin/generate_seminar_report.html | 4 + .../templates/members/seminar_report.tex | 2 +- 5 files changed, 58 insertions(+), 32 deletions(-) diff --git a/jdav_web/finance/models.py b/jdav_web/finance/models.py index 5704f01..b2bc714 100644 --- a/jdav_web/finance/models.py +++ b/jdav_web/finance/models.py @@ -6,6 +6,7 @@ from .rules import is_creator, not_submitted, leads_excursion from members.rules import is_leader, statement_not_submitted from django.db import models +from django.db.models import Sum from django.utils.translation import gettext_lazy as _ from members.models import Member, Freizeit, OEFFENTLICHE_ANREISE, MUSKELKRAFT_ANREISE from django.conf import settings @@ -349,6 +350,11 @@ class Statement(CommonModel): } return dict(context, **excursion_context) + def grouped_bills(self): + return self.bill_set.values('short_description')\ + .order_by('short_description')\ + .annotate(amount=Sum('amount')) + class StatementUnSubmittedManager(models.Manager): def get_queryset(self): diff --git a/jdav_web/members/locale/de/LC_MESSAGES/django.po b/jdav_web/members/locale/de/LC_MESSAGES/django.po index 200a4bc..08b248d 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: 2024-11-30 03:54+0100\n" +"POT-Creation-Date: 2024-11-30 04:20+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -942,8 +942,8 @@ msgid "Demote" msgstr "Zurück auf die Warteliste setzen" #: members/templates/admin/demote_to_waiter.html:46 -#: members/templates/admin/freizeit_finance_overview.html:153 -#: members/templates/admin/generate_seminar_report.html:54 +#: members/templates/admin/freizeit_finance_overview.html:154 +#: members/templates/admin/generate_seminar_report.html:58 #: members/templates/admin/invite_as_user.html:37 #: members/templates/admin/invite_for_group.html:52 #: members/templates/admin/invite_selected_as_user.html:49 @@ -963,7 +963,7 @@ msgstr "" "kein garantierter Kostenplan.\n" #: members/templates/admin/freizeit_finance_overview.html:34 -#: members/templates/admin/freizeit_finance_overview.html:99 +#: members/templates/admin/freizeit_finance_overview.html:100 msgid "Expenses" msgstr "Ausgaben" @@ -972,22 +972,28 @@ msgid "You listed the following expenses:" msgstr "Du hast die folgenden Ausgaben angegeben:" #: members/templates/admin/freizeit_finance_overview.html:39 +#, fuzzy +#| msgid "Evaluation" +msgid "Explanation" +msgstr "Wertung" + +#: members/templates/admin/freizeit_finance_overview.html:40 msgid "Amount" msgstr "Betrag" -#: members/templates/admin/freizeit_finance_overview.html:57 +#: members/templates/admin/freizeit_finance_overview.html:58 #, python-format msgid "The total expected expenses are %(total_bills_theoretic)s €." msgstr "" "Insgesamt belaufen sich die geschätzten Ausgaben auf " "%(total_bills_theoretic)s €." -#: members/templates/admin/freizeit_finance_overview.html:59 -#: members/templates/admin/freizeit_finance_overview.html:107 +#: members/templates/admin/freizeit_finance_overview.html:60 +#: members/templates/admin/freizeit_finance_overview.html:108 msgid "Contributions by the association" msgstr "Sektionszuschüsse" -#: members/templates/admin/freizeit_finance_overview.html:62 +#: members/templates/admin/freizeit_finance_overview.html:63 #, python-format msgid "" "According to the contribution guidelines,\n" @@ -996,7 +1002,7 @@ msgstr "" "Gemäß den Zuschussrichtlinien erhalten %(staff_count)s Jugendleiter:innen " "Zuschüsse. Jeweils sind das" -#: members/templates/admin/freizeit_finance_overview.html:68 +#: members/templates/admin/freizeit_finance_overview.html:69 #, python-format msgid "" "%(nights)s nights for %(price_per_night)s€ per night making a total of " @@ -1005,7 +1011,7 @@ msgstr "" "%(nights)s Nächte zum Preis von %(price_per_night)s€ pro Nacht. Das ergibt " "eine Gesamtsumme von %(nights_per_yl)s€." -#: members/templates/admin/freizeit_finance_overview.html:71 +#: members/templates/admin/freizeit_finance_overview.html:72 #, python-format msgid "" "%(duration)s days for %(allowance_per_day)s€ per day making a total of " @@ -1014,7 +1020,7 @@ msgstr "" "%(duration)s Tage für %(allowance_per_day)s€ pro Tag. Das ergibt eine " "Gesamtsumme von %(allowance_per_yl)s€." -#: members/templates/admin/freizeit_finance_overview.html:74 +#: members/templates/admin/freizeit_finance_overview.html:75 #, python-format msgid "" "%(kilometers_traveled)s km by %(means_of_transport)s (%(euro_per_km)s € / " @@ -1023,7 +1029,7 @@ msgstr "" "%(kilometers_traveled)s km mit %(means_of_transport)s (%(euro_per_km)s€ / " "km). Das ergibt eine Gesamtsumme von %(transportation_per_yl)s€." -#: members/templates/admin/freizeit_finance_overview.html:79 +#: members/templates/admin/freizeit_finance_overview.html:80 #, python-format msgid "" "In total these are contributions of %(total_per_yl)s€ times %(staff_count)s, " @@ -1032,11 +1038,11 @@ msgstr "" "Insgesamt sind das Kosten von %(total_per_yl)s€ mal %(staff_count)s, " "insgesamt also %(total_staff)s€." -#: members/templates/admin/freizeit_finance_overview.html:82 +#: members/templates/admin/freizeit_finance_overview.html:83 msgid "LJP contributions" msgstr "LJP Zuschüsse" -#: members/templates/admin/freizeit_finance_overview.html:85 +#: members/templates/admin/freizeit_finance_overview.html:86 #, python-format msgid "" "By submitting a seminar report, you may apply for LJP contributions. In this " @@ -1051,23 +1057,23 @@ msgstr "" "Gesamtausgaben erhalten. Das resultiert in einem Gesamtzuschuss von " "%(ljp_contributions)s€." -#: members/templates/admin/freizeit_finance_overview.html:90 +#: members/templates/admin/freizeit_finance_overview.html:91 msgid "Summary" msgstr "Zusammenfassung" -#: members/templates/admin/freizeit_finance_overview.html:93 +#: members/templates/admin/freizeit_finance_overview.html:94 msgid "This is the estimated cost and contribution summary:" msgstr "Das ist die geschätzte Kosten- und Zuschussübersicht." -#: members/templates/admin/freizeit_finance_overview.html:115 +#: members/templates/admin/freizeit_finance_overview.html:116 msgid "Potential LJP contributions" msgstr "Mögliche LJP Zuschüsse" -#: members/templates/admin/freizeit_finance_overview.html:123 +#: members/templates/admin/freizeit_finance_overview.html:124 msgid "Remaining costs" msgstr "Verbleibende Kosten" -#: members/templates/admin/freizeit_finance_overview.html:132 +#: members/templates/admin/freizeit_finance_overview.html:133 msgid "" "Positive remaining costs indicate that the estimated costs exceed the " "estimated contributions, while negative\n" @@ -1078,7 +1084,7 @@ msgstr "" "geschätzten Zuschüsse übersteigen, während negative Kosten\n" " bedeuten, dass die geschätzten Zuschüsse die geschätzten Kosten übersteigen." -#: members/templates/admin/freizeit_finance_overview.html:136 +#: members/templates/admin/freizeit_finance_overview.html:137 msgid "" "Note that this cost calculation expects you to apply for LJP contributions. " "On the\n" @@ -1088,11 +1094,11 @@ msgstr "" "beantragst. Auf der Hauptseite dieser Ausfahrt kannst du dir eine Vorlage " "und alle Formblätter für einen solchen Antrag erstellen lassen." -#: members/templates/admin/freizeit_finance_overview.html:141 +#: members/templates/admin/freizeit_finance_overview.html:142 msgid "Submit statement" msgstr "Abrechnung einreichen" -#: members/templates/admin/freizeit_finance_overview.html:143 +#: members/templates/admin/freizeit_finance_overview.html:144 msgid "" "Did you already complete this excursion? If yes, please check if all listed " "expenses are correct\n" @@ -1105,15 +1111,15 @@ msgstr "" "Finanzreferat ein. Wenn du fortschreitest sind keine weiteren Änderungen an " "der Abrechnung mehr möglich." -#: members/templates/admin/freizeit_finance_overview.html:152 +#: members/templates/admin/freizeit_finance_overview.html:153 msgid "Submit" msgstr "Einreichen" -#: members/templates/admin/freizeit_finance_overview.html:157 +#: members/templates/admin/freizeit_finance_overview.html:158 msgid "Statement submitted" msgstr "Abrechnung eingereicht" -#: members/templates/admin/freizeit_finance_overview.html:159 +#: members/templates/admin/freizeit_finance_overview.html:160 msgid "" "The statement for this excursion was already submitted. The finance " "department is currently processing your\n" @@ -1123,7 +1129,7 @@ msgstr "" "Finanzreferat bearbeitet deine Abrechnung zur Zeit und kommt " "schnellstmöglich auf dich zurück." -#: members/templates/admin/freizeit_finance_overview.html:162 +#: members/templates/admin/freizeit_finance_overview.html:163 msgid "Back" msgstr "Zurück" @@ -1135,7 +1141,16 @@ msgstr "" "Hier kannst du einen Seminarbericht für den Landesjugendplan erstellen. Ein " "Bericht enthält immer einen Kopf mit den Stammdaten des Seminars." -#: members/templates/admin/generate_seminar_report.html:32 +#: members/templates/admin/generate_seminar_report.html:31 +msgid "" +"Expenses with same short description are automatically summed up and shown " +"as one expense in the\n" +"expense overview." +msgstr "" +"Ausgaben mit der gleichen Kurzbeschreibung werden automatisch aufsummiert " +"und zu einer Ausgabe zusammengefasst." + +#: members/templates/admin/generate_seminar_report.html:36 msgid "" "Full report: Include learning goals and a detailed, tabularized time " "schedule. This requires\n" @@ -1145,7 +1160,7 @@ msgstr "" "Zeitplan dar. Dies benötigt, dass der Seminarbericht in der Ausfahrt " "ausgefüllt ist." -#: members/templates/admin/generate_seminar_report.html:36 +#: members/templates/admin/generate_seminar_report.html:40 msgid "" "Costs and participants only: Only show a list of participants and costs. In " "this case you\n" @@ -1155,11 +1170,11 @@ msgstr "" "Kosten an. In diesem Fall musst du Lernziele und einen Zeitplan manuell " "hinzufügen." -#: members/templates/admin/generate_seminar_report.html:42 +#: members/templates/admin/generate_seminar_report.html:46 msgid "Please choose one of the listed modes." msgstr "Bitte wähle einen der obigen Modi." -#: members/templates/admin/generate_seminar_report.html:53 +#: members/templates/admin/generate_seminar_report.html:57 msgid "Generate" msgstr "Erstellen" diff --git a/jdav_web/members/templates/admin/freizeit_finance_overview.html b/jdav_web/members/templates/admin/freizeit_finance_overview.html index 9026873..ffba21f 100644 --- a/jdav_web/members/templates/admin/freizeit_finance_overview.html +++ b/jdav_web/members/templates/admin/freizeit_finance_overview.html @@ -36,6 +36,7 @@ cost plan!

    {% for bill in memberlist.statement.bill_set.all %} @@ -47,7 +48,7 @@ cost plan! {{bill.explanation}} {% endfor %} diff --git a/jdav_web/members/templates/admin/generate_seminar_report.html b/jdav_web/members/templates/admin/generate_seminar_report.html index 8b4cfa0..6a3e8e8 100644 --- a/jdav_web/members/templates/admin/generate_seminar_report.html +++ b/jdav_web/members/templates/admin/generate_seminar_report.html @@ -27,6 +27,10 @@ {% blocktrans %}Here you can generate a seminar report suitable for the LJP. A report always contains a head page with the basic information on the seminar.{% endblocktrans %}

    +

    +{% blocktrans %}Expenses with same short description are automatically summed up and shown as one expense in the +expense overview.{% endblocktrans %} +

    • {% blocktrans %}Full report: Include learning goals and a detailed, tabularized time schedule. This requires diff --git a/jdav_web/members/templates/members/seminar_report.tex b/jdav_web/members/templates/members/seminar_report.tex index ea0160b..30ff1f6 100644 --- a/jdav_web/members/templates/members/seminar_report.tex +++ b/jdav_web/members/templates/members/seminar_report.tex @@ -148,7 +148,7 @@ Aufwandsentschädigung & {{ memberlist.statement.total_allowance }} € \\ Fahrtkosten & {{ memberlist.statement.total_transportation }} € \\ Übernachtungskosten & {{ memberlist.statement.total_nights }} € \\ - {% for bill in memberlist.statement.bill_set.all %} + {% for bill in memberlist.statement.grouped_bills %} {{ bill.short_description|esc_all }} & {{ bill.amount }} € \\ {% endfor %} \bottomrule From 7d93a4be0abd99c824b7e8029f4b83b2438b01fa Mon Sep 17 00:00:00 2001 From: Christian Merten Date: Sat, 30 Nov 2024 16:08:55 +0100 Subject: [PATCH 23/56] members/excursion: add V32 and improve texts --- .../finance/locale/de/LC_MESSAGES/django.po | 78 ++++----- .../jdav_web/settings/components/texts.py | 5 + jdav_web/jdav_web/settings/local.py | 13 ++ jdav_web/locale/de/LC_MESSAGES/django.po | 10 +- jdav_web/members/admin.py | 20 ++- .../members/locale/de/LC_MESSAGES/django.po | 156 ++++++++++-------- jdav_web/members/models.py | 68 +++++++- jdav_web/members/pdf.py | 48 ++++-- .../admin/generate_seminar_report.html | 6 +- ...1_Themenorientierte_Bildungsmassnahmen.pdf | Bin 0 -> 128108 bytes .../members/crisis_intervention_list.tex | 2 +- .../members/templates/members/notes_list.tex | 2 +- .../templates/members/seminar_report.tex | 2 +- .../freizeit/change_form_object_tools.html | 4 +- 14 files changed, 271 insertions(+), 143 deletions(-) create mode 100644 jdav_web/members/templates/members/V32-1_Themenorientierte_Bildungsmassnahmen.pdf diff --git a/jdav_web/finance/locale/de/LC_MESSAGES/django.po b/jdav_web/finance/locale/de/LC_MESSAGES/django.po index 8e561f5..d0f37a9 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: 2024-11-30 03:54+0100\n" +"POT-Creation-Date: 2024-11-30 15:59+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -132,165 +132,165 @@ msgstr "Bestätigung zurücknehmen" msgid "Finance" msgstr "Finanzen" -#: finance/models.py:20 +#: finance/models.py:21 msgid "Name" msgstr "Name" -#: finance/models.py:26 finance/models.py:466 finance/models.py:490 +#: finance/models.py:27 finance/models.py:472 finance/models.py:496 #: finance/templates/admin/confirmed_statement.html:38 #: finance/templates/admin/overview_submitted_statement.html:100 msgid "Ledger" msgstr "Geldtopf" -#: finance/models.py:27 +#: finance/models.py:28 msgid "Ledgers" msgstr "Geldtöpfe" -#: finance/models.py:47 finance/models.py:409 finance/models.py:489 +#: finance/models.py:48 finance/models.py:415 finance/models.py:495 msgid "Short description" msgstr "Kurzbeschreibung" -#: finance/models.py:50 finance/models.py:410 +#: finance/models.py:51 finance/models.py:416 msgid "Explanation" msgstr "Erklärung" -#: finance/models.py:52 +#: finance/models.py:53 msgid "Associated excursion" msgstr "Zugehörige Ausfahrt" -#: finance/models.py:57 +#: finance/models.py:58 msgid "Price per night" msgstr "Preis pro Nacht" -#: finance/models.py:59 +#: finance/models.py:60 msgid "Submitted" msgstr "Eingericht" -#: finance/models.py:60 +#: finance/models.py:61 msgid "Submitted on" msgstr "Eingereicht am" -#: finance/models.py:61 +#: finance/models.py:62 msgid "Confirmed" msgstr "Abgewickelt" -#: finance/models.py:62 finance/models.py:473 +#: finance/models.py:63 finance/models.py:479 msgid "Paid on" msgstr "Bezahlt am" -#: finance/models.py:64 +#: finance/models.py:65 msgid "Created by" msgstr "Erstellt von" -#: finance/models.py:69 +#: finance/models.py:70 msgid "Submitted by" msgstr "Eingereicht bei" -#: finance/models.py:74 finance/models.py:474 +#: finance/models.py:75 finance/models.py:480 msgid "Authorized by" msgstr "Autorisiert von" -#: finance/models.py:81 finance/models.py:408 finance/models.py:469 +#: finance/models.py:82 finance/models.py:414 finance/models.py:475 msgid "Statement" msgstr "Abrechnung" -#: finance/models.py:82 +#: finance/models.py:83 msgid "Statements" msgstr "Abrechnungen" -#: finance/models.py:97 +#: finance/models.py:98 #, python-format msgid "Statement: %(excursion)s" msgstr "Abrechnung: %(excursion)s" -#: finance/models.py:149 +#: finance/models.py:150 msgid "Ready to confirm" msgstr "Bereit zur Abwicklung" -#: finance/models.py:193 +#: finance/models.py:194 #, python-format msgid "Compensation for %(excu)s" msgstr "Entschädigung für %(excu)s" -#: finance/models.py:326 +#: finance/models.py:327 #: finance/templates/admin/overview_submitted_statement.html:78 msgid "Total" msgstr "Gesamtbetrag" -#: finance/models.py:363 +#: finance/models.py:369 msgid "Statement in preparation" msgstr "Abrechnung in Vorbereitung" -#: finance/models.py:364 +#: finance/models.py:370 msgid "Statements in preparation" msgstr "Abrechnungen in Vorbereitung" -#: finance/models.py:383 +#: finance/models.py:389 msgid "Submitted statement" msgstr "Eingereichte Abrechnung" -#: finance/models.py:384 +#: finance/models.py:390 msgid "Submitted statements" msgstr "Eingereichte Abrechnungen" -#: finance/models.py:400 +#: finance/models.py:406 msgid "Paid statement" msgstr "Bezahlte Abrechnung" -#: finance/models.py:401 +#: finance/models.py:407 msgid "Paid statements" msgstr "Bezahlte Abrechnungen" -#: finance/models.py:412 finance/models.py:426 finance/models.py:463 +#: finance/models.py:418 finance/models.py:432 finance/models.py:469 #: finance/templates/admin/confirmed_statement.html:36 #: finance/templates/admin/overview_submitted_statement.html:31 #: finance/templates/admin/overview_submitted_statement.html:98 msgid "Amount" msgstr "Betrag" -#: finance/models.py:413 +#: finance/models.py:419 msgid "Paid by" msgstr "Bezahlt von" -#: finance/models.py:415 +#: finance/models.py:421 msgid "Covered" msgstr "Übernommen" -#: finance/models.py:416 +#: finance/models.py:422 msgid "Refunded" msgstr "Ausgezahlt" -#: finance/models.py:418 +#: finance/models.py:424 msgid "Proof" msgstr "Beleg" -#: finance/models.py:429 finance/models.py:436 finance/models.py:449 +#: finance/models.py:435 finance/models.py:442 finance/models.py:455 msgid "Bill" msgstr "Ausgabe" -#: finance/models.py:430 finance/models.py:437 finance/models.py:450 +#: finance/models.py:436 finance/models.py:443 finance/models.py:456 #: finance/templates/admin/overview_submitted_statement.html:26 msgid "Bills" msgstr "Ausgaben" -#: finance/models.py:462 finance/templates/admin/confirmed_statement.html:37 +#: finance/models.py:468 finance/templates/admin/confirmed_statement.html:37 #: finance/templates/admin/overview_submitted_statement.html:99 msgid "Reference" msgstr "Verwendungszweck" -#: finance/models.py:464 +#: finance/models.py:470 msgid "Recipient" msgstr "Empfänger" -#: finance/models.py:472 +#: finance/models.py:478 msgid "Paid" msgstr "Bezahlt" -#: finance/models.py:484 +#: finance/models.py:490 msgid "Transaction" msgstr "Überweisung" -#: finance/models.py:485 +#: finance/models.py:491 #: finance/templates/admin/overview_submitted_statement.html:84 msgid "Transactions" msgstr "Überweisungen" diff --git a/jdav_web/jdav_web/settings/components/texts.py b/jdav_web/jdav_web/settings/components/texts.py index 0bb3ad3..577e348 100644 --- a/jdav_web/jdav_web/settings/components/texts.py +++ b/jdav_web/jdav_web/settings/components/texts.py @@ -162,3 +162,8 @@ Bei Fragen, wende dich gerne an %(RESPONSIBLE_MAIL)s. Viele Grüße Deine JDAV %(SEKTION)s""" % { 'SEKTION': SEKTION, 'RESPONSIBLE_MAIL': RESPONSIBLE_MAIL } + + +ADDRESS = """JDAV %(SEKTION)s +%(STREET)s +%(PLACE)s""" % { 'SEKTION': SEKTION, 'STREET': SEKTION_STREET, 'PLACE': SEKTION_TOWN } diff --git a/jdav_web/jdav_web/settings/local.py b/jdav_web/jdav_web/settings/local.py index d873429..a92da5e 100644 --- a/jdav_web/jdav_web/settings/local.py +++ b/jdav_web/jdav_web/settings/local.py @@ -8,10 +8,23 @@ SEKTION_TELEFAX = "06221 437338" SEKTION_CONTACT_MAIL = "geschaeftsstelle@alpenverein-heidelberg.de" SEKTION_BOARD_MAIL = "vorstand@alpenverein-heidelberg.de" SEKTION_CRISIS_INTERVENTION_MAIL = "krisenmanagement@alpenverein-heidelberg.de" +SEKTION_IBAN = "DE22 6729 0000 0000 1019 40" +SEKTION_ACCOUNT_HOLDER = "Deutscher Alpenverein Sektion Heidelberg 1869" RESPONSIBLE_MAIL = "jugendreferat@jdav-hd.de" DIGITAL_MAIL = "digitales@jdav-hd.de" +# LJP + +V32_HEAD_ORGANISATION = """JDAV Baden-Württemberg +Rotebühlstraße 59A +70178 Stuttgart + +info@jdav-bw.de +0711 - 49 09 46 00""" + +LJP_CONTRIBUTION_PER_DAY = 25 + # echo ECHO_PASSWORD_BIRTHDATE_FORMAT = '%d.%m.%Y' diff --git a/jdav_web/locale/de/LC_MESSAGES/django.po b/jdav_web/locale/de/LC_MESSAGES/django.po index 7ed7671..bb7020a 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: 2024-11-30 03:54+0100\n" +"POT-Creation-Date: 2024-11-30 15:59+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -258,17 +258,15 @@ msgstr "SJR Antrag erstellen" #: templates/admin/members/freizeit/change_form_object_tools.html:23 msgid "Generate overview" -msgstr "Übersicht erstellen" +msgstr "Hinweise für Jugendleiter:innen erstellen" #: templates/admin/members/freizeit/change_form_object_tools.html:30 msgid "Generate seminar report" -msgstr "Seminarbericht erstellen" +msgstr "Landesjugendplan Antrag erstellen" #: templates/admin/members/freizeit/change_form_object_tools.html:38 -#, fuzzy -#| msgid "Generate overview" msgid "Finance overview" -msgstr "Übersicht erstellen" +msgstr "Kostenübersicht" #: templates/admin/members/member/change_form_object_tools.html:8 msgid "Invite as user" diff --git a/jdav_web/members/admin.py b/jdav_web/members/admin.py index 0d24940..154d1cd 100644 --- a/jdav_web/members/admin.py +++ b/jdav_web/members/admin.py @@ -23,10 +23,10 @@ from django.utils.html import format_html from django.utils.translation import gettext_lazy as _ from django.db.models import TextField, ManyToManyField, ForeignKey, Count,\ Sum, Case, Q, F, When, Value, IntegerField, Subquery, OuterRef -from django.forms import Textarea, RadioSelect, TypedChoiceField +from django.forms import Textarea, RadioSelect, TypedChoiceField, CheckboxInput from django.shortcuts import render from django.core.exceptions import PermissionDenied -from .pdf import render_tex, fill_pdf_form +from .pdf import render_tex, fill_pdf_form, merge_pdfs, serve_pdf from contrib.admin import CommonAdminInlineMixin, CommonAdminMixin @@ -825,6 +825,9 @@ class GenerateSeminarReportForm(forms.Form): modes = (('full', _('Full report')), ('basic', _('Costs and participants only'))) mode = forms.ChoiceField(choices=modes, label=_('Mode')) + prepend_v32 = forms.BooleanField(label=_('Prepend V32'), initial=True, + widget=CheckboxInput(attrs={'style': 'display: inherit'}), + required=False) class FreizeitAdmin(CommonAdminMixin, nested_admin.NestedModelAdmin): @@ -904,12 +907,21 @@ class FreizeitAdmin(CommonAdminMixin, nested_admin.NestedModelAdmin): messages.error(request, _('Please select a mode.')) return self.render_seminar_report_options(request, memberlist, form) mode = form.cleaned_data['mode'] + prepend_v32 = form.cleaned_data['prepend_v32'] if mode == 'full' and not hasattr(memberlist, 'ljpproposal'): messages.error(request, _('Full mode is only available, if the seminar report section is filled out.')) return self.render_seminar_report_options(request, memberlist, form) - context = dict(memberlist=memberlist, settings=settings, mode=mode) title = memberlist.ljpproposal.title if hasattr(memberlist, 'ljpproposal') else memberlist.name - return render_tex(title + '_Seminarbericht', 'members/seminar_report.tex', context) + context = dict(memberlist=memberlist, settings=settings, mode=mode) + fp = render_tex(title + '_Seminarbericht', 'members/seminar_report.tex', context, save_only=True) + if prepend_v32: + context = memberlist.v32_fields() + v32_fp = fill_pdf_form(title + "_LJP_V32", + 'members/V32-1_Themenorientierte_Bildungsmassnahmen.pdf', + context, + save_only=True) + return merge_pdfs(title + 'LJP_Antrag', [v32_fp, fp]) + return serve_pdf(fp) return self.render_seminar_report_options(request, memberlist, GenerateSeminarReportForm()) seminar_report.short_description = _('Generate seminar report') diff --git a/jdav_web/members/locale/de/LC_MESSAGES/django.po b/jdav_web/members/locale/de/LC_MESSAGES/django.po index 08b248d..8871d4e 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: 2024-11-30 04:20+0100\n" +"POT-Creation-Date: 2024-11-30 15:59+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -109,7 +109,7 @@ msgstr "" msgid "activity" msgstr "Aktivität" -#: members/admin.py:374 members/models.py:54 members/models.py:1409 +#: members/admin.py:374 members/models.py:54 members/models.py:1475 msgid "Name" msgstr "Name" @@ -160,7 +160,7 @@ msgid "Successfully demoted %(name)s to waiter." msgstr "%(name)s zurück auf die Warteliste gesetzt." #: members/admin.py:542 members/models.py:389 members/models.py:733 -#: members/models.py:1154 +#: members/models.py:1220 msgid "Group" msgstr "Gruppe" @@ -273,7 +273,11 @@ msgstr "Nur Kosten und Teilnehmende" msgid "Mode" msgstr "Modus" -#: members/admin.py:841 +#: members/admin.py:828 +msgid "Prepend V32" +msgstr "V32 Formblatt einfügen" + +#: members/admin.py:844 msgid "" "General information on your excursion. These are partly relevant for the " "amount of financial compensation (means of transport, travel distance, etc.)." @@ -282,48 +286,48 @@ msgstr "" "teilweise relevant für die Zuschüsse aus dem Jugendetat (Verkehrsmittel, " "Fahrstrecke in km)." -#: members/admin.py:871 +#: members/admin.py:874 #, python-format msgid "You are not allowed to view all members on excursion %(name)s." msgstr "" "Du hast nicht die nötigen Rechte um alle Teilnehmer:innen der Ausfahrt " "%(name)s anzusehen." -#: members/admin.py:879 +#: members/admin.py:882 msgid "Generate crisis intervention list" msgstr "Kriseninterventionsliste erstellen" -#: members/admin.py:887 +#: members/admin.py:890 msgid "Generate overview" msgstr "Hinweise für Jugendleiter erstellen" -#: members/admin.py:891 members/admin.py:914 +#: members/admin.py:894 members/admin.py:926 #: members/templates/admin/generate_seminar_report.html:21 msgid "Generate seminar report" -msgstr "Seminarbericht erstellen" +msgstr "Landesjugendplan Antrag erstellen" -#: members/admin.py:904 +#: members/admin.py:907 msgid "Please select a mode." msgstr "Bitte wähle einen Modus aus." -#: members/admin.py:908 +#: members/admin.py:912 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:926 +#: members/admin.py:938 msgid "Generate SJR application" msgstr "SJR Antrag erstellen" -#: members/admin.py:930 +#: members/admin.py:942 msgid "No statement found. Please add a statement and then retry." msgstr "" "Keine Abrechnung angelegt. Bitte lege eine Abrechnung and und versuche es " "erneut." -#: members/admin.py:934 +#: members/admin.py:946 msgid "" "Successfully submited statement. The finance department will notify you as " "soon as possible." @@ -331,7 +335,7 @@ msgstr "" "Abrechnung erfolgreich eingericht. Die Finanzabteilung wird sich bei dir so " "schnell wie möglich melden." -#: members/admin.py:937 +#: members/admin.py:949 #: members/templates/admin/freizeit_finance_overview.html:21 msgid "Finance overview" msgstr "Kostenübersicht" @@ -409,7 +413,7 @@ msgstr "Jugendleiter" msgid "week day" msgstr "Wochentag" -#: members/models.py:78 members/models.py:1236 +#: members/models.py:78 members/models.py:1302 msgid "Starting time" msgstr "Zeitpunkt" @@ -599,7 +603,7 @@ msgid "Set login data for Kompass" msgstr "Zugangsdaten für Kompass wählen" #: members/models.py:689 members/models.py:885 members/models.py:896 -#: members/models.py:1185 members/models.py:1192 +#: members/models.py:1251 members/models.py:1258 msgid "Member" msgstr "Teilnehmer" @@ -700,7 +704,7 @@ msgstr "Von der Warteliste abgemeldet" msgid "Comment" msgstr "Kommentar" -#: members/models.py:897 members/models.py:1193 +#: members/models.py:897 members/models.py:1259 msgid "Members" msgstr "Teilnehmer" @@ -748,7 +752,7 @@ msgstr "mittel" msgid "hard" msgstr "schwer" -#: members/models.py:966 members/models.py:1216 +#: members/models.py:966 members/models.py:1282 #: members/templates/admin/freizeit_finance_overview.html:26 msgid "Excursion" msgstr "Ausfahrt" @@ -757,163 +761,163 @@ msgstr "Ausfahrt" msgid "Excursions" msgstr "Ausfahrten" -#: members/models.py:1131 members/models.py:1207 members/models.py:1423 +#: members/models.py:1197 members/models.py:1273 members/models.py:1489 msgid "Title" msgstr "Titel" -#: members/models.py:1132 members/models.py:1150 members/models.py:1424 +#: members/models.py:1198 members/models.py:1216 members/models.py:1490 msgid "Date" msgstr "Datum" -#: members/models.py:1151 +#: members/models.py:1217 msgid "Location" msgstr "Ort" -#: members/models.py:1152 +#: members/models.py:1218 msgid "Topic" msgstr "Thema" -#: members/models.py:1176 +#: members/models.py:1242 msgid "Jugendleiter" msgstr "Jugendleiter" -#: members/models.py:1179 +#: members/models.py:1245 msgid "Klettertreff" msgstr "Klettertreff" -#: members/models.py:1180 +#: members/models.py:1246 msgid "Klettertreffs" msgstr "Klettertreffs" -#: members/models.py:1198 +#: members/models.py:1264 msgid "Password" msgstr "Passwort" -#: members/models.py:1201 +#: members/models.py:1267 msgid "registration password" msgstr "Registrierungspassort" -#: members/models.py:1202 +#: members/models.py:1268 msgid "registration passwords" msgstr "Registrierungspasswörter" -#: members/models.py:1209 +#: members/models.py:1275 msgid "Alpinistic goals" msgstr "Alpintechnische Ziele" -#: members/models.py:1210 +#: members/models.py:1276 msgid "Pedagogic goals" msgstr "Pädagogische Ziele" -#: members/models.py:1211 +#: members/models.py:1277 msgid "Content and methods" msgstr "Inhalte und Methoden" -#: members/models.py:1212 +#: members/models.py:1278 msgid "Evaluation" msgstr "Wertung" -#: members/models.py:1213 +#: members/models.py:1279 msgid "Experiences and possible improvements" msgstr "Erfahrungen und Verbesserungsvorschläge" -#: members/models.py:1222 members/models.py:1243 +#: members/models.py:1288 members/models.py:1309 msgid "LJP Proposal" msgstr "Seminarbericht" -#: members/models.py:1223 +#: members/models.py:1289 msgid "LJP Proposals" msgstr "Seminarberichte" -#: members/models.py:1237 +#: members/models.py:1303 msgid "Duration in hours" msgstr "Dauer in Stunden" -#: members/models.py:1240 +#: members/models.py:1306 msgid "Activity and method" msgstr "Art der Aktion inkl. Methode" -#: members/models.py:1248 +#: members/models.py:1314 msgid "Intervention" msgstr "Aktion" -#: members/models.py:1249 +#: members/models.py:1315 msgid "Interventions" msgstr "Aktionen" -#: members/models.py:1351 members/models.py:1381 +#: members/models.py:1417 members/models.py:1447 msgid "May list members" msgstr "Darf folgende Teilnehmer:innen listen" -#: members/models.py:1353 members/models.py:1383 +#: members/models.py:1419 members/models.py:1449 msgid "May view members" msgstr "Darf folgende Teilnehmer:innen anzeigen" -#: members/models.py:1355 members/models.py:1385 +#: members/models.py:1421 members/models.py:1451 msgid "May change members" msgstr "Darf folgende Teilnehmer:innen ändern" -#: members/models.py:1357 members/models.py:1387 +#: members/models.py:1423 members/models.py:1453 msgid "May delete members" msgstr "Darf folgende Teilnehmer:innen löschen" -#: members/models.py:1361 members/models.py:1391 +#: members/models.py:1427 members/models.py:1457 msgid "May list members of groups" msgstr "Darf Teilnehmer:innen folgender Gruppen listen" -#: members/models.py:1363 members/models.py:1393 +#: members/models.py:1429 members/models.py:1459 msgid "May view members of groups" msgstr "Darf Teilnehmer:innen folgender Gruppen anzeigen" -#: members/models.py:1365 members/models.py:1395 +#: members/models.py:1431 members/models.py:1461 msgid "May change members of groups" msgstr "Darf Teilnehmer:innen folgender Gruppen ändern" -#: members/models.py:1367 members/models.py:1397 +#: members/models.py:1433 members/models.py:1463 msgid "May delete members of groups" msgstr "Darf Teilnehmer:innen folgender Gruppen löschen" -#: members/models.py:1370 members/models.py:1371 members/models.py:1374 +#: members/models.py:1436 members/models.py:1437 members/models.py:1440 msgid "Permissions" msgstr "Berechtigungen" -#: members/models.py:1400 members/models.py:1401 members/models.py:1404 +#: members/models.py:1466 members/models.py:1467 members/models.py:1470 msgid "Group permissions" msgstr "Gruppenberechtigungen" -#: members/models.py:1410 +#: members/models.py:1476 msgid "Permission needed" msgstr "Freigabe erforderlich" -#: members/models.py:1413 +#: members/models.py:1479 msgid "Training category" msgstr "Fortbildungstyp" -#: members/models.py:1414 +#: members/models.py:1480 msgid "Training categories" msgstr "Fortbildungstypen" -#: members/models.py:1425 +#: members/models.py:1491 msgid "Category" msgstr "Kategorien" -#: members/models.py:1426 +#: members/models.py:1492 msgid "Comments" msgstr "Kommentar" -#: members/models.py:1427 +#: members/models.py:1493 msgid "Participated" msgstr "Teilgenommmen" -#: members/models.py:1428 +#: members/models.py:1494 msgid "Passed" msgstr "Bestanden" -#: members/models.py:1431 +#: members/models.py:1497 msgid "Training" msgstr "Fortbildung" -#: members/models.py:1432 +#: members/models.py:1498 msgid "Trainings" msgstr "Fortbildungen" @@ -943,7 +947,7 @@ msgstr "Zurück auf die Warteliste setzen" #: members/templates/admin/demote_to_waiter.html:46 #: members/templates/admin/freizeit_finance_overview.html:154 -#: members/templates/admin/generate_seminar_report.html:58 +#: members/templates/admin/generate_seminar_report.html:60 #: members/templates/admin/invite_as_user.html:37 #: members/templates/admin/invite_for_group.html:52 #: members/templates/admin/invite_selected_as_user.html:49 @@ -972,10 +976,8 @@ msgid "You listed the following expenses:" msgstr "Du hast die folgenden Ausgaben angegeben:" #: members/templates/admin/freizeit_finance_overview.html:39 -#, fuzzy -#| msgid "Evaluation" msgid "Explanation" -msgstr "Wertung" +msgstr "Erklärung" #: members/templates/admin/freizeit_finance_overview.html:40 msgid "Amount" @@ -1138,8 +1140,12 @@ msgid "" "Here you can generate a seminar report suitable for the LJP. A report\n" "always contains a head page with the basic information on the seminar." msgstr "" -"Hier kannst du einen Seminarbericht für den Landesjugendplan erstellen. Ein " -"Bericht enthält immer einen Kopf mit den Stammdaten des Seminars." +"Hier kannst du einen Zuschussantrag für den Landesjugendplan (LJP) " +"erstellen. Ein solcher Antrag besteht immer aus zwei Teilen: Einem Formblatt " +"und einem Seminarbericht. Ein Bericht enthält immer einen Kopf mit den " +"Stammdaten des Seminars. Darüber hinaus muss der Seminarbericht eine " +"Teilnehemendenliste, eine Kostenübersicht und eine detaillierte didaktische " +"Planung enthalten. " #: members/templates/admin/generate_seminar_report.html:31 msgid "" @@ -1147,8 +1153,8 @@ msgid "" "as one expense in the\n" "expense overview." msgstr "" -"Ausgaben mit der gleichen Kurzbeschreibung werden automatisch aufsummiert " -"und zu einer Ausgabe zusammengefasst." +"In der Kostenübersicht werden Ausgaben mit der gleichen Kurzbeschreibung " +"automatisch aufsummiert und zu einer Ausgabe zusammengefasst." #: members/templates/admin/generate_seminar_report.html:36 msgid "" @@ -1156,7 +1162,7 @@ msgid "" "schedule. This requires\n" "the seminar report section to be filled out." msgstr "" -"Vollständiger Bericht: Stelle Lernziele und einen detaillierte, tabellierten " +"Vollständiger Bericht: Stelle Lernziele und einen detaillierten, tabellierten " "Zeitplan dar. Dies benötigt, dass der Seminarbericht in der Ausfahrt " "ausgefüllt ist." @@ -1171,10 +1177,15 @@ msgstr "" "hinzufügen." #: members/templates/admin/generate_seminar_report.html:46 -msgid "Please choose one of the listed modes." -msgstr "Bitte wähle einen der obigen Modi." +msgid "You may also choose to include the V32 attachment." +msgstr "" +"Ein LJP Antrag benötigt immer ein Formblatt (in unserem Fall V32-1 " +"Themenorientierte Bildungsmaßnahmen). Dieses kannst du automatisch " +"vorausfüllen lassen und dem Antrag hinzufügen. " +"Bitte fülle die verbleibenden Felder im Formblatt selbst aus und " +"unterschreibe das PDF." -#: members/templates/admin/generate_seminar_report.html:57 +#: members/templates/admin/generate_seminar_report.html:59 msgid "Generate" msgstr "Erstellen" @@ -1636,6 +1647,9 @@ msgstr "abgelaufen" msgid "Invalid emergency contacts" msgstr "Ungültige Notfallkontakte" +#~ msgid "Please choose one of the listed modes." +#~ msgstr "Bitte wähle einen der obigen Modi." + #~ msgid "Good conduct certificate presentation needed" #~ msgstr "Vorlage Führungszeugnis notwendig" diff --git a/jdav_web/members/models.py b/jdav_web/members/models.py index 3b6739e..54d9f51 100644 --- a/jdav_web/members/models.py +++ b/jdav_web/members/models.py @@ -1024,9 +1024,21 @@ class Freizeit(CommonModel): jls = set(self.jugendleiter.distinct()) return len(ps - jls) + @property + def ljp_participant_count(self): + ps = set(map(lambda x: x.member, self.membersonlist.distinct())) + jls = set(self.jugendleiter.distinct()) + count = len(ps.union(jls)) + return count + #return count if count >= 5 else 0 + + @property + def maximal_ljp_contributions(self): + return cvt_to_decimal(settings.LJP_CONTRIBUTION_PER_DAY * self.ljp_participant_count * self.duration) + @property def potential_ljp_contributions(self): - return cvt_to_decimal(min(25 * self.participant_count * self.duration, + return cvt_to_decimal(min(self.maximal_ljp_contributions, 0.9 * float(self.statement.total_bills_theoretic) + float(self.statement.total_staff))) @property @@ -1113,6 +1125,60 @@ class Freizeit(CommonModel): base['Status' + suffix] = str(2) return base + def v32_fields(self): + title = self.ljpproposal.title if hasattr(self, 'ljpproposal') else self.name + base = { + # AntragstellerIn + 'Textfeld 2': settings.ADDRESS, + # Dachorganisation + 'Textfeld 3': settings.V32_HEAD_ORGANISATION, + # Datum der Maßnahme am/vom + 'Textfeld 20': self.date.strftime('%d.%m.%Y'), + # bis + 'Textfeld 28': self.end.strftime('%d.%m.%Y'), + # Thema der Maßnahme + 'Textfeld 22': title, + # IBAN + 'Textfeld 36': settings.SEKTION_IBAN, + # Kontoinhaber + 'Textfeld 37': settings.SEKTION_ACCOUNT_HOLDER, + # Zahl der zuwendungsfähigen Teilnehemr + 'Textfeld 43': str(self.ljp_participant_count), + # Teilnahmetage + 'Textfeld 46': str(round(self.duration * self.ljp_participant_count, 1)).replace('.', ','), + # Euro Tagessatz + 'Textfeld 48': str(settings.LJP_CONTRIBUTION_PER_DAY), + # Erbetener Zuschuss + 'Textfeld 50': str(self.maximal_ljp_contributions).replace('.', ','), + # Stunden Bildungsprogramm + 'Textfeld 52': '??', + # Tage + 'Textfeld 53': str(round(self.duration, 1)).replace('.', ','), + # Haushaltsjahr + 'Textfeld 54': str(datetime.now().year), + # nicht anrechenbare Teilnahmetage + 'Textfeld 55': '0', + # Gesamt-Teilnahmetage + 'Textfeld 56': str(round(self.duration * self.ljp_participant_count, 1)).replace('.', ','), + # Ort, Datum + 'DatumOrt 2': 'Heidelberg, ' + datetime.now().strftime('%d.%m.%Y') + } + if self.statement: + possible_contributions = self.maximal_ljp_contributions + total_contributions = min(self.statement.total_theoretic, possible_contributions) + self_participation = max(cvt_to_decimal(0), self.statement.total_theoretic - possible_contributions) + # Gesamtkosten von + base['Textfeld 62'] = str(self.statement.total_theoretic).replace('.', ',') + # Eigenmittel und Teilnahmebeiträge + base['Textfeld 59'] = str(self_participation).replace('.', ',') + # Drittmittel + base['Textfeld 60'] = '0,00' + # Erbetener Zuschuss + base['Textfeld 61'] = str(total_contributions).replace('.', ',') + # Ergibt wieder + base['Textfeld 58'] = base['Textfeld 62'] + return base + @staticmethod def filter_queryset_by_permissions(member, queryset=None): if queryset is None: diff --git a/jdav_web/members/pdf.py b/jdav_web/members/pdf.py index 00a9978..a273b95 100644 --- a/jdav_web/members/pdf.py +++ b/jdav_web/members/pdf.py @@ -31,7 +31,17 @@ def media_dir(): return os.path.join(settings.MEDIA_MEMBERLISTS, "memberlists") -def render_tex(name, template_path, context): +def serve_pdf(filename_pdf): + # provide the user with the resulting pdf file + with open(media_path(filename_pdf), 'rb') as pdf: + response = HttpResponse(FileWrapper(pdf))#, content='application/pdf') + response['Content-Type'] = 'application/pdf' + response['Content-Disposition'] = 'attachment; filename='+filename_pdf + + return response + + +def render_tex(name, template_path, context, save_only=False): filename = name + "_" + datetime.today().strftime("%d_%m_%Y") filename = filename.replace(' ', '_').replace('&', '').replace('/', '_') # drop umlauts, accents etc. @@ -64,16 +74,12 @@ def render_tex(name, template_path, context): os.chdir(oldwd) - # provide the user with the resulting pdf file - with open(media_path(filename_pdf), 'rb') as pdf: - response = HttpResponse(FileWrapper(pdf))#, content='application/pdf') - response['Content-Type'] = 'application/pdf' - response['Content-Disposition'] = 'attachment; filename='+filename_pdf - - return response + if save_only: + return filename_pdf + return serve_pdf(filename_pdf) -def fill_pdf_form(name, template_path, fields, attachments=[]): +def fill_pdf_form(name, template_path, fields, attachments=[], save_only=False): filename = name + "_" + datetime.today().strftime("%d_%m_%Y") filename = filename.replace(' ', '_').replace('&', '').replace('/', '_') # drop umlauts, accents etc. @@ -104,10 +110,22 @@ def fill_pdf_form(name, template_path, fields, attachments=[]): with open(media_path(filename_pdf), 'wb') as output_stream: writer.write(output_stream) - # provide the user with the resulting pdf file - with open(media_path(filename_pdf), 'rb') as pdf: - response = HttpResponse(FileWrapper(pdf))#, content='application/pdf') - response['Content-Type'] = 'application/pdf' - response['Content-Disposition'] = 'attachment; filename='+filename_pdf + if save_only: + return filename_pdf + return serve_pdf(filename_pdf) - return response + +def merge_pdfs(name, filenames, save_only=False): + merger = PdfWriter() + + for pdf in filenames: + merger.append(media_path(pdf)) + + filename = name + "_" + datetime.today().strftime("%d_%m_%Y") + filename_pdf = filename + ".pdf" + merger.write(media_path(filename_pdf)) + merger.close() + + if save_only: + return filename_pdf + return serve_pdf(filename_pdf) diff --git a/jdav_web/members/templates/admin/generate_seminar_report.html b/jdav_web/members/templates/admin/generate_seminar_report.html index 6a3e8e8..6a52699 100644 --- a/jdav_web/members/templates/admin/generate_seminar_report.html +++ b/jdav_web/members/templates/admin/generate_seminar_report.html @@ -43,12 +43,14 @@ have to add learning goals and a time schedule manually.{% endblocktrans %}

    -

    {% blocktrans %}Please choose one of the listed modes.{% endblocktrans %}

    +

    {% blocktrans %}You may also choose to include the V32 attachment.{% endblocktrans %}

    {% csrf_token %}

    - {{form}} +

    + {% trans "Explanation" %} {% trans "Amount" %} - {{ bill.amount }}€. + {{ bill.amount }}€
    + {{ form }} +


    diff --git a/jdav_web/members/templates/members/V32-1_Themenorientierte_Bildungsmassnahmen.pdf b/jdav_web/members/templates/members/V32-1_Themenorientierte_Bildungsmassnahmen.pdf new file mode 100644 index 0000000000000000000000000000000000000000..46a427aa0e550561f0d3e2cd6afa0168ff8eee5e GIT binary patch literal 128108 zcmeFZbyOWq_AZPB4Hkj~clU!6+&#EE9NgU#NN{%#5Zv7@xVt;S-Ce?W^2*$I=H|_v z_1$&<_{|zv-CcdUx~uxBXV;n~>#R~f=ULmMNYoW8x41E@qH8%rlEYX?GB20446k(r^R zjXmhuyu1veW|odXdj?TUeMjK$w=hTuYjU%2in56cv9mA<2{4OrvIuetFp09TvaqqU zaxk+Bh=}rXv#<+`aIy(7vI(;?2?((AjGqxdQ;sn)Dfk7H*ZQ^K3$i%|@qdv~Rza}Sxf{l$MA%N+(EQ%m_2$`5U7?j*> zfedO2Kw}0~O(sHSLM9Lb4vzLfeJezG(-i{)BRv#7Jp(g(z0HNP4C z0I%kg=;yNm6-+1wDNYBu5!Z>J*Me}b_YDc!dxk{XYK0rm#JT1Bgi4$VIStD2Ehh7G7&=pw(J*RHR%3%1p-KSEYwYx1AgstvhJ& z;Fqa*a=2ZtJAgTNlnO}Np1u!=Ai>k|0E@GN^7we>PW@>#873QurM8N%eZc|j&&+~p zD^agj`<7OhfH&uX5K17DiMENZ(PPknOii@0=VhLH&aRNNRpNm(w@-aq|0pzX^j7D6^%F34@9m z&;@7@5+GxsJK-@2*v`&4oVq-_UxcN9T)(Vn*(&!5X=~KjT1~Cv~hwNQZY#DJ2=YN z7?~NH0gZkXBn)~u0Q3j|=${Gn|Ks@MoDq~}20cK7ib2-N$^d9@WBf-`GrY4mGcmK) zxBPXD*+36420e-sR8w|PiVjp4CeZeyc0cOK0{Wc}R4+DA9(_;>2r7~pwC4c*^5Z>z zyf3I)R180gRkGK&b}$ApRR0HgWb_^F&0M9;92`NoF={gXL5&~u_)8kp5&w3tvV`!T zSwYgy^vAENW=4*t|M>k6R{dZk=(+;X!N$q{cgBKLla0Nit-c`;RF;q;BS_H^f>;5{ zCF1HRrsxP#OrQ&5KQ8<(5Mqit z1>$e5py*`a_(Qq==$QUjk1QTE;ex~_XN#o52qxsGXTnDh$wQ*(XAed1<&vS~&ZL^@ zOQeP>zK;cw6B>F&OBWi39_`S;-_f8&p6ecOyv=Wn6k707$xz=M9F39Rz{D2H0m^RCWly>tV!S%?>w?eBQJ%N z?*#-{pX2mft$QS#SVZW_9Mb7V(H0G5>#s{&_=%J(N}*&_2Su^a9~p(n%VPJ?6SFn4 zV$5*B6WcCQIdT^aT%$gUWVW{pz9$%e>vvz4(k7R?GBO!6)bLs0@uiIw-;OE|{0CQz zvf=x>+6g+a(6Sd_&$l&G1|Pr}&sy^(u|A-=`zB z@t-u0_Bt-5oa@;Q0Fo*OJ|yjvmz5T>?N?}|Ntbqg;=^0l#k;+5b2XtFjCIe!i0JFg zlP*#Ib~Hmh1?^OWp=j}}`1(C??i~x?Y<<098F<+oOga5I*m>Pcu&oI&g=)lApOs6x zxM&!_DeLODmB*z~xceK$Z@iOPDkaGwF-BW@_F1jg-lLc55D*y<)o3%`P~V`&z7# z*T2?*L2l1F<-KL}gy2Qi{YddG;FJ~u1-nBG_Z1PbD5*G?LSQVBdp7!>D0Gy(5uZH* zXNZ;nd6Zb+%h*7Bc?9$?-%L@HLk7mNtI>}{0>-s>^)Ff6q0$6R#%5nYx5uxEz>h2HN`DhB3;xN|K`934=3zN))CgR6$7zYUwKJg6!JplIm*eQb!Fk z5;-RpiJXuCMEgvMEC?=$-G@3RvBH*YBE+;iA|Y5EMr@aCjV%PXy1DuYu{@BHFnsx@XH+F#8mZG zHPOO}Y5HWYDZ?&qBZamg!xx;rgI$7&h{?7ueEN)UtV2yji8{Zk_0A1*bl)bQErnWa z8zwei6g!Y3R3qB-9ZuVl_4dc`$8T;BT$05$;anATpvnSn zG*@2O^rRZ%n|?M~(c?Av9&|@a@U7`A=aJf*;F<85>p90SO(fKB!XT{MJ7f@Jl-7zi zi!LsHIUa_#OueaqKdQN2^!0m*3Ner@U)q+t?*)S!@}RkIS&2?UGu%q%ipGij365YRqo^9i5>4v)w}?Fa7;Xs8+OWUEio=?|