From 6b839b7f60dab95aa25d42839136dc58bb19d3fb Mon Sep 17 00:00:00 2001 From: mpeltriaux Date: Wed, 20 Oct 2021 13:23:35 +0200 Subject: [PATCH] #26 Annual conservation reports * adds index form for selecting timespan and office of interest * adds timespan support for TimespanReport * fixes naive datetime issues * fixes missing error message css tag * adds/updates translations --- analysis/forms.py | 80 ++++++++++ analysis/settings.py | 6 +- .../templates/analysis/reports/detail.html | 5 +- .../templates/analysis/reports/index.html | 4 +- analysis/utils/report.py | 40 +++-- analysis/views.py | 49 ++++++- compensation/views/compensation_views.py | 4 +- compensation/views/eco_account_views.py | 4 +- ema/views.py | 4 +- intervention/views.py | 4 +- konova/utils/message_templates.py | 1 + locale/de/LC_MESSAGES/django.mo | Bin 26257 -> 26670 bytes locale/de/LC_MESSAGES/django.po | 137 ++++++++++-------- 13 files changed, 247 insertions(+), 91 deletions(-) create mode 100644 analysis/forms.py diff --git a/analysis/forms.py b/analysis/forms.py new file mode 100644 index 00000000..4aafdcbb --- /dev/null +++ b/analysis/forms.py @@ -0,0 +1,80 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: michel.peltriaux@sgdnord.rlp.de +Created on: 20.10.21 + +""" +from dal import autocomplete +from django import forms +from django.urls import reverse +from django.utils.translation import gettext_lazy as _ + +from codelist.models import KonovaCode +from codelist.settings import CODELIST_CONSERVATION_OFFICE_ID +from konova.forms import BaseForm + + +class TimespanReportForm(BaseForm): + """ TimespanReporForm is used for allowing simple creation of an e.g. annual report for conservation offices + + """ + date_from = forms.DateField( + label_suffix="", + label=_("From"), + widget=forms.DateInput( + attrs={ + "type": "date", + "data-provide": "datepicker", + "class": "form-control", + }, + format="%d.%m.%Y" + ) + ) + date_to = forms.DateField( + label_suffix="", + label=_("To"), + widget=forms.DateInput( + attrs={ + "type": "date", + "data-provide": "datepicker", + "class": "form-control", + }, + format="%d.%m.%Y" + ) + ) + conservation_office = forms.ModelChoiceField( + label=_("Conservation office"), + label_suffix="", + help_text=_("Select the responsible office"), + queryset=KonovaCode.objects.filter( + is_archived=False, + is_leaf=True, + code_lists__in=[CODELIST_CONSERVATION_OFFICE_ID], + ), + widget=autocomplete.ModelSelect2( + url="codes-conservation-office-autocomplete", + attrs={ + "data-placeholder": _("Click for selection") + } + ), + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.form_title = _("Generate report") + self.form_caption = _("Select a timespan and the desired conservation office") + self.action_url = reverse("analysis:reports") + + def save(self) -> str: + """ Generates a redirect url for the detail report + + Returns: + detail_report_url (str): The constructed detail report url + + """ + date_from = self.cleaned_data.get("date_from", None) + date_to = self.cleaned_data.get("date_to", None) + office = self.cleaned_data.get("conservation_office", None) + detail_report_url = reverse("analysis:report-detail", args=(office.id,)) + f"?df={date_from}&dt={date_to}" + return detail_report_url diff --git a/analysis/settings.py b/analysis/settings.py index 5ea5fadf..74978d13 100644 --- a/analysis/settings.py +++ b/analysis/settings.py @@ -6,7 +6,7 @@ Created on: 19.10.21 """ -import datetime - # Defines the date of the legal publishing of the LKompVzVo -LKOMPVZVO_PUBLISH_DATE = datetime.date.fromisoformat("2018-06-16") +from django.utils import timezone + +LKOMPVZVO_PUBLISH_DATE = timezone.make_aware(timezone.datetime.fromisoformat("2018-06-16")) diff --git a/analysis/templates/analysis/reports/detail.html b/analysis/templates/analysis/reports/detail.html index 4497adf3..1ba78d54 100644 --- a/analysis/templates/analysis/reports/detail.html +++ b/analysis/templates/analysis/reports/detail.html @@ -4,10 +4,11 @@ {% block body %}
-

