#86 Log detail enhancements

* restructures removing of related data into separate sub-delete forms for easier logic handling
pull/111/head
mpeltriaux 3 years ago
parent 43bc3517ff
commit 5ebb3f833a

@ -18,7 +18,7 @@ from codelist.settings import CODELIST_BIOTOPES_ID, CODELIST_COMPENSATION_ACTION
CODELIST_COMPENSATION_ACTION_DETAIL_ID
from compensation.models import CompensationDocument, EcoAccountDocument
from konova.contexts import BaseContext
from konova.forms import BaseModalForm, NewDocumentForm
from konova.forms import BaseModalForm, NewDocumentForm, RemoveModalForm
from konova.models import DeadlineType
from konova.utils.message_templates import FORM_INVALID, ADDED_COMPENSATION_STATE, ADDED_DEADLINE, \
ADDED_COMPENSATION_ACTION, PAYMENT_ADDED
@ -100,10 +100,26 @@ class NewPaymentForm(BaseModalForm):
def save(self):
pay = self.instance.add_payment(self)
self.instance.mark_as_edited(self.user, self.request, edit_comment=PAYMENT_ADDED)
return pay
class PaymentRemoveModalForm(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
@ -219,6 +235,40 @@ class NewStateModalForm(BaseModalForm):
raise NotImplementedError
class CompensationStateRemoveModalForm(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 CompensationActionRemoveModalForm(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

@ -76,13 +76,3 @@ class CompensationAction(BaseResource):
if choice[0] == self.unit:
return choice[1]
return None
def delete(self, user=None, *args, **kwargs):
from compensation.models import Compensation
if user:
comps = Compensation.objects.filter(
actions__id__in=[self.id]
).distinct()
for comp in comps:
comp.mark_as_edited(user, edit_comment=COMPENSATION_ACTION_REMOVED)
super().delete(*args, **kwargs)

@ -21,7 +21,8 @@ from konova.models import BaseObject, AbstractDocument, Deadline, generate_docum
GeoReferencedMixin
from konova.settings import DEFAULT_SRID_RLP, LANIS_LINK_TEMPLATE
from konova.utils.message_templates import DATA_UNSHARED_EXPLANATION, COMPENSATION_REMOVED_TEMPLATE, \
DOCUMENT_REMOVED_TEMPLATE, COMPENSATION_EDITED_TEMPLATE, DEADLINE_REMOVED, ADDED_DEADLINE
DOCUMENT_REMOVED_TEMPLATE, COMPENSATION_EDITED_TEMPLATE, DEADLINE_REMOVED, ADDED_DEADLINE, \
COMPENSATION_ACTION_REMOVED, COMPENSATION_STATE_REMOVED
from user.models import UserActionLogEntry
@ -114,6 +115,21 @@ class AbstractCompensation(BaseObject, GeoReferencedMixin):
self.actions.add(comp_action)
return comp_action
def remove_action(self, form):
""" Removes a CompensationAction from the abstract compensation
Args:
form (CompensationActionRemoveModalForm): The form holding all relevant data
Returns:
"""
action = form.action
user = form.user
with transaction.atomic():
action.delete()
self.mark_as_edited(user, edit_comment=COMPENSATION_ACTION_REMOVED)
def add_state(self, form, is_before_state: bool) -> CompensationState:
""" Adds a new compensation state to the compensation
@ -138,6 +154,21 @@ class AbstractCompensation(BaseObject, GeoReferencedMixin):
self.after_states.add(state)
return state
def remove_state(self, form):
""" Removes a CompensationState from the abstract compensation
Args:
form (CompensationStateRemoveModalForm): The form holding all relevant data
Returns:
"""
state = form.state
user = form.user
with transaction.atomic():
state.delete()
self.mark_as_edited(user, edit_comment=COMPENSATION_STATE_REMOVED)
def get_surface_after_states(self) -> float:
""" Calculates the compensation's/account's surface
@ -346,7 +377,7 @@ class Compensation(AbstractCompensation, CEFMixin, CoherenceMixin):
"""
self.intervention.unrecord(user, request)
action = super().mark_as_edited(user, edit_comment)
action = super().mark_as_edited(user, edit_comment=edit_comment)
return action
def is_ready_for_publish(self) -> bool:

@ -37,8 +37,3 @@ class Payment(BaseResource):
ordering = [
"-amount",
]
def delete(self, user=None, *args, **kwargs):
if user is not None:
self.intervention.mark_as_edited(user, edit_comment=PAYMENT_REMOVED)
super().delete(*args, **kwargs)

@ -47,14 +47,3 @@ class CompensationState(UuidModel):
def __str__(self):
return f"{self.biotope_type} | {self.surface}"
def delete(self, user=None, *args, **kwargs):
from compensation.models import Compensation
if user:
comps = Compensation.objects.filter(
Q(before_states__id__in=[self.id]) |
Q(after_states__id__in=[self.id])
).distinct()
for comp in comps:
comp.mark_as_edited(user, edit_comment=COMPENSATION_STATE_REMOVED)
super().delete(*args, **kwargs)

@ -10,6 +10,6 @@ from compensation.views.payment import *
app_name = "pay"
urlpatterns = [
path('<intervention_id>/new', new_payment_view, name='new'),
path('<id>/remove', payment_remove_view, name='remove'),
path('<id>/new', new_payment_view, name='new'),
path('<id>/remove/<payment_id>', payment_remove_view, name='remove'),
]

@ -6,7 +6,7 @@ from django.utils.translation import gettext_lazy as _
from compensation.forms.forms import NewCompensationForm, EditCompensationForm
from compensation.forms.modalForms import NewStateModalForm, NewDeadlineModalForm, NewActionModalForm, \
NewCompensationDocumentForm
NewCompensationDocumentForm, CompensationActionRemoveModalForm, CompensationStateRemoveModalForm
from compensation.models import Compensation, CompensationState, CompensationAction, CompensationDocument
from compensation.tables import CompensationTable
from intervention.models import Intervention
@ -436,8 +436,9 @@ def state_remove_view(request: HttpRequest, id: str, state_id: str):
Returns:
"""
comp = get_object_or_404(Compensation, id=id)
state = get_object_or_404(CompensationState, id=state_id)
form = RemoveModalForm(request.POST or None, instance=state, request=request)
form = CompensationStateRemoveModalForm(request.POST or None, instance=comp, state=state, request=request)
return form.process_request(
request,
msg_success=COMPENSATION_STATE_REMOVED,
@ -459,8 +460,9 @@ def action_remove_view(request: HttpRequest, id: str, action_id: str):
Returns:
"""
comp = get_object_or_404(Compensation, id=id)
action = get_object_or_404(CompensationAction, id=action_id)
form = RemoveModalForm(request.POST or None, instance=action, request=request)
form = CompensationActionRemoveModalForm(request.POST or None, instance=comp, action=action, request=request)
return form.process_request(
request,
msg_success=COMPENSATION_ACTION_REMOVED,

@ -16,10 +16,10 @@ 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, \
NewEcoAccountDocumentForm
NewEcoAccountDocumentForm, CompensationActionRemoveModalForm, CompensationStateRemoveModalForm
from compensation.models import EcoAccount, EcoAccountDocument, CompensationState, CompensationAction
from compensation.tables import EcoAccountTable
from intervention.forms.modalForms import NewDeductionModalForm, ShareModalForm
from intervention.forms.modalForms import NewDeductionModalForm, ShareModalForm, DeductionRemoveModalForm
from konova.contexts import BaseContext
from konova.decorators import any_group_check, default_group_required, conservation_office_group_required, \
shared_access_required
@ -286,7 +286,7 @@ def deduction_remove_view(request: HttpRequest, id: str, deduction_id: str):
except ObjectDoesNotExist:
raise Http404("Unknown deduction")
form = RemoveModalForm(request.POST or None, instance=eco_deduction, request=request)
form = DeductionRemoveModalForm(request.POST or None, instance=acc, deduction=eco_deduction, request=request)
return form.process_request(
request=request,
msg_success=DEDUCTION_REMOVED,
@ -401,8 +401,9 @@ def state_remove_view(request: HttpRequest, id: str, state_id: str):
Returns:
"""
acc = get_object_or_404(EcoAccount, id=id)
state = get_object_or_404(CompensationState, id=state_id)
form = RemoveModalForm(request.POST or None, instance=state, request=request)
form = CompensationStateRemoveModalForm(request.POST or None, instance=acc, state=state, request=request)
return form.process_request(
request,
msg_success=COMPENSATION_STATE_REMOVED,
@ -424,8 +425,9 @@ def action_remove_view(request: HttpRequest, id: str, action_id: str):
Returns:
"""
acc = get_object_or_404(EcoAccount, id=id)
action = get_object_or_404(CompensationAction, id=action_id)
form = RemoveModalForm(request.POST or None, instance=action, request=request)
form = CompensationActionRemoveModalForm(request.POST or None, instance=acc, action=action, request=request)
return form.process_request(
request,
msg_success=COMPENSATION_ACTION_REMOVED,

@ -11,7 +11,7 @@ from django.contrib.auth.decorators import login_required
from django.http import HttpRequest
from django.shortcuts import get_object_or_404
from compensation.forms.modalForms import NewPaymentForm
from compensation.forms.modalForms import NewPaymentForm, PaymentRemoveModalForm
from compensation.models import Payment
from intervention.models import Intervention
from konova.decorators import default_group_required
@ -21,39 +21,41 @@ from konova.utils.message_templates import PAYMENT_ADDED, PAYMENT_REMOVED
@login_required
@default_group_required
def new_payment_view(request: HttpRequest, intervention_id: str):
def new_payment_view(request: HttpRequest, id: str):
""" Renders a modal view for adding new payments
Args:
request (HttpRequest): The incoming request
intervention_id (str): The intervention's id for which a new payment shall be added
id (str): The intervention's id for which a new payment shall be added
Returns:
"""
intervention = get_object_or_404(Intervention, id=intervention_id)
intervention = get_object_or_404(Intervention, id=id)
form = NewPaymentForm(request.POST or None, instance=intervention, request=request)
return form.process_request(
request,
msg_success=PAYMENT_ADDED,
redirect_url=reverse("intervention:detail", args=(intervention_id,)) + "#related_data"
redirect_url=reverse("intervention:detail", args=(id,)) + "#related_data"
)
@login_required
@default_group_required
def payment_remove_view(request: HttpRequest, id: str):
def payment_remove_view(request: HttpRequest, id: str, payment_id: str):
""" Renders a modal view for removing payments
Args:
request (HttpRequest): The incoming request
id (str): The payment's id
id (str): The intervention's id
payment_id (str): The payment's id
Returns:
"""
payment = get_object_or_404(Payment, id=id)
form = RemoveModalForm(request.POST or None, instance=payment, request=request)
intervention = get_object_or_404(Intervention, id=id)
payment = get_object_or_404(Payment, id=payment_id)
form = PaymentRemoveModalForm(request.POST or None, instance=intervention, payment=payment, request=request)
return form.process_request(
request=request,
msg_success=PAYMENT_REMOVED,

@ -6,7 +6,8 @@ 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
from compensation.forms.modalForms import NewStateModalForm, NewActionModalForm, NewDeadlineModalForm, \
CompensationActionRemoveModalForm, CompensationStateRemoveModalForm
from compensation.models import CompensationAction, CompensationState
from ema.forms import NewEmaForm, EditEmaForm, NewEmaDocumentForm
from ema.tables import EmaTable
@ -425,8 +426,9 @@ def state_remove_view(request: HttpRequest, id: str, state_id: str):
Returns:
"""
ema = get_object_or_404(Ema, id=id)
state = get_object_or_404(CompensationState, id=state_id)
form = RemoveModalForm(request.POST or None, instance=state, request=request)
form = CompensationStateRemoveModalForm(request.POST or None, instance=ema, state=state, request=request)
return form.process_request(
request,
msg_success=COMPENSATION_STATE_REMOVED,
@ -448,8 +450,9 @@ def action_remove_view(request: HttpRequest, id: str, action_id: str):
Returns:
"""
ema = get_object_or_404(Ema, id=id)
action = get_object_or_404(CompensationAction, id=action_id)
form = RemoveModalForm(request.POST or None, instance=action, request=request)
form = CompensationActionRemoveModalForm(request.POST or None, instance=ema, action=action, request=request)
return form.process_request(
request,
msg_success=COMPENSATION_ACTION_REMOVED,

@ -7,7 +7,7 @@ Created on: 27.09.21
"""
from dal import autocomplete
from konova.utils.message_templates import DEDUCTION_ADDED, REVOCATION_ADDED
from konova.utils.message_templates import DEDUCTION_ADDED, REVOCATION_ADDED, DEDUCTION_REMOVED
from user.models import User, UserActionLogEntry
from django.db import transaction
from django import forms
@ -16,7 +16,7 @@ from django.utils.translation import gettext_lazy as _
from compensation.models import EcoAccount, EcoAccountDeduction
from intervention.inputs import TextToClipboardInput
from intervention.models import Intervention, InterventionDocument
from konova.forms import BaseModalForm, NewDocumentForm
from konova.forms import BaseModalForm, NewDocumentForm, RemoveModalForm
from konova.utils.general import format_german_float
from konova.utils.user_checks import is_default_group_only
@ -172,6 +172,23 @@ class NewRevocationModalForm(BaseModalForm):
return revocation
class RevocationRemoveModalForm(RemoveModalForm):
""" Removing modal form for Revocation
Can be used for anything, where removing shall be confirmed by the user a second time.
"""
revocation = None
def __init__(self, *args, **kwargs):
revocation = kwargs.pop("revocation", None)
self.revocation = revocation
super().__init__(*args, **kwargs)
def save(self):
self.instance.remove_revocation(self)
class CheckModalForm(BaseModalForm):
""" The modal form for running a check on interventions and their compensations
@ -390,5 +407,25 @@ class NewDeductionModalForm(BaseModalForm):
return deduction
class DeductionRemoveModalForm(RemoveModalForm):
""" Removing modal form for EcoAccountDeduction
Can be used for anything, where removing shall be confirmed by the user a second time.
"""
deduction = None
def __init__(self, *args, **kwargs):
deduction = kwargs.pop("deduction", None)
self.deduction = deduction
super().__init__(*args, **kwargs)
def save(self):
with transaction.atomic():
self.deduction.intervention.mark_as_edited(self.user, edit_comment=DEDUCTION_REMOVED)
self.deduction.account.mark_as_edited(self.user, edit_comment=DEDUCTION_REMOVED)
self.deduction.delete()
class NewInterventionDocumentForm(NewDocumentForm):
document_model = InterventionDocument

@ -16,7 +16,6 @@ from django.db import models, transaction
from django.db.models import QuerySet
from django.http import HttpRequest
from compensation.models import EcoAccountDeduction
from intervention.managers import InterventionManager
from intervention.models.legal import Legal
from intervention.models.responsibility import Responsibility
@ -26,7 +25,8 @@ from konova.models import generate_document_file_upload_path, AbstractDocument,
ShareableObjectMixin, \
RecordableObjectMixin, CheckableObjectMixin, GeoReferencedMixin
from konova.settings import LANIS_LINK_TEMPLATE, LANIS_ZOOM_LUT, DEFAULT_SRID_RLP
from konova.utils.message_templates import DATA_UNSHARED_EXPLANATION, DEDUCTION_ADDED, DOCUMENT_REMOVED_TEMPLATE
from konova.utils.message_templates import DATA_UNSHARED_EXPLANATION, DOCUMENT_REMOVED_TEMPLATE, \
PAYMENT_REMOVED, PAYMENT_ADDED, REVOCATION_REMOVED
from user.models import UserActionLogEntry
@ -196,6 +196,7 @@ class Intervention(BaseObject, ShareableObjectMixin, RecordableObjectMixin, Chec
comment=form_data.get("comment", None),
intervention=self,
)
self.mark_as_edited(user, form.request, edit_comment=PAYMENT_ADDED)
return pay
def add_revocation(self, form):
@ -229,6 +230,21 @@ class Intervention(BaseObject, ShareableObjectMixin, RecordableObjectMixin, Chec
)
return revocation
def remove_revocation(self, form):
""" Removes a revocation from the intervention
Args:
form (RevocationRemoveModalForm): The form holding all relevant data
Returns:
"""
revocation = form.revocation
user = form.user
with transaction.atomic():
revocation.delete()
self.mark_as_edited(user, request=form.request, edit_comment=REVOCATION_REMOVED)
def mark_as_edited(self, performing_user: User, request: HttpRequest = None, edit_comment: str = None, reset_recorded: bool = True):
""" In case the object or a related object changed, internal processes need to be started, such as
unrecord and uncheck
@ -242,7 +258,7 @@ class Intervention(BaseObject, ShareableObjectMixin, RecordableObjectMixin, Chec
Returns:
"""
action = super().mark_as_edited(performing_user, edit_comment)
action = super().mark_as_edited(performing_user, edit_comment=edit_comment)
if reset_recorded:
self.unrecord(performing_user, request)
if self.checked:
@ -289,6 +305,21 @@ class Intervention(BaseObject, ShareableObjectMixin, RecordableObjectMixin, Chec
"""
return reverse("intervention:share", args=(self.id, self.access_token))
def remove_payment(self, form):
""" Removes a Payment from the intervention
Args:
form (PaymentRemoveModalForm): The form holding all relevant data
Returns:
"""
payment = form.payment
user = form.user
with transaction.atomic():
payment.delete()
self.mark_as_edited(user, request=form.request, edit_comment=PAYMENT_REMOVED)
class InterventionDocument(AbstractDocument):
"""

@ -23,7 +23,7 @@ class Revocation(BaseResource):
legal = models.ForeignKey("Legal", null=False, blank=False, on_delete=models.CASCADE, help_text="Refers to 'Widerspruch am'", related_name="revocations")
comment = models.TextField(null=True, blank=True)
def delete(self, user=None, *args, **kwargs):
def delete(self, *args, **kwargs):
# Make sure related objects are being removed as well
try:
self.document.delete(*args, **kwargs)
@ -31,9 +31,6 @@ class Revocation(BaseResource):
# No file to delete
pass
if user is not None:
self.legal.intervention.mark_as_edited(user, edit_comment=REVOCATION_REMOVED)
super().delete()
@property

@ -56,7 +56,7 @@
</td>
<td class="align-middle">
{% if is_default_member and has_access %}
<button data-form-url="{% url 'compensation:pay:remove' pay.id %}" class="btn btn-default btn-modal float-right" title="{% trans 'Remove payment' %}">
<button data-form-url="{% url 'compensation:pay:remove' obj.id pay.id %}" class="btn btn-default btn-modal float-right" title="{% trans 'Remove payment' %}">
{% fa5_icon 'trash' %}
</button>
{% endif %}

@ -65,7 +65,7 @@
</td>
<td class="align-middle">
{% if is_default_member and has_access %}
<button data-form-url="{% url 'intervention:remove-revocation' rev.id %}" class="btn btn-default btn-modal float-right" title="{% trans 'Remove revocation' %}">
<button data-form-url="{% url 'intervention:remove-revocation' obj.id rev.id %}" class="btn btn-default btn-modal float-right" title="{% trans 'Remove revocation' %}">
{% fa5_icon 'trash' %}
</button>
{% endif %}

@ -262,7 +262,7 @@ class InterventionWorkflowTestCase(BaseWorkflowTestCase):
pre_payment_logs_count = self.intervention.log.count()
# Create removing url for the payment
remove_url = reverse("compensation:pay:remove", args=(payment.id,))
remove_url = reverse("compensation:pay:remove", args=(self.intervention.id, payment.id,))
post_data = {
"confirm": True,
}

@ -28,7 +28,7 @@ urlpatterns = [
path('<id>/report', report_view, name='report'),
# Compensations
path('<id>/remove/<comp_id>', remove_compensation_view, name='remove-compensation'),
path('<id>/compensation/<comp_id>/remove', remove_compensation_view, name='remove-compensation'),
# Documents
path('<id>/document/new/', new_document_view, name='new-doc'),
@ -37,10 +37,10 @@ urlpatterns = [
# Deductions
path('<id>/deduction/new', new_deduction_view, name='new-deduction'),
path('<id>/remove/<deduction_id>', remove_deduction_view, name='remove-deduction'),
path('<id>/deduction/<deduction_id>/remove', remove_deduction_view, name='remove-deduction'),
# Revocation routes
path('<id>/revocation/new', new_revocation_view, name='new-revocation'),
path('revocation/<id>/remove', remove_revocation_view, name='remove-revocation'),
path('<id>/revocation/<revocation_id>/remove', remove_revocation_view, name='remove-revocation'),
path('revocation/<doc_id>', get_revocation_view, name='get-doc-revocation'),
]

@ -6,7 +6,8 @@ from django.shortcuts import render
from intervention.forms.forms import NewInterventionForm, EditInterventionForm
from intervention.forms.modalForms import ShareModalForm, NewRevocationModalForm, \
CheckModalForm, NewDeductionModalForm, NewInterventionDocumentForm
CheckModalForm, NewDeductionModalForm, NewInterventionDocumentForm, DeductionRemoveModalForm, \
RevocationRemoveModalForm
from intervention.models import Intervention, Revocation, InterventionDocument, RevocationDocument
from intervention.tables import InterventionTable
from konova.contexts import BaseContext
@ -340,7 +341,7 @@ def remove_view(request: HttpRequest, id: str):
@login_required
@default_group_required
def remove_revocation_view(request: HttpRequest, id: str):
def remove_revocation_view(request: HttpRequest, id: str, revocation_id: str):
""" Renders a remove view for a revocation
Args:
@ -350,13 +351,14 @@ def remove_revocation_view(request: HttpRequest, id: str):
Returns:
"""
obj = Revocation.objects.get(id=id)
intervention = get_object_or_404(Intervention, id=id)
revocation = get_object_or_404(Revocation, id=revocation_id)
form = RemoveModalForm(request.POST or None, instance=obj, request=request)
form = RevocationRemoveModalForm(request.POST or None, instance=intervention, revocation=revocation, request=request)
return form.process_request(
request,
REVOCATION_REMOVED,
redirect_url=reverse("intervention:detail", args=(obj.intervention.id,)) + "#related_data"
redirect_url=reverse("intervention:detail", args=(intervention.id,)) + "#related_data"
)
@ -533,7 +535,7 @@ def remove_deduction_view(request: HttpRequest, id: str, deduction_id: str):
except ObjectDoesNotExist:
raise Http404("Unknown deduction")
form = RemoveModalForm(request.POST or None, instance=eco_deduction, request=request)
form = DeductionRemoveModalForm(request.POST or None, instance=intervention, deduction=eco_deduction, request=request)
return form.process_request(
request=request,
msg_success=DEDUCTION_REMOVED,

@ -327,7 +327,7 @@ class RemoveModalForm(BaseModalForm):
self.instance.mark_as_deleted(self.user)
else:
# If the class does not provide restorable delete functionality, we must delete the entry finally
self.instance.delete(self.user)
self.instance.delete()
class DeadlineRemoveModalForm(RemoveModalForm):

Binary file not shown.

@ -1896,7 +1896,7 @@ msgstr "Zustand hinzugefügt"
#: konova/utils/message_templates.py:44
msgid "Added compensation action"
msgstr "Maßnahme hinzufügen"
msgstr "Maßnahme hinzugefügt"
#: konova/utils/message_templates.py:47
msgid "Geometry conflict detected with {}"

Loading…
Cancel
Save