2021-07-01 13:36:07 +02:00
"""
Author : Michel Peltriaux
Organization : Struktur - und Genehmigungsdirektion Nord , Rhineland - Palatinate , Germany
Contact : michel . peltriaux @sgdnord.rlp.de
2021-10-04 09:55:59 +02:00
Created on : 04.10 .21
2021-07-01 13:36:07 +02:00
"""
2021-08-19 09:06:35 +02:00
from bootstrap_modal_forms . utils import is_ajax
2021-08-24 09:31:12 +02:00
from dal import autocomplete
2021-07-26 10:23:09 +02:00
from django import forms
2021-08-03 17:22:41 +02:00
from django . contrib import messages
2021-08-19 09:06:35 +02:00
from django . http import HttpRequest , HttpResponseRedirect
from django . shortcuts import render
2021-10-04 09:55:59 +02:00
from django . utils . translation import pgettext_lazy as _con , gettext_lazy as _
2021-07-26 10:23:09 +02:00
2021-08-24 09:31:12 +02:00
from codelist . models import KonovaCode
2022-01-31 12:58:55 +01:00
from codelist . settings import CODELIST_BIOTOPES_ID , CODELIST_COMPENSATION_ACTION_ID , CODELIST_BIOTOPES_EXTRA_CODES_ID , \
CODELIST_COMPENSATION_ACTION_DETAIL_ID
2021-11-15 17:09:17 +01:00
from compensation . models import CompensationDocument , EcoAccountDocument
2022-02-15 10:48:01 +01:00
from intervention . inputs import CompensationActionTreeCheckboxSelectMultiple
2021-08-03 17:22:41 +02:00
from konova . contexts import BaseContext
2022-02-10 10:21:18 +01:00
from konova . forms import BaseModalForm , NewDocumentModalForm , RemoveModalForm
2021-11-15 17:09:17 +01:00
from konova . models import DeadlineType
2022-02-11 16:21:44 +01:00
from konova . utils . message_templates import FORM_INVALID , ADDED_COMPENSATION_STATE , \
2022-02-10 12:33:22 +01:00
ADDED_COMPENSATION_ACTION , PAYMENT_EDITED , COMPENSATION_STATE_EDITED , COMPENSATION_ACTION_EDITED , DEADLINE_EDITED
2021-07-01 13:36:07 +02:00
2021-07-26 10:23:09 +02:00
class NewPaymentForm ( BaseModalForm ) :
2021-10-04 09:55:59 +02:00
""" Form handling payment related input
"""
2021-07-26 11:29:05 +02:00
amount = forms . DecimalField (
min_value = 0.00 ,
decimal_places = 2 ,
2021-08-24 14:50:51 +02:00
label = _con ( " money " , " Amount " ) , # contextual translation
2021-07-26 10:23:09 +02:00
label_suffix = _ ( " " ) ,
2021-08-24 14:50:51 +02:00
help_text = _ ( " in Euro " ) ,
2021-09-27 13:57:56 +02:00
widget = forms . NumberInput (
attrs = {
2021-10-06 13:10:10 +02:00
" class " : " form-control " ,
" placeholder " : " 0,00 " ,
2021-09-27 13:57:56 +02:00
}
)
2021-07-26 10:23:09 +02:00
)
due = forms . DateField (
label = _ ( " Due on " ) ,
label_suffix = _ ( " " ) ,
2021-08-24 14:50:51 +02:00
required = False ,
2021-07-26 11:29:05 +02:00
help_text = _ ( " Due on which date " ) ,
2021-07-26 10:23:09 +02:00
widget = forms . DateInput (
attrs = {
" type " : " date " ,
" data-provide " : " datepicker " ,
2021-09-27 13:57:56 +02:00
" class " : " form-control " ,
2021-07-26 10:23:09 +02:00
} ,
format = " %d . % m. % Y "
)
)
2021-08-26 14:30:05 +02:00
comment = forms . CharField (
2021-08-04 13:32:35 +02:00
max_length = 200 ,
2021-07-26 10:23:09 +02:00
required = False ,
2021-08-26 14:30:05 +02:00
label = _ ( " Comment " ) ,
2021-07-26 10:23:09 +02:00
label_suffix = _ ( " " ) ,
2021-08-26 14:30:05 +02:00
help_text = _ ( " Additional comment, maximum {} letters " ) . format ( 200 ) ,
widget = forms . Textarea (
attrs = {
" rows " : 5 ,
2021-09-27 13:57:56 +02:00
" class " : " form-control "
2021-08-26 14:30:05 +02:00
}
)
2021-07-26 10:23:09 +02:00
)
def __init__ ( self , * args , * * kwargs ) :
super ( ) . __init__ ( * args , * * kwargs )
2021-07-26 11:29:05 +02:00
self . intervention = self . instance
2021-07-26 10:23:09 +02:00
self . form_title = _ ( " Payment " )
self . form_caption = _ ( " Add a payment for intervention ' {} ' " ) . format ( self . intervention . title )
2021-08-26 14:30:05 +02:00
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
2021-07-26 10:23:09 +02:00
def save ( self ) :
2021-11-15 17:09:17 +01:00
pay = self . instance . add_payment ( self )
return pay
2021-08-03 13:13:01 +02:00
2022-02-09 10:29:34 +01:00
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 )
2022-02-21 09:04:46 +01:00
self . form_title = _ ( " Edit payment " )
2022-02-09 10:29:34 +01:00
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 )
return payment
2022-02-08 13:31:40 +01:00
class RemovePaymentModalForm ( RemoveModalForm ) :
2022-02-08 13:16:20 +01:00
""" 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 )
2021-08-03 13:13:01 +02:00
class NewStateModalForm ( BaseModalForm ) :
2021-10-04 09:55:59 +02:00
""" 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 ' ) ?
"""
2021-08-24 09:37:59 +02:00
biotope_type = forms . ModelChoiceField (
2021-08-03 13:13:01 +02:00
label = _ ( " Biotope Type " ) ,
label_suffix = " " ,
required = True ,
2021-08-24 09:37:59 +02:00
help_text = _ ( " Select the biotope type " ) ,
queryset = KonovaCode . objects . filter (
2021-08-26 12:45:48 +02:00
is_archived = False ,
2021-08-24 14:50:51 +02:00
is_leaf = True ,
code_lists__in = [ CODELIST_BIOTOPES_ID ] ,
2021-08-24 09:37:59 +02:00
) ,
widget = autocomplete . ModelSelect2 (
url = " codes-biotope-autocomplete " ,
attrs = {
" data-placeholder " : _ ( " Biotope Type " ) ,
}
) ,
2021-08-03 13:13:01 +02:00
)
2022-01-31 11:26:24 +01:00
biotope_extra = forms . ModelMultipleChoiceField (
2022-01-31 10:52:35 +01:00
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 " ) ,
}
) ,
)
2021-08-03 13:13:01 +02:00
surface = forms . DecimalField (
min_value = 0.00 ,
decimal_places = 2 ,
label = _ ( " Surface " ) ,
label_suffix = " " ,
required = True ,
2021-09-27 13:57:56 +02:00
help_text = _ ( " in m² " ) ,
widget = forms . NumberInput (
attrs = {
" class " : " form-control " ,
2021-10-06 13:10:10 +02:00
" placeholder " : " 0,00 "
2021-09-27 13:57:56 +02:00
}
)
2021-08-03 13:13:01 +02:00
)
def __init__ ( self , * args , * * kwargs ) :
super ( ) . __init__ ( * args , * * kwargs )
self . form_title = _ ( " New state " )
self . form_caption = _ ( " Insert data for the new state " )
def save ( self , is_before_state : bool = False ) :
2021-11-15 17:09:17 +01:00
state = self . instance . add_state ( self , is_before_state )
2021-11-17 14:33:05 +01:00
self . instance . mark_as_edited ( self . user , self . request , ADDED_COMPENSATION_STATE )
2021-08-03 13:13:01 +02:00
return state
2021-08-03 17:22:41 +02:00
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
2021-08-10 13:12:15 +02:00
+ + +
The generic method from super class can not be used , since we need to do some request parameter check in here .
+ + +
2021-08-03 17:22:41 +02:00
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 ( ) :
2021-08-19 09:06:35 +02:00
# 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 )
2021-08-03 17:22:41 +02:00
else :
2021-08-19 09:06:35 +02:00
context = {
" form " : self ,
}
context = BaseContext ( request , context ) . context
return render ( request , template , context )
2021-08-03 17:22:41 +02:00
elif request . method == " GET " :
context = {
" form " : self ,
}
context = BaseContext ( request , context ) . context
return render ( request , template , context )
else :
raise NotImplementedError
2021-08-03 13:13:01 +02:00
2022-02-10 11:02:30 +01:00
class EditCompensationStateModalForm ( NewStateModalForm ) :
state = None
def __init__ ( self , * args , * * kwargs ) :
self . state = kwargs . pop ( " state " , None )
super ( ) . __init__ ( * args , * * kwargs )
2022-02-21 09:04:46 +01:00
self . form_title = _ ( " Edit state " )
2022-02-10 11:02:30 +01:00
form_data = {
" biotope_type " : self . state . biotope_type ,
" 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
state . biotope_type = self . cleaned_data . get ( " biotope_type " , None )
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
2022-02-08 13:31:40 +01:00
class RemoveCompensationStateModalForm ( RemoveModalForm ) :
2022-02-08 13:16:20 +01:00
""" 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 )
2022-02-08 13:31:40 +01:00
class RemoveCompensationActionModalForm ( RemoveModalForm ) :
2022-02-08 13:16:20 +01:00
""" 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 )
2021-08-03 13:13:01 +02:00
class NewDeadlineModalForm ( BaseModalForm ) :
2021-10-04 09:55:59 +02:00
""" Form handling deadline related input
"""
2021-08-03 13:13:01 +02:00
type = forms . ChoiceField (
label = _ ( " Deadline Type " ) ,
label_suffix = " " ,
required = True ,
help_text = _ ( " Select the deadline type " ) ,
2021-08-04 10:44:02 +02:00
choices = DeadlineType . choices ,
widget = forms . Select (
attrs = {
2021-09-27 13:57:56 +02:00
" class " : " form-control "
2021-08-04 10:44:02 +02:00
}
)
2021-08-03 13:13:01 +02:00
)
date = forms . DateField (
label = _ ( " Date " ) ,
label_suffix = " " ,
required = True ,
help_text = _ ( " Select date " ) ,
widget = forms . DateInput (
attrs = {
" type " : " date " ,
" data-provide " : " datepicker " ,
2021-09-27 13:57:56 +02:00
" class " : " form-control " ,
2021-08-03 13:13:01 +02:00
} ,
format = " %d . % m. % Y "
)
)
comment = forms . CharField (
required = False ,
2021-08-04 11:56:56 +02:00
max_length = 200 ,
2021-08-03 13:13:01 +02:00
label = _ ( " Comment " ) ,
label_suffix = _ ( " " ) ,
2021-08-04 11:56:56 +02:00
help_text = _ ( " Additional comment, maximum {} letters " ) . format ( 200 ) ,
2021-08-03 13:13:01 +02:00
widget = forms . Textarea (
attrs = {
" cols " : 30 ,
" rows " : 5 ,
2021-09-27 13:57:56 +02:00
" class " : " form-control " ,
2021-08-03 13:13:01 +02:00
}
)
)
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 ) :
2021-11-17 14:33:05 +01:00
deadline = self . instance . add_deadline ( self )
2021-08-03 13:13:01 +02:00
return deadline
2021-08-04 10:44:02 +02:00
2022-02-10 12:33:22 +01:00
class EditDeadlineModalForm ( NewDeadlineModalForm ) :
deadline = None
def __init__ ( self , * args , * * kwargs ) :
self . deadline = kwargs . pop ( " deadline " , None )
super ( ) . __init__ ( * args , * * kwargs )
2022-02-21 09:04:46 +01:00
self . form_title = _ ( " Edit deadline " )
2022-02-10 12:33:22 +01:00
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
2021-08-04 10:44:02 +02:00
class NewActionModalForm ( BaseModalForm ) :
2021-10-04 09:55:59 +02:00
""" 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 ) .
"""
2021-11-15 17:09:17 +01:00
from compensation . models import UnitChoices
2022-02-15 10:48:01 +01:00
action_type = forms . MultipleChoiceField (
2021-08-04 10:44:02 +02:00
label = _ ( " Action Type " ) ,
label_suffix = " " ,
required = True ,
2022-02-15 11:32:20 +01:00
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. " ) ,
2022-02-15 10:48:01 +01:00
choices = [ ] ,
widget = CompensationActionTreeCheckboxSelectMultiple ( ) ,
2021-08-04 10:44:02 +02:00
)
2022-01-31 12:58:55 +01:00
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 " ) ,
}
) ,
)
2021-08-04 10:44:02 +02:00
unit = forms . ChoiceField (
label = _ ( " Unit " ) ,
label_suffix = " " ,
required = True ,
help_text = _ ( " Select the unit " ) ,
choices = UnitChoices . choices ,
widget = forms . Select (
attrs = {
2021-09-27 13:57:56 +02:00
" class " : " form-control "
2021-08-04 10:44:02 +02:00
}
)
)
amount = forms . DecimalField (
label = _ ( " Amount " ) ,
label_suffix = " " ,
required = True ,
help_text = _ ( " Insert the amount " ) ,
decimal_places = 2 ,
min_value = 0.00 ,
2021-09-27 13:57:56 +02:00
widget = forms . NumberInput (
attrs = {
" class " : " form-control " ,
2021-10-06 13:10:10 +02:00
" placeholder " : " 0,00 " ,
2021-09-27 13:57:56 +02:00
}
)
2021-08-04 10:44:02 +02:00
)
comment = forms . CharField (
required = False ,
label = _ ( " Comment " ) ,
label_suffix = _ ( " " ) ,
2022-02-02 12:54:45 +01:00
help_text = _ ( " Additional comment " ) ,
2021-08-04 10:44:02 +02:00
widget = forms . Textarea (
attrs = {
" rows " : 5 ,
2021-09-27 13:57:56 +02:00
" class " : " form-control " ,
2021-08-04 10:44:02 +02:00
}
)
)
def __init__ ( self , * args , * * kwargs ) :
super ( ) . __init__ ( * args , * * kwargs )
self . form_title = _ ( " New action " )
self . form_caption = _ ( " Insert data for the new action " )
2022-02-15 10:48:01 +01:00
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
2021-08-04 10:44:02 +02:00
def save ( self ) :
2021-11-17 14:33:05 +01:00
action = self . instance . add_action ( self )
self . instance . mark_as_edited ( self . user , self . request , ADDED_COMPENSATION_ACTION )
2021-11-15 17:09:17 +01:00
return action
2022-02-10 11:24:20 +01:00
class EditCompensationActionModalForm ( NewActionModalForm ) :
action = None
def __init__ ( self , * args , * * kwargs ) :
self . action = kwargs . pop ( " action " , None )
super ( ) . __init__ ( * args , * * kwargs )
2022-02-21 09:04:46 +01:00
self . form_title = _ ( " Edit action " )
2022-02-10 11:24:20 +01:00
form_data = {
2022-02-15 10:48:01 +01:00
" action_type " : list ( self . action . action_type . values_list ( " id " , flat = True ) ) ,
2022-02-10 11:24:20 +01:00
" 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
2022-02-10 14:45:00 +01:00
action . action_type . set ( self . cleaned_data . get ( " action_type " , [ ] ) )
2022-02-10 11:24:20 +01:00
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
2022-02-10 10:21:18 +01:00
class NewCompensationDocumentModalForm ( NewDocumentModalForm ) :
2021-11-15 17:09:17 +01:00
document_model = CompensationDocument
2022-02-10 10:21:18 +01:00
class NewEcoAccountDocumentModalForm ( NewDocumentModalForm ) :
2021-11-15 17:09:17 +01:00
document_model = EcoAccountDocument