members/excursion: add finance overview

pull/73/head
Christian Merten 1 year ago
parent 5734d41a23
commit 79b5389107
Signed by: christian.merten
GPG Key ID: D953D69721B948B3

@ -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

@ -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 <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\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"

@ -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)

@ -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 <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\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"

@ -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,)))

File diff suppressed because it is too large Load Diff

@ -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')

@ -0,0 +1,166 @@
{% extends "admin/base_site.html" %}
{% load i18n admin_urls static %}
{% block extrahead %}
{{ block.super }}
{{ media }}
<script src="{% static 'admin/js/cancel.js' %}" async></script>
<script type="text/javascript" src="{% static "admin/js/vendor/jquery/jquery.js" %}"></script>
<script type="text/javascript" src="{% static "admin/js/jquery.init.js" %}"></script>
{% endblock %}
{% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} invite-waiter
{% endblock %}
{% block breadcrumbs %}
<div class="breadcrumbs">
<a href="{% url 'admin:index' %}">{% translate 'Home' %}</a>
&rsaquo; <a href="{% url 'admin:app_list' app_label=opts.app_label %}">{{ opts.app_config.verbose_name }}</a>
&rsaquo; <a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a>
&rsaquo; <a href="{% url opts|admin_urlname:'change' object.pk|admin_urlquote %}">{{ object|truncatewords:"18" }}</a>
&rsaquo; {% translate 'Finance overview' %}
</div>
{% endblock %}
{% block content %}
<h2>{% trans 'Excursion' %}: {{ memberlist.name }}</h2>
<p>
{% blocktrans %}
Here you see an estimate on the expected costs and contributions by the association. This is not a guaranteed
cost plan!
{% endblocktrans %}
</p>
<h3>{% translate "Expenses" %}</h3>
{% blocktrans %}You listed the following expenses:{% endblocktrans %}
<p>
<table>
<th>
<td>{% trans "Amount" %}</td>
</th>
{% for bill in memberlist.statement.bill_set.all %}
<tr>
<td>
{{bill.short_description}}
</td>
<td>
{{bill.explanation}}
</td>
<td>
{{ bill.amount }}€.
</td>
</tr>
{% endfor %}
</table>
</p>
<p>{% blocktrans %}The total expected expenses are {{ total_bills_theoretic }} €.{% endblocktrans %}</p>
<h3>{% trans "Contributions by the association" %}</h3>
<p>
{% blocktrans %}According to the contribution guidelines,
{{ staff_count }} youth leader(s) receive contributions. Each of them receives{% endblocktrans %}
</p>
<p>
<ul>
<li>
{% blocktrans %}{{ nights }} nights for {{ price_per_night }}€ per night making a total of {{ nights_per_yl }}€.{% endblocktrans %}
</li>
<li>
{% blocktrans %}{{ duration }} days for {{ allowance_per_day }}€ per day making a total of {{ allowance_per_yl }}€.{% endblocktrans %}
</li>
<li>
{% blocktrans %}{{ kilometers_traveled }} km by {{ means_of_transport }} ({{euro_per_km}} € / km) making a total of {{ transportation_per_yl }}€.{% endblocktrans %}
</li>
</ul>
</p>
<p>
{% blocktrans %}In total these are contributions of {{ total_per_yl }}€ times {{ staff_count }}, giving {{ total_staff }}€.{% endblocktrans %}
</p>
<h3>{% trans "LJP contributions" %}</h3>
<p>
{% 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 %}
</p>
<h3>{% trans "Summary" %}</h3>
<p>
{% blocktrans %}This is the estimated cost and contribution summary:{% endblocktrans %}
</p>
<table>
<tr>
<td>
{% trans "Expenses" %}
</td>
<td>
{{ total_bills_theoretic }}€
</td>
</tr>
<tr>
<td>
{% trans "Contributions by the association" %}
</td>
<td>
-{{ total_staff }}€
</td>
</tr>
<tr>
<td>
{% trans "Potential LJP contributions" %}
</td>
<td>
-{{ ljp_contributions }}€
</td>
</tr>
<tr>
<td>
{% trans "Remaining costs" %}
</td>
<td>
{{ total_relative_costs }}€
</td>
</tr>
</table>
<br>
<p>
{% 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 %}
</p>
<p>
{% 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 %}
</p>
{% if not memberlist.statement.submitted %}
<h3>{% trans "Submit statement" %}</h3>
<p>
{% 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 %}
</p>
<form action="" method="post">
{% csrf_token %}
<input type="hidden" name="action" value="finance_overview">
<input type="hidden" name="finance_overview">
<input class="default" style="color: $default-link-color" type="submit" name="apply" value="{% translate 'Submit' %}">
<a href="#" class="button cancel-link">{% translate "Cancel" %}</a>
</form>
{% else %}
<br>
<h3>{% trans "Statement submitted" %}</h3>
<p>
{% 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 %}
</p>
<a href="#" class="button cancel-link">{% translate "Back" %}</a>
{% endif %}
{% endblock %}

@ -31,9 +31,12 @@
</form>
</li>
{% if original.statement and not original.statement.submitted %}
{% if original.statement %}
<li>
<a class="historylink" href="{% url 'admin:finance_statementunsubmitted_submit' original.statement.pk %}">{% trans 'Submit statement' %}</a>
<form method="post" action="{% url 'admin:members_freizeit_action' original.pk %}">
{% csrf_token %}
<input type="submit" name="finance_overview" value="{% trans 'Finance overview' %}">
</form>
</li>
{% endif %}
{{block.super}}

@ -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

Loading…
Cancel
Save