+
{% include 'konova/includes/report/qrcodes.html' %}
diff --git a/intervention/tests/test_workflow.py b/intervention/tests/test_workflow.py
index be885c96..d44c6d42 100644
--- a/intervention/tests/test_workflow.py
+++ b/intervention/tests/test_workflow.py
@@ -78,6 +78,7 @@ class InterventionWorkflowTestCase(BaseWorkflowTestCase):
self.assertEqual(1, obj.log.count())
self.assertEqual(obj.log.first().action, UserAction.CREATED)
self.assertEqual(obj.log.first().user, self.superuser)
+ self.assertEqual(obj.created, obj.modified)
except ObjectDoesNotExist:
# Fail if there is no such object
self.fail()
diff --git a/intervention/utils/egon_export.py b/intervention/utils/egon_export.py
index f8c24f16..38aa2ff7 100644
--- a/intervention/utils/egon_export.py
+++ b/intervention/utils/egon_export.py
@@ -11,7 +11,7 @@ import json
import pika
import xmltodict
from django.db.models import Sum
-from django.utils import formats, timezone
+from django.utils import formats
from intervention.settings import EGON_RABBITMQ_HOST, EGON_RABBITMQ_USER, EGON_RABBITMQ_PW, EGON_RABBITMQ_PORT
from konova.sub_settings.django_settings import DEFAULT_DATE_FORMAT
@@ -43,6 +43,7 @@ class EgonExporter:
"nachricht": self.gml_builder.gml,
}
msg = json.dumps(msg)
+ print(msg)
credentials = pika.PlainCredentials(EGON_RABBITMQ_USER, EGON_RABBITMQ_PW)
params = pika.ConnectionParameters(
EGON_RABBITMQ_HOST,
@@ -67,6 +68,7 @@ class EgonGmlBuilder:
"""
intervention = None
gml = None
+ _PAYMENT_FALLBACK_DATE = ""
def __init__(self, intervention):
self.intervention = intervention
@@ -164,9 +166,10 @@ class EgonGmlBuilder:
payment_date = None
if payment is not None:
payment_date = payment.due_on
- if payment_date is None:
- payment_date = timezone.datetime.fromisoformat("1970-01-01")
- payment_date = payment_date.strftime(DEFAULT_DATE_FORMAT)
+ if payment_date is not None:
+ payment_date = payment_date.strftime(DEFAULT_DATE_FORMAT)
+ else:
+ payment_date = self._PAYMENT_FALLBACK_DATE
cons_office = self.intervention.responsible.conservation_office
reg_office = self.intervention.responsible.registration_office
@@ -188,14 +191,14 @@ class EgonGmlBuilder:
"@gml:id": self.intervention.identifier,
"oneo:azEintragungsstelle": self.intervention.responsible.conservation_file_number,
"oneo:azZulassungsstelle": self.intervention.responsible.registration_file_number,
- "oneo:bemerkungZulassungsstelle": None,
+ "oneo:bemerkungZulassungsstelle": "",
"oneo:eintragungsstelle": {
- "@xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/907/{cons_office.atom_id if cons_office else None}",
- "#text": cons_office.long_name if cons_office else None
+ "@xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/907/{cons_office.atom_id if cons_office else ''}",
+ "#text": cons_office.long_name if cons_office else ""
},
"oneo:zulassungsstelle": {
- "@xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/1053/{reg_office.atom_id if reg_office else None}",
- "#text": reg_office.long_name if reg_office else None
+ "@xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/1053/{reg_office.atom_id if reg_office else ''}",
+ "#text": reg_office.long_name if reg_office else ""
},
"oneo:ersatzzahlung": self._float_to_localized_string(self._sum_all_payments()),
"oneo:kompensationsart": {
@@ -203,33 +206,33 @@ class EgonGmlBuilder:
"#text": comp_type
},
"oneo:verfahrensrecht": {
- "@xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/1048/{law.atom_id if law else None}",
- "#text": law.short_name if law else None
+ "@xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/1048/{law.atom_id if law else ''}",
+ "#text": law.short_name if law else ""
},
"oneo:verfahrenstyp": {
- "@xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/44382/{process_type.atom_id if process_type else None}",
- "#text": process_type.long_name if process_type else None,
+ "@xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/44382/{process_type.atom_id if process_type else ''}",
+ "#text": process_type.long_name if process_type else "",
},
"oneo:eingreifer": {
"oneo:Eingreifer": {
"oneo:art": {
- "@xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/1053/{handler.type.atom_id if handler.type else None}",
- "#text": handler.type.long_name if handler.type else None,
+ "@xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/1053/{handler.type.atom_id if handler.type else ''}",
+ "#text": handler.type.long_name if handler.type else "",
},
- "oneo:bemerkung": handler.detail if handler else None,
+ "oneo:bemerkung": handler.detail if handler else "",
}
},
"oneo:erfasser": {
"oneo:Erfasser": {
- "oneo:name": None,
- "oneo:bemerkung": None,
+ "oneo:name": "",
+ "oneo:bemerkung": "",
}
},
"oneo:zulassung": {
"oneo:Zulassungstermin": {
"oneo:bauBeginn": payment_date,
- "oneo:erlass": reg_date.strftime(DEFAULT_DATE_FORMAT) if reg_date else None,
- "oneo:rechtsKraft": bind_date.strftime(DEFAULT_DATE_FORMAT) if bind_date else None,
+ "oneo:erlass": reg_date.strftime(DEFAULT_DATE_FORMAT) if reg_date else "",
+ "oneo:rechtsKraft": bind_date.strftime(DEFAULT_DATE_FORMAT) if bind_date else "",
}
},
"oneo:geometrie": {
@@ -243,8 +246,8 @@ class EgonGmlBuilder:
"oneo:kennung": self.intervention.identifier,
"oneo:bezeichnung": self.intervention.title,
"oneo:bemerkung": self.intervention.comment,
- "oneo:verantwortlicheStelle": None,
- "oneo:veroffentlichtAm": None,
+ "oneo:verantwortlicheStelle": "",
+ "oneo:veroffentlichtAm": "",
"oneo:raumreferenz": {
"oneo:Raumreferenz": self._gen_raumreferenz(),
},
diff --git a/intervention/views/intervention.py b/intervention/views/intervention.py
index 1bca8968..0dd59bdf 100644
--- a/intervention/views/intervention.py
+++ b/intervention/views/intervention.py
@@ -45,6 +45,8 @@ def index_view(request: HttpRequest):
deleted=None, # not deleted
).select_related(
"legal"
+ ).order_by(
+ "-modified__timestamp"
)
table = InterventionTable(
request=request,
@@ -141,7 +143,8 @@ def detail_view(request: HttpRequest, id: str):
"legal",
"responsible",
),
- id=id
+ id=id,
+ deleted=None
)
compensations = intervention.compensations.filter(
deleted=None,
diff --git a/intervention/views/report.py b/intervention/views/report.py
index fa4798d0..663c293e 100644
--- a/intervention/views/report.py
+++ b/intervention/views/report.py
@@ -67,6 +67,7 @@ def report_view(request:HttpRequest, id: str):
},
"geom_form": geom_form,
"parcels": parcels,
+ "tables_scrollable": False,
TAB_TITLE_IDENTIFIER: tab_title,
}
context = BaseContext(request, context).context
diff --git a/konova/contexts.py b/konova/contexts.py
index 70cb1aac..23faedb8 100644
--- a/konova/contexts.py
+++ b/konova/contexts.py
@@ -28,6 +28,7 @@ class BaseContext:
"help_link": HELP_LINK,
"impressum_link": IMPRESSUM_LINK,
"CONTACT_MAIL": EMAIL_REPLY_TO,
+ "tables_scrollable": True, # tables in boxes
}
# Add additional context, derived from given parameters
diff --git a/konova/filters/mixins/geo_reference.py b/konova/filters/mixins/geo_reference.py
index 71fa41f5..6d77f6b2 100644
--- a/konova/filters/mixins/geo_reference.py
+++ b/konova/filters/mixins/geo_reference.py
@@ -19,7 +19,7 @@ class GeoReferencedTableFilterMixin(django_filters.FilterSet):
Specialized on filtering GeoReferenced model types
"""
- # Parcel gmrkng
+ # District
di = django_filters.CharFilter(
method="filter_district",
label=_(""),
@@ -72,7 +72,7 @@ class GeoReferencedTableFilterMixin(django_filters.FilterSet):
),
)
- # Parcel counter
+ # Parcel number
pn = django_filters.NumberFilter(
method="filter_parcel_number",
label=_(""),
@@ -112,7 +112,7 @@ class GeoReferencedTableFilterMixin(django_filters.FilterSet):
return queryset
def filter_district(self, queryset, name, value) -> QuerySet:
- """ Filters queryset depending on value for 'Gemarkung'
+ """ Filters queryset depending on value for 'Kreis'
Args:
queryset ():
@@ -122,10 +122,13 @@ class GeoReferencedTableFilterMixin(django_filters.FilterSet):
Returns:
"""
- matching_districts = District.objects.filter(
- Q(name__icontains=value) |
- Q(key__icontains=value)
- ).distinct()
+ values = value.split(",")
+ q = Q()
+ for val in values:
+ val = val.strip()
+ q |= Q(name__icontains=val) | Q(key__icontains=val)
+
+ matching_districts = District.objects.filter(q).distinct()
matching_parcels = Parcel.objects.filter(
district__in=matching_districts
)
@@ -148,9 +151,14 @@ class GeoReferencedTableFilterMixin(django_filters.FilterSet):
Returns:
"""
+ values = value.split(",")
+ q = Q()
+ for val in values:
+ val = val.strip()
+ q |= Q(parcel_group__name__icontains=val) | Q(parcel_group__key__icontains=val)
queryset = self._filter_parcel_reference(
queryset,
- Q(parcel_group__name__icontains=value) | Q(parcel_group__key__icontains=value),
+ q,
)
return queryset
diff --git a/konova/filters/mixins/record.py b/konova/filters/mixins/record.py
index 45476078..f9d8b09b 100644
--- a/konova/filters/mixins/record.py
+++ b/konova/filters/mixins/record.py
@@ -24,6 +24,7 @@ class RecordableTableFilterMixin(django_filters.FilterSet):
widget=forms.CheckboxInput(
attrs={
"class": "form-check-input",
+ "title": _("If activated also shows entries which have been already recorded"),
}
)
)
diff --git a/konova/filters/mixins/self_created.py b/konova/filters/mixins/self_created.py
new file mode 100644
index 00000000..43c4d603
--- /dev/null
+++ b/konova/filters/mixins/self_created.py
@@ -0,0 +1,53 @@
+"""
+Author: Michel Peltriaux
+Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
+Contact: ksp-servicestelle@sgdnord.rlp.de
+Created on: 06.12.22
+
+"""
+import django_filters
+from django import forms
+from django.db.models import QuerySet
+
+from django.utils.translation import gettext_lazy as _
+
+
+class SelfCreatedTableFilterMixin(django_filters.FilterSet):
+ """ A mixin for AbstractTableFilter
+
+ Specialized on filtering recordable model types
+
+ """
+ sc = django_filters.BooleanFilter(
+ method='filter_show_self_created',
+ label=_("Show only self created"),
+ label_suffix=_(""),
+ widget=forms.CheckboxInput(
+ attrs={
+ "class": "form-check-input",
+ "title": _("If activated only shows entries which have been created by you"),
+ }
+ ),
+ )
+
+ class Meta:
+ abstract = True
+
+ def filter_show_self_created(self, queryset, name, value) -> QuerySet:
+ """ Filters queryset depending on value of 'self_created' setting
+
+ Args:
+ queryset ():
+ name ():
+ value ():
+
+ Returns:
+
+ """
+ if value:
+ return queryset.filter(
+ created__user=self.user,
+ )
+ else:
+ return queryset
+
diff --git a/konova/filters/mixins/share.py b/konova/filters/mixins/share.py
index 562263c6..0c94bdc9 100644
--- a/konova/filters/mixins/share.py
+++ b/konova/filters/mixins/share.py
@@ -24,6 +24,7 @@ class ShareableTableFilterMixin(django_filters.FilterSet):
widget=forms.CheckboxInput(
attrs={
"class": "form-check-input",
+ "title": _("If activated also shows entries which are not shared with you"),
}
)
)
diff --git a/konova/filters/table_filters.py b/konova/filters/table_filters.py
index 5b8a4cc1..323bf1e7 100644
--- a/konova/filters/table_filters.py
+++ b/konova/filters/table_filters.py
@@ -12,6 +12,7 @@ from konova.filters.mixins.geo_reference import GeoReferencedTableFilterMixin
from konova.filters.mixins.keyword import KeywordTableFilterMixin
from konova.filters.mixins.office import ConservationOfficeTableFilterMixin, RegistrationOfficeTableFilterMixin
from konova.filters.mixins.record import RecordableTableFilterMixin
+from konova.filters.mixins.self_created import SelfCreatedTableFilterMixin
from konova.filters.mixins.share import ShareableTableFilterMixin
@@ -46,8 +47,10 @@ class QueryTableFilter(KeywordTableFilterMixin,
pass
-class CheckboxTableFilter(ShareableTableFilterMixin, RecordableTableFilterMixin):
+class CheckboxTableFilter(ShareableTableFilterMixin,
+ RecordableTableFilterMixin,
+ SelfCreatedTableFilterMixin):
""" TableFilter holding different filter options for checkbox related filtering
"""
- pass
\ No newline at end of file
+ pass
diff --git a/konova/forms/base_form.py b/konova/forms/base_form.py
index 6b71c213..98eaa41c 100644
--- a/konova/forms/base_form.py
+++ b/konova/forms/base_form.py
@@ -29,6 +29,7 @@ class BaseForm(forms.Form):
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
+ label_input_ratio = (3, 9) # used for col-sm-xy in the template. Must sum up to 12. Specify on inheriting forms
def __init__(self, *args, **kwargs):
self.instance = kwargs.pop("instance", None)
@@ -42,12 +43,26 @@ class BaseForm(forms.Form):
break
self.check_for_recorded_instance()
+ self.__check_valid_label_input_ratio()
@abstractmethod
def save(self):
# To be implemented in subclasses!
pass
+ def __check_valid_label_input_ratio(self):
+ """ Checks whether the configured label-input ratio is valid
+
+ If not valid an AssertionError will be raised.
+ The valid sum of label-input ratio is defined by bootstrap's column layout system.
+
+ Returns:
+
+ """
+ ratio = self.label_input_ratio[0] + self.label_input_ratio[1]
+ if ratio != 12:
+ raise AssertionError(f"Label-input ratio on form must sum up to 12! It's {self.label_input_ratio}")
+
def disable_form_field(self, field: str):
"""
Disables a form field for user editing
diff --git a/konova/forms/modals/remove_form.py b/konova/forms/modals/remove_form.py
index 7a146268..f09af99a 100644
--- a/konova/forms/modals/remove_form.py
+++ b/konova/forms/modals/remove_form.py
@@ -24,6 +24,7 @@ class RemoveModalForm(BaseModalForm):
widget=forms.CheckboxInput(),
required=True,
)
+ label_input_ratio = (2, 10)
def __init__(self, *args, **kwargs):
self.template = "modal/modal_form.html"
diff --git a/konova/management/commands/generate_report.py b/konova/management/commands/generate_report.py
new file mode 100644
index 00000000..51091871
--- /dev/null
+++ b/konova/management/commands/generate_report.py
@@ -0,0 +1,137 @@
+"""
+Author: Michel Peltriaux
+Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
+Contact: michel.peltriaux@sgdnord.rlp.de
+Created on: 26.10.22
+
+"""
+import zipfile
+from io import BytesIO
+
+from django.core.mail import EmailMessage
+from django.utils import timezone
+from django.utils.datetime_safe import datetime
+
+from analysis.utils.excel.excel import TempExcelFile
+from analysis.utils.report import TimespanReport
+from codelist.models import KonovaCode
+from codelist.settings import CODELIST_CONSERVATION_OFFICE_ID
+from konova.management.commands.setup import BaseKonovaCommand
+from konova.sub_settings.django_settings import DEFAULT_FROM_EMAIL, ADMINS
+
+
+class Command(BaseKonovaCommand):
+ help = "Generates reports for conservation offices"
+
+ __from_key = "from"
+ __to_key = "to"
+ __for_key = "for"
+
+ from_date = None
+ to_date = None
+ offices = None
+
+ def add_arguments(self, parser):
+ try:
+ parser.add_argument(f"--{self.__from_key}", type=str, nargs="+")
+ parser.add_argument(f"--{self.__to_key}", type=str, nargs="+")
+ parser.add_argument(f"--{self.__for_key}", type=str, nargs="*")
+ except ValueError as e:
+ self._write_error(f"Argument error: {e}")
+ exit(-1)
+
+ def handle(self, *args, **options):
+ self.__check_arguments(options)
+ in_memory_zipped_reports = self.generate_reports_in_memory_zipped()
+ self.send_mail_to_admins(in_memory_zipped_reports)
+
+ def generate_reports_in_memory_zipped(self):
+ """
+ Generates in-memory reports and zips into in-memory zip file.
+
+ Returns:
+
+ """
+ memory_zip = BytesIO()
+ with zipfile.ZipFile(memory_zip, "w", compression=zipfile.ZIP_DEFLATED) as zf:
+ for office in self.offices:
+ self._write_warning(f" Process report for {office.long_name}...")
+ report = TimespanReport(office.id, self.from_date, self.to_date)
+ excel_file = TempExcelFile(report.excel_template_path, report.excel_map)
+ zf.writestr(zinfo_or_arcname=f"{office.long_name}_{self.from_date.date()}_{self.to_date.date()}.xlsx", data=excel_file.stream)
+ self._write_success(f"Reports generated for {self.offices.count()} offices and zipped.")
+ return memory_zip.getvalue()
+
+ def __check_arguments(self, options):
+ """
+ Checks given parameters for validity
+
+ Args:
+ options ():
+
+ Returns:
+
+ """
+ _from_value = options.get(self.__from_key, [None])[0]
+ _to_value = options.get(self.__to_key, [None])[0]
+ _for_value = options.get(self.__for_key, [])
+
+ # Check ISO dates
+ try:
+ _from_date = timezone.make_aware(datetime.fromisoformat(_from_value))
+ _to_date = timezone.make_aware(datetime.fromisoformat(_to_value))
+ except Exception as e:
+ self._write_warning(f"One of the dates is not in ISO format (YYYY-MM-DD). {e}")
+ exit(-1)
+
+ # Check conservation office IDs
+ _filter = {
+ "is_archived": False,
+ "is_leaf": True,
+ "code_lists__in": [CODELIST_CONSERVATION_OFFICE_ID],
+ }
+ offices = KonovaCode.objects.filter(**_filter)
+ if _for_value is not None and len(_for_value) != 0:
+ # Specifc offices requested
+ offices = offices.filter(short_name__in=_for_value)
+ all_requested_offices_exist = offices.count() == len(_for_value)
+ if not all_requested_offices_exist:
+ offices_short_name = set(offices.values_list("short_name", flat=True))
+ missing_ids = []
+ for val in _for_value:
+ if val not in offices_short_name:
+ missing_ids.append(val)
+ self._write_warning(
+ f"Unknown offices: {missing_ids}"
+ )
+ exit(-1)
+
+ self.offices = offices
+ self.from_date = _from_date
+ self.to_date = _to_date
+
+ def send_mail_to_admins(self, attachment):
+ office_names = [office.long_name for office in self.offices]
+ admin_mails = [admin[1] for admin in ADMINS]
+
+ date_from_date = self.from_date.date()
+ date_to_date = self.to_date.date()
+
+ mail = EmailMessage(
+ subject="Konova reports generated",
+ body=f"Zipped reports attached from {date_from_date} to {date_to_date} for {office_names}.",
+ from_email=DEFAULT_FROM_EMAIL,
+ to=admin_mails,
+ attachments=[
+ (
+ f"reports_{date_from_date}_{date_to_date}.zip",
+ attachment,
+ "application/zip"
+ )
+ ]
+ )
+ success = mail.send()
+ if success == 1:
+ self._write_success(f"Mails with zip as attachment sent to {admin_mails}.")
+ else:
+ self._write_error(f"Something went wrong during mail sending. Returned sending code was '{success}'")
diff --git a/konova/management/commands/handle_resubmissions.py b/konova/management/commands/handle_resubmissions.py
index 047dbd5c..65954a3a 100644
--- a/konova/management/commands/handle_resubmissions.py
+++ b/konova/management/commands/handle_resubmissions.py
@@ -39,6 +39,9 @@ class Command(BaseKonovaCommand):
for obj in all_objs:
obj.resubmit()
self._write_success("Mails have been sent.")
+ resubmissions = Resubmission.objects.filter(
+ resubmission_sent=True,
+ )
resubmissions.delete()
self._write_success("Resubmissions have been deleted.")
except KeyboardInterrupt:
diff --git a/konova/models/document.py b/konova/models/document.py
index b465d70c..70ff3d79 100644
--- a/konova/models/document.py
+++ b/konova/models/document.py
@@ -87,7 +87,7 @@ class AbstractDocument(BaseResource):
"""
try:
os.remove(self.file.file.name)
- except FileNotFoundError:
+ except (FileNotFoundError, ValueError):
# File seems to missing anyway - continue!
pass
super().delete(using=using, keep_parents=keep_parents)
@@ -113,7 +113,7 @@ class AbstractDocument(BaseResource):
"""
try:
os.remove(self.file.file.name)
- except FileNotFoundError:
+ except (FileNotFoundError, ValueError):
pass
self.file = new_file
- self.save()
\ No newline at end of file
+ self.save()
diff --git a/konova/static/css/konova.css b/konova/static/css/konova.css
index ed797046..eb727894 100644
--- a/konova/static/css/konova.css
+++ b/konova/static/css/konova.css
@@ -60,6 +60,10 @@ a {
color: var(--rlp-red);
}
+.form-label {
+ width: 100%;
+}
+
.form-control:focus{
outline: none;
border-color: var(--rlp-red);
diff --git a/konova/utils/mailer.py b/konova/utils/mailer.py
index 65bbbe61..5c25d84b 100644
--- a/konova/utils/mailer.py
+++ b/konova/utils/mailer.py
@@ -429,7 +429,7 @@ class Mailer:
"EMAIL_REPLY_TO": EMAIL_REPLY_TO,
}
msg = render_to_string("email/resubmission/resubmission.html", context)
- user_mail_address = [SUPPORT_MAIL_RECIPIENT]
+ user_mail_address = [resubmission.user.email]
self.send(
user_mail_address,
_("Resubmission - {}").format(obj_identifier),
diff --git a/konova/views/geometry.py b/konova/views/geometry.py
index 868d629f..7d7fa6e3 100644
--- a/konova/views/geometry.py
+++ b/konova/views/geometry.py
@@ -5,11 +5,13 @@ Contact: ksp-servicestelle@sgdnord.rlp.de
Created on: 19.08.22
"""
+from django.contrib.gis.geos import MultiPolygon
from django.http import HttpResponse, HttpRequest
from django.shortcuts import get_object_or_404
from django.template.loader import render_to_string
from konova.models import Geometry, Municipal
+from konova.sub_settings.lanis_settings import DEFAULT_SRID_RLP
def get_geom_parcels(request: HttpRequest, id: str):
@@ -30,7 +32,7 @@ def get_geom_parcels(request: HttpRequest, id: str):
template = "konova/includes/parcels/parcel_table_frame.html"
geom = get_object_or_404(Geometry, id=id)
parcels = geom.get_underlying_parcels()
- geos_geom = geom.geom
+ geos_geom = geom.geom or MultiPolygon(srid=DEFAULT_SRID_RLP)
geometry_exists = not geos_geom.empty
parcels_are_currently_calculated = geometry_exists and geos_geom.area > 0 and len(parcels) == 0
diff --git a/locale/de/LC_MESSAGES/django.mo b/locale/de/LC_MESSAGES/django.mo
index b87493bc..1eca3291 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 fb261034..c225fa4f 100644
--- a/locale/de/LC_MESSAGES/django.po
+++ b/locale/de/LC_MESSAGES/django.po
@@ -28,8 +28,8 @@
#: konova/filters/mixins/geo_reference.py:79 konova/filters/mixins/office.py:24
#: konova/filters/mixins/office.py:25 konova/filters/mixins/office.py:56
#: konova/filters/mixins/office.py:57 konova/filters/mixins/record.py:23
-#: konova/filters/mixins/share.py:23 konova/forms/geometry_form.py:30
-#: konova/forms/modals/document_form.py:25
+#: konova/filters/mixins/self_created.py:24 konova/filters/mixins/share.py:23
+#: konova/forms/geometry_form.py:31 konova/forms/modals/document_form.py:25
#: konova/forms/modals/document_form.py:35
#: konova/forms/modals/document_form.py:48
#: konova/forms/modals/document_form.py:60
@@ -43,7 +43,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2022-11-16 13:36+0100\n"
+"POT-Creation-Date: 2022-12-06 08:23+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME
\n"
"Language-Team: LANGUAGE \n"
@@ -77,7 +77,7 @@ msgstr "Einträge erstellt bis..."
#: intervention/forms/intervention.py:103
#: intervention/templates/intervention/detail/view.html:56
#: intervention/templates/intervention/report/report.html:37
-#: intervention/utils/quality.py:49 konova/filters/mixins/office.py:34
+#: intervention/utils/quality.py:62 konova/filters/mixins/office.py:34
msgid "Conservation office"
msgstr "Eintragungsstelle"
@@ -365,8 +365,8 @@ msgstr "Kennung"
#: compensation/forms/compensation.py:33 intervention/forms/intervention.py:32
#: user/forms/user.py:77
-msgid "Generated automatically"
-msgstr "Automatisch generiert"
+msgid "Generated automatically - not editable"
+msgstr "Automatisch generiert - nicht bearbeitbar"
#: compensation/forms/compensation.py:42 compensation/tables/compensation.py:28
#: compensation/tables/eco_account.py:28
@@ -392,7 +392,7 @@ msgstr "Bezeichnung"
msgid "An explanatory name"
msgstr "Aussagekräftiger Titel"
-#: compensation/forms/compensation.py:48 ema/forms.py:51 ema/forms.py:111
+#: compensation/forms/compensation.py:48 ema/forms.py:51 ema/forms.py:114
msgid "Compensation XY; Location ABC"
msgstr "Kompensation XY; Flur ABC"
@@ -438,11 +438,11 @@ msgid "Select the intervention for which this compensation compensates"
msgstr "Wählen Sie den Eingriff, für den diese Kompensation bestimmt ist"
#: compensation/forms/compensation.py:113
-#: compensation/views/compensation/compensation.py:113
+#: compensation/views/compensation/compensation.py:115
msgid "New compensation"
msgstr "Neue Kompensation"
-#: compensation/forms/compensation.py:186
+#: compensation/forms/compensation.py:189
msgid "Edit compensation"
msgstr "Bearbeite Kompensation"
@@ -465,7 +465,7 @@ msgid "When did the parties agree on this?"
msgstr "Wann wurde dieses Ökokonto offiziell vereinbart?"
#: compensation/forms/eco_account.py:70
-#: compensation/views/eco_account/eco_account.py:94
+#: compensation/views/eco_account/eco_account.py:96
msgid "New Eco-Account"
msgstr "Neues Ökokonto"
@@ -473,11 +473,11 @@ msgstr "Neues Ökokonto"
msgid "Eco-Account XY; Location ABC"
msgstr "Ökokonto XY; Flur ABC"
-#: compensation/forms/eco_account.py:143
+#: compensation/forms/eco_account.py:145
msgid "Edit Eco-Account"
msgstr "Ökokonto bearbeiten"
-#: compensation/forms/eco_account.py:228
+#: compensation/forms/eco_account.py:230
msgid "The account can not be removed, since there are still deductions."
msgstr ""
"Das Ökokonto kann nicht entfernt werden, da hierzu noch Abbuchungen "
@@ -491,7 +491,7 @@ msgstr ""
#: intervention/forms/intervention.py:131
#: intervention/templates/intervention/detail/view.html:60
#: intervention/templates/intervention/report/report.html:41
-#: intervention/utils/quality.py:42
+#: intervention/utils/quality.py:55
msgid "Conservation office file number"
msgstr "Aktenzeichen Eintragungsstelle"
@@ -725,18 +725,22 @@ msgid "m"
msgstr ""
#: compensation/models/action.py:22
-msgid "km"
-msgstr ""
-
-#: compensation/models/action.py:23
msgid "m²"
msgstr ""
+#: compensation/models/action.py:23
+msgid "m³"
+msgstr ""
+
#: compensation/models/action.py:24
-msgid "ha"
+msgid "km"
msgstr ""
#: compensation/models/action.py:25
+msgid "ha"
+msgstr ""
+
+#: compensation/models/action.py:26
msgid "Pieces"
msgstr "Stück"
@@ -971,6 +975,7 @@ msgstr "Frist löschen"
#: compensation/templates/compensation/detail/eco_account/includes/documents.html:8
#: ema/templates/ema/detail/includes/documents.html:8
#: intervention/templates/intervention/detail/includes/documents.html:8
+#: intervention/utils/quality.py:37
msgid "Documents"
msgstr "Dokumente"
@@ -1135,7 +1140,7 @@ msgstr "Verzeichnet am"
#: ema/templates/ema/detail/view.html:71
#: ema/templates/ema/report/report.html:34
#: intervention/templates/intervention/detail/view.html:113
-#: intervention/templates/intervention/report/report.html:87
+#: intervention/templates/intervention/report/report.html:89
msgid "Last modified"
msgstr "Zuletzt bearbeitet"
@@ -1240,7 +1245,8 @@ msgstr "Abbuchungen für"
#: compensation/templates/compensation/report/eco_account/report.html:42
#: intervention/templates/intervention/report/report.html:53
-#: intervention/templates/intervention/report/report.html:74
+#: intervention/templates/intervention/report/report.html:66
+#: intervention/templates/intervention/report/report.html:76
msgid "None"
msgstr "-"
@@ -1252,7 +1258,7 @@ msgstr "Ungleiche Zustandsflächenmengen"
msgid "Finished deadlines"
msgstr "Umsetzungstermin"
-#: compensation/utils/quality.py:85 intervention/utils/quality.py:84
+#: compensation/utils/quality.py:85 intervention/utils/quality.py:97
msgid "Legal data"
msgstr "Rechtliche Daten"
@@ -1263,22 +1269,22 @@ msgstr ""
"überschreiten"
#: compensation/utils/quality.py:115 ema/utils/quality.py:30
-#: intervention/utils/quality.py:55
+#: intervention/utils/quality.py:68
msgid "Responsible data"
msgstr "Daten zu den verantwortlichen Stellen"
-#: compensation/views/compensation/compensation.py:56
+#: compensation/views/compensation/compensation.py:58
msgid "Compensations - Overview"
msgstr "Kompensationen - Übersicht"
-#: compensation/views/compensation/compensation.py:175
+#: compensation/views/compensation/compensation.py:177
#: konova/utils/message_templates.py:37
msgid "Compensation {} edited"
msgstr "Kompensation {} bearbeitet"
-#: compensation/views/compensation/compensation.py:185
-#: compensation/views/eco_account/eco_account.py:159 ema/views/ema.py:210
-#: intervention/views/intervention.py:228
+#: compensation/views/compensation/compensation.py:187
+#: compensation/views/eco_account/eco_account.py:161 ema/views/ema.py:212
+#: intervention/views/intervention.py:230
msgid "Edit {}"
msgstr "Bearbeite {}"
@@ -1288,27 +1294,27 @@ msgstr "Bearbeite {}"
msgid "Report {}"
msgstr "Bericht {}"
-#: compensation/views/eco_account/eco_account.py:51
+#: compensation/views/eco_account/eco_account.py:53
msgid "Eco-account - Overview"
msgstr "Ökokonten - Übersicht"
-#: compensation/views/eco_account/eco_account.py:84
+#: compensation/views/eco_account/eco_account.py:86
msgid "Eco-Account {} added"
msgstr "Ökokonto {} hinzugefügt"
-#: compensation/views/eco_account/eco_account.py:149
+#: compensation/views/eco_account/eco_account.py:151
msgid "Eco-Account {} edited"
msgstr "Ökokonto {} bearbeitet"
-#: compensation/views/eco_account/eco_account.py:265
+#: compensation/views/eco_account/eco_account.py:267
msgid "Eco-account removed"
msgstr "Ökokonto entfernt"
-#: ema/forms.py:42 ema/views/ema.py:93
+#: ema/forms.py:42 ema/views/ema.py:95
msgid "New EMA"
msgstr "Neue EMA hinzufügen"
-#: ema/forms.py:105
+#: ema/forms.py:108
msgid "Edit EMA"
msgstr "Bearbeite EMA"
@@ -1332,19 +1338,19 @@ msgstr ""
msgid "Payment funded compensation"
msgstr "Ersatzzahlungsmaßnahme"
-#: ema/views/ema.py:50
+#: ema/views/ema.py:52
msgid "EMAs - Overview"
msgstr "EMAs - Übersicht"
-#: ema/views/ema.py:83
+#: ema/views/ema.py:85
msgid "EMA {} added"
msgstr "EMA {} hinzugefügt"
-#: ema/views/ema.py:200
+#: ema/views/ema.py:202
msgid "EMA {} edited"
msgstr "EMA {} bearbeitet"
-#: ema/views/ema.py:234
+#: ema/views/ema.py:236
msgid "EMA removed"
msgstr "EMA entfernt"
@@ -1355,7 +1361,7 @@ msgstr "Bauvorhaben XY; Flur ABC"
#: intervention/forms/intervention.py:53
#: intervention/templates/intervention/detail/view.html:35
#: intervention/templates/intervention/report/report.html:16
-#: intervention/utils/quality.py:82
+#: intervention/utils/quality.py:95
msgid "Process type"
msgstr "Verfahrenstyp"
@@ -1366,14 +1372,14 @@ msgstr "Mehrfachauswahl möglich"
#: intervention/forms/intervention.py:87
#: intervention/templates/intervention/detail/view.html:48
#: intervention/templates/intervention/report/report.html:29
-#: intervention/utils/quality.py:46 konova/filters/mixins/office.py:66
+#: intervention/utils/quality.py:59 konova/filters/mixins/office.py:66
msgid "Registration office"
msgstr "Zulassungsbehörde"
#: intervention/forms/intervention.py:119
#: intervention/templates/intervention/detail/view.html:52
#: intervention/templates/intervention/report/report.html:33
-#: intervention/utils/quality.py:39
+#: intervention/utils/quality.py:52
msgid "Registration office file number"
msgstr "Aktenzeichen Zulassungsbehörde"
@@ -1395,22 +1401,23 @@ msgstr "Detailangabe zum Eingriffsverursacher"
#: intervention/forms/intervention.py:174
#: intervention/templates/intervention/detail/view.html:101
-#: intervention/templates/intervention/report/report.html:79
-#: intervention/utils/quality.py:73
+#: intervention/templates/intervention/report/report.html:81
+#: intervention/utils/quality.py:86
msgid "Registration date"
msgstr "Datum Zulassung bzw. Satzungsbeschluss"
#: intervention/forms/intervention.py:186
#: intervention/templates/intervention/detail/view.html:105
-#: intervention/templates/intervention/report/report.html:83
+#: intervention/templates/intervention/report/report.html:85
msgid "Binding on"
msgstr "Datum Bestandskraft bzw. Rechtskraft"
-#: intervention/forms/intervention.py:212 intervention/views/intervention.py:98
+#: intervention/forms/intervention.py:212
+#: intervention/views/intervention.py:100
msgid "New intervention"
msgstr "Neuer Eingriff"
-#: intervention/forms/intervention.py:299
+#: intervention/forms/intervention.py:302
msgid "Edit intervention"
msgstr "Eingriff bearbeiten"
@@ -1559,10 +1566,11 @@ msgid ""
"You entered a payment. Please upload the legal document which defines the "
"payment`s amount."
msgstr ""
-"Sie haben Ersatzzahlungen angegeben. Laden Sie bitte den Zahlungsbescheid als Dokument hoch."
+"Sie haben Ersatzzahlungen angegeben. Laden Sie bitte den Zahlungsbescheid "
+"als Dokument hoch."
#: intervention/templates/intervention/detail/includes/payments.html:8
-#: intervention/templates/intervention/report/report.html:69
+#: intervention/templates/intervention/report/report.html:71
msgid "Payments"
msgstr "Ersatzzahlungen"
@@ -1598,7 +1606,7 @@ msgid "Remove revocation"
msgstr "Widerspruch entfernen"
#: intervention/templates/intervention/detail/view.html:64
-#: intervention/utils/quality.py:52
+#: intervention/utils/quality.py:65
msgid "Intervention handler"
msgstr "Eingriffsverursacher"
@@ -1610,24 +1618,24 @@ msgstr "vorhanden"
msgid "Deductions of eco-accounts"
msgstr "Abbuchungen von Ökokonten"
-#: intervention/templates/intervention/report/report.html:72
+#: intervention/templates/intervention/report/report.html:74
msgid "Exist"
msgstr "Vorhanden"
-#: intervention/utils/quality.py:70
+#: intervention/utils/quality.py:83
#: templates/table/revocation_warning_col.html:5
msgid "Revocations exists"
msgstr "Widersprüche liegen vor"
-#: intervention/utils/quality.py:76
+#: intervention/utils/quality.py:89
msgid "Binding date"
msgstr "Datum Bestandskraft bzw. Rechtskraft"
-#: intervention/utils/quality.py:79
+#: intervention/utils/quality.py:92
msgid "Laws"
msgstr "Gesetze"
-#: intervention/utils/quality.py:101
+#: intervention/utils/quality.py:114
msgid "No compensation of any type found (Compensation, Payment, Deduction)"
msgstr ""
"Kein Ausgleich jeglicher Art gefunden (Kompensation, Ersatzzahlung, "
@@ -1637,19 +1645,19 @@ msgstr ""
msgid "Check performed"
msgstr "Prüfung durchgeführt"
-#: intervention/views/intervention.py:55
+#: intervention/views/intervention.py:57
msgid "Interventions - Overview"
msgstr "Eingriffe - Übersicht"
-#: intervention/views/intervention.py:88
+#: intervention/views/intervention.py:90
msgid "Intervention {} added"
msgstr "Eingriff {} hinzugefügt"
-#: intervention/views/intervention.py:216
+#: intervention/views/intervention.py:218
msgid "Intervention {} edited"
msgstr "Eingriff {} bearbeitet"
-#: intervention/views/intervention.py:253
+#: intervention/views/intervention.py:255
msgid "{} removed"
msgstr "{} entfernt"
@@ -1734,10 +1742,26 @@ msgstr "Nach Zulassungsbehörde suchen"
msgid "Show recorded"
msgstr "Verzeichnete anzeigen"
+#: konova/filters/mixins/record.py:27
+msgid "If activated also shows entries which have been already recorded"
+msgstr "Wenn aktiviert werden auch Einträge angezeigt, die bereits verzeichnet wurden"
+
+#: konova/filters/mixins/self_created.py:23
+msgid "Show only self created"
+msgstr "Nur selbst erstellte anzeigen"
+
+#: konova/filters/mixins/self_created.py:28
+msgid "If activated only shows entries which have been created by you"
+msgstr "Wenn aktiviert werden nur Einträge angezeigt, die von Ihnen erstellt worden sind"
+
#: konova/filters/mixins/share.py:22
msgid "Show unshared"
msgstr "Nicht freigegebene anzeigen"
+#: konova/filters/mixins/share.py:27
+msgid "If activated also shows entries which are not shared with you"
+msgstr "Wenn aktiviert werden auch Einträge angezeigt, die nicht für Sie freigegeben sind"
+
#: konova/forms/base_form.py:23 templates/form/collapsable/form.html:62
msgid "Save"
msgstr "Speichern"
@@ -1746,12 +1770,12 @@ msgstr "Speichern"
msgid "Not editable"
msgstr "Nicht editierbar"
-#: konova/forms/geometry_form.py:29 konova/utils/quality.py:44
+#: konova/forms/geometry_form.py:30 konova/utils/quality.py:44
#: konova/utils/quality.py:46 templates/form/collapsable/form.html:45
msgid "Geometry"
msgstr "Geometrie"
-#: konova/forms/geometry_form.py:80
+#: konova/forms/geometry_form.py:99
msgid "Only surfaces allowed. Points or lines must be buffered."
msgstr ""
"Nur Flächen erlaubt. Punkte oder Linien müssen zu Flächen gepuffert werden."
@@ -1904,6 +1928,10 @@ msgstr "Gemarkungsschlüssel"
msgid "Spatial reference"
msgstr "Raumreferenz"
+#: konova/templates/konova/includes/parcels/parcels.html:28
+msgid "No geometry entry found on database. Please contact an admin!"
+msgstr ""
+
#: konova/templates/konova/includes/quickstart/compensations.html:20
#: konova/templates/konova/includes/quickstart/ecoaccounts.html:20
#: konova/templates/konova/includes/quickstart/interventions.html:20
@@ -2308,7 +2336,9 @@ msgstr ""
#: templates/500.html:10
msgid "Something happened. Admins have been informed. We are working on it!"
-msgstr "Irgendetwas ist passiert. Die Administratoren wurden informiert. Wir arbeiten daran!"
+msgstr ""
+"Irgendetwas ist passiert. Die Administratoren wurden informiert. Wir "
+"arbeiten daran!"
#: templates/email/api/verify_token.html:7
msgid "Hello support"
diff --git a/templates/form/table/generic_table_form_body.html b/templates/form/table/generic_table_form_body.html
index 0f9b790e..aac55633 100644
--- a/templates/form/table/generic_table_form_body.html
+++ b/templates/form/table/generic_table_form_body.html
@@ -4,12 +4,18 @@
{% for field in form %}
-
- {{ field.label }}{% if field.field.required %}*{% endif %}
-
- {{ field.help_text }}
+ {{form.small_label_column}}
+
+
+ {{ field.label }}
+
+ {% if field.field.required %}*{% endif %}
+
+
+ {{ field.help_text }}
+
-
+
{{ field }}
{% for error in field.errors %}
diff --git a/templates/map/geom_form.html b/templates/map/geom_form.html
index 5cc5bdd8..58e21b84 100644
--- a/templates/map/geom_form.html
+++ b/templates/map/geom_form.html
@@ -4,9 +4,9 @@
Encapsules the rendering and initializing of a geometry view component, e.g. used in the detail views.
{% endcomment %}
-{% if geom_form.empty %}
+{% if geom_form.empty and geom_form.read_only %}
-
+
{% fa5_icon 'search-location' %}
{% trans 'No geometry added, yet.' %}
diff --git a/user/forms/user.py b/user/forms/user.py
index 99afc372..e27dba9b 100644
--- a/user/forms/user.py
+++ b/user/forms/user.py
@@ -74,7 +74,7 @@ class UserAPITokenForm(BaseForm):
label_suffix="",
max_length=255,
required=True,
- help_text=_("Generated automatically"),
+ help_text=_("Generated automatically - not editable"),
widget=GenerateInput(
attrs={
"class": "form-control",