Compare commits

...

4 Commits

Author SHA1 Message Date
ea0a07890c #7 New forms
* introduces bootstrap class form-control for proper html form input rendering
* fixes bug where missing shared users for an entry resulted in a None exception
* adds GenerateInput with template in generate-content-input.html, which provides a generate button for fetching server-side content
* adds/updates translations
2021-09-27 13:57:56 +02:00
78ef1b79af #7 New forms
* removes unused OpenInterventionForm
2021-09-27 11:46:41 +02:00
877a1ca335 #7 New forms
* refactors large forms.py into forms/modalForms.py and forms/forms.py
* refactors custom input fields into intervention/inputs.py
2021-09-27 11:45:13 +02:00
e94dbbd3c8 #7 New forms
* fixes bug in case of unset dates for intervention
* adds missing template formater
* adds/updates translations
2021-09-27 11:12:40 +02:00
15 changed files with 1052 additions and 946 deletions

View File

@ -46,6 +46,11 @@ class NewPaymentForm(BaseModalForm):
label=_con("money", "Amount"), # contextual translation label=_con("money", "Amount"), # contextual translation
label_suffix=_(""), label_suffix=_(""),
help_text=_("in Euro"), help_text=_("in Euro"),
widget=forms.NumberInput(
attrs={
"class": "form-control"
}
)
) )
due = forms.DateField( due = forms.DateField(
label=_("Due on"), label=_("Due on"),
@ -56,6 +61,7 @@ class NewPaymentForm(BaseModalForm):
attrs={ attrs={
"type": "date", "type": "date",
"data-provide": "datepicker", "data-provide": "datepicker",
"class": "form-control",
}, },
format="%d.%m.%Y" format="%d.%m.%Y"
) )
@ -69,14 +75,11 @@ class NewPaymentForm(BaseModalForm):
widget=forms.Textarea( widget=forms.Textarea(
attrs={ attrs={
"rows": 5, "rows": 5,
"class": "w-100" "class": "form-control"
} }
) )
) )
# Define w-100 for all form fields
full_width_fields = True
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.intervention = self.instance self.intervention = self.instance
@ -155,7 +158,12 @@ class NewStateModalForm(BaseModalForm):
label=_("Surface"), label=_("Surface"),
label_suffix="", label_suffix="",
required=True, required=True,
help_text=_("in m²") help_text=_("in m²"),
widget=forms.NumberInput(
attrs={
"class": "form-control",
}
)
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -243,7 +251,7 @@ class NewDeadlineModalForm(BaseModalForm):
choices=DeadlineType.choices, choices=DeadlineType.choices,
widget=forms.Select( widget=forms.Select(
attrs={ attrs={
"class": "custom-select" "class": "form-control"
} }
) )
) )
@ -256,6 +264,7 @@ class NewDeadlineModalForm(BaseModalForm):
attrs={ attrs={
"type": "date", "type": "date",
"data-provide": "datepicker", "data-provide": "datepicker",
"class": "form-control",
}, },
format="%d.%m.%Y" format="%d.%m.%Y"
) )
@ -270,6 +279,7 @@ class NewDeadlineModalForm(BaseModalForm):
attrs={ attrs={
"cols": 30, "cols": 30,
"rows": 5, "rows": 5,
"class": "form-control",
} }
) )
) )
@ -329,7 +339,7 @@ class NewActionModalForm(BaseModalForm):
choices=UnitChoices.choices, choices=UnitChoices.choices,
widget=forms.Select( widget=forms.Select(
attrs={ attrs={
"class": "custom-select" "class": "form-control"
} }
) )
) )
@ -340,6 +350,11 @@ class NewActionModalForm(BaseModalForm):
help_text=_("Insert the amount"), help_text=_("Insert the amount"),
decimal_places=2, decimal_places=2,
min_value=0.00, min_value=0.00,
widget=forms.NumberInput(
attrs={
"class": "form-control",
}
)
) )
comment = forms.CharField( comment = forms.CharField(
required=False, required=False,
@ -350,7 +365,7 @@ class NewActionModalForm(BaseModalForm):
widget=forms.Textarea( widget=forms.Textarea(
attrs={ attrs={
"rows": 5, "rows": 5,
"class": "w-100" "class": "form-control",
} }
) )
) )

View File

@ -5,6 +5,7 @@ Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 01.12.20 Created on: 01.12.20
""" """
from django.contrib.auth.models import User
from django.http import HttpRequest from django.http import HttpRequest
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.urls import reverse from django.urls import reverse
@ -148,6 +149,8 @@ class CompensationTable(BaseTable):
""" """
html = "" html = ""
if value is None:
value = User.objects.none()
has_access = value.filter( has_access = value.filter(
username=self.user.username username=self.user.username
).exists() ).exists()

View File

