* refactors remove view for kom, eiv, oek and ema * introduces BaseRemoveModalFormView * moves html blocking logic from BaseModalForm into BaseModalFormView
		
			
				
	
	
		
			265 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			265 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""
 | 
						|
Author: Michel Peltriaux
 | 
						|
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
 | 
						|
Contact: ksp-servicestelle@sgdnord.rlp.de
 | 
						|
Created on: 19.08.22
 | 
						|
 | 
						|
"""
 | 
						|
from django.contrib import messages
 | 
						|
from django.contrib.auth.decorators import login_required
 | 
						|
from django.contrib.auth.mixins import LoginRequiredMixin
 | 
						|
from django.http import HttpRequest
 | 
						|
from django.shortcuts import get_object_or_404, redirect, render
 | 
						|
from django.urls import reverse
 | 
						|
from django.utils.translation import gettext_lazy as _
 | 
						|
 | 
						|
from compensation.forms.eco_account import EditEcoAccountForm, NewEcoAccountForm, RemoveEcoAccountModalForm
 | 
						|
from compensation.models import EcoAccount
 | 
						|
from compensation.tables.eco_account import EcoAccountTable
 | 
						|
from konova.contexts import BaseContext
 | 
						|
from konova.decorators import shared_access_required, default_group_required, login_required_modal
 | 
						|
from konova.forms import SimpleGeomForm
 | 
						|
from konova.settings import ETS_GROUP
 | 
						|
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
 | 
						|
from konova.utils.message_templates import CANCEL_ACC_RECORDED_OR_DEDUCTED, RECORDED_BLOCKS_EDIT, FORM_INVALID, \
 | 
						|
    IDENTIFIER_REPLACED, GEOMETRY_SIMPLIFIED, GEOMETRIES_IGNORED_TEMPLATE
 | 
						|
from konova.views.base import BaseIndexView, BaseIdentifierGeneratorView, BaseNewSpatialLocatedObjectFormView, \
 | 
						|
    BaseEditSpatialLocatedObjectFormView
 | 
						|
from konova.views.detail import BaseDetailView
 | 
						|
from konova.views.remove import BaseRemoveModalFormView
 | 
						|
 | 
						|
 | 
						|
class EcoAccountIndexView(LoginRequiredMixin, BaseIndexView):
 | 
						|
    _INDEX_TABLE_CLS = EcoAccountTable
 | 
						|
    _TAB_TITLE = _("Eco-account - Overview")
 | 
						|
 | 
						|
    def _get_queryset(self):
 | 
						|
        qs = EcoAccount.objects.filter(
 | 
						|
            deleted=None,
 | 
						|
        ).order_by(
 | 
						|
            "-modified__timestamp"
 | 
						|
        )
 | 
						|
        return qs
 | 
						|
 | 
						|
 | 
						|
class NewEcoAccountFormView(BaseNewSpatialLocatedObjectFormView):
 | 
						|
    _FORM_CLS = NewEcoAccountForm
 | 
						|
    _MODEL_CLS = EcoAccount
 | 
						|
    _TEMPLATE = "compensation/form/view.html"
 | 
						|
    _TAB_TITLE = _("New Eco-Account")
 | 
						|
    _REDIRECT_URL = "compensation:acc:detail"
 | 
						|
 | 
						|
    def _user_has_permission(self, user):
 | 
						|
        # User has to be a default user
 | 
						|
        return user.is_default_user()
 | 
						|
 | 
						|
 | 
						|
class EditEcoAccountFormView(BaseEditSpatialLocatedObjectFormView):
 | 
						|
    _FORM_CLS = EditEcoAccountForm
 | 
						|
    _MODEL_CLS = EcoAccount
 | 
						|
    _TEMPLATE = "compensation/form/view.html"
 | 
						|
    _REDIRECT_URL = "compensation:acc:detail"
 | 
						|
 | 
						|
    def _user_has_permission(self, user):
 | 
						|
        # User has to be a default user
 | 
						|
        return user.is_default_user()
 | 
						|
 | 
						|
 | 
						|
@login_required
 | 
						|
@default_group_required
 | 
						|
def new_view(request: HttpRequest):
 | 
						|
    """
 | 
						|
    Renders a view for a new eco account creation
 | 
						|
 | 
						|
    Args:
 | 
						|
        request (HttpRequest): The incoming request
 | 
						|
 | 
						|
    Returns:
 | 
						|
 | 
						|
    """
 | 
						|
    template = "compensation/form/view.html"
 | 
						|
    data_form = NewEcoAccountForm(request.POST or None)
 | 
						|
    geom_form = SimpleGeomForm(request.POST or None, read_only=False)
 | 
						|
    if request.method == "POST":
 | 
						|
        if data_form.is_valid() and geom_form.is_valid():
 | 
						|
            generated_identifier = data_form.cleaned_data.get("identifier", None)
 | 
						|
            acc = data_form.save(request.user, geom_form)
 | 
						|
            if generated_identifier != acc.identifier:
 | 
						|
                messages.info(
 | 
						|
                    request,
 | 
						|
                    IDENTIFIER_REPLACED.format(
 | 
						|
                        generated_identifier,
 | 
						|
                        acc.identifier
 | 
						|
                    )
 | 
						|
                )
 | 
						|
            messages.success(request, _("Eco-Account {} added").format(acc.identifier))
 | 
						|
            if geom_form.has_geometry_simplified():
 | 
						|
                messages.info(
 | 
						|
                    request,
 | 
						|
                    GEOMETRY_SIMPLIFIED
 | 
						|
                )
 | 
						|
 | 
						|
            num_ignored_geometries = geom_form.get_num_geometries_ignored()
 | 
						|
            if num_ignored_geometries > 0:
 | 
						|
                messages.info(
 | 
						|
                    request,
 | 
						|
                    GEOMETRIES_IGNORED_TEMPLATE.format(num_ignored_geometries)
 | 
						|
                )
 | 
						|
 | 
						|
            return redirect("compensation:acc:detail", id=acc.id)
 | 
						|
        else:
 | 
						|
            messages.error(request, FORM_INVALID, extra_tags="danger",)
 | 
						|
    else:
 | 
						|
        # For clarification: nothing in this case
 | 
						|
        pass
 | 
						|
    context = {
 | 
						|
        "form": data_form,
 | 
						|
        "geom_form": geom_form,
 | 
						|
        TAB_TITLE_IDENTIFIER: _("New Eco-Account"),
 | 
						|
    }
 | 
						|
    context = BaseContext(request, context).context
 | 
						|
    return render(request, template, context)
 | 
						|
 | 
						|
 | 
						|
class EcoAccountIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView):
 | 
						|
    _MODEL_CLS = EcoAccount
 | 
						|
    _REDIRECT_URL = "compensation:acc:index"
 | 
						|
 | 
						|
 | 
						|
@login_required
 | 
						|
@default_group_required
 | 
						|
@shared_access_required(EcoAccount, "id")
 | 
						|
def edit_view(request: HttpRequest, id: str):
 | 
						|
    """
 | 
						|
    Renders a view for editing compensations
 | 
						|
 | 
						|
    Args:
 | 
						|
        request (HttpRequest): The incoming request
 | 
						|
 | 
						|
    Returns:
 | 
						|
 | 
						|
    """
 | 
						|
    template = "compensation/form/view.html"
 | 
						|
    # Get object from db
 | 
						|
    acc = get_object_or_404(EcoAccount, id=id)
 | 
						|
    if acc.is_recorded:
 | 
						|
        messages.info(
 | 
						|
            request,
 | 
						|
            RECORDED_BLOCKS_EDIT
 | 
						|
        )
 | 
						|
        return redirect("compensation:acc:detail", id=id)
 | 
						|
 | 
						|
    # Create forms, initialize with values from db/from POST request
 | 
						|
    data_form = EditEcoAccountForm(request.POST or None, instance=acc)
 | 
						|
    geom_form = SimpleGeomForm(request.POST or None, read_only=False, instance=acc)
 | 
						|
    if request.method == "POST":
 | 
						|
        data_form_valid = data_form.is_valid()
 | 
						|
        geom_form_valid = geom_form.is_valid()
 | 
						|
        if data_form_valid and geom_form_valid:
 | 
						|
            # The data form takes the geom form for processing, as well as the performing user
 | 
						|
            acc = data_form.save(request.user, geom_form)
 | 
						|
            messages.success(request, _("Eco-Account {} edited").format(acc.identifier))
 | 
						|
            if geom_form.has_geometry_simplified():
 | 
						|
                messages.info(
 | 
						|
                    request,
 | 
						|
                    GEOMETRY_SIMPLIFIED
 | 
						|
                )
 | 
						|
 | 
						|
            num_ignored_geometries = geom_form.get_num_geometries_ignored()
 | 
						|
            if num_ignored_geometries > 0:
 | 
						|
                messages.info(
 | 
						|
                    request,
 | 
						|
                    GEOMETRIES_IGNORED_TEMPLATE.format(num_ignored_geometries)
 | 
						|
                )
 | 
						|
 | 
						|
            return redirect("compensation:acc:detail", id=acc.id)
 | 
						|
        else:
 | 
						|
            messages.error(request, FORM_INVALID, extra_tags="danger",)
 | 
						|
    else:
 | 
						|
        # For clarification: nothing in this case
 | 
						|
        pass
 | 
						|
    context = {
 | 
						|
        "form": data_form,
 | 
						|
        "geom_form": geom_form,
 | 
						|
        TAB_TITLE_IDENTIFIER: _("Edit {}").format(acc.identifier),
 | 
						|
    }
 | 
						|
    context = BaseContext(request, context).context
 | 
						|
    return render(request, template, context)
 | 
						|
 | 
						|
 | 
						|
class EcoAccountDetailView(BaseDetailView):
 | 
						|
    _MODEL_CLS = EcoAccount
 | 
						|
    _TEMPLATE = "compensation/detail/eco_account/view.html"
 | 
						|
 | 
						|
    def _get_object(self, id: str):
 | 
						|
        """ Fetch object for detail view
 | 
						|
 | 
						|
        Args:
 | 
						|
            id (str): The record's id'
 | 
						|
 | 
						|
        Returns:
 | 
						|
 | 
						|
        """
 | 
						|
        acc = get_object_or_404(
 | 
						|
            EcoAccount.objects.prefetch_related(
 | 
						|
                "deadlines",
 | 
						|
            ).select_related(
 | 
						|
                'geometry',
 | 
						|
                'responsible',
 | 
						|
            ),
 | 
						|
            id=id,
 | 
						|
            deleted=None,
 | 
						|
        )
 | 
						|
        return acc
 | 
						|
 | 
						|
    def _get_detail_context(self, obj: EcoAccount):
 | 
						|
        """ Generate object specific detail context for  view
 | 
						|
 | 
						|
        Args:
 | 
						|
            obj (): The record
 | 
						|
 | 
						|
        Returns:
 | 
						|
 | 
						|
        """
 | 
						|
        # Order states according to surface
 | 
						|
        before_states = obj.before_states.order_by("-surface")
 | 
						|
        after_states = obj.after_states.order_by("-surface")
 | 
						|
 | 
						|
        # Precalculate logical errors between before- and after-states
 | 
						|
        # Sum() returns None in case of no states, so we catch that and replace it with 0 for easier handling
 | 
						|
        sum_before_states = obj.get_surface_before_states()
 | 
						|
        sum_after_states = obj.get_surface_after_states()
 | 
						|
        diff_states = abs(sum_before_states - sum_after_states)
 | 
						|
        # Calculate rest of available surface for deductions
 | 
						|
        available_total = obj.deductable_rest
 | 
						|
        available_relative = obj.get_deductable_rest_relative()
 | 
						|
 | 
						|
        # Prefetch related data to decrease the amount of db connections
 | 
						|
        deductions = obj.deductions.filter(
 | 
						|
            intervention__deleted=None,
 | 
						|
        )
 | 
						|
        actions = obj.actions.all()
 | 
						|
 | 
						|
        context = {
 | 
						|
            "before_states": before_states,
 | 
						|
            "after_states": after_states,
 | 
						|
            "sum_before_states": sum_before_states,
 | 
						|
            "sum_after_states": sum_after_states,
 | 
						|
            "diff_states": diff_states,
 | 
						|
            "available": available_relative,
 | 
						|
            "available_total": available_total,
 | 
						|
            "deductions": deductions,
 | 
						|
            "actions": actions,
 | 
						|
            "has_finished_deadlines": obj.get_finished_deadlines().exists(),
 | 
						|
        }
 | 
						|
        return context
 | 
						|
 | 
						|
 | 
						|
class RemoveEcoAccountView(LoginRequiredMixin, BaseRemoveModalFormView):
 | 
						|
    _MODEL_CLS = EcoAccount
 | 
						|
    _FORM_CLS = RemoveEcoAccountModalForm
 | 
						|
    _REDIRECT_URL = "compensation:acc:index"
 | 
						|
 | 
						|
    def _user_has_permission(self, user):
 | 
						|
        return user.is_default_user()
 |