diff --git a/analysis/__init__.py b/analysis/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/analysis/admin.py b/analysis/admin.py new file mode 100644 index 00000000..8c38f3f3 --- /dev/null +++ b/analysis/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/analysis/apps.py b/analysis/apps.py new file mode 100644 index 00000000..126ab0e5 --- /dev/null +++ b/analysis/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class AnalysisConfig(AppConfig): + name = 'analysis' diff --git a/analysis/forms.py b/analysis/forms.py new file mode 100644 index 00000000..11d2f98b --- /dev/null +++ b/analysis/forms.py @@ -0,0 +1,82 @@ +""" +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") + self.show_cancel_btn = False + self.action_btn_label = _("Continue") + + 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/models.py b/analysis/models.py new file mode 100644 index 00000000..71a83623 --- /dev/null +++ b/analysis/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/analysis/settings.py b/analysis/settings.py new file mode 100644 index 00000000..74978d13 --- /dev/null +++ b/analysis/settings.py @@ -0,0 +1,12 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: michel.peltriaux@sgdnord.rlp.de +Created on: 19.10.21 + +""" + +# Defines the date of the legal publishing of the LKompVzVo +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 new file mode 100644 index 00000000..ac4f08e2 --- /dev/null +++ b/analysis/templates/analysis/reports/detail.html @@ -0,0 +1,36 @@ +{% extends 'base.html' %} +{% load i18n fontawesome_5 %} + +{% block body %} +
+
+

