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 %}
{% 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 5a1733c1..ef92aa2c 100644
Binary files a/locale/de/LC_MESSAGES/django.mo and b/locale/de/LC_MESSAGES/django.mo differ
diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po
index 85533a66..2c6664ec 100644
--- a/locale/de/LC_MESSAGES/django.po
+++ b/locale/de/LC_MESSAGES/django.po
@@ -19,7 +19,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2021-10-19 16:04+0200\n"
+"POT-Creation-Date: 2021-10-20 13:19+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME
\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"