@ -16,7 +16,7 @@ from django.shortcuts import render, get_object_or_404
from compensation.forms import NewStateModalForm, NewActionModalForm, NewDeadlineModalForm from compensation.forms import NewStateModalForm, NewActionModalForm, NewDeadlineModalForm
from compensation.models import EcoAccount, EcoAccountDocument from compensation.models import EcoAccount, EcoAccountDocument
from compensation.tables import EcoAccountTable from compensation.tables import EcoAccountTable
from intervention.forms import NewDeductionForm from intervention.forms.modalForms import NewDeductionModalForm
from konova.contexts import BaseContext from konova.contexts import BaseContext
from konova.decorators import any_group_check, default_group_required, conservation_office_group_required from konova.decorators import any_group_check, default_group_required, conservation_office_group_required
from konova.forms import RemoveModalForm, SimpleGeomForm, NewDocumentForm, RecordModalForm from konova.forms import RemoveModalForm, SimpleGeomForm, NewDocumentForm, RecordModalForm
@ -340,7 +340,7 @@ def new_deduction_view(request: HttpRequest, id: str):
""" """
acc = get_object_or_404(EcoAccount, id=id) acc = get_object_or_404(EcoAccount, id=id)
form = NewDeductionForm(request.POST or None, instance=acc, user=request.user) form = NewDeductionModalForm(request.POST or None, instance=acc, user=request.user)
return form.process_request( return form.process_request(
request, request,
msg_success=_("Deduction added") msg_success=_("Deduction added")

View File

@ -12,7 +12,7 @@ from django.db.models import QuerySet, Q
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from intervention.forms import DummyFilterInput from intervention.inputs import DummyFilterInput
from intervention.models import Intervention from intervention.models import Intervention

View File

@ -1,737 +0,0 @@
"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 02.12.20
"""
from dal import autocomplete
from django import forms
from django.contrib.auth.models import User
from django.contrib.gis.geos import Polygon
from django.db import transaction
from django.urls import reverse
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from codelist.models import KonovaCode
from codelist.settings import CODELIST_PROCESS_TYPE_ID, CODELIST_LAW_ID, \
CODELIST_REGISTRATION_OFFICE_ID, CODELIST_CONSERVATION_OFFICE_ID
from compensation.models import EcoAccountDeduction, EcoAccount
from intervention.models import Intervention, Revocation, RevocationDocument, LegalData, ResponsibilityData
from konova.forms import BaseForm, BaseModalForm, SimpleGeomForm
from konova.settings import ZB_GROUP, ETS_GROUP
from konova.utils.general import format_german_float
from konova.utils.messenger import Messenger
from konova.utils.user_checks import in_group
from user.models import UserActionLogEntry, UserAction
class NewInterventionForm(BaseForm):
identifier = forms.CharField(
label=_("Identifier"),
label_suffix="",
max_length=255,
help_text=_("Generated automatically"),
)
title = forms.CharField(
label=_("Title"),
label_suffix="",
help_text=_("An explanatory name"),
max_length=255,
widget=forms.TextInput(
attrs={
"placeholder": _("Construction XY; Location ABC")
}
)
)
type = forms.ModelChoiceField(
label=_("Process type"),
label_suffix="",
help_text=_(""),
required=False,
queryset=KonovaCode.objects.filter(
is_archived=False,
is_leaf=True,
code_lists__in=[CODELIST_PROCESS_TYPE_ID],
),
widget=autocomplete.ModelSelect2(
url="codes-process-type-autocomplete",
attrs={
}
),
)
laws = forms.ModelMultipleChoiceField(
label=_("Law"),
label_suffix="",
help_text=_("Multiple selection possible"),
required=False,
queryset=KonovaCode.objects.filter(
is_archived=False,
is_leaf=True,
code_lists__in=[CODELIST_LAW_ID],
),
widget=autocomplete.ModelSelect2Multiple(
url="codes-law-autocomplete",
attrs={
}
),
)
registration_office = forms.ModelChoiceField(
label=_("Registration office"),
label_suffix="",
required=False,
queryset=KonovaCode.objects.filter(
is_archived=False,
is_leaf=True,
code_lists__in=[CODELIST_REGISTRATION_OFFICE_ID],
),
widget=autocomplete.ModelSelect2(
url="codes-registration-office-autocomplete",
attrs={
}
),
)
conservation_office = forms.ModelChoiceField(
label=_("Conservation office"),
label_suffix="",
required=False,
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={
}
),
)
registration_file_number = forms.CharField(
label=_("Registration office file number"),
label_suffix="",
max_length=255,
required=False,
widget=forms.TextInput(
attrs={
"placeholder": _("ZB-123/ABC.456")
}
)
)
conservation_file_number = forms.CharField(
label=_("Conservation office file number"),
label_suffix="",
max_length=255,
required=False,
widget=forms.TextInput(
attrs={
"placeholder": _("ETS-123/ABC.456")
}
)
)
handler = forms.CharField(
label=_("Intervention handler"),
label_suffix="",
max_length=255,
required=False,
help_text=_("Who performs the intervention"),
widget=forms.TextInput(
attrs={
"placeholder": _("Company Mustermann")
}
)
)
registration_date = forms.DateField(
label=_("Registration date"),
label_suffix=_(""),
required=False,
widget=forms.DateInput(
attrs={
"type": "date",
},
format="%d.%m.%Y"
)
)
binding_date = forms.DateField(
label=_("Binding on"),
label_suffix=_(""),
required=False,
widget=forms.DateInput(
attrs={
"type": "date",
},
format="%d.%m.%Y"
)
)
comment = forms.CharField(
label_suffix="",
label=_("Comment"),
required=False,
help_text=_("Additional comment"),
widget=forms.Textarea(
attrs={
"rows": 5,
"class": "w-100"
}
)
)
# Define w-100 for all form fields
full_width_fields = True
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form_title = _("New intervention")
self.action_url = reverse("intervention:new")
self.cancel_redirect = reverse("intervention:index")
tmp_intervention = Intervention()
identifier = tmp_intervention._generate_new_identifier()
self.initialize_form_field("identifier", identifier)
def save(self, user: User, geom_form: SimpleGeomForm):
with transaction.atomic():
# Fetch data from cleaned POST values
identifier = self.cleaned_data.get("identifier", None)
title = self.cleaned_data.get("title", None)
_type = self.cleaned_data.get("type", None)
laws = self.cleaned_data.get("laws", None)
handler = self.cleaned_data.get("handler", None)
registration_office = self.cleaned_data.get("registration_office", None)
conservation_office = self.cleaned_data.get("conservation_office", None)
conservation_file_number = self.cleaned_data.get("conservation_file_number", None)
registration_file_number = self.cleaned_data.get("registration_file_number", None)
binding_date = self.cleaned_data.get("binding_date", None)
registration_date = self.cleaned_data.get("registration_date", None)
comment = self.cleaned_data.get("comment", None)
# Create log entry
action = UserActionLogEntry.objects.create(
user=user,
action=UserAction.CREATED,
)
# Create legal data object (without M2M laws first)
legal_data = LegalData.objects.create(
registration_date=registration_date,
binding_date=binding_date,
process_type=_type,
)
# Then add the M2M laws to the object
legal_data.laws.set(laws)
# Create responsible data object
responsibility_data = ResponsibilityData.objects.create(
registration_office=registration_office,
conservation_office=conservation_office,
registration_file_number=registration_file_number,
conservation_file_number=conservation_file_number,
handler=handler,
)
# Process the geometry form
geometry = geom_form.save(action)
# Finally create main object, holding the other objects
intervention = Intervention.objects.create(
identifier=identifier,
title=title,
responsible=responsibility_data,
legal=legal_data,
created=action,
geometry=geometry,
comment=comment,
)
# Add the log entry to the main objects log list
intervention.log.add(action)
# Add the performing user as the first user having access to the data
intervention.users.add(user)
return intervention
class EditInterventionForm(NewInterventionForm):
""" Subclasses NewInterventionForm
Simply adds initializing of a provided self.instance object into the form fields
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.instance is not None:
self.action_url = reverse("intervention:edit", args=(self.instance.id,))
self.cancel_redirect = reverse("intervention:open", args=(self.instance.id,))
self.form_title = _("Edit intervention")
self.form_caption = ""
# Initialize form data
form_data = {
"identifier": self.instance.identifier,
"title": self.instance.title,
"type": self.instance.legal.process_type,
"laws": list(self.instance.legal.laws.values_list("id", flat=True)),
"handler": self.instance.responsible.handler,
"registration_office": self.instance.responsible.registration_office,
"registration_file_number": self.instance.responsible.registration_file_number,
"conservation_office": self.instance.responsible.conservation_office,
"conservation_file_number": self.instance.responsible.conservation_file_number,
"registration_date": self.instance.legal.registration_date.isoformat(),
"binding_date": self.instance.legal.binding_date.isoformat(),
"comment": self.instance.comment,
}
disabled_fields = [
"identifier",
]
self.load_initial_data(
form_data,
disabled_fields,
)
def save(self, user: User, geom_form: SimpleGeomForm):
""" Overwrite instance with new form data
Args:
user ():
Returns:
"""
with transaction.atomic():
identifier = self.cleaned_data.get("identifier", None)
title = self.cleaned_data.get("title", None)
process_type = self.cleaned_data.get("type", None)
laws = self.cleaned_data.get("laws", None)
handler = self.cleaned_data.get("handler", None)
registration_office = self.cleaned_data.get("registration_office", None)
registration_file_number = self.cleaned_data.get("registration_file_number", None)
conservation_office = self.cleaned_data.get("conservation_office", None)
conservation_file_number = self.cleaned_data.get("conservation_file_number", None)
registration_date = self.cleaned_data.get("registration_date", None)
binding_date = self.cleaned_data.get("binding_date", None)
comment = self.cleaned_data.get("comment", None)
self.instance.legal.process_type = process_type
self.instance.legal.registration_date = registration_date
self.instance.legal.binding_date = binding_date
self.instance.legal.laws.set(laws)
self.instance.legal.save()
self.instance.responsible.handler = handler
self.instance.responsible.registration_office = registration_office
self.instance.responsible.registration_file_number = registration_file_number
self.instance.responsible.conservation_office = conservation_office
self.instance.responsible.conservation_file_number = conservation_file_number
self.instance.responsible.save()
user_action = UserActionLogEntry.objects.create(
user=user,
timestamp=timezone.now(),
action=UserAction.EDITED,
)
geometry = geom_form.save(user_action)
self.instance.geometry = geometry
self.instance.geometry.save()
self.instance.log.add(user_action)
self.instance.identifier = identifier
self.instance.title = title
self.instance.comment = comment
self.instance.modified = user_action
self.instance.save()
return self.instance
class OpenInterventionForm(EditInterventionForm):
"""
This form is not intended to be used as data-input form. It's used to simplify the rendering of intervention:open
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Resize map
self.fields["geometry"].widget.attrs["map_width"] = 500
self.fields["geometry"].widget.attrs["map_height"] = 300
# Disable all form fields
for field in self.fields:
self.disable_form_field(field)
class DummyFilterInput(forms.HiddenInput):
""" A dummy input widget
Does not render anything. Can be used to keep filter logic using django_filter without having a pre defined
filter widget being rendered to the template.
"""
template_name = "konova/custom_widgets/dummy-filter-input.html"
class TextToClipboardInput(forms.TextInput):
template_name = "konova/custom_widgets/text-to-clipboard-input.html"
class ShareInterventionForm(BaseModalForm):
url = forms.CharField(
label=_("Share link"),
label_suffix="",
help_text=_("Send this link to users who you want to have writing access on the data"),
required=False,
widget=TextToClipboardInput(
attrs={
"readonly": True
}
)
)
users = forms.MultipleChoiceField(
label=_("Shared with"),
label_suffix="",
required=True,
help_text=_("Remove check to remove access for this user"),
widget=forms.CheckboxSelectMultiple(
attrs={
"class": "list-unstyled",
}
),
choices=[]
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form_title = _("Share")
self.form_caption = _("Share settings for {}").format(self.instance.identifier)
self.template = "modal/modal_form.html"
# Make sure an access_token is set
if self.instance.access_token is None:
self.instance.generate_access_token()
self._init_fields()
def _init_fields(self):
""" Wraps initializing of fields
Returns:
"""
# Initialize share_link field
self.share_link = self.request.build_absolute_uri(
reverse("intervention:share", args=(self.instance.id, self.instance.access_token,))
)
self.initialize_form_field(
"url",
self.share_link
)
# Initialize users field
# Remove field if user is not in registration or conservation group
if not in_group(self.request.user, ZB_GROUP) and not in_group(self.request.user, ETS_GROUP):
del self.fields["users"]
else:
users = self.instance.users.all()
choices = []
for n in users:
choices.append(
(n.id, n.username)
)
self.fields["users"].choices = choices
u_ids = list(users.values_list("id", flat=True))
self.initialize_form_field(
"users",
u_ids
)
def save(self):
accessing_users = User.objects.filter(
id__in=self.cleaned_data["users"]
)
self.instance.users.set(accessing_users)
class NewRevocationForm(BaseModalForm):
date = forms.DateField(
label=_("Date"),
label_suffix=_(""),
help_text=_("Date of revocation"),
widget=forms.DateInput(
attrs={
"type": "date",
"data-provide": "datepicker",
},
format="%d.%m.%Y"
)
)
file = forms.FileField(
label=_("Document"),
label_suffix=_(""),
required=False,
help_text=_("Must be smaller than 15 Mb"),
widget=forms.FileInput(
attrs={
"class": "w-75"
}
)
)
comment = forms.CharField(
required=False,
max_length=200,
label=_("Comment"),
label_suffix=_(""),
help_text=_("Additional comment, maximum {} letters").format(200),
widget=forms.Textarea(
attrs={
"cols": 30,
"rows": 5,
}
)
)
# Define w-100 for all form fields
full_width_fields = True
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form_title = _("Add revocation")
self.form_caption = ""
self.form_attrs = {
"enctype": "multipart/form-data", # important for file upload
}
def save(self):
with transaction.atomic():
created_action = UserActionLogEntry.objects.create(
user=self.user,
action=UserAction.CREATED
)
edited_action = UserActionLogEntry.objects.create(
user=self.user,
action=UserAction.EDITED
)
revocation = Revocation.objects.create(
date=self.cleaned_data["date"],
comment=self.cleaned_data["comment"],
created=created_action,
)
self.instance.modified = edited_action
self.instance.save()
self.instance.log.add(edited_action)
self.instance.legal.revocation = revocation
self.instance.legal.save()
if self.cleaned_data["file"]:
RevocationDocument.objects.create(
title="revocation_of_{}".format(self.instance.identifier),
date_of_creation=self.cleaned_data["date"],
comment=self.cleaned_data["comment"],
file=self.cleaned_data["file"],
instance=revocation
)
return revocation
class RunCheckForm(BaseModalForm):
checked_intervention = forms.BooleanField(
label=_("Checked intervention data"),
label_suffix="",
widget=forms.CheckboxInput(),
required=True,
)
checked_comps = forms.BooleanField(
label=_("Checked compensations data and payments"),
label_suffix="",
widget=forms.CheckboxInput(),
required=True
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form_title = _("Run check")
self.form_caption = _("I, {} {}, confirm that all necessary control steps have been performed by myself.").format(self.user.first_name, self.user.last_name)
def is_valid(self) -> bool:
""" Perform a validity check based on quality_check() logic
Returns:
result (bool)
"""
super_result = super().is_valid()
# Perform check
msgs = self.instance.quality_check()
for msg in msgs:
self.add_error(
"checked_intervention",
msg
)
return super_result and (len(msgs) == 0)
def save(self):
""" Saving logic
Returns:
"""
with transaction.atomic():
user_action = UserActionLogEntry.objects.create(
user=self.user,
action=UserAction.CHECKED
)
# Replace old checked
if self.instance.checked:
self.instance.checked.delete()
self.instance.checked = user_action
self.instance.log.add(user_action)
self.instance.save()
# Send message to the SSO server
messenger = Messenger(
self.instance.users.all(),
type="INFO",
)
messenger.send_object_checked(
self.instance.identifier,
self.user,
)
class NewDeductionForm(BaseModalForm):
""" Form for creating new deduction
Can be used for Intervention view as well as for EcoAccount views.
Parameter 'instance' can be an intervention, as well as an ecoAccount.
An instance check handles both workflows properly.
"""
account = forms.ModelChoiceField(
label=_("Eco-account"),
label_suffix="",
help_text=_("Only recorded accounts can be selected for deductions"),
queryset=EcoAccount.objects.filter(deleted=None),
widget=autocomplete.ModelSelect2(
url="accounts-autocomplete",
attrs={
"data-placeholder": _("Eco-account"),
"data-minimum-input-length": 3,
"readonly": True,
}
),
)
surface = forms.DecimalField(
min_value=0.00,
decimal_places=2,
label=_("Surface"),
label_suffix="",
help_text=_("in m²"),
)
intervention = forms.ModelChoiceField(
label=_("Intervention"),
label_suffix="",
help_text=_("Only shared interventions can be selected"),
queryset=Intervention.objects.filter(deleted=None),
widget=autocomplete.ModelSelect2(
url="interventions-autocomplete",
attrs={
"data-placeholder": _("Intervention"),
"data-minimum-input-length": 3,
}
),
)
# Define w-100 for all form fields
full_width_fields = True
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form_title = _("New Deduction")
self.form_caption = _("Enter the information for a new deduction from a chosen eco-account")
self.is_intervention_initially = False
# Add a placeholder for field 'surface' without having to define the whole widget above
self.add_placeholder_for_field("surface", "0,00")
# Check for Intervention or EcoAccount
if isinstance(self.instance, Intervention):
# Form has been called with a given intervention
self.initialize_form_field("intervention", self.instance)
self.disable_form_field("intervention")
self.is_intervention_initially = True
elif isinstance(self.instance, EcoAccount):
# Form has been called with a given account --> make it initial in the form and read-only
self.initialize_form_field("account", self.instance)
self.disable_form_field("account")
else:
raise NotImplementedError
def is_valid(self):
""" Custom validity check
Makes sure the deduction can not contain more surface than the account still provides
Returns:
is_valid (bool)
"""
super_result = super().is_valid()
if self.is_intervention_initially:
acc = self.cleaned_data["account"]
else:
acc = self.instance
if not acc.recorded:
self.add_error(
"account",
_("Eco-account {} is not recorded yet. You can only deduct from recorded accounts.").format(acc.identifier)
)
return False
# Calculate valid surface
sum_surface = acc.get_surface()
sum_surface_deductions = acc.get_deductions_surface()
rest_surface = sum_surface - sum_surface_deductions
form_surface = float(self.cleaned_data["surface"])
is_valid_surface = form_surface < rest_surface
if not is_valid_surface:
self.add_error(
"surface",
_("The account {} has not enough surface for a deduction of {} m². There are only {} m² left").format(
acc.identifier,
format_german_float(form_surface),
format_german_float(rest_surface),
),
)
return is_valid_surface and super_result
def save(self):
with transaction.atomic():
# Create log entry
user_action_edit = UserActionLogEntry.objects.create(
user=self.user,
action=UserAction.EDITED
)
user_action_create = UserActionLogEntry.objects.create(
user=self.user,
action=UserAction.CREATED
)
self.instance.log.add(user_action_edit)
self.instance.modified = user_action_edit
self.instance.save()
# Create deductions depending on Intervention or EcoAccount as the initial instance
if self.is_intervention_initially:
deduction = EcoAccountDeduction.objects.create(
intervention=self.instance,
account=self.cleaned_data["account"],
surface=self.cleaned_data["surface"],
created=user_action_create,
)
else:
deduction = EcoAccountDeduction.objects.create(
intervention=self.cleaned_data["intervention"],
account=self.instance,
surface=self.cleaned_data["surface"],
created=user_action_create,
)
return deduction

355
intervention/forms/forms.py Normal file
View File

@ -0,0 +1,355 @@
"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 02.12.20
"""
from dal import autocomplete
from django import forms
from django.contrib.auth.models import User
from django.db import transaction
from django.urls import reverse, reverse_lazy
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from codelist.models import KonovaCode
from codelist.settings import CODELIST_PROCESS_TYPE_ID, CODELIST_LAW_ID, \
CODELIST_REGISTRATION_OFFICE_ID, CODELIST_CONSERVATION_OFFICE_ID
from intervention.inputs import GenerateInput
from intervention.models import Intervention, LegalData, ResponsibilityData
from konova.forms import BaseForm, SimpleGeomForm
from user.models import UserActionLogEntry, UserAction
class NewInterventionForm(BaseForm):
identifier = forms.CharField(
label=_("Identifier"),
label_suffix="",
max_length=255,
help_text=_("Generated automatically"),
widget=GenerateInput(
attrs={
"class": "form-control",
"url": reverse_lazy("intervention:new-id"),
}
)
)
title = forms.CharField(
label=_("Title"),
label_suffix="",
help_text=_("An explanatory name"),
max_length=255,
widget=forms.TextInput(
attrs={
"placeholder": _("Construction XY; Location ABC"),
"class": "form-control",
}
)
)
type = forms.ModelChoiceField(
label=_("Process type"),
label_suffix="",
help_text=_(""),
required=False,
queryset=KonovaCode.objects.filter(
is_archived=False,
is_leaf=True,
code_lists__in=[CODELIST_PROCESS_TYPE_ID],
),
widget=autocomplete.ModelSelect2(
url="codes-process-type-autocomplete",
attrs={
}
),
)
laws = forms.ModelMultipleChoiceField(
label=_("Law"),
label_suffix="",
help_text=_("Multiple selection possible"),
required=False,
queryset=KonovaCode.objects.filter(
is_archived=False,
is_leaf=True,
code_lists__in=[CODELIST_LAW_ID],
),
widget=autocomplete.ModelSelect2Multiple(
url="codes-law-autocomplete",
attrs={
}
),
)
registration_office = forms.ModelChoiceField(
label=_("Registration office"),
label_suffix="",
required=False,
queryset=KonovaCode.objects.filter(
is_archived=False,
is_leaf=True,
code_lists__in=[CODELIST_REGISTRATION_OFFICE_ID],
),
widget=autocomplete.ModelSelect2(
url="codes-registration-office-autocomplete",
attrs={
}
),
)
conservation_office = forms.ModelChoiceField(
label=_("Conservation office"),
label_suffix="",
required=False,
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={
}
),
)
registration_file_number = forms.CharField(
label=_("Registration office file number"),
label_suffix="",
max_length=255,
required=False,
widget=forms.TextInput(
attrs={
"placeholder": _("ZB-123/ABC.456"),
"class": "form-control",
}
)
)
conservation_file_number = forms.CharField(
label=_("Conservation office file number"),
label_suffix="",
max_length=255,
required=False,
widget=forms.TextInput(
attrs={
"placeholder": _("ETS-123/ABC.456"),
"class": "form-control",
}
)
)
handler = forms.CharField(
label=_("Intervention handler"),
label_suffix="",
max_length=255,
required=False,
help_text=_("Who performs the intervention"),
widget=forms.TextInput(
attrs={
"placeholder": _("Company Mustermann"),
"class": "form-control",
}
)
)
registration_date = forms.DateField(
label=_("Registration date"),
label_suffix=_(""),
required=False,
widget=forms.DateInput(
attrs={
"type": "date",
"class": "form-control",
},
format="%d.%m.%Y"
)
)
binding_date = forms.DateField(
label=_("Binding on"),
label_suffix=_(""),
required=False,
widget=forms.DateInput(
attrs={
"type": "date",
"class": "form-control",
},
format="%d.%m.%Y"
)
)
comment = forms.CharField(
label_suffix="",
label=_("Comment"),
required=False,
help_text=_("Additional comment"),
widget=forms.Textarea(
attrs={
"rows": 5,
"class": "form-control"
}
)
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form_title = _("New intervention")
self.action_url = reverse("intervention:new")
self.cancel_redirect = reverse("intervention:index")
tmp_intervention = Intervention()
identifier = tmp_intervention._generate_new_identifier()
self.initialize_form_field("identifier", identifier)
def save(self, user: User, geom_form: SimpleGeomForm):
with transaction.atomic():
# Fetch data from cleaned POST values
identifier = self.cleaned_data.get("identifier", None)
title = self.cleaned_data.get("title", None)
_type = self.cleaned_data.get("type", None)
laws = self.cleaned_data.get("laws", None)
handler = self.cleaned_data.get("handler", None)
registration_office = self.cleaned_data.get("registration_office", None)
conservation_office = self.cleaned_data.get("conservation_office", None)
conservation_file_number = self.cleaned_data.get("conservation_file_number", None)
registration_file_number = self.cleaned_data.get("registration_file_number", None)
binding_date = self.cleaned_data.get("binding_date", None)
registration_date = self.cleaned_data.get("registration_date", None)
comment = self.cleaned_data.get("comment", None)
# Create log entry
action = UserActionLogEntry.objects.create(
user=user,
action=UserAction.CREATED,
)
# Create legal data object (without M2M laws first)
legal_data = LegalData.objects.create(
registration_date=registration_date,
binding_date=binding_date,
process_type=_type,
)
# Then add the M2M laws to the object
legal_data.laws.set(laws)
# Create responsible data object
responsibility_data = ResponsibilityData.objects.create(
registration_office=registration_office,
conservation_office=conservation_office,
registration_file_number=registration_file_number,
conservation_file_number=conservation_file_number,
handler=handler,
)
# Process the geometry form
geometry = geom_form.save(action)
# Finally create main object, holding the other objects
intervention = Intervention.objects.create(
identifier=identifier,
title=title,
responsible=responsibility_data,
legal=legal_data,
created=action,
geometry=geometry,
comment=comment,
)
# Add the log entry to the main objects log list
intervention.log.add(action)
# Add the performing user as the first user having access to the data
intervention.users.add(user)
return intervention
class EditInterventionForm(NewInterventionForm):
""" Subclasses NewInterventionForm
Simply adds initializing of a provided self.instance object into the form fields
"""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.instance is not None:
self.action_url = reverse("intervention:edit", args=(self.instance.id,))
self.cancel_redirect = reverse("intervention:open", args=(self.instance.id,))
self.form_title = _("Edit intervention")
self.form_caption = ""
reg_date = self.instance.legal.registration_date
bind_date = self.instance.legal.binding_date
if reg_date is not None:
reg_date = reg_date.isoformat()
if bind_date is not None:
bind_date = bind_date.isoformat()
# Initialize form data
form_data = {
"identifier": self.instance.identifier,
"title": self.instance.title,
"type": self.instance.legal.process_type,
"laws": list(self.instance.legal.laws.values_list("id", flat=True)),
"handler": self.instance.responsible.handler,
"registration_office": self.instance.responsible.registration_office,
"registration_file_number": self.instance.responsible.registration_file_number,
"conservation_office": self.instance.responsible.conservation_office,
"conservation_file_number": self.instance.responsible.conservation_file_number,
"registration_date": reg_date,
"binding_date": bind_date,
"comment": self.instance.comment,
}
disabled_fields = []
self.load_initial_data(
form_data,
disabled_fields
)
def save(self, user: User, geom_form: SimpleGeomForm):
""" Overwrite instance with new form data
Args:
user ():
Returns:
"""
with transaction.atomic():
identifier = self.cleaned_data.get("identifier", None)
title = self.cleaned_data.get("title", None)
process_type = self.cleaned_data.get("type", None)
laws = self.cleaned_data.get("laws", None)
handler = self.cleaned_data.get("handler", None)
registration_office = self.cleaned_data.get("registration_office", None)
registration_file_number = self.cleaned_data.get("registration_file_number", None)
conservation_office = self.cleaned_data.get("conservation_office", None)
conservation_file_number = self.cleaned_data.get("conservation_file_number", None)
registration_date = self.cleaned_data.get("registration_date", None)
binding_date = self.cleaned_data.get("binding_date", None)
comment = self.cleaned_data.get("comment", None)
self.instance.legal.process_type = process_type
self.instance.legal.registration_date = registration_date
self.instance.legal.binding_date = binding_date
self.instance.legal.laws.set(laws)
self.instance.legal.save()
self.instance.responsible.handler = handler
self.instance.responsible.registration_office = registration_office
self.instance.responsible.registration_file_number = registration_file_number
self.instance.responsible.conservation_office = conservation_office
self.instance.responsible.conservation_file_number = conservation_file_number
self.instance.responsible.save()
user_action = UserActionLogEntry.objects.create(
user=user,
timestamp=timezone.now(),
action=UserAction.EDITED,
)
geometry = geom_form.save(user_action)
self.instance.geometry = geometry
self.instance.geometry.save()
self.instance.log.add(user_action)
self.instance.identifier = identifier
self.instance.title = title
self.instance.comment = comment
self.instance.modified = user_action
self.instance.save()
return self.instance

View File

@ -0,0 +1,387 @@
"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 27.09.21
"""
from dal import autocomplete
from django.contrib.auth.models import User
from django.db import transaction
from django import forms
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from compensation.models import EcoAccount, EcoAccountDeduction
from intervention.inputs import TextToClipboardInput
from intervention.models import Revocation, RevocationDocument, Intervention
from konova.forms import BaseModalForm
from konova.settings import ZB_GROUP, ETS_GROUP
from konova.utils.general import format_german_float
from konova.utils.messenger import Messenger
from konova.utils.user_checks import in_group
from user.models import UserActionLogEntry, UserAction
class ShareInterventionModalForm(BaseModalForm):
url = forms.CharField(
label=_("Share link"),
label_suffix="",
help_text=_("Send this link to users who you want to have writing access on the data"),
required=False,
widget=TextToClipboardInput(
attrs={
"readonly": True,
"class": "form-control",
}
)
)
users = forms.MultipleChoiceField(
label=_("Shared with"),
label_suffix="",
required=True,
help_text=_("Remove check to remove access for this user"),
widget=forms.CheckboxSelectMultiple(
attrs={
"class": "list-unstyled",
}
),
choices=[]
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form_title = _("Share")
self.form_caption = _("Share settings for {}").format(self.instance.identifier)
self.template = "modal/modal_form.html"
# Make sure an access_token is set
if self.instance.access_token is None:
self.instance.generate_access_token()
self._init_fields()
def _init_fields(self):
""" Wraps initializing of fields
Returns:
"""
# Initialize share_link field
self.share_link = self.request.build_absolute_uri(
reverse("intervention:share", args=(self.instance.id, self.instance.access_token,))
)
self.initialize_form_field(
"url",
self.share_link
)
# Initialize users field
# Remove field if user is not in registration or conservation group
if not in_group(self.request.user, ZB_GROUP) and not in_group(self.request.user, ETS_GROUP):
del self.fields["users"]
else:
users = self.instance.users.all()
choices = []
for n in users:
choices.append(
(n.id, n.username)
)
self.fields["users"].choices = choices
u_ids = list(users.values_list("id", flat=True))
self.initialize_form_field(
"users",
u_ids
)
def save(self):
accessing_users = User.objects.filter(
id__in=self.cleaned_data["users"]
)
self.instance.users.set(accessing_users)
class NewRevocationModalForm(BaseModalForm):
date = forms.DateField(
label=_("Date"),
label_suffix=_(""),
help_text=_("Date of revocation"),
widget=forms.DateInput(
attrs={
"type": "date",
"data-provide": "datepicker",
"class": "form-control",
},
format="%d.%m.%Y"
)
)
file = forms.FileField(
label=_("Document"),
label_suffix=_(""),
required=False,
help_text=_("Must be smaller than 15 Mb"),
widget=forms.FileInput(
attrs={
"class": "form-control-file"
}
)
)
comment = forms.CharField(
required=False,
max_length=200,
label=_("Comment"),
label_suffix=_(""),
help_text=_("Additional comment, maximum {} letters").format(200),
widget=forms.Textarea(
attrs={
"cols": 30,
"rows": 5,
"class": "form-control",
}
)
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form_title = _("Add revocation")
self.form_caption = ""
self.form_attrs = {
"enctype": "multipart/form-data", # important for file upload
}
def save(self):
with transaction.atomic():
created_action = UserActionLogEntry.objects.create(
user=self.user,
action=UserAction.CREATED
)
edited_action = UserActionLogEntry.objects.create(
user=self.user,
action=UserAction.EDITED
)
revocation = Revocation.objects.create(
date=self.cleaned_data["date"],
comment=self.cleaned_data["comment"],
created=created_action,
)
self.instance.modified = edited_action
self.instance.save()
self.instance.log.add(edited_action)
self.instance.legal.revocation = revocation
self.instance.legal.save()
if self.cleaned_data["file"]:
RevocationDocument.objects.create(
title="revocation_of_{}".format(self.instance.identifier),
date_of_creation=self.cleaned_data["date"],
comment=self.cleaned_data["comment"],
file=self.cleaned_data["file"],
instance=revocation
)
return revocation
class RunCheckModalForm(BaseModalForm):
checked_intervention = forms.BooleanField(
label=_("Checked intervention data"),
label_suffix="",
widget=forms.CheckboxInput(),
required=True,
)
checked_comps = forms.BooleanField(
label=_("Checked compensations data and payments"),
label_suffix="",
widget=forms.CheckboxInput(),
required=True
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form_title = _("Run check")
self.form_caption = _("I, {} {}, confirm that all necessary control steps have been performed by myself.").format(self.user.first_name, self.user.last_name)
def is_valid(self) -> bool:
""" Perform a validity check based on quality_check() logic
Returns:
result (bool)
"""
super_result = super().is_valid()
# Perform check
msgs = self.instance.quality_check()
for msg in msgs:
self.add_error(
"checked_intervention",
msg
)
return super_result and (len(msgs) == 0)
def save(self):
""" Saving logic
Returns:
"""
with transaction.atomic():
user_action = UserActionLogEntry.objects.create(
user=self.user,
action=UserAction.CHECKED
)
# Replace old checked
if self.instance.checked:
self.instance.checked.delete()
self.instance.checked = user_action
self.instance.log.add(user_action)
self.instance.save()
# Send message to the SSO server
messenger = Messenger(
self.instance.users.all(),
type="INFO",
)
messenger.send_object_checked(
self.instance.identifier,
self.user,
)
class NewDeductionModalForm(BaseModalForm):
""" Form for creating new deduction
Can be used for Intervention view as well as for EcoAccount views.
Parameter 'instance' can be an intervention, as well as an ecoAccount.
An instance check handles both workflows properly.
"""
account = forms.ModelChoiceField(
label=_("Eco-account"),
label_suffix="",
help_text=_("Only recorded accounts can be selected for deductions"),
queryset=EcoAccount.objects.filter(deleted=None),
widget=autocomplete.ModelSelect2(
url="accounts-autocomplete",
attrs={
"data-placeholder": _("Eco-account"),
"data-minimum-input-length": 3,
"readonly": True,
}
),
)
surface = forms.DecimalField(
min_value=0.00,
decimal_places=2,
label=_("Surface"),
label_suffix="",
help_text=_("in m²"),
widget=forms.NumberInput(
attrs={
"class": "form-control",
}
)
)
intervention = forms.ModelChoiceField(
label=_("Intervention"),
label_suffix="",
help_text=_("Only shared interventions can be selected"),
queryset=Intervention.objects.filter(deleted=None),
widget=autocomplete.ModelSelect2(
url="interventions-autocomplete",
attrs={
"data-placeholder": _("Intervention"),
"data-minimum-input-length": 3,
}
),
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.form_title = _("New Deduction")
self.form_caption = _("Enter the information for a new deduction from a chosen eco-account")
self.is_intervention_initially = False
# Add a placeholder for field 'surface' without having to define the whole widget above
self.add_placeholder_for_field("surface", "0,00")
# Check for Intervention or EcoAccount
if isinstance(self.instance, Intervention):
# Form has been called with a given intervention
self.initialize_form_field("intervention", self.instance)
self.disable_form_field("intervention")
self.is_intervention_initially = True
elif isinstance(self.instance, EcoAccount):
# Form has been called with a given account --> make it initial in the form and read-only
self.initialize_form_field("account", self.instance)
self.disable_form_field("account")
else:
raise NotImplementedError
def is_valid(self):
""" Custom validity check
Makes sure the deduction can not contain more surface than the account still provides
Returns:
is_valid (bool)
"""
super_result = super().is_valid()
if self.is_intervention_initially:
acc = self.cleaned_data["account"]
else:
acc = self.instance
if not acc.recorded:
self.add_error(
"account",
_("Eco-account {} is not recorded yet. You can only deduct from recorded accounts.").format(acc.identifier)
)
return False
# Calculate valid surface
sum_surface = acc.get_surface()
sum_surface_deductions = acc.get_deductions_surface()
rest_surface = sum_surface - sum_surface_deductions
form_surface = float(self.cleaned_data["surface"])
is_valid_surface = form_surface < rest_surface
if not is_valid_surface:
self.add_error(
"surface",
_("The account {} has not enough surface for a deduction of {} m². There are only {} m² left").format(
acc.identifier,
format_german_float(form_surface),
format_german_float(rest_surface),
),
)
return is_valid_surface and super_result
def save(self):
with transaction.atomic():
# Create log entry
user_action_edit = UserActionLogEntry.objects.create(
user=self.user,
action=UserAction.EDITED
)
user_action_create = UserActionLogEntry.objects.create(
user=self.user,
action=UserAction.CREATED
)
self.instance.log.add(user_action_edit)
self.instance.modified = user_action_edit
self.instance.save()
# Create deductions depending on Intervention or EcoAccount as the initial instance
if self.is_intervention_initially:
deduction = EcoAccountDeduction.objects.create(
intervention=self.instance,
account=self.cleaned_data["account"],
surface=self.cleaned_data["surface"],
created=user_action_create,
)
else:
deduction = EcoAccountDeduction.objects.create(
intervention=self.cleaned_data["intervention"],
account=self.instance,
surface=self.cleaned_data["surface"],
created=user_action_create,
)
return deduction

32
intervention/inputs.py Normal file
View File

@ -0,0 +1,32 @@
from django import forms
class DummyFilterInput(forms.HiddenInput):
""" A dummy input widget
Does not render anything. Can be used to keep filter logic using django_filter without having a pre defined
filter widget being rendered to the template.
"""
template_name = "konova/custom_widgets/dummy-filter-input.html"
class TextToClipboardInput(forms.TextInput):
template_name = "konova/custom_widgets/text-to-clipboard-input.html"
class GenerateInput(forms.TextInput):
"""
Provides a form group with a button at the end, which generates new content for the input.
The url used to fetch new content can be added using the attrs like
widget=GenerateInput(
attrs={
"url": reverse_lazy("app_name:view_name")
...
}
)
"""
template_name = "konova/custom_widgets/generate-content-input.html"

View File

@ -9,12 +9,13 @@ from django.urls import path
from intervention.views import index_view, new_view, open_view, edit_view, remove_view, new_document_view, share_view, \ from intervention.views import index_view, new_view, open_view, edit_view, remove_view, new_document_view, share_view, \
create_share_view, remove_revocation_view, new_revocation_view, run_check_view, log_view, new_deduction_view, \ create_share_view, remove_revocation_view, new_revocation_view, run_check_view, log_view, new_deduction_view, \
record_view, remove_document_view, get_document_view, get_revocation_view record_view, remove_document_view, get_document_view, get_revocation_view, new_id_view
app_name = "intervention" app_name = "intervention"
urlpatterns = [ urlpatterns = [
path("", index_view, name="index"), path("", index_view, name="index"),
path('new/', new_view, name='new'), path('new/', new_view, name='new'),
path('new/id', new_id_view, name='new-id'),
path('<id>', open_view, name='open'), path('<id>', open_view, name='open'),
path('<id>/log', log_view, name='log'), path('<id>/log', log_view, name='log'),
path('<id>/edit', edit_view, name='edit'), path('<id>/edit', edit_view, name='edit'),

View File

@ -1,11 +1,11 @@
from django.contrib import messages
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.http import HttpRequest from django.http import HttpRequest, JsonResponse
from django.shortcuts import render, get_object_or_404 from django.shortcuts import render, get_object_or_404
from intervention.forms import NewInterventionForm, EditInterventionForm, ShareInterventionForm, NewRevocationForm, \ from intervention.forms.forms import NewInterventionForm, EditInterventionForm
RunCheckForm, NewDeductionForm from intervention.forms.modalForms import ShareInterventionModalForm, NewRevocationModalForm, \
RunCheckModalForm, NewDeductionModalForm
from intervention.models import Intervention, Revocation, InterventionDocument, RevocationDocument from intervention.models import Intervention, Revocation, InterventionDocument, RevocationDocument
from intervention.tables import InterventionTable from intervention.tables import InterventionTable
from konova.contexts import BaseContext from konova.contexts import BaseContext
@ -13,7 +13,7 @@ from konova.decorators import *
from konova.forms import SimpleGeomForm, NewDocumentForm, RemoveModalForm, RecordModalForm from konova.forms import SimpleGeomForm, NewDocumentForm, RemoveModalForm, RecordModalForm
from konova.sub_settings.django_settings import DEFAULT_DATE_FORMAT from konova.sub_settings.django_settings import DEFAULT_DATE_FORMAT
from konova.utils.documents import remove_document, get_document from konova.utils.documents import remove_document, get_document
from konova.utils.message_templates import FORM_INVALID, INTERVENTION_INVALID from konova.utils.message_templates import INTERVENTION_INVALID
from konova.utils.user_checks import in_group from konova.utils.user_checks import in_group
@ -68,7 +68,10 @@ def new_view(request: HttpRequest):
if generated_identifier != intervention.identifier: if generated_identifier != intervention.identifier:
messages.info( messages.info(
request, request,
_("The identifier '{}' had to be changed to '{}' since another entry has been added in the meanwhile, which uses this identifier") _("The identifier '{}' had to be changed to '{}' since another entry has been added in the meanwhile, which uses this identifier").format(
generated_identifier,
intervention.identifier
)
) )
messages.success(request, _("Intervention {} added").format(intervention.identifier)) messages.success(request, _("Intervention {} added").format(intervention.identifier))
return redirect("intervention:index") return redirect("intervention:index")
@ -80,11 +83,30 @@ def new_view(request: HttpRequest):
context = { context = {
"data_form": data_form, "data_form": data_form,
"geom_form": geom_form, "geom_form": geom_form,
"url": reverse("intervention:new-id")
} }
context = BaseContext(request, context).context context = BaseContext(request, context).context
return render(request, template, context) return render(request, template, context)
@login_required
def new_id_view(request: HttpRequest):
""" JSON endpoint
Provides fetching of free identifiers for e.g. AJAX calls
"""
tmp_intervention = Intervention()
identifier = tmp_intervention._generate_new_identifier()
while Intervention.objects.filter(identifier=identifier).exists():
identifier = tmp_intervention._generate_new_identifier()
return JsonResponse(
data={
"identifier": identifier
}
)
@login_required @login_required
def new_document_view(request: HttpRequest, id: str): def new_document_view(request: HttpRequest, id: str):
""" Renders a form for uploading new documents """ Renders a form for uploading new documents
@ -221,20 +243,17 @@ def edit_view(request: HttpRequest, id: str):
""" """
template = "intervention/new/view.html" template = "intervention/new/view.html"
# Get object from db
intervention = get_object_or_404(Intervention, id=id) intervention = get_object_or_404(Intervention, id=id)
# Create forms, initialize with values from db/from POST request
data_form = EditInterventionForm(request.POST or None, instance=intervention) data_form = EditInterventionForm(request.POST or None, instance=intervention)
geom_form = SimpleGeomForm(request.POST or None, read_only=False, instance=intervention) geom_form = SimpleGeomForm(request.POST or None, read_only=False, instance=intervention)
if request.method == "POST": if request.method == "POST":
if data_form.is_valid() and geom_form.is_valid(): if data_form.is_valid() and geom_form.is_valid():
generated_identifier = data_form.cleaned_data.get("identifier", None) # The data form takes the geom form for processing, as well as the performing user
intervention = data_form.save(request.user, geom_form) intervention = data_form.save(request.user, geom_form)
if generated_identifier != intervention.identifier: messages.success(request, _("Intervention {} edited").format(intervention.identifier))
messages.info( return redirect("intervention:open", id=intervention.id)
request,
_("The identifier '{}' had to be changed to '{}' since another entry has been added in the meanwhile, which uses this identifier")
)
messages.success(request, _("Intervention {} added").format(intervention.identifier))
return redirect("intervention:index")
else: else:
messages.error(request, _("Invalid input")) messages.error(request, _("Invalid input"))
else: else:
@ -342,7 +361,7 @@ def create_share_view(request: HttpRequest, id: str):
""" """
intervention = get_object_or_404(Intervention, id=id) intervention = get_object_or_404(Intervention, id=id)
form = ShareInterventionForm(request.POST or None, instance=intervention, request=request) form = ShareInterventionModalForm(request.POST or None, instance=intervention, request=request)
return form.process_request( return form.process_request(
request, request,
msg_success=_("Share settings updated") msg_success=_("Share settings updated")
@ -361,7 +380,7 @@ def run_check_view(request: HttpRequest, id: str):
""" """
intervention = get_object_or_404(Intervention, id=id) intervention = get_object_or_404(Intervention, id=id)
form = RunCheckForm(request.POST or None, instance=intervention, user=request.user) form = RunCheckModalForm(request.POST or None, instance=intervention, user=request.user)
return form.process_request( return form.process_request(
request, request,
msg_success=_("Check performed"), msg_success=_("Check performed"),
@ -381,7 +400,7 @@ def new_revocation_view(request: HttpRequest, id: str):
""" """
intervention = get_object_or_404(Intervention, id=id) intervention = get_object_or_404(Intervention, id=id)
form = NewRevocationForm(request.POST or None, request.FILES or None, instance=intervention, user=request.user) form = NewRevocationModalForm(request.POST or None, request.FILES or None, instance=intervention, user=request.user)
return form.process_request( return form.process_request(
request, request,
msg_success=_("Revocation added") msg_success=_("Revocation added")
@ -425,7 +444,7 @@ def new_deduction_view(request: HttpRequest, id: str):
""" """
intervention = get_object_or_404(Intervention, id=id) intervention = get_object_or_404(Intervention, id=id)
form = NewDeductionForm(request.POST or None, instance=intervention, user=request.user) form = NewDeductionModalForm(request.POST or None, instance=intervention, user=request.user)
return form.process_request( return form.process_request(
request, request,
msg_success=_("Deduction added") msg_success=_("Deduction added")

View File

@ -43,7 +43,6 @@ class BaseForm(forms.Form):
instance = None # The data holding model object instance = None # The data holding model object
form_attrs = {} # Holds additional attributes, that can be used in the template form_attrs = {} # Holds additional attributes, that can be used in the template
has_required_fields = False # Automatically set. Triggers hint rendering in templates has_required_fields = False # Automatically set. Triggers hint rendering in templates
full_width_fields = False # w-100 for all input fields
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.instance = kwargs.pop("instance", None) self.instance = kwargs.pop("instance", None)
@ -56,11 +55,6 @@ class BaseForm(forms.Form):
self.has_required_fields = True self.has_required_fields = True
break break
if self.full_width_fields:
# Automatically add bootstrap w-100 class for maximum width of form fields in modals
for key, val in self.fields.items():
self.add_widget_html_class(key, "w-100")
@abstractmethod @abstractmethod
def save(self): def save(self):
# To be implemented in subclasses! # To be implemented in subclasses!
@ -276,9 +270,9 @@ class SimpleGeomForm(BaseForm):
geom = Polygon.from_bbox([0, 0, 0, 0]) geom = Polygon.from_bbox([0, 0, 0, 0])
# Zoom out to a very high level, so the user can see directly that there is no geometry for this entry # Zoom out to a very high level, so the user can see directly that there is no geometry for this entry
self.fields["geom"].widget.attrs["default_zoom"] = 1 self.fields["geom"].widget.attrs["default_zoom"] = 1
self.initialize_form_field("geom", geom)
self.area = geom.area
if read_only: if read_only:
self.initialize_form_field("geom", geom)
self.area = geom.area
self.fields["geom"].disabled = True self.fields["geom"].disabled = True
def save(self, action: UserActionLogEntry): def save(self, action: UserActionLogEntry):
@ -326,6 +320,11 @@ class NewDocumentForm(BaseModalForm):
label=_("Title"), label=_("Title"),
label_suffix=_(""), label_suffix=_(""),
max_length=500, max_length=500,
widget=forms.TextInput(
attrs={
"class": "form-control",
}
)
) )
creation_date = forms.DateField( creation_date = forms.DateField(
label=_("Created on"), label=_("Created on"),
@ -335,6 +334,7 @@ class NewDocumentForm(BaseModalForm):
attrs={ attrs={
"type": "date", "type": "date",
"data-provide": "datepicker", "data-provide": "datepicker",
"class": "form-control",
}, },
format="%d.%m.%Y" format="%d.%m.%Y"
) )
@ -345,7 +345,7 @@ class NewDocumentForm(BaseModalForm):
help_text=_("Must be smaller than 15 Mb"), help_text=_("Must be smaller than 15 Mb"),
widget=forms.FileInput( widget=forms.FileInput(
attrs={ attrs={
"class": "w-75" "class": "form-control-file",
} }
), ),
) )
@ -359,6 +359,7 @@ class NewDocumentForm(BaseModalForm):
attrs={ attrs={
"cols": 30, "cols": 30,
"rows": 5, "rows": 5,
"class": "form-control",
} }
) )
) )
@ -370,9 +371,6 @@ class NewDocumentForm(BaseModalForm):
Ema: EmaDocument, Ema: EmaDocument,
} }
# Define w-100 for all form fields
full_width_fields = True
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.form_title = _("Add new document") self.form_title = _("Add new document")

View File

@ -60,13 +60,7 @@ a {
color: var(--rlp-red); color: var(--rlp-red);
} }
input[type=text], input[type=date] { .form-control:focus{
border: 1px solid gray;
border-radius: 0.2rem;
padding: 0.3rem 0.5rem;
}
input:focus, textarea:focus, select:focus{
outline: none; outline: none;
border-color: var(--rlp-red); border-color: var(--rlp-red);
box-shadow: 0 0 3px var(--rlp-red); box-shadow: 0 0 3px var(--rlp-red);

View File

@ -0,0 +1,22 @@
{% load i18n fontawesome_5 %}
<div class="input-group w-100" title="{{ widget.value|stringformat:'s' }}">
<input id="gen-id-input" aria-describedby="gen-id-btn" type="{{ widget.type }}" name="{{ widget.name }}"{% if widget.value != None %} value="{{ widget.value|stringformat:'s' }}"{% endif %}{% include "django/forms/widgets/attrs.html" %}>
<div class="input-group-append" onclick="fetchNewIdentifier()">
<span id="gen-id-btn" class="btn btn-default" value="{% trans 'Generate new' %}" title="{% trans 'Generate new' %}">{% fa5_icon 'dice' %}</span>
</div>
</div>
<script>
function fetchNewIdentifier() {
fetch("{{ widget.attrs.url }}")
.then(function(response){
return response.json();
})
.then(function(data){
document.getElementById("gen-id-input").value = data["identifier"];
})
.catch(function(error){
console.log(error);
});
}
</script>

Binary file not shown.

View File

@ -3,21 +3,22 @@
# This file is distributed under the same license as the PACKAGE package. # This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
# #
#: compensation/filters.py:71 compensation/forms.py:47 compensation/forms.py:52 #: compensation/filters.py:71 compensation/forms.py:47 compensation/forms.py:57
#: compensation/forms.py:67 compensation/forms.py:264 compensation/forms.py:345 #: compensation/forms.py:73 compensation/forms.py:276 compensation/forms.py:363
#: intervention/filters.py:26 intervention/filters.py:40 #: intervention/filters.py:26 intervention/filters.py:40
#: intervention/filters.py:47 intervention/filters.py:48 #: intervention/filters.py:47 intervention/filters.py:48
#: intervention/forms.py:56 intervention/forms.py:151 intervention/forms.py:162 #: intervention/forms/forms.py:53 intervention/forms/forms.py:151
#: intervention/forms.py:422 intervention/forms.py:434 #: intervention/forms/forms.py:163 intervention/forms/modalForms.py:107
#: intervention/forms.py:447 konova/forms.py:140 konova/forms.py:250 #: intervention/forms/modalForms.py:120 intervention/forms/modalForms.py:133
#: konova/forms.py:296 konova/forms.py:331 konova/forms.py:336 #: konova/forms.py:140 konova/forms.py:244 konova/forms.py:294
#: konova/forms.py:348 konova/forms.py:360 konova/forms.py:380 user/forms.py:38 #: konova/forms.py:321 konova/forms.py:331 konova/forms.py:344
#: konova/forms.py:356 konova/forms.py:377 user/forms.py:38
#, fuzzy #, fuzzy
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-09-23 12:46+0200\n" "POT-Creation-Date: 2021-09-27 13:56+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -35,16 +36,16 @@ msgstr "Nur unverzeichnete anzeigen"
msgid "in Euro" msgid "in Euro"
msgstr "in Euro" msgstr "in Euro"
#: compensation/forms.py:51 #: compensation/forms.py:56
#: intervention/templates/intervention/detail/includes/payments.html:31 #: intervention/templates/intervention/detail/includes/payments.html:31
msgid "Due on" msgid "Due on"
msgstr "Fällig am" msgstr "Fällig am"
#: compensation/forms.py:54 #: compensation/forms.py:59
msgid "Due on which date" msgid "Due on which date"
msgstr "Zahlung wird an diesem Datum erwartet" msgstr "Zahlung wird an diesem Datum erwartet"
#: compensation/forms.py:66 compensation/forms.py:263 compensation/forms.py:344 #: compensation/forms.py:72 compensation/forms.py:275 compensation/forms.py:362
#: compensation/templates/compensation/detail/compensation/includes/actions.html:34 #: compensation/templates/compensation/detail/compensation/includes/actions.html:34
#: compensation/templates/compensation/detail/compensation/includes/deadlines.html:34 #: compensation/templates/compensation/detail/compensation/includes/deadlines.html:34
#: compensation/templates/compensation/detail/compensation/includes/documents.html:31 #: compensation/templates/compensation/detail/compensation/includes/documents.html:31
@ -54,115 +55,115 @@ msgstr "Zahlung wird an diesem Datum erwartet"
#: ema/templates/ema/detail/includes/actions.html:34 #: ema/templates/ema/detail/includes/actions.html:34
#: ema/templates/ema/detail/includes/deadlines.html:34 #: ema/templates/ema/detail/includes/deadlines.html:34
#: ema/templates/ema/detail/includes/documents.html:31 #: ema/templates/ema/detail/includes/documents.html:31
#: intervention/forms.py:446 #: intervention/forms/forms.py:175 intervention/forms/modalForms.py:132
#: intervention/templates/intervention/detail/includes/documents.html:31 #: intervention/templates/intervention/detail/includes/documents.html:31
#: intervention/templates/intervention/detail/includes/payments.html:34 #: intervention/templates/intervention/detail/includes/payments.html:34
#: intervention/templates/intervention/detail/includes/revocation.html:38 #: intervention/templates/intervention/detail/includes/revocation.html:38
#: konova/forms.py:359 #: konova/forms.py:355
msgid "Comment" msgid "Comment"
msgstr "Kommentar" msgstr "Kommentar"
#: compensation/forms.py:68 compensation/forms.py:265 compensation/forms.py:346 #: compensation/forms.py:74 compensation/forms.py:277 compensation/forms.py:364
#: intervention/forms.py:448 konova/forms.py:361 #: intervention/forms/modalForms.py:134 konova/forms.py:357
msgid "Additional comment, maximum {} letters" msgid "Additional comment, maximum {} letters"
msgstr "Zusätzlicher Kommentar, maximal {} Zeichen" msgstr "Zusätzlicher Kommentar, maximal {} Zeichen"
#: compensation/forms.py:80 #: compensation/forms.py:86
msgid "Payment" msgid "Payment"
msgstr "Zahlung" msgstr "Zahlung"
#: compensation/forms.py:81 #: compensation/forms.py:87
msgid "Add a payment for intervention '{}'" msgid "Add a payment for intervention '{}'"
msgstr "Neue Ersatzzahlung zu Eingriff '{}' hinzufügen" msgstr "Neue Ersatzzahlung zu Eingriff '{}' hinzufügen"
#: compensation/forms.py:102 #: compensation/forms.py:108
msgid "If there is no date you can enter, please explain why." msgid "If there is no date you can enter, please explain why."
msgstr "Falls Sie kein Datum angeben können, erklären Sie bitte weshalb." msgstr "Falls Sie kein Datum angeben können, erklären Sie bitte weshalb."
#: compensation/forms.py:116 #: compensation/forms.py:122
msgid "Added payment" msgid "Added payment"
msgstr "Zahlung hinzufügen" msgstr "Zahlung hinzufügen"
#: compensation/forms.py:133 compensation/forms.py:145 #: compensation/forms.py:139 compensation/forms.py:151
msgid "Biotope Type" msgid "Biotope Type"
msgstr "Biotoptyp" msgstr "Biotoptyp"
#: compensation/forms.py:136 #: compensation/forms.py:142
msgid "Select the biotope type" msgid "Select the biotope type"
msgstr "Biotoptyp wählen" msgstr "Biotoptyp wählen"
#: compensation/forms.py:152 #: compensation/forms.py:158
#: compensation/templates/compensation/detail/compensation/includes/states-after.html:36 #: compensation/templates/compensation/detail/compensation/includes/states-after.html:36
#: compensation/templates/compensation/detail/compensation/includes/states-before.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-after.html:36
#: compensation/templates/compensation/detail/eco_account/includes/states-before.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-after.html:36
#: ema/templates/ema/detail/includes/states-before.html:36 #: ema/templates/ema/detail/includes/states-before.html:36
#: intervention/forms.py:587 #: intervention/forms/modalForms.py:274
msgid "Surface" msgid "Surface"
msgstr "Fläche" msgstr "Fläche"
#: compensation/forms.py:155 intervention/forms.py:589 #: compensation/forms.py:161 intervention/forms/modalForms.py:276
msgid "in m²" msgid "in m²"
msgstr "" msgstr ""
#: compensation/forms.py:160 #: compensation/forms.py:171
msgid "New state" msgid "New state"
msgstr "Neuer Zustand" msgstr "Neuer Zustand"
#: compensation/forms.py:161 #: compensation/forms.py:172
msgid "Insert data for the new state" msgid "Insert data for the new state"
msgstr "Geben Sie die Daten des neuen Zustandes ein" msgstr "Geben Sie die Daten des neuen Zustandes ein"
#: compensation/forms.py:169 #: compensation/forms.py:180
msgid "Added state" msgid "Added state"
msgstr "Zustand hinzugefügt" msgstr "Zustand hinzugefügt"
#: compensation/forms.py:185 konova/forms.py:199 #: compensation/forms.py:196 konova/forms.py:193
msgid "Object removed" msgid "Object removed"
msgstr "Objekt entfernt" msgstr "Objekt entfernt"
#: compensation/forms.py:236 #: compensation/forms.py:247
msgid "Deadline Type" msgid "Deadline Type"
msgstr "Fristart" msgstr "Fristart"
#: compensation/forms.py:239 #: compensation/forms.py:250
msgid "Select the deadline type" msgid "Select the deadline type"
msgstr "Fristart wählen" msgstr "Fristart wählen"
#: compensation/forms.py:248 #: compensation/forms.py:259
#: compensation/templates/compensation/detail/compensation/includes/deadlines.html:31 #: compensation/templates/compensation/detail/compensation/includes/deadlines.html:31
#: compensation/templates/compensation/detail/eco_account/includes/deadlines.html:31 #: compensation/templates/compensation/detail/eco_account/includes/deadlines.html:31
#: ema/templates/ema/detail/includes/deadlines.html:31 #: ema/templates/ema/detail/includes/deadlines.html:31
#: intervention/forms.py:421 #: intervention/forms/modalForms.py:106
msgid "Date" msgid "Date"
msgstr "Datum" msgstr "Datum"
#: compensation/forms.py:251 #: compensation/forms.py:262
msgid "Select date" msgid "Select date"
msgstr "Datum wählen" msgstr "Datum wählen"
#: compensation/forms.py:276 #: compensation/forms.py:289
msgid "New deadline" msgid "New deadline"
msgstr "Neue Frist" msgstr "Neue Frist"
#: compensation/forms.py:277 #: compensation/forms.py:290
msgid "Insert data for the new deadline" msgid "Insert data for the new deadline"
msgstr "Geben Sie die Daten der neuen Frist ein" msgstr "Geben Sie die Daten der neuen Frist ein"
#: compensation/forms.py:294 #: compensation/forms.py:307
msgid "Added deadline" msgid "Added deadline"
msgstr "Frist/Termin hinzugefügt" msgstr "Frist/Termin hinzugefügt"
#: compensation/forms.py:305 #: compensation/forms.py:318
msgid "Action Type" msgid "Action Type"
msgstr "Maßnahmentyp" msgstr "Maßnahmentyp"
#: compensation/forms.py:308 #: compensation/forms.py:321
msgid "Select the action type" msgid "Select the action type"
msgstr "Maßnahmentyp wählen" msgstr "Maßnahmentyp wählen"
#: compensation/forms.py:317 #: compensation/forms.py:330
#: compensation/templates/compensation/detail/compensation/includes/actions.html:37 #: compensation/templates/compensation/detail/compensation/includes/actions.html:37
#: compensation/templates/compensation/detail/compensation/includes/deadlines.html:37 #: compensation/templates/compensation/detail/compensation/includes/deadlines.html:37
#: compensation/templates/compensation/detail/compensation/includes/documents.html:34 #: compensation/templates/compensation/detail/compensation/includes/documents.html:34
@ -188,33 +189,33 @@ msgstr "Maßnahmentyp wählen"
msgid "Action" msgid "Action"
msgstr "Aktionen" msgstr "Aktionen"
#: compensation/forms.py:322 #: compensation/forms.py:335
msgid "Unit" msgid "Unit"
msgstr "Einheit" msgstr "Einheit"
#: compensation/forms.py:325 #: compensation/forms.py:338
msgid "Select the unit" msgid "Select the unit"
msgstr "Einheit wählen" msgstr "Einheit wählen"
#: compensation/forms.py:334 #: compensation/forms.py:347
#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:34 #: compensation/templates/compensation/detail/eco_account/includes/deductions.html:34
#: intervention/templates/intervention/detail/includes/deductions.html:31 #: intervention/templates/intervention/detail/includes/deductions.html:31
msgid "Amount" msgid "Amount"
msgstr "Menge" msgstr "Menge"
#: compensation/forms.py:337 #: compensation/forms.py:350
msgid "Insert the amount" msgid "Insert the amount"
msgstr "Menge eingeben" msgstr "Menge eingeben"
#: compensation/forms.py:357 #: compensation/forms.py:375
msgid "New action" msgid "New action"
msgstr "Neue Maßnahme" msgstr "Neue Maßnahme"
#: compensation/forms.py:358 #: compensation/forms.py:376
msgid "Insert data for the new action" msgid "Insert data for the new action"
msgstr "Geben Sie die Daten der neuen Maßnahme ein" msgstr "Geben Sie die Daten der neuen Maßnahme ein"
#: compensation/forms.py:377 #: compensation/forms.py:395
msgid "Added action" msgid "Added action"
msgstr "Maßnahme hinzugefügt" msgstr "Maßnahme hinzugefügt"
@ -257,34 +258,34 @@ msgstr ""
"Es wurde bereits mehr Fläche abgebucht, als Sie nun als abbuchbar einstellen " "Es wurde bereits mehr Fläche abgebucht, als Sie nun als abbuchbar einstellen "
"wollen. Kontaktieren Sie die für die Abbuchungen verantwortlichen Nutzer!" "wollen. Kontaktieren Sie die für die Abbuchungen verantwortlichen Nutzer!"
#: compensation/tables.py:24 compensation/tables.py:164 ema/tables.py:28 #: compensation/tables.py:25 compensation/tables.py:167 ema/tables.py:28
#: intervention/forms.py:37 intervention/tables.py:23 #: intervention/forms/forms.py:27 intervention/tables.py:23
#: intervention/templates/intervention/detail/includes/compensations.html:30 #: intervention/templates/intervention/detail/includes/compensations.html:30
msgid "Identifier" msgid "Identifier"
msgstr "Kennung" msgstr "Kennung"
#: compensation/tables.py:29 compensation/tables.py:169 #: compensation/tables.py:30 compensation/tables.py:172
#: compensation/templates/compensation/detail/compensation/includes/documents.html:28 #: compensation/templates/compensation/detail/compensation/includes/documents.html:28
#: compensation/templates/compensation/detail/compensation/view.html:31 #: compensation/templates/compensation/detail/compensation/view.html:31
#: compensation/templates/compensation/detail/eco_account/includes/documents.html:28 #: compensation/templates/compensation/detail/eco_account/includes/documents.html:28
#: compensation/templates/compensation/detail/eco_account/view.html:31 #: compensation/templates/compensation/detail/eco_account/view.html:31
#: ema/tables.py:33 ema/templates/ema/detail/includes/documents.html:28 #: ema/tables.py:33 ema/templates/ema/detail/includes/documents.html:28
#: ema/templates/ema/detail/view.html:24 intervention/forms.py:43 #: ema/templates/ema/detail/view.html:24 intervention/forms/forms.py:39
#: intervention/tables.py:28 #: intervention/tables.py:28
#: intervention/templates/intervention/detail/includes/compensations.html:33 #: intervention/templates/intervention/detail/includes/compensations.html:33
#: intervention/templates/intervention/detail/includes/documents.html:28 #: intervention/templates/intervention/detail/includes/documents.html:28
#: intervention/templates/intervention/detail/view.html:31 konova/forms.py:330 #: intervention/templates/intervention/detail/view.html:31 konova/forms.py:320
msgid "Title" msgid "Title"
msgstr "Bezeichnung" msgstr "Bezeichnung"
#: compensation/tables.py:34 #: compensation/tables.py:35
#: compensation/templates/compensation/detail/compensation/view.html:43 #: compensation/templates/compensation/detail/compensation/view.html:43
#: intervention/tables.py:33 #: intervention/tables.py:33
#: intervention/templates/intervention/detail/view.html:68 user/models.py:48 #: intervention/templates/intervention/detail/view.html:68 user/models.py:48
msgid "Checked" msgid "Checked"
msgstr "Geprüft" msgstr "Geprüft"
#: compensation/tables.py:40 compensation/tables.py:179 #: compensation/tables.py:41 compensation/tables.py:182
#: compensation/templates/compensation/detail/compensation/view.html:57 #: compensation/templates/compensation/detail/compensation/view.html:57
#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:31 #: compensation/templates/compensation/detail/eco_account/includes/deductions.html:31
#: compensation/templates/compensation/detail/eco_account/view.html:44 #: compensation/templates/compensation/detail/eco_account/view.html:44
@ -294,82 +295,82 @@ msgstr "Geprüft"
msgid "Recorded" msgid "Recorded"
msgstr "Verzeichnet" msgstr "Verzeichnet"
#: compensation/tables.py:46 compensation/tables.py:185 ema/tables.py:44 #: compensation/tables.py:47 compensation/tables.py:188 ema/tables.py:44
#: intervention/tables.py:51 #: intervention/tables.py:51
msgid "Editable" msgid "Editable"
msgstr "Freigegeben" msgstr "Freigegeben"
#: compensation/tables.py:52 compensation/tables.py:191 ema/tables.py:50 #: compensation/tables.py:53 compensation/tables.py:194 ema/tables.py:50
#: intervention/tables.py:57 #: intervention/tables.py:57
msgid "Last edit" msgid "Last edit"
msgstr "Zuletzt bearbeitet" msgstr "Zuletzt bearbeitet"
#: compensation/tables.py:61 #: compensation/tables.py:62
#: intervention/templates/intervention/detail/includes/compensations.html:8 #: intervention/templates/intervention/detail/includes/compensations.html:8
msgid "Compensations" msgid "Compensations"
msgstr "Kompensationen" msgstr "Kompensationen"
#: compensation/tables.py:83 compensation/tables.py:222 ema/tables.py:82 #: compensation/tables.py:84 compensation/tables.py:225 ema/tables.py:82
#: intervention/tables.py:88 #: intervention/tables.py:88
msgid "Open {}" msgid "Open {}"
msgstr "Öffne {}" msgstr "Öffne {}"
#: compensation/tables.py:83 #: compensation/tables.py:84
#: compensation/templates/compensation/detail/compensation/view.html:19 #: compensation/templates/compensation/detail/compensation/view.html:19
#: konova/templates/konova/home.html:49 templates/navbar.html:28 #: konova/templates/konova/home.html:49 templates/navbar.html:28
msgid "Compensation" msgid "Compensation"
msgstr "Kompensation" msgstr "Kompensation"
#: compensation/tables.py:104 intervention/tables.py:107 #: compensation/tables.py:105 intervention/tables.py:107
msgid "Not checked yet" msgid "Not checked yet"
msgstr "Noch nicht geprüft" msgstr "Noch nicht geprüft"
#: compensation/tables.py:109 intervention/tables.py:112 #: compensation/tables.py:110 intervention/tables.py:112
msgid "Checked on {} by {}" msgid "Checked on {} by {}"
msgstr "Am {} von {} geprüft worden" msgstr "Am {} von {} geprüft worden"
#: compensation/tables.py:128 #: compensation/tables.py:129
#: compensation/templates/compensation/detail/compensation/view.html:60 #: compensation/templates/compensation/detail/compensation/view.html:60
#: compensation/templates/compensation/detail/eco_account/view.html:47 #: compensation/templates/compensation/detail/eco_account/view.html:47
#: ema/tables.py:101 ema/templates/ema/detail/view.html:31 #: ema/tables.py:101 ema/templates/ema/detail/view.html:31
#: intervention/models.py:352 intervention/tables.py:131 #: intervention/models.py:379 intervention/tables.py:131
#: intervention/templates/intervention/detail/view.html:85 #: intervention/templates/intervention/detail/view.html:85
msgid "Not recorded yet" msgid "Not recorded yet"
msgstr "Noch nicht verzeichnet" msgstr "Noch nicht verzeichnet"
#: compensation/tables.py:133 compensation/tables.py:260 ema/tables.py:106 #: compensation/tables.py:134 compensation/tables.py:263 ema/tables.py:106
#: intervention/models.py:357 intervention/tables.py:136 #: intervention/models.py:384 intervention/tables.py:136
msgid "Recorded on {} by {}" msgid "Recorded on {} by {}"
msgstr "Am {} von {} verzeichnet worden" msgstr "Am {} von {} verzeichnet worden"
#: compensation/tables.py:156 compensation/tables.py:283 ema/tables.py:129 #: compensation/tables.py:159 compensation/tables.py:286 ema/tables.py:129
#: intervention/tables.py:159 #: intervention/tables.py:159
msgid "Full access granted" msgid "Full access granted"
msgstr "Für Sie freigegeben - Datensatz kann bearbeitet werden" msgstr "Für Sie freigegeben - Datensatz kann bearbeitet werden"
#: compensation/tables.py:156 compensation/tables.py:283 ema/tables.py:129 #: compensation/tables.py:159 compensation/tables.py:286 ema/tables.py:129
#: intervention/tables.py:159 #: intervention/tables.py:159
msgid "Access not granted" msgid "Access not granted"
msgstr "Nicht freigegeben - Datensatz nur lesbar" msgstr "Nicht freigegeben - Datensatz nur lesbar"
#: compensation/tables.py:174 #: compensation/tables.py:177
#: compensation/templates/compensation/detail/eco_account/view.html:35 #: compensation/templates/compensation/detail/eco_account/view.html:35
#: konova/templates/konova/custom_widgets/progressbar.html:3 #: konova/templates/konova/custom_widgets/progressbar.html:3
msgid "Available" msgid "Available"
msgstr "Verfügbar" msgstr "Verfügbar"
#: compensation/tables.py:200 #: compensation/tables.py:203
msgid "Eco Accounts" msgid "Eco Accounts"
msgstr "Ökokonten" msgstr "Ökokonten"
#: compensation/tables.py:222 #: compensation/tables.py:225
#: compensation/templates/compensation/detail/eco_account/view.html:19 #: compensation/templates/compensation/detail/eco_account/view.html:19
#: intervention/forms.py:571 intervention/forms.py:578 #: intervention/forms/modalForms.py:258 intervention/forms/modalForms.py:265
#: konova/templates/konova/home.html:88 templates/navbar.html:34 #: konova/templates/konova/home.html:88 templates/navbar.html:34
msgid "Eco-account" msgid "Eco-account"
msgstr "Ökokonto" msgstr "Ökokonto"
#: compensation/tables.py:255 #: compensation/tables.py:258
msgid "Not recorded yet. Can not be used for deductions, yet." msgid "Not recorded yet. Can not be used for deductions, yet."
msgstr "" msgstr ""
"Noch nicht verzeichnet. Kann noch nicht für Abbuchungen genutzt werden." "Noch nicht verzeichnet. Kann noch nicht für Abbuchungen genutzt werden."
@ -477,7 +478,7 @@ msgstr "Dokumente"
#: compensation/templates/compensation/detail/eco_account/includes/documents.html:14 #: compensation/templates/compensation/detail/eco_account/includes/documents.html:14
#: ema/templates/ema/detail/includes/documents.html:14 #: ema/templates/ema/detail/includes/documents.html:14
#: intervention/templates/intervention/detail/includes/documents.html:14 #: intervention/templates/intervention/detail/includes/documents.html:14
#: konova/forms.py:379 #: konova/forms.py:376
msgid "Add new document" msgid "Add new document"
msgstr "Neues Dokument hinzufügen" msgstr "Neues Dokument hinzufügen"
@ -582,7 +583,7 @@ msgstr "Zuletzt bearbeitet"
#: compensation/templates/compensation/detail/compensation/view.html:92 #: compensation/templates/compensation/detail/compensation/view.html:92
#: compensation/templates/compensation/detail/eco_account/view.html:91 #: compensation/templates/compensation/detail/eco_account/view.html:91
#: ema/templates/ema/detail/view.html:82 intervention/forms.py:355 #: ema/templates/ema/detail/view.html:82 intervention/forms/modalForms.py:40
#: intervention/templates/intervention/detail/view.html:116 #: intervention/templates/intervention/detail/view.html:116
msgid "Shared with" msgid "Shared with"
msgstr "Freigegeben für" msgstr "Freigegeben für"
@ -643,19 +644,19 @@ msgid "Missing"
msgstr "Fehlt" msgstr "Fehlt"
#: compensation/templates/compensation/detail/eco_account/view.html:58 #: compensation/templates/compensation/detail/eco_account/view.html:58
#: ema/templates/ema/detail/view.html:42 intervention/forms.py:101 #: ema/templates/ema/detail/view.html:42 intervention/forms/forms.py:98
#: intervention/templates/intervention/detail/view.html:56 #: intervention/templates/intervention/detail/view.html:56
msgid "Conservation office" msgid "Conservation office"
msgstr "Eintragungsstelle" msgstr "Eintragungsstelle"
#: compensation/templates/compensation/detail/eco_account/view.html:62 #: compensation/templates/compensation/detail/eco_account/view.html:62
#: ema/templates/ema/detail/view.html:46 intervention/forms.py:127 #: ema/templates/ema/detail/view.html:46 intervention/forms/forms.py:125
#: intervention/templates/intervention/detail/view.html:60 #: intervention/templates/intervention/detail/view.html:60
msgid "Conservation office file number" msgid "Conservation office file number"
msgstr "Aktenzeichen Eintragungsstelle" msgstr "Aktenzeichen Eintragungsstelle"
#: compensation/templates/compensation/detail/eco_account/view.html:66 #: compensation/templates/compensation/detail/eco_account/view.html:66
#: ema/templates/ema/detail/view.html:50 intervention/forms.py:138 #: ema/templates/ema/detail/view.html:50 intervention/forms/forms.py:137
#: intervention/templates/intervention/detail/view.html:64 #: intervention/templates/intervention/detail/view.html:64
msgid "Intervention handler" msgid "Intervention handler"
msgstr "Eingriffsverursacher" msgstr "Eingriffsverursacher"
@ -667,7 +668,7 @@ msgstr ""
#: compensation/views/compensation_views.py:123 #: compensation/views/compensation_views.py:123
#: compensation/views/eco_account_views.py:190 ema/views.py:128 #: compensation/views/eco_account_views.py:190 ema/views.py:128
#: intervention/views.py:393 #: intervention/views.py:428
msgid "Log" msgid "Log"
msgstr "Log" msgstr "Log"
@ -677,7 +678,7 @@ msgstr "Kompensation entfernt"
#: compensation/views/compensation_views.py:163 #: compensation/views/compensation_views.py:163
#: compensation/views/eco_account_views.py:289 ema/views.py:250 #: compensation/views/eco_account_views.py:289 ema/views.py:250
#: intervention/views.py:96 #: intervention/views.py:124
msgid "Document added" msgid "Document added"
msgstr "Dokument hinzugefügt" msgstr "Dokument hinzugefügt"
@ -713,16 +714,16 @@ msgid "Deduction removed"
msgstr "Abbuchung entfernt" msgstr "Abbuchung entfernt"
#: compensation/views/eco_account_views.py:210 ema/views.py:171 #: compensation/views/eco_account_views.py:210 ema/views.py:171
#: intervention/views.py:433 #: intervention/views.py:468
msgid "{} unrecorded" msgid "{} unrecorded"
msgstr "{} entzeichnet" msgstr "{} entzeichnet"
#: compensation/views/eco_account_views.py:210 ema/views.py:171 #: compensation/views/eco_account_views.py:210 ema/views.py:171
#: intervention/views.py:433 #: intervention/views.py:468
msgid "{} recorded" msgid "{} recorded"
msgstr "{} verzeichnet" msgstr "{} verzeichnet"
#: compensation/views/eco_account_views.py:346 intervention/views.py:415 #: compensation/views/eco_account_views.py:346 intervention/views.py:450
msgid "Deduction added" msgid "Deduction added"
msgstr "Abbuchung hinzugefügt" msgstr "Abbuchung hinzugefügt"
@ -774,129 +775,133 @@ msgstr "Gemarkung"
msgid "Search for district" msgid "Search for district"
msgstr "Nach Gemarkung suchen" msgstr "Nach Gemarkung suchen"
#: intervention/forms.py:40 #: intervention/forms/forms.py:30
msgid "Generated automatically" msgid "Generated automatically"
msgstr "Automatisch generiert" msgstr "Automatisch generiert"
#: intervention/forms.py:45 #: intervention/forms/forms.py:41
msgid "An explanatory name" msgid "An explanatory name"
msgstr "Aussagekräftiger Titel" msgstr "Aussagekräftiger Titel"
#: intervention/forms.py:49 #: intervention/forms/forms.py:45
msgid "Construction XY; Location ABC" msgid "Construction XY; Location ABC"
msgstr "Bauvorhaben XY; Flur ABC" msgstr "Bauvorhaben XY; Flur ABC"
#: intervention/forms.py:54 #: intervention/forms/forms.py:51
#: intervention/templates/intervention/detail/view.html:35 #: intervention/templates/intervention/detail/view.html:35
msgid "Process type" msgid "Process type"
msgstr "Verfahrenstyp" msgstr "Verfahrenstyp"
#: intervention/forms.py:70 #: intervention/forms/forms.py:67
#: intervention/templates/intervention/detail/view.html:39 #: intervention/templates/intervention/detail/view.html:39
msgid "Law" msgid "Law"
msgstr "Gesetz" msgstr "Gesetz"
#: intervention/forms.py:72 #: intervention/forms/forms.py:69
msgid "Multiple selection possible" msgid "Multiple selection possible"
msgstr "Mehrfachauswahl möglich" msgstr "Mehrfachauswahl möglich"
#: intervention/forms.py:86 #: intervention/forms/forms.py:83
#: intervention/templates/intervention/detail/view.html:48 #: intervention/templates/intervention/detail/view.html:48
msgid "Registration office" msgid "Registration office"
msgstr "Zulassungsbehörde" msgstr "Zulassungsbehörde"
#: intervention/forms.py:116 #: intervention/forms/forms.py:113
#: intervention/templates/intervention/detail/view.html:52 #: intervention/templates/intervention/detail/view.html:52
msgid "Registration office file number" msgid "Registration office file number"
msgstr "Aktenzeichen Zulassungsbehörde" msgstr "Aktenzeichen Zulassungsbehörde"
#: intervention/forms.py:122 #: intervention/forms/forms.py:119
msgid "ZB-123/ABC.456" msgid "ZB-123/ABC.456"
msgstr "" msgstr ""
#: intervention/forms.py:133 #: intervention/forms/forms.py:131
msgid "ETS-123/ABC.456" msgid "ETS-123/ABC.456"
msgstr "" msgstr ""
#: intervention/forms.py:142 #: intervention/forms/forms.py:141
msgid "Who performs the intervention" msgid "Who performs the intervention"
msgstr "Wer führt den Eingriff durch" msgstr "Wer führt den Eingriff durch"
#: intervention/forms.py:145 #: intervention/forms/forms.py:144
msgid "Company Mustermann" msgid "Company Mustermann"
msgstr "Firma Mustermann" msgstr "Firma Mustermann"
#: intervention/forms.py:150 #: intervention/forms/forms.py:150
#: intervention/templates/intervention/detail/view.html:96 #: intervention/templates/intervention/detail/view.html:96
msgid "Registration date" msgid "Registration date"
msgstr "Datum Zulassung bzw. Satzungsbeschluss" msgstr "Datum Zulassung bzw. Satzungsbeschluss"
#: intervention/forms.py:161 #: intervention/forms/forms.py:162
#: intervention/templates/intervention/detail/view.html:100 #: intervention/templates/intervention/detail/view.html:100
msgid "Binding on" msgid "Binding on"
msgstr "Datum Bestandskraft" msgstr "Datum Bestandskraft"
#: intervention/forms.py:174 #: intervention/forms/forms.py:177
msgid "Additional comment"
msgstr "Zusätzlicher Kommentar"
#: intervention/forms/forms.py:188
msgid "New intervention" msgid "New intervention"
msgstr "Neuer Eingriff" msgstr "Neuer Eingriff"
#: intervention/forms.py:248 #: intervention/forms/forms.py:269
msgid "Edit intervention" msgid "Edit intervention"
msgstr "Eingriff bearbeiten" msgstr "Eingriff bearbeiten"
#: intervention/forms.py:344 #: intervention/forms/modalForms.py:28
msgid "Share link" msgid "Share link"
msgstr "Freigabelink" msgstr "Freigabelink"
#: intervention/forms.py:346 #: intervention/forms/modalForms.py:30
msgid "Send this link to users who you want to have writing access on the data" msgid "Send this link to users who you want to have writing access on the data"
msgstr "Andere Nutzer erhalten über diesen Link Zugriff auf die Daten" msgstr "Andere Nutzer erhalten über diesen Link Zugriff auf die Daten"
#: intervention/forms.py:358 #: intervention/forms/modalForms.py:43
msgid "Remove check to remove access for this user" msgid "Remove check to remove access for this user"
msgstr "Wählen Sie die Nutzer ab, die keinen Zugriff mehr haben sollen" msgstr "Wählen Sie die Nutzer ab, die keinen Zugriff mehr haben sollen"
#: intervention/forms.py:369 #: intervention/forms/modalForms.py:54
#: intervention/templates/intervention/detail/includes/controls.html:15 #: intervention/templates/intervention/detail/includes/controls.html:15
msgid "Share" msgid "Share"
msgstr "Freigabe" msgstr "Freigabe"
#: intervention/forms.py:370 #: intervention/forms/modalForms.py:55
msgid "Share settings for {}" msgid "Share settings for {}"
msgstr "Freigabe Einstellungen für {}" msgstr "Freigabe Einstellungen für {}"
#: intervention/forms.py:423 #: intervention/forms/modalForms.py:108
msgid "Date of revocation" msgid "Date of revocation"
msgstr "Datum des Widerspruchs" msgstr "Datum des Widerspruchs"
#: intervention/forms.py:433 #: intervention/forms/modalForms.py:119
#: intervention/templates/intervention/detail/includes/revocation.html:35 #: intervention/templates/intervention/detail/includes/revocation.html:35
msgid "Document" msgid "Document"
msgstr "Dokument" msgstr "Dokument"
#: intervention/forms.py:436 konova/forms.py:349 #: intervention/forms/modalForms.py:122 konova/forms.py:345
msgid "Must be smaller than 15 Mb" msgid "Must be smaller than 15 Mb"
msgstr "Muss kleiner als 15 Mb sein" msgstr "Muss kleiner als 15 Mb sein"
#: intervention/forms.py:459 #: intervention/forms/modalForms.py:146
#: intervention/templates/intervention/detail/includes/revocation.html:18 #: intervention/templates/intervention/detail/includes/revocation.html:18
msgid "Add revocation" msgid "Add revocation"
msgstr "Widerspruch hinzufügen" msgstr "Widerspruch hinzufügen"
#: intervention/forms.py:499 #: intervention/forms/modalForms.py:186
msgid "Checked intervention data" msgid "Checked intervention data"
msgstr "Eingriffsdaten geprüft" msgstr "Eingriffsdaten geprüft"
#: intervention/forms.py:505 #: intervention/forms/modalForms.py:192
msgid "Checked compensations data and payments" msgid "Checked compensations data and payments"
msgstr "Kompensationen und Zahlungen geprüft" msgstr "Kompensationen und Zahlungen geprüft"
#: intervention/forms.py:513 #: intervention/forms/modalForms.py:200
#: intervention/templates/intervention/detail/includes/controls.html:19 #: intervention/templates/intervention/detail/includes/controls.html:19
msgid "Run check" msgid "Run check"
msgstr "Prüfung vornehmen" msgstr "Prüfung vornehmen"
#: intervention/forms.py:514 konova/forms.py:433 #: intervention/forms/modalForms.py:201 konova/forms.py:430
msgid "" msgid ""
"I, {} {}, confirm that all necessary control steps have been performed by " "I, {} {}, confirm that all necessary control steps have been performed by "
"myself." "myself."
@ -904,30 +909,30 @@ msgstr ""
"Ich, {} {}, bestätige, dass die notwendigen Kontrollschritte durchgeführt " "Ich, {} {}, bestätige, dass die notwendigen Kontrollschritte durchgeführt "
"wurden:" "wurden:"
#: intervention/forms.py:573 #: intervention/forms/modalForms.py:260
msgid "Only recorded accounts can be selected for deductions" msgid "Only recorded accounts can be selected for deductions"
msgstr "Nur verzeichnete Ökokonten können für Abbuchungen verwendet werden." msgstr "Nur verzeichnete Ökokonten können für Abbuchungen verwendet werden."
#: intervention/forms.py:592 intervention/forms.py:599 #: intervention/forms/modalForms.py:284 intervention/forms/modalForms.py:291
#: intervention/tables.py:88 #: intervention/tables.py:88
#: intervention/templates/intervention/detail/view.html:19 #: intervention/templates/intervention/detail/view.html:19
#: konova/templates/konova/home.html:11 templates/navbar.html:22 #: konova/templates/konova/home.html:11 templates/navbar.html:22
msgid "Intervention" msgid "Intervention"
msgstr "Eingriff" msgstr "Eingriff"
#: intervention/forms.py:594 #: intervention/forms/modalForms.py:286
msgid "Only shared interventions can be selected" msgid "Only shared interventions can be selected"
msgstr "Nur freigegebene Eingriffe können gewählt werden" msgstr "Nur freigegebene Eingriffe können gewählt werden"
#: intervention/forms.py:607 #: intervention/forms/modalForms.py:299
msgid "New Deduction" msgid "New Deduction"
msgstr "Neue Abbuchung" msgstr "Neue Abbuchung"
#: intervention/forms.py:608 #: intervention/forms/modalForms.py:300
msgid "Enter the information for a new deduction from a chosen eco-account" msgid "Enter the information for a new deduction from a chosen eco-account"
msgstr "Geben Sie die Informationen für eine neue Abbuchung ein." msgstr "Geben Sie die Informationen für eine neue Abbuchung ein."
#: intervention/forms.py:644 #: intervention/forms/modalForms.py:336
msgid "" msgid ""
"Eco-account {} is not recorded yet. You can only deduct from recorded " "Eco-account {} is not recorded yet. You can only deduct from recorded "
"accounts." "accounts."
@ -935,7 +940,7 @@ msgstr ""
"Ökokonto {} ist noch nicht verzeichnet. Abbuchungen können nur von " "Ökokonto {} ist noch nicht verzeichnet. Abbuchungen können nur von "
"verzeichneten Ökokonten erfolgen." "verzeichneten Ökokonten erfolgen."
#: intervention/forms.py:657 #: intervention/forms/modalForms.py:349
msgid "" msgid ""
"The account {} has not enough surface for a deduction of {} m². There are " "The account {} has not enough surface for a deduction of {} m². There are "
"only {} m² left" "only {} m² left"
@ -943,31 +948,31 @@ msgstr ""
"Das Ökokonto {} hat für eine Abbuchung von {} m² nicht ausreichend " "Das Ökokonto {} hat für eine Abbuchung von {} m² nicht ausreichend "
"Restfläche. Es stehen noch {} m² zur Verfügung." "Restfläche. Es stehen noch {} m² zur Verfügung."
#: intervention/models.py:298 #: intervention/models.py:325
msgid "Registration office file number missing" msgid "Registration office file number missing"
msgstr "Aktenzeichen Zulassungsbehörde fehlt" msgstr "Aktenzeichen Zulassungsbehörde fehlt"
#: intervention/models.py:301 #: intervention/models.py:328
msgid "Conservation office file number missing" msgid "Conservation office file number missing"
msgstr "Aktenzeichen Naturschutzbehörde fehlt" msgstr "Aktenzeichen Naturschutzbehörde fehlt"
#: intervention/models.py:304 #: intervention/models.py:331
msgid "Responsible data missing" msgid "Responsible data missing"
msgstr "Daten zu Verantwortlichen fehlen" msgstr "Daten zu Verantwortlichen fehlen"
#: intervention/models.py:318 #: intervention/models.py:345
msgid "Revocation exists" msgid "Revocation exists"
msgstr "Widerspruch liegt vor" msgstr "Widerspruch liegt vor"
#: intervention/models.py:321 #: intervention/models.py:348
msgid "Registration date missing" msgid "Registration date missing"
msgstr "Datum Zulassung bzw. Satzungsbeschluss fehlt" msgstr "Datum Zulassung bzw. Satzungsbeschluss fehlt"
#: intervention/models.py:324 #: intervention/models.py:351
msgid "Binding on missing" msgid "Binding on missing"
msgstr "Datum Bestandskraft fehlt" msgstr "Datum Bestandskraft fehlt"
#: intervention/models.py:326 #: intervention/models.py:353
msgid "Legal data missing" msgid "Legal data missing"
msgstr "Rechtliche Daten fehlen" msgstr "Rechtliche Daten fehlen"
@ -1040,19 +1045,27 @@ msgstr "Widerspruch entfernen"
msgid "Exists" msgid "Exists"
msgstr "vorhanden" msgstr "vorhanden"
#: intervention/views.py:67 #: intervention/views.py:71
msgid ""
"The identifier '{}' had to be changed to '{}' since another entry has been "
"added in the meanwhile, which uses this identifier"
msgstr ""
"Die Kennung '{}' musste zu '{}' geändert werden, da ein anderer Eintrag in "
"der Zwischenzeit angelegt wurde, welcher diese Kennung nun bereits verwendet"
#: intervention/views.py:76
msgid "Intervention {} added" msgid "Intervention {} added"
msgstr "Eingriff {} hinzugefügt" msgstr "Eingriff {} hinzugefügt"
#: intervention/views.py:70 intervention/views.py:226 #: intervention/views.py:79 intervention/views.py:258
msgid "Invalid input" msgid "Invalid input"
msgstr "Eingabe fehlerhaft" msgstr "Eingabe fehlerhaft"
#: intervention/views.py:184 #: intervention/views.py:212
msgid "This intervention has a revocation from {}" msgid "This intervention has a revocation from {}"
msgstr "Es existiert ein Widerspruch vom {}" msgstr "Es existiert ein Widerspruch vom {}"
#: intervention/views.py:200 #: intervention/views.py:228
msgid "" msgid ""
"Remember: This data has not been shared with you, yet. This means you can " "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 " "only read but can not edit or perform any actions like running a check or "
@ -1062,43 +1075,43 @@ msgstr ""
"bedeutet, dass Sie nur lesenden Zugriff hierauf haben und weder bearbeiten, " "bedeutet, dass Sie nur lesenden Zugriff hierauf haben und weder bearbeiten, "
"noch Prüfungen durchführen oder verzeichnen können." "noch Prüfungen durchführen oder verzeichnen können."
#: intervention/views.py:223 #: intervention/views.py:255
msgid "{} edited" msgid "Intervention {} edited"
msgstr "{} bearbeitet" msgstr "Eingriff {} bearbeitet"
#: intervention/views.py:252 #: intervention/views.py:287
msgid "{} removed" msgid "{} removed"
msgstr "{} entfernt" msgstr "{} entfernt"
#: intervention/views.py:273 #: intervention/views.py:308
msgid "Revocation removed" msgid "Revocation removed"
msgstr "Widerspruch entfernt" msgstr "Widerspruch entfernt"
#: intervention/views.py:299 #: intervention/views.py:334
msgid "{} has already been shared with you" msgid "{} has already been shared with you"
msgstr "{} wurde bereits für Sie freigegeben" msgstr "{} wurde bereits für Sie freigegeben"
#: intervention/views.py:304 #: intervention/views.py:339
msgid "{} has been shared with you" msgid "{} has been shared with you"
msgstr "{} ist nun für Sie freigegeben" msgstr "{} ist nun für Sie freigegeben"
#: intervention/views.py:311 #: intervention/views.py:346
msgid "Share link invalid" msgid "Share link invalid"
msgstr "Freigabelink ungültig" msgstr "Freigabelink ungültig"
#: intervention/views.py:332 #: intervention/views.py:367
msgid "Share settings updated" msgid "Share settings updated"
msgstr "Freigabe Einstellungen aktualisiert" msgstr "Freigabe Einstellungen aktualisiert"
#: intervention/views.py:351 #: intervention/views.py:386
msgid "Check performed" msgid "Check performed"
msgstr "Prüfung durchgeführt" msgstr "Prüfung durchgeführt"
#: intervention/views.py:371 #: intervention/views.py:406
msgid "Revocation added" msgid "Revocation added"
msgstr "Widerspruch hinzugefügt" msgstr "Widerspruch hinzugefügt"
#: intervention/views.py:438 #: intervention/views.py:473
msgid "There are errors on this intervention:" msgid "There are errors on this intervention:"
msgstr "Es liegen Fehler in diesem Eingriff vor:" msgstr "Es liegen Fehler in diesem Eingriff vor:"
@ -1127,11 +1140,11 @@ msgstr "Hierfür müssen Sie einer anderen Nutzergruppe angehören!"
msgid "Not editable" msgid "Not editable"
msgstr "Nicht editierbar" msgstr "Nicht editierbar"
#: konova/forms.py:139 konova/forms.py:295 #: konova/forms.py:139 konova/forms.py:293
msgid "Confirm" msgid "Confirm"
msgstr "Bestätige" msgstr "Bestätige"
#: konova/forms.py:151 konova/forms.py:304 #: konova/forms.py:151 konova/forms.py:302
msgid "Remove" msgid "Remove"
msgstr "Löschen" msgstr "Löschen"
@ -1139,48 +1152,48 @@ msgstr "Löschen"
msgid "You are about to remove {} {}" msgid "You are about to remove {} {}"
msgstr "Sie sind dabei {} {} zu löschen" msgstr "Sie sind dabei {} {} zu löschen"
#: konova/forms.py:249 templates/form/main_data_collapse_form.html:47 #: konova/forms.py:243 templates/form/main_data_collapse_form.html:47
msgid "Geometry" msgid "Geometry"
msgstr "Geometrie" msgstr "Geometrie"
#: konova/forms.py:305 #: konova/forms.py:303
msgid "Are you sure?" msgid "Are you sure?"
msgstr "Sind Sie sicher?" msgstr "Sind Sie sicher?"
#: konova/forms.py:335 #: konova/forms.py:330
msgid "Created on" msgid "Created on"
msgstr "Erstellt" msgstr "Erstellt"
#: konova/forms.py:337 #: konova/forms.py:332
msgid "When has this file been created? Important for photos." msgid "When has this file been created? Important for photos."
msgstr "Wann wurde diese Datei erstellt oder das Foto aufgenommen?" msgstr "Wann wurde diese Datei erstellt oder das Foto aufgenommen?"
#: konova/forms.py:347 #: konova/forms.py:343
#: venv/lib/python3.7/site-packages/django/db/models/fields/files.py:231 #: venv/lib/python3.7/site-packages/django/db/models/fields/files.py:231
msgid "File" msgid "File"
msgstr "Datei" msgstr "Datei"
#: konova/forms.py:410 #: konova/forms.py:407
msgid "Added document" msgid "Added document"
msgstr "Dokument hinzugefügt" msgstr "Dokument hinzugefügt"
#: konova/forms.py:424 #: konova/forms.py:421
msgid "Confirm record" msgid "Confirm record"
msgstr "Verzeichnen bestätigen" msgstr "Verzeichnen bestätigen"
#: konova/forms.py:432 #: konova/forms.py:429
msgid "Record data" msgid "Record data"
msgstr "Daten verzeichnen" msgstr "Daten verzeichnen"
#: konova/forms.py:439 #: konova/forms.py:436
msgid "Confirm unrecord" msgid "Confirm unrecord"
msgstr "Entzeichnen bestätigen" msgstr "Entzeichnen bestätigen"
#: konova/forms.py:440 #: konova/forms.py:437
msgid "Unrecord data" msgid "Unrecord data"
msgstr "Daten entzeichnen" msgstr "Daten entzeichnen"
#: konova/forms.py:441 #: konova/forms.py:438
msgid "I, {} {}, confirm that this data must be unrecorded." msgid "I, {} {}, confirm that this data must be unrecorded."
msgstr "" msgstr ""
"Ich, {} {}, bestätige, dass diese Daten wieder entzeichnet werden müssen." "Ich, {} {}, bestätige, dass diese Daten wieder entzeichnet werden müssen."
@ -1209,22 +1222,26 @@ msgstr "Wenn meine freigegebenen Daten gelöscht wurden"
msgid "On registered data edited" msgid "On registered data edited"
msgstr "Wenn meine freigegebenen Daten bearbeitet wurden" msgstr "Wenn meine freigegebenen Daten bearbeitet wurden"
#: konova/models.py:190 #: konova/models.py:204
msgid "Finished" msgid "Finished"
msgstr "Umgesetzt bis" msgstr "Umgesetzt bis"
#: konova/models.py:191 #: konova/models.py:205
msgid "Maintain" msgid "Maintain"
msgstr "Unterhaltung bis" msgstr "Unterhaltung bis"
#: konova/models.py:192 #: konova/models.py:206
msgid "Control" msgid "Control"
msgstr "Kontrolle am" msgstr "Kontrolle am"
#: konova/models.py:193 #: konova/models.py:207
msgid "Other" msgid "Other"
msgstr "Sonstige" msgstr "Sonstige"
#: konova/templates/konova/custom_widgets/generate-content-input.html:6
msgid "Generate new"
msgstr "Neu generieren"
#: konova/templates/konova/custom_widgets/text-to-clipboard-input.html:6 #: konova/templates/konova/custom_widgets/text-to-clipboard-input.html:6
msgid "Copy to clipboard" msgid "Copy to clipboard"
msgstr "In Zwischenablage kopieren" msgstr "In Zwischenablage kopieren"
@ -2720,6 +2737,9 @@ msgstr ""
msgid "A fontawesome icon field" msgid "A fontawesome icon field"
msgstr "" msgstr ""
#~ msgid "{} edited"
#~ msgstr "{} bearbeitet"
#~ msgid "Map" #~ msgid "Map"
#~ msgstr "Karte" #~ msgstr "Karte"
@ -2771,9 +2791,6 @@ msgstr ""
#~ msgid "Actions" #~ msgid "Actions"
#~ msgstr "Aktionen" #~ msgstr "Aktionen"
#~ msgid "Additional comment"
#~ msgstr "Zusätzlicher Kommentar"
#~ msgid "Missing surfaces: " #~ msgid "Missing surfaces: "
#~ msgstr "Fehlende Flächen: " #~ msgstr "Fehlende Flächen: "