{% 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' %} + {% include 'analysis/reports/includes/eco_account/card_eco_account.html' %} + {% include 'analysis/reports/includes/old_data/card_old_interventions.html' %} +
+{% endblock %} \ No newline at end of file diff --git a/analysis/templates/analysis/reports/includes/compensation/amount.html b/analysis/templates/analysis/reports/includes/compensation/amount.html new file mode 100644 index 00000000..86383b69 --- /dev/null +++ b/analysis/templates/analysis/reports/includes/compensation/amount.html @@ -0,0 +1,55 @@ +{% load i18n fontawesome_5 ksp_filters %} + +

{% trans 'Amount' %}

+ + {% blocktrans %} + Checked = Has been checked by the registration office according to LKompVzVo + {% endblocktrans %} +
+ {% blocktrans %} + Recorded = Has been checked and published by the conservation office + {% endblocktrans %} +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{% trans 'Area of responsibility' %}{% fa5_icon 'star' %} {% trans 'Checked' %}{% fa5_icon 'bookmark' %} {% trans 'Recorded' %}{% trans 'Number single areas' %}{% trans 'Total' %}
{% trans 'Conservation office by law' %}{{report.compensation_report.queryset_registration_office_unb_checked_count|default_if_zero:"-"}}{{report.compensation_report.queryset_registration_office_unb_recorded_count|default_if_zero:"-"}}{{report.compensation_report.num_single_surfaces_total_unb|default_if_zero:"-"}}{{report.compensation_report.queryset_registration_office_unb_count|default_if_zero:"-"}}
{% trans 'Land-use planning' %}{{report.compensation_report.queryset_registration_office_tbp_checked_count|default_if_zero:"-"}}{{report.compensation_report.queryset_registration_office_tbp_recorded_count|default_if_zero:"-"}}{{report.compensation_report.num_single_surfaces_total_tbp|default_if_zero:"-"}}{{report.compensation_report.queryset_registration_office_tbp_count|default_if_zero:"-"}}
{% trans 'Other registration office' %}{{report.compensation_report.queryset_registration_office_other_checked_count|default_if_zero:"-"}}{{report.compensation_report.queryset_registration_office_other_recorded_count|default_if_zero:"-"}}{{report.compensation_report.num_single_surfaces_total_other|default_if_zero:"-"}}{{report.compensation_report.queryset_registration_office_other_count|default_if_zero:"-"}}
{% trans 'Total' %}{{report.compensation_report.queryset_checked_count|default_if_zero:"-"}}{{report.compensation_report.queryset_recorded_count|default_if_zero:"-"}}{{report.compensation_report.num_single_surfaces_total|default_if_zero:"-"}}{{report.compensation_report.queryset_count|default_if_zero:"-"}}
+
\ No newline at end of file diff --git a/analysis/templates/analysis/reports/includes/compensation/card_compensation.html b/analysis/templates/analysis/reports/includes/compensation/card_compensation.html new file mode 100644 index 00000000..8fe2eec4 --- /dev/null +++ b/analysis/templates/analysis/reports/includes/compensation/card_compensation.html @@ -0,0 +1,23 @@ +{% load i18n fontawesome_5 %} + +
+
+
+
+
+
+
+ {% fa5_icon 'leaf' %} + {% trans 'Compensations' %} +
+
+
+
+
+
+ {% include 'analysis/reports/includes/compensation/amount.html' %} +
+
+
+
+
\ No newline at end of file diff --git a/analysis/templates/analysis/reports/includes/eco_account/amount.html b/analysis/templates/analysis/reports/includes/eco_account/amount.html new file mode 100644 index 00000000..668250e6 --- /dev/null +++ b/analysis/templates/analysis/reports/includes/eco_account/amount.html @@ -0,0 +1,24 @@ +{% load i18n fontawesome_5 ksp_filters %} + +

{% trans 'Amount' %}

+ + {% blocktrans %} + Recorded = Has been checked and published by the conservation office + {% endblocktrans %} + +
+ + + + + + + + + + + + + +
{% fa5_icon 'bookmark' %} {% trans 'Recorded' %}{% trans 'Total' %}
{{report.eco_account_report.queryset_recorded_count|default_if_zero:"-"}}{{report.eco_account_report.queryset_count|default_if_zero:"-"}}
+
\ No newline at end of file diff --git a/analysis/templates/analysis/reports/includes/eco_account/card_eco_account.html b/analysis/templates/analysis/reports/includes/eco_account/card_eco_account.html new file mode 100644 index 00000000..850ac60a --- /dev/null +++ b/analysis/templates/analysis/reports/includes/eco_account/card_eco_account.html @@ -0,0 +1,25 @@ +{% load i18n fontawesome_5 %} + +
+
+
+
+
+
+
+ {% fa5_icon 'tree' %} + {% trans 'Eco-Accounts' %} +
+
+
+
+
+
+ {% include 'analysis/reports/includes/eco_account/amount.html' %} +
+ {% include 'analysis/reports/includes/eco_account/deductions.html' %} +
+
+
+
+
\ No newline at end of file diff --git a/analysis/templates/analysis/reports/includes/eco_account/deductions.html b/analysis/templates/analysis/reports/includes/eco_account/deductions.html new file mode 100644 index 00000000..c9a0e8d5 --- /dev/null +++ b/analysis/templates/analysis/reports/includes/eco_account/deductions.html @@ -0,0 +1,23 @@ +{% load i18n fontawesome_5 ksp_filters %} + +

{% trans 'Deductions' %}

+
+ + + + + + + + + + + + + + + + + +
{% fa5_icon 'bookmark' %} {% trans 'Recorded' %}{% fa5_icon 'bookmark' %} {% trans 'Recorded' %} {% trans 'Surface' %}{% trans 'Total' %}{% trans 'Total' %} {% trans 'Surface' %}
{{report.eco_account_report.queryset_deductions_recorded_count|default_if_zero:"-"}}{{report.eco_account_report.recorded_deductions_sq_m|default_if_zero:"-"}}m²{{report.eco_account_report.queryset_deductions_count|default_if_zero:"-"}}{{report.eco_account_report.deductions_sq_m|default_if_zero:"-"}}m²
+
\ No newline at end of file diff --git a/analysis/templates/analysis/reports/includes/intervention/amount.html b/analysis/templates/analysis/reports/includes/intervention/amount.html new file mode 100644 index 00000000..0c934483 --- /dev/null +++ b/analysis/templates/analysis/reports/includes/intervention/amount.html @@ -0,0 +1,30 @@ +{% load i18n fontawesome_5 ksp_filters %} + +

{% trans 'Amount' %}

+ + {% blocktrans %} + Checked = Has been checked by the registration office according to LKompVzVo + {% endblocktrans %} +
+ {% blocktrans %} + Recorded = Has been checked and published by the conservation office + {% endblocktrans %} +
+
+ + + + + + + + + + + + + + + +
{% fa5_icon 'star' %} {% trans 'Checked' %}{% fa5_icon 'bookmark' %} {% trans 'Recorded' %}{% trans 'Total' %}
{{report.intervention_report.queryset_checked_count|default_if_zero:"-"}}{{report.intervention_report.queryset_recorded_count|default_if_zero:"-"}}{{report.intervention_report.queryset_count|default_if_zero:"-"}}
+
\ No newline at end of file diff --git a/analysis/templates/analysis/reports/includes/intervention/card_intervention.html b/analysis/templates/analysis/reports/includes/intervention/card_intervention.html new file mode 100644 index 00000000..6a9993a3 --- /dev/null +++ b/analysis/templates/analysis/reports/includes/intervention/card_intervention.html @@ -0,0 +1,26 @@ +{% load i18n fontawesome_5 %} +
+
+
+
+
+
+
+ {% fa5_icon 'pencil-ruler' %} + {% trans 'Interventions' %} +
+
+
+
+
+
+ {% include 'analysis/reports/includes/intervention/amount.html' %} +
+ {% include 'analysis/reports/includes/intervention/compensated_by.html' %} +
+ {% include 'analysis/reports/includes/intervention/laws.html' %} +
+
+
+
+
\ No newline at end of file diff --git a/analysis/templates/analysis/reports/includes/intervention/compensated_by.html b/analysis/templates/analysis/reports/includes/intervention/compensated_by.html new file mode 100644 index 00000000..c6be40cc --- /dev/null +++ b/analysis/templates/analysis/reports/includes/intervention/compensated_by.html @@ -0,0 +1,34 @@ +{% load i18n fontawesome_5 ksp_filters %} +

{% trans 'Compensated by' %}

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
{% trans 'Compensation type' %}{% fa5_icon 'star' %} {% trans 'Checked' %}{% fa5_icon 'bookmark' %} {% trans 'Recorded' %}{% trans 'Total' %}
{% trans 'Compensation' %}{{report.intervention_report.compensation_sum_checked|default_if_zero:"-"}}{{report.intervention_report.compensation_sum_recorded|default_if_zero:"-"}}{{report.intervention_report.compensation_sum|default_if_zero:"-"}}
{% trans 'Payment' %}{{report.intervention_report.payment_sum_checked|default_if_zero:"-"}}{{report.intervention_report.payment_sum_recorded|default_if_zero:"-"}}{{report.intervention_report.payment_sum|default_if_zero:"-"}}
{% trans 'Deductions' %}{{report.intervention_report.deduction_sum_checked|default_if_zero:"-"}}{{report.intervention_report.deduction_sum_recorded|default_if_zero:"-"}}{{report.intervention_report.deduction_sum|default_if_zero:"-"}}
+
\ No newline at end of file diff --git a/analysis/templates/analysis/reports/includes/intervention/laws.html b/analysis/templates/analysis/reports/includes/intervention/laws.html new file mode 100644 index 00000000..e310197f --- /dev/null +++ b/analysis/templates/analysis/reports/includes/intervention/laws.html @@ -0,0 +1,50 @@ +{% load i18n fontawesome_5 ksp_filters %} +

{% trans 'Law usage' %}

+ + {% blocktrans %} + Please note: One intervention can be based on multiple laws. This table therefore does not + count + {% endblocktrans %} + +
+ + + + + + + + + + + {% for law in report.intervention_report.evaluated_laws %} + + + + + + + {% endfor %} + + + + + + + +
+ {% trans 'Law' %} + + {% fa5_icon 'star' %} {% trans 'Checked' %} + + {% fa5_icon 'bookmark' %} {% trans 'Recorded' %} + + {% trans 'Total' %} +
+ {{law.short_name}} +
+ + {{law.long_name}} + +
{{law.num_checked|default_if_zero:"-"}}{{law.num_recorded|default_if_zero:"-"}}{{law.num|default_if_zero:"-"}}
{% trans 'Total' %}{{report.intervention_report.law_sum_checked|default_if_zero:"-"}}{{report.intervention_report.law_sum_recorded|default_if_zero:"-"}}{{report.intervention_report.law_sum|default_if_zero:"-"}}
+
\ No newline at end of file diff --git a/analysis/templates/analysis/reports/includes/old_data/amount.html b/analysis/templates/analysis/reports/includes/old_data/amount.html new file mode 100644 index 00000000..cd79cb6f --- /dev/null +++ b/analysis/templates/analysis/reports/includes/old_data/amount.html @@ -0,0 +1,40 @@ +{% load i18n fontawesome_5 ksp_filters %} + +

{% trans 'Amount' %}

+ + {% blocktrans %} + Checked = Has been checked by the registration office according to LKompVzVo + {% endblocktrans %} +
+ {% blocktrans %} + Recorded = Has been checked and published by the conservation office + {% endblocktrans %} +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
{% fa5_icon 'star' %} {% trans 'Type' %}{% fa5_icon 'bookmark' %} {% trans 'Recorded' %}{% trans 'Total' %}
{% trans 'Intervention' %}{{report.old_data_report.queryset_intervention_recorded_count|default_if_zero:"-"}}{{report.old_data_report.queryset_intervention_count|default_if_zero:"-"}}
{% trans 'Compensation' %}{{report.old_data_report.queryset_comps_recorded_count|default_if_zero:"-"}}{{report.old_data_report.queryset_comps_count|default_if_zero:"-"}}
{% trans 'Eco-account' %}{{report.old_data_report.queryset_acc_recorded_count|default_if_zero:"-"}}{{report.old_data_report.queryset_acc_count|default_if_zero:"-"}}
+
\ No newline at end of file diff --git a/analysis/templates/analysis/reports/includes/old_data/card_old_interventions.html b/analysis/templates/analysis/reports/includes/old_data/card_old_interventions.html new file mode 100644 index 00000000..a25a5712 --- /dev/null +++ b/analysis/templates/analysis/reports/includes/old_data/card_old_interventions.html @@ -0,0 +1,24 @@ +{% load i18n fontawesome_5 %} + +
+
+
+
+
+
+
+ {% fa5_icon 'pencil-ruler' %} + {% trans 'Old interventions' %} +
+ {% trans 'Before' %} 16.06.2018 +
+
+
+
+
+ {% include 'analysis/reports/includes/old_data/amount.html' %} +
+
+
+
+
\ No newline at end of file diff --git a/analysis/templates/analysis/reports/index.html b/analysis/templates/analysis/reports/index.html new file mode 100644 index 00000000..9c35d057 --- /dev/null +++ b/analysis/templates/analysis/reports/index.html @@ -0,0 +1,10 @@ +{% extends 'base.html' %} +{% load i18n fontawesome_5 %} + +{% block body %} +
+
+ {% include 'form/table/generic_table_form.html' %} +
+
+{% endblock %} \ No newline at end of file diff --git a/analysis/tests.py b/analysis/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/analysis/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/analysis/urls.py b/analysis/urls.py new file mode 100644 index 00000000..71eb6665 --- /dev/null +++ b/analysis/urls.py @@ -0,0 +1,15 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: michel.peltriaux@sgdnord.rlp.de +Created on: 15.10.21 + +""" +from django.urls import path +from analysis.views import * + +app_name = "analysis" +urlpatterns = [ + path("reports/", index_reports_view, name="reports"), + path("reports/", detail_report_view, name="report-detail"), +] \ No newline at end of file diff --git a/analysis/utils/excel/excel.py b/analysis/utils/excel/excel.py new file mode 100644 index 00000000..611f6a0c --- /dev/null +++ b/analysis/utils/excel/excel.py @@ -0,0 +1,114 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: michel.peltriaux@sgdnord.rlp.de +Created on: 21.10.21 + +""" +from django.core.files.temp import NamedTemporaryFile +from openpyxl import load_workbook + + +class TempExcelFile: + """ A temporary excel sheet which will not be saved on the hard drive permanently. + + Using a template file and a template_map dictionary, this class can be used to fill in automatically + predefined values into certain cells. + + Can be used to create excel files from data and sending it as a response like + _file = TempExcelFile() + response = HttpResponse( + content=file.stream, + content_type="application/ms-excel", + ) + response['Content-Disposition'] = 'attachment; filename=my_file.xlsx' + return response + + """ + stream = None + _template_file_path = None + _template_map = {} + _data_obj = None + + def __init__(self, template_file_path: str = None, template_map: dict = None): + self._template_map = template_map or {} + self._template_file_path = template_file_path + self._workbook = load_workbook(template_file_path) + self._file = NamedTemporaryFile() + + self._replace_template_placeholders() + + def _replace_template_placeholders(self, start_row: int = 0): + """ Replaces all placeholder inside the template according to _template_map + + Args: + start_row (int): Defines where to start + + Returns: + + """ + sheets = self._workbook.worksheets + for sheet in sheets: + ws = sheet + # Always activate sheet protection + ws.protection.sheet = True + ws.protection.enable() + _rows = ws.iter_rows(start_row) + for row in _rows: + for cell in row: + val = cell.value + if val in self._template_map: + attr = self._template_map[val] + # If keyword '_iter' can be found inside the placeholder value it's an iterable and we + # need to process it differently + if isinstance(attr, dict): + # Read the iterable object and related attributes from the dict + _iter_obj = attr.get("iterable", None) + _attrs = attr.get("attrs", []) + self._add_cells_from_iterable(ws, cell, _iter_obj, _attrs) + # Since the sheet length did change now, we need to rerun this function starting with the new + # row counter + self._replace_template_placeholders(start_row=cell.row + len(_iter_obj)) + else: + cell.value = attr + self._workbook.save(self._file.name) + self._file.seek(0) + self.stream = self._file.read() + + def _add_cells_from_iterable(self, ws, start_cell, _iter_obj: iter, _attrs: list): + """ + Adds iterable data defined by _template_map like + ... + "some_placeholder_iter": { + "iterable": iterable_object, + "attrs": [ + "attr1", + "attr2", + "attr3", + ... + ] + }, + ... + + Args: + ws (Workbook): The active workbook + _iter_obj (dict): Iterable definitions from template_map + + Returns: + + """ + # Save border style + border_style = start_cell.border.copy() + # Drop current row, since it is just placeholder + ws.delete_rows(start_cell.row) + # Add enoug empty rows for the data + ws.insert_rows(start_cell.row, len(_iter_obj)) + + i = 0 + for _iter_entry in _iter_obj: + j = 0 + for _iter_attr in _attrs: + _new_cell = ws.cell(start_cell.row + i, start_cell.column + j, getattr(_iter_entry, _iter_attr)) + _new_cell.border = border_style + j += 1 + i += 1 diff --git a/analysis/utils/excel/excel_report.xlsx b/analysis/utils/excel/excel_report.xlsx new file mode 100644 index 00000000..72cf1295 Binary files /dev/null and b/analysis/utils/excel/excel_report.xlsx differ diff --git a/analysis/utils/report.py b/analysis/utils/report.py new file mode 100644 index 00000000..3bfd6370 --- /dev/null +++ b/analysis/utils/report.py @@ -0,0 +1,547 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: michel.peltriaux@sgdnord.rlp.de +Created on: 18.10.21 + +""" +from django.contrib.gis.db.models import MultiPolygonField +from django.contrib.gis.db.models.functions import NumGeometries +from django.db.models import Count, Sum, Q +from django.db.models.functions import Cast + +from analysis.settings import LKOMPVZVO_PUBLISH_DATE +from codelist.models import KonovaCode +from codelist.settings import CODELIST_LAW_ID +from compensation.models import Compensation, Payment, EcoAccountDeduction, EcoAccount +from intervention.models import Intervention +from konova.models import Geometry +from konova.sub_settings.django_settings import BASE_DIR, DEFAULT_DATE_FORMAT + + +class TimespanReport: + """ Holds multiple report elements for a timespan report + + """ + office_id = -1 + date_from = -1 + date_to = -1 + + # Excel map is used to map a cell value ("A1") to an attribute + excel_map = {} + excel_template_path = f"{BASE_DIR}/analysis/utils/excel/excel_report.xlsx" + + class InterventionReport: + queryset = Intervention.objects.none() + queryset_checked = Intervention.objects.none() + queryset_recorded = Intervention.objects.none() + + queryset_count = -1 + queryset_checked_count = -1 + queryset_recorded_count = -1 + + # Law related + law_sum = -1 + law_sum_checked = -1 + law_sum_recorded = -1 + evaluated_laws = None + + # Compensations related + compensation_sum = -1 + compensation_sum_checked = -1 + compensation_sum_recorded = -1 + payment_sum = -1 + payment_sum_checked = -1 + payment_sum_recorded = -1 + deduction_sum = -1 + deduction_sum_checked = -1 + deduction_sum_recorded = -1 + + excel_map = {} + + 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 + ) + self.queryset_recorded = self.queryset.filter( + recorded__isnull=False + ) + self.queryset_count = self.queryset.count() + self.queryset_checked_count = self.queryset_checked.count() + self.queryset_recorded_count = self.queryset_recorded.count() + + self._create_report() + self._define_excel_map() + + def _define_excel_map(self): + """ Define the excel map, which holds values for each placeholder used in the template + + Returns: + + """ + self.excel_map = { + "i_checked": self.queryset_checked_count, + "i_recorded": self.queryset_recorded_count, + "i_total": self.queryset_count, + "i_compensations_checked": self.compensation_sum_checked, + "i_compensations_recorded": self.compensation_sum_recorded, + "i_compensations_total": self.compensation_sum, + "i_payments_recorded": self.payment_sum_recorded, + "i_payments_checked": self.payment_sum_checked, + "i_payments_total": self.payment_sum, + "i_deductions_recorded": self.deduction_sum_recorded, + "i_deductions_checked": self.deduction_sum_checked, + "i_deductions_total": self.deduction_sum, + "i_laws_iter": { + "iterable": self.evaluated_laws, + "attrs": [ + "short_name", + "num_checked", + "num_recorded", + "num", + ] + }, + "i_laws_checked": self.law_sum_checked, + "i_laws_recorded": self.law_sum_recorded, + "i_laws_total": self.law_sum, + } + + def _create_report(self): + """ Creates all report information + + Returns: + + """ + self._evaluate_laws() + self._evaluate_compensations() + + def _evaluate_laws(self): + """ Analyzes the intervention-law distribution + + Returns: + + """ + # Count interventions based on law + # Fetch all KonovaCodes for laws, sorted alphabetically + laws = KonovaCode.objects.filter( + is_archived=False, + is_leaf=True, + code_lists__in=[CODELIST_LAW_ID], + ).order_by( + "long_name" + ) + # Fetch all law ids which are used by any .legal object of an intervention object + intervention_laws_total = self.queryset.values_list("legal__laws__id") + intervention_laws_checked = self.queryset.filter(checked__isnull=False).values_list("legal__laws__id") + intervention_laws_recorded = self.queryset.filter(recorded__isnull=False).values_list( + "legal__laws__id") + # Count how often which law id appears in the above list, return only the long_name of the law and the resulting + # count (here 'num'). This is for keeping the db fetch as small as possible + # Compute the sum for total, checked and recorded + self.evaluated_laws = laws.annotate( + num=Count("id", filter=Q(id__in=intervention_laws_total)), + num_checked=Count("id", filter=Q(id__in=intervention_laws_checked)), + num_recorded=Count("id", filter=Q(id__in=intervention_laws_recorded)), + ).values_list("short_name", "long_name", "num_checked", "num_recorded", "num", named=True) + self.law_sum = self.evaluated_laws.aggregate(sum_num=Sum("num"))["sum_num"] + self.law_sum_checked = self.evaluated_laws.aggregate(sum_num_checked=Sum("num_checked"))["sum_num_checked"] + self.law_sum_recorded = self.evaluated_laws.aggregate(sum_num_recorded=Sum("num_recorded"))["sum_num_recorded"] + + def _evaluate_compensations(self): + """ Analyzes the types of compensation distribution + + Returns: + + """ + # Count all compensations + comps = Compensation.objects.filter( + intervention__in=self.queryset + ) + self.compensation_sum = comps.count() + self.compensation_sum_checked = comps.filter(intervention__checked__isnull=False).count() + self.compensation_sum_recorded = comps.filter(intervention__recorded__isnull=False).count() + + # Count all payments + payments = Payment.objects.filter( + intervention__in=self.queryset + ) + self.payment_sum = payments.count() + self.payment_sum_checked = payments.filter(intervention__checked__isnull=False).count() + self.payment_sum_recorded = payments.filter(intervention__recorded__isnull=False).count() + + # Count all deductions + deductions = EcoAccountDeduction.objects.filter( + intervention__in=self.queryset + ) + self.deduction_sum = deductions.count() + self.deduction_sum_checked = deductions.filter(intervention__checked__isnull=False).count() + self.deduction_sum_recorded = deductions.filter(intervention__recorded__isnull=False).count() + + class CompensationReport: + queryset = Compensation.objects.none() + queryset_checked = Compensation.objects.none() + queryset_recorded = Compensation.objects.none() + queryset_count = -1 + queryset_checked_count = -1 + queryset_recorded_count = -1 + + queryset_registration_office_unb = Compensation.objects.none() + queryset_registration_office_unb_checked = Compensation.objects.none() + queryset_registration_office_unb_recorded = Compensation.objects.none() + queryset_registration_office_unb_count = -1 + queryset_registration_office_unb_checked_count = -1 + queryset_registration_office_unb_recorded_count = -1 + num_single_surfaces_total_unb = -1 + + queryset_registration_office_tbp = Compensation.objects.none() + queryset_registration_office_tbp_checked = Compensation.objects.none() + queryset_registration_office_tbp_recorded = Compensation.objects.none() + queryset_registration_office_tbp_count = -1 + queryset_registration_office_tbp_checked_count = -1 + queryset_registration_office_tbp_recorded_count = -1 + num_single_surfaces_total_tbp = -1 + + queryset_registration_office_other = Compensation.objects.none() + queryset_registration_office_other_checked = Compensation.objects.none() + queryset_registration_office_other_recorded = Compensation.objects.none() + queryset_registration_office_other_count = -1 + queryset_registration_office_other_checked_count = -1 + queryset_registration_office_other_recorded_count = -1 + num_single_surfaces_total_other = -1 + + num_single_surfaces_total = -1 + num_single_surfaces_recorded = -1 + + # Code list id for 'Träger der Bauleitplanung' parent + id_tbp = 1943695 + # Code list id for 'untere Naturschutzbehörde' + id_unb = 1943087 + # Code list id for 'obere Naturschutzbehörde' + id_onb = 1943084 + + 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 + ) + self.queryset_recorded = self.queryset.filter( + intervention__recorded__isnull=False + ) + + self.queryset_count = self.queryset.count() + self.queryset_checked_count = self.queryset_checked.count() + self.queryset_recorded_count = self.queryset_recorded.count() + + self._create_report() + self._define_excel_map() + + def _define_excel_map(self): + """ Define the excel map, which holds values for each placeholder used in the template + + Returns: + + """ + self.excel_map = { + "c_unb_checked": self.queryset_registration_office_unb_checked_count, + "c_unb_recorded": self.queryset_registration_office_unb_recorded_count, + "c_unb": self.queryset_registration_office_unb_count, + "c_surfaces_unb": self.num_single_surfaces_total_unb, + "c_tbp_checked": self.queryset_registration_office_tbp_checked_count, + "c_tbp_recorded": self.queryset_registration_office_tbp_recorded_count, + "c_tbp": self.queryset_registration_office_tbp_count, + "c_surfaces_tbp": self.num_single_surfaces_total_tbp, + "c_other_checked": self.queryset_registration_office_other_checked_count, + "c_other_recorded": self.queryset_registration_office_other_recorded_count, + "c_other": self.queryset_registration_office_other_count, + "c_surfaces_other": self.num_single_surfaces_total_other, + "c_checked": self.queryset_checked_count, + "c_recorded": self.queryset_recorded_count, + "c_total": self.queryset_count, + "c_surfaces": self.num_single_surfaces_total, + } + + def _create_report(self): + """ Creates all report information + + Returns: + + """ + self._evaluate_compensation_responsibility() + self._evaluate_surfaces() + + def _evaluate_surfaces(self): + """ Evaluates the surfaces of compensation Multipolygon fields + + Returns: + + """ + # Evaluate all surfaces + ids = self.queryset.values_list("geometry_id") + self.num_single_surfaces_total = self._count_geometry_surfaces(ids) + + # Evaluate surfaces where the conservation office is the registration office as well + ids = self.queryset_registration_office_unb.values_list("geometry_id") + self.num_single_surfaces_total_unb = self._count_geometry_surfaces(ids) + + # Evaluates surfaces where the registration office is a Träger Bauleitplanung + ids = self.queryset_registration_office_tbp.values_list("geometry_id") + self.num_single_surfaces_total_tbp = self._count_geometry_surfaces(ids) + + # Evaluates surfaces where any other registration office is responsible + ids = self.queryset_registration_office_other.values_list("geometry_id") + self.num_single_surfaces_total_other = self._count_geometry_surfaces(ids) + + def _count_geometry_surfaces(self, ids: list): + """ Wraps counting of geometry surfaces from a given list of ids + + Args: + ids (list): List of geometry ids + + Returns: + + """ + # Now select all geometries matching the ids + # Then perform a ST_NumGeometries variant over all geometries + # Then sum up all of the calculated surface numbers + return Geometry.objects.filter( + id__in=ids + ).annotate( + geom_cast=Cast("geom", MultiPolygonField()) + ).annotate( + num=NumGeometries("geom_cast") + ).aggregate( + num_geoms=Sum("num") + )["num_geoms"] or 0 + + def _evaluate_compensation_responsibility(self): + """ Evaluates compensations based on different responsibility areas + + unb -> Untere Naturschutzbehörde + Holds entries where conservation_office and registration_office basically are the same + tbp -> Träger Bauleitplanung + Holds entries where registration_office is a Träger der Bauleitplanung + other -> Other registration offices + Holds all other entries + + Returns: + + """ + self.queryset_registration_office_unb = self.queryset.filter( + intervention__responsible__registration_office__parent__id=self.id_unb + ) + self.queryset_registration_office_unb_recorded = self.queryset_registration_office_unb.filter( + intervention__recorded__isnull=False, + ) + self.queryset_registration_office_unb_checked = self.queryset_registration_office_unb.filter( + intervention__checked__isnull=False, + ) + self.queryset_registration_office_unb_count = self.queryset_registration_office_unb.count() + self.queryset_registration_office_unb_checked_count = self.queryset_registration_office_unb_checked.count() + self.queryset_registration_office_unb_recorded_count = self.queryset_registration_office_unb_recorded.count() + + self.queryset_registration_office_tbp = self.queryset.filter( + intervention__responsible__registration_office__parent__id=self.id_tbp + ) + self.queryset_registration_office_tbp_recorded = self.queryset_registration_office_tbp.filter( + intervention__recorded__isnull=False, + ) + self.queryset_registration_office_tbp_checked = self.queryset_registration_office_tbp.filter( + intervention__checked__isnull=False, + ) + self.queryset_registration_office_tbp_count = self.queryset_registration_office_tbp.count() + self.queryset_registration_office_tbp_checked_count = self.queryset_registration_office_tbp_checked.count() + self.queryset_registration_office_tbp_recorded_count = self.queryset_registration_office_tbp_recorded.count() + + self.queryset_registration_office_other = self.queryset.exclude( + Q(id__in=self.queryset_registration_office_tbp) | Q(id__in=self.queryset_registration_office_unb) + ) + self.queryset_registration_office_other_recorded = self.queryset_registration_office_other.filter( + intervention__recorded__isnull=False, + ) + self.queryset_registration_office_other_checked = self.queryset_registration_office_other.filter( + intervention__checked__isnull=False, + ) + self.queryset_registration_office_other_count = self.queryset_registration_office_other.count() + self.queryset_registration_office_other_checked_count = self.queryset_registration_office_other_checked.count() + self.queryset_registration_office_other_recorded_count = self.queryset_registration_office_other_recorded.count() + + class EcoAccountReport: + queryset = EcoAccount.objects.none() + queryset_recorded = EcoAccount.objects.none() + queryset_count = -1 + queryset_recorded_count = -1 + + queryset_deductions = EcoAccountDeduction.objects.none() + queryset_deductions_recorded = EcoAccountDeduction.objects.none() + queryset_has_deductions = EcoAccountDeduction.objects.none() + queryset_deductions_count = -1 + queryset_deductions_recorded_count = -1 + queryset_has_deductions_count = -1 + + # Total size of deductions + deductions_sq_m = -1 + recorded_deductions_sq_m = -1 + + def __init__(self, id: str, date_from: str, date_to: str): + # First fetch all eco account for this office + self.queryset = 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.filter( + recorded__isnull=False + ) + # Fetch all related deductions + self.queryset_deductions = EcoAccountDeduction.objects.filter( + account__id__in=self.queryset.values_list("id") + ) + # Fetch deductions for interventions which are already recorded + self.queryset_deductions_recorded = self.queryset_deductions.filter( + intervention__recorded__isnull=False + ) + + self.queryset_count = self.queryset.count() + self.queryset_recorded_count = self.queryset_recorded.count() + self.queryset_deductions_count = self.queryset_deductions.count() + self.queryset_deductions_recorded_count = self.queryset_deductions_recorded.count() + self.queryset_has_deductions_count = self.queryset_has_deductions.count() + + self._create_report() + self._define_excel_map() + + def _define_excel_map(self): + """ Define the excel map, which holds values for each placeholder used in the template + + Returns: + + """ + self.excel_map = { + "acc_total": self.queryset_count, + "acc_recorded": self.queryset_recorded_count, + "acc_deduc_recorded": self.queryset_deductions_recorded_count, + "acc_deduc_surface_recorded": self.recorded_deductions_sq_m, + "acc_deduc_total": self.queryset_deductions_count, + "acc_deduc_surface_total": self.deductions_sq_m, + } + + def _create_report(self): + """ Creates all report information + + Returns: + + """ + self._evaluate_deductions() + + def _evaluate_deductions(self): + self.deductions_sq_m = self.queryset_deductions.aggregate( + sum=Sum("surface") + )["sum"] or 0 + self.recorded_deductions_sq_m = self.queryset_deductions_recorded.aggregate( + sum=Sum("surface") + )["sum"] or 0 + + class OldDataReport: + """ + Evaluates 'old data' (registered (zugelassen) before 16.06.2018) + """ + queryset_intervention = Intervention.objects.none() + queryset_intervention_recorded = Intervention.objects.none() + queryset_intervention_count = -1 + queryset_intervention_recorded_count = -1 + + queryset_comps = Compensation.objects.none() + queryset_comps_recorded = Compensation.objects.none() + queryset_comps_count = -1 + queryset_comps_recorded_count = -1 + + queryset_acc = EcoAccount.objects.none() + queryset_acc_recorded = EcoAccount.objects.none() + queryset_acc_count = -1 + queryset_acc_recorded_count = -1 + + def __init__(self, id: str, date_from: str, date_to: str): + self.queryset_intervention = 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_intervention_recorded = self.queryset_intervention.filter( + recorded__isnull=False + ) + self.queryset_intervention_count = self.queryset_intervention.count() + self.queryset_intervention_recorded_count = self.queryset_intervention_recorded.count() + + self.queryset_comps = Compensation.objects.filter( + intervention__in=self.queryset_intervention + ) + self.queryset_comps_recorded = Compensation.objects.filter( + intervention__in=self.queryset_intervention_recorded, + ) + self.queryset_comps_count = self.queryset_comps.count() + self.queryset_comps_recorded_count = self.queryset_comps_recorded.count() + + self.queryset_acc = EcoAccount.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_acc_recorded = self.queryset_acc.filter( + recorded__isnull=False, + ) + self.queryset_acc_count = self.queryset_acc.count() + self.queryset_acc_recorded_count = self.queryset_acc_recorded.count() + self._define_excel_map() + + def _define_excel_map(self): + """ Define the excel map, which holds values for each placeholder used in the template + + Returns: + + """ + self.excel_map = { + "old_i_recorded": self.queryset_intervention_recorded_count, + "old_i_total": self.queryset_intervention_count, + "old_c_recorded": self.queryset_comps_recorded_count, + "old_c_total": self.queryset_comps_count, + "old_ea_recorded": self.queryset_acc_recorded_count, + "old_ea_total": self.queryset_acc_count, + } + + def __init__(self, office_id: str, date_from: str, date_to: str): + self.office_id = 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_data_report = self.OldDataReport(self.office_id, date_from, date_to) + + # Build excel map + self.excel_map = { + "date_from": date_from.strftime(DEFAULT_DATE_FORMAT), + "date_to": date_to.strftime(DEFAULT_DATE_FORMAT), + } + self.excel_map.update(self.intervention_report.excel_map) + self.excel_map.update(self.compensation_report.excel_map) + self.excel_map.update(self.eco_account_report.excel_map) + self.excel_map.update(self.old_data_report.excel_map) diff --git a/analysis/views.py b/analysis/views.py new file mode 100644 index 00000000..6da4a586 --- /dev/null +++ b/analysis/views.py @@ -0,0 +1,98 @@ +from django.contrib import messages +from django.contrib.auth.decorators import login_required +from django.http import HttpRequest, HttpResponse +from django.shortcuts import render, redirect, get_object_or_404 +from django.utils import timezone + +from analysis.forms import TimespanReportForm +from analysis.utils.excel.excel import TempExcelFile +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 +@conservation_office_group_required +def index_reports_view(request: HttpRequest): + """ + + Args: + request (HttpRequest): The incoming request + + Returns: + + """ + template = "analysis/reports/index.html" + 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 + + Args: + request (HttpRequest): The incoming request + id (str): The conservation_office KonovaCode id + + Returns: + + """ + # Try to resolve the requested office id + cons_office = get_object_or_404( + KonovaCode, + id=id + ) + # Try to resolve the date parameters into Date objects -> redirect if this fails + try: + df = request.GET.get("df", None) + dt = request.GET.get("dt", None) + date_from = timezone.make_aware(timezone.datetime.fromisoformat(df)) + date_to = timezone.make_aware(timezone.datetime.fromisoformat(dt)) + except ValueError: + messages.error( + request, + PARAMS_INVALID, + extra_tags="danger", + ) + return redirect("analysis:reports") + + # Check whether the html default rendering is requested or an alternative + format_param = request.GET.get("format", "html") + report = TimespanReport(id, date_from, date_to) + + if format_param == "html": + template = "analysis/reports/detail.html" + context = { + "office": cons_office, + "report": report, + } + context = BaseContext(request, context).context + return render(request, template, context) + elif format_param == "excel": + file = TempExcelFile(report.excel_template_path, report.excel_map) + response = HttpResponse( + content=file.stream, + content_type="application/ms-excel", + ) + response['Content-Disposition'] = f'attachment; filename={cons_office.long_name}_{df}_{dt}.xlsx' + return response + else: + raise NotImplementedError diff --git a/compensation/forms/forms.py b/compensation/forms/forms.py index fd747ef5..eadee2f4 100644 --- a/compensation/forms/forms.py +++ b/compensation/forms/forms.py @@ -16,7 +16,7 @@ from codelist.models import KonovaCode from codelist.settings import CODELIST_COMPENSATION_FUNDING_ID, CODELIST_CONSERVATION_OFFICE_ID from compensation.models import Compensation, EcoAccount from intervention.inputs import GenerateInput -from intervention.models import Intervention, ResponsibilityData +from intervention.models import Intervention, ResponsibilityData, LegalData from konova.forms import BaseForm, SimpleGeomForm from user.models import UserActionLogEntry, UserAction @@ -284,10 +284,40 @@ class NewEcoAccountForm(AbstractCompensationForm, CompensationResponsibleFormMix Inherits from basic AbstractCompensationForm and further form fields from CompensationResponsibleFormMixin """ + surface = forms.DecimalField( + min_value=0.00, + decimal_places=2, + label=_("Available Surface"), + label_suffix="", + required=False, + help_text=_("The amount that can be used for deductions"), + widget=forms.NumberInput( + attrs={ + "class": "form-control", + "placeholder": "0,00" + } + ) + ) + registration_date = forms.DateField( + label=_("Agreement date"), + label_suffix="", + help_text=_("When did the parties agree on this?"), + required=False, + widget=forms.DateInput( + attrs={ + "type": "date", + "class": "form-control", + }, + format="%d.%m.%Y" + ) + ) + field_order = [ "identifier", "title", "conservation_office", + "registration_date", + "surface", "conservation_file_number", "handler", "fundings", @@ -313,7 +343,9 @@ class NewEcoAccountForm(AbstractCompensationForm, CompensationResponsibleFormMix identifier = self.cleaned_data.get("identifier", None) title = self.cleaned_data.get("title", None) fundings = self.cleaned_data.get("fundings", None) + registration_date = self.cleaned_data.get("registration_date", None) handler = self.cleaned_data.get("handler", None) + surface = self.cleaned_data.get("surface", None) conservation_office = self.cleaned_data.get("conservation_office", None) conservation_file_number = self.cleaned_data.get("conservation_file_number", None) comment = self.cleaned_data.get("comment", None) @@ -332,15 +364,20 @@ class NewEcoAccountForm(AbstractCompensationForm, CompensationResponsibleFormMix conservation_office=conservation_office, ) + legal = LegalData.objects.create( + registration_date=registration_date + ) + # Finally create main object acc = EcoAccount.objects.create( identifier=identifier, title=title, responsible=responsible, - deductable_surface=0.00, + deductable_surface=surface, created=action, geometry=geometry, comment=comment, + legal=legal ) acc.fundings.set(fundings) acc.users.add(user) @@ -354,30 +391,6 @@ class EditEcoAccountForm(NewEcoAccountForm): """ Form for editing eco accounts """ - surface = forms.DecimalField( - min_value=0.00, - decimal_places=2, - label=_("Available Surface"), - label_suffix="", - required=False, - help_text=_("The amount that can be used for deductions"), - widget=forms.NumberInput( - attrs={ - "class": "form-control", - "placeholder": "0,00" - } - ) - ) - field_order = [ - "identifier", - "title", - "conservation_office", - "surface", - "conservation_file_number", - "handler", - "fundings", - "comment", - ] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -387,11 +400,15 @@ class EditEcoAccountForm(NewEcoAccountForm): self.cancel_redirect = reverse("compensation:acc-detail", args=(self.instance.id,)) # Initialize form data + reg_date = self.instance.legal.registration_date + if reg_date is not None: + reg_date = reg_date.isoformat() form_data = { "identifier": self.instance.identifier, "title": self.instance.title, "surface": self.instance.deductable_surface, "handler": self.instance.responsible.handler, + "registration_date": reg_date, "conservation_office": self.instance.responsible.conservation_office, "conservation_file_number": self.instance.responsible.conservation_file_number, "fundings": self.instance.fundings.all(), @@ -409,6 +426,7 @@ class EditEcoAccountForm(NewEcoAccountForm): identifier = self.cleaned_data.get("identifier", None) title = self.cleaned_data.get("title", None) fundings = self.cleaned_data.get("fundings", None) + registration_date = self.cleaned_data.get("registration_date", None) handler = self.cleaned_data.get("handler", None) surface = self.cleaned_data.get("surface", None) conservation_office = self.cleaned_data.get("conservation_office", None) @@ -429,6 +447,10 @@ class EditEcoAccountForm(NewEcoAccountForm): self.instance.responsible.conservation_file_number = conservation_file_number self.instance.responsible.save() + # Update legal data + self.instance.legal.registration_date = registration_date + self.instance.legal.save() + # Update main oject data self.instance.identifier = identifier self.instance.title = title diff --git a/compensation/models.py b/compensation/models.py index 4f9cc919..d2d18be5 100644 --- a/compensation/models.py +++ b/compensation/models.py @@ -19,7 +19,7 @@ from codelist.settings import CODELIST_COMPENSATION_ACTION_ID, CODELIST_BIOTOPES CODELIST_COMPENSATION_FUNDING_ID from compensation.managers import CompensationStateManager, EcoAccountDeductionManager, CompensationActionManager, \ EcoAccountManager, CompensationManager -from intervention.models import Intervention, ResponsibilityData +from intervention.models import Intervention, ResponsibilityData, LegalData from konova.models import BaseObject, BaseResource, Geometry, UuidModel, AbstractDocument, \ generate_document_file_upload_path from konova.settings import DEFAULT_SRID_RLP, LANIS_LINK_TEMPLATE @@ -309,6 +309,14 @@ class EcoAccount(AbstractCompensation): default=0, ) + legal = models.OneToOneField( + LegalData, + on_delete=models.SET_NULL, + null=True, + blank=True, + help_text="Holds data on legal dates or law" + ) + objects = EcoAccountManager() def __str__(self): diff --git a/compensation/templates/compensation/detail/eco_account/view.html b/compensation/templates/compensation/detail/eco_account/view.html index e839e6e9..6f7eca99 100644 --- a/compensation/templates/compensation/detail/eco_account/view.html +++ b/compensation/templates/compensation/detail/eco_account/view.html @@ -61,6 +61,10 @@ {% trans 'Conservation office file number' %} {{obj.responsible.conservation_file_number|default_if_none:""}} + + {% trans 'Agreement date' %} + {{obj.legal.registration_date|default_if_none:""}} + {% trans 'Action handler' %} {{obj.responsible.handler|default_if_none:""}} 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/managers.py b/intervention/managers.py index 213e8659..a0fb28ae 100644 --- a/intervention/managers.py +++ b/intervention/managers.py @@ -23,26 +23,3 @@ class InterventionManager(models.Manager): ).prefetch_related( "users", ) - - -class LegalDataManager(models.Manager): - """ Holds default db fetch setting for this model type - - """ - def get_queryset(self): - return super().get_querset().select_related( - "process_type", - ).prefetch_related( - "laws" - ) - - -class ResponsibilityDataManager(models.Manager): - """ Holds default db fetch setting for this model type - - """ - def get_queryset(self): - return super().get_querset().select_related( - "registration_office", - "conservation_office", - ) diff --git a/intervention/models.py b/intervention/models.py index 2bdf1eff..9d0c8816 100644 --- a/intervention/models.py +++ b/intervention/models.py @@ -15,7 +15,7 @@ from django.utils.translation import gettext_lazy as _ from codelist.models import KonovaCode from codelist.settings import CODELIST_REGISTRATION_OFFICE_ID, CODELIST_CONSERVATION_OFFICE_ID, CODELIST_LAW_ID, \ CODELIST_PROCESS_TYPE_ID -from intervention.managers import InterventionManager, LegalDataManager, ResponsibilityDataManager +from intervention.managers import InterventionManager from konova.models import BaseObject, Geometry, UuidModel, BaseResource, AbstractDocument, \ generate_document_file_upload_path from konova.settings import DEFAULT_SRID_RLP, LANIS_LINK_TEMPLATE, LANIS_ZOOM_LUT @@ -56,7 +56,6 @@ class ResponsibilityData(UuidModel): conservation_file_number = models.CharField(max_length=1000, blank=True, null=True) handler = models.CharField(max_length=500, null=True, blank=True, help_text="Refers to 'Eingriffsverursacher' or 'Maßnahmenträger'") - objects = ResponsibilityDataManager() def __str__(self): return "ZB: {} | ETS: {} | Handler: {}".format( @@ -172,8 +171,6 @@ class LegalData(UuidModel): revocation = models.OneToOneField(Revocation, null=True, blank=True, help_text="Refers to 'Widerspruch am'", on_delete=models.SET_NULL) - objects = LegalDataManager() - class Intervention(BaseObject): """ 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/forms.py b/konova/forms.py index 26914d27..74e53896 100644 --- a/konova/forms.py +++ b/konova/forms.py @@ -37,12 +37,14 @@ class BaseForm(forms.Form): """ template = None action_url = None + action_btn_label = _("Save") form_title = None cancel_redirect = None form_caption = None instance = None # The data holding model object form_attrs = {} # Holds additional attributes, that can be used in the template has_required_fields = False # Automatically set. Triggers hint rendering in templates + show_cancel_btn = True def __init__(self, *args, **kwargs): self.instance = kwargs.pop("instance", None) @@ -189,6 +191,7 @@ class BaseModalForm(BaseForm, BSModalForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) + self.action_btn_label = _("Continue") def process_request(self, request: HttpRequest, msg_success: str = _("Object removed"), msg_error: str = FORM_INVALID, redirect_url: str = None): """ Generic processing of request diff --git a/konova/sub_settings/django_settings.py b/konova/sub_settings/django_settings.py index 29540d4b..df875a81 100644 --- a/konova/sub_settings/django_settings.py +++ b/konova/sub_settings/django_settings.py @@ -69,6 +69,7 @@ INSTALLED_APPS = [ 'user', 'ema', 'codelist', + 'analysis', ] if DEBUG: INSTALLED_APPS += [ diff --git a/konova/templatetags/ksp_filters.py b/konova/templatetags/ksp_filters.py index 95fc7ea0..1472d503 100644 --- a/konova/templatetags/ksp_filters.py +++ b/konova/templatetags/ksp_filters.py @@ -34,3 +34,19 @@ def bootstrap_cls(value): """ return SVI_BOOTSTRAP_CLS_MAP.get(value, "") + + +@register.filter("default_if_zero") +def default_if_zero(val1, val2): + """ Returns val2 if val1 is 0 + + Similar to default_if_none + + Args: + val1 (int): The numerical value + val2 (str): The alternative + + Returns: + + """ + return val1 if val1 > 0 else val2 diff --git a/konova/urls.py b/konova/urls.py index 8448cb4e..1aebcbcc 100644 --- a/konova/urls.py +++ b/konova/urls.py @@ -36,7 +36,8 @@ urlpatterns = [ path('ema/', include("ema.urls")), path('user/', include("user.urls")), path('news/', include("news.urls")), - path('news/', include("codelist.urls")), + path('cl/', include("codelist.urls")), + path('analysis/', include("analysis.urls")), # Generic deadline routes path('deadline//remove', remove_deadline_view, name="deadline-remove"), 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 b9d3ebde..8a1e11b3 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 aebd7445..2ac3f918 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/LC_MESSAGES/django.po @@ -11,15 +11,15 @@ #: intervention/forms/forms.py:53 intervention/forms/forms.py:155 #: intervention/forms/forms.py:167 intervention/forms/modalForms.py:107 #: intervention/forms/modalForms.py:120 intervention/forms/modalForms.py:133 -#: konova/forms.py:140 konova/forms.py:244 konova/forms.py:310 -#: konova/forms.py:337 konova/forms.py:347 konova/forms.py:360 -#: konova/forms.py:372 konova/forms.py:393 user/forms.py:38 +#: konova/forms.py:142 konova/forms.py:247 konova/forms.py:313 +#: konova/forms.py:340 konova/forms.py:350 konova/forms.py:363 +#: konova/forms.py:375 konova/forms.py:396 user/forms.py:38 #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2021-10-14 09:12+0200\n" +"POT-Creation-Date: 2021-10-22 13:14+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -29,23 +29,288 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: analysis/forms.py:24 analysis/templates/analysis/reports/detail.html:8 +msgid "From" +msgstr "Vom" + +#: analysis/forms.py:36 +msgid "To" +msgstr "Bis" + +#: analysis/forms.py:47 compensation/forms/forms.py:94 +#: 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:49 compensation/forms/forms.py:96 +msgid "Select the responsible office" +msgstr "Verantwortliche Stelle" + +#: analysis/forms.py:58 compensation/forms/forms.py:68 +#: compensation/forms/forms.py:105 compensation/forms/forms.py:156 +#: 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:65 +msgid "Generate report" +msgstr "Bericht generieren" + +#: analysis/forms.py:66 +msgid "Select a timespan and the desired conservation office" +msgstr "Wählen Sie die Zeitspanne und die gewünschte Eintragungsstelle" + +#: analysis/forms.py:69 konova/forms.py:194 +msgid "Continue" +msgstr "Weiter" + +#: analysis/templates/analysis/reports/detail.html:7 +msgid "Evaluation report" +msgstr "Auswertungsbericht" + +#: analysis/templates/analysis/reports/detail.html:8 +msgid "to" +msgstr "bis" + +#: analysis/templates/analysis/reports/detail.html:14 +msgid "Download" +msgstr "" + +#: analysis/templates/analysis/reports/includes/compensation/amount.html:3 +#: analysis/templates/analysis/reports/includes/eco_account/amount.html:3 +#: analysis/templates/analysis/reports/includes/intervention/amount.html:3 +#: analysis/templates/analysis/reports/includes/old_data/amount.html:3 +#: compensation/forms/modalForms.py:351 +#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:34 +#: intervention/templates/intervention/detail/includes/deductions.html:31 +msgid "Amount" +msgstr "Menge" + +#: analysis/templates/analysis/reports/includes/compensation/amount.html:5 +#: analysis/templates/analysis/reports/includes/intervention/amount.html:5 +#: analysis/templates/analysis/reports/includes/old_data/amount.html:5 +msgid "" +"\n" +" Checked = Has been checked by the registration office according to " +"LKompVzVo\n" +" " +msgstr "" +"\n" +" Geprüft = Wurde von der zuständigen Zulassungsbehörde überprüft\n" +" " + +#: analysis/templates/analysis/reports/includes/compensation/amount.html:9 +#: analysis/templates/analysis/reports/includes/eco_account/amount.html:5 +#: analysis/templates/analysis/reports/includes/intervention/amount.html:9 +#: analysis/templates/analysis/reports/includes/old_data/amount.html:9 +msgid "" +"\n" +" Recorded = Has been checked and published by the conservation office\n" +" " +msgstr "" +"\n" +" Verzeichnet = Wurde von der Eintragungsstelle überprüft und " +"veröffentlicht\n" +" " + +#: analysis/templates/analysis/reports/includes/compensation/amount.html:17 +msgid "Area of responsibility" +msgstr "Zuständigkeitsbereich" + +#: analysis/templates/analysis/reports/includes/compensation/amount.html:18 +#: analysis/templates/analysis/reports/includes/intervention/amount.html:17 +#: analysis/templates/analysis/reports/includes/intervention/compensated_by.html:8 +#: analysis/templates/analysis/reports/includes/intervention/laws.html:17 +#: compensation/tables.py:35 +#: compensation/templates/compensation/detail/compensation/view.html:43 +#: intervention/tables.py:33 +#: intervention/templates/intervention/detail/view.html:68 user/models.py:48 +msgid "Checked" +msgstr "Geprüft" + +#: analysis/templates/analysis/reports/includes/compensation/amount.html:19 +#: analysis/templates/analysis/reports/includes/eco_account/amount.html:13 +#: analysis/templates/analysis/reports/includes/eco_account/deductions.html:8 +#: analysis/templates/analysis/reports/includes/eco_account/deductions.html:9 +#: analysis/templates/analysis/reports/includes/intervention/amount.html:18 +#: analysis/templates/analysis/reports/includes/intervention/compensated_by.html:9 +#: analysis/templates/analysis/reports/includes/intervention/laws.html:20 +#: analysis/templates/analysis/reports/includes/old_data/amount.html:18 +#: compensation/tables.py:41 compensation/tables.py:181 +#: compensation/templates/compensation/detail/compensation/view.html:57 +#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:31 +#: compensation/templates/compensation/detail/eco_account/view.html:44 +#: ema/tables.py:38 ema/templates/ema/detail/view.html:28 +#: intervention/tables.py:39 +#: intervention/templates/intervention/detail/view.html:82 user/models.py:49 +msgid "Recorded" +msgstr "Verzeichnet" + +#: analysis/templates/analysis/reports/includes/compensation/amount.html:20 +msgid "Number single areas" +msgstr "Einzelflächen" + +#: analysis/templates/analysis/reports/includes/compensation/amount.html:21 +#: analysis/templates/analysis/reports/includes/compensation/amount.html:47 +#: analysis/templates/analysis/reports/includes/eco_account/amount.html:14 +#: analysis/templates/analysis/reports/includes/eco_account/deductions.html:10 +#: analysis/templates/analysis/reports/includes/eco_account/deductions.html:11 +#: analysis/templates/analysis/reports/includes/intervention/amount.html:19 +#: analysis/templates/analysis/reports/includes/intervention/compensated_by.html:10 +#: analysis/templates/analysis/reports/includes/intervention/laws.html:23 +#: analysis/templates/analysis/reports/includes/intervention/laws.html:43 +#: analysis/templates/analysis/reports/includes/old_data/amount.html:19 +#: konova/templates/konova/home.html:23 konova/templates/konova/home.html:61 +#: konova/templates/konova/home.html:100 +msgid "Total" +msgstr "Insgesamt" + +#: analysis/templates/analysis/reports/includes/compensation/amount.html:26 +msgid "Conservation office by law" +msgstr "Naturschutzbehörde (§17 Abs.3 BNatSchG)" + +#: analysis/templates/analysis/reports/includes/compensation/amount.html:33 +msgid "Land-use planning" +msgstr "Träger Bauleitplanung" + +#: analysis/templates/analysis/reports/includes/compensation/amount.html:40 +msgid "Other registration office" +msgstr "Andere Zulassungsbehörden" + +#: analysis/templates/analysis/reports/includes/compensation/card_compensation.html:11 +#: compensation/tables.py:62 +#: intervention/templates/intervention/detail/includes/compensations.html:8 +#: intervention/templates/intervention/report/report.html:49 +msgid "Compensations" +msgstr "Kompensationen" + +#: analysis/templates/analysis/reports/includes/eco_account/card_eco_account.html:11 +msgid "Eco-Accounts" +msgstr "Ökokonten" + +#: analysis/templates/analysis/reports/includes/eco_account/deductions.html:3 +#: analysis/templates/analysis/reports/includes/intervention/compensated_by.html:27 +msgid "Deductions" +msgstr "Abbuchungen" + +#: analysis/templates/analysis/reports/includes/eco_account/deductions.html:9 +#: analysis/templates/analysis/reports/includes/eco_account/deductions.html:11 +#: compensation/forms/modalForms.py:152 +#: compensation/templates/compensation/detail/compensation/includes/states-after.html:36 +#: compensation/templates/compensation/detail/compensation/includes/states-before.html:36 +#: compensation/templates/compensation/detail/eco_account/includes/states-after.html:36 +#: compensation/templates/compensation/detail/eco_account/includes/states-before.html:36 +#: ema/templates/ema/detail/includes/states-after.html:36 +#: ema/templates/ema/detail/includes/states-before.html:36 +#: intervention/forms/modalForms.py:274 +msgid "Surface" +msgstr "Fläche" + +#: analysis/templates/analysis/reports/includes/intervention/card_intervention.html:10 +#: intervention/tables.py:66 +msgid "Interventions" +msgstr "Eingriffe" + +#: analysis/templates/analysis/reports/includes/intervention/compensated_by.html:2 +msgid "Compensated by" +msgstr "Kompensiert durch" + +#: analysis/templates/analysis/reports/includes/intervention/compensated_by.html:7 +msgid "Compensation type" +msgstr "Kompensationsart" + +#: analysis/templates/analysis/reports/includes/intervention/compensated_by.html:15 +#: analysis/templates/analysis/reports/includes/old_data/amount.html:29 +#: compensation/tables.py:84 +#: compensation/templates/compensation/detail/compensation/view.html:19 +#: konova/templates/konova/home.html:49 templates/navbars/navbar.html:28 +msgid "Compensation" +msgstr "Kompensation" + +#: analysis/templates/analysis/reports/includes/intervention/compensated_by.html:21 +#: compensation/forms/modalForms.py:75 +msgid "Payment" +msgstr "Zahlung" + +#: analysis/templates/analysis/reports/includes/intervention/laws.html:2 +msgid "Law usage" +msgstr "Gesetzesanwendungen" + +#: analysis/templates/analysis/reports/includes/intervention/laws.html:4 +msgid "" +"\n" +" Please note: One intervention can be based on multiple laws. This table " +"therefore does not\n" +" count\n" +" " +msgstr "" +"\n" +" Beachten Sie: Ein Eingriff kann mehreren Gesetzen zugeordnet worden " +"sein. Diese Tabelle zählt daher nicht die Eingriffe selbst , sondern wie oft " +"ein Gesetz Anwendung fand.\n" +" " + +#: analysis/templates/analysis/reports/includes/intervention/laws.html:14 +#: intervention/forms/forms.py:68 +#: intervention/templates/intervention/detail/view.html:39 +#: intervention/templates/intervention/report/report.html:20 +msgid "Law" +msgstr "Gesetz" + +#: analysis/templates/analysis/reports/includes/old_data/amount.html:17 +#: compensation/templates/compensation/detail/compensation/includes/deadlines.html:28 +#: compensation/templates/compensation/detail/eco_account/includes/deadlines.html:28 +#: ema/templates/ema/detail/includes/deadlines.html:28 +msgid "Type" +msgstr "Typ" + +#: analysis/templates/analysis/reports/includes/old_data/amount.html:24 +#: intervention/forms/modalForms.py:285 intervention/forms/modalForms.py:292 +#: intervention/tables.py:88 +#: intervention/templates/intervention/detail/view.html:19 +#: konova/templates/konova/home.html:11 templates/navbars/navbar.html:22 +msgid "Intervention" +msgstr "Eingriff" + +#: analysis/templates/analysis/reports/includes/old_data/amount.html:34 +#: compensation/tables.py:224 +#: compensation/templates/compensation/detail/eco_account/view.html:19 +#: intervention/forms/modalForms.py:258 intervention/forms/modalForms.py:265 +#: konova/templates/konova/home.html:88 templates/navbars/navbar.html:34 +msgid "Eco-account" +msgstr "Ökokonto" + +#: analysis/templates/analysis/reports/includes/old_data/card_old_interventions.html:11 +msgid "Old interventions" +msgstr "Altfälle" + +#: analysis/templates/analysis/reports/includes/old_data/card_old_interventions.html:13 +msgid "Before" +msgstr "Vor" + #: compensation/filters.py:70 msgid "Show only unrecorded" msgstr "Nur unverzeichnete anzeigen" -#: compensation/forms/forms.py:31 compensation/tables.py:25 -#: compensation/tables.py:167 ema/tables.py:28 intervention/forms/forms.py:27 +#: compensation/forms/forms.py:32 compensation/tables.py:25 +#: compensation/tables.py:166 ema/tables.py:28 intervention/forms/forms.py:27 #: intervention/tables.py:23 #: intervention/templates/intervention/detail/includes/compensations.html:30 msgid "Identifier" msgstr "Kennung" -#: compensation/forms/forms.py:34 intervention/forms/forms.py:30 +#: compensation/forms/forms.py:35 intervention/forms/forms.py:30 msgid "Generated automatically" msgstr "Automatisch generiert" -#: compensation/forms/forms.py:43 compensation/tables.py:30 -#: compensation/tables.py:172 +#: compensation/forms/forms.py:44 compensation/tables.py:30 +#: compensation/tables.py:171 #: compensation/templates/compensation/detail/compensation/includes/documents.html:28 #: compensation/templates/compensation/detail/compensation/view.html:31 #: compensation/templates/compensation/detail/eco_account/includes/documents.html:28 @@ -60,34 +325,27 @@ msgstr "Automatisch generiert" #: intervention/templates/intervention/detail/includes/documents.html:28 #: intervention/templates/intervention/detail/view.html:31 #: intervention/templates/intervention/report/report.html:12 -#: konova/forms.py:336 +#: konova/forms.py:339 msgid "Title" msgstr "Bezeichnung" -#: compensation/forms/forms.py:45 intervention/forms/forms.py:41 +#: compensation/forms/forms.py:46 intervention/forms/forms.py:41 msgid "An explanatory name" msgstr "Aussagekräftiger Titel" -#: compensation/forms/forms.py:49 ema/forms.py:47 ema/forms.py:105 +#: compensation/forms/forms.py:50 ema/forms.py:47 ema/forms.py:105 msgid "Compensation XY; Location ABC" msgstr "Kompensation XY; Flur ABC" -#: compensation/forms/forms.py:55 +#: compensation/forms/forms.py:56 msgid "Fundings" msgstr "Förderungen" -#: compensation/forms/forms.py:58 +#: compensation/forms/forms.py:59 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/forms.py:74 compensation/forms/modalForms.py:61 #: compensation/forms/modalForms.py:272 compensation/forms/modalForms.py:367 #: compensation/templates/compensation/detail/compensation/includes/actions.html:34 #: compensation/templates/compensation/detail/compensation/includes/deadlines.html:34 @@ -102,29 +360,15 @@ msgstr "Auswählen..." #: intervention/templates/intervention/detail/includes/documents.html:31 #: intervention/templates/intervention/detail/includes/payments.html:34 #: intervention/templates/intervention/detail/includes/revocation.html:38 -#: konova/forms.py:371 konova/templates/konova/comment_card.html:16 +#: konova/forms.py:374 konova/templates/konova/comment_card.html:16 msgid "Comment" msgstr "Kommentar" -#: compensation/forms/forms.py:75 intervention/forms/forms.py:181 +#: compensation/forms/forms.py:76 intervention/forms/forms.py:181 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/forms/forms.py:110 #: compensation/templates/compensation/detail/eco_account/view.html:62 #: compensation/templates/compensation/report/eco_account/report.html:20 #: ema/templates/ema/detail/view.html:46 @@ -134,57 +378,65 @@ msgstr "Verantwortliche Stelle" msgid "Conservation office file number" msgstr "Aktenzeichen Eintragungsstelle" -#: compensation/forms/forms.py:115 intervention/forms/forms.py:135 +#: compensation/forms/forms.py:116 intervention/forms/forms.py:135 msgid "ETS-123/ABC.456" msgstr "" -#: compensation/forms/forms.py:121 +#: compensation/forms/forms.py:122 msgid "Eco-account handler" msgstr "Maßnahmenträger" -#: compensation/forms/forms.py:125 +#: compensation/forms/forms.py:126 msgid "Who handles the eco-account" msgstr "Wer für die Herrichtung des Ökokontos verantwortlich ist" -#: compensation/forms/forms.py:128 intervention/forms/forms.py:148 +#: compensation/forms/forms.py:129 intervention/forms/forms.py:148 msgid "Company Mustermann" msgstr "Firma Mustermann" -#: compensation/forms/forms.py:146 +#: compensation/forms/forms.py:147 #: compensation/templates/compensation/detail/compensation/view.html:35 #: compensation/templates/compensation/report/compensation/report.html:16 msgid "compensates intervention" msgstr "kompensiert Eingriff" -#: compensation/forms/forms.py:148 +#: compensation/forms/forms.py:149 msgid "Select the intervention for which this compensation compensates" msgstr "Wählen Sie den Eingriff, für den diese Kompensation bestimmt ist" -#: compensation/forms/forms.py:173 +#: compensation/forms/forms.py:174 msgid "New compensation" msgstr "Neue Kompensation" -#: compensation/forms/forms.py:231 +#: compensation/forms/forms.py:232 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:291 msgid "Available Surface" msgstr "Verfügbare Fläche" -#: compensation/forms/forms.py:363 +#: compensation/forms/forms.py:294 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:303 +msgid "Agreement date" +msgstr "Vereinbarungsdatum" + +#: compensation/forms/forms.py:304 +msgid "When did the parties agree on this?" +msgstr "Wann wurde dieses Ökokonto offiziell vereinbart?" + +#: compensation/forms/forms.py:329 +msgid "New Eco-Account" +msgstr "Neues Ökokonto" + +#: compensation/forms/forms.py:338 +msgid "Eco-Account XY; Location ABC" +msgstr "Ökokonto XY; Flur ABC" + +#: compensation/forms/forms.py:397 msgid "Edit Eco-Account" msgstr "Ökokonto bearbeiten" @@ -203,14 +455,10 @@ msgstr "Zahlung wird an diesem Datum erwartet" #: compensation/forms/modalForms.py:63 compensation/forms/modalForms.py:274 #: compensation/forms/modalForms.py:369 intervention/forms/modalForms.py:134 -#: konova/forms.py:373 +#: konova/forms.py:376 msgid "Additional comment, maximum {} letters" msgstr "Zusätzlicher Kommentar, maximal {} Zeichen" -#: compensation/forms/modalForms.py:75 -msgid "Payment" -msgstr "Zahlung" - #: compensation/forms/modalForms.py:76 msgid "Add a payment for intervention '{}'" msgstr "Neue Ersatzzahlung zu Eingriff '{}' hinzufügen" @@ -231,17 +479,6 @@ msgstr "Biotoptyp" msgid "Select the biotope type" msgstr "Biotoptyp wählen" -#: compensation/forms/modalForms.py:152 -#: compensation/templates/compensation/detail/compensation/includes/states-after.html:36 -#: compensation/templates/compensation/detail/compensation/includes/states-before.html:36 -#: compensation/templates/compensation/detail/eco_account/includes/states-after.html:36 -#: compensation/templates/compensation/detail/eco_account/includes/states-before.html:36 -#: ema/templates/ema/detail/includes/states-after.html:36 -#: ema/templates/ema/detail/includes/states-before.html:36 -#: intervention/forms/modalForms.py:274 -msgid "Surface" -msgstr "Fläche" - #: compensation/forms/modalForms.py:155 intervention/forms/modalForms.py:276 msgid "in m²" msgstr "" @@ -258,7 +495,7 @@ msgstr "Geben Sie die Daten des neuen Zustandes ein" msgid "Added state" msgstr "Zustand hinzugefügt" -#: compensation/forms/modalForms.py:190 konova/forms.py:193 +#: compensation/forms/modalForms.py:190 konova/forms.py:196 msgid "Object removed" msgstr "Objekt entfernt" @@ -308,12 +545,12 @@ msgstr "Maßnahmentyp wählen" #: compensation/templates/compensation/detail/compensation/includes/documents.html:35 #: compensation/templates/compensation/detail/compensation/includes/states-after.html:40 #: compensation/templates/compensation/detail/compensation/includes/states-before.html:40 -#: compensation/templates/compensation/detail/eco_account/includes/actions.html:37 +#: compensation/templates/compensation/detail/eco_account/includes/actions.html:38 #: compensation/templates/compensation/detail/eco_account/includes/deadlines.html:37 #: compensation/templates/compensation/detail/eco_account/includes/deductions.html:40 #: compensation/templates/compensation/detail/eco_account/includes/documents.html:34 -#: compensation/templates/compensation/detail/eco_account/includes/states-after.html:39 -#: compensation/templates/compensation/detail/eco_account/includes/states-before.html:39 +#: compensation/templates/compensation/detail/eco_account/includes/states-after.html:40 +#: compensation/templates/compensation/detail/eco_account/includes/states-before.html:40 #: ema/templates/ema/detail/includes/actions.html:37 #: ema/templates/ema/detail/includes/deadlines.html:37 #: ema/templates/ema/detail/includes/documents.html:34 @@ -336,12 +573,6 @@ msgstr "Einheit" msgid "Select the unit" msgstr "Einheit wählen" -#: compensation/forms/modalForms.py:351 -#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:34 -#: intervention/templates/intervention/detail/includes/deductions.html:31 -msgid "Amount" -msgstr "Menge" - #: compensation/forms/modalForms.py:354 msgid "Insert the amount" msgstr "Menge eingeben" @@ -358,38 +589,38 @@ msgstr "Geben Sie die Daten der neuen Maßnahme ein" msgid "Added action" msgstr "Maßnahme hinzugefügt" -#: compensation/models.py:78 +#: compensation/models.py:82 msgid "cm" msgstr "" -#: compensation/models.py:79 +#: compensation/models.py:83 msgid "m" msgstr "" -#: compensation/models.py:80 +#: compensation/models.py:84 msgid "km" msgstr "" -#: compensation/models.py:81 +#: compensation/models.py:85 msgid "m²" msgstr "" -#: compensation/models.py:82 +#: compensation/models.py:86 msgid "ha" msgstr "" -#: compensation/models.py:83 +#: compensation/models.py:87 msgid "Pieces" msgstr "Stück" -#: compensation/models.py:311 +#: compensation/models.py:329 msgid "" "Deductable surface can not be larger than existing surfaces in after states" msgstr "" "Die abbuchbare Fläche darf die Gesamtfläche der Zielzustände nicht " "überschreiten" -#: compensation/models.py:318 +#: compensation/models.py:336 msgid "" "Deductable surface can not be smaller than the sum of already existing " "deductions. Please contact the responsible users for the deductions!" @@ -397,50 +628,21 @@ msgstr "" "Es wurde bereits mehr Fläche abgebucht, als Sie nun als abbuchbar einstellen " "wollen. Kontaktieren Sie die für die Abbuchungen verantwortlichen Nutzer!" -#: compensation/tables.py:35 -#: compensation/templates/compensation/detail/compensation/view.html:43 -#: intervention/tables.py:33 -#: intervention/templates/intervention/detail/view.html:68 user/models.py:48 -msgid "Checked" -msgstr "Geprüft" - -#: compensation/tables.py:41 compensation/tables.py:182 -#: compensation/templates/compensation/detail/compensation/view.html:57 -#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:31 -#: compensation/templates/compensation/detail/eco_account/view.html:44 -#: ema/tables.py:38 ema/templates/ema/detail/view.html:28 -#: intervention/tables.py:39 -#: intervention/templates/intervention/detail/view.html:82 user/models.py:49 -msgid "Recorded" -msgstr "Verzeichnet" - -#: compensation/tables.py:47 compensation/tables.py:188 ema/tables.py:44 +#: compensation/tables.py:47 compensation/tables.py:187 ema/tables.py:44 #: intervention/tables.py:51 msgid "Editable" msgstr "Freigegeben" -#: compensation/tables.py:53 compensation/tables.py:194 ema/tables.py:50 +#: compensation/tables.py:53 compensation/tables.py:193 ema/tables.py:50 #: intervention/tables.py:57 msgid "Last edit" msgstr "Zuletzt bearbeitet" -#: compensation/tables.py:62 -#: intervention/templates/intervention/detail/includes/compensations.html:8 -#: intervention/templates/intervention/report/report.html:49 -msgid "Compensations" -msgstr "Kompensationen" - -#: compensation/tables.py:84 compensation/tables.py:225 ema/tables.py:82 +#: compensation/tables.py:84 compensation/tables.py:224 ema/tables.py:82 #: intervention/tables.py:88 msgid "Open {}" msgstr "Öffne {}" -#: compensation/tables.py:84 -#: compensation/templates/compensation/detail/compensation/view.html:19 -#: konova/templates/konova/home.html:49 templates/navbars/navbar.html:28 -msgid "Compensation" -msgstr "Kompensation" - #: compensation/tables.py:105 intervention/tables.py:107 msgid "Not checked yet" msgstr "Noch nicht geprüft" @@ -451,46 +653,40 @@ msgstr "Am {} von {} geprüft worden" #: compensation/tables.py:129 #: compensation/templates/compensation/detail/compensation/view.html:60 +#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:56 #: compensation/templates/compensation/detail/eco_account/view.html:47 #: ema/tables.py:101 ema/templates/ema/detail/view.html:31 -#: intervention/models.py:384 intervention/tables.py:131 +#: intervention/tables.py:131 #: intervention/templates/intervention/detail/view.html:85 msgid "Not recorded yet" msgstr "Noch nicht verzeichnet" -#: compensation/tables.py:134 compensation/tables.py:263 ema/tables.py:106 -#: intervention/models.py:389 intervention/tables.py:136 +#: compensation/tables.py:134 compensation/tables.py:262 ema/tables.py:106 +#: intervention/tables.py:136 msgid "Recorded on {} by {}" msgstr "Am {} von {} verzeichnet worden" -#: compensation/tables.py:159 compensation/tables.py:286 ema/tables.py:129 +#: compensation/tables.py:158 compensation/tables.py:284 ema/tables.py:129 #: intervention/tables.py:159 msgid "Full access granted" msgstr "Für Sie freigegeben - Datensatz kann bearbeitet werden" -#: compensation/tables.py:159 compensation/tables.py:286 ema/tables.py:129 +#: compensation/tables.py:158 compensation/tables.py:284 ema/tables.py:129 #: intervention/tables.py:159 msgid "Access not granted" msgstr "Nicht freigegeben - Datensatz nur lesbar" -#: compensation/tables.py:177 +#: compensation/tables.py:176 #: compensation/templates/compensation/detail/eco_account/view.html:35 #: konova/templates/konova/widgets/progressbar.html:3 msgid "Available" msgstr "Verfügbar" -#: compensation/tables.py:203 +#: compensation/tables.py:202 msgid "Eco Accounts" msgstr "Ökokonten" -#: compensation/tables.py:225 -#: compensation/templates/compensation/detail/eco_account/view.html:19 -#: intervention/forms/modalForms.py:258 intervention/forms/modalForms.py:265 -#: konova/templates/konova/home.html:88 templates/navbars/navbar.html:34 -msgid "Eco-account" -msgstr "Ökokonto" - -#: compensation/tables.py:258 +#: compensation/tables.py:257 msgid "Not recorded yet. Can not be used for deductions, yet." msgstr "" "Noch nicht verzeichnet. Kann noch nicht für Abbuchungen genutzt werden." @@ -522,7 +718,7 @@ msgid "Amount" msgstr "Menge" #: compensation/templates/compensation/detail/compensation/includes/actions.html:53 -#: compensation/templates/compensation/detail/eco_account/includes/actions.html:51 +#: compensation/templates/compensation/detail/eco_account/includes/actions.html:53 #: ema/templates/ema/detail/includes/actions.html:51 msgid "Remove action" msgstr "Maßnahme entfernen" @@ -575,12 +771,6 @@ msgstr "Termine und Fristen" msgid "Add new deadline" msgstr "Frist/Termin hinzufügen" -#: compensation/templates/compensation/detail/compensation/includes/deadlines.html:28 -#: compensation/templates/compensation/detail/eco_account/includes/deadlines.html:28 -#: ema/templates/ema/detail/includes/deadlines.html:28 -msgid "Type" -msgstr "Typ" - #: compensation/templates/compensation/detail/compensation/includes/deadlines.html:53 #: compensation/templates/compensation/detail/eco_account/includes/deadlines.html:51 #: ema/templates/ema/detail/includes/deadlines.html:51 @@ -598,7 +788,7 @@ msgstr "Dokumente" #: compensation/templates/compensation/detail/eco_account/includes/documents.html:14 #: ema/templates/ema/detail/includes/documents.html:14 #: intervention/templates/intervention/detail/includes/documents.html:14 -#: konova/forms.py:392 +#: konova/forms.py:395 msgid "Add new document" msgstr "Neues Dokument hinzufügen" @@ -638,8 +828,8 @@ msgstr "Biotoptyp" #: compensation/templates/compensation/detail/compensation/includes/states-after.html:54 #: compensation/templates/compensation/detail/compensation/includes/states-before.html:54 -#: compensation/templates/compensation/detail/eco_account/includes/states-after.html:52 -#: compensation/templates/compensation/detail/eco_account/includes/states-before.html:52 +#: compensation/templates/compensation/detail/eco_account/includes/states-after.html:54 +#: compensation/templates/compensation/detail/eco_account/includes/states-before.html:54 #: ema/templates/ema/detail/includes/states-after.html:52 #: ema/templates/ema/detail/includes/states-before.html:52 msgid "Remove state" @@ -670,6 +860,7 @@ msgstr "Geprüft am " #: compensation/templates/compensation/detail/compensation/view.html:50 #: compensation/templates/compensation/detail/compensation/view.html:64 +#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:54 #: compensation/templates/compensation/detail/eco_account/view.html:51 #: ema/templates/ema/detail/view.html:35 #: intervention/templates/intervention/detail/view.html:75 @@ -703,7 +894,7 @@ msgstr "Gefördert mit" #: intervention/templates/intervention/report/report.html:57 #: intervention/templates/intervention/report/report.html:78 msgid "None" -msgstr "" +msgstr "-" #: compensation/templates/compensation/detail/compensation/view.html:84 #: compensation/templates/compensation/detail/eco_account/view.html:83 @@ -755,6 +946,10 @@ msgstr "Eingriffskennung" msgid "Created" msgstr "Erstellt" +#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:54 +msgid "Recorded on" +msgstr "Verzeichnet am" + #: compensation/templates/compensation/detail/eco_account/includes/deductions.html:63 #: intervention/templates/intervention/detail/includes/deductions.html:58 msgid "Remove Deduction" @@ -796,17 +991,17 @@ msgstr "Maßnahmenträger" msgid "Report" msgstr "Bericht" -#: compensation/templates/compensation/report/compensation/report.html:58 -#: compensation/templates/compensation/report/eco_account/report.html:75 -#: ema/templates/ema/report/report.html:62 -#: intervention/templates/intervention/report/report.html:108 +#: compensation/templates/compensation/report/compensation/report.html:55 +#: compensation/templates/compensation/report/eco_account/report.html:72 +#: ema/templates/ema/report/report.html:59 +#: intervention/templates/intervention/report/report.html:105 msgid "Open in browser" msgstr "Im Browser öffnen" -#: compensation/templates/compensation/report/compensation/report.html:62 -#: compensation/templates/compensation/report/eco_account/report.html:79 -#: ema/templates/ema/report/report.html:66 -#: intervention/templates/intervention/report/report.html:112 +#: compensation/templates/compensation/report/compensation/report.html:59 +#: compensation/templates/compensation/report/eco_account/report.html:76 +#: ema/templates/ema/report/report.html:63 +#: intervention/templates/intervention/report/report.html:109 msgid "View in LANIS" msgstr "In LANIS öffnen" @@ -823,8 +1018,8 @@ msgid "Compensation {} edited" msgstr "Kompensation {} bearbeitet" #: compensation/views/compensation_views.py:213 -#: compensation/views/eco_account_views.py:278 ema/views.py:175 -#: intervention/views.py:428 +#: compensation/views/eco_account_views.py:287 ema/views.py:175 +#: intervention/views.py:437 msgid "Log" msgstr "Log" @@ -833,23 +1028,23 @@ msgid "Compensation removed" msgstr "Kompensation entfernt" #: compensation/views/compensation_views.py:253 -#: compensation/views/eco_account_views.py:377 ema/views.py:328 -#: intervention/views.py:124 +#: compensation/views/eco_account_views.py:386 ema/views.py:328 +#: intervention/views.py:126 msgid "Document added" msgstr "Dokument hinzugefügt" #: compensation/views/compensation_views.py:309 -#: compensation/views/eco_account_views.py:321 ema/views.py:272 +#: compensation/views/eco_account_views.py:330 ema/views.py:272 msgid "State added" msgstr "Zustand hinzugefügt" #: compensation/views/compensation_views.py:328 -#: compensation/views/eco_account_views.py:340 ema/views.py:291 +#: compensation/views/eco_account_views.py:349 ema/views.py:291 msgid "Action added" msgstr "Maßnahme hinzugefügt" #: compensation/views/compensation_views.py:347 -#: compensation/views/eco_account_views.py:359 ema/views.py:310 +#: compensation/views/eco_account_views.py:368 ema/views.py:310 msgid "Deadline added" msgstr "Frist/Termin hinzugefügt" @@ -861,33 +1056,33 @@ msgstr "Zustand gelöscht" msgid "Action removed" msgstr "Maßnahme entfernt" -#: compensation/views/eco_account_views.py:87 +#: compensation/views/eco_account_views.py:86 msgid "Eco-Account {} added" msgstr "Ökokonto {} hinzugefügt" -#: compensation/views/eco_account_views.py:142 +#: compensation/views/eco_account_views.py:141 msgid "Eco-Account {} edited" msgstr "Ökokonto {} bearbeitet" -#: compensation/views/eco_account_views.py:228 +#: compensation/views/eco_account_views.py:237 msgid "Eco-account removed" msgstr "Ökokonto entfernt" -#: compensation/views/eco_account_views.py:255 +#: compensation/views/eco_account_views.py:264 msgid "Deduction removed" msgstr "Abbuchung entfernt" -#: compensation/views/eco_account_views.py:298 ema/views.py:249 -#: intervention/views.py:468 +#: compensation/views/eco_account_views.py:307 ema/views.py:249 +#: intervention/views.py:477 msgid "{} unrecorded" msgstr "{} entzeichnet" -#: compensation/views/eco_account_views.py:298 ema/views.py:249 -#: intervention/views.py:468 +#: compensation/views/eco_account_views.py:307 ema/views.py:249 +#: intervention/views.py:477 msgid "{} recorded" msgstr "{} verzeichnet" -#: compensation/views/eco_account_views.py:434 intervention/views.py:450 +#: compensation/views/eco_account_views.py:443 intervention/views.py:459 msgid "Deduction added" msgstr "Abbuchung hinzugefügt" @@ -965,12 +1160,6 @@ msgstr "Bauvorhaben XY; Flur ABC" msgid "Process type" msgstr "Verfahrenstyp" -#: intervention/forms/forms.py:68 -#: intervention/templates/intervention/detail/view.html:39 -#: intervention/templates/intervention/report/report.html:20 -msgid "Law" -msgstr "Gesetz" - #: intervention/forms/forms.py:70 msgid "Multiple selection possible" msgstr "Mehrfachauswahl möglich" @@ -1051,7 +1240,7 @@ msgstr "Datum des Widerspruchs" msgid "Document" msgstr "Dokument" -#: intervention/forms/modalForms.py:122 konova/forms.py:361 +#: intervention/forms/modalForms.py:122 konova/forms.py:364 msgid "Must be smaller than 15 Mb" msgstr "Muss kleiner als 15 Mb sein" @@ -1073,7 +1262,7 @@ msgstr "Kompensationen und Zahlungen geprüft" msgid "Run check" msgstr "Prüfung vornehmen" -#: intervention/forms/modalForms.py:201 konova/forms.py:446 +#: intervention/forms/modalForms.py:201 konova/forms.py:449 msgid "" "I, {} {}, confirm that all necessary control steps have been performed by " "myself." @@ -1085,13 +1274,6 @@ msgstr "" msgid "Only recorded accounts can be selected for deductions" msgstr "Nur verzeichnete Ökokonten können für Abbuchungen verwendet werden." -#: intervention/forms/modalForms.py:285 intervention/forms/modalForms.py:292 -#: intervention/tables.py:88 -#: intervention/templates/intervention/detail/view.html:19 -#: konova/templates/konova/home.html:11 templates/navbars/navbar.html:22 -msgid "Intervention" -msgstr "Eingriff" - #: intervention/forms/modalForms.py:287 msgid "Only shared interventions can be selected" msgstr "Nur freigegebene Eingriffe können gewählt werden" @@ -1120,31 +1302,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:324 +#: intervention/models.py:326 msgid "Registration office file number missing" msgstr "Aktenzeichen Zulassungsbehörde fehlt" -#: intervention/models.py:327 +#: intervention/models.py:329 msgid "Conservation office file number missing" msgstr "Aktenzeichen Naturschutzbehörde fehlt" -#: intervention/models.py:330 +#: intervention/models.py:332 msgid "Responsible data missing" msgstr "Daten zu Verantwortlichen fehlen" -#: intervention/models.py:344 +#: intervention/models.py:346 msgid "Revocation exists" msgstr "Widerspruch liegt vor" -#: intervention/models.py:347 +#: intervention/models.py:349 msgid "Registration date missing" msgstr "Datum Zulassung bzw. Satzungsbeschluss fehlt" -#: intervention/models.py:350 +#: intervention/models.py:352 msgid "Binding on missing" msgstr "Datum Bestandskraft fehlt" -#: intervention/models.py:352 +#: intervention/models.py:354 msgid "Legal data missing" msgstr "Rechtliche Daten fehlen" @@ -1155,10 +1337,6 @@ msgstr "Rechtliche Daten fehlen" msgid "Revocation" msgstr "Widerspruch" -#: intervention/tables.py:66 -msgid "Interventions" -msgstr "Eingriffe" - #: intervention/tables.py:176 msgid "No revocation" msgstr "Kein Widerspruch" @@ -1226,15 +1404,15 @@ msgstr "Abbuchungen von Ökokonten" msgid "Exist" msgstr "Vorhanden" -#: intervention/views.py:77 +#: intervention/views.py:79 msgid "Intervention {} added" msgstr "Eingriff {} hinzugefügt" -#: intervention/views.py:212 +#: intervention/views.py:221 msgid "This intervention has a revocation from {}" msgstr "Es existiert ein Widerspruch vom {}" -#: intervention/views.py:228 +#: intervention/views.py:237 msgid "" "Remember: This data has not been shared with you, yet. This means you can " "only read but can not edit or perform any actions like running a check or " @@ -1244,43 +1422,43 @@ msgstr "" "bedeutet, dass Sie nur lesenden Zugriff hierauf haben und weder bearbeiten, " "noch Prüfungen durchführen oder verzeichnen können." -#: intervention/views.py:255 +#: intervention/views.py:264 msgid "Intervention {} edited" msgstr "Eingriff {} bearbeitet" -#: intervention/views.py:287 +#: intervention/views.py:296 msgid "{} removed" msgstr "{} entfernt" -#: intervention/views.py:308 +#: intervention/views.py:317 msgid "Revocation removed" msgstr "Widerspruch entfernt" -#: intervention/views.py:334 +#: intervention/views.py:343 msgid "{} has already been shared with you" msgstr "{} wurde bereits für Sie freigegeben" -#: intervention/views.py:339 +#: intervention/views.py:348 msgid "{} has been shared with you" msgstr "{} ist nun für Sie freigegeben" -#: intervention/views.py:346 +#: intervention/views.py:355 msgid "Share link invalid" msgstr "Freigabelink ungültig" -#: intervention/views.py:367 +#: intervention/views.py:376 msgid "Share settings updated" msgstr "Freigabe Einstellungen aktualisiert" -#: intervention/views.py:386 +#: intervention/views.py:395 msgid "Check performed" msgstr "Prüfung durchgeführt" -#: intervention/views.py:406 +#: intervention/views.py:415 msgid "Revocation added" msgstr "Widerspruch hinzugefügt" -#: intervention/views.py:473 +#: intervention/views.py:482 msgid "There are errors on this intervention:" msgstr "Es liegen Fehler in diesem Eingriff vor:" @@ -1301,64 +1479,68 @@ msgstr "" "somit nichts eingeben, bearbeiten oder sonstige Aktionen ausführen. " "Kontaktieren Sie bitte einen Administrator. +++" -#: konova/forms.py:69 +#: konova/forms.py:40 templates/form/collapsable/form.html:62 +msgid "Save" +msgstr "Speichern" + +#: konova/forms.py:71 msgid "Not editable" msgstr "Nicht editierbar" -#: konova/forms.py:139 konova/forms.py:309 +#: konova/forms.py:141 konova/forms.py:312 msgid "Confirm" msgstr "Bestätige" -#: konova/forms.py:151 konova/forms.py:318 +#: konova/forms.py:153 konova/forms.py:321 msgid "Remove" msgstr "Löschen" -#: konova/forms.py:153 +#: konova/forms.py:155 msgid "You are about to remove {} {}" msgstr "Sie sind dabei {} {} zu löschen" -#: konova/forms.py:243 templates/form/collapsable/form.html:45 +#: konova/forms.py:246 templates/form/collapsable/form.html:45 msgid "Geometry" msgstr "Geometrie" -#: konova/forms.py:319 +#: konova/forms.py:322 msgid "Are you sure?" msgstr "Sind Sie sicher?" -#: konova/forms.py:346 +#: konova/forms.py:349 msgid "Created on" msgstr "Erstellt" -#: konova/forms.py:348 +#: konova/forms.py:351 msgid "When has this file been created? Important for photos." msgstr "Wann wurde diese Datei erstellt oder das Foto aufgenommen?" -#: konova/forms.py:359 +#: konova/forms.py:362 #: venv/lib/python3.7/site-packages/django/db/models/fields/files.py:231 msgid "File" msgstr "Datei" -#: konova/forms.py:423 +#: konova/forms.py:426 msgid "Added document" msgstr "Dokument hinzugefügt" -#: konova/forms.py:437 +#: konova/forms.py:440 msgid "Confirm record" msgstr "Verzeichnen bestätigen" -#: konova/forms.py:445 +#: konova/forms.py:448 msgid "Record data" msgstr "Daten verzeichnen" -#: konova/forms.py:452 +#: konova/forms.py:455 msgid "Confirm unrecord" msgstr "Entzeichnen bestätigen" -#: konova/forms.py:453 +#: konova/forms.py:456 msgid "Unrecord data" msgstr "Daten entzeichnen" -#: konova/forms.py:454 +#: konova/forms.py:457 msgid "I, {} {}, confirm that this data must be unrecorded." msgstr "" "Ich, {} {}, bestätige, dass diese Daten wieder entzeichnet werden müssen." @@ -1403,10 +1585,13 @@ msgstr "Kontrolle am" msgid "Other" msgstr "Sonstige" -#: konova/templates/konova/home.html:23 konova/templates/konova/home.html:61 -#: konova/templates/konova/home.html:100 -msgid "Total" -msgstr "Insgesamt" +#: konova/sub_settings/django_settings.py:154 +msgid "German" +msgstr "" + +#: konova/sub_settings/django_settings.py:155 +msgid "English" +msgstr "" #: konova/templates/konova/home.html:27 konova/templates/konova/home.html:65 #: konova/templates/konova/home.html:104 @@ -1448,10 +1633,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" @@ -1459,11 +1648,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!" @@ -1549,15 +1738,10 @@ msgid "General data" msgstr "Allgemeine Daten" #: templates/form/collapsable/form.html:58 -#: templates/form/table/generic_table_form.html:23 +#: templates/form/table/generic_table_form.html:24 msgid "Cancel" msgstr "Abbrechen" -#: templates/form/collapsable/form.html:62 -#: templates/form/table/generic_table_form.html:27 -msgid "Save" -msgstr "Speichern" - #: templates/form/table/generic_table_form_body.html:24 msgid "Fields with * are required." msgstr "* sind Pflichtfelder." @@ -1606,10 +1790,6 @@ msgstr "Nutzer" msgid "No geometry added, yet." msgstr "Keine Geometrie vorhanden" -#: templates/modal/modal_form.html:25 -msgid "Continue" -msgstr "Weiter" - #: templates/navbars/navbar.html:4 msgid "Kompensationsverzeichnis Service Portal" msgstr "" @@ -2935,6 +3115,21 @@ msgstr "" msgid "A fontawesome icon field" msgstr "" +#~ msgid "After" +#~ msgstr "Nach" + +#~ msgid "Total interventions" +#~ msgstr "Insgesamt" + +#~ msgid "Amount total" +#~ msgstr "Anzahl insgesamt" + +#~ msgid "Amount checked" +#~ msgstr "Anzahl geprüft" + +#~ msgid "Amount recorded" +#~ msgstr "Anzahl verzeichnet" + #~ msgid "Funding by..." #~ msgstr "Gefördert mit..." @@ -2980,9 +3175,6 @@ msgstr "" #~ msgid "Transfer comment" #~ msgstr "Verwendungszweck" -#~ msgid "EMA recorded" -#~ msgstr "EMA verzeichnet" - #~ msgid "Edit {}" #~ msgstr "Bearbeite {}" @@ -3059,9 +3251,6 @@ msgstr "" #~ msgid "Role changed" #~ msgstr "Rolle geändert" -#~ msgid "Invalid role" -#~ msgstr "Rolle ungültig" - #~ msgid "Official" #~ msgstr "Amtlich" diff --git a/requirements.txt b/requirements.txt index 360af590..ac893917 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,11 +11,14 @@ django-filter==2.4.0 django-fontawesome-5==1.0.18 django-simple-sso==1.1.0 django-tables2==2.3.4 +et-xmlfile==1.1.0 idna==2.10 importlib-metadata==2.1.1 -itsdangerous -psycopg2-binary +itsdangerous==0.24 +openpyxl==3.0.9 +psycopg2-binary==2.9.1 pytz==2020.4 +qrcode==7.3.1 requests==2.25.0 six==1.15.0 soupsieve==2.2.1 diff --git a/templates/form/table/generic_table_form.html b/templates/form/table/generic_table_form.html index 7d321436..a89ee4bf 100644 --- a/templates/form/table/generic_table_form.html +++ b/templates/form/table/generic_table_form.html @@ -19,12 +19,14 @@ {% include 'form/table/generic_table_form_body.html' %}
+ {% if form.show_cancel_btn %} + {% endif %}
- +
diff --git a/templates/modal/modal_form.html b/templates/modal/modal_form.html index eda17303..6f47b127 100644 --- a/templates/modal/modal_form.html +++ b/templates/modal/modal_form.html @@ -22,7 +22,7 @@ {% if form.render_submit %} {% endif %} \ No newline at end of file diff --git a/templates/navbars/navbar.html b/templates/navbars/navbar.html index 39b622e1..46a274ff 100644 --- a/templates/navbars/navbar.html +++ b/templates/navbars/navbar.html @@ -43,7 +43,7 @@ {% fa5_icon 'euro-sign' %} {% trans 'EMA' %} {% fa5_icon 'file-import' %} {% trans 'Import...' %} {% fa5_icon 'file-export' %} {% trans 'Export...' %} - {% fa5_icon 'file-alt' %} {% trans 'Reports' %} + {% fa5_icon 'file-alt' %} {% trans 'Reports' %}