From 42b6f7590b4c97aaa8634363d94119e65673c939 Mon Sep 17 00:00:00 2001 From: mariusrklein <47218379+mariusrklein@users.noreply.github.com> Date: Thu, 27 Mar 2025 23:10:39 +0100 Subject: [PATCH] feat(finance/excursion): implement org. fee for people over 27 --- .../finance/locale/de/LC_MESSAGES/django.po | 36 +++++++++++++-- jdav_web/finance/models.py | 45 +++++++++++++++++-- .../admin/overview_submitted_statement.html | 17 ++++++- .../members/locale/de/LC_MESSAGES/django.po | 27 +++++++++-- jdav_web/members/models.py | 13 +++++- .../admin/freizeit_finance_overview.html | 18 +++++++- 6 files changed, 139 insertions(+), 17 deletions(-) diff --git a/jdav_web/finance/locale/de/LC_MESSAGES/django.po b/jdav_web/finance/locale/de/LC_MESSAGES/django.po index 5cadb5a..4df0ed4 100644 --- a/jdav_web/finance/locale/de/LC_MESSAGES/django.po +++ b/jdav_web/finance/locale/de/LC_MESSAGES/django.po @@ -302,6 +302,16 @@ msgstr "Übernachtungs- und Fahrtkosten für %(excu)s" msgid "LJP-Contribution %(excu)s" msgstr "LJP-Zuschuss %(excu)s" +#: finance/models.py +#: finance/models.py +msgid "reduced by org fee" +msgstr "reduziert um Org-Beitrag" + +#: finance/models.py +#, python-format +msgid "Night and travel costs for %(excu)s, reduced by org fee" +msgstr "Übernachtungs- und Fahrtkosten für %(excu)s, reduziert um Org-Beitrag" + #: finance/models.py msgid "Total" msgstr "Gesamtbetrag" @@ -528,11 +538,12 @@ msgstr "" #: finance/templates/admin/overview_submitted_statement.html #, python-format msgid "" -"The subsidies for night and transportation costs of %(total_subsidies)s€ " -"should be paid to:" +"The subsidies for night and transportation costs of " +"%(total_subsidies_theoretical)s€ should be paid to:" msgstr "" -"Die Zuschüsse für Übernachtungs- und Fahrtkosten von %(total_subsidies)s€ " -"für alle Jugendleiter*innen sollen ausgezahlt werden an:" +"Die Zuschüsse für Übernachtungs- und Fahrtkosten von " +"%(total_subsidies_theoretical)s€ für alle Jugendleiter*innen sollen " +"ausgezahlt werden an:" #: finance/templates/admin/overview_submitted_statement.html msgid "" @@ -541,6 +552,23 @@ msgstr "" "Keine Empfänger*innen für Sektionszuschüsse angegeben. Es werden daher keine " "Sektionszuschüsse ausbezahlt." +#: finance/templates/admin/overview_submitted_statement.html +#, python-format +msgid "" +"Since overaged people where part of the excursion, an organisational fee of " +"10,00€ per person per day has to be paid. This totals to " +"%(total_org_fee_theoretical)s€. This organisational fee will be accounted " +"against allowances and subsidies." +msgstr "" +"Da Personen über 27 an der Ausfahrt teilnehommen haben, wird ein " +"Organisationsbeitrag von 10,00€ pro Person und Tag fällig. Der Gesamtbetrag " +"von %(total_org_fee_theoretical)s€ wird mit Zuschüssen und " +"Aufwandsentschädigungen verrechnet." + +#: finance/templates/admin/overview_submitted_statement.html +msgid "Organisation fees" +msgstr "Org-Beitrag" + #: finance/templates/admin/overview_submitted_statement.html #, python-format msgid "" diff --git a/jdav_web/finance/models.py b/jdav_web/finance/models.py index 5765aef..11477d4 100644 --- a/jdav_web/finance/models.py +++ b/jdav_web/finance/models.py @@ -135,6 +135,10 @@ class Statement(CommonModel): needed_paiments.extend([(yl, self.allowance_per_yl) for yl in self.allowance_to.all()]) if self.subsidy_to: needed_paiments.append((self.subsidy_to, self.total_subsidies)) + # only include org fee if either allowance or subsidy is claimed (part of the property) + elif self.total_org_fee: + needed_paiments.append((self.allowance_to.all()[0], self.total_subsidies)) + if self.ljp_to: needed_paiments.append((self.ljp_to, self.paid_ljp_contributions)) @@ -247,13 +251,23 @@ class Statement(CommonModel): Transaction(statement=self, member=yl, amount=self.allowance_per_yl, confirmed=False, reference=ref).save() # subsidies (i.e. night and transportation costs) - if self.subsidy_to: - ref = _("Night and travel costs for %(excu)s") % {'excu': self.excursion.name} - Transaction(statement=self, member=self.subsidy_to, amount=self.total_subsidies, confirmed=False, reference=ref).save() + if self.subsidy_to or self.total_org_fee: + if self.total_org_fee == 0: + ref = _("Night and travel costs for %(excu)s") % {'excu': self.excursion.name} + elif not self.subsidy_to: + ref = _("reduced by org fee") + else: + ref = _("Night and travel costs for %(excu)s, reduced by org fee") % {'excu': self.excursion.name} + + # if no subsidy receiver is given but org fees have to be paid. Just pick on of allowance receivers + member = self.subsidy_to if self.subsidy_to else self.allowance_to.all()[0] + + Transaction(statement=self, member=member, amount=self.total_subsidies, confirmed=False, reference=ref).save() if self.ljp_to: ref = _("LJP-Contribution %(excu)s") % {'excu': self.excursion.name} Transaction(statement=self, member=self.ljp_to, amount=self.paid_ljp_contributions, confirmed=False, reference=ref).save() + return True @@ -369,7 +383,21 @@ class Statement(CommonModel): return cvt_to_decimal(self.total_staff / self.excursion.staff_count) @property - def total_subsidies(self): + def total_org_fee_theoretical(self): + """participants older than 26.99 years need to pay a fee of 10€ per person per day.""" + if self.excursion is None: + return 0 + return cvt_to_decimal(10 * self.excursion.duration * self.excursion.old_participant_count) + + @property + def total_org_fee(self): + """only calculate org fee if subsidies or allowances are claimed.""" + if self.subsidy_to or self.allowances_paid > 0: + return self.total_org_fee_theoretical + return cvt_to_decimal(0) + + @property + def total_subsidies_theoretical(self): """ The total amount of subsidies excluding the allowance, i.e. the transportation and night costs per youth leader multiplied with the real number of youth leaders. @@ -378,6 +406,10 @@ class Statement(CommonModel): return (self.transportation_per_yl + self.nights_per_yl) * self.real_staff_count else: return cvt_to_decimal(0) + + @property + def total_subsidies(self): + return self.total_subsidies_theoretical - self.total_org_fee @property def theoretical_total_staff(self): @@ -460,6 +492,7 @@ class Statement(CommonModel): 'allowances_paid': self.allowances_paid, 'nights_per_yl': self.nights_per_yl, 'allowance_per_yl': self.allowance_per_yl, + 'total_allowance': self.total_allowance, 'transportation_per_yl': self.transportation_per_yl, 'total_per_yl': self.total_per_yl, 'total_staff': self.total_staff, @@ -475,6 +508,10 @@ class Statement(CommonModel): 'participant_count': self.excursion.participant_count, 'total_seminar_days': self.excursion.total_seminar_days, 'ljp_tax': settings.LJP_TAX * 100, + 'total_subsidies_theoretical': self.total_subsidies_theoretical, + 'total_org_fee_theoretical': self.total_org_fee_theoretical, + 'total_org_fee': self.total_org_fee, + 'old_participant_count': self.excursion.old_participant_count, } return dict(context, **excursion_context) else: diff --git a/jdav_web/finance/templates/admin/overview_submitted_statement.html b/jdav_web/finance/templates/admin/overview_submitted_statement.html index 0d97736..cdd4d09 100644 --- a/jdav_web/finance/templates/admin/overview_submitted_statement.html +++ b/jdav_web/finance/templates/admin/overview_submitted_statement.html @@ -98,7 +98,7 @@ {% endif %} {% if statement.subsidy_to %}

