#86 Edit deductions
* adds support for editing deductions * adds tests * improves major base test logic
This commit is contained in:
@@ -7,7 +7,7 @@ Created on: 27.09.21
|
||||
"""
|
||||
from dal import autocomplete
|
||||
|
||||
from konova.utils.message_templates import DEDUCTION_ADDED, REVOCATION_ADDED, DEDUCTION_REMOVED
|
||||
from konova.utils.message_templates import DEDUCTION_ADDED, REVOCATION_ADDED, DEDUCTION_REMOVED, DEDUCTION_EDITED
|
||||
from user.models import User, UserActionLogEntry
|
||||
from django.db import transaction
|
||||
from django import forms
|
||||
@@ -349,6 +349,21 @@ class NewDeductionModalForm(BaseModalForm):
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
def _get_available_surface(self, acc):
|
||||
""" Calculates how much available surface is left on the account
|
||||
|
||||
Args:
|
||||
acc (EcoAccount):
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
# Calculate valid surface
|
||||
deductable_surface = acc.deductable_surface
|
||||
sum_surface_deductions = acc.get_deductions_surface()
|
||||
rest_surface = deductable_surface - sum_surface_deductions
|
||||
return rest_surface
|
||||
|
||||
def is_valid(self):
|
||||
""" Custom validity check
|
||||
|
||||
@@ -367,10 +382,7 @@ class NewDeductionModalForm(BaseModalForm):
|
||||
)
|
||||
return False
|
||||
|
||||
# Calculate valid surface
|
||||
deductable_surface = acc.deductable_surface
|
||||
sum_surface_deductions = acc.get_deductions_surface()
|
||||
rest_surface = deductable_surface - sum_surface_deductions
|
||||
rest_surface = self._get_available_surface(acc)
|
||||
form_surface = float(self.cleaned_data["surface"])
|
||||
is_valid_surface = form_surface <= rest_surface
|
||||
if not is_valid_surface:
|
||||
@@ -407,6 +419,57 @@ class NewDeductionModalForm(BaseModalForm):
|
||||
return deduction
|
||||
|
||||
|
||||
class EditEcoAccountDeductionModalForm(NewDeductionModalForm):
|
||||
deduction = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.deduction = kwargs.pop("deduction", None)
|
||||
super().__init__(*args, **kwargs)
|
||||
form_data = {
|
||||
"account": self.deduction.account,
|
||||
"intervention": self.deduction.intervention,
|
||||
"surface": self.deduction.surface,
|
||||
}
|
||||
self.load_initial_data(form_data)
|
||||
|
||||
def _get_available_surface(self, acc):
|
||||
rest_surface = super()._get_available_surface(acc)
|
||||
# Increase available surface by the currently deducted surface, so we can 'deduct' the same amount again or
|
||||
# increase the surface only a little, which will still be valid.
|
||||
# Example: 200 m² left, 500 m² deducted. Entering 700 m² would fail if we would not add the 500 m² to the available
|
||||
# surface again.
|
||||
rest_surface += self.deduction.surface
|
||||
return rest_surface
|
||||
|
||||
def save(self):
|
||||
deduction = self.deduction
|
||||
form_account = self.cleaned_data.get("account", None)
|
||||
form_intervention = self.cleaned_data.get("intervention", None)
|
||||
current_account = deduction.account
|
||||
current_intervention = deduction.intervention
|
||||
|
||||
|
||||
# If account or intervention has been changed, we put that change in the logs just as if the deduction has
|
||||
# been removed for this entry. Act as if the deduction is newly created for the new entries
|
||||
if current_account != form_account:
|
||||
current_account.mark_as_edited(self.user, self.request, edit_comment=DEDUCTION_REMOVED)
|
||||
form_account.mark_as_edited(self.user, self.request, edit_comment=DEDUCTION_ADDED)
|
||||
else:
|
||||
current_account.mark_as_edited(self.user, self.request, edit_comment=DEDUCTION_EDITED)
|
||||
|
||||
if current_intervention != form_intervention:
|
||||
current_intervention.mark_as_edited(self.user, self.request, edit_comment=DEDUCTION_REMOVED)
|
||||
form_intervention.mark_as_edited(self.user, self.request, edit_comment=DEDUCTION_ADDED)
|
||||
else:
|
||||
current_intervention.mark_as_edited(self.user, self.request, edit_comment=DEDUCTION_EDITED)
|
||||
|
||||
deduction.account = form_account
|
||||
deduction.intervention = self.cleaned_data.get("intervention", None)
|
||||
deduction.surface = self.cleaned_data.get("surface", None)
|
||||
deduction.save()
|
||||
return deduction
|
||||
|
||||
|
||||
class RemoveEcoAccountDeductionModalForm(RemoveModalForm):
|
||||
""" Removing modal form for EcoAccountDeduction
|
||||
|
||||
|
||||
@@ -55,9 +55,12 @@
|
||||
</td>
|
||||
<td class="align-middle">{{ deduction.surface|floatformat:2|intcomma }} m²</td>
|
||||
<td class="align-middle">{{ deduction.created.timestamp|default_if_none:""|naturalday}}</td>
|
||||
<td>
|
||||
<td class="align-middle float-right">
|
||||
{% if is_default_member and has_access %}
|
||||
<button data-form-url="{% url 'intervention:remove-deduction' obj.id deduction.id %}" class="btn btn-default btn-modal float-right" title="{% trans 'Remove Deduction' %}">
|
||||
<button data-form-url="{% url 'intervention:edit-deduction' obj.id deduction.id %}" class="btn btn-default btn-modal" title="{% trans 'Edit Deduction' %}">
|
||||
{% fa5_icon 'edit' %}
|
||||
</button>
|
||||
<button data-form-url="{% url 'intervention:remove-deduction' obj.id deduction.id %}" class="btn btn-default btn-modal" title="{% trans 'Remove Deduction' %}">
|
||||
{% fa5_icon 'trash' %}
|
||||
</button>
|
||||
{% endif %}
|
||||
|
||||
@@ -21,30 +21,32 @@ class InterventionViewTestCase(BaseViewTestCase):
|
||||
def setUpTestData(cls) -> None:
|
||||
super().setUpTestData()
|
||||
|
||||
def setUp(self) -> None:
|
||||
super().setUp()
|
||||
# Prepare urls
|
||||
cls.index_url = reverse("intervention:index", args=())
|
||||
cls.new_url = reverse("intervention:new", args=())
|
||||
cls.new_id_url = reverse("intervention:new-id", args=())
|
||||
cls.detail_url = reverse("intervention:detail", args=(cls.intervention.id,))
|
||||
cls.log_url = reverse("intervention:log", args=(cls.intervention.id,))
|
||||
cls.edit_url = reverse("intervention:edit", args=(cls.intervention.id,))
|
||||
cls.remove_url = reverse("intervention:remove", args=(cls.intervention.id,))
|
||||
cls.share_url = reverse("intervention:share", args=(cls.intervention.id, cls.intervention.access_token,))
|
||||
cls.share_create_url = reverse("intervention:share-create", args=(cls.intervention.id,))
|
||||
cls.run_check_url = reverse("intervention:check", args=(cls.intervention.id,))
|
||||
cls.record_url = reverse("intervention:record", args=(cls.intervention.id,))
|
||||
cls.report_url = reverse("intervention:report", args=(cls.intervention.id,))
|
||||
self.index_url = reverse("intervention:index", args=())
|
||||
self.new_url = reverse("intervention:new", args=())
|
||||
self.new_id_url = reverse("intervention:new-id", args=())
|
||||
self.detail_url = reverse("intervention:detail", args=(self.intervention.id,))
|
||||
self.log_url = reverse("intervention:log", args=(self.intervention.id,))
|
||||
self.edit_url = reverse("intervention:edit", args=(self.intervention.id,))
|
||||
self.remove_url = reverse("intervention:remove", args=(self.intervention.id,))
|
||||
self.share_url = reverse("intervention:share", args=(self.intervention.id, self.intervention.access_token,))
|
||||
self.share_create_url = reverse("intervention:share-create", args=(self.intervention.id,))
|
||||
self.run_check_url = reverse("intervention:check", args=(self.intervention.id,))
|
||||
self.record_url = reverse("intervention:record", args=(self.intervention.id,))
|
||||
self.report_url = reverse("intervention:report", args=(self.intervention.id,))
|
||||
|
||||
cls.deduction.intervention = cls.intervention
|
||||
cls.deduction.save()
|
||||
cls.deduction_new_url = reverse("intervention:new-deduction", args=(cls.intervention.id,))
|
||||
cls.deduction_remove_url = reverse("intervention:remove-deduction", args=(cls.intervention.id, cls.deduction.id))
|
||||
self.deduction.intervention = self.intervention
|
||||
self.deduction.save()
|
||||
self.deduction_new_url = reverse("intervention:new-deduction", args=(self.intervention.id,))
|
||||
self.deduction_remove_url = reverse("intervention:remove-deduction", args=(self.intervention.id, self.deduction.id))
|
||||
|
||||
cls.revocation = Revocation.objects.create(
|
||||
legal=cls.intervention.legal
|
||||
self.revocation = Revocation.objects.create(
|
||||
legal=self.intervention.legal
|
||||
)
|
||||
cls.revocation_new_url = reverse("intervention:new-revocation", args=(cls.intervention.id,))
|
||||
cls.revocation_remove_url = reverse("intervention:remove-revocation", args=(cls.intervention.id, cls.revocation.id))
|
||||
self.revocation_new_url = reverse("intervention:new-revocation", args=(self.intervention.id,))
|
||||
self.revocation_remove_url = reverse("intervention:remove-revocation", args=(self.intervention.id, self.revocation.id))
|
||||
|
||||
def test_views_anonymous_user(self):
|
||||
""" Check correct status code for all requests
|
||||
|
||||
@@ -10,7 +10,7 @@ from django.urls import path
|
||||
from intervention.views import index_view, new_view, detail_view, edit_view, remove_view, new_document_view, share_view, \
|
||||
create_share_view, remove_revocation_view, new_revocation_view, check_view, log_view, new_deduction_view, \
|
||||
record_view, remove_document_view, get_document_view, get_revocation_view, new_id_view, report_view, \
|
||||
remove_deduction_view, remove_compensation_view
|
||||
remove_deduction_view, remove_compensation_view, edit_deduction_view
|
||||
|
||||
app_name = "intervention"
|
||||
urlpatterns = [
|
||||
@@ -37,6 +37,7 @@ urlpatterns = [
|
||||
|
||||
# Deductions
|
||||
path('<id>/deduction/new', new_deduction_view, name='new-deduction'),
|
||||
path('<id>/deduction/<deduction_id>/edit', edit_deduction_view, name='edit-deduction'),
|
||||
path('<id>/deduction/<deduction_id>/remove', remove_deduction_view, name='remove-deduction'),
|
||||
|
||||
# Revocation routes
|
||||
|
||||
@@ -7,7 +7,7 @@ from django.shortcuts import render
|
||||
from intervention.forms.forms import NewInterventionForm, EditInterventionForm
|
||||
from intervention.forms.modalForms import ShareModalForm, NewRevocationModalForm, \
|
||||
CheckModalForm, NewDeductionModalForm, NewInterventionDocumentForm, RemoveEcoAccountDeductionModalForm, \
|
||||
RemoveRevocationModalForm
|
||||
RemoveRevocationModalForm, EditEcoAccountDeductionModalForm
|
||||
from intervention.models import Intervention, Revocation, InterventionDocument, RevocationDocument
|
||||
from intervention.tables import InterventionTable
|
||||
from konova.contexts import BaseContext
|
||||
@@ -18,7 +18,7 @@ from konova.utils.documents import remove_document, get_document
|
||||
from konova.utils.generators import generate_qr_code
|
||||
from konova.utils.message_templates import INTERVENTION_INVALID, FORM_INVALID, IDENTIFIER_REPLACED, \
|
||||
CHECKED_RECORDED_RESET, DEDUCTION_REMOVED, DEDUCTION_ADDED, REVOCATION_ADDED, REVOCATION_REMOVED, \
|
||||
COMPENSATION_REMOVED_TEMPLATE, DOCUMENT_ADDED
|
||||
COMPENSATION_REMOVED_TEMPLATE, DOCUMENT_ADDED, DEDUCTION_EDITED
|
||||
from konova.utils.user_checks import in_group
|
||||
|
||||
|
||||
@@ -536,6 +536,34 @@ def remove_deduction_view(request: HttpRequest, id: str, deduction_id: str):
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@default_group_required
|
||||
@shared_access_required(Intervention, "id")
|
||||
def edit_deduction_view(request: HttpRequest, id: str, deduction_id: str):
|
||||
""" Renders a modal view for removing deductions
|
||||
|
||||
Args:
|
||||
request (HttpRequest): The incoming request
|
||||
id (str): The intervention's id
|
||||
deduction_id (str): The deduction's id
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
intervention = get_object_or_404(Intervention, id=id)
|
||||
try:
|
||||
eco_deduction = intervention.deductions.get(id=deduction_id)
|
||||
except ObjectDoesNotExist:
|
||||
raise Http404("Unknown deduction")
|
||||
|
||||
form = EditEcoAccountDeductionModalForm(request.POST or None, instance=intervention, deduction=eco_deduction, request=request)
|
||||
return form.process_request(
|
||||
request=request,
|
||||
msg_success=DEDUCTION_EDITED,
|
||||
redirect_url=reverse("intervention:detail", args=(id,)) + "#related_data"
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
@conservation_office_group_required
|
||||
@shared_access_required(Intervention, "id")
|
||||
|
||||
Reference in New Issue
Block a user