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 %}
+
+
+ |
+ | {% trans "Amount" %} |
+
+ {% for bill in memberlist.statement.bill_set.all %}
+
+ |
+ {{bill.short_description}}
+ |
+
+ {{bill.explanation}}
+ |
+
+ {{ bill.amount }}€.
+ |
+
+ {% endfor %}
+
+
+
+{% 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 %}
+
+
+
+{% 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' %}
+
{% 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