-{% blocktrans %}The subsidies for night and transportation costs of {{ total_subsidies }}€ should be paid to:{% endblocktrans %} +{% blocktrans %}The subsidies for night and transportation costs of {{ total_subsidies_theoretical }}€ should be paid to:{% endblocktrans %} @@ -109,10 +109,17 @@
{% trans "IBAN valid" %}

+ {% else %}

{% blocktrans %}No receivers of the subsidies were provided. Subsidies will not be used.{% endblocktrans %}

{% endif %} +{% if total_org_fee %} +{% blocktrans %}Since overaged people where part of the excursion, an organisational fee of 10,00€ per person per day has to be paid. This totals to {{ total_org_fee_theoretical }}€. This organisational fee will be accounted against allowances and subsidies.{% endblocktrans %} + +{% endif %} + + {% if statement.ljp_to %}

{% blocktrans %} The youth leaders have documented interventions worth of {{ total_seminar_days }} seminar @@ -163,6 +170,14 @@ Once their proposal was approved, the ljp contributions of should be paid to:{% {{ total_subsidies }}€ + + + {% trans "Organisation fees" %} + + + -{{ total_org_fee }}€ + + {% trans "ljp contributions" %} diff --git a/jdav_web/members/locale/de/LC_MESSAGES/django.po b/jdav_web/members/locale/de/LC_MESSAGES/django.po index 108b36f..ed43669 100644 --- a/jdav_web/members/locale/de/LC_MESSAGES/django.po +++ b/jdav_web/members/locale/de/LC_MESSAGES/django.po @@ -1366,11 +1366,12 @@ msgstr "" #: members/templates/admin/freizeit_finance_overview.html #, python-format msgid "" -"The subsidies for night and transportation costs of %(total_subsidies)s€ is " -"configured to be paid to:" +"The subsidies for night and transportation costs of " +"%(total_subsidies_theoretical)s€ is configured to be paid to:" msgstr "" -"Die Zuschüsse für Übernachtungs- und Fahrtkosten von %(total_subsidies)s€ " -"für alle Jugendleiter*innen werden ausgezahlt an:" +"Die Zuschüsse für Übernachtungs- und Fahrtkosten von " +"%(total_subsidies_theoretical)s€ für alle Jugendleiter*innen werden " +"ausgezahlt an:" #: members/templates/admin/freizeit_finance_overview.html msgid "" @@ -1379,6 +1380,20 @@ msgstr "" "Keine Empfänger*innen für Sektionszuschüsse angegeben. Es werden daher keine " "Sektionszuschüsse ausbezahlt." +#: members/templates/admin/freizeit_finance_overview.html +#, python-format +msgid "" +"Warning: %(old_participant_count)s participant(s) of the excursion are 27 or " +"older. For each of them, an organisation fee of 10,00 € per day has to be " +"paid to the account. A total of %(total_org_fee_theoretical)s € is charged " +"against the other transactions." +msgstr "" +"Achtung: %(old_participant_count)s Teilnehmende der Ausfahrt sind 27 oder " +"älter. Für diese Teilnehmende ist ein Org-Beitrag von 10,00 € pro Tag " +"fällig. Daher werden insgesamt %(total_org_fee_theoretical)s € mit den " +"Zuschüssen und Aufwandsentschädigungen verrechnet, sofern diese in Anspruch " +"genommen werden." + #: members/templates/admin/freizeit_finance_overview.html msgid "" "Warning: The configured recipients of the allowance don't match the " @@ -1442,6 +1457,10 @@ msgstr "Zusammenfassung" 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 +msgid "Organisation fees" +msgstr "Org-Beitrag" + #: members/templates/admin/freizeit_finance_overview.html msgid "Potential LJP contributions" msgstr "Mögliche LJP Zuschüsse" diff --git a/jdav_web/members/models.py b/jdav_web/members/models.py index aedcf49..7fdf422 100644 --- a/jdav_web/members/models.py +++ b/jdav_web/members/models.py @@ -1328,10 +1328,19 @@ class Freizeit(CommonModel): @property def participant_count(self): + return len(self.participants) + + @property + def participants(self): ps = set(map(lambda x: x.member, self.membersonlist.distinct())) jls = set(self.jugendleiter.distinct()) - return len(ps - jls) - + return list(ps - jls) + + @property + def old_participant_count(self): + old_ps = [m for m in self.participants if m.age() >= 27] + return len(old_ps) + @property def head_count(self): return self.staff_on_memberlist_count + self.participant_count diff --git a/jdav_web/members/templates/admin/freizeit_finance_overview.html b/jdav_web/members/templates/admin/freizeit_finance_overview.html index aecc588..43229f1 100644 --- a/jdav_web/members/templates/admin/freizeit_finance_overview.html +++ b/jdav_web/members/templates/admin/freizeit_finance_overview.html @@ -109,7 +109,7 @@ cost plan! {% endif %} {% if memberlist.statement.subsidy_to %}

-{% blocktrans %}The subsidies for night and transportation costs of {{ total_subsidies }}€ is configured to be paid to:{% endblocktrans %} +{% blocktrans %}The subsidies for night and transportation costs of {{ total_subsidies_theoretical }}€ is configured to be paid to:{% endblocktrans %} @@ -122,8 +122,14 @@ cost plan!

{% else %}

{% blocktrans %}No receivers of the subsidies were provided. Subsidies will not be used.{% endblocktrans %}

+{% endif %} +{% if total_org_fee %} +

+{% blocktrans %}Warning: {{ old_participant_count }} participant(s) of the excursion are 27 or older. For each of them, an organisation fee of 10,00 € per day has to be paid to the account. A total of {{ total_org_fee_theoretical }} € is charged against the other transactions.{% endblocktrans %} +

{% endif %} + {% if not memberlist.statement.allowance_to_valid %}

{% blocktrans %}Warning: The configured recipients of the allowance don't match the regulations. This might be because the number of recipients is bigger then the number of admissable youth leaders for this excursion.{% endblocktrans %} @@ -178,12 +184,20 @@ you may obtain up to 25€ times {{ duration }} days for {{ participant_count }} {{ total_bills_theoretic }}€

+ + + +
{% trans "IBAN valid" %}
+ {% trans "Organisation fees" %} + + {{ total_org_fee }}€ +
{% trans "Contributions by the association" %} - -{{ total_subsidies }}€ + -{{ total_subsidies_theoretical }}€