* adds NewCompensationForm content and functionality
* renames CODELIST_COMPENSATION_COMBINATION_ID into CODELIST_COMPENSATION_FUNDING_ID for more clarity
* reorganizes compensation forms into compensation/forms/forms.py and forms/modalForms.py
* adds new compensation html template in compensation/templates/compensation/new
* adds new default message template in message_templates.py: IDENTIFIER_REPLACED
* adds/updates translations
This commit is contained in:
mipel
2021-10-04 09:55:59 +02:00
parent a44c014f4b
commit b7ef6ff006
17 changed files with 441 additions and 174 deletions

View File

@@ -12,6 +12,7 @@ urlpatterns = [
# Main compensation
path("", index_view, name="index"),
path('new', new_view, name='new'),
path('new/id', new_id_view, name='new-id'),
path('<id>', open_view, name='open'),
path('<id>/log', log_view, name='log'),
path('<id>/edit', edit_view, name='edit'),

136
compensation/forms/forms.py Normal file
View File

@@ -0,0 +1,136 @@
"""
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
from compensation.models import Compensation
from intervention.inputs import GenerateInput
from intervention.models import Intervention
from konova.forms import BaseForm, SimpleGeomForm
from user.models import UserActionLogEntry, UserAction
class NewCompensationForm(BaseForm):
identifier = forms.CharField(
label=_("Identifier"),
label_suffix="",
max_length=255,
help_text=_("Generated automatically"),
widget=GenerateInput(
attrs={
"class": "form-control",
"url": reverse_lazy("compensation:new-id"),
}
)
)
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",
}
)
)
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": _("Intervention"),
"data-minimum-input-length": 3,
}
),
)
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": _("Funding by..."),
}
),
)
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 compensation")
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)
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

View File

@@ -2,7 +2,7 @@
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 04.12.20
Created on: 04.10.21
"""
from bootstrap_modal_forms.utils import is_ajax
@@ -12,34 +12,22 @@ from django.contrib import messages
from django.db import transaction
from django.http import HttpRequest, HttpResponseRedirect
from django.shortcuts import render
from django.utils.translation import gettext_lazy as _
from django.utils.translation import pgettext_lazy as _con
from django.utils.translation import pgettext_lazy as _con, gettext_lazy as _
from codelist.models import KonovaCode
from codelist.settings import CODELIST_BIOTOPES_ID, CODELIST_COMPENSATION_ACTION_ID
from compensation.models import Payment, CompensationState, CompensationAction, UnitChoices
from compensation.models import Payment, CompensationState, UnitChoices, CompensationAction
from konova.contexts import BaseContext
from konova.forms import BaseForm, BaseModalForm
from konova.models import Deadline, DeadlineType
from konova.forms import BaseModalForm
from konova.models import DeadlineType, Deadline
from konova.utils.message_templates import FORM_INVALID
from user.models import UserActionLogEntry, UserAction
class NewCompensationForm(BaseForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def save(self):
with transaction.atomic():
user_action = UserActionLogEntry.objects.create(
user=self.user,
action=UserAction.CREATED
)
# Save action to log
class NewPaymentForm(BaseModalForm):
""" Form handling payment related input
"""
amount = forms.DecimalField(
min_value=0.00,
decimal_places=2,
@@ -135,6 +123,12 @@ class NewPaymentForm(BaseModalForm):
class NewStateModalForm(BaseModalForm):
""" Form handling state related input
Compensation states refer to 'before' and 'after' states of a compensated surface. Basically it means:
What has been on this area before changes/compensations have been applied and what will be the result ('after')?
"""
biotope_type = forms.ModelChoiceField(
label=_("Biotope Type"),
label_suffix="",
@@ -243,6 +237,9 @@ class NewStateModalForm(BaseModalForm):
class NewDeadlineModalForm(BaseModalForm):
""" Form handling deadline related input
"""
type = forms.ChoiceField(
label=_("Deadline Type"),
label_suffix="",
@@ -314,6 +311,13 @@ class NewDeadlineModalForm(BaseModalForm):
class NewActionModalForm(BaseModalForm):
""" Form handling action related input
Compensation actions are the actions performed on the area, which shall be compensated. Actions will change the
surface of the area, the biotopes, and have an environmental impact. With actions the before-after states can change
(not in the process logic in Konova, but in the real world).
"""
action_type = forms.ModelChoiceField(
label=_("Action Type"),
label_suffix="",
@@ -398,5 +402,4 @@ class NewActionModalForm(BaseModalForm):
self.instance.save()
self.instance.log.add(edited_action)
self.instance.actions.add(comp_action)
return comp_action
return comp_action

View File

@@ -16,7 +16,7 @@ from django.utils.translation import gettext_lazy as _
from codelist.models import KonovaCode
from codelist.settings import CODELIST_COMPENSATION_ACTION_ID, CODELIST_BIOTOPES_ID, \
CODELIST_COMPENSATION_COMBINATION_ID
CODELIST_COMPENSATION_FUNDING_ID
from intervention.models import Intervention, ResponsibilityData
from konova.models import BaseObject, BaseResource, Geometry, UuidModel, AbstractDocument, \
generate_document_file_upload_path
@@ -144,7 +144,7 @@ class AbstractCompensation(BaseObject):
null=True,
blank=True,
limit_choices_to={
"code_lists__in": [CODELIST_COMPENSATION_COMBINATION_ID],
"code_lists__in": [CODELIST_COMPENSATION_FUNDING_ID],
"is_selectable": True,
"is_archived": False,
},

View File

@@ -0,0 +1,16 @@
{% extends 'base.html' %}
{% load i18n l10n %}
{% block head %}
{% comment %}
dal documentation (django-autocomplete-light) states using form.media for adding needed scripts.
This does not work properly with modal forms, as the scripts are not loaded properly inside the modal.
Therefore the script linkages from form.media have been extracted and put inside dal/scripts.html to ensure
these scripts are loaded when needed.
{% endcomment %}
{% include 'dal/scripts.html' %}
{% endblock %}
{% block body %}
{% include 'form/main_data_collapse_form.html' %}
{% endblock %}

View File

@@ -1,16 +1,18 @@
from django.contrib.auth.decorators import login_required
from django.db.models import Sum
from django.http import HttpRequest
from django.http import HttpRequest, JsonResponse
from django.shortcuts import render, get_object_or_404
from django.utils.translation import gettext_lazy as _
from compensation.forms import NewStateModalForm, NewDeadlineModalForm, NewActionModalForm
from compensation.forms.forms import NewCompensationForm
from compensation.forms.modalForms import NewStateModalForm, NewDeadlineModalForm, NewActionModalForm
from compensation.models import Compensation, CompensationState, CompensationAction, CompensationDocument
from compensation.tables import CompensationTable
from konova.contexts import BaseContext
from konova.decorators import *
from konova.forms import RemoveModalForm, SimpleGeomForm, NewDocumentForm
from konova.utils.documents import get_document, remove_document
from konova.utils.message_templates import FORM_INVALID, IDENTIFIER_REPLACED
from konova.utils.user_checks import in_group
@@ -45,8 +47,62 @@ def index_view(request: HttpRequest):
@login_required
@default_group_required
def new_view(request: HttpRequest):
# ToDo
pass
"""
Renders a view for a new compensation creation
Args:
request (HttpRequest): The incoming request
Returns:
"""
template = "compensation/new/view.html"
data_form = NewCompensationForm(request.POST or None)
geom_form = SimpleGeomForm(request.POST or None, read_only=False)
if request.method == "POST":
if data_form.is_valid() and geom_form.is_valid():
generated_identifier = data_form.cleaned_data.get("identifier", None)
comp = data_form.save(request.user, geom_form)
if generated_identifier != comp.identifier:
messages.info(
request,
IDENTIFIER_REPLACED.format(
generated_identifier,
comp.identifier
)
)
messages.success(request, _("Compensation {} added").format(comp.identifier))
return redirect("compensation:open", id=comp.id)
else:
messages.error(request, FORM_INVALID)
else:
# For clarification: nothing in this case
pass
context = {
"form": data_form,
"geom_form": geom_form,
"url": reverse("compensation:new-id")
}
context = BaseContext(request, context).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 = Compensation()
identifier = tmp._generate_new_identifier()
while Compensation.objects.filter(identifier=identifier).exists():
identifier = tmp._generate_new_identifier()
return JsonResponse(
data={
"identifier": identifier
}
)
@login_required

View File

@@ -13,7 +13,7 @@ from django.core.exceptions import ObjectDoesNotExist
from django.http import HttpRequest, Http404
from django.shortcuts import render, get_object_or_404
from compensation.forms import NewStateModalForm, NewActionModalForm, NewDeadlineModalForm
from compensation.forms.modalForms import NewStateModalForm, NewActionModalForm, NewDeadlineModalForm
from compensation.models import EcoAccount, EcoAccountDocument
from compensation.tables import EcoAccountTable
from intervention.forms.modalForms import NewDeductionModalForm

View File

@@ -10,7 +10,7 @@ from django.contrib.auth.decorators import login_required
from django.http import HttpRequest
from django.shortcuts import get_object_or_404
from compensation.forms import NewPaymentForm
from compensation.forms.modalForms import NewPaymentForm
from compensation.models import Payment
from intervention.models import Intervention
from konova.decorators import default_group_required