{% trans 'Report' %}

-
{{office.long_name}}
+

{% trans 'Evaluation report' %} {{office.long_name}}

+
{% trans 'From' %} {{report.date_from.date}} {% trans 'to' %} {{report.date_to.date}}
+
{% include 'analysis/reports/includes/intervention/card_intervention.html' %} {% include 'analysis/reports/includes/compensation/card_compensation.html' %} diff --git a/analysis/templates/analysis/reports/index.html b/analysis/templates/analysis/reports/index.html index 4f7d8bd0..9c35d057 100644 --- a/analysis/templates/analysis/reports/index.html +++ b/analysis/templates/analysis/reports/index.html @@ -3,6 +3,8 @@ {% block body %}
-

{% trans 'Reports' %}

+
+ {% include 'form/table/generic_table_form.html' %} +
{% endblock %} \ No newline at end of file diff --git a/analysis/utils/report.py b/analysis/utils/report.py index 4792a166..c9c7a1bd 100644 --- a/analysis/utils/report.py +++ b/analysis/utils/report.py @@ -7,7 +7,6 @@ Created on: 18.10.21 """ from django.contrib.gis.db.models import MultiPolygonField from django.contrib.gis.db.models.functions import NumGeometries -from django.contrib.gis.measure import Area from django.db.models import Count, Sum, Q from django.db.models.functions import Cast @@ -20,14 +19,18 @@ from konova.models import Geometry class TimespanReport: + """ Holds multiple report elements for a timespan report + + """ office_id = -1 + date_from = -1 + date_to = -1 class InterventionReport: queryset = Intervention.objects.none() queryset_checked = Intervention.objects.none() queryset_recorded = Intervention.objects.none() - # Law related law_sum = -1 law_sum_checked = -1 @@ -45,11 +48,13 @@ class TimespanReport: deduction_sum_checked = -1 deduction_sum_recorded = -1 - def __init__(self, id: str): + def __init__(self, id: str, date_from: str, date_to: str): self.queryset = Intervention.objects.filter( responsible__conservation_office__id=id, legal__registration_date__gt=LKOMPVZVO_PUBLISH_DATE, deleted=None, + created__timestamp__gte=date_from, + created__timestamp__lte=date_to, ) self.queryset_checked = self.queryset.filter( checked__isnull=False @@ -160,11 +165,13 @@ class TimespanReport: # Code list id for 'obere Naturschutzbehörde' id_onb = 1943084 - def __init__(self, id: str): + def __init__(self, id: str, date_from: str, date_to: str): self.queryset = Compensation.objects.filter( intervention__responsible__conservation_office__id=id, intervention__legal__registration_date__gt=LKOMPVZVO_PUBLISH_DATE, deleted=None, + intervention__created__timestamp__gte=date_from, + intervention__created__timestamp__lte=date_to, ) self.queryset_checked = self.queryset.filter( intervention__checked__isnull=False @@ -282,11 +289,13 @@ class TimespanReport: deductions_sq_m = -1 recorded_deductions_sq_m = -1 - def __init__(self, id: str): + def __init__(self, id: str, date_from: str, date_to: str): # First fetch all eco account for this office self.queryset_total = EcoAccount.objects.filter( responsible__conservation_office__id=id, deleted=None, + created__timestamp__gte=date_from, + created__timestamp__lte=date_to, ) self.queryset_recorded = self.queryset_total.filter( recorded__isnull=False @@ -320,21 +329,23 @@ class TimespanReport: def _evaluate_deductions(self): self.deductions_sq_m = self.queryset_deductions.aggregate( sum=Sum("surface") - )["sum"] + )["sum"] or 0 self.recorded_deductions_sq_m = self.queryset_deductions_recorded.aggregate( sum=Sum("surface") - )["sum"] + )["sum"] or 0 class OldInterventionReport: queryset = Compensation.objects.none() queryset_checked = Compensation.objects.none() queryset_recorded = Compensation.objects.none() - def __init__(self, id: str): + def __init__(self, id: str, date_from: str, date_to: str): self.queryset = Intervention.objects.filter( legal__registration_date__lte=LKOMPVZVO_PUBLISH_DATE, responsible__conservation_office__id=id, deleted=None, + created__timestamp__gte=date_from, + created__timestamp__lte=date_to, ) self.queryset_checked = self.queryset.filter( checked__isnull=False @@ -343,9 +354,12 @@ class TimespanReport: recorded__isnull=False ) - def __init__(self, office_id: str): + def __init__(self, office_id: str, date_from: str, date_to: str): self.office_id = office_id - self.intervention_report = self.InterventionReport(self.office_id) - self.compensation_report = self.CompensationReport(self.office_id) - self.eco_account_report = self.EcoAccountReport(self.office_id) - self.old_intervention_report = self.OldInterventionReport(self.office_id) + self.date_from = date_from + self.date_to = date_to + + self.intervention_report = self.InterventionReport(self.office_id, date_from, date_to) + self.compensation_report = self.CompensationReport(self.office_id, date_from, date_to) + self.eco_account_report = self.EcoAccountReport(self.office_id, date_from, date_to) + self.old_intervention_report = self.OldInterventionReport(self.office_id, date_from, date_to) diff --git a/analysis/views.py b/analysis/views.py index 7e297e6a..dab3b276 100644 --- a/analysis/views.py +++ b/analysis/views.py @@ -1,11 +1,16 @@ +from django.contrib import messages from django.contrib.auth.decorators import login_required +from django.core.exceptions import ObjectDoesNotExist from django.http import HttpRequest -from django.shortcuts import render, get_object_or_404 +from django.shortcuts import render, redirect +from django.utils import timezone +from analysis.forms import TimespanReportForm from analysis.utils.report import TimespanReport from codelist.models import KonovaCode from konova.contexts import BaseContext from konova.decorators import conservation_office_group_required +from konova.utils.message_templates import FORM_INVALID, PARAMS_INVALID @login_required @@ -20,11 +25,26 @@ def index_reports_view(request: HttpRequest): """ template = "analysis/reports/index.html" - context = {} + form = TimespanReportForm(request.POST or None) + if request.method == "POST": + if form.is_valid(): + redirect_url = form.save() + return redirect(redirect_url) + else: + messages.error( + request, + FORM_INVALID, + extra_tags="danger", + ) + context = { + "form": form + } context = BaseContext(request, context).context return render(request, template, context) +@login_required +@conservation_office_group_required def detail_report_view(request: HttpRequest, id: str): """ Renders the detailed report for a conservation office @@ -35,12 +55,27 @@ def detail_report_view(request: HttpRequest, id: str): Returns: """ - cons_office = get_object_or_404( - KonovaCode, - id=id, - ) - report = TimespanReport(id) + try: + cons_office = KonovaCode.objects.get(id=id) + except (ObjectDoesNotExist, ValueError) as e: + messages.error( + request, + PARAMS_INVALID, + extra_tags="danger", + ) + return redirect("analysis:reports") + try: + date_from = timezone.make_aware(timezone.datetime.fromisoformat(request.GET.get("df", None))) + date_to = timezone.make_aware(timezone.datetime.fromisoformat(request.GET.get("dt", None))) + except ValueError: + messages.error( + request, + PARAMS_INVALID, + extra_tags="danger", + ) + return redirect("analysis:reports") + report = TimespanReport(id, date_from, date_to) template = "analysis/reports/detail.html" context = { "office": cons_office, diff --git a/compensation/views/compensation_views.py b/compensation/views/compensation_views.py index 994e9647..5b187501 100644 --- a/compensation/views/compensation_views.py +++ b/compensation/views/compensation_views.py @@ -77,7 +77,7 @@ def new_view(request: HttpRequest, intervention_id: str = None): messages.success(request, _("Compensation {} added").format(comp.identifier)) return redirect("compensation:detail", id=comp.id) else: - messages.error(request, FORM_INVALID) + messages.error(request, FORM_INVALID, extra_tags="danger",) else: # For clarification: nothing in this case pass @@ -132,7 +132,7 @@ def edit_view(request: HttpRequest, id: str): messages.success(request, _("Compensation {} edited").format(comp.identifier)) return redirect("compensation:detail", id=comp.id) else: - messages.error(request, FORM_INVALID) + messages.error(request, FORM_INVALID, extra_tags="danger",) else: # For clarification: nothing in this case pass diff --git a/compensation/views/eco_account_views.py b/compensation/views/eco_account_views.py index dadac7e6..bb04facb 100644 --- a/compensation/views/eco_account_views.py +++ b/compensation/views/eco_account_views.py @@ -86,7 +86,7 @@ def new_view(request: HttpRequest): messages.success(request, _("Eco-Account {} added").format(acc.identifier)) return redirect("compensation:acc-detail", id=acc.id) else: - messages.error(request, FORM_INVALID) + messages.error(request, FORM_INVALID, extra_tags="danger",) else: # For clarification: nothing in this case pass @@ -141,7 +141,7 @@ def edit_view(request: HttpRequest, id: str): messages.success(request, _("Eco-Account {} edited").format(acc.identifier)) return redirect("compensation:acc-detail", id=acc.id) else: - messages.error(request, FORM_INVALID) + messages.error(request, FORM_INVALID, extra_tags="danger",) else: # For clarification: nothing in this case pass diff --git a/ema/views.py b/ema/views.py index ead1a899..a9ad2bdb 100644 --- a/ema/views.py +++ b/ema/views.py @@ -78,7 +78,7 @@ def new_view(request: HttpRequest): messages.success(request, _("EMA {} added").format(ema.identifier)) return redirect("ema:detail", id=ema.id) else: - messages.error(request, FORM_INVALID) + messages.error(request, FORM_INVALID, extra_tags="danger",) else: # For clarification: nothing in this case pass @@ -202,7 +202,7 @@ def edit_view(request: HttpRequest, id: str): messages.success(request, _("EMA {} edited").format(ema.identifier)) return redirect("ema:detail", id=ema.id) else: - messages.error(request, FORM_INVALID) + messages.error(request, FORM_INVALID, extra_tags="danger",) else: # For clarification: nothing in this case pass diff --git a/intervention/views.py b/intervention/views.py index 6853197f..bd770ce2 100644 --- a/intervention/views.py +++ b/intervention/views.py @@ -79,7 +79,7 @@ def new_view(request: HttpRequest): messages.success(request, _("Intervention {} added").format(intervention.identifier)) return redirect("intervention:detail", id=intervention.id) else: - messages.error(request, FORM_INVALID) + messages.error(request, FORM_INVALID, extra_tags="danger",) else: # For clarification: nothing in this case pass @@ -264,7 +264,7 @@ def edit_view(request: HttpRequest, id: str): messages.success(request, _("Intervention {} edited").format(intervention.identifier)) return redirect("intervention:detail", id=intervention.id) else: - messages.error(request, FORM_INVALID) + messages.error(request, FORM_INVALID, extra_tags="danger",) else: # For clarification: nothing in this case pass diff --git a/konova/utils/message_templates.py b/konova/utils/message_templates.py index f9c8e2b9..e28f39de 100644 --- a/konova/utils/message_templates.py +++ b/konova/utils/message_templates.py @@ -9,6 +9,7 @@ from django.utils.translation import gettext_lazy as _ FORM_INVALID = _("There was an error on this form.") +PARAMS_INVALID = _("Invalid parameters") INTERVENTION_INVALID = _("There are errors in this intervention.") IDENTIFIER_REPLACED = _("The identifier '{}' had to be changed to '{}' since another entry has been added in the meanwhile, which uses this identifier") DATA_UNSHARED = _("This data is not shared with you") diff --git a/locale/de/LC_MESSAGES/django.mo b/locale/de/LC_MESSAGES/django.mo index 5a1733c1f00002998058c4654832abdf7a2d8932..ef92aa2c6906e36bc682fee868c04730bd59e29d 100644 GIT binary patch delta 8671 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 TuP!XUH!x^QX?fLI?=$}c00GCv delta 8288 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\n" "Language-Team: LANGUAGE \n" @@ -29,13 +29,50 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: analysis/forms.py:26 analysis/templates/analysis/reports/detail.html:8 +msgid "From" +msgstr "Vom" + +#: analysis/forms.py:38 +msgid "To" +msgstr "Bis" + +#: analysis/forms.py:49 compensation/forms/forms.py:93 +#: compensation/templates/compensation/detail/eco_account/view.html:58 +#: compensation/templates/compensation/report/eco_account/report.html:16 +#: ema/templates/ema/detail/view.html:42 +#: ema/templates/ema/report/report.html:16 intervention/forms/forms.py:101 +#: intervention/templates/intervention/detail/view.html:56 +#: intervention/templates/intervention/report/report.html:37 +msgid "Conservation office" +msgstr "Eintragungsstelle" + +#: analysis/forms.py:51 compensation/forms/forms.py:95 +msgid "Select the responsible office" +msgstr "Verantwortliche Stelle" + +#: analysis/forms.py:60 compensation/forms/forms.py:67 +#: compensation/forms/forms.py:104 compensation/forms/forms.py:155 +#: intervention/forms/forms.py:63 intervention/forms/forms.py:80 +#: intervention/forms/forms.py:96 intervention/forms/forms.py:112 +msgid "Click for selection" +msgstr "Auswählen..." + +#: analysis/forms.py:67 +msgid "Generate report" +msgstr "Bericht generieren" + +#: analysis/forms.py:68 +msgid "Select a timespan and the desired conservation office" +msgstr "Wählen Sie die Zeitspanne und die gewünschte Eintragungsstelle" + #: analysis/templates/analysis/reports/detail.html:7 -#: compensation/templates/compensation/report/compensation/report.html:7 -#: compensation/templates/compensation/report/eco_account/report.html:7 -#: ema/templates/ema/report/report.html:7 -#: intervention/templates/intervention/report/report.html:7 -msgid "Report" -msgstr "Bericht" +msgid "Evaluation report" +msgstr "Auswertungsbericht" + +#: analysis/templates/analysis/reports/detail.html:8 +msgid "to" +msgstr "bis" #: analysis/templates/analysis/reports/includes/compensation/amount.html:3 #: analysis/templates/analysis/reports/includes/eco_account/amount.html:3 @@ -232,11 +269,6 @@ msgstr "Gesetz" msgid "Old interventions" msgstr "Altfälle" -#: analysis/templates/analysis/reports/index.html:6 -#: templates/navbars/navbar.html:46 -msgid "Reports" -msgstr "Berichte" - #: compensation/filters.py:70 msgid "Show only unrecorded" msgstr "Nur unverzeichnete anzeigen" @@ -288,13 +320,6 @@ msgstr "Förderungen" msgid "Select fundings for this compensation" msgstr "Wählen Sie ggf. Fördermittelprojekte" -#: compensation/forms/forms.py:67 compensation/forms/forms.py:104 -#: compensation/forms/forms.py:155 intervention/forms/forms.py:63 -#: intervention/forms/forms.py:80 intervention/forms/forms.py:96 -#: intervention/forms/forms.py:112 -msgid "Click for selection" -msgstr "Auswählen..." - #: compensation/forms/forms.py:73 compensation/forms/modalForms.py:61 #: compensation/forms/modalForms.py:272 compensation/forms/modalForms.py:367 #: compensation/templates/compensation/detail/compensation/includes/actions.html:34 @@ -318,20 +343,6 @@ msgstr "Kommentar" msgid "Additional comment" msgstr "Zusätzlicher Kommentar" -#: compensation/forms/forms.py:93 -#: compensation/templates/compensation/detail/eco_account/view.html:58 -#: compensation/templates/compensation/report/eco_account/report.html:16 -#: ema/templates/ema/detail/view.html:42 -#: ema/templates/ema/report/report.html:16 intervention/forms/forms.py:101 -#: intervention/templates/intervention/detail/view.html:56 -#: intervention/templates/intervention/report/report.html:37 -msgid "Conservation office" -msgstr "Eintragungsstelle" - -#: compensation/forms/forms.py:95 -msgid "Select the responsible office" -msgstr "Verantwortliche Stelle" - #: compensation/forms/forms.py:109 #: compensation/templates/compensation/detail/eco_account/view.html:62 #: compensation/templates/compensation/report/eco_account/report.html:20 @@ -376,23 +387,23 @@ msgstr "Neue Kompensation" msgid "Edit compensation" msgstr "Bearbeite Kompensation" -#: compensation/forms/forms.py:299 -msgid "New Eco-Account" -msgstr "Neues Ökokonto" - -#: compensation/forms/forms.py:308 -msgid "Eco-Account XY; Location ABC" -msgstr "Ökokonto XY; Flur ABC" - -#: compensation/forms/forms.py:360 +#: compensation/forms/forms.py:290 msgid "Available Surface" msgstr "Verfügbare Fläche" -#: compensation/forms/forms.py:363 +#: compensation/forms/forms.py:293 msgid "The amount that can be used for deductions" msgstr "Die für Abbuchungen zur Verfügung stehende Menge" -#: compensation/forms/forms.py:384 +#: compensation/forms/forms.py:315 +msgid "New Eco-Account" +msgstr "Neues Ökokonto" + +#: compensation/forms/forms.py:324 +msgid "Eco-Account XY; Location ABC" +msgstr "Ökokonto XY; Flur ABC" + +#: compensation/forms/forms.py:377 msgid "Edit Eco-Account" msgstr "Ökokonto bearbeiten" @@ -953,6 +964,13 @@ msgstr "Fehlt" msgid "Action handler" msgstr "Maßnahmenträger" +#: compensation/templates/compensation/report/compensation/report.html:7 +#: compensation/templates/compensation/report/eco_account/report.html:7 +#: ema/templates/ema/report/report.html:7 +#: intervention/templates/intervention/report/report.html:7 +msgid "Report" +msgstr "Bericht" + #: compensation/templates/compensation/report/compensation/report.html:55 #: compensation/templates/compensation/report/eco_account/report.html:72 #: ema/templates/ema/report/report.html:59 @@ -1271,31 +1289,31 @@ msgstr "" "Das Ökokonto {} hat für eine Abbuchung von {} m² nicht ausreichend " "Restfläche. Es stehen noch {} m² zur Verfügung." -#: intervention/models.py:329 +#: intervention/models.py:326 msgid "Registration office file number missing" msgstr "Aktenzeichen Zulassungsbehörde fehlt" -#: intervention/models.py:332 +#: intervention/models.py:329 msgid "Conservation office file number missing" msgstr "Aktenzeichen Naturschutzbehörde fehlt" -#: intervention/models.py:335 +#: intervention/models.py:332 msgid "Responsible data missing" msgstr "Daten zu Verantwortlichen fehlen" -#: intervention/models.py:349 +#: intervention/models.py:346 msgid "Revocation exists" msgstr "Widerspruch liegt vor" -#: intervention/models.py:352 +#: intervention/models.py:349 msgid "Registration date missing" msgstr "Datum Zulassung bzw. Satzungsbeschluss fehlt" -#: intervention/models.py:355 +#: intervention/models.py:352 msgid "Binding on missing" msgstr "Datum Bestandskraft fehlt" -#: intervention/models.py:357 +#: intervention/models.py:354 msgid "Legal data missing" msgstr "Rechtliche Daten fehlen" @@ -1598,10 +1616,14 @@ msgid "There was an error on this form." msgstr "Es gab einen Fehler im Formular." #: konova/utils/message_templates.py:12 +msgid "Invalid parameters" +msgstr "Parameter ungültig" + +#: konova/utils/message_templates.py:13 msgid "There are errors in this intervention." msgstr "Es liegen Fehler in diesem Eingriff vor:" -#: konova/utils/message_templates.py:13 +#: konova/utils/message_templates.py:14 msgid "" "The identifier '{}' had to be changed to '{}' since another entry has been " "added in the meanwhile, which uses this identifier" @@ -1609,11 +1631,11 @@ msgstr "" "Die Kennung '{}' musste zu '{}' geändert werden, da ein anderer Eintrag in " "der Zwischenzeit angelegt wurde, welcher diese Kennung nun bereits verwendet" -#: konova/utils/message_templates.py:14 +#: konova/utils/message_templates.py:15 msgid "This data is not shared with you" msgstr "Diese Daten sind für Sie nicht freigegeben" -#: konova/utils/message_templates.py:15 +#: konova/utils/message_templates.py:16 msgid "You need to be part of another user group." msgstr "Hierfür müssen Sie einer anderen Nutzergruppe angehören!" @@ -1784,6 +1806,10 @@ msgstr "" msgid "Export..." msgstr "" +#: templates/navbars/navbar.html:46 +msgid "Reports" +msgstr "Berichte" + #: templates/navbars/navbar.html:58 user/templates/user/index.html:31 msgid "Settings" msgstr "Einstellungen" @@ -3214,9 +3240,6 @@ msgstr "" #~ msgid "Role changed" #~ msgstr "Rolle geändert" -#~ msgid "Invalid role" -#~ msgstr "Rolle ungültig" - #~ msgid "Official" #~ msgstr "Amtlich"