From ea7a53eb4f370e7cca346fcb861ed625dc2391b3 Mon Sep 17 00:00:00 2001 From: mpeltriaux Date: Thu, 18 Aug 2022 09:54:49 +0200 Subject: [PATCH] Compensation forms refactoring * splits compensation/forms.py and /modalForms.py into individual files inside new packages * general forms stay in new files in compensation/forms * modal forms stay in new files in compensation/forms/modals --- compensation/forms/__init__.py | 7 + compensation/forms/compensation.py | 238 ++++++++ compensation/forms/eco_account.py | 212 +++++++ compensation/forms/forms.py | 539 ------------------ compensation/forms/mixins.py | 117 ++++ compensation/forms/modalForms.py | 534 ----------------- compensation/forms/modals/__init__.py | 7 + .../forms/modals/compensation_action.py | 155 +++++ compensation/forms/modals/deadline.py | 92 +++ compensation/forms/modals/document.py | 17 + compensation/forms/modals/payment.py | 136 +++++ compensation/forms/modals/state.py | 179 ++++++ compensation/views/compensation.py | 16 +- compensation/views/eco_account.py | 15 +- compensation/views/payment.py | 3 +- ema/forms.py | 4 +- ema/views.py | 12 +- 17 files changed, 1188 insertions(+), 1095 deletions(-) create mode 100644 compensation/forms/__init__.py create mode 100644 compensation/forms/compensation.py create mode 100644 compensation/forms/eco_account.py delete mode 100644 compensation/forms/forms.py create mode 100644 compensation/forms/mixins.py delete mode 100644 compensation/forms/modalForms.py create mode 100644 compensation/forms/modals/__init__.py create mode 100644 compensation/forms/modals/compensation_action.py create mode 100644 compensation/forms/modals/deadline.py create mode 100644 compensation/forms/modals/document.py create mode 100644 compensation/forms/modals/payment.py create mode 100644 compensation/forms/modals/state.py diff --git a/compensation/forms/__init__.py b/compensation/forms/__init__.py new file mode 100644 index 00000000..ca978536 --- /dev/null +++ b/compensation/forms/__init__.py @@ -0,0 +1,7 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: ksp-servicestelle@sgdnord.rlp.de +Created on: 18.08.22 + +""" diff --git a/compensation/forms/compensation.py b/compensation/forms/compensation.py new file mode 100644 index 00000000..1672e161 --- /dev/null +++ b/compensation/forms/compensation.py @@ -0,0 +1,238 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: ksp-servicestelle@sgdnord.rlp.de +Created on: 18.08.22 + +""" +from dal import autocomplete +from django import forms +from django.db import transaction +from django.urls import reverse, reverse_lazy +from django.utils.translation import gettext_lazy as _ + +from compensation.forms.mixins import CEFCompensationFormMixin, CoherenceCompensationFormMixin, PikCompensationFormMixin +from compensation.models import Compensation +from intervention.inputs import GenerateInput +from intervention.models import Intervention +from konova.forms import BaseForm, SimpleGeomForm +from konova.utils.message_templates import COMPENSATION_ADDED_TEMPLATE, EDITED_GENERAL_DATA +from user.models import UserActionLogEntry, User + + +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", + } + ) + ) + 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 NewCompensationForm(AbstractCompensationForm, + CEFCompensationFormMixin, + CoherenceCompensationFormMixin, + PikCompensationFormMixin): + """ 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", + "is_pik", + "is_cef", + "is_coherence_keeping", + "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:detail", 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 __create_comp(self, user, geom_form) -> Compensation: + """ Creates the compensation from form data + + Args: + user (User): The performing user + geom_form (SimpleGeomForm): The geometry form + + Returns: + comp (Compensation): The compensation object + """ + # Fetch data from cleaned POST values + identifier = self.cleaned_data.get("identifier", None) + title = self.cleaned_data.get("title", None) + intervention = self.cleaned_data.get("intervention", None) + is_cef = self.cleaned_data.get("is_cef", None) + is_coherence_keeping = self.cleaned_data.get("is_coherence_keeping", None) + is_pik = self.cleaned_data.get("is_pik", None) + comment = self.cleaned_data.get("comment", None) + + # Create log entry + action = UserActionLogEntry.get_created_action(user) + # 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, + is_cef=is_cef, + is_coherence_keeping=is_coherence_keeping, + is_pik=is_pik, + geometry=geometry, + comment=comment, + ) + + # Add the log entry to the main objects log list + comp.log.add(action) + return comp + + def save(self, user: User, geom_form: SimpleGeomForm): + with transaction.atomic(): + comp = self.__create_comp(user, geom_form) + comp.intervention.mark_as_edited(user, edit_comment=COMPENSATION_ADDED_TEMPLATE.format(comp.identifier)) + 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:detail", args=(self.instance.id,)) + + # Initialize form data + form_data = { + "identifier": self.instance.identifier, + "title": self.instance.title, + "intervention": self.instance.intervention, + "is_cef": self.instance.is_cef, + "is_coherence_keeping": self.instance.is_coherence_keeping, + "is_pik": self.instance.is_pik, + "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) + intervention = self.cleaned_data.get("intervention", None) + is_cef = self.cleaned_data.get("is_cef", None) + is_coherence_keeping = self.cleaned_data.get("is_coherence_keeping", None) + is_pik = self.cleaned_data.get("is_pik", None) + comment = self.cleaned_data.get("comment", None) + + # Create log entry + action = UserActionLogEntry.get_edited_action(user) + + # 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.is_cef = is_cef + self.instance.is_coherence_keeping = is_coherence_keeping + self.instance.comment = comment + self.instance.is_pik = is_pik + self.instance.modified = action + self.instance.save() + + self.instance.log.add(action) + + intervention.mark_as_edited(user, self.request, EDITED_GENERAL_DATA) + return self.instance \ No newline at end of file diff --git a/compensation/forms/eco_account.py b/compensation/forms/eco_account.py new file mode 100644 index 00000000..6bc12618 --- /dev/null +++ b/compensation/forms/eco_account.py @@ -0,0 +1,212 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: ksp-servicestelle@sgdnord.rlp.de +Created on: 18.08.22 + +""" +from django import forms +from django.db import transaction +from django.urls import reverse, reverse_lazy +from django.utils.translation import gettext_lazy as _ +from compensation.forms.compensation import AbstractCompensationForm +from compensation.forms.mixins import CompensationResponsibleFormMixin, PikCompensationFormMixin +from compensation.models import EcoAccount +from intervention.models import Handler, Responsibility, Legal +from konova.forms import SimpleGeomForm +from user.models import User, UserActionLogEntry + + +class NewEcoAccountForm(AbstractCompensationForm, CompensationResponsibleFormMixin, PikCompensationFormMixin): + """ Form for creating eco accounts + + Inherits from basic AbstractCompensationForm and further form fields from CompensationResponsibleFormMixin + + """ + surface = forms.DecimalField( + min_value=0.00, + decimal_places=2, + label=_("Available Surface"), + label_suffix="", + required=False, + help_text=_("The amount that can be used for deductions"), + widget=forms.NumberInput( + attrs={ + "class": "form-control", + "placeholder": "0,00" + } + ) + ) + registration_date = forms.DateField( + label=_("Agreement date"), + label_suffix="", + help_text=_("When did the parties agree on this?"), + required=False, + widget=forms.DateInput( + attrs={ + "type": "date", + "class": "form-control", + }, + format="%d.%m.%Y" + ) + ) + + field_order = [ + "identifier", + "title", + "conservation_office", + "registration_date", + "surface", + "conservation_file_number", + "is_pik", + "handler_type", + "handler_detail", + "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) + registration_date = self.cleaned_data.get("registration_date", None) + handler_type = self.cleaned_data.get("handler_type", None) + handler_detail = self.cleaned_data.get("handler_detail", 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) + is_pik = self.cleaned_data.get("is_pik", None) + comment = self.cleaned_data.get("comment", None) + + # Create log entry + action = UserActionLogEntry.get_created_action(user) + # Process the geometry form + geometry = geom_form.save(action) + + handler = Handler.objects.create( + type=handler_type, + detail=handler_detail, + ) + + responsible = Responsibility.objects.create( + handler=handler, + conservation_file_number=conservation_file_number, + conservation_office=conservation_office, + ) + + legal = Legal.objects.create( + registration_date=registration_date + ) + + # Finally create main object + acc = EcoAccount.objects.create( + identifier=identifier, + title=title, + responsible=responsible, + deductable_surface=surface, + created=action, + geometry=geometry, + comment=comment, + is_pik=is_pik, + legal=legal + ) + acc.share_with_user(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 + + """ + + 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:detail", args=(self.instance.id,)) + + # Initialize form data + reg_date = self.instance.legal.registration_date + if reg_date is not None: + reg_date = reg_date.isoformat() + + form_data = { + "identifier": self.instance.identifier, + "title": self.instance.title, + "surface": self.instance.deductable_surface, + "handler_type": self.instance.responsible.handler.type, + "handler_detail": self.instance.responsible.handler.detail, + "registration_date": reg_date, + "conservation_office": self.instance.responsible.conservation_office, + "conservation_file_number": self.instance.responsible.conservation_file_number, + "is_pik": self.instance.is_pik, + "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) + registration_date = self.cleaned_data.get("registration_date", None) + handler_type = self.cleaned_data.get("handler_type", None) + handler_detail = self.cleaned_data.get("handler_detail", 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) + is_pik = self.cleaned_data.get("is_pik", None) + + # Create log entry + action = UserActionLogEntry.get_edited_action(user) + + # Process the geometry form + geometry = geom_form.save(action) + + # Update responsible data + self.instance.responsible.handler.type = handler_type + self.instance.responsible.handler.detail = handler_detail + self.instance.responsible.handler.save() + self.instance.responsible.conservation_office = conservation_office + self.instance.responsible.conservation_file_number = conservation_file_number + self.instance.responsible.save() + + # Update legal data + self.instance.legal.registration_date = registration_date + self.instance.legal.save() + + # Update main oject data + self.instance.identifier = identifier + self.instance.title = title + self.instance.deductable_surface = surface + self.instance.geometry = geometry + self.instance.comment = comment + self.instance.is_pik = is_pik + self.instance.modified = action + self.instance.save() + + # Add the log entry to the main objects log list + self.instance.log.add(action) + return self.instance diff --git a/compensation/forms/forms.py b/compensation/forms/forms.py deleted file mode 100644 index 8f28c5ff..00000000 --- a/compensation/forms/forms.py +++ /dev/null @@ -1,539 +0,0 @@ -""" -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 user.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_CONSERVATION_OFFICE_ID, CODELIST_HANDLER_ID -from compensation.models import Compensation, EcoAccount -from intervention.inputs import GenerateInput -from intervention.models import Intervention, Responsibility, Legal, Handler -from konova.forms import BaseForm, SimpleGeomForm -from konova.utils.message_templates import EDITED_GENERAL_DATA, COMPENSATION_ADDED_TEMPLATE -from user.models import UserActionLogEntry - - -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", - } - ) - ) - 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_type = forms.ModelChoiceField( - label=_("Eco-Account handler type"), - label_suffix="", - help_text=_("What type of handler is responsible for the ecoaccount?"), - required=False, - queryset=KonovaCode.objects.filter( - is_archived=False, - is_leaf=True, - code_lists__in=[CODELIST_HANDLER_ID], - ), - widget=autocomplete.ModelSelect2( - url="codes-handler-autocomplete", - attrs={ - "data-placeholder": _("Click for selection"), - } - ), - ) - handler_detail = forms.CharField( - label=_("Eco-Account handler detail"), - label_suffix="", - max_length=255, - required=False, - help_text=_("Detail input on the handler"), - widget=forms.TextInput( - attrs={ - "placeholder": _("Company Mustermann"), - "class": "form-control", - } - ) - ) - - -class CEFCompensationFormMixin(forms.Form): - """ A form mixin, providing CEF compensation field - - """ - is_cef = forms.BooleanField( - label_suffix="", - label=_("Is CEF"), - help_text=_("Optionally: Whether this compensation is a CEF compensation?"), - required=False, - widget=forms.CheckboxInput() - ) - - -class CoherenceCompensationFormMixin(forms.Form): - """ A form mixin, providing coherence compensation field - - """ - is_coherence_keeping = forms.BooleanField( - label_suffix="", - label=_("Is coherence keeping"), - help_text=_("Optionally: Whether this compensation is a coherence keeping compensation?"), - required=False, - widget=forms.CheckboxInput() - ) - - -class PikCompensationFormMixin(forms.Form): - """ A form mixin, providing PIK compensation field - - """ - is_pik = forms.BooleanField( - label_suffix="", - label=_("Is PIK"), - help_text=_("Optionally: Whether this compensation is a compensation integrated in production?"), - required=False, - widget=forms.CheckboxInput() - ) - - -class NewCompensationForm(AbstractCompensationForm, - CEFCompensationFormMixin, - CoherenceCompensationFormMixin, - PikCompensationFormMixin): - """ 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", - "is_pik", - "is_cef", - "is_coherence_keeping", - "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:detail", 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 __create_comp(self, user, geom_form) -> Compensation: - """ Creates the compensation from form data - - Args: - user (User): The performing user - geom_form (SimpleGeomForm): The geometry form - - Returns: - comp (Compensation): The compensation object - """ - # Fetch data from cleaned POST values - identifier = self.cleaned_data.get("identifier", None) - title = self.cleaned_data.get("title", None) - intervention = self.cleaned_data.get("intervention", None) - is_cef = self.cleaned_data.get("is_cef", None) - is_coherence_keeping = self.cleaned_data.get("is_coherence_keeping", None) - is_pik = self.cleaned_data.get("is_pik", None) - comment = self.cleaned_data.get("comment", None) - - # Create log entry - action = UserActionLogEntry.get_created_action(user) - # 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, - is_cef=is_cef, - is_coherence_keeping=is_coherence_keeping, - is_pik=is_pik, - geometry=geometry, - comment=comment, - ) - - # Add the log entry to the main objects log list - comp.log.add(action) - return comp - - def save(self, user: User, geom_form: SimpleGeomForm): - with transaction.atomic(): - comp = self.__create_comp(user, geom_form) - comp.intervention.mark_as_edited(user, edit_comment=COMPENSATION_ADDED_TEMPLATE.format(comp.identifier)) - 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:detail", args=(self.instance.id,)) - - # Initialize form data - form_data = { - "identifier": self.instance.identifier, - "title": self.instance.title, - "intervention": self.instance.intervention, - "is_cef": self.instance.is_cef, - "is_coherence_keeping": self.instance.is_coherence_keeping, - "is_pik": self.instance.is_pik, - "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) - intervention = self.cleaned_data.get("intervention", None) - is_cef = self.cleaned_data.get("is_cef", None) - is_coherence_keeping = self.cleaned_data.get("is_coherence_keeping", None) - is_pik = self.cleaned_data.get("is_pik", None) - comment = self.cleaned_data.get("comment", None) - - # Create log entry - action = UserActionLogEntry.get_edited_action(user) - - # 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.is_cef = is_cef - self.instance.is_coherence_keeping = is_coherence_keeping - self.instance.comment = comment - self.instance.is_pik = is_pik - self.instance.modified = action - self.instance.save() - - self.instance.log.add(action) - - intervention.mark_as_edited(user, self.request, EDITED_GENERAL_DATA) - return self.instance - - -class NewEcoAccountForm(AbstractCompensationForm, CompensationResponsibleFormMixin, PikCompensationFormMixin): - """ Form for creating eco accounts - - Inherits from basic AbstractCompensationForm and further form fields from CompensationResponsibleFormMixin - - """ - surface = forms.DecimalField( - min_value=0.00, - decimal_places=2, - label=_("Available Surface"), - label_suffix="", - required=False, - help_text=_("The amount that can be used for deductions"), - widget=forms.NumberInput( - attrs={ - "class": "form-control", - "placeholder": "0,00" - } - ) - ) - registration_date = forms.DateField( - label=_("Agreement date"), - label_suffix="", - help_text=_("When did the parties agree on this?"), - required=False, - widget=forms.DateInput( - attrs={ - "type": "date", - "class": "form-control", - }, - format="%d.%m.%Y" - ) - ) - - field_order = [ - "identifier", - "title", - "conservation_office", - "registration_date", - "surface", - "conservation_file_number", - "is_pik", - "handler_type", - "handler_detail", - "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) - registration_date = self.cleaned_data.get("registration_date", None) - handler_type = self.cleaned_data.get("handler_type", None) - handler_detail = self.cleaned_data.get("handler_detail", 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) - is_pik = self.cleaned_data.get("is_pik", None) - comment = self.cleaned_data.get("comment", None) - - # Create log entry - action = UserActionLogEntry.get_created_action(user) - # Process the geometry form - geometry = geom_form.save(action) - - handler = Handler.objects.create( - type=handler_type, - detail=handler_detail, - ) - - responsible = Responsibility.objects.create( - handler=handler, - conservation_file_number=conservation_file_number, - conservation_office=conservation_office, - ) - - legal = Legal.objects.create( - registration_date=registration_date - ) - - # Finally create main object - acc = EcoAccount.objects.create( - identifier=identifier, - title=title, - responsible=responsible, - deductable_surface=surface, - created=action, - geometry=geometry, - comment=comment, - is_pik=is_pik, - legal=legal - ) - acc.share_with_user(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 - - """ - - 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:detail", args=(self.instance.id,)) - - # Initialize form data - reg_date = self.instance.legal.registration_date - if reg_date is not None: - reg_date = reg_date.isoformat() - - form_data = { - "identifier": self.instance.identifier, - "title": self.instance.title, - "surface": self.instance.deductable_surface, - "handler_type": self.instance.responsible.handler.type, - "handler_detail": self.instance.responsible.handler.detail, - "registration_date": reg_date, - "conservation_office": self.instance.responsible.conservation_office, - "conservation_file_number": self.instance.responsible.conservation_file_number, - "is_pik": self.instance.is_pik, - "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) - registration_date = self.cleaned_data.get("registration_date", None) - handler_type = self.cleaned_data.get("handler_type", None) - handler_detail = self.cleaned_data.get("handler_detail", 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) - is_pik = self.cleaned_data.get("is_pik", None) - - # Create log entry - action = UserActionLogEntry.get_edited_action(user) - - # Process the geometry form - geometry = geom_form.save(action) - - # Update responsible data - self.instance.responsible.handler.type = handler_type - self.instance.responsible.handler.detail = handler_detail - self.instance.responsible.handler.save() - self.instance.responsible.conservation_office = conservation_office - self.instance.responsible.conservation_file_number = conservation_file_number - self.instance.responsible.save() - - # Update legal data - self.instance.legal.registration_date = registration_date - self.instance.legal.save() - - # Update main oject data - self.instance.identifier = identifier - self.instance.title = title - self.instance.deductable_surface = surface - self.instance.geometry = geometry - self.instance.comment = comment - self.instance.is_pik = is_pik - self.instance.modified = action - self.instance.save() - - # Add the log entry to the main objects log list - self.instance.log.add(action) - return self.instance diff --git a/compensation/forms/mixins.py b/compensation/forms/mixins.py new file mode 100644 index 00000000..db174808 --- /dev/null +++ b/compensation/forms/mixins.py @@ -0,0 +1,117 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: ksp-servicestelle@sgdnord.rlp.de +Created on: 18.08.22 + +""" +from dal import autocomplete +from django import forms +from django.utils.translation import gettext_lazy as _ + +from codelist.models import KonovaCode +from codelist.settings import CODELIST_CONSERVATION_OFFICE_ID, CODELIST_HANDLER_ID + + +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_type = forms.ModelChoiceField( + label=_("Eco-Account handler type"), + label_suffix="", + help_text=_("What type of handler is responsible for the ecoaccount?"), + required=False, + queryset=KonovaCode.objects.filter( + is_archived=False, + is_leaf=True, + code_lists__in=[CODELIST_HANDLER_ID], + ), + widget=autocomplete.ModelSelect2( + url="codes-handler-autocomplete", + attrs={ + "data-placeholder": _("Click for selection"), + } + ), + ) + handler_detail = forms.CharField( + label=_("Eco-Account handler detail"), + label_suffix="", + max_length=255, + required=False, + help_text=_("Detail input on the handler"), + widget=forms.TextInput( + attrs={ + "placeholder": _("Company Mustermann"), + "class": "form-control", + } + ) + ) + + +class CEFCompensationFormMixin(forms.Form): + """ A form mixin, providing CEF compensation field + + """ + is_cef = forms.BooleanField( + label_suffix="", + label=_("Is CEF"), + help_text=_("Optionally: Whether this compensation is a CEF compensation?"), + required=False, + widget=forms.CheckboxInput() + ) + + +class CoherenceCompensationFormMixin(forms.Form): + """ A form mixin, providing coherence compensation field + + """ + is_coherence_keeping = forms.BooleanField( + label_suffix="", + label=_("Is coherence keeping"), + help_text=_("Optionally: Whether this compensation is a coherence keeping compensation?"), + required=False, + widget=forms.CheckboxInput() + ) + + +class PikCompensationFormMixin(forms.Form): + """ A form mixin, providing PIK compensation field + + """ + is_pik = forms.BooleanField( + label_suffix="", + label=_("Is PIK"), + help_text=_("Optionally: Whether this compensation is a compensation integrated in production?"), + required=False, + widget=forms.CheckboxInput() + ) \ No newline at end of file diff --git a/compensation/forms/modalForms.py b/compensation/forms/modalForms.py deleted file mode 100644 index ef21aa3f..00000000 --- a/compensation/forms/modalForms.py +++ /dev/null @@ -1,534 +0,0 @@ -""" -Author: Michel Peltriaux -Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany -Contact: michel.peltriaux@sgdnord.rlp.de -Created on: 04.10.21 - -""" -from bootstrap_modal_forms.utils import is_ajax -from dal import autocomplete -from django import forms -from django.contrib import messages -from django.http import HttpRequest, HttpResponseRedirect -from django.shortcuts import render -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, CODELIST_BIOTOPES_EXTRA_CODES_ID, \ - CODELIST_COMPENSATION_ACTION_DETAIL_ID -from compensation.models import CompensationDocument, EcoAccountDocument -from intervention.inputs import CompensationActionTreeCheckboxSelectMultiple, \ - CompensationStateTreeRadioSelect -from konova.contexts import BaseContext -from konova.forms.modals import BaseModalForm, NewDocumentModalForm, RemoveModalForm -from konova.models import DeadlineType -from konova.utils.message_templates import FORM_INVALID, ADDED_COMPENSATION_STATE, \ - ADDED_COMPENSATION_ACTION, PAYMENT_EDITED, COMPENSATION_STATE_EDITED, COMPENSATION_ACTION_EDITED, DEADLINE_EDITED - - -class NewPaymentForm(BaseModalForm): - """ Form handling payment related input - - """ - amount = forms.DecimalField( - min_value=0.00, - decimal_places=2, - label=_con("money", "Amount"), # contextual translation - label_suffix=_(""), - help_text=_("in Euro"), - widget=forms.NumberInput( - attrs={ - "class": "form-control", - "placeholder": "0,00", - } - ) - ) - due = forms.DateField( - label=_("Due on"), - label_suffix=_(""), - required=False, - help_text=_("Due on which date"), - widget=forms.DateInput( - attrs={ - "type": "date", - "data-provide": "datepicker", - "class": "form-control", - }, - format="%d.%m.%Y" - ) - ) - comment = forms.CharField( - max_length=200, - required=False, - label=_("Comment"), - label_suffix=_(""), - help_text=_("Additional comment, maximum {} letters").format(200), - widget=forms.Textarea( - attrs={ - "rows": 5, - "class": "form-control" - } - ) - ) - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.intervention = self.instance - self.form_title = _("Payment") - self.form_caption = _("Add a payment for intervention '{}'").format(self.intervention.title) - - def is_valid(self): - """ - Checks on form validity. - - For this form we need to make sure that a date or a comment is set. - If both are missing, the user needs to enter at least an explanation why - there is no date to be entered. - - Returns: - is_valid (bool): True if valid, False otherwise - """ - super_valid = super().is_valid() - date = self.cleaned_data["due"] - comment = self.cleaned_data["comment"] or None - if not date and not comment: - # At least one needs to be set! - self.add_error( - "comment", - _("If there is no date you can enter, please explain why.") - ) - return False - return super_valid - - def save(self): - pay = self.instance.add_payment(self) - return pay - - -class EditPaymentModalForm(NewPaymentForm): - """ Form handling edit for Payment - - """ - payment = None - - def __init__(self, *args, **kwargs): - self.payment = kwargs.pop("payment", None) - super().__init__(*args, **kwargs) - self.form_title = _("Edit payment") - form_date = { - "amount": self.payment.amount, - "due": str(self.payment.due_on), - "comment": self.payment.comment, - } - self.load_initial_data(form_date, disabled_fields=[]) - - def save(self): - payment = self.payment - payment.amount = self.cleaned_data.get("amount", None) - payment.due_on = self.cleaned_data.get("due", None) - payment.comment = self.cleaned_data.get("comment", None) - payment.save() - self.instance.mark_as_edited(self.user, self.request, edit_comment=PAYMENT_EDITED) - self.instance.send_data_to_egon() - return payment - - -class RemovePaymentModalForm(RemoveModalForm): - """ Removing modal form for Payment - - Can be used for anything, where removing shall be confirmed by the user a second time. - - """ - payment = None - - def __init__(self, *args, **kwargs): - payment = kwargs.pop("payment", None) - self.payment = payment - super().__init__(*args, **kwargs) - - def save(self): - self.instance.remove_payment(self) - - -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.ChoiceField( - label=_("Biotope Type"), - label_suffix="", - required=True, - help_text=_("Select the biotope type"), - widget=CompensationStateTreeRadioSelect(), - ) - biotope_extra = forms.ModelMultipleChoiceField( - label=_("Biotope additional type"), - label_suffix="", - required=False, - help_text=_("Select an additional biotope type"), - queryset=KonovaCode.objects.filter( - is_archived=False, - is_leaf=True, - code_lists__in=[CODELIST_BIOTOPES_EXTRA_CODES_ID], - ), - widget=autocomplete.ModelSelect2Multiple( - url="codes-biotope-extra-type-autocomplete", - attrs={ - "data-placeholder": _("Biotope additional type"), - } - ), - ) - surface = forms.DecimalField( - min_value=0.00, - decimal_places=2, - label=_("Surface"), - label_suffix="", - required=True, - help_text=_("in m²"), - widget=forms.NumberInput( - attrs={ - "class": "form-control", - "placeholder": "0,00" - } - ) - ) - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.form_title = _("New state") - self.form_caption = _("Insert data for the new state") - choices = KonovaCode.objects.filter( - code_lists__in=[CODELIST_BIOTOPES_ID], - is_archived=False, - is_leaf=True, - ).values_list("id", flat=True) - choices = [ - (choice, choice) - for choice in choices - ] - self.fields["biotope_type"].choices = choices - - def save(self, is_before_state: bool = False): - state = self.instance.add_state(self, is_before_state) - self.instance.mark_as_edited(self.user, self.request, ADDED_COMPENSATION_STATE) - return state - - def process_request(self, request: HttpRequest, msg_success: str = _("Object removed"), msg_error: str = FORM_INVALID, redirect_url: str = None): - """ Generic processing of request - - Wraps the request processing logic, so we don't need the same code everywhere a RemoveModalForm is being used - - +++ - The generic method from super class can not be used, since we need to do some request parameter check in here. - +++ - - Args: - request (HttpRequest): The incoming request - msg_success (str): The message in case of successful removing - msg_error (str): The message in case of an error - - Returns: - - """ - redirect_url = redirect_url if redirect_url is not None else request.META.get("HTTP_REFERER", "home") - template = self.template - if request.method == "POST": - if self.is_valid(): - # Modal forms send one POST for checking on data validity. This can be used to return possible errors - # on the form. A second POST (if no errors occured) is sent afterwards and needs to process the - # saving/commiting of the data to the database. is_ajax() performs this check. The first request is - # an ajax call, the second is a regular form POST. - if not is_ajax(request.META): - is_before_state = bool(request.GET.get("before", False)) - self.save(is_before_state=is_before_state) - messages.success( - request, - msg_success - ) - return HttpResponseRedirect(redirect_url) - else: - context = { - "form": self, - } - context = BaseContext(request, context).context - return render(request, template, context) - elif request.method == "GET": - context = { - "form": self, - } - context = BaseContext(request, context).context - return render(request, template, context) - else: - raise NotImplementedError - - -class EditCompensationStateModalForm(NewStateModalForm): - state = None - - def __init__(self, *args, **kwargs): - self.state = kwargs.pop("state", None) - super().__init__(*args, **kwargs) - self.form_title = _("Edit state") - biotope_type_id = self.state.biotope_type.id if self.state.biotope_type else None - form_data = { - "biotope_type": biotope_type_id, - "biotope_extra": self.state.biotope_type_details.all(), - "surface": self.state.surface, - } - self.load_initial_data(form_data) - - def save(self, is_before_state: bool = False): - state = self.state - biotope_type_id = self.cleaned_data.get("biotope_type", None) - state.biotope_type = KonovaCode.objects.get(id=biotope_type_id) - state.biotope_type_details.set(self.cleaned_data.get("biotope_extra", [])) - state.surface = self.cleaned_data.get("surface", None) - state.save() - self.instance.mark_as_edited(self.user, self.request, edit_comment=COMPENSATION_STATE_EDITED) - return state - - -class RemoveCompensationStateModalForm(RemoveModalForm): - """ Removing modal form for CompensationState - - Can be used for anything, where removing shall be confirmed by the user a second time. - - """ - state = None - - def __init__(self, *args, **kwargs): - state = kwargs.pop("state", None) - self.state = state - super().__init__(*args, **kwargs) - - def save(self): - self.instance.remove_state(self) - - -class RemoveCompensationActionModalForm(RemoveModalForm): - """ Removing modal form for CompensationAction - - Can be used for anything, where removing shall be confirmed by the user a second time. - - """ - action = None - - def __init__(self, *args, **kwargs): - action = kwargs.pop("action", None) - self.action = action - super().__init__(*args, **kwargs) - - def save(self): - self.instance.remove_action(self) - - -class NewDeadlineModalForm(BaseModalForm): - """ Form handling deadline related input - - """ - type = forms.ChoiceField( - label=_("Deadline Type"), - label_suffix="", - required=True, - help_text=_("Select the deadline type"), - choices=DeadlineType.choices, - widget=forms.Select( - attrs={ - "class": "form-control" - } - ) - ) - date = forms.DateField( - label=_("Date"), - label_suffix="", - required=True, - help_text=_("Select date"), - widget=forms.DateInput( - attrs={ - "type": "date", - "data-provide": "datepicker", - "class": "form-control", - }, - format="%d.%m.%Y" - ) - ) - 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 = _("New deadline") - self.form_caption = _("Insert data for the new deadline") - - def save(self): - deadline = self.instance.add_deadline(self) - return deadline - - -class EditDeadlineModalForm(NewDeadlineModalForm): - deadline = None - - def __init__(self, *args, **kwargs): - self.deadline = kwargs.pop("deadline", None) - super().__init__(*args, **kwargs) - self.form_title = _("Edit deadline") - form_data = { - "type": self.deadline.type, - "date": str(self.deadline.date), - "comment": self.deadline.comment, - } - self.load_initial_data(form_data) - - def save(self): - deadline = self.deadline - deadline.type = self.cleaned_data.get("type", None) - deadline.date = self.cleaned_data.get("date", None) - deadline.comment = self.cleaned_data.get("comment", None) - deadline.save() - self.instance.mark_as_edited(self.user, self.request, edit_comment=DEADLINE_EDITED) - return deadline - - -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). - - """ - from compensation.models import UnitChoices - action_type = forms.MultipleChoiceField( - label=_("Action Type"), - label_suffix="", - required=True, - help_text=_("An action can consist of multiple different action types. All the selected action types are expected to be performed according to the amount and unit below on this form."), - choices=[], - widget=CompensationActionTreeCheckboxSelectMultiple(), - ) - action_type_details = forms.ModelMultipleChoiceField( - label=_("Action Type detail"), - label_suffix="", - required=False, - help_text=_("Select the action type detail"), - queryset=KonovaCode.objects.filter( - is_archived=False, - is_leaf=True, - code_lists__in=[CODELIST_COMPENSATION_ACTION_DETAIL_ID], - ), - widget=autocomplete.ModelSelect2Multiple( - url="codes-compensation-action-detail-autocomplete", - attrs={ - "data-placeholder": _("Action Type detail"), - } - ), - ) - unit = forms.ChoiceField( - label=_("Unit"), - label_suffix="", - required=True, - help_text=_("Select the unit"), - choices=UnitChoices.choices, - widget=forms.Select( - attrs={ - "class": "form-control" - } - ) - ) - amount = forms.DecimalField( - label=_("Amount"), - label_suffix="", - required=True, - help_text=_("Insert the amount"), - decimal_places=2, - min_value=0.00, - widget=forms.NumberInput( - attrs={ - "class": "form-control", - "placeholder": "0,00", - } - ) - ) - comment = forms.CharField( - required=False, - label=_("Comment"), - label_suffix=_(""), - 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 action") - self.form_caption = _("Insert data for the new action") - choices =KonovaCode.objects.filter( - code_lists__in=[CODELIST_COMPENSATION_ACTION_ID], - is_archived=False, - is_leaf=True, - ).values_list("id", flat=True) - choices = [ - (choice, choice) - for choice in choices - ] - self.fields["action_type"].choices = choices - - def save(self): - action = self.instance.add_action(self) - self.instance.mark_as_edited(self.user, self.request, ADDED_COMPENSATION_ACTION) - return action - - -class EditCompensationActionModalForm(NewActionModalForm): - action = None - - def __init__(self, *args, **kwargs): - self.action = kwargs.pop("action", None) - super().__init__(*args, **kwargs) - self.form_title = _("Edit action") - form_data = { - "action_type": list(self.action.action_type.values_list("id", flat=True)), - "action_type_details": self.action.action_type_details.all(), - "amount": self.action.amount, - "unit": self.action.unit, - "comment": self.action.comment, - } - self.load_initial_data(form_data) - - def save(self): - action = self.action - action.action_type.set(self.cleaned_data.get("action_type", [])) - action.action_type_details.set(self.cleaned_data.get("action_type_details", [])) - action.amount = self.cleaned_data.get("amount", None) - action.unit = self.cleaned_data.get("unit", None) - action.comment = self.cleaned_data.get("comment", None) - action.save() - self.instance.mark_as_edited(self.user, self.request, edit_comment=COMPENSATION_ACTION_EDITED) - return action - - -class NewCompensationDocumentModalForm(NewDocumentModalForm): - document_model = CompensationDocument - - -class NewEcoAccountDocumentModalForm(NewDocumentModalForm): - document_model = EcoAccountDocument \ No newline at end of file diff --git a/compensation/forms/modals/__init__.py b/compensation/forms/modals/__init__.py new file mode 100644 index 00000000..ca978536 --- /dev/null +++ b/compensation/forms/modals/__init__.py @@ -0,0 +1,7 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: ksp-servicestelle@sgdnord.rlp.de +Created on: 18.08.22 + +""" diff --git a/compensation/forms/modals/compensation_action.py b/compensation/forms/modals/compensation_action.py new file mode 100644 index 00000000..cc0bae15 --- /dev/null +++ b/compensation/forms/modals/compensation_action.py @@ -0,0 +1,155 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: ksp-servicestelle@sgdnord.rlp.de +Created on: 18.08.22 + +""" +from dal import autocomplete +from django import forms +from django.utils.translation import gettext_lazy as _ + +from codelist.models import KonovaCode +from codelist.settings import CODELIST_COMPENSATION_ACTION_ID, CODELIST_COMPENSATION_ACTION_DETAIL_ID +from intervention.inputs import CompensationActionTreeCheckboxSelectMultiple +from konova.forms.modals import BaseModalForm, RemoveModalForm +from konova.utils.message_templates import COMPENSATION_ACTION_EDITED, ADDED_COMPENSATION_ACTION + + +class NewCompensationActionModalForm(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). + + """ + from compensation.models import UnitChoices + action_type = forms.MultipleChoiceField( + label=_("Action Type"), + label_suffix="", + required=True, + help_text=_("An action can consist of multiple different action types. All the selected action types are expected to be performed according to the amount and unit below on this form."), + choices=[], + widget=CompensationActionTreeCheckboxSelectMultiple(), + ) + action_type_details = forms.ModelMultipleChoiceField( + label=_("Action Type detail"), + label_suffix="", + required=False, + help_text=_("Select the action type detail"), + queryset=KonovaCode.objects.filter( + is_archived=False, + is_leaf=True, + code_lists__in=[CODELIST_COMPENSATION_ACTION_DETAIL_ID], + ), + widget=autocomplete.ModelSelect2Multiple( + url="codes-compensation-action-detail-autocomplete", + attrs={ + "data-placeholder": _("Action Type detail"), + } + ), + ) + unit = forms.ChoiceField( + label=_("Unit"), + label_suffix="", + required=True, + help_text=_("Select the unit"), + choices=UnitChoices.choices, + widget=forms.Select( + attrs={ + "class": "form-control" + } + ) + ) + amount = forms.DecimalField( + label=_("Amount"), + label_suffix="", + required=True, + help_text=_("Insert the amount"), + decimal_places=2, + min_value=0.00, + widget=forms.NumberInput( + attrs={ + "class": "form-control", + "placeholder": "0,00", + } + ) + ) + comment = forms.CharField( + required=False, + label=_("Comment"), + label_suffix=_(""), + 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 action") + self.form_caption = _("Insert data for the new action") + choices =KonovaCode.objects.filter( + code_lists__in=[CODELIST_COMPENSATION_ACTION_ID], + is_archived=False, + is_leaf=True, + ).values_list("id", flat=True) + choices = [ + (choice, choice) + for choice in choices + ] + self.fields["action_type"].choices = choices + + def save(self): + action = self.instance.add_action(self) + self.instance.mark_as_edited(self.user, self.request, ADDED_COMPENSATION_ACTION) + return action + + +class EditCompensationActionModalForm(NewCompensationActionModalForm): + action = None + + def __init__(self, *args, **kwargs): + self.action = kwargs.pop("action", None) + super().__init__(*args, **kwargs) + self.form_title = _("Edit action") + form_data = { + "action_type": list(self.action.action_type.values_list("id", flat=True)), + "action_type_details": self.action.action_type_details.all(), + "amount": self.action.amount, + "unit": self.action.unit, + "comment": self.action.comment, + } + self.load_initial_data(form_data) + + def save(self): + action = self.action + action.action_type.set(self.cleaned_data.get("action_type", [])) + action.action_type_details.set(self.cleaned_data.get("action_type_details", [])) + action.amount = self.cleaned_data.get("amount", None) + action.unit = self.cleaned_data.get("unit", None) + action.comment = self.cleaned_data.get("comment", None) + action.save() + self.instance.mark_as_edited(self.user, self.request, edit_comment=COMPENSATION_ACTION_EDITED) + return action + + +class RemoveCompensationActionModalForm(RemoveModalForm): + """ Removing modal form for CompensationAction + + Can be used for anything, where removing shall be confirmed by the user a second time. + + """ + action = None + + def __init__(self, *args, **kwargs): + action = kwargs.pop("action", None) + self.action = action + super().__init__(*args, **kwargs) + + def save(self): + self.instance.remove_action(self) \ No newline at end of file diff --git a/compensation/forms/modals/deadline.py b/compensation/forms/modals/deadline.py new file mode 100644 index 00000000..330c83c8 --- /dev/null +++ b/compensation/forms/modals/deadline.py @@ -0,0 +1,92 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: ksp-servicestelle@sgdnord.rlp.de +Created on: 18.08.22 + +""" +from django import forms +from django.utils.translation import gettext_lazy as _ + +from konova.forms.modals import BaseModalForm +from konova.models import DeadlineType +from konova.utils.message_templates import DEADLINE_EDITED + + +class NewDeadlineModalForm(BaseModalForm): + """ Form handling deadline related input + + """ + type = forms.ChoiceField( + label=_("Deadline Type"), + label_suffix="", + required=True, + help_text=_("Select the deadline type"), + choices=DeadlineType.choices, + widget=forms.Select( + attrs={ + "class": "form-control" + } + ) + ) + date = forms.DateField( + label=_("Date"), + label_suffix="", + required=True, + help_text=_("Select date"), + widget=forms.DateInput( + attrs={ + "type": "date", + "data-provide": "datepicker", + "class": "form-control", + }, + format="%d.%m.%Y" + ) + ) + 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 = _("New deadline") + self.form_caption = _("Insert data for the new deadline") + + def save(self): + deadline = self.instance.add_deadline(self) + return deadline + + +class EditDeadlineModalForm(NewDeadlineModalForm): + deadline = None + + def __init__(self, *args, **kwargs): + self.deadline = kwargs.pop("deadline", None) + super().__init__(*args, **kwargs) + self.form_title = _("Edit deadline") + form_data = { + "type": self.deadline.type, + "date": str(self.deadline.date), + "comment": self.deadline.comment, + } + self.load_initial_data(form_data) + + def save(self): + deadline = self.deadline + deadline.type = self.cleaned_data.get("type", None) + deadline.date = self.cleaned_data.get("date", None) + deadline.comment = self.cleaned_data.get("comment", None) + deadline.save() + self.instance.mark_as_edited(self.user, self.request, edit_comment=DEADLINE_EDITED) + return deadline diff --git a/compensation/forms/modals/document.py b/compensation/forms/modals/document.py new file mode 100644 index 00000000..83c2ff92 --- /dev/null +++ b/compensation/forms/modals/document.py @@ -0,0 +1,17 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: ksp-servicestelle@sgdnord.rlp.de +Created on: 18.08.22 + +""" +from compensation.models import CompensationDocument, EcoAccountDocument +from konova.forms.modals import NewDocumentModalForm + + +class NewCompensationDocumentModalForm(NewDocumentModalForm): + document_model = CompensationDocument + + +class NewEcoAccountDocumentModalForm(NewDocumentModalForm): + document_model = EcoAccountDocument diff --git a/compensation/forms/modals/payment.py b/compensation/forms/modals/payment.py new file mode 100644 index 00000000..4383a576 --- /dev/null +++ b/compensation/forms/modals/payment.py @@ -0,0 +1,136 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: ksp-servicestelle@sgdnord.rlp.de +Created on: 18.08.22 + +""" +from django import forms +from django.utils.translation import pgettext_lazy as _con, gettext_lazy as _ + +from konova.forms.modals import RemoveModalForm, BaseModalForm +from konova.utils.message_templates import PAYMENT_EDITED + + +class NewPaymentForm(BaseModalForm): + """ Form handling payment related input + + """ + amount = forms.DecimalField( + min_value=0.00, + decimal_places=2, + label=_con("money", "Amount"), # contextual translation + label_suffix=_(""), + help_text=_("in Euro"), + widget=forms.NumberInput( + attrs={ + "class": "form-control", + "placeholder": "0,00", + } + ) + ) + due = forms.DateField( + label=_("Due on"), + label_suffix=_(""), + required=False, + help_text=_("Due on which date"), + widget=forms.DateInput( + attrs={ + "type": "date", + "data-provide": "datepicker", + "class": "form-control", + }, + format="%d.%m.%Y" + ) + ) + comment = forms.CharField( + max_length=200, + required=False, + label=_("Comment"), + label_suffix=_(""), + help_text=_("Additional comment, maximum {} letters").format(200), + widget=forms.Textarea( + attrs={ + "rows": 5, + "class": "form-control" + } + ) + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.intervention = self.instance + self.form_title = _("Payment") + self.form_caption = _("Add a payment for intervention '{}'").format(self.intervention.title) + + def is_valid(self): + """ + Checks on form validity. + + For this form we need to make sure that a date or a comment is set. + If both are missing, the user needs to enter at least an explanation why + there is no date to be entered. + + Returns: + is_valid (bool): True if valid, False otherwise + """ + super_valid = super().is_valid() + date = self.cleaned_data["due"] + comment = self.cleaned_data["comment"] or None + if not date and not comment: + # At least one needs to be set! + self.add_error( + "comment", + _("If there is no date you can enter, please explain why.") + ) + return False + return super_valid + + def save(self): + pay = self.instance.add_payment(self) + return pay + + +class EditPaymentModalForm(NewPaymentForm): + """ Form handling edit for Payment + + """ + payment = None + + def __init__(self, *args, **kwargs): + self.payment = kwargs.pop("payment", None) + super().__init__(*args, **kwargs) + self.form_title = _("Edit payment") + form_date = { + "amount": self.payment.amount, + "due": str(self.payment.due_on), + "comment": self.payment.comment, + } + self.load_initial_data(form_date, disabled_fields=[]) + + def save(self): + payment = self.payment + payment.amount = self.cleaned_data.get("amount", None) + payment.due_on = self.cleaned_data.get("due", None) + payment.comment = self.cleaned_data.get("comment", None) + payment.save() + self.instance.mark_as_edited(self.user, self.request, edit_comment=PAYMENT_EDITED) + self.instance.send_data_to_egon() + return payment + + +class RemovePaymentModalForm(RemoveModalForm): + """ Removing modal form for Payment + + Can be used for anything, where removing shall be confirmed by the user a second time. + + """ + payment = None + + def __init__(self, *args, **kwargs): + payment = kwargs.pop("payment", None) + self.payment = payment + super().__init__(*args, **kwargs) + + def save(self): + self.instance.remove_payment(self) diff --git a/compensation/forms/modals/state.py b/compensation/forms/modals/state.py new file mode 100644 index 00000000..485045ba --- /dev/null +++ b/compensation/forms/modals/state.py @@ -0,0 +1,179 @@ +""" +Author: Michel Peltriaux +Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany +Contact: ksp-servicestelle@sgdnord.rlp.de +Created on: 18.08.22 + +""" +from bootstrap_modal_forms.utils import is_ajax +from dal import autocomplete +from django import forms +from django.contrib import messages +from django.http import HttpResponseRedirect, HttpRequest +from django.shortcuts import render +from django.utils.translation import gettext_lazy as _ + +from codelist.models import KonovaCode +from codelist.settings import CODELIST_BIOTOPES_ID, CODELIST_BIOTOPES_EXTRA_CODES_ID +from intervention.inputs import CompensationStateTreeRadioSelect +from konova.contexts import BaseContext +from konova.forms.modals import RemoveModalForm, BaseModalForm +from konova.utils.message_templates import COMPENSATION_STATE_EDITED, FORM_INVALID, ADDED_COMPENSATION_STATE + + +class NewCompensationStateModalForm(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.ChoiceField( + label=_("Biotope Type"), + label_suffix="", + required=True, + help_text=_("Select the biotope type"), + widget=CompensationStateTreeRadioSelect(), + ) + biotope_extra = forms.ModelMultipleChoiceField( + label=_("Biotope additional type"), + label_suffix="", + required=False, + help_text=_("Select an additional biotope type"), + queryset=KonovaCode.objects.filter( + is_archived=False, + is_leaf=True, + code_lists__in=[CODELIST_BIOTOPES_EXTRA_CODES_ID], + ), + widget=autocomplete.ModelSelect2Multiple( + url="codes-biotope-extra-type-autocomplete", + attrs={ + "data-placeholder": _("Biotope additional type"), + } + ), + ) + surface = forms.DecimalField( + min_value=0.00, + decimal_places=2, + label=_("Surface"), + label_suffix="", + required=True, + help_text=_("in m²"), + widget=forms.NumberInput( + attrs={ + "class": "form-control", + "placeholder": "0,00" + } + ) + ) + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.form_title = _("New state") + self.form_caption = _("Insert data for the new state") + choices = KonovaCode.objects.filter( + code_lists__in=[CODELIST_BIOTOPES_ID], + is_archived=False, + is_leaf=True, + ).values_list("id", flat=True) + choices = [ + (choice, choice) + for choice in choices + ] + self.fields["biotope_type"].choices = choices + + def save(self, is_before_state: bool = False): + state = self.instance.add_state(self, is_before_state) + self.instance.mark_as_edited(self.user, self.request, ADDED_COMPENSATION_STATE) + return state + + def process_request(self, request: HttpRequest, msg_success: str = _("Object removed"), msg_error: str = FORM_INVALID, redirect_url: str = None): + """ Generic processing of request + + Wraps the request processing logic, so we don't need the same code everywhere a RemoveModalForm is being used + + +++ + The generic method from super class can not be used, since we need to do some request parameter check in here. + +++ + + Args: + request (HttpRequest): The incoming request + msg_success (str): The message in case of successful removing + msg_error (str): The message in case of an error + + Returns: + + """ + redirect_url = redirect_url if redirect_url is not None else request.META.get("HTTP_REFERER", "home") + template = self.template + if request.method == "POST": + if self.is_valid(): + # Modal forms send one POST for checking on data validity. This can be used to return possible errors + # on the form. A second POST (if no errors occured) is sent afterwards and needs to process the + # saving/commiting of the data to the database. is_ajax() performs this check. The first request is + # an ajax call, the second is a regular form POST. + if not is_ajax(request.META): + is_before_state = bool(request.GET.get("before", False)) + self.save(is_before_state=is_before_state) + messages.success( + request, + msg_success + ) + return HttpResponseRedirect(redirect_url) + else: + context = { + "form": self, + } + context = BaseContext(request, context).context + return render(request, template, context) + elif request.method == "GET": + context = { + "form": self, + } + context = BaseContext(request, context).context + return render(request, template, context) + else: + raise NotImplementedError + + +class EditCompensationStateModalForm(NewCompensationStateModalForm): + state = None + + def __init__(self, *args, **kwargs): + self.state = kwargs.pop("state", None) + super().__init__(*args, **kwargs) + self.form_title = _("Edit state") + biotope_type_id = self.state.biotope_type.id if self.state.biotope_type else None + form_data = { + "biotope_type": biotope_type_id, + "biotope_extra": self.state.biotope_type_details.all(), + "surface": self.state.surface, + } + self.load_initial_data(form_data) + + def save(self, is_before_state: bool = False): + state = self.state + biotope_type_id = self.cleaned_data.get("biotope_type", None) + state.biotope_type = KonovaCode.objects.get(id=biotope_type_id) + state.biotope_type_details.set(self.cleaned_data.get("biotope_extra", [])) + state.surface = self.cleaned_data.get("surface", None) + state.save() + self.instance.mark_as_edited(self.user, self.request, edit_comment=COMPENSATION_STATE_EDITED) + return state + + +class RemoveCompensationStateModalForm(RemoveModalForm): + """ Removing modal form for CompensationState + + Can be used for anything, where removing shall be confirmed by the user a second time. + + """ + state = None + + def __init__(self, *args, **kwargs): + state = kwargs.pop("state", None) + self.state = state + super().__init__(*args, **kwargs) + + def save(self): + self.instance.remove_state(self) diff --git a/compensation/views/compensation.py b/compensation/views/compensation.py index db01a045..e12324ce 100644 --- a/compensation/views/compensation.py +++ b/compensation/views/compensation.py @@ -5,10 +5,12 @@ from django.http import HttpRequest, JsonResponse from django.shortcuts import render from django.utils.translation import gettext_lazy as _ -from compensation.forms.forms import NewCompensationForm, EditCompensationForm -from compensation.forms.modalForms import NewStateModalForm, NewDeadlineModalForm, NewActionModalForm, \ - NewCompensationDocumentModalForm, RemoveCompensationActionModalForm, RemoveCompensationStateModalForm, \ - EditCompensationStateModalForm, EditCompensationActionModalForm, EditDeadlineModalForm +from compensation.forms.compensation import NewCompensationForm, EditCompensationForm +from compensation.forms.modals.state import NewCompensationStateModalForm, RemoveCompensationStateModalForm, EditCompensationStateModalForm +from compensation.forms.modals.document import NewCompensationDocumentModalForm +from compensation.forms.modals.compensation_action import NewCompensationActionModalForm, \ + EditCompensationActionModalForm, RemoveCompensationActionModalForm +from compensation.forms.modals.deadline import NewDeadlineModalForm, EditDeadlineModalForm from compensation.models import Compensation, CompensationState, CompensationAction, CompensationDocument from compensation.tables import CompensationTable from intervention.models import Intervention @@ -21,7 +23,7 @@ from konova.models import Deadline from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER from konova.utils.documents import get_document, remove_document from konova.utils.generators import generate_qr_code -from konova.utils.message_templates import FORM_INVALID, IDENTIFIER_REPLACED, DATA_UNSHARED_EXPLANATION, \ +from konova.utils.message_templates import FORM_INVALID, IDENTIFIER_REPLACED, \ CHECKED_RECORDED_RESET, COMPENSATION_ADDED_TEMPLATE, COMPENSATION_REMOVED_TEMPLATE, DOCUMENT_ADDED, \ COMPENSATION_STATE_REMOVED, COMPENSATION_STATE_ADDED, COMPENSATION_ACTION_REMOVED, COMPENSATION_ACTION_ADDED, \ DEADLINE_ADDED, DEADLINE_REMOVED, DOCUMENT_EDITED, COMPENSATION_STATE_EDITED, COMPENSATION_ACTION_EDITED, \ @@ -402,7 +404,7 @@ def state_new_view(request: HttpRequest, id: str): """ comp = get_object_or_404(Compensation, id=id) - form = NewStateModalForm(request.POST or None, instance=comp, request=request) + form = NewCompensationStateModalForm(request.POST or None, instance=comp, request=request) return form.process_request( request, msg_success=COMPENSATION_STATE_ADDED, @@ -424,7 +426,7 @@ def action_new_view(request: HttpRequest, id: str): """ comp = get_object_or_404(Compensation, id=id) - form = NewActionModalForm(request.POST or None, instance=comp, request=request) + form = NewCompensationActionModalForm(request.POST or None, instance=comp, request=request) return form.process_request( request, msg_success=COMPENSATION_ACTION_ADDED, diff --git a/compensation/views/eco_account.py b/compensation/views/eco_account.py index 2ebeb1f7..d600c23c 100644 --- a/compensation/views/eco_account.py +++ b/compensation/views/eco_account.py @@ -14,10 +14,13 @@ from django.core.exceptions import ObjectDoesNotExist from django.http import HttpRequest, Http404, JsonResponse from django.shortcuts import render, get_object_or_404, redirect -from compensation.forms.forms import NewEcoAccountForm, EditEcoAccountForm -from compensation.forms.modalForms import NewStateModalForm, NewActionModalForm, NewDeadlineModalForm, \ - NewEcoAccountDocumentModalForm, RemoveCompensationActionModalForm, RemoveCompensationStateModalForm, \ - EditCompensationStateModalForm, EditCompensationActionModalForm, EditDeadlineModalForm +from compensation.forms.eco_account import NewEcoAccountForm, EditEcoAccountForm +from compensation.forms.modals.compensation_action import NewCompensationActionModalForm, \ + RemoveCompensationActionModalForm, EditCompensationActionModalForm +from compensation.forms.modals.deadline import EditDeadlineModalForm, NewDeadlineModalForm +from compensation.forms.modals.document import NewEcoAccountDocumentModalForm +from compensation.forms.modals.state import NewCompensationStateModalForm, RemoveCompensationStateModalForm, \ + EditCompensationStateModalForm from compensation.models import EcoAccount, EcoAccountDocument, CompensationState, CompensationAction from compensation.tables import EcoAccountTable from intervention.forms.modalForms import NewDeductionModalForm, ShareModalForm, RemoveEcoAccountDeductionModalForm, \ @@ -401,7 +404,7 @@ def state_new_view(request: HttpRequest, id: str): """ acc = get_object_or_404(EcoAccount, id=id) - form = NewStateModalForm(request.POST or None, instance=acc, request=request) + form = NewCompensationStateModalForm(request.POST or None, instance=acc, request=request) return form.process_request( request, msg_success=COMPENSATION_STATE_ADDED, @@ -423,7 +426,7 @@ def action_new_view(request: HttpRequest, id: str): """ acc = get_object_or_404(EcoAccount, id=id) - form = NewActionModalForm(request.POST or None, instance=acc, request=request) + form = NewCompensationActionModalForm(request.POST or None, instance=acc, request=request) return form.process_request( request, msg_success=COMPENSATION_ACTION_ADDED, diff --git a/compensation/views/payment.py b/compensation/views/payment.py index 84fad5bc..29e89ac3 100644 --- a/compensation/views/payment.py +++ b/compensation/views/payment.py @@ -6,12 +6,11 @@ Created on: 09.08.21 """ from django.urls import reverse -from django.utils.translation import gettext_lazy as _ from django.contrib.auth.decorators import login_required from django.http import HttpRequest from django.shortcuts import get_object_or_404 -from compensation.forms.modalForms import NewPaymentForm, RemovePaymentModalForm, EditPaymentModalForm +from compensation.forms.modals.payment import NewPaymentForm, RemovePaymentModalForm, EditPaymentModalForm from compensation.models import Payment from intervention.models import Intervention from konova.decorators import default_group_required, shared_access_required diff --git a/ema/forms.py b/ema/forms.py index 93f23490..bbe09a88 100644 --- a/ema/forms.py +++ b/ema/forms.py @@ -10,8 +10,8 @@ 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, \ - PikCompensationFormMixin +from compensation.forms.mixins import CompensationResponsibleFormMixin, PikCompensationFormMixin +from compensation.forms.compensation import AbstractCompensationForm from ema.models import Ema, EmaDocument from intervention.models import Responsibility, Handler from konova.forms import SimpleGeomForm diff --git a/ema/views.py b/ema/views.py index f07187aa..fea6d4bc 100644 --- a/ema/views.py +++ b/ema/views.py @@ -6,9 +6,11 @@ from django.shortcuts import render, get_object_or_404, redirect from django.urls import reverse from django.utils.translation import gettext_lazy as _ -from compensation.forms.modalForms import NewStateModalForm, NewActionModalForm, NewDeadlineModalForm, \ - RemoveCompensationActionModalForm, RemoveCompensationStateModalForm, EditCompensationStateModalForm, \ - EditCompensationActionModalForm, EditDeadlineModalForm +from compensation.forms.modals.compensation_action import NewCompensationActionModalForm, \ + EditCompensationActionModalForm, RemoveCompensationActionModalForm +from compensation.forms.modals.deadline import NewDeadlineModalForm, EditDeadlineModalForm +from compensation.forms.modals.state import NewCompensationStateModalForm, RemoveCompensationStateModalForm, \ + EditCompensationStateModalForm from compensation.models import CompensationAction, CompensationState from ema.forms import NewEmaForm, EditEmaForm, NewEmaDocumentModalForm from ema.tables import EmaTable @@ -303,7 +305,7 @@ def state_new_view(request: HttpRequest, id: str): """ ema = get_object_or_404(Ema, id=id) - form = NewStateModalForm(request.POST or None, instance=ema, request=request) + form = NewCompensationStateModalForm(request.POST or None, instance=ema, request=request) return form.process_request( request, msg_success=COMPENSATION_STATE_ADDED, @@ -325,7 +327,7 @@ def action_new_view(request: HttpRequest, id: str): """ ema = get_object_or_404(Ema, id=id) - form = NewActionModalForm(request.POST or None, instance=ema, request=request) + form = NewCompensationActionModalForm(request.POST or None, instance=ema, request=request) return form.process_request( request, msg_success=COMPENSATION_ACTION_ADDED,