Merge pull request '7_New_forms' (#28) from 7_New_forms into master
Reviewed-on: SGD-Nord/konova#28pull/29/head
commit
0e7c378d4a
@ -0,0 +1,444 @@
|
||||
"""
|
||||
Author: Michel Peltriaux
|
||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
|
||||
Contact: michel.peltriaux@sgdnord.rlp.de
|
||||
Created on: 04.12.20
|
||||
|
||||
"""
|
||||
from dal import autocomplete
|
||||
from django.contrib.auth.models import User
|
||||
from django.db import transaction
|
||||
from django.urls import reverse_lazy, reverse
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django import forms
|
||||
|
||||
from codelist.models import KonovaCode
|
||||
from codelist.settings import CODELIST_COMPENSATION_FUNDING_ID, CODELIST_CONSERVATION_OFFICE_ID
|
||||
from compensation.models import Compensation, EcoAccount
|
||||
from intervention.inputs import GenerateInput
|
||||
from intervention.models import Intervention, ResponsibilityData
|
||||
from konova.forms import BaseForm, SimpleGeomForm
|
||||
from user.models import UserActionLogEntry, UserAction
|
||||
|
||||
|
||||
class AbstractCompensationForm(BaseForm):
|
||||
""" Abstract form for compensations
|
||||
|
||||
Holds all important form fields, which are used in compensation and eco account forms
|
||||
|
||||
"""
|
||||
identifier = forms.CharField(
|
||||
label=_("Identifier"),
|
||||
label_suffix="",
|
||||
max_length=255,
|
||||
help_text=_("Generated automatically"),
|
||||
widget=GenerateInput(
|
||||
attrs={
|
||||
"class": "form-control",
|
||||
"url": None, # Needs to be set in inheriting constructors
|
||||
}
|
||||
)
|
||||
)
|
||||
title = forms.CharField(
|
||||
label=_("Title"),
|
||||
label_suffix="",
|
||||
help_text=_("An explanatory name"),
|
||||
max_length=255,
|
||||
widget=forms.TextInput(
|
||||
attrs={
|
||||
"placeholder": _("Compensation XY; Location ABC"),
|
||||
"class": "form-control",
|
||||
}
|
||||
)
|
||||
)
|
||||
fundings = forms.ModelMultipleChoiceField(
|
||||
label=_("Fundings"),
|
||||
label_suffix="",
|
||||
required=False,
|
||||
help_text=_("Select fundings for this compensation"),
|
||||
queryset=KonovaCode.objects.filter(
|
||||
is_archived=False,
|
||||
is_leaf=True,
|
||||
code_lists__in=[CODELIST_COMPENSATION_FUNDING_ID],
|
||||
),
|
||||
widget=autocomplete.ModelSelect2Multiple(
|
||||
url="codes-compensation-funding-autocomplete",
|
||||
attrs={
|
||||
"data-placeholder": _("Click for selection"),
|
||||
}
|
||||
),
|
||||
)
|
||||
comment = forms.CharField(
|
||||
label_suffix="",
|
||||
label=_("Comment"),
|
||||
required=False,
|
||||
help_text=_("Additional comment"),
|
||||
widget=forms.Textarea(
|
||||
attrs={
|
||||
"rows": 5,
|
||||
"class": "form-control"
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
||||
class CompensationResponsibleFormMixin(forms.Form):
|
||||
""" Encapsulates form fields used in different compensation related models like EcoAccount or EMA
|
||||
|
||||
"""
|
||||
conservation_office = forms.ModelChoiceField(
|
||||
label=_("Conservation office"),
|
||||
label_suffix="",
|
||||
help_text=_("Select the responsible office"),
|
||||
queryset=KonovaCode.objects.filter(
|
||||
is_archived=False,
|
||||
is_leaf=True,
|
||||
code_lists__in=[CODELIST_CONSERVATION_OFFICE_ID],
|
||||
),
|
||||
widget=autocomplete.ModelSelect2(
|
||||
url="codes-conservation-office-autocomplete",
|
||||
attrs={
|
||||
"data-placeholder": _("Click for selection")
|
||||
}
|
||||
),
|
||||
)
|
||||
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=_("Eco-account handler"),
|
||||
label_suffix="",
|
||||
max_length=255,
|
||||
required=False,
|
||||
help_text=_("Who handles the eco-account"),
|
||||
widget=forms.TextInput(
|
||||
attrs={
|
||||
"placeholder": _("Company Mustermann"),
|
||||
"class": "form-control",
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class NewCompensationForm(AbstractCompensationForm):
|
||||
""" Form for creating new compensations.
|
||||
|
||||
Can be initialized with an intervention id for preselecting the related intervention.
|
||||
form = NewCompensationForm(request.POST or None, intervention_id=intervention_id)
|
||||
...
|
||||
The intervention id will not be resolved into the intervention ORM object but instead will be used to initialize
|
||||
the related form field.
|
||||
|
||||
"""
|
||||
intervention = forms.ModelChoiceField(
|
||||
label=_("compensates intervention"),
|
||||
label_suffix="",
|
||||
help_text=_("Select the intervention for which this compensation compensates"),
|
||||
queryset=Intervention.objects.filter(
|
||||
deleted=None,
|
||||
),
|
||||
widget=autocomplete.ModelSelect2(
|
||||
url="interventions-autocomplete",
|
||||
attrs={
|
||||
"data-placeholder": _("Click for selection"),
|
||||
"data-minimum-input-length": 3,
|
||||
}
|
||||
),
|
||||
)
|
||||
|
||||
# Define a field order for a nicer layout instead of running with the inheritance result
|
||||
field_order = [
|
||||
"identifier",
|
||||
"title",
|
||||
"intervention",
|
||||
"fundings",
|
||||
"comment",
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
intervention_id = kwargs.pop("intervention_id", None)
|
||||
super().__init__(*args, **kwargs)
|
||||
self.form_title = _("New compensation")
|
||||
|
||||
# If the compensation shall directly be initialized from an intervention, we need to fill in the intervention id
|
||||
# and disable the form field.
|
||||
# Furthermore the action_url needs to be set accordingly.
|
||||
if intervention_id is not None:
|
||||
self.initialize_form_field("intervention", intervention_id)
|
||||
self.disable_form_field("intervention")
|
||||
self.action_url = reverse("compensation:new", args=(intervention_id,))
|
||||
self.cancel_redirect = reverse("intervention:open", args=(intervention_id,))
|
||||
else:
|
||||
self.action_url = reverse("compensation:new")
|
||||
self.cancel_redirect = reverse("compensation:index")
|
||||
|
||||
tmp = Compensation()
|
||||
identifier = tmp.generate_new_identifier()
|
||||
self.initialize_form_field("identifier", identifier)
|
||||
self.fields["identifier"].widget.attrs["url"] = reverse_lazy("compensation:new-id")
|
||||
|
||||
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)
|
||||
fundings = self.cleaned_data.get("fundings", None)
|
||||
intervention = self.cleaned_data.get("intervention", None)
|
||||
comment = self.cleaned_data.get("comment", None)
|
||||
|
||||
# Create log entry
|
||||
action = UserActionLogEntry.objects.create(
|
||||
user=user,
|
||||
action=UserAction.CREATED,
|
||||
)
|
||||
# Process the geometry form
|
||||
geometry = geom_form.save(action)
|
||||
|
||||
# Finally create main object
|
||||
comp = Compensation.objects.create(
|
||||
identifier=identifier,
|
||||
title=title,
|
||||
intervention=intervention,
|
||||
created=action,
|
||||
geometry=geometry,
|
||||
comment=comment,
|
||||
)
|
||||
comp.fundings.set(fundings)
|
||||
|
||||
# Add the log entry to the main objects log list
|
||||
comp.log.add(action)
|
||||
return comp
|
||||
|
||||
|
||||
class EditCompensationForm(NewCompensationForm):
|
||||
""" Form for editing compensations
|
||||
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.form_title = _("Edit compensation")
|
||||
self.action_url = reverse("compensation:edit", args=(self.instance.id,))
|
||||
self.cancel_redirect = reverse("compensation:open", args=(self.instance.id,))
|
||||
|
||||
# Initialize form data
|
||||
form_data = {
|
||||
"identifier": self.instance.identifier,
|
||||
"title": self.instance.title,
|
||||
"intervention": self.instance.intervention,
|
||||
"fundings": self.instance.fundings.all(),
|
||||
"comment": self.instance.comment,
|
||||
}
|
||||
disabled_fields = []
|
||||
self.load_initial_data(
|
||||
form_data,
|
||||
disabled_fields
|
||||
)
|
||||
|
||||
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)
|
||||
fundings = self.cleaned_data.get("fundings", None)
|
||||
intervention = self.cleaned_data.get("intervention", None)
|
||||
comment = self.cleaned_data.get("comment", None)
|
||||
|
||||
# Create log entry
|
||||
action = UserActionLogEntry.objects.create(
|
||||
user=user,
|
||||
action=UserAction.EDITED,
|
||||
)
|
||||
|
||||
# Process the geometry form
|
||||
geometry = geom_form.save(action)
|
||||
|
||||
# Finally create main object
|
||||
self.instance.identifier = identifier
|
||||
self.instance.title = title
|
||||
self.instance.intervention = intervention
|
||||
self.instance.geometry = geometry
|
||||
self.instance.comment = comment
|
||||
self.instance.modified = action
|
||||
self.instance.fundings.set(fundings)
|
||||
self.instance.save()
|
||||
|
||||
self.instance.log.add(action)
|
||||
return self.instance
|
||||
|
||||
|
||||
class NewEcoAccountForm(AbstractCompensationForm, CompensationResponsibleFormMixin):
|
||||
""" Form for creating eco accounts
|
||||
|
||||
Inherits from basic AbstractCompensationForm and further form fields from CompensationResponsibleFormMixin
|
||||
|
||||
"""
|
||||
field_order = [
|
||||
"identifier",
|
||||
"title",
|
||||
"conservation_office",
|
||||
"conservation_file_number",
|
||||
"handler",
|
||||
"fundings",
|
||||
"comment",
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.form_title = _("New Eco-Account")
|
||||
|
||||
self.action_url = reverse("compensation:acc-new")
|
||||
self.cancel_redirect = reverse("compensation:acc-index")
|
||||
|
||||
tmp = EcoAccount()
|
||||
identifier = tmp.generate_new_identifier()
|
||||
self.initialize_form_field("identifier", identifier)
|
||||
self.fields["identifier"].widget.attrs["url"] = reverse_lazy("compensation:acc-new-id")
|
||||
self.fields["title"].widget.attrs["placeholder"] = _("Eco-Account XY; Location ABC")
|
||||
|
||||
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)
|
||||
fundings = self.cleaned_data.get("fundings", None)
|
||||
handler = self.cleaned_data.get("handler", None)
|
||||
conservation_office = self.cleaned_data.get("conservation_office", None)
|
||||
conservation_file_number = self.cleaned_data.get("conservation_file_number", None)
|
||||
comment = self.cleaned_data.get("comment", None)
|
||||
|
||||
# Create log entry
|
||||
action = UserActionLogEntry.objects.create(
|
||||
user=user,
|
||||
action=UserAction.CREATED,
|
||||
)
|
||||
# Process the geometry form
|
||||
geometry = geom_form.save(action)
|
||||
|
||||
responsible = ResponsibilityData.objects.create(
|
||||
handler=handler,
|
||||
conservation_file_number=conservation_file_number,
|
||||
conservation_office=conservation_office,
|
||||
)
|
||||
|
||||
# Finally create main object
|
||||
acc = EcoAccount.objects.create(
|
||||
identifier=identifier,
|
||||
title=title,
|
||||
responsible=responsible,
|
||||
deductable_surface=0.00,
|
||||
created=action,
|
||||
geometry=geometry,
|
||||
comment=comment,
|
||||
)
|
||||
acc.fundings.set(fundings)
|
||||
acc.users.add(user)
|
||||
|
||||
# Add the log entry to the main objects log list
|
||||
acc.log.add(action)
|
||||
return acc
|
||||
|
||||
|
||||
class EditEcoAccountForm(NewEcoAccountForm):
|
||||
""" Form for editing eco accounts
|
||||
|
||||
"""
|
||||
surface = forms.DecimalField(
|
||||
min_value=0.00,
|
||||
decimal_places=2,
|
||||
label=_("Available Surface"),
|
||||
label_suffix="",
|
||||
required=False,
|
||||
help_text=_("The amount that can be used for deductions"),
|
||||
widget=forms.NumberInput(
|
||||
attrs={
|
||||
"class": "form-control",
|
||||
"placeholder": "0,00"
|
||||
}
|
||||
)
|
||||
)
|
||||
field_order = [
|
||||
"identifier",
|
||||
"title",
|
||||
"conservation_office",
|
||||
"surface",
|
||||
"conservation_file_number",
|
||||
"handler",
|
||||
"fundings",
|
||||
"comment",
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.form_title = _("Edit Eco-Account")
|
||||
|
||||
self.action_url = reverse("compensation:acc-edit", args=(self.instance.id,))
|
||||
self.cancel_redirect = reverse("compensation:acc-open", args=(self.instance.id,))
|
||||
|
||||
# Initialize form data
|
||||
form_data = {
|
||||
"identifier": self.instance.identifier,
|
||||
"title": self.instance.title,
|
||||
"surface": self.instance.deductable_surface,
|
||||
"handler": self.instance.responsible.handler,
|
||||
"conservation_office": self.instance.responsible.conservation_office,
|
||||
"conservation_file_number": self.instance.responsible.conservation_file_number,
|
||||
"fundings": self.instance.fundings.all(),
|
||||
"comment": self.instance.comment,
|
||||
}
|
||||
disabled_fields = []
|
||||
self.load_initial_data(
|
||||
form_data,
|
||||
disabled_fields
|
||||
)
|
||||
|
||||
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)
|
||||
fundings = self.cleaned_data.get("fundings", None)
|
||||
handler = self.cleaned_data.get("handler", None)
|
||||
surface = self.cleaned_data.get("surface", None)
|
||||
conservation_office = self.cleaned_data.get("conservation_office", None)
|
||||
conservation_file_number = self.cleaned_data.get("conservation_file_number", None)
|
||||
comment = self.cleaned_data.get("comment", None)
|
||||
|
||||
# Create log entry
|
||||
action = UserActionLogEntry.objects.create(
|
||||
user=user,
|
||||
action=UserAction.EDITED,
|
||||
)
|
||||
# Process the geometry form
|
||||
geometry = geom_form.save(action)
|
||||
|
||||
# Update responsible data
|
||||
self.instance.responsible.handler = handler
|
||||
self.instance.responsible.conservation_office = conservation_office
|
||||
self.instance.responsible.conservation_file_number = conservation_file_number
|
||||
self.instance.responsible.save()
|
||||
|
||||
# Update main oject data
|
||||
self.instance.identifier = identifier
|
||||
self.instance.title = title
|
||||
self.instance.deductable_surface = surface
|
||||
self.instance.geometry = geometry
|
||||
self.instance.comment = comment
|
||||
self.instance.modified = action
|
||||
self.instance.save()
|
||||
self.instance.fundings.set(fundings)
|
||||
|
||||
# Add the log entry to the main objects log list
|
||||
self.instance.log.add(action)
|
||||
return self.instance
|
@ -0,0 +1,23 @@
|
||||
{% load i18n fontawesome_5 %}
|
||||
|
||||
{% if obj.comment %}
|
||||
<div class="w-100">
|
||||
<div class="card mt-3">
|
||||
<div class="card-header rlp-gd">
|
||||
<div class="row">
|
||||
<div class="col-sm-12 col-md-12 col-lg-12">
|
||||
<h5 class="card-title">
|
||||
{% fa5_icon 'info-circle' %}
|
||||
{% trans 'Comment' %}
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="card-text font-italic">
|
||||
{{obj.comment}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
@ -0,0 +1,23 @@
|
||||
{% load i18n fontawesome_5 %}
|
||||
|
||||
{% if obj.comment %}
|
||||
<div class="w-100">
|
||||
<div class="card mt-3">
|
||||
<div class="card-header rlp-gd">
|
||||
<div class="row">
|
||||
<div class="col-sm-12 col-md-12 col-lg-12">
|
||||
<h5 class="card-title">
|
||||
{% fa5_icon 'info-circle' %}
|
||||
{% trans 'Comment' %}
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="card-text font-italic">
|
||||
{{obj.comment}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
@ -0,0 +1,6 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n l10n %}
|
||||
|
||||
{% block body %}
|
||||
{% include 'form/collapsable/form.html' %}
|
||||
{% endblock %}
|
@ -0,0 +1,159 @@
|
||||
"""
|
||||
Author: Michel Peltriaux
|
||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
|
||||
Contact: michel.peltriaux@sgdnord.rlp.de
|
||||
Created on: 06.10.21
|
||||
|
||||
"""
|
||||
from django.contrib.auth.models import User
|
||||
from django.db import transaction
|
||||
from django.urls import reverse, reverse_lazy
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from compensation.forms.forms import AbstractCompensationForm, CompensationResponsibleFormMixin
|
||||
from ema.models import Ema
|
||||
from intervention.models import ResponsibilityData
|
||||
from konova.forms import SimpleGeomForm
|
||||
from user.models import UserActionLogEntry, UserAction
|
||||
|
||||
|
||||
class NewEmaForm(AbstractCompensationForm, CompensationResponsibleFormMixin):
|
||||
""" Form for creating new EMA objects.
|
||||
|
||||
Inherits basic form fields from AbstractCompensationForm and additional from CompensationResponsibleFormMixin.
|
||||
Second holds self.instance.response related fields
|
||||
|
||||
"""
|
||||
field_order = [
|
||||
"identifier",
|
||||
"title",
|
||||
"conservation_office",
|
||||
"conservation_file_number",
|
||||
"handler",
|
||||
"fundings",
|
||||
"comment",
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.form_title = _("New EMA")
|
||||
|
||||
self.action_url = reverse("ema:new")
|
||||
self.cancel_redirect = reverse("ema:index")
|
||||
|
||||
tmp = Ema()
|
||||
identifier = tmp.generate_new_identifier()
|
||||
self.initialize_form_field("identifier", identifier)
|
||||
self.fields["identifier"].widget.attrs["url"] = reverse_lazy("ema:new-id")
|
||||
self.fields["title"].widget.attrs["placeholder"] = _("Compensation XY; Location ABC")
|
||||
|
||||
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)
|
||||
fundings = self.cleaned_data.get("fundings", None)
|
||||
handler = self.cleaned_data.get("handler", None)
|
||||
conservation_office = self.cleaned_data.get("conservation_office", None)
|
||||
conservation_file_number = self.cleaned_data.get("conservation_file_number", None)
|
||||
comment = self.cleaned_data.get("comment", None)
|
||||
|
||||
# Create log entry
|
||||
action = UserActionLogEntry.objects.create(
|
||||
user=user,
|
||||
action=UserAction.CREATED,
|
||||
)
|
||||
# Process the geometry form
|
||||
geometry = geom_form.save(action)
|
||||
|
||||
responsible = ResponsibilityData.objects.create(
|
||||
handler=handler,
|
||||
conservation_file_number=conservation_file_number,
|
||||
conservation_office=conservation_office,
|
||||
)
|
||||
|
||||
# Finally create main object
|
||||
acc = Ema.objects.create(
|
||||
identifier=identifier,
|
||||
title=title,
|
||||
responsible=responsible,
|
||||
created=action,
|
||||
geometry=geometry,
|
||||
comment=comment,
|
||||
)
|
||||
acc.fundings.set(fundings)
|
||||
|
||||
# Add the creating user to the list of shared users
|
||||
acc.users.add(user)
|
||||
|
||||
# Add the log entry to the main objects log list
|
||||
acc.log.add(action)
|
||||
return acc
|
||||
|
||||
|
||||
class EditEmaForm(NewEmaForm):
|
||||
""" Form for editing EMAs
|
||||
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.form_title = _("Edit EMA")
|
||||
|
||||
self.action_url = reverse("ema:edit", args=(self.instance.id,))
|
||||
self.cancel_redirect = reverse("ema:open", args=(self.instance.id,))
|
||||
|
||||
self.fields["identifier"].widget.attrs["url"] = reverse_lazy("ema:new-id")
|
||||
self.fields["title"].widget.attrs["placeholder"] = _("Compensation XY; Location ABC")
|
||||
|
||||
# Initialize form data
|
||||
form_data = {
|
||||
"identifier": self.instance.identifier,
|
||||
"title": self.instance.title,
|
||||
"handler": self.instance.responsible.handler,
|
||||
"conservation_office": self.instance.responsible.conservation_office,
|
||||
"conservation_file_number": self.instance.responsible.conservation_file_number,
|
||||
"fundings": self.instance.fundings.all(),
|
||||
"comment": self.instance.comment,
|
||||
}
|
||||
disabled_fields = []
|
||||
self.load_initial_data(
|
||||
form_data,
|
||||
disabled_fields
|
||||
)
|
||||
|
||||
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)
|
||||
fundings = self.cleaned_data.get("fundings", None)
|
||||
handler = self.cleaned_data.get("handler", None)
|
||||
conservation_office = self.cleaned_data.get("conservation_office", None)
|
||||
conservation_file_number = self.cleaned_data.get("conservation_file_number", None)
|
||||
comment = self.cleaned_data.get("comment", None)
|
||||
|
||||
# Create log entry
|
||||
action = UserActionLogEntry.objects.create(
|
||||
user=user,
|
||||
action=UserAction.EDITED,
|
||||
)
|
||||
# Process the geometry form
|
||||
geometry = geom_form.save(action)
|
||||
|
||||
# Update responsible data
|
||||
self.instance.responsible.handler = handler
|
||||
self.instance.responsible.conservation_office = conservation_office
|
||||
self.instance.responsible.conservation_file_number = conservation_file_number
|
||||
self.instance.responsible.save()
|
||||
|
||||
# Update main oject data
|
||||
self.instance.identifier = identifier
|
||||
self.instance.title = title
|
||||
self.instance.geometry = geometry
|
||||
self.instance.comment = comment
|
||||
self.instance.modified = action
|
||||
self.instance.save()
|
||||
self.instance.fundings.set(fundings)
|
||||
|
||||
# Add the log entry to the main objects log list
|
||||
self.instance.log.add(action)
|
||||
return self.instance
|
@ -0,0 +1,6 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n l10n %}
|
||||
|
||||
{% block body %}
|
||||
{% include 'form/collapsable/form.html' %}
|
||||
{% endblock %}
|
@ -0,0 +1,359 @@
|
||||
"""
|
||||
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={
|
||||
"data-placeholder": _("Click for selection"),
|
||||
}
|
||||
),
|
||||
)
|
||||
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={
|
||||
"data-placeholder": _("Click for selection"),
|
||||
}
|
||||
),
|
||||
)
|
||||
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={
|
||||
"data-placeholder": _("Click for selection"),
|
||||
}
|
||||
),
|
||||
)
|
||||
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={
|
||||
"data-placeholder": _("Click for selection"),
|
||||
}
|
||||
),
|
||||
)
|
||||
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
|
||||
|
@ -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/widgets/empty-dummy-input.html"
|
||||
|
||||
|
||||
class TextToClipboardInput(forms.TextInput):
|
||||
template_name = "konova/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/widgets/generate-content-input.html"
|
@ -0,0 +1,23 @@
|
||||
{% load i18n fontawesome_5 %}
|
||||
|
||||
{% if intervention.comment %}
|
||||
<div class="w-100">
|
||||
<div class="card mt-3">
|
||||
<div class="card-header rlp-gd">
|
||||
<div class="row">
|
||||
<div class="col-sm-12 col-md-12 col-lg-12">
|
||||
<h5 class="card-title">
|
||||
{% fa5_icon 'info-circle' %}
|
||||
{% trans 'Comment' %}
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="card-text font-italic">
|
||||
{{intervention.comment}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
@ -0,0 +1,6 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load i18n l10n %}
|
||||
|
||||
{% block body %}
|
||||
{% include 'form/collapsable/form.html' %}
|
||||
{% endblock %}
|
@ -1,5 +0,0 @@
|
||||
|
||||
<form action="{{ form.action_url }}" method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
</form>
|
@ -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.
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,65 @@
|
||||
{% load i18n l10n fontawesome_5 %}
|
||||
<form method="post" action="{{ form.action_url }}" {% for attr_key, attr_val in form.form_attrs.items %} {{attr_key}}="{{attr_val}}"{% endfor %}>
|
||||
{% csrf_token %}
|
||||
<h2>{{form.form_title}}</h2>
|
||||
<div id="help" class="col">
|
||||
<div class="row rlp-gd-outline p-2">
|
||||
<div class="col-lg-1 rlp-r-inv">
|
||||
<span class="d-flex justify-content-center align-items-center h-100">
|
||||
{% fa5_icon 'question-circle' 'far' %}
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-lg-11">
|
||||
<small>
|
||||
{% blocktrans %}
|
||||
First enter the most basic data. Of course you can change everything later.
|
||||
All further data, like documents or further details, can be added in the detail view after saving
|
||||
your new entry.
|
||||
{% endblocktrans %}
|
||||
<br>
|
||||
{% trans 'Open the input topic with a simple click.' %}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-3">
|
||||
<div class="card">
|
||||
<div id="dataCardHeader" class="card-header cursor-pointer rlp-r" data-toggle="collapse" data-target="#dataCard" aria-expanded="true" aria-controls="dataCard">
|
||||
<h5>
|
||||
{% fa5_icon 'list' %}
|
||||
{% trans 'General data' %}
|
||||
</h5>
|
||||
</div>
|
||||
<div id="dataCard" class="collapse" aria-labelledby="dataCardHeader">
|
||||
<div class="card-body">
|
||||
{% include 'form/table/generic_table_form_body.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="">
|
||||
<div class="card">
|
||||
<div id="geometryCardHeader" class="card-header cursor-pointer rlp-r" data-toggle="collapse" data-target="#geometryCard" aria-expanded="true" aria-controls="geometryCard">
|
||||
<h5>
|
||||
{% fa5_icon 'map-marked-alt' %}
|
||||
{% trans 'Geometry' %}
|
||||
</h5>
|
||||
</div>
|
||||
<div id="geometryCard" class="collapse show" aria-labelledby="geometryCardHeader">
|
||||
<div class="card-body">
|
||||
{% include 'map/geom_form.html' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<a href="{{ form.cancel_redirect }}">
|
||||
<button class="btn btn-default" type="button" title="{% trans 'Cancel' %}">{% trans 'Cancel' %}</button>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-6 d-flex justify-content-end">
|
||||
<button class="btn btn-default" type="submit" title="{% trans 'Save' %}">{% trans 'Save' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
@ -1,5 +1,5 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block body %}
|
||||
{% include 'form/generic_table_form.html' %}
|
||||
{% include 'form/table/generic_table_form.html' %}
|
||||
{% endblock %}
|
Loading…
Reference in New Issue