26_Annual_conservation_reports #33
							
								
								
									
										0
									
								
								analysis/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								analysis/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										3
									
								
								analysis/admin.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								analysis/admin.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
			
		||||
from django.contrib import admin
 | 
			
		||||
 | 
			
		||||
# Register your models here.
 | 
			
		||||
							
								
								
									
										5
									
								
								analysis/apps.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								analysis/apps.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
from django.apps import AppConfig
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AnalysisConfig(AppConfig):
 | 
			
		||||
    name = 'analysis'
 | 
			
		||||
							
								
								
									
										82
									
								
								analysis/forms.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								analysis/forms.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,82 @@
 | 
			
		||||
"""
 | 
			
		||||
Author: Michel Peltriaux
 | 
			
		||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
 | 
			
		||||
Contact: michel.peltriaux@sgdnord.rlp.de
 | 
			
		||||
Created on: 20.10.21
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
from dal import autocomplete
 | 
			
		||||
from django import forms
 | 
			
		||||
from django.urls import reverse
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from codelist.models import KonovaCode
 | 
			
		||||
from codelist.settings import CODELIST_CONSERVATION_OFFICE_ID
 | 
			
		||||
from konova.forms import BaseForm
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TimespanReportForm(BaseForm):
 | 
			
		||||
    """ TimespanReporForm is used for allowing simple creation of an e.g. annual report for conservation offices
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    date_from = forms.DateField(
 | 
			
		||||
        label_suffix="",
 | 
			
		||||
        label=_("From"),
 | 
			
		||||
        widget=forms.DateInput(
 | 
			
		||||
            attrs={
 | 
			
		||||
                "type": "date",
 | 
			
		||||
                "data-provide": "datepicker",
 | 
			
		||||
                "class": "form-control",
 | 
			
		||||
            },
 | 
			
		||||
            format="%d.%m.%Y"
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
    date_to = forms.DateField(
 | 
			
		||||
        label_suffix="",
 | 
			
		||||
        label=_("To"),
 | 
			
		||||
        widget=forms.DateInput(
 | 
			
		||||
            attrs={
 | 
			
		||||
                "type": "date",
 | 
			
		||||
                "data-provide": "datepicker",
 | 
			
		||||
                "class": "form-control",
 | 
			
		||||
            },
 | 
			
		||||
            format="%d.%m.%Y"
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
    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")
 | 
			
		||||
            }
 | 
			
		||||
        ),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.form_title = _("Generate report")
 | 
			
		||||
        self.form_caption = _("Select a timespan and the desired conservation office")
 | 
			
		||||
        self.action_url = reverse("analysis:reports")
 | 
			
		||||
        self.show_cancel_btn = False
 | 
			
		||||
        self.action_btn_label = _("Continue")
 | 
			
		||||
 | 
			
		||||
    def save(self) -> str:
 | 
			
		||||
        """ Generates a redirect url for the detail report
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
            detail_report_url (str): The constructed detail report url
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        date_from = self.cleaned_data.get("date_from", None)
 | 
			
		||||
        date_to = self.cleaned_data.get("date_to", None)
 | 
			
		||||
        office = self.cleaned_data.get("conservation_office", None)
 | 
			
		||||
        detail_report_url = reverse("analysis:report-detail", args=(office.id,)) + f"?df={date_from}&dt={date_to}"
 | 
			
		||||
        return detail_report_url
 | 
			
		||||
							
								
								
									
										3
									
								
								analysis/models.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								analysis/models.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
			
		||||
from django.db import models
 | 
			
		||||
 | 
			
		||||
# Create your models here.
 | 
			
		||||
							
								
								
									
										12
									
								
								analysis/settings.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								analysis/settings.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
"""
 | 
			
		||||
Author: Michel Peltriaux
 | 
			
		||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
 | 
			
		||||
Contact: michel.peltriaux@sgdnord.rlp.de
 | 
			
		||||
Created on: 19.10.21
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
# Defines the date of the legal publishing of the LKompVzVo
 | 
			
		||||
from django.utils import timezone
 | 
			
		||||
 | 
			
		||||
LKOMPVZVO_PUBLISH_DATE = timezone.make_aware(timezone.datetime.fromisoformat("2018-06-16"))
 | 
			
		||||
							
								
								
									
										36
									
								
								analysis/templates/analysis/reports/detail.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								analysis/templates/analysis/reports/detail.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,36 @@
 | 
			
		||||
{% extends 'base.html' %}
 | 
			
		||||
{% load i18n fontawesome_5 %}
 | 
			
		||||
 | 
			
		||||
{% block body %}
 | 
			
		||||
    <div class="row">
 | 
			
		||||
        <div class="col-sm-12 col-md-12 col-lg-6">
 | 
			
		||||
            <h3>{% trans 'Evaluation report' %} {{office.long_name}}</h3>
 | 
			
		||||
            <h5>{% trans 'From' %} {{report.date_from.date}} {% trans 'to' %} {{report.date_to.date}}</h5>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="col-sm-12 col-md-12 col-lg-6">
 | 
			
		||||
            <div class="d-flex justify-content-end">
 | 
			
		||||
                <div class="dropdown">
 | 
			
		||||
                    <div class="btn btn" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
 | 
			
		||||
                        <button class="btn btn-default" title="{% trans 'Download' %}">
 | 
			
		||||
                            {% fa5_icon 'download' %}
 | 
			
		||||
                        </button>
 | 
			
		||||
                    </div>
 | 
			
		||||
                    <div class="dropdown-menu dropdown-menu-right">
 | 
			
		||||
                        <a href="{{request.url}}?format=excel&{{request.GET.urlencode}}">
 | 
			
		||||
                            <button class="dropdown-item" title="Excel">
 | 
			
		||||
                                {% fa5_icon 'file-excel' %} Excel
 | 
			
		||||
                            </button>
 | 
			
		||||
                        </a>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <hr>
 | 
			
		||||
    <div class="col-sm-12 col-md-12 col-lg-12">
 | 
			
		||||
    {% include 'analysis/reports/includes/intervention/card_intervention.html' %}
 | 
			
		||||
    {% include 'analysis/reports/includes/compensation/card_compensation.html' %}
 | 
			
		||||
    {% include 'analysis/reports/includes/eco_account/card_eco_account.html' %}
 | 
			
		||||
    {% include 'analysis/reports/includes/old_data/card_old_interventions.html' %}
 | 
			
		||||
    </div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
@ -0,0 +1,55 @@
 | 
			
		||||
{% load i18n fontawesome_5 ksp_filters %}
 | 
			
		||||
 | 
			
		||||
<h3>{% trans 'Amount' %}</h3>
 | 
			
		||||
<strong>
 | 
			
		||||
    {% blocktrans %}
 | 
			
		||||
    Checked = Has been checked by the registration office according to LKompVzVo
 | 
			
		||||
    {% endblocktrans %}
 | 
			
		||||
    <br>
 | 
			
		||||
    {% blocktrans %}
 | 
			
		||||
    Recorded = Has been checked and published by the conservation office
 | 
			
		||||
    {% endblocktrans %}
 | 
			
		||||
</strong>
 | 
			
		||||
<div class="table-container">
 | 
			
		||||
    <table class="table table-hover">
 | 
			
		||||
        <thead>
 | 
			
		||||
        <tr>
 | 
			
		||||
            <th scope="col">{% trans 'Area of responsibility' %}</th>
 | 
			
		||||
            <th scope="col">{% fa5_icon 'star' %} {% trans 'Checked' %}</th>
 | 
			
		||||
            <th scope="col">{% fa5_icon 'bookmark' %} {% trans 'Recorded' %}</th>
 | 
			
		||||
            <th scope="col">{% trans 'Number single areas' %}</th>
 | 
			
		||||
            <th scope="col">{% trans 'Total' %}</th>
 | 
			
		||||
        </tr>
 | 
			
		||||
        </thead>
 | 
			
		||||
        <tbody>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>{% trans 'Conservation office by law' %}</td>
 | 
			
		||||
                <td>{{report.compensation_report.queryset_registration_office_unb_checked_count|default_if_zero:"-"}}</td>
 | 
			
		||||
                <td>{{report.compensation_report.queryset_registration_office_unb_recorded_count|default_if_zero:"-"}}</td>
 | 
			
		||||
                <td>{{report.compensation_report.num_single_surfaces_total_unb|default_if_zero:"-"}}</td>
 | 
			
		||||
                <td>{{report.compensation_report.queryset_registration_office_unb_count|default_if_zero:"-"}}</td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>{% trans 'Land-use planning' %}</td>
 | 
			
		||||
                <td>{{report.compensation_report.queryset_registration_office_tbp_checked_count|default_if_zero:"-"}}</td>
 | 
			
		||||
                <td>{{report.compensation_report.queryset_registration_office_tbp_recorded_count|default_if_zero:"-"}}</td>
 | 
			
		||||
                <td>{{report.compensation_report.num_single_surfaces_total_tbp|default_if_zero:"-"}}</td>
 | 
			
		||||
                <td>{{report.compensation_report.queryset_registration_office_tbp_count|default_if_zero:"-"}}</td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>{% trans 'Other registration office' %}</td>
 | 
			
		||||
                <td>{{report.compensation_report.queryset_registration_office_other_checked_count|default_if_zero:"-"}}</td>
 | 
			
		||||
                <td>{{report.compensation_report.queryset_registration_office_other_recorded_count|default_if_zero:"-"}}</td>
 | 
			
		||||
                <td>{{report.compensation_report.num_single_surfaces_total_other|default_if_zero:"-"}}</td>
 | 
			
		||||
                <td>{{report.compensation_report.queryset_registration_office_other_count|default_if_zero:"-"}}</td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td><strong>{% trans 'Total' %}</strong></td>
 | 
			
		||||
                <td><strong>{{report.compensation_report.queryset_checked_count|default_if_zero:"-"}}</strong></td>
 | 
			
		||||
                <td><strong>{{report.compensation_report.queryset_recorded_count|default_if_zero:"-"}}</strong></td>
 | 
			
		||||
                <td><strong>{{report.compensation_report.num_single_surfaces_total|default_if_zero:"-"}}</strong></td>
 | 
			
		||||
                <td><strong>{{report.compensation_report.queryset_count|default_if_zero:"-"}}</strong></td>
 | 
			
		||||
            </tr>
 | 
			
		||||
        </tbody>
 | 
			
		||||
    </table>
 | 
			
		||||
</div>
 | 
			
		||||
@ -0,0 +1,23 @@
 | 
			
		||||
{% load i18n fontawesome_5 %}
 | 
			
		||||
 | 
			
		||||
    <div class="row">
 | 
			
		||||
        <div class="col-sm-12 col-md-12 col-lg-12">
 | 
			
		||||
            <div class="card">
 | 
			
		||||
                <div id="compensation" class="card-header cursor-pointer rlp-r" data-toggle="collapse" data-target="#compensationBody" aria-expanded="true" aria-controls="compensationBody">
 | 
			
		||||
                    <div class="row">
 | 
			
		||||
                        <div class="col-sm-6">
 | 
			
		||||
                            <h5>
 | 
			
		||||
                                {% fa5_icon 'leaf' %}
 | 
			
		||||
                                {% trans 'Compensations' %}
 | 
			
		||||
                            </h5>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div id="compensationBody"  class="collapse" aria-labelledby="compensation">
 | 
			
		||||
                    <div class="card-body">
 | 
			
		||||
                        {% include 'analysis/reports/includes/compensation/amount.html' %}
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
@ -0,0 +1,24 @@
 | 
			
		||||
{% load i18n fontawesome_5 ksp_filters %}
 | 
			
		||||
 | 
			
		||||
<h3>{% trans 'Amount' %}</h3>
 | 
			
		||||
<strong>
 | 
			
		||||
    {% blocktrans %}
 | 
			
		||||
    Recorded = Has been checked and published by the conservation office
 | 
			
		||||
    {% endblocktrans %}
 | 
			
		||||
</strong>
 | 
			
		||||
<div class="table-container">
 | 
			
		||||
    <table class="table table-hover">
 | 
			
		||||
        <thead>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <th scope="col" class="w-25">{% fa5_icon 'bookmark' %} {% trans 'Recorded' %}</th>
 | 
			
		||||
                <th scope="col">{% trans 'Total' %}</th>
 | 
			
		||||
            </tr>
 | 
			
		||||
        </thead>
 | 
			
		||||
        <tbody>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>{{report.eco_account_report.queryset_recorded_count|default_if_zero:"-"}}</td>
 | 
			
		||||
                <td>{{report.eco_account_report.queryset_count|default_if_zero:"-"}}</td>
 | 
			
		||||
            </tr>
 | 
			
		||||
        </tbody>
 | 
			
		||||
    </table>
 | 
			
		||||
</div>
 | 
			
		||||
@ -0,0 +1,25 @@
 | 
			
		||||
{% load i18n fontawesome_5 %}
 | 
			
		||||
 | 
			
		||||
    <div class="row">
 | 
			
		||||
        <div class="col-sm-12 col-md-12 col-lg-12">
 | 
			
		||||
            <div class="card">
 | 
			
		||||
                <div id="ecoAccounts" class="card-header cursor-pointer rlp-r" data-toggle="collapse" data-target="#ecoAccountsBody" aria-expanded="true" aria-controls="ecoAccountsBody">
 | 
			
		||||
                    <div class="row">
 | 
			
		||||
                        <div class="col-sm-6">
 | 
			
		||||
                            <h5>
 | 
			
		||||
                                {% fa5_icon 'tree' %}
 | 
			
		||||
                                {% trans 'Eco-Accounts' %}
 | 
			
		||||
                            </h5>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div id="ecoAccountsBody"  class="collapse" aria-labelledby="ecoAccounts">
 | 
			
		||||
                    <div class="card-body">
 | 
			
		||||
                        {% include 'analysis/reports/includes/eco_account/amount.html' %}
 | 
			
		||||
                        <hr>
 | 
			
		||||
                        {% include 'analysis/reports/includes/eco_account/deductions.html' %}
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
@ -0,0 +1,23 @@
 | 
			
		||||
{% load i18n fontawesome_5 ksp_filters %}
 | 
			
		||||
 | 
			
		||||
<h3>{% trans 'Deductions' %}</h3>
 | 
			
		||||
<div class="table-container">
 | 
			
		||||
    <table class="table table-hover">
 | 
			
		||||
        <thead>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <th scope="col">{% fa5_icon 'bookmark' %} {% trans 'Recorded' %}</th>
 | 
			
		||||
                <th scope="col">{% fa5_icon 'bookmark' %} {% trans 'Recorded' %} {% trans 'Surface' %}</th>
 | 
			
		||||
                <th scope="col" class="w-25">{% trans 'Total' %}</th>
 | 
			
		||||
                <th scope="col" class="w-25">{% trans 'Total' %} {% trans 'Surface' %}</th>
 | 
			
		||||
            </tr>
 | 
			
		||||
        </thead>
 | 
			
		||||
        <tbody>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>{{report.eco_account_report.queryset_deductions_recorded_count|default_if_zero:"-"}}</td>
 | 
			
		||||
                <td>{{report.eco_account_report.recorded_deductions_sq_m|default_if_zero:"-"}}m²</td>
 | 
			
		||||
                <td>{{report.eco_account_report.queryset_deductions_count|default_if_zero:"-"}}</td>
 | 
			
		||||
                <td>{{report.eco_account_report.deductions_sq_m|default_if_zero:"-"}}m²</td>
 | 
			
		||||
            </tr>
 | 
			
		||||
        </tbody>
 | 
			
		||||
    </table>
 | 
			
		||||
</div>
 | 
			
		||||
@ -0,0 +1,30 @@
 | 
			
		||||
{% load i18n fontawesome_5 ksp_filters %}
 | 
			
		||||
 | 
			
		||||
<h3>{% trans 'Amount' %}</h3>
 | 
			
		||||
<strong>
 | 
			
		||||
    {% blocktrans %}
 | 
			
		||||
    Checked = Has been checked by the registration office according to LKompVzVo
 | 
			
		||||
    {% endblocktrans %}
 | 
			
		||||
    <br>
 | 
			
		||||
    {% blocktrans %}
 | 
			
		||||
    Recorded = Has been checked and published by the conservation office
 | 
			
		||||
    {% endblocktrans %}
 | 
			
		||||
</strong>
 | 
			
		||||
<div class="table-container">
 | 
			
		||||
    <table class="table table-hover">
 | 
			
		||||
        <thead>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <th scope="col">{% fa5_icon 'star' %} {% trans 'Checked' %}</th>
 | 
			
		||||
                <th scope="col">{% fa5_icon 'bookmark' %} {% trans 'Recorded' %}</th>
 | 
			
		||||
                <th scope="col" class="w-25">{% trans 'Total' %}</th>
 | 
			
		||||
            </tr>
 | 
			
		||||
        </thead>
 | 
			
		||||
        <tbody>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>{{report.intervention_report.queryset_checked_count|default_if_zero:"-"}}</td>
 | 
			
		||||
                <td>{{report.intervention_report.queryset_recorded_count|default_if_zero:"-"}}</td>
 | 
			
		||||
                <td>{{report.intervention_report.queryset_count|default_if_zero:"-"}}</td>
 | 
			
		||||
            </tr>
 | 
			
		||||
        </tbody>
 | 
			
		||||
    </table>
 | 
			
		||||
</div>
 | 
			
		||||
@ -0,0 +1,26 @@
 | 
			
		||||
{% load i18n fontawesome_5 %}
 | 
			
		||||
    <div class="row">
 | 
			
		||||
        <div class="col-sm-12 col-md-12 col-lg-12">
 | 
			
		||||
            <div class="card">
 | 
			
		||||
                <div id="intervention" class="card-header cursor-pointer rlp-r" data-toggle="collapse" data-target="#interventionBody" aria-expanded="true" aria-controls="interventionBody">
 | 
			
		||||
                    <div class="row">
 | 
			
		||||
                        <div class="col-sm-6">
 | 
			
		||||
                            <h5>
 | 
			
		||||
                                {% fa5_icon 'pencil-ruler' %}
 | 
			
		||||
                                {% trans 'Interventions' %}
 | 
			
		||||
                            </h5>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div id="interventionBody"  class="collapse" aria-labelledby="intervention">
 | 
			
		||||
                    <div class="card-body">
 | 
			
		||||
                        {% include 'analysis/reports/includes/intervention/amount.html' %}
 | 
			
		||||
                        <hr>
 | 
			
		||||
                        {% include 'analysis/reports/includes/intervention/compensated_by.html' %}
 | 
			
		||||
                        <hr>
 | 
			
		||||
                        {% include 'analysis/reports/includes/intervention/laws.html' %}
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
@ -0,0 +1,34 @@
 | 
			
		||||
{% load i18n fontawesome_5 ksp_filters %}
 | 
			
		||||
<h3>{% trans 'Compensated by' %}</h3>
 | 
			
		||||
<div class="table-container scroll-300">
 | 
			
		||||
    <table class="table table-hover">
 | 
			
		||||
        <thead>
 | 
			
		||||
        <tr>
 | 
			
		||||
            <th class="w-25" scope="col">{% trans 'Compensation type' %}</th>
 | 
			
		||||
            <th class="w-25" scope="col">{% fa5_icon 'star' %} {% trans 'Checked' %}</th>
 | 
			
		||||
            <th class="w-25" scope="col">{% fa5_icon 'bookmark' %} {% trans 'Recorded' %}</th>
 | 
			
		||||
            <th class="w-25" scope="col">{% trans 'Total' %}</th>
 | 
			
		||||
        </tr>
 | 
			
		||||
        </thead>
 | 
			
		||||
        <tbody>
 | 
			
		||||
        <tr>
 | 
			
		||||
            <th>{% trans 'Compensation' %}</th>
 | 
			
		||||
            <td>{{report.intervention_report.compensation_sum_checked|default_if_zero:"-"}}</td>
 | 
			
		||||
            <td>{{report.intervention_report.compensation_sum_recorded|default_if_zero:"-"}}</td>
 | 
			
		||||
            <td>{{report.intervention_report.compensation_sum|default_if_zero:"-"}}</td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr>
 | 
			
		||||
            <th>{% trans 'Payment' %}</th>
 | 
			
		||||
            <td>{{report.intervention_report.payment_sum_checked|default_if_zero:"-"}}</td>
 | 
			
		||||
            <td>{{report.intervention_report.payment_sum_recorded|default_if_zero:"-"}}</td>
 | 
			
		||||
            <td>{{report.intervention_report.payment_sum|default_if_zero:"-"}}</td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr>
 | 
			
		||||
            <th>{% trans 'Deductions' %}</th>
 | 
			
		||||
            <td>{{report.intervention_report.deduction_sum_checked|default_if_zero:"-"}}</td>
 | 
			
		||||
            <td>{{report.intervention_report.deduction_sum_recorded|default_if_zero:"-"}}</td>
 | 
			
		||||
            <td>{{report.intervention_report.deduction_sum|default_if_zero:"-"}}</td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        </tbody>
 | 
			
		||||
    </table>
 | 
			
		||||
</div>
 | 
			
		||||
@ -0,0 +1,50 @@
 | 
			
		||||
{% load i18n fontawesome_5 ksp_filters %}
 | 
			
		||||
<h3>{% trans 'Law usage' %}</h3>
 | 
			
		||||
<strong>
 | 
			
		||||
    {% blocktrans %}
 | 
			
		||||
    Please note: One intervention can be based on multiple laws. This table therefore does not
 | 
			
		||||
    count
 | 
			
		||||
    {% endblocktrans %}
 | 
			
		||||
</strong>
 | 
			
		||||
<div class="table-container scroll-300">
 | 
			
		||||
    <table class="table table-hover">
 | 
			
		||||
        <thead>
 | 
			
		||||
        <tr>
 | 
			
		||||
            <th class="w-25" scope="col">
 | 
			
		||||
                {% trans 'Law' %}
 | 
			
		||||
            </th>
 | 
			
		||||
            <th scope="col">
 | 
			
		||||
                {% fa5_icon 'star' %} {% trans 'Checked' %}
 | 
			
		||||
            </th>
 | 
			
		||||
            <th scope="col">
 | 
			
		||||
                {% fa5_icon 'bookmark' %} {% trans 'Recorded' %}
 | 
			
		||||
            </th>
 | 
			
		||||
            <th scope="col">
 | 
			
		||||
                {% trans 'Total' %}
 | 
			
		||||
            </th>
 | 
			
		||||
        </tr>
 | 
			
		||||
        </thead>
 | 
			
		||||
        <tbody>
 | 
			
		||||
        {% for law in report.intervention_report.evaluated_laws %}
 | 
			
		||||
        <tr>
 | 
			
		||||
            <td>
 | 
			
		||||
                {{law.short_name}}
 | 
			
		||||
                <br>
 | 
			
		||||
                <small>
 | 
			
		||||
                    {{law.long_name}}
 | 
			
		||||
                </small>
 | 
			
		||||
            </td>
 | 
			
		||||
            <td>{{law.num_checked|default_if_zero:"-"}}</td>
 | 
			
		||||
            <td>{{law.num_recorded|default_if_zero:"-"}}</td>
 | 
			
		||||
            <td>{{law.num|default_if_zero:"-"}}</td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        {% endfor %}
 | 
			
		||||
        <tr>
 | 
			
		||||
            <td><strong>{% trans 'Total' %}</strong></td>
 | 
			
		||||
            <td><strong>{{report.intervention_report.law_sum_checked|default_if_zero:"-"}}</strong></td>
 | 
			
		||||
            <td><strong>{{report.intervention_report.law_sum_recorded|default_if_zero:"-"}}</strong></td>
 | 
			
		||||
            <td><strong>{{report.intervention_report.law_sum|default_if_zero:"-"}}</strong></td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        </tbody>
 | 
			
		||||
    </table>
 | 
			
		||||
</div>
 | 
			
		||||
@ -0,0 +1,40 @@
 | 
			
		||||
{% load i18n fontawesome_5 ksp_filters %}
 | 
			
		||||
 | 
			
		||||
<h3>{% trans 'Amount' %}</h3>
 | 
			
		||||
<strong>
 | 
			
		||||
    {% blocktrans %}
 | 
			
		||||
    Checked = Has been checked by the registration office according to LKompVzVo
 | 
			
		||||
    {% endblocktrans %}
 | 
			
		||||
    <br>
 | 
			
		||||
    {% blocktrans %}
 | 
			
		||||
    Recorded = Has been checked and published by the conservation office
 | 
			
		||||
    {% endblocktrans %}
 | 
			
		||||
</strong>
 | 
			
		||||
<div class="table-container">
 | 
			
		||||
    <table class="table table-hover">
 | 
			
		||||
        <thead>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <th scope="col" class="w-25">{% fa5_icon 'star' %} {% trans 'Type' %}</th>
 | 
			
		||||
                <th scope="col">{% fa5_icon 'bookmark' %} {% trans 'Recorded' %}</th>
 | 
			
		||||
                <th scope="col">{% trans 'Total' %}</th>
 | 
			
		||||
            </tr>
 | 
			
		||||
        </thead>
 | 
			
		||||
        <tbody>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>{% trans 'Intervention' %}</td>
 | 
			
		||||
                <td>{{report.old_data_report.queryset_intervention_recorded_count|default_if_zero:"-"}}</td>
 | 
			
		||||
                <td>{{report.old_data_report.queryset_intervention_count|default_if_zero:"-"}}</td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>{% trans 'Compensation' %}</td>
 | 
			
		||||
                <td>{{report.old_data_report.queryset_comps_recorded_count|default_if_zero:"-"}}</td>
 | 
			
		||||
                <td>{{report.old_data_report.queryset_comps_count|default_if_zero:"-"}}</td>
 | 
			
		||||
            </tr>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>{% trans 'Eco-account' %}</td>
 | 
			
		||||
                <td>{{report.old_data_report.queryset_acc_recorded_count|default_if_zero:"-"}}</td>
 | 
			
		||||
                <td>{{report.old_data_report.queryset_acc_count|default_if_zero:"-"}}</td>
 | 
			
		||||
            </tr>
 | 
			
		||||
        </tbody>
 | 
			
		||||
    </table>
 | 
			
		||||
</div>
 | 
			
		||||
@ -0,0 +1,24 @@
 | 
			
		||||
{% load i18n fontawesome_5 %}
 | 
			
		||||
 | 
			
		||||
    <div class="row">
 | 
			
		||||
        <div class="col-sm-12 col-md-12 col-lg-12">
 | 
			
		||||
            <div class="card">
 | 
			
		||||
                <div id="oldIntervention" class="card-header cursor-pointer rlp-r" data-toggle="collapse" data-target="#oldInterventionBody" aria-expanded="true" aria-controls="oldInterventionBody">
 | 
			
		||||
                    <div class="row">
 | 
			
		||||
                        <div class="col-sm-6">
 | 
			
		||||
                            <h5>
 | 
			
		||||
                                {% fa5_icon 'pencil-ruler' %}
 | 
			
		||||
                                {% trans 'Old interventions' %}
 | 
			
		||||
                            </h5>
 | 
			
		||||
                            <span>{% trans 'Before' %} 16.06.2018</span>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div id="oldInterventionBody"  class="collapse" aria-labelledby="oldIntervention">
 | 
			
		||||
                    <div class="card-body">
 | 
			
		||||
                        {% include 'analysis/reports/includes/old_data/amount.html' %}
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
							
								
								
									
										10
									
								
								analysis/templates/analysis/reports/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								analysis/templates/analysis/reports/index.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
			
		||||
{% extends 'base.html' %}
 | 
			
		||||
{% load i18n fontawesome_5 %}
 | 
			
		||||
 | 
			
		||||
{% block body %}
 | 
			
		||||
    <div class="row">
 | 
			
		||||
        <div class="col-sm-12 col-md-12 col-lg-12">
 | 
			
		||||
             {% include 'form/table/generic_table_form.html' %}
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
							
								
								
									
										3
									
								
								analysis/tests.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								analysis/tests.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
			
		||||
from django.test import TestCase
 | 
			
		||||
 | 
			
		||||
# Create your tests here.
 | 
			
		||||
							
								
								
									
										15
									
								
								analysis/urls.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								analysis/urls.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,15 @@
 | 
			
		||||
"""
 | 
			
		||||
Author: Michel Peltriaux
 | 
			
		||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
 | 
			
		||||
Contact: michel.peltriaux@sgdnord.rlp.de
 | 
			
		||||
Created on: 15.10.21
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
from django.urls import path
 | 
			
		||||
from analysis.views import *
 | 
			
		||||
 | 
			
		||||
app_name = "analysis"
 | 
			
		||||
urlpatterns = [
 | 
			
		||||
    path("reports/", index_reports_view, name="reports"),
 | 
			
		||||
    path("reports/<id>", detail_report_view, name="report-detail"),
 | 
			
		||||
]
 | 
			
		||||
							
								
								
									
										114
									
								
								analysis/utils/excel/excel.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								analysis/utils/excel/excel.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,114 @@
 | 
			
		||||
"""
 | 
			
		||||
Author: Michel Peltriaux
 | 
			
		||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
 | 
			
		||||
Contact: michel.peltriaux@sgdnord.rlp.de
 | 
			
		||||
Created on: 21.10.21
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
from django.core.files.temp import NamedTemporaryFile
 | 
			
		||||
from openpyxl import load_workbook
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TempExcelFile:
 | 
			
		||||
    """ A temporary excel sheet which will not be saved on the hard drive permanently.
 | 
			
		||||
 | 
			
		||||
    Using a template file and a template_map dictionary, this class can be used to fill in automatically
 | 
			
		||||
    predefined values into certain cells.
 | 
			
		||||
 | 
			
		||||
    Can be used to create excel files from data and sending it as a response like
 | 
			
		||||
        _file = TempExcelFile()
 | 
			
		||||
        response = HttpResponse(
 | 
			
		||||
            content=file.stream,
 | 
			
		||||
            content_type="application/ms-excel",
 | 
			
		||||
        )
 | 
			
		||||
        response['Content-Disposition'] = 'attachment; filename=my_file.xlsx'
 | 
			
		||||
        return response
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    stream = None
 | 
			
		||||
    _template_file_path = None
 | 
			
		||||
    _template_map = {}
 | 
			
		||||
    _data_obj = None
 | 
			
		||||
 | 
			
		||||
    def __init__(self, template_file_path: str = None, template_map: dict = None):
 | 
			
		||||
        self._template_map = template_map or {}
 | 
			
		||||
        self._template_file_path = template_file_path
 | 
			
		||||
        self._workbook = load_workbook(template_file_path)
 | 
			
		||||
        self._file = NamedTemporaryFile()
 | 
			
		||||
 | 
			
		||||
        self._replace_template_placeholders()
 | 
			
		||||
 | 
			
		||||
    def _replace_template_placeholders(self, start_row: int = 0):
 | 
			
		||||
        """ Replaces all placeholder inside the template according to _template_map
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
            start_row (int): Defines where to start
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        sheets = self._workbook.worksheets
 | 
			
		||||
        for sheet in sheets:
 | 
			
		||||
            ws = sheet
 | 
			
		||||
            # Always activate sheet protection
 | 
			
		||||
            ws.protection.sheet = True
 | 
			
		||||
            ws.protection.enable()
 | 
			
		||||
            _rows = ws.iter_rows(start_row)
 | 
			
		||||
            for row in _rows:
 | 
			
		||||
                for cell in row:
 | 
			
		||||
                    val = cell.value
 | 
			
		||||
                    if val in self._template_map:
 | 
			
		||||
                        attr = self._template_map[val]
 | 
			
		||||
                        # If keyword '_iter' can be found inside the placeholder value it's an iterable and we
 | 
			
		||||
                        # need to process it differently
 | 
			
		||||
                        if isinstance(attr, dict):
 | 
			
		||||
                            # Read the iterable object and related attributes from the dict
 | 
			
		||||
                            _iter_obj = attr.get("iterable", None)
 | 
			
		||||
                            _attrs = attr.get("attrs", [])
 | 
			
		||||
                            self._add_cells_from_iterable(ws, cell, _iter_obj, _attrs)
 | 
			
		||||
                            # Since the sheet length did change now, we need to rerun this function starting with the new
 | 
			
		||||
                            # row counter
 | 
			
		||||
                            self._replace_template_placeholders(start_row=cell.row + len(_iter_obj))
 | 
			
		||||
                        else:
 | 
			
		||||
                            cell.value = attr
 | 
			
		||||
        self._workbook.save(self._file.name)
 | 
			
		||||
        self._file.seek(0)
 | 
			
		||||
        self.stream = self._file.read()
 | 
			
		||||
 | 
			
		||||
    def _add_cells_from_iterable(self, ws, start_cell, _iter_obj: iter, _attrs: list):
 | 
			
		||||
        """
 | 
			
		||||
        Adds iterable data defined by _template_map like
 | 
			
		||||
            ...
 | 
			
		||||
            "some_placeholder_iter": {
 | 
			
		||||
                "iterable": iterable_object,
 | 
			
		||||
                "attrs": [
 | 
			
		||||
                    "attr1",
 | 
			
		||||
                    "attr2",
 | 
			
		||||
                    "attr3",
 | 
			
		||||
                    ...
 | 
			
		||||
                ]
 | 
			
		||||
            },
 | 
			
		||||
            ...
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
            ws (Workbook): The active workbook
 | 
			
		||||
            _iter_obj (dict): Iterable definitions from template_map
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        # Save border style
 | 
			
		||||
        border_style = start_cell.border.copy()
 | 
			
		||||
        # Drop current row, since it is just placeholder
 | 
			
		||||
        ws.delete_rows(start_cell.row)
 | 
			
		||||
        # Add enoug empty rows for the data
 | 
			
		||||
        ws.insert_rows(start_cell.row, len(_iter_obj))
 | 
			
		||||
 | 
			
		||||
        i = 0
 | 
			
		||||
        for _iter_entry in _iter_obj:
 | 
			
		||||
            j = 0
 | 
			
		||||
            for _iter_attr in _attrs:
 | 
			
		||||
                _new_cell = ws.cell(start_cell.row + i, start_cell.column + j, getattr(_iter_entry, _iter_attr))
 | 
			
		||||
                _new_cell.border = border_style
 | 
			
		||||
                j += 1
 | 
			
		||||
            i += 1
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								analysis/utils/excel/excel_report.xlsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								analysis/utils/excel/excel_report.xlsx
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										547
									
								
								analysis/utils/report.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										547
									
								
								analysis/utils/report.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,547 @@
 | 
			
		||||
"""
 | 
			
		||||
Author: Michel Peltriaux
 | 
			
		||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
 | 
			
		||||
Contact: michel.peltriaux@sgdnord.rlp.de
 | 
			
		||||
Created on: 18.10.21
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
from django.contrib.gis.db.models import MultiPolygonField
 | 
			
		||||
from django.contrib.gis.db.models.functions import NumGeometries
 | 
			
		||||
from django.db.models import Count, Sum, Q
 | 
			
		||||
from django.db.models.functions import Cast
 | 
			
		||||
 | 
			
		||||
from analysis.settings import LKOMPVZVO_PUBLISH_DATE
 | 
			
		||||
from codelist.models import KonovaCode
 | 
			
		||||
from codelist.settings import CODELIST_LAW_ID
 | 
			
		||||
from compensation.models import Compensation, Payment, EcoAccountDeduction, EcoAccount
 | 
			
		||||
from intervention.models import Intervention
 | 
			
		||||
from konova.models import Geometry
 | 
			
		||||
from konova.sub_settings.django_settings import BASE_DIR, DEFAULT_DATE_FORMAT
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TimespanReport:
 | 
			
		||||
    """ Holds multiple report elements for a timespan report
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    office_id = -1
 | 
			
		||||
    date_from = -1
 | 
			
		||||
    date_to = -1
 | 
			
		||||
 | 
			
		||||
    # Excel map is used to map a cell value ("A1") to an attribute
 | 
			
		||||
    excel_map = {}
 | 
			
		||||
    excel_template_path = f"{BASE_DIR}/analysis/utils/excel/excel_report.xlsx"
 | 
			
		||||
 | 
			
		||||
    class InterventionReport:
 | 
			
		||||
        queryset = Intervention.objects.none()
 | 
			
		||||
        queryset_checked = Intervention.objects.none()
 | 
			
		||||
        queryset_recorded = Intervention.objects.none()
 | 
			
		||||
 | 
			
		||||
        queryset_count = -1
 | 
			
		||||
        queryset_checked_count = -1
 | 
			
		||||
        queryset_recorded_count = -1
 | 
			
		||||
 | 
			
		||||
        # Law related
 | 
			
		||||
        law_sum = -1
 | 
			
		||||
        law_sum_checked = -1
 | 
			
		||||
        law_sum_recorded = -1
 | 
			
		||||
        evaluated_laws = None
 | 
			
		||||
 | 
			
		||||
        # Compensations related
 | 
			
		||||
        compensation_sum = -1
 | 
			
		||||
        compensation_sum_checked = -1
 | 
			
		||||
        compensation_sum_recorded = -1
 | 
			
		||||
        payment_sum = -1
 | 
			
		||||
        payment_sum_checked = -1
 | 
			
		||||
        payment_sum_recorded = -1
 | 
			
		||||
        deduction_sum = -1
 | 
			
		||||
        deduction_sum_checked = -1
 | 
			
		||||
        deduction_sum_recorded = -1
 | 
			
		||||
 | 
			
		||||
        excel_map = {}
 | 
			
		||||
 | 
			
		||||
        def __init__(self, id: str, date_from: str, date_to: str):
 | 
			
		||||
            self.queryset = Intervention.objects.filter(
 | 
			
		||||
                responsible__conservation_office__id=id,
 | 
			
		||||
                legal__registration_date__gt=LKOMPVZVO_PUBLISH_DATE,
 | 
			
		||||
                deleted=None,
 | 
			
		||||
                created__timestamp__gte=date_from,
 | 
			
		||||
                created__timestamp__lte=date_to,
 | 
			
		||||
            )
 | 
			
		||||
            self.queryset_checked = self.queryset.filter(
 | 
			
		||||
                checked__isnull=False
 | 
			
		||||
            )
 | 
			
		||||
            self.queryset_recorded = self.queryset.filter(
 | 
			
		||||
                recorded__isnull=False
 | 
			
		||||
            )
 | 
			
		||||
            self.queryset_count = self.queryset.count()
 | 
			
		||||
            self.queryset_checked_count = self.queryset_checked.count()
 | 
			
		||||
            self.queryset_recorded_count = self.queryset_recorded.count()
 | 
			
		||||
 | 
			
		||||
            self._create_report()
 | 
			
		||||
            self._define_excel_map()
 | 
			
		||||
 | 
			
		||||
        def _define_excel_map(self):
 | 
			
		||||
            """ Define the excel map, which holds values for each placeholder used in the template
 | 
			
		||||
 | 
			
		||||
            Returns:
 | 
			
		||||
 | 
			
		||||
            """
 | 
			
		||||
            self.excel_map = {
 | 
			
		||||
                "i_checked": self.queryset_checked_count,
 | 
			
		||||
                "i_recorded": self.queryset_recorded_count,
 | 
			
		||||
                "i_total": self.queryset_count,
 | 
			
		||||
                "i_compensations_checked": self.compensation_sum_checked,
 | 
			
		||||
                "i_compensations_recorded": self.compensation_sum_recorded,
 | 
			
		||||
                "i_compensations_total": self.compensation_sum,
 | 
			
		||||
                "i_payments_recorded": self.payment_sum_recorded,
 | 
			
		||||
                "i_payments_checked": self.payment_sum_checked,
 | 
			
		||||
                "i_payments_total": self.payment_sum,
 | 
			
		||||
                "i_deductions_recorded": self.deduction_sum_recorded,
 | 
			
		||||
                "i_deductions_checked": self.deduction_sum_checked,
 | 
			
		||||
                "i_deductions_total": self.deduction_sum,
 | 
			
		||||
                "i_laws_iter": {
 | 
			
		||||
                    "iterable": self.evaluated_laws,
 | 
			
		||||
                    "attrs": [
 | 
			
		||||
                        "short_name",
 | 
			
		||||
                        "num_checked",
 | 
			
		||||
                        "num_recorded",
 | 
			
		||||
                        "num",
 | 
			
		||||
                    ]
 | 
			
		||||
                },
 | 
			
		||||
                "i_laws_checked": self.law_sum_checked,
 | 
			
		||||
                "i_laws_recorded": self.law_sum_recorded,
 | 
			
		||||
                "i_laws_total": self.law_sum,
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        def _create_report(self):
 | 
			
		||||
            """ Creates all report information
 | 
			
		||||
 | 
			
		||||
            Returns:
 | 
			
		||||
 | 
			
		||||
            """
 | 
			
		||||
            self._evaluate_laws()
 | 
			
		||||
            self._evaluate_compensations()
 | 
			
		||||
 | 
			
		||||
        def _evaluate_laws(self):
 | 
			
		||||
            """ Analyzes the intervention-law distribution
 | 
			
		||||
 | 
			
		||||
            Returns:
 | 
			
		||||
 | 
			
		||||
            """
 | 
			
		||||
            # Count interventions based on law
 | 
			
		||||
            # Fetch all KonovaCodes for laws, sorted alphabetically
 | 
			
		||||
            laws = KonovaCode.objects.filter(
 | 
			
		||||
                is_archived=False,
 | 
			
		||||
                is_leaf=True,
 | 
			
		||||
                code_lists__in=[CODELIST_LAW_ID],
 | 
			
		||||
            ).order_by(
 | 
			
		||||
                "long_name"
 | 
			
		||||
            )
 | 
			
		||||
            # Fetch all law ids which are used by any .legal object of an intervention object
 | 
			
		||||
            intervention_laws_total = self.queryset.values_list("legal__laws__id")
 | 
			
		||||
            intervention_laws_checked = self.queryset.filter(checked__isnull=False).values_list("legal__laws__id")
 | 
			
		||||
            intervention_laws_recorded = self.queryset.filter(recorded__isnull=False).values_list(
 | 
			
		||||
                "legal__laws__id")
 | 
			
		||||
            # Count how often which law id appears in the above list, return only the long_name of the law and the resulting
 | 
			
		||||
            # count (here 'num'). This is for keeping the db fetch as small as possible
 | 
			
		||||
            # Compute the sum for total, checked and recorded
 | 
			
		||||
            self.evaluated_laws = laws.annotate(
 | 
			
		||||
                num=Count("id", filter=Q(id__in=intervention_laws_total)),
 | 
			
		||||
                num_checked=Count("id", filter=Q(id__in=intervention_laws_checked)),
 | 
			
		||||
                num_recorded=Count("id", filter=Q(id__in=intervention_laws_recorded)),
 | 
			
		||||
            ).values_list("short_name", "long_name", "num_checked", "num_recorded", "num", named=True)
 | 
			
		||||
            self.law_sum = self.evaluated_laws.aggregate(sum_num=Sum("num"))["sum_num"]
 | 
			
		||||
            self.law_sum_checked = self.evaluated_laws.aggregate(sum_num_checked=Sum("num_checked"))["sum_num_checked"]
 | 
			
		||||
            self.law_sum_recorded = self.evaluated_laws.aggregate(sum_num_recorded=Sum("num_recorded"))["sum_num_recorded"]
 | 
			
		||||
 | 
			
		||||
        def _evaluate_compensations(self):
 | 
			
		||||
            """ Analyzes the types of compensation distribution
 | 
			
		||||
 | 
			
		||||
            Returns:
 | 
			
		||||
 | 
			
		||||
            """
 | 
			
		||||
            # Count all compensations
 | 
			
		||||
            comps = Compensation.objects.filter(
 | 
			
		||||
                intervention__in=self.queryset
 | 
			
		||||
            )
 | 
			
		||||
            self.compensation_sum = comps.count()
 | 
			
		||||
            self.compensation_sum_checked = comps.filter(intervention__checked__isnull=False).count()
 | 
			
		||||
            self.compensation_sum_recorded = comps.filter(intervention__recorded__isnull=False).count()
 | 
			
		||||
 | 
			
		||||
            # Count all payments
 | 
			
		||||
            payments = Payment.objects.filter(
 | 
			
		||||
                intervention__in=self.queryset
 | 
			
		||||
            )
 | 
			
		||||
            self.payment_sum = payments.count()
 | 
			
		||||
            self.payment_sum_checked = payments.filter(intervention__checked__isnull=False).count()
 | 
			
		||||
            self.payment_sum_recorded = payments.filter(intervention__recorded__isnull=False).count()
 | 
			
		||||
 | 
			
		||||
            # Count all deductions
 | 
			
		||||
            deductions = EcoAccountDeduction.objects.filter(
 | 
			
		||||
                intervention__in=self.queryset
 | 
			
		||||
            )
 | 
			
		||||
            self.deduction_sum = deductions.count()
 | 
			
		||||
            self.deduction_sum_checked = deductions.filter(intervention__checked__isnull=False).count()
 | 
			
		||||
            self.deduction_sum_recorded = deductions.filter(intervention__recorded__isnull=False).count()
 | 
			
		||||
 | 
			
		||||
    class CompensationReport:
 | 
			
		||||
        queryset = Compensation.objects.none()
 | 
			
		||||
        queryset_checked = Compensation.objects.none()
 | 
			
		||||
        queryset_recorded = Compensation.objects.none()
 | 
			
		||||
        queryset_count = -1
 | 
			
		||||
        queryset_checked_count = -1
 | 
			
		||||
        queryset_recorded_count = -1
 | 
			
		||||
 | 
			
		||||
        queryset_registration_office_unb = Compensation.objects.none()
 | 
			
		||||
        queryset_registration_office_unb_checked = Compensation.objects.none()
 | 
			
		||||
        queryset_registration_office_unb_recorded = Compensation.objects.none()
 | 
			
		||||
        queryset_registration_office_unb_count = -1
 | 
			
		||||
        queryset_registration_office_unb_checked_count = -1
 | 
			
		||||
        queryset_registration_office_unb_recorded_count = -1
 | 
			
		||||
        num_single_surfaces_total_unb = -1
 | 
			
		||||
 | 
			
		||||
        queryset_registration_office_tbp = Compensation.objects.none()
 | 
			
		||||
        queryset_registration_office_tbp_checked = Compensation.objects.none()
 | 
			
		||||
        queryset_registration_office_tbp_recorded = Compensation.objects.none()
 | 
			
		||||
        queryset_registration_office_tbp_count = -1
 | 
			
		||||
        queryset_registration_office_tbp_checked_count = -1
 | 
			
		||||
        queryset_registration_office_tbp_recorded_count = -1
 | 
			
		||||
        num_single_surfaces_total_tbp = -1
 | 
			
		||||
 | 
			
		||||
        queryset_registration_office_other = Compensation.objects.none()
 | 
			
		||||
        queryset_registration_office_other_checked = Compensation.objects.none()
 | 
			
		||||
        queryset_registration_office_other_recorded = Compensation.objects.none()
 | 
			
		||||
        queryset_registration_office_other_count = -1
 | 
			
		||||
        queryset_registration_office_other_checked_count = -1
 | 
			
		||||
        queryset_registration_office_other_recorded_count = -1
 | 
			
		||||
        num_single_surfaces_total_other = -1
 | 
			
		||||
 | 
			
		||||
        num_single_surfaces_total = -1
 | 
			
		||||
        num_single_surfaces_recorded = -1
 | 
			
		||||
 | 
			
		||||
        # Code list id for 'Träger der Bauleitplanung' parent
 | 
			
		||||
        id_tbp = 1943695
 | 
			
		||||
        # Code list id for 'untere Naturschutzbehörde'
 | 
			
		||||
        id_unb = 1943087
 | 
			
		||||
        # Code list id for 'obere Naturschutzbehörde'
 | 
			
		||||
        id_onb = 1943084
 | 
			
		||||
 | 
			
		||||
        def __init__(self, id: str, date_from: str, date_to: str):
 | 
			
		||||
            self.queryset = Compensation.objects.filter(
 | 
			
		||||
                intervention__responsible__conservation_office__id=id,
 | 
			
		||||
                intervention__legal__registration_date__gt=LKOMPVZVO_PUBLISH_DATE,
 | 
			
		||||
                deleted=None,
 | 
			
		||||
                intervention__created__timestamp__gte=date_from,
 | 
			
		||||
                intervention__created__timestamp__lte=date_to,
 | 
			
		||||
            )
 | 
			
		||||
            self.queryset_checked = self.queryset.filter(
 | 
			
		||||
                intervention__checked__isnull=False
 | 
			
		||||
            )
 | 
			
		||||
            self.queryset_recorded = self.queryset.filter(
 | 
			
		||||
                intervention__recorded__isnull=False
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            self.queryset_count = self.queryset.count()
 | 
			
		||||
            self.queryset_checked_count = self.queryset_checked.count()
 | 
			
		||||
            self.queryset_recorded_count = self.queryset_recorded.count()
 | 
			
		||||
 | 
			
		||||
            self._create_report()
 | 
			
		||||
            self._define_excel_map()
 | 
			
		||||
 | 
			
		||||
        def _define_excel_map(self):
 | 
			
		||||
            """ Define the excel map, which holds values for each placeholder used in the template
 | 
			
		||||
 | 
			
		||||
            Returns:
 | 
			
		||||
 | 
			
		||||
            """
 | 
			
		||||
            self.excel_map = {
 | 
			
		||||
                "c_unb_checked": self.queryset_registration_office_unb_checked_count,
 | 
			
		||||
                "c_unb_recorded": self.queryset_registration_office_unb_recorded_count,
 | 
			
		||||
                "c_unb": self.queryset_registration_office_unb_count,
 | 
			
		||||
                "c_surfaces_unb": self.num_single_surfaces_total_unb,
 | 
			
		||||
                "c_tbp_checked": self.queryset_registration_office_tbp_checked_count,
 | 
			
		||||
                "c_tbp_recorded": self.queryset_registration_office_tbp_recorded_count,
 | 
			
		||||
                "c_tbp": self.queryset_registration_office_tbp_count,
 | 
			
		||||
                "c_surfaces_tbp": self.num_single_surfaces_total_tbp,
 | 
			
		||||
                "c_other_checked": self.queryset_registration_office_other_checked_count,
 | 
			
		||||
                "c_other_recorded": self.queryset_registration_office_other_recorded_count,
 | 
			
		||||
                "c_other": self.queryset_registration_office_other_count,
 | 
			
		||||
                "c_surfaces_other": self.num_single_surfaces_total_other,
 | 
			
		||||
                "c_checked": self.queryset_checked_count,
 | 
			
		||||
                "c_recorded": self.queryset_recorded_count,
 | 
			
		||||
                "c_total": self.queryset_count,
 | 
			
		||||
                "c_surfaces": self.num_single_surfaces_total,
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        def _create_report(self):
 | 
			
		||||
            """ Creates all report information
 | 
			
		||||
 | 
			
		||||
            Returns:
 | 
			
		||||
 | 
			
		||||
            """
 | 
			
		||||
            self._evaluate_compensation_responsibility()
 | 
			
		||||
            self._evaluate_surfaces()
 | 
			
		||||
 | 
			
		||||
        def _evaluate_surfaces(self):
 | 
			
		||||
            """ Evaluates the surfaces of compensation Multipolygon fields
 | 
			
		||||
 | 
			
		||||
            Returns:
 | 
			
		||||
 | 
			
		||||
            """
 | 
			
		||||
            # Evaluate all surfaces
 | 
			
		||||
            ids = self.queryset.values_list("geometry_id")
 | 
			
		||||
            self.num_single_surfaces_total = self._count_geometry_surfaces(ids)
 | 
			
		||||
 | 
			
		||||
            # Evaluate surfaces where the conservation office is the registration office as well
 | 
			
		||||
            ids = self.queryset_registration_office_unb.values_list("geometry_id")
 | 
			
		||||
            self.num_single_surfaces_total_unb = self._count_geometry_surfaces(ids)
 | 
			
		||||
 | 
			
		||||
            # Evaluates surfaces where the registration office is a Träger Bauleitplanung
 | 
			
		||||
            ids = self.queryset_registration_office_tbp.values_list("geometry_id")
 | 
			
		||||
            self.num_single_surfaces_total_tbp = self._count_geometry_surfaces(ids)
 | 
			
		||||
 | 
			
		||||
            # Evaluates surfaces where any other registration office is responsible
 | 
			
		||||
            ids = self.queryset_registration_office_other.values_list("geometry_id")
 | 
			
		||||
            self.num_single_surfaces_total_other = self._count_geometry_surfaces(ids)
 | 
			
		||||
 | 
			
		||||
        def _count_geometry_surfaces(self, ids: list):
 | 
			
		||||
            """ Wraps counting of geometry surfaces from a given list of ids
 | 
			
		||||
 | 
			
		||||
            Args:
 | 
			
		||||
                ids (list): List of geometry ids
 | 
			
		||||
 | 
			
		||||
            Returns:
 | 
			
		||||
 | 
			
		||||
            """
 | 
			
		||||
            # Now select all geometries matching the ids
 | 
			
		||||
            # Then perform a ST_NumGeometries variant over all geometries
 | 
			
		||||
            # Then sum up all of the calculated surface numbers
 | 
			
		||||
            return Geometry.objects.filter(
 | 
			
		||||
                id__in=ids
 | 
			
		||||
            ).annotate(
 | 
			
		||||
                geom_cast=Cast("geom", MultiPolygonField())
 | 
			
		||||
            ).annotate(
 | 
			
		||||
                num=NumGeometries("geom_cast")
 | 
			
		||||
            ).aggregate(
 | 
			
		||||
                num_geoms=Sum("num")
 | 
			
		||||
            )["num_geoms"] or 0
 | 
			
		||||
 | 
			
		||||
        def _evaluate_compensation_responsibility(self):
 | 
			
		||||
            """ Evaluates compensations based on different responsibility areas
 | 
			
		||||
 | 
			
		||||
            unb -> Untere Naturschutzbehörde
 | 
			
		||||
                Holds entries where conservation_office and registration_office basically are the same
 | 
			
		||||
            tbp -> Träger Bauleitplanung
 | 
			
		||||
                Holds entries where registration_office is a Träger der Bauleitplanung
 | 
			
		||||
            other -> Other registration offices
 | 
			
		||||
                Holds all other entries
 | 
			
		||||
 | 
			
		||||
            Returns:
 | 
			
		||||
 | 
			
		||||
            """
 | 
			
		||||
            self.queryset_registration_office_unb = self.queryset.filter(
 | 
			
		||||
                intervention__responsible__registration_office__parent__id=self.id_unb
 | 
			
		||||
            )
 | 
			
		||||
            self.queryset_registration_office_unb_recorded = self.queryset_registration_office_unb.filter(
 | 
			
		||||
                intervention__recorded__isnull=False,
 | 
			
		||||
            )
 | 
			
		||||
            self.queryset_registration_office_unb_checked = self.queryset_registration_office_unb.filter(
 | 
			
		||||
                intervention__checked__isnull=False,
 | 
			
		||||
            )
 | 
			
		||||
            self.queryset_registration_office_unb_count = self.queryset_registration_office_unb.count()
 | 
			
		||||
            self.queryset_registration_office_unb_checked_count = self.queryset_registration_office_unb_checked.count()
 | 
			
		||||
            self.queryset_registration_office_unb_recorded_count = self.queryset_registration_office_unb_recorded.count()
 | 
			
		||||
 | 
			
		||||
            self.queryset_registration_office_tbp = self.queryset.filter(
 | 
			
		||||
                intervention__responsible__registration_office__parent__id=self.id_tbp
 | 
			
		||||
            )
 | 
			
		||||
            self.queryset_registration_office_tbp_recorded = self.queryset_registration_office_tbp.filter(
 | 
			
		||||
                intervention__recorded__isnull=False,
 | 
			
		||||
            )
 | 
			
		||||
            self.queryset_registration_office_tbp_checked = self.queryset_registration_office_tbp.filter(
 | 
			
		||||
                intervention__checked__isnull=False,
 | 
			
		||||
            )
 | 
			
		||||
            self.queryset_registration_office_tbp_count = self.queryset_registration_office_tbp.count()
 | 
			
		||||
            self.queryset_registration_office_tbp_checked_count = self.queryset_registration_office_tbp_checked.count()
 | 
			
		||||
            self.queryset_registration_office_tbp_recorded_count = self.queryset_registration_office_tbp_recorded.count()
 | 
			
		||||
 | 
			
		||||
            self.queryset_registration_office_other = self.queryset.exclude(
 | 
			
		||||
                Q(id__in=self.queryset_registration_office_tbp) | Q(id__in=self.queryset_registration_office_unb)
 | 
			
		||||
            )
 | 
			
		||||
            self.queryset_registration_office_other_recorded = self.queryset_registration_office_other.filter(
 | 
			
		||||
                intervention__recorded__isnull=False,
 | 
			
		||||
            )
 | 
			
		||||
            self.queryset_registration_office_other_checked = self.queryset_registration_office_other.filter(
 | 
			
		||||
                intervention__checked__isnull=False,
 | 
			
		||||
            )
 | 
			
		||||
            self.queryset_registration_office_other_count = self.queryset_registration_office_other.count()
 | 
			
		||||
            self.queryset_registration_office_other_checked_count = self.queryset_registration_office_other_checked.count()
 | 
			
		||||
            self.queryset_registration_office_other_recorded_count = self.queryset_registration_office_other_recorded.count()
 | 
			
		||||
 | 
			
		||||
    class EcoAccountReport:
 | 
			
		||||
        queryset = EcoAccount.objects.none()
 | 
			
		||||
        queryset_recorded = EcoAccount.objects.none()
 | 
			
		||||
        queryset_count = -1
 | 
			
		||||
        queryset_recorded_count = -1
 | 
			
		||||
 | 
			
		||||
        queryset_deductions = EcoAccountDeduction.objects.none()
 | 
			
		||||
        queryset_deductions_recorded = EcoAccountDeduction.objects.none()
 | 
			
		||||
        queryset_has_deductions = EcoAccountDeduction.objects.none()
 | 
			
		||||
        queryset_deductions_count = -1
 | 
			
		||||
        queryset_deductions_recorded_count = -1
 | 
			
		||||
        queryset_has_deductions_count = -1
 | 
			
		||||
 | 
			
		||||
        # Total size of deductions
 | 
			
		||||
        deductions_sq_m = -1
 | 
			
		||||
        recorded_deductions_sq_m = -1
 | 
			
		||||
 | 
			
		||||
        def __init__(self, id: str, date_from: str, date_to: str):
 | 
			
		||||
            # First fetch all eco account for this office
 | 
			
		||||
            self.queryset = EcoAccount.objects.filter(
 | 
			
		||||
                responsible__conservation_office__id=id,
 | 
			
		||||
                deleted=None,
 | 
			
		||||
                created__timestamp__gte=date_from,
 | 
			
		||||
                created__timestamp__lte=date_to,
 | 
			
		||||
            )
 | 
			
		||||
            self.queryset_recorded = self.queryset.filter(
 | 
			
		||||
                recorded__isnull=False
 | 
			
		||||
            )
 | 
			
		||||
            # Fetch all related deductions
 | 
			
		||||
            self.queryset_deductions = EcoAccountDeduction.objects.filter(
 | 
			
		||||
                account__id__in=self.queryset.values_list("id")
 | 
			
		||||
            )
 | 
			
		||||
            # Fetch deductions for interventions which are already recorded
 | 
			
		||||
            self.queryset_deductions_recorded = self.queryset_deductions.filter(
 | 
			
		||||
                intervention__recorded__isnull=False
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            self.queryset_count = self.queryset.count()
 | 
			
		||||
            self.queryset_recorded_count = self.queryset_recorded.count()
 | 
			
		||||
            self.queryset_deductions_count = self.queryset_deductions.count()
 | 
			
		||||
            self.queryset_deductions_recorded_count = self.queryset_deductions_recorded.count()
 | 
			
		||||
            self.queryset_has_deductions_count = self.queryset_has_deductions.count()
 | 
			
		||||
 | 
			
		||||
            self._create_report()
 | 
			
		||||
            self._define_excel_map()
 | 
			
		||||
 | 
			
		||||
        def _define_excel_map(self):
 | 
			
		||||
            """ Define the excel map, which holds values for each placeholder used in the template
 | 
			
		||||
 | 
			
		||||
            Returns:
 | 
			
		||||
 | 
			
		||||
            """
 | 
			
		||||
            self.excel_map = {
 | 
			
		||||
                "acc_total": self.queryset_count,
 | 
			
		||||
                "acc_recorded": self.queryset_recorded_count,
 | 
			
		||||
                "acc_deduc_recorded": self.queryset_deductions_recorded_count,
 | 
			
		||||
                "acc_deduc_surface_recorded": self.recorded_deductions_sq_m,
 | 
			
		||||
                "acc_deduc_total": self.queryset_deductions_count,
 | 
			
		||||
                "acc_deduc_surface_total": self.deductions_sq_m,
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        def _create_report(self):
 | 
			
		||||
            """ Creates all report information
 | 
			
		||||
 | 
			
		||||
            Returns:
 | 
			
		||||
 | 
			
		||||
            """
 | 
			
		||||
            self._evaluate_deductions()
 | 
			
		||||
 | 
			
		||||
        def _evaluate_deductions(self):
 | 
			
		||||
            self.deductions_sq_m = self.queryset_deductions.aggregate(
 | 
			
		||||
                sum=Sum("surface")
 | 
			
		||||
            )["sum"] or 0
 | 
			
		||||
            self.recorded_deductions_sq_m = self.queryset_deductions_recorded.aggregate(
 | 
			
		||||
                sum=Sum("surface")
 | 
			
		||||
            )["sum"] or 0
 | 
			
		||||
 | 
			
		||||
    class OldDataReport:
 | 
			
		||||
        """
 | 
			
		||||
        Evaluates 'old data' (registered (zugelassen) before 16.06.2018)
 | 
			
		||||
        """
 | 
			
		||||
        queryset_intervention = Intervention.objects.none()
 | 
			
		||||
        queryset_intervention_recorded = Intervention.objects.none()
 | 
			
		||||
        queryset_intervention_count = -1
 | 
			
		||||
        queryset_intervention_recorded_count = -1
 | 
			
		||||
 | 
			
		||||
        queryset_comps = Compensation.objects.none()
 | 
			
		||||
        queryset_comps_recorded = Compensation.objects.none()
 | 
			
		||||
        queryset_comps_count = -1
 | 
			
		||||
        queryset_comps_recorded_count = -1
 | 
			
		||||
 | 
			
		||||
        queryset_acc = EcoAccount.objects.none()
 | 
			
		||||
        queryset_acc_recorded = EcoAccount.objects.none()
 | 
			
		||||
        queryset_acc_count = -1
 | 
			
		||||
        queryset_acc_recorded_count = -1
 | 
			
		||||
 | 
			
		||||
        def __init__(self, id: str, date_from: str, date_to: str):
 | 
			
		||||
            self.queryset_intervention = Intervention.objects.filter(
 | 
			
		||||
                legal__registration_date__lte=LKOMPVZVO_PUBLISH_DATE,
 | 
			
		||||
                responsible__conservation_office__id=id,
 | 
			
		||||
                deleted=None,
 | 
			
		||||
                created__timestamp__gte=date_from,
 | 
			
		||||
                created__timestamp__lte=date_to,
 | 
			
		||||
            )
 | 
			
		||||
            self.queryset_intervention_recorded = self.queryset_intervention.filter(
 | 
			
		||||
                recorded__isnull=False
 | 
			
		||||
            )
 | 
			
		||||
            self.queryset_intervention_count = self.queryset_intervention.count()
 | 
			
		||||
            self.queryset_intervention_recorded_count = self.queryset_intervention_recorded.count()
 | 
			
		||||
 | 
			
		||||
            self.queryset_comps = Compensation.objects.filter(
 | 
			
		||||
                intervention__in=self.queryset_intervention
 | 
			
		||||
            )
 | 
			
		||||
            self.queryset_comps_recorded = Compensation.objects.filter(
 | 
			
		||||
                intervention__in=self.queryset_intervention_recorded,
 | 
			
		||||
            )
 | 
			
		||||
            self.queryset_comps_count = self.queryset_comps.count()
 | 
			
		||||
            self.queryset_comps_recorded_count = self.queryset_comps_recorded.count()
 | 
			
		||||
 | 
			
		||||
            self.queryset_acc = EcoAccount.objects.filter(
 | 
			
		||||
                legal__registration_date__lte=LKOMPVZVO_PUBLISH_DATE,
 | 
			
		||||
                responsible__conservation_office__id=id,
 | 
			
		||||
                deleted=None,
 | 
			
		||||
                created__timestamp__gte=date_from,
 | 
			
		||||
                created__timestamp__lte=date_to,
 | 
			
		||||
            )
 | 
			
		||||
            self.queryset_acc_recorded = self.queryset_acc.filter(
 | 
			
		||||
                recorded__isnull=False,
 | 
			
		||||
            )
 | 
			
		||||
            self.queryset_acc_count = self.queryset_acc.count()
 | 
			
		||||
            self.queryset_acc_recorded_count = self.queryset_acc_recorded.count()
 | 
			
		||||
            self._define_excel_map()
 | 
			
		||||
 | 
			
		||||
        def _define_excel_map(self):
 | 
			
		||||
            """ Define the excel map, which holds values for each placeholder used in the template
 | 
			
		||||
 | 
			
		||||
            Returns:
 | 
			
		||||
 | 
			
		||||
            """
 | 
			
		||||
            self.excel_map = {
 | 
			
		||||
                "old_i_recorded": self.queryset_intervention_recorded_count,
 | 
			
		||||
                "old_i_total": self.queryset_intervention_count,
 | 
			
		||||
                "old_c_recorded": self.queryset_comps_recorded_count,
 | 
			
		||||
                "old_c_total": self.queryset_comps_count,
 | 
			
		||||
                "old_ea_recorded": self.queryset_acc_recorded_count,
 | 
			
		||||
                "old_ea_total": self.queryset_acc_count,
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
    def __init__(self, office_id: str, date_from: str, date_to: str):
 | 
			
		||||
        self.office_id = office_id
 | 
			
		||||
        self.date_from = date_from
 | 
			
		||||
        self.date_to = date_to
 | 
			
		||||
 | 
			
		||||
        self.intervention_report = self.InterventionReport(self.office_id, date_from, date_to)
 | 
			
		||||
        self.compensation_report = self.CompensationReport(self.office_id, date_from, date_to)
 | 
			
		||||
        self.eco_account_report = self.EcoAccountReport(self.office_id, date_from, date_to)
 | 
			
		||||
        self.old_data_report = self.OldDataReport(self.office_id, date_from, date_to)
 | 
			
		||||
 | 
			
		||||
        # Build excel map
 | 
			
		||||
        self.excel_map = {
 | 
			
		||||
            "date_from": date_from.strftime(DEFAULT_DATE_FORMAT),
 | 
			
		||||
            "date_to": date_to.strftime(DEFAULT_DATE_FORMAT),
 | 
			
		||||
        }
 | 
			
		||||
        self.excel_map.update(self.intervention_report.excel_map)
 | 
			
		||||
        self.excel_map.update(self.compensation_report.excel_map)
 | 
			
		||||
        self.excel_map.update(self.eco_account_report.excel_map)
 | 
			
		||||
        self.excel_map.update(self.old_data_report.excel_map)
 | 
			
		||||
							
								
								
									
										98
									
								
								analysis/views.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								analysis/views.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,98 @@
 | 
			
		||||
from django.contrib import messages
 | 
			
		||||
from django.contrib.auth.decorators import login_required
 | 
			
		||||
from django.http import HttpRequest, HttpResponse
 | 
			
		||||
from django.shortcuts import render, redirect, get_object_or_404
 | 
			
		||||
from django.utils import timezone
 | 
			
		||||
 | 
			
		||||
from analysis.forms import TimespanReportForm
 | 
			
		||||
from analysis.utils.excel.excel import TempExcelFile
 | 
			
		||||
from analysis.utils.report import TimespanReport
 | 
			
		||||
from codelist.models import KonovaCode
 | 
			
		||||
from konova.contexts import BaseContext
 | 
			
		||||
from konova.decorators import conservation_office_group_required
 | 
			
		||||
from konova.utils.message_templates import FORM_INVALID, PARAMS_INVALID
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@login_required
 | 
			
		||||
@conservation_office_group_required
 | 
			
		||||
def index_reports_view(request: HttpRequest):
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    Args:
 | 
			
		||||
        request (HttpRequest): The incoming request
 | 
			
		||||
 | 
			
		||||
    Returns:
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    template = "analysis/reports/index.html"
 | 
			
		||||
    form = TimespanReportForm(request.POST or None)
 | 
			
		||||
    if request.method == "POST":
 | 
			
		||||
        if form.is_valid():
 | 
			
		||||
            redirect_url = form.save()
 | 
			
		||||
            return redirect(redirect_url)
 | 
			
		||||
        else:
 | 
			
		||||
            messages.error(
 | 
			
		||||
                request,
 | 
			
		||||
                FORM_INVALID,
 | 
			
		||||
                extra_tags="danger",
 | 
			
		||||
            )
 | 
			
		||||
    context = {
 | 
			
		||||
        "form": form
 | 
			
		||||
    }
 | 
			
		||||
    context = BaseContext(request, context).context
 | 
			
		||||
    return render(request, template, context)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@login_required
 | 
			
		||||
@conservation_office_group_required
 | 
			
		||||
def detail_report_view(request: HttpRequest, id: str):
 | 
			
		||||
    """ Renders the detailed report for a conservation office
 | 
			
		||||
 | 
			
		||||
    Args:
 | 
			
		||||
        request (HttpRequest): The incoming request
 | 
			
		||||
        id (str): The conservation_office KonovaCode id
 | 
			
		||||
 | 
			
		||||
    Returns:
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    # Try to resolve the requested office id
 | 
			
		||||
    cons_office = get_object_or_404(
 | 
			
		||||
        KonovaCode,
 | 
			
		||||
        id=id
 | 
			
		||||
    )
 | 
			
		||||
    # Try to resolve the date parameters into Date objects -> redirect if this fails
 | 
			
		||||
    try:
 | 
			
		||||
        df = request.GET.get("df", None)
 | 
			
		||||
        dt = request.GET.get("dt", None)
 | 
			
		||||
        date_from = timezone.make_aware(timezone.datetime.fromisoformat(df))
 | 
			
		||||
        date_to = timezone.make_aware(timezone.datetime.fromisoformat(dt))
 | 
			
		||||
    except ValueError:
 | 
			
		||||
        messages.error(
 | 
			
		||||
            request,
 | 
			
		||||
            PARAMS_INVALID,
 | 
			
		||||
            extra_tags="danger",
 | 
			
		||||
        )
 | 
			
		||||
        return redirect("analysis:reports")
 | 
			
		||||
 | 
			
		||||
    # Check whether the html default rendering is requested or an alternative
 | 
			
		||||
    format_param = request.GET.get("format", "html")
 | 
			
		||||
    report = TimespanReport(id, date_from, date_to)
 | 
			
		||||
 | 
			
		||||
    if format_param == "html":
 | 
			
		||||
        template = "analysis/reports/detail.html"
 | 
			
		||||
        context = {
 | 
			
		||||
            "office": cons_office,
 | 
			
		||||
            "report": report,
 | 
			
		||||
        }
 | 
			
		||||
        context = BaseContext(request, context).context
 | 
			
		||||
        return render(request, template, context)
 | 
			
		||||
    elif format_param == "excel":
 | 
			
		||||
        file = TempExcelFile(report.excel_template_path, report.excel_map)
 | 
			
		||||
        response = HttpResponse(
 | 
			
		||||
            content=file.stream,
 | 
			
		||||
            content_type="application/ms-excel",
 | 
			
		||||
        )
 | 
			
		||||
        response['Content-Disposition'] = f'attachment; filename={cons_office.long_name}_{df}_{dt}.xlsx'
 | 
			
		||||
        return response
 | 
			
		||||
    else:
 | 
			
		||||
        raise NotImplementedError
 | 
			
		||||
@ -16,7 +16,7 @@ from codelist.models import KonovaCode
 | 
			
		||||
from codelist.settings import CODELIST_COMPENSATION_FUNDING_ID, CODELIST_CONSERVATION_OFFICE_ID
 | 
			
		||||
from compensation.models import Compensation, EcoAccount
 | 
			
		||||
from intervention.inputs import GenerateInput
 | 
			
		||||
from intervention.models import Intervention, ResponsibilityData
 | 
			
		||||
from intervention.models import Intervention, ResponsibilityData, LegalData
 | 
			
		||||
from konova.forms import BaseForm, SimpleGeomForm
 | 
			
		||||
from user.models import UserActionLogEntry, UserAction
 | 
			
		||||
 | 
			
		||||
@ -284,10 +284,40 @@ class NewEcoAccountForm(AbstractCompensationForm, CompensationResponsibleFormMix
 | 
			
		||||
    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",
 | 
			
		||||
        "handler",
 | 
			
		||||
        "fundings",
 | 
			
		||||
@ -313,7 +343,9 @@ class NewEcoAccountForm(AbstractCompensationForm, CompensationResponsibleFormMix
 | 
			
		||||
            identifier = self.cleaned_data.get("identifier", None)
 | 
			
		||||
            title = self.cleaned_data.get("title", None)
 | 
			
		||||
            fundings = self.cleaned_data.get("fundings", None)
 | 
			
		||||
            registration_date = self.cleaned_data.get("registration_date", None)
 | 
			
		||||
            handler = self.cleaned_data.get("handler", 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)
 | 
			
		||||
@ -332,15 +364,20 @@ class NewEcoAccountForm(AbstractCompensationForm, CompensationResponsibleFormMix
 | 
			
		||||
                conservation_office=conservation_office,
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            legal = LegalData.objects.create(
 | 
			
		||||
                registration_date=registration_date
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
            # Finally create main object
 | 
			
		||||
            acc = EcoAccount.objects.create(
 | 
			
		||||
                identifier=identifier,
 | 
			
		||||
                title=title,
 | 
			
		||||
                responsible=responsible,
 | 
			
		||||
                deductable_surface=0.00,
 | 
			
		||||
                deductable_surface=surface,
 | 
			
		||||
                created=action,
 | 
			
		||||
                geometry=geometry,
 | 
			
		||||
                comment=comment,
 | 
			
		||||
                legal=legal
 | 
			
		||||
            )
 | 
			
		||||
            acc.fundings.set(fundings)
 | 
			
		||||
            acc.users.add(user)
 | 
			
		||||
@ -354,30 +391,6 @@ class EditEcoAccountForm(NewEcoAccountForm):
 | 
			
		||||
    """ Form for editing eco accounts
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    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"
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
    field_order = [
 | 
			
		||||
        "identifier",
 | 
			
		||||
        "title",
 | 
			
		||||
        "conservation_office",
 | 
			
		||||
        "surface",
 | 
			
		||||
        "conservation_file_number",
 | 
			
		||||
        "handler",
 | 
			
		||||
        "fundings",
 | 
			
		||||
        "comment",
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
@ -387,11 +400,15 @@ class EditEcoAccountForm(NewEcoAccountForm):
 | 
			
		||||
        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": self.instance.responsible.handler,
 | 
			
		||||
            "registration_date": reg_date,
 | 
			
		||||
            "conservation_office": self.instance.responsible.conservation_office,
 | 
			
		||||
            "conservation_file_number": self.instance.responsible.conservation_file_number,
 | 
			
		||||
            "fundings": self.instance.fundings.all(),
 | 
			
		||||
@ -409,6 +426,7 @@ class EditEcoAccountForm(NewEcoAccountForm):
 | 
			
		||||
            identifier = self.cleaned_data.get("identifier", None)
 | 
			
		||||
            title = self.cleaned_data.get("title", None)
 | 
			
		||||
            fundings = self.cleaned_data.get("fundings", None)
 | 
			
		||||
            registration_date = self.cleaned_data.get("registration_date", None)
 | 
			
		||||
            handler = self.cleaned_data.get("handler", None)
 | 
			
		||||
            surface = self.cleaned_data.get("surface", None)
 | 
			
		||||
            conservation_office = self.cleaned_data.get("conservation_office", None)
 | 
			
		||||
@ -429,6 +447,10 @@ class EditEcoAccountForm(NewEcoAccountForm):
 | 
			
		||||
            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
 | 
			
		||||
 | 
			
		||||
@ -19,7 +19,7 @@ from codelist.settings import CODELIST_COMPENSATION_ACTION_ID, CODELIST_BIOTOPES
 | 
			
		||||
    CODELIST_COMPENSATION_FUNDING_ID
 | 
			
		||||
from compensation.managers import CompensationStateManager, EcoAccountDeductionManager, CompensationActionManager, \
 | 
			
		||||
    EcoAccountManager, CompensationManager
 | 
			
		||||
from intervention.models import Intervention, ResponsibilityData
 | 
			
		||||
from intervention.models import Intervention, ResponsibilityData, LegalData
 | 
			
		||||
from konova.models import BaseObject, BaseResource, Geometry, UuidModel, AbstractDocument, \
 | 
			
		||||
    generate_document_file_upload_path
 | 
			
		||||
from konova.settings import DEFAULT_SRID_RLP, LANIS_LINK_TEMPLATE
 | 
			
		||||
@ -309,6 +309,14 @@ class EcoAccount(AbstractCompensation):
 | 
			
		||||
        default=0,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    legal = models.OneToOneField(
 | 
			
		||||
        LegalData,
 | 
			
		||||
        on_delete=models.SET_NULL,
 | 
			
		||||
        null=True,
 | 
			
		||||
        blank=True,
 | 
			
		||||
        help_text="Holds data on legal dates or law"
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    objects = EcoAccountManager()
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
 | 
			
		||||
@ -61,6 +61,10 @@
 | 
			
		||||
                        <th scope="row">{% trans 'Conservation office file number' %}</th>
 | 
			
		||||
                        <td class="align-middle">{{obj.responsible.conservation_file_number|default_if_none:""}}</td>
 | 
			
		||||
                    </tr>
 | 
			
		||||
                    <tr {% if not obj.legal.registration_date %}class="alert alert-danger" title="{% trans 'Missing' %}" {% endif %}>
 | 
			
		||||
                        <th scope="row">{% trans 'Agreement date' %}</th>
 | 
			
		||||
                        <td class="align-middle">{{obj.legal.registration_date|default_if_none:""}}</td>
 | 
			
		||||
                    </tr>
 | 
			
		||||
                    <tr {% if not obj.responsible.handler %}class="alert alert-danger" title="{% trans 'Missing' %}" {% endif %}>
 | 
			
		||||
                        <th scope="row">{% trans 'Action handler' %}</th>
 | 
			
		||||
                        <td class="align-middle">{{obj.responsible.handler|default_if_none:""}}</td>
 | 
			
		||||
 | 
			
		||||
@ -77,7 +77,7 @@ def new_view(request: HttpRequest, intervention_id: str = None):
 | 
			
		||||
            messages.success(request, _("Compensation {} added").format(comp.identifier))
 | 
			
		||||
            return redirect("compensation:detail", id=comp.id)
 | 
			
		||||
        else:
 | 
			
		||||
            messages.error(request, FORM_INVALID)
 | 
			
		||||
            messages.error(request, FORM_INVALID, extra_tags="danger",)
 | 
			
		||||
    else:
 | 
			
		||||
        # For clarification: nothing in this case
 | 
			
		||||
        pass
 | 
			
		||||
@ -132,7 +132,7 @@ def edit_view(request: HttpRequest, id: str):
 | 
			
		||||
            messages.success(request, _("Compensation {} edited").format(comp.identifier))
 | 
			
		||||
            return redirect("compensation:detail", id=comp.id)
 | 
			
		||||
        else:
 | 
			
		||||
            messages.error(request, FORM_INVALID)
 | 
			
		||||
            messages.error(request, FORM_INVALID, extra_tags="danger",)
 | 
			
		||||
    else:
 | 
			
		||||
        # For clarification: nothing in this case
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
@ -86,7 +86,7 @@ def new_view(request: HttpRequest):
 | 
			
		||||
            messages.success(request, _("Eco-Account {} added").format(acc.identifier))
 | 
			
		||||
            return redirect("compensation:acc-detail", id=acc.id)
 | 
			
		||||
        else:
 | 
			
		||||
            messages.error(request, FORM_INVALID)
 | 
			
		||||
            messages.error(request, FORM_INVALID, extra_tags="danger",)
 | 
			
		||||
    else:
 | 
			
		||||
        # For clarification: nothing in this case
 | 
			
		||||
        pass
 | 
			
		||||
@ -141,7 +141,7 @@ def edit_view(request: HttpRequest, id: str):
 | 
			
		||||
            messages.success(request, _("Eco-Account {} edited").format(acc.identifier))
 | 
			
		||||
            return redirect("compensation:acc-detail", id=acc.id)
 | 
			
		||||
        else:
 | 
			
		||||
            messages.error(request, FORM_INVALID)
 | 
			
		||||
            messages.error(request, FORM_INVALID, extra_tags="danger",)
 | 
			
		||||
    else:
 | 
			
		||||
        # For clarification: nothing in this case
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
@ -78,7 +78,7 @@ def new_view(request: HttpRequest):
 | 
			
		||||
            messages.success(request, _("EMA {} added").format(ema.identifier))
 | 
			
		||||
            return redirect("ema:detail", id=ema.id)
 | 
			
		||||
        else:
 | 
			
		||||
            messages.error(request, FORM_INVALID)
 | 
			
		||||
            messages.error(request, FORM_INVALID, extra_tags="danger",)
 | 
			
		||||
    else:
 | 
			
		||||
        # For clarification: nothing in this case
 | 
			
		||||
        pass
 | 
			
		||||
@ -202,7 +202,7 @@ def edit_view(request: HttpRequest, id: str):
 | 
			
		||||
            messages.success(request, _("EMA {} edited").format(ema.identifier))
 | 
			
		||||
            return redirect("ema:detail", id=ema.id)
 | 
			
		||||
        else:
 | 
			
		||||
            messages.error(request, FORM_INVALID)
 | 
			
		||||
            messages.error(request, FORM_INVALID, extra_tags="danger",)
 | 
			
		||||
    else:
 | 
			
		||||
        # For clarification: nothing in this case
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
@ -23,26 +23,3 @@ class InterventionManager(models.Manager):
 | 
			
		||||
        ).prefetch_related(
 | 
			
		||||
            "users",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LegalDataManager(models.Manager):
 | 
			
		||||
    """ Holds default db fetch setting for this model type
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        return super().get_querset().select_related(
 | 
			
		||||
            "process_type",
 | 
			
		||||
        ).prefetch_related(
 | 
			
		||||
            "laws"
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ResponsibilityDataManager(models.Manager):
 | 
			
		||||
    """ Holds default db fetch setting for this model type
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        return super().get_querset().select_related(
 | 
			
		||||
            "registration_office",
 | 
			
		||||
            "conservation_office",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,7 @@ from django.utils.translation import gettext_lazy as _
 | 
			
		||||
from codelist.models import KonovaCode
 | 
			
		||||
from codelist.settings import CODELIST_REGISTRATION_OFFICE_ID, CODELIST_CONSERVATION_OFFICE_ID, CODELIST_LAW_ID, \
 | 
			
		||||
    CODELIST_PROCESS_TYPE_ID
 | 
			
		||||
from intervention.managers import InterventionManager, LegalDataManager, ResponsibilityDataManager
 | 
			
		||||
from intervention.managers import InterventionManager
 | 
			
		||||
from konova.models import BaseObject, Geometry, UuidModel, BaseResource, AbstractDocument, \
 | 
			
		||||
    generate_document_file_upload_path
 | 
			
		||||
from konova.settings import DEFAULT_SRID_RLP, LANIS_LINK_TEMPLATE, LANIS_ZOOM_LUT
 | 
			
		||||
@ -56,7 +56,6 @@ class ResponsibilityData(UuidModel):
 | 
			
		||||
    conservation_file_number = models.CharField(max_length=1000, blank=True, null=True)
 | 
			
		||||
    handler = models.CharField(max_length=500, null=True, blank=True, help_text="Refers to 'Eingriffsverursacher' or 'Maßnahmenträger'")
 | 
			
		||||
 | 
			
		||||
    objects = ResponsibilityDataManager()
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        return "ZB: {} | ETS: {} | Handler: {}".format(
 | 
			
		||||
@ -172,8 +171,6 @@ class LegalData(UuidModel):
 | 
			
		||||
 | 
			
		||||
    revocation = models.OneToOneField(Revocation, null=True, blank=True, help_text="Refers to 'Widerspruch am'", on_delete=models.SET_NULL)
 | 
			
		||||
 | 
			
		||||
    objects = LegalDataManager()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Intervention(BaseObject):
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
@ -79,7 +79,7 @@ def new_view(request: HttpRequest):
 | 
			
		||||
            messages.success(request, _("Intervention {} added").format(intervention.identifier))
 | 
			
		||||
            return redirect("intervention:detail", id=intervention.id)
 | 
			
		||||
        else:
 | 
			
		||||
            messages.error(request, FORM_INVALID)
 | 
			
		||||
            messages.error(request, FORM_INVALID, extra_tags="danger",)
 | 
			
		||||
    else:
 | 
			
		||||
        # For clarification: nothing in this case
 | 
			
		||||
        pass
 | 
			
		||||
@ -264,7 +264,7 @@ def edit_view(request: HttpRequest, id: str):
 | 
			
		||||
            messages.success(request, _("Intervention {} edited").format(intervention.identifier))
 | 
			
		||||
            return redirect("intervention:detail", id=intervention.id)
 | 
			
		||||
        else:
 | 
			
		||||
            messages.error(request, FORM_INVALID)
 | 
			
		||||
            messages.error(request, FORM_INVALID, extra_tags="danger",)
 | 
			
		||||
    else:
 | 
			
		||||
        # For clarification: nothing in this case
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
@ -37,12 +37,14 @@ class BaseForm(forms.Form):
 | 
			
		||||
    """
 | 
			
		||||
    template = None
 | 
			
		||||
    action_url = None
 | 
			
		||||
    action_btn_label = _("Save")
 | 
			
		||||
    form_title = None
 | 
			
		||||
    cancel_redirect = None
 | 
			
		||||
    form_caption = None
 | 
			
		||||
    instance = None  # The data holding model object
 | 
			
		||||
    form_attrs = {}  # Holds additional attributes, that can be used in the template
 | 
			
		||||
    has_required_fields = False  # Automatically set. Triggers hint rendering in templates
 | 
			
		||||
    show_cancel_btn = True
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        self.instance = kwargs.pop("instance", None)
 | 
			
		||||
@ -189,6 +191,7 @@ class BaseModalForm(BaseForm, BSModalForm):
 | 
			
		||||
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.action_btn_label = _("Continue")
 | 
			
		||||
 | 
			
		||||
    def process_request(self, request: HttpRequest, msg_success: str = _("Object removed"), msg_error: str = FORM_INVALID, redirect_url: str = None):
 | 
			
		||||
        """ Generic processing of request
 | 
			
		||||
 | 
			
		||||
@ -69,6 +69,7 @@ INSTALLED_APPS = [
 | 
			
		||||
    'user',
 | 
			
		||||
    'ema',
 | 
			
		||||
    'codelist',
 | 
			
		||||
    'analysis',
 | 
			
		||||
]
 | 
			
		||||
if DEBUG:
 | 
			
		||||
    INSTALLED_APPS += [
 | 
			
		||||
 | 
			
		||||
@ -34,3 +34,19 @@ def bootstrap_cls(value):
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    return SVI_BOOTSTRAP_CLS_MAP.get(value, "")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@register.filter("default_if_zero")
 | 
			
		||||
def default_if_zero(val1, val2):
 | 
			
		||||
    """ Returns val2 if val1 is 0
 | 
			
		||||
 | 
			
		||||
    Similar to default_if_none
 | 
			
		||||
 | 
			
		||||
    Args:
 | 
			
		||||
        val1 (int): The numerical value
 | 
			
		||||
        val2 (str): The alternative
 | 
			
		||||
 | 
			
		||||
    Returns:
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    return val1 if val1 > 0 else val2
 | 
			
		||||
 | 
			
		||||
@ -36,7 +36,8 @@ urlpatterns = [
 | 
			
		||||
    path('ema/', include("ema.urls")),
 | 
			
		||||
    path('user/', include("user.urls")),
 | 
			
		||||
    path('news/', include("news.urls")),
 | 
			
		||||
    path('news/', include("codelist.urls")),
 | 
			
		||||
    path('cl/', include("codelist.urls")),
 | 
			
		||||
    path('analysis/', include("analysis.urls")),
 | 
			
		||||
 | 
			
		||||
    # Generic deadline routes
 | 
			
		||||
    path('deadline/<id>/remove', remove_deadline_view, name="deadline-remove"),
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@ from django.utils.translation import gettext_lazy as _
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
FORM_INVALID = _("There was an error on this form.")
 | 
			
		||||
PARAMS_INVALID = _("Invalid parameters")
 | 
			
		||||
INTERVENTION_INVALID = _("There are errors in this intervention.")
 | 
			
		||||
IDENTIFIER_REPLACED = _("The identifier '{}' had to be changed to '{}' since another entry has been added in the meanwhile, which uses this identifier")
 | 
			
		||||
DATA_UNSHARED = _("This data is not shared with you")
 | 
			
		||||
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -11,11 +11,14 @@ django-filter==2.4.0
 | 
			
		||||
django-fontawesome-5==1.0.18
 | 
			
		||||
django-simple-sso==1.1.0
 | 
			
		||||
django-tables2==2.3.4
 | 
			
		||||
et-xmlfile==1.1.0
 | 
			
		||||
idna==2.10
 | 
			
		||||
importlib-metadata==2.1.1
 | 
			
		||||
itsdangerous
 | 
			
		||||
psycopg2-binary
 | 
			
		||||
itsdangerous==0.24
 | 
			
		||||
openpyxl==3.0.9
 | 
			
		||||
psycopg2-binary==2.9.1
 | 
			
		||||
pytz==2020.4
 | 
			
		||||
qrcode==7.3.1
 | 
			
		||||
requests==2.25.0
 | 
			
		||||
six==1.15.0
 | 
			
		||||
soupsieve==2.2.1
 | 
			
		||||
 | 
			
		||||
@ -19,12 +19,14 @@
 | 
			
		||||
        {% include 'form/table/generic_table_form_body.html' %}
 | 
			
		||||
        <div class="row">
 | 
			
		||||
            <div class="col-6">
 | 
			
		||||
                {% if form.show_cancel_btn %}
 | 
			
		||||
                <a href="{{ form.cancel_redirect }}">
 | 
			
		||||
                    <button class="btn btn-default" type="button" title="{% trans 'Cancel' %}">{% trans 'Cancel' %}</button>
 | 
			
		||||
                </a>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col-6 d-flex justify-content-end">
 | 
			
		||||
                <button class="btn btn-default" type="submit" title="{% trans 'Save' %}">{% trans 'Save' %}</button>
 | 
			
		||||
                <button class="btn btn-default" type="submit" title="{{form.action_btn_label}}">{{form.action_btn_label}}</button>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </form>
 | 
			
		||||
 | 
			
		||||
@ -22,7 +22,7 @@
 | 
			
		||||
    </div>
 | 
			
		||||
    {% if form.render_submit %}
 | 
			
		||||
    <div class="modal-footer">
 | 
			
		||||
        <button type="submit" class="btn btn-default">{% trans 'Continue' %}</button>
 | 
			
		||||
        <button type="submit" class="btn btn-default" title="{{form.action_btn_label}}">{{form.action_btn_label}}</button>
 | 
			
		||||
    </div>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
</form>
 | 
			
		||||
@ -43,7 +43,7 @@
 | 
			
		||||
                    <a class="dropdown-item" href="{% url 'ema:index' %}" title="{% trans 'Payment funded compensations' %}">{% fa5_icon 'euro-sign' %}  {% trans 'EMA' %}</a>
 | 
			
		||||
                    <a class="dropdown-item" href="{% url 'home' %}">{% fa5_icon 'file-import' %}  {% trans 'Import...' %}</a>
 | 
			
		||||
                    <a class="dropdown-item" href="{% url 'home' %}">{% fa5_icon 'file-export' %}  {% trans 'Export...' %}</a>
 | 
			
		||||
                    <a class="dropdown-item" href="{% url 'home' %}">{% fa5_icon 'file-alt' %}  {% trans 'Reports' %}</a>
 | 
			
		||||
                    <a class="dropdown-item" href="{% url 'analysis:reports' %}">{% fa5_icon 'file-alt' %}  {% trans 'Reports' %}</a>
 | 
			
		||||
                </div>
 | 
			
		||||
            </li>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user