Compare commits
No commits in common. "615b7bf5eab107c73a8d6d0466f68966c8819777" and "c82ee8afbc15f88683197595298617205f31c27a" have entirely different histories.
615b7bf5ea
...
c82ee8afbc
@ -5,12 +5,11 @@ Contact: michel.peltriaux@sgdnord.rlp.de
|
|||||||
Created on: 04.12.20
|
Created on: 04.12.20
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from bootstrap_modal_forms.utils import is_ajax
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.http import HttpRequest, HttpResponseRedirect
|
from django.http import HttpRequest
|
||||||
from django.shortcuts import render
|
from django.shortcuts import redirect, render
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from compensation.models import Payment, CompensationState, CompensationAction, UnitChoices
|
from compensation.models import Payment, CompensationState, CompensationAction, UnitChoices
|
||||||
@ -89,8 +88,6 @@ class NewPaymentForm(BaseModalForm):
|
|||||||
intervention=self.intervention,
|
intervention=self.intervention,
|
||||||
)
|
)
|
||||||
self.intervention.log.add(edited_action)
|
self.intervention.log.add(edited_action)
|
||||||
self.intervention.modified = edited_action
|
|
||||||
self.intervention.save()
|
|
||||||
return pay
|
return pay
|
||||||
|
|
||||||
|
|
||||||
@ -124,8 +121,6 @@ class NewStateModalForm(BaseModalForm):
|
|||||||
comment=_("Added state")
|
comment=_("Added state")
|
||||||
)
|
)
|
||||||
self.instance.log.add(user_action)
|
self.instance.log.add(user_action)
|
||||||
self.instance.modified = user_action
|
|
||||||
self.instance.save()
|
|
||||||
|
|
||||||
state = CompensationState.objects.create(
|
state = CompensationState.objects.create(
|
||||||
biotope_type=self.cleaned_data["biotope_type"],
|
biotope_type=self.cleaned_data["biotope_type"],
|
||||||
@ -158,24 +153,19 @@ class NewStateModalForm(BaseModalForm):
|
|||||||
template = self.template
|
template = self.template
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
if self.is_valid():
|
if self.is_valid():
|
||||||
# Modal forms send one POST for checking on data validity. This can be used to return possible errors
|
|
||||||
# on the form. A second POST (if no errors occured) is sent afterwards and needs to process the
|
|
||||||
# saving/commiting of the data to the database. is_ajax() performs this check. The first request is
|
|
||||||
# an ajax call, the second is a regular form POST.
|
|
||||||
if not is_ajax(request.META):
|
|
||||||
is_before_state = bool(request.GET.get("before", False))
|
is_before_state = bool(request.GET.get("before", False))
|
||||||
self.save(is_before_state=is_before_state)
|
self.save(is_before_state=is_before_state)
|
||||||
messages.success(
|
messages.success(
|
||||||
request,
|
request,
|
||||||
msg_success
|
msg_success
|
||||||
)
|
)
|
||||||
return HttpResponseRedirect(redirect_url)
|
return redirect(redirect_url)
|
||||||
else:
|
else:
|
||||||
context = {
|
messages.info(
|
||||||
"form": self,
|
request,
|
||||||
}
|
msg_error
|
||||||
context = BaseContext(request, context).context
|
)
|
||||||
return render(request, template, context)
|
return redirect(redirect_url)
|
||||||
elif request.method == "GET":
|
elif request.method == "GET":
|
||||||
context = {
|
context = {
|
||||||
"form": self,
|
"form": self,
|
||||||
@ -248,8 +238,6 @@ class NewDeadlineModalForm(BaseModalForm):
|
|||||||
action=UserAction.EDITED,
|
action=UserAction.EDITED,
|
||||||
comment=_("Added deadline")
|
comment=_("Added deadline")
|
||||||
)
|
)
|
||||||
self.instance.modified = edited_action
|
|
||||||
self.instance.save()
|
|
||||||
self.instance.log.add(edited_action)
|
self.instance.log.add(edited_action)
|
||||||
self.instance.deadlines.add(deadline)
|
self.instance.deadlines.add(deadline)
|
||||||
return deadline
|
return deadline
|
||||||
@ -320,8 +308,6 @@ class NewActionModalForm(BaseModalForm):
|
|||||||
action=UserAction.EDITED,
|
action=UserAction.EDITED,
|
||||||
comment=_("Added action"),
|
comment=_("Added action"),
|
||||||
)
|
)
|
||||||
self.instance.modified = edited_action
|
|
||||||
self.instance.save()
|
|
||||||
self.instance.log.add(edited_action)
|
self.instance.log.add(edited_action)
|
||||||
self.instance.actions.add(comp_action)
|
self.instance.actions.add(comp_action)
|
||||||
return comp_action
|
return comp_action
|
||||||
|
@ -91,8 +91,8 @@ class CompensationAction(BaseResource):
|
|||||||
|
|
||||||
class AbstractCompensation(BaseObject):
|
class AbstractCompensation(BaseObject):
|
||||||
"""
|
"""
|
||||||
Abstract compensation model which holds basic attributes, shared by subclasses like the regular Compensation,
|
Abstract compensation model which holds basic attributes, shared by subclasses like the regular Compensation
|
||||||
EMA or EcoAccount.
|
or EcoAccount.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
responsible = models.OneToOneField(
|
responsible = models.OneToOneField(
|
||||||
@ -112,6 +112,9 @@ class AbstractCompensation(BaseObject):
|
|||||||
geometry = models.ForeignKey(Geometry, null=True, blank=True, on_delete=models.SET_NULL)
|
geometry = models.ForeignKey(Geometry, null=True, blank=True, on_delete=models.SET_NULL)
|
||||||
documents = models.ManyToManyField("konova.Document", blank=True)
|
documents = models.ManyToManyField("konova.Document", blank=True)
|
||||||
|
|
||||||
|
# Holds a successor for this data
|
||||||
|
next_version = models.ForeignKey("Compensation", null=True, blank=True, on_delete=models.DO_NOTHING)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
@ -257,17 +260,9 @@ class EcoAccount(AbstractCompensation):
|
|||||||
y,
|
y,
|
||||||
)
|
)
|
||||||
|
|
||||||
def quality_check(self) -> list:
|
def quality_check(self) -> (bool, dict):
|
||||||
""" Quality check
|
# ToDo
|
||||||
|
pass
|
||||||
Returns:
|
|
||||||
ret_msgs (list): Holds error messages
|
|
||||||
"""
|
|
||||||
ret_msgs = []
|
|
||||||
|
|
||||||
# ToDo: Add check methods!
|
|
||||||
|
|
||||||
return ret_msgs
|
|
||||||
|
|
||||||
|
|
||||||
class EcoAccountWithdraw(BaseResource):
|
class EcoAccountWithdraw(BaseResource):
|
||||||
|
@ -7,6 +7,5 @@ Created on: 18.12.20
|
|||||||
"""
|
"""
|
||||||
COMPENSATION_IDENTIFIER_LENGTH = 10
|
COMPENSATION_IDENTIFIER_LENGTH = 10
|
||||||
COMPENSATION_IDENTIFIER_TEMPLATE = "KOM-{}"
|
COMPENSATION_IDENTIFIER_TEMPLATE = "KOM-{}"
|
||||||
|
|
||||||
ECO_ACCOUNT_IDENTIFIER_LENGTH = 10
|
ECO_ACCOUNT_IDENTIFIER_LENGTH = 10
|
||||||
ECO_ACCOUNT_IDENTIFIER_TEMPLATE = "OEK-{}"
|
ECO_ACCOUNT_IDENTIFIER_TEMPLATE = "OEK-{}"
|
@ -5,6 +5,7 @@ Contact: michel.peltriaux@sgdnord.rlp.de
|
|||||||
Created on: 01.12.20
|
Created on: 01.12.20
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
from django.db.models import Sum
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
@ -14,6 +15,7 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
|
|
||||||
from compensation.filters import CompensationTableFilter, EcoAccountTableFilter
|
from compensation.filters import CompensationTableFilter, EcoAccountTableFilter
|
||||||
from compensation.models import Compensation, EcoAccount
|
from compensation.models import Compensation, EcoAccount
|
||||||
|
from intervention.filters import InterventionTableFilter
|
||||||
from konova.sub_settings.django_settings import DEFAULT_DATE_TIME_FORMAT
|
from konova.sub_settings.django_settings import DEFAULT_DATE_TIME_FORMAT
|
||||||
from konova.utils.tables import BaseTable
|
from konova.utils.tables import BaseTable
|
||||||
import django_tables2 as tables
|
import django_tables2 as tables
|
||||||
@ -51,7 +53,7 @@ class CompensationTable(BaseTable):
|
|||||||
lm = tables.Column(
|
lm = tables.Column(
|
||||||
verbose_name=_("Last edit"),
|
verbose_name=_("Last edit"),
|
||||||
orderable=True,
|
orderable=True,
|
||||||
accessor="modified__timestamp",
|
accessor="created__timestamp",
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta(BaseTable.Meta):
|
class Meta(BaseTable.Meta):
|
||||||
@ -124,21 +126,21 @@ class CompensationTable(BaseTable):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
html = ""
|
html = ""
|
||||||
recorded = value is not None
|
checked = value is not None
|
||||||
tooltip = _("Not recorded yet")
|
tooltip = _("Not recorded yet")
|
||||||
if recorded:
|
if checked:
|
||||||
value = value.timestamp
|
value = value.timestamp
|
||||||
value = localtime(value)
|
value = localtime(value)
|
||||||
on = value.strftime(DEFAULT_DATE_TIME_FORMAT)
|
on = value.strftime(DEFAULT_DATE_TIME_FORMAT)
|
||||||
tooltip = _("Recorded on {} by {}").format(on, record.intervention.recorded.user)
|
tooltip = _("Recorded on {} by {}").format(on, record.intervention.recorded.user)
|
||||||
html += self.render_bookmark(
|
html += self.render_bookmark(
|
||||||
tooltip=tooltip,
|
tooltip=tooltip,
|
||||||
icn_filled=recorded,
|
icn_filled=checked,
|
||||||
)
|
)
|
||||||
return format_html(html)
|
return format_html(html)
|
||||||
|
|
||||||
def render_e(self, value, record: Compensation):
|
def render_e(self, value, record: Compensation):
|
||||||
""" Renders the editable column for a compensation
|
""" Renders the registered column for a compensation
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
value (str): The identifier value
|
value (str): The identifier value
|
||||||
@ -190,7 +192,7 @@ class EcoAccountTable(BaseTable):
|
|||||||
lm = tables.Column(
|
lm = tables.Column(
|
||||||
verbose_name=_("Last edit"),
|
verbose_name=_("Last edit"),
|
||||||
orderable=True,
|
orderable=True,
|
||||||
accessor="modified__timestamp",
|
accessor="created__timestamp",
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta(BaseTable.Meta):
|
class Meta(BaseTable.Meta):
|
||||||
|
@ -63,9 +63,9 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th scope="row">{% trans 'Last modified' %}</th>
|
<th scope="row">{% trans 'Last modified' %}</th>
|
||||||
<td class="align-middle">
|
<td class="align-middle">
|
||||||
{{obj.modified.timestamp|default_if_none:""|naturalday}}
|
{{obj.created.timestamp|default_if_none:""|naturalday}}
|
||||||
<br>
|
<br>
|
||||||
{{obj.modified.user.username}}
|
{{obj.created.user.username}}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -55,9 +55,9 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th scope="row">{% trans 'Last modified' %}</th>
|
<th scope="row">{% trans 'Last modified' %}</th>
|
||||||
<td class="align-middle">
|
<td class="align-middle">
|
||||||
{{obj.modified.timestamp|default_if_none:""|naturalday}}
|
{{obj.created.timestamp|default_if_none:""|naturalday}}
|
||||||
<br>
|
<br>
|
||||||
{{obj.modified.user.username}}
|
{{obj.created.user.username}}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -118,7 +118,7 @@ def log_view(request: HttpRequest, id: str):
|
|||||||
|
|
||||||
context = {
|
context = {
|
||||||
"modal_body_template": body_template,
|
"modal_body_template": body_template,
|
||||||
"log": comp.log.all(),
|
"log": comp.log.all().order_by("-timestamp"),
|
||||||
"modal_title": _("Log"),
|
"modal_title": _("Log"),
|
||||||
}
|
}
|
||||||
context = BaseContext(request, context).context
|
context = BaseContext(request, context).context
|
||||||
@ -141,7 +141,7 @@ def remove_view(request: HttpRequest, id: str):
|
|||||||
return form.process_request(
|
return form.process_request(
|
||||||
request=request,
|
request=request,
|
||||||
msg_success=_("Compensation removed"),
|
msg_success=_("Compensation removed"),
|
||||||
redirect_url=reverse("compensation:index"),
|
redirect_url="",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -180,7 +180,7 @@ def log_view(request: HttpRequest, id: str):
|
|||||||
|
|
||||||
context = {
|
context = {
|
||||||
"modal_body_template": body_template,
|
"modal_body_template": body_template,
|
||||||
"log": comp.log.all(),
|
"log": comp.log.all().order_by("-timestamp"),
|
||||||
"modal_title": _("Log"),
|
"modal_title": _("Log"),
|
||||||
}
|
}
|
||||||
context = BaseContext(request, context).context
|
context = BaseContext(request, context).context
|
||||||
|
@ -6,15 +6,18 @@ Created on: 09.08.21
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404, render, redirect
|
||||||
|
|
||||||
from compensation.forms import NewPaymentForm
|
from compensation.forms import NewPaymentForm
|
||||||
from compensation.models import Payment
|
from compensation.models import Payment
|
||||||
from intervention.models import Intervention
|
from intervention.models import Intervention
|
||||||
|
from konova.contexts import BaseContext
|
||||||
from konova.decorators import default_group_required
|
from konova.decorators import default_group_required
|
||||||
from konova.forms import RemoveModalForm
|
from konova.forms import RemoveModalForm
|
||||||
|
from konova.utils.message_templates import FORM_INVALID
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@ -31,10 +34,29 @@ def new_payment_view(request: HttpRequest, intervention_id: str):
|
|||||||
"""
|
"""
|
||||||
intervention = get_object_or_404(Intervention, id=intervention_id)
|
intervention = get_object_or_404(Intervention, id=intervention_id)
|
||||||
form = NewPaymentForm(request.POST or None, instance=intervention, user=request.user)
|
form = NewPaymentForm(request.POST or None, instance=intervention, user=request.user)
|
||||||
return form.process_request(
|
template = form.template
|
||||||
|
if request.method == "POST":
|
||||||
|
if form.is_valid():
|
||||||
|
payment = form.save()
|
||||||
|
messages.success(
|
||||||
request,
|
request,
|
||||||
msg_success=_("Payment added")
|
_("Payment added")
|
||||||
)
|
)
|
||||||
|
return redirect(request.META.get("HTTP_REFERER", "home"))
|
||||||
|
else:
|
||||||
|
messages.info(
|
||||||
|
request,
|
||||||
|
FORM_INVALID
|
||||||
|
)
|
||||||
|
return redirect(request.META.get("HTTP_REFERER", "home"))
|
||||||
|
elif request.method == "GET":
|
||||||
|
context = {
|
||||||
|
"form": form,
|
||||||
|
}
|
||||||
|
context = BaseContext(request, context).context
|
||||||
|
return render(request, template, context)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
10
ema/admin.py
10
ema/admin.py
@ -1,10 +0,0 @@
|
|||||||
from django.contrib import admin
|
|
||||||
|
|
||||||
from compensation.admin import CompensationAdmin
|
|
||||||
from ema.models import Ema
|
|
||||||
|
|
||||||
|
|
||||||
class EmaAdmin(CompensationAdmin):
|
|
||||||
pass
|
|
||||||
|
|
||||||
admin.site.register(Ema, EmaAdmin)
|
|
@ -1,5 +0,0 @@
|
|||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class EmaConfig(AppConfig):
|
|
||||||
name = 'ema'
|
|
@ -1,53 +0,0 @@
|
|||||||
"""
|
|
||||||
Author: Michel Peltriaux
|
|
||||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
|
|
||||||
Contact: michel.peltriaux@sgdnord.rlp.de
|
|
||||||
Created on: 19.08.21
|
|
||||||
|
|
||||||
"""
|
|
||||||
from django.db.models import QuerySet
|
|
||||||
|
|
||||||
from compensation.filters import CompensationTableFilter
|
|
||||||
|
|
||||||
|
|
||||||
class EmaTableFilter(CompensationTableFilter):
|
|
||||||
"""
|
|
||||||
Since EMA and compensation are basically the same, we can reuse CompensationTableFilter and extend the MAE filter
|
|
||||||
in the future by inheriting.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def _filter_show_all(self, queryset, name, value) -> QuerySet:
|
|
||||||
""" Filters queryset depending on value of 'show_all' setting
|
|
||||||
|
|
||||||
Args:
|
|
||||||
queryset ():
|
|
||||||
name ():
|
|
||||||
value ():
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
if not value:
|
|
||||||
return queryset.filter(
|
|
||||||
users__in=[self.user], # requesting user has access
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return queryset
|
|
||||||
|
|
||||||
def _filter_show_recorded(self, queryset, name, value) -> QuerySet:
|
|
||||||
""" Filters queryset depending on value of 'show_recorded' setting
|
|
||||||
|
|
||||||
Args:
|
|
||||||
queryset ():
|
|
||||||
name ():
|
|
||||||
value ():
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
if not value:
|
|
||||||
return queryset.filter(
|
|
||||||
recorded=None,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
return queryset
|
|
@ -1,86 +0,0 @@
|
|||||||
from django.contrib.auth.models import User
|
|
||||||
from django.db import models
|
|
||||||
|
|
||||||
from compensation.models import AbstractCompensation
|
|
||||||
from konova.settings import DEFAULT_SRID_RLP, LANIS_LINK_TEMPLATE
|
|
||||||
from user.models import UserActionLogEntry
|
|
||||||
|
|
||||||
|
|
||||||
class Ema(AbstractCompensation):
|
|
||||||
"""
|
|
||||||
EMA = Ersatzzahlungsmaßnahme
|
|
||||||
(compensation actions from payments)
|
|
||||||
|
|
||||||
Until 2015 the EMA was the data object to keep track of any compensation, which has been funded by payments
|
|
||||||
previously paid. In 2015 another organization got in charge of this, which led to the creation of the data object
|
|
||||||
MAE (which is basically the same, just renamed in their system) to differ between the 'old' payment funded ones and
|
|
||||||
the new. For historical reasons, we need to keep EMAs in our system, since there are still entries done to this day,
|
|
||||||
which have been performed somewhere before 2015 and therefore needs to be entered.
|
|
||||||
Further information:
|
|
||||||
https://snu.rlp.de/de/foerderungen/massnahmen-aus-ersatzzahlungen/uebersicht-mae/
|
|
||||||
|
|
||||||
EMA therefore holds data like a compensation: actions, before-/after-states, deadlines, ...
|
|
||||||
|
|
||||||
"""
|
|
||||||
# Users having access on this object
|
|
||||||
# Not needed in regular Compensation since their access is defined by the linked intervention's access
|
|
||||||
users = models.ManyToManyField(
|
|
||||||
User,
|
|
||||||
help_text="Users having access (shared with)"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Refers to "verzeichnen"
|
|
||||||
recorded = models.OneToOneField(
|
|
||||||
UserActionLogEntry,
|
|
||||||
on_delete=models.SET_NULL,
|
|
||||||
null=True,
|
|
||||||
blank=True,
|
|
||||||
help_text="Holds data on user and timestamp of this action",
|
|
||||||
related_name="+"
|
|
||||||
)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "{}".format(self.identifier)
|
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
|
||||||
if self.identifier is None or len(self.identifier) == 0:
|
|
||||||
# Create new identifier
|
|
||||||
new_id = self._generate_new_identifier()
|
|
||||||
while Ema.objects.filter(identifier=new_id).exists():
|
|
||||||
new_id = self._generate_new_identifier()
|
|
||||||
self.identifier = new_id
|
|
||||||
super().save(*args, **kwargs)
|
|
||||||
|
|
||||||
def get_LANIS_link(self) -> str:
|
|
||||||
""" Generates a link for LANIS depending on the geometry
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
geom = self.geometry.geom.transform(DEFAULT_SRID_RLP, clone=True)
|
|
||||||
x = geom.centroid.x
|
|
||||||
y = geom.centroid.y
|
|
||||||
zoom_lvl = 16
|
|
||||||
except AttributeError:
|
|
||||||
# If no geometry has been added, yet.
|
|
||||||
x = 1
|
|
||||||
y = 1
|
|
||||||
zoom_lvl = 6
|
|
||||||
return LANIS_LINK_TEMPLATE.format(
|
|
||||||
zoom_lvl,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
)
|
|
||||||
|
|
||||||
def quality_check(self) -> list:
|
|
||||||
""" Quality check
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
ret_msgs (list): Holds error messages
|
|
||||||
"""
|
|
||||||
ret_msgs = []
|
|
||||||
|
|
||||||
# ToDo: Add check methods!
|
|
||||||
|
|
||||||
return ret_msgs
|
|
@ -1,10 +0,0 @@
|
|||||||
"""
|
|
||||||
Author: Michel Peltriaux
|
|
||||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
|
|
||||||
Contact: michel.peltriaux@sgdnord.rlp.de
|
|
||||||
Created on: 19.08.21
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
EMA_ACCOUNT_IDENTIFIER_LENGTH = 10
|
|
||||||
EMA_ACCOUNT_IDENTIFIER_TEMPLATE = "EMA-{}"
|
|
132
ema/tables.py
132
ema/tables.py
@ -1,132 +0,0 @@
|
|||||||
"""
|
|
||||||
Author: Michel Peltriaux
|
|
||||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
|
|
||||||
Contact: michel.peltriaux@sgdnord.rlp.de
|
|
||||||
Created on: 19.08.21
|
|
||||||
|
|
||||||
"""
|
|
||||||
from django.http import HttpRequest
|
|
||||||
from django.utils.html import format_html
|
|
||||||
from django.utils.timezone import localtime
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
from django.urls import reverse
|
|
||||||
|
|
||||||
import django_tables2 as tables
|
|
||||||
|
|
||||||
from konova.sub_settings.django_settings import DEFAULT_DATE_TIME_FORMAT
|
|
||||||
from konova.utils.tables import BaseTable
|
|
||||||
from ema.filters import EmaTableFilter
|
|
||||||
from ema.models import Ema
|
|
||||||
|
|
||||||
|
|
||||||
class EmaTable(BaseTable):
|
|
||||||
"""
|
|
||||||
Since EMA and compensation are basically the same, we can reuse CompensationTableFilter and extend the EMA filter
|
|
||||||
in the future by inheriting.
|
|
||||||
"""
|
|
||||||
id = tables.Column(
|
|
||||||
verbose_name=_("Identifier"),
|
|
||||||
orderable=True,
|
|
||||||
accessor="identifier",
|
|
||||||
)
|
|
||||||
t = tables.Column(
|
|
||||||
verbose_name=_("Title"),
|
|
||||||
orderable=True,
|
|
||||||
accessor="title",
|
|
||||||
)
|
|
||||||
r = tables.Column(
|
|
||||||
verbose_name=_("Recorded"),
|
|
||||||
orderable=True,
|
|
||||||
empty_values=[],
|
|
||||||
accessor="recorded",
|
|
||||||
)
|
|
||||||
e = tables.Column(
|
|
||||||
verbose_name=_("Editable"),
|
|
||||||
orderable=True,
|
|
||||||
empty_values=[],
|
|
||||||
accessor="users",
|
|
||||||
)
|
|
||||||
lm = tables.Column(
|
|
||||||
verbose_name=_("Last edit"),
|
|
||||||
orderable=True,
|
|
||||||
accessor="created__timestamp",
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta(BaseTable.Meta):
|
|
||||||
template_name = "django_tables2/bootstrap4.html"
|
|
||||||
|
|
||||||
def __init__(self, request: HttpRequest, *args, **kwargs):
|
|
||||||
self.title = _("Payment funded compensations")
|
|
||||||
self.subtitle = _("EMA explanation")
|
|
||||||
self.add_new_url = reverse("ema:new")
|
|
||||||
qs = kwargs.get("queryset", None)
|
|
||||||
self.filter = EmaTableFilter(
|
|
||||||
user=request.user,
|
|
||||||
data=request.GET,
|
|
||||||
queryset=qs,
|
|
||||||
)
|
|
||||||
super().__init__(request, self.filter, *args, **kwargs)
|
|
||||||
|
|
||||||
def render_id(self, value, record: Ema):
|
|
||||||
""" Renders the id column for a EMA
|
|
||||||
|
|
||||||
Args:
|
|
||||||
value (str): The identifier value
|
|
||||||
record (EMA): The EMA record
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
html = ""
|
|
||||||
html += self.render_link(
|
|
||||||
tooltip=_("Open {}").format(_("EMA")),
|
|
||||||
href=reverse("ema:open", args=(record.id,)),
|
|
||||||
txt=value,
|
|
||||||
new_tab=False,
|
|
||||||
)
|
|
||||||
return format_html(html)
|
|
||||||
|
|
||||||
def render_r(self, value, record: Ema):
|
|
||||||
""" Renders the registered column for a EMA
|
|
||||||
|
|
||||||
Args:
|
|
||||||
value (str): The identifier value
|
|
||||||
record (Ema): The EMA record
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
html = ""
|
|
||||||
recorded = value is not None
|
|
||||||
tooltip = _("Not recorded yet")
|
|
||||||
if recorded:
|
|
||||||
value = value.timestamp
|
|
||||||
value = localtime(value)
|
|
||||||
on = value.strftime(DEFAULT_DATE_TIME_FORMAT)
|
|
||||||
tooltip = _("Recorded on {} by {}").format(on, record.recorded.user)
|
|
||||||
html += self.render_bookmark(
|
|
||||||
tooltip=tooltip,
|
|
||||||
icn_filled=recorded,
|
|
||||||
)
|
|
||||||
return format_html(html)
|
|
||||||
|
|
||||||
def render_e(self, value, record: Ema):
|
|
||||||
""" Renders the editable column for a EMA
|
|
||||||
|
|
||||||
Args:
|
|
||||||
value (str): The identifier value
|
|
||||||
record (Ema): The EMA record
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
html = ""
|
|
||||||
has_access = value.filter(
|
|
||||||
username=self.user.username
|
|
||||||
).exists()
|
|
||||||
|
|
||||||
html += self.render_icn(
|
|
||||||
tooltip=_("Full access granted") if has_access else _("Access not granted"),
|
|
||||||
icn_class="fas fa-edit rlp-r-inv" if has_access else "far fa-edit",
|
|
||||||
)
|
|
||||||
return format_html(html)
|
|
@ -1,61 +0,0 @@
|
|||||||
{% load i18n l10n fontawesome_5 humanize %}
|
|
||||||
<div id="actions" class="card">
|
|
||||||
<div class="card-header rlp-r">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<h5>
|
|
||||||
<span class="badge badge-light">{{obj.actions.count}}</span>
|
|
||||||
{% trans 'Actions' context 'Compensation' %}
|
|
||||||
</h5>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<div class="d-flex justify-content-end">
|
|
||||||
{% if is_default_member and has_access %}
|
|
||||||
<button class="btn btn-outline-default btn-modal" data-form-url="{% url 'ema:new-action' obj.id %}" title="{% trans 'Add new action' %}">
|
|
||||||
{% fa5_icon 'plus' %}
|
|
||||||
{% fa5_icon 'seedling' %}
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-body scroll-300">
|
|
||||||
<table class="table table-hover">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th scope="col">
|
|
||||||
{% trans 'Action type' %}
|
|
||||||
</th>
|
|
||||||
<th scope="col">
|
|
||||||
{% trans 'Amount' context 'Compensation' %}
|
|
||||||
</th>
|
|
||||||
<th scope="col">
|
|
||||||
{% trans 'Comment' %}
|
|
||||||
</th>
|
|
||||||
<th scope="col">
|
|
||||||
{% trans 'Action' %}
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for action in obj.actions.all %}
|
|
||||||
<tr>
|
|
||||||
<td class="align-middle">
|
|
||||||
{{ action.action_type }}
|
|
||||||
</td>
|
|
||||||
<td class="align-middle">{{ action.amount|floatformat:2|intcomma }} {{ action.unit_humanize }}</td>
|
|
||||||
<td class="align-middle">{{ action.comment|default_if_none:"" }}</td>
|
|
||||||
<td>
|
|
||||||
{% if is_default_member and has_access %}
|
|
||||||
<button data-form-url="{% url 'ema:action-remove' action.id %}" class="btn btn-default btn-modal" title="{% trans 'Remove action' %}">
|
|
||||||
{% fa5_icon 'trash' %}
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,40 +0,0 @@
|
|||||||
{% load i18n l10n fontawesome_5 %}
|
|
||||||
|
|
||||||
<div class="d-flex justify-content-end">
|
|
||||||
<a href="{{LANIS_LINK}}" class="mr-2" target="_blank">
|
|
||||||
<button class="btn btn-default" title="{% trans 'Open in LANIS' %}">
|
|
||||||
LANIS
|
|
||||||
</button>
|
|
||||||
</a>
|
|
||||||
<a href="{% url 'home' %}" class="mr-2">
|
|
||||||
<button class="btn btn-default" title="{% trans 'Public report' %}">
|
|
||||||
{% fa5_icon 'file-alt' %}
|
|
||||||
</button>
|
|
||||||
</a>
|
|
||||||
{% if has_access %}
|
|
||||||
{% if is_ets_member %}
|
|
||||||
{% if obj.recorded %}
|
|
||||||
<button class="btn btn-default btn-modal mr-2" title="{% trans 'Unrecord' %}" data-form-url="{% url 'ema:record' obj.id %}">
|
|
||||||
{% fa5_icon 'bookmark' 'far' %}
|
|
||||||
</button>
|
|
||||||
{% else %}
|
|
||||||
<button class="btn btn-default btn-modal mr-2" title="{% trans 'Record' %}" data-form-url="{% url 'ema:record' obj.id %}">
|
|
||||||
{% fa5_icon 'bookmark' %}
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
{% if is_default_member %}
|
|
||||||
<a href="{% url 'home' %}" class="mr-2">
|
|
||||||
<button class="btn btn-default" title="{% trans 'Edit' %}">
|
|
||||||
{% fa5_icon 'edit' %}
|
|
||||||
</button>
|
|
||||||
</a>
|
|
||||||
<button class="btn btn-default btn-modal mr-2" data-form-url="{% url 'ema:log' obj.id %}" title="{% trans 'Show log' %}">
|
|
||||||
{% fa5_icon 'history' %}
|
|
||||||
</button>
|
|
||||||
<button class="btn btn-default btn-modal" data-form-url="{% url 'ema:remove' obj.id %}" title="{% trans 'Delete' %}">
|
|
||||||
{% fa5_icon 'trash' %}
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
@ -1,61 +0,0 @@
|
|||||||
{% load i18n l10n fontawesome_5 %}
|
|
||||||
<div id="deadlines" class="card">
|
|
||||||
<div class="card-header rlp-r">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<h5>
|
|
||||||
<span class="badge badge-light">{{obj.deadlines.count}}</span>
|
|
||||||
{% trans 'Deadlines' %}
|
|
||||||
</h5>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<div class="d-flex justify-content-end">
|
|
||||||
{% if is_default_member and has_access %}
|
|
||||||
<button class="btn btn-outline-default btn-modal" data-form-url="{% url 'ema:new-deadline' obj.id %}" title="{% trans 'Add new deadline' %}">
|
|
||||||
{% fa5_icon 'plus' %}
|
|
||||||
{% fa5_icon 'calendar-check' %}
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-body scroll-300">
|
|
||||||
<table class="table table-hover">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th scope="col">
|
|
||||||
{% trans 'Type' %}
|
|
||||||
</th>
|
|
||||||
<th scope="col">
|
|
||||||
{% trans 'Date' %}
|
|
||||||
</th>
|
|
||||||
<th scope="col">
|
|
||||||
{% trans 'Comment' %}
|
|
||||||
</th>
|
|
||||||
<th scope="col">
|
|
||||||
{% trans 'Action' %}
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for deadline in obj.deadlines.all %}
|
|
||||||
<tr>
|
|
||||||
<td class="align-middle">
|
|
||||||
{% trans deadline.type_humanized %}
|
|
||||||
</td>
|
|
||||||
<td class="align-middle">{{ deadline.date }}</td>
|
|
||||||
<td class="align-middle">{{ deadline.comment }}</td>
|
|
||||||
<td>
|
|
||||||
{% if is_default_member and has_access %}
|
|
||||||
<button data-form-url="{% url 'deadline-remove' deadline.id %}" class="btn btn-default btn-modal" title="{% trans 'Remove deadline' %}">
|
|
||||||
{% fa5_icon 'trash' %}
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,59 +0,0 @@
|
|||||||
{% load i18n l10n fontawesome_5 %}
|
|
||||||
<div id="documents" class="card">
|
|
||||||
<div class="card-header rlp-r">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<h5>
|
|
||||||
<span class="badge badge-light">{{obj.documents.count}}</span>
|
|
||||||
{% trans 'Documents' %}
|
|
||||||
</h5>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<div class="d-flex justify-content-end">
|
|
||||||
{% if is_default_member and has_access %}
|
|
||||||
<button class="btn btn-outline-default btn-modal" data-form-url="{% url 'ema:new-doc' obj.id %}" title="{% trans 'Add new document' %}">
|
|
||||||
{% fa5_icon 'plus' %}
|
|
||||||
{% fa5_icon 'file' %}
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-body scroll-300">
|
|
||||||
<table class="table table-hover">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th scope="col">
|
|
||||||
{% trans 'Title' %}
|
|
||||||
</th>
|
|
||||||
<th scope="col">
|
|
||||||
{% trans 'Comment' %}
|
|
||||||
</th>
|
|
||||||
<th scope="col">
|
|
||||||
{% trans 'Action' %}
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for doc in obj.documents.all %}
|
|
||||||
<tr>
|
|
||||||
<td class="align-middle">
|
|
||||||
<a href="{% url 'doc-open' doc.id %}">
|
|
||||||
{{ doc.title }}
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td class="align-middle">{{ doc.comment }}</td>
|
|
||||||
<td>
|
|
||||||
{% if is_default_member and has_access %}
|
|
||||||
<button data-form-url="{% url 'doc-remove' doc.id %}" class="btn btn-default btn-modal" title="{% trans 'Remove document' %}">
|
|
||||||
{% fa5_icon 'trash' %}
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,62 +0,0 @@
|
|||||||
{% load i18n l10n fontawesome_5 %}
|
|
||||||
<div id="states-after" class="card">
|
|
||||||
<div class="card-header rlp-r">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<h5>
|
|
||||||
<span class="badge badge-light">{{obj.after_states.count}}</span>
|
|
||||||
{% trans 'States after' %}
|
|
||||||
</h5>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<div class="d-flex justify-content-end">
|
|
||||||
{% if is_default_member and has_access %}
|
|
||||||
<button class="btn btn-outline-default btn-modal" data-form-url="{% url 'ema:new-state' obj.id %}" title="{% trans 'Add new state after' %}">
|
|
||||||
{% fa5_icon 'plus' %}
|
|
||||||
{% fa5_icon 'layer-group' %}
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-body scroll-300">
|
|
||||||
{% if sum_before_states > sum_after_states %}
|
|
||||||
<div class="row alert alert-danger">
|
|
||||||
{% trans 'Missing surfaces according to states before: ' %}{{ diff_states|floatformat:2 }} m²
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
<table class="table table-hover">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th scope="col">
|
|
||||||
{% trans 'Biotope type' %}
|
|
||||||
</th>
|
|
||||||
<th scope="col">
|
|
||||||
{% trans 'Surface' %}
|
|
||||||
</th>
|
|
||||||
<th scope="col">
|
|
||||||
{% trans 'Action' %}
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for state in after_states %}
|
|
||||||
<tr>
|
|
||||||
<td class="align-middle">
|
|
||||||
{{ state.biotope_type }}
|
|
||||||
</td>
|
|
||||||
<td class="align-middle">{{ state.surface|floatformat:2 }} m²</td>
|
|
||||||
<td>
|
|
||||||
{% if is_default_member and has_access %}
|
|
||||||
<button data-form-url="{% url 'ema:state-remove' state.id %}" class="btn btn-default btn-modal" title="{% trans 'Remove state' %}">
|
|
||||||
{% fa5_icon 'trash' %}
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,62 +0,0 @@
|
|||||||
{% load i18n l10n fontawesome_5 %}
|
|
||||||
<div id="states-before" class="card">
|
|
||||||
<div class="card-header rlp-r">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<h5>
|
|
||||||
<span class="badge badge-light">{{obj.before_states.count}}</span>
|
|
||||||
{% trans 'States before' %}
|
|
||||||
</h5>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<div class="d-flex justify-content-end">
|
|
||||||
{% if is_default_member and has_access %}
|
|
||||||
<button class="btn btn-outline-default btn-modal" data-form-url="{% url 'ema:new-state' obj.id %}?before=true" title="{% trans 'Add new state before' %}">
|
|
||||||
{% fa5_icon 'plus' %}
|
|
||||||
{% fa5_icon 'layer-group' %}
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card-body scroll-300">
|
|
||||||
{% if sum_before_states < sum_after_states %}
|
|
||||||
<div class="row alert alert-danger">
|
|
||||||
{% trans 'Missing surfaces according to states after: ' %}{{ diff_states|floatformat:2 }} m²
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
<table class="table table-hover">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th scope="col">
|
|
||||||
{% trans 'Biotope type' %}
|
|
||||||
</th>
|
|
||||||
<th scope="col">
|
|
||||||
{% trans 'Surface' %}
|
|
||||||
</th>
|
|
||||||
<th scope="col">
|
|
||||||
{% trans 'Action' %}
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for state in before_states %}
|
|
||||||
<tr>
|
|
||||||
<td class="align-middle">
|
|
||||||
{{ state.biotope_type }}
|
|
||||||
</td>
|
|
||||||
<td class="align-middle">{{ state.surface|floatformat:2 }} m²</td>
|
|
||||||
<td>
|
|
||||||
{% if is_default_member and has_access %}
|
|
||||||
<button data-form-url="{% url 'ema:state-remove' state.id %}" class="btn btn-default btn-modal" title="{% trans 'Remove state' %}">
|
|
||||||
{% fa5_icon 'trash' %}
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,100 +0,0 @@
|
|||||||
{% extends 'base.html' %}
|
|
||||||
{% load i18n l10n static fontawesome_5 humanize %}
|
|
||||||
|
|
||||||
{% block head %}
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block body %}
|
|
||||||
|
|
||||||
<div id="detail-header" class="row">
|
|
||||||
<div class="col-sm-12 col-md-12 col-lg-6">
|
|
||||||
<h3>{{obj.identifier}}</h3>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-12 col-md-12 col-lg-6">
|
|
||||||
{% include 'ema/detail/includes/controls.html' %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
<div id="data" class="row">
|
|
||||||
<div class="col-sm-12 col-md-12 col-lg-6">
|
|
||||||
<div class="table-container">
|
|
||||||
<table class="table table-hover">
|
|
||||||
<tr>
|
|
||||||
<th class="w-25" scope="row">{% trans 'Title' %}</th>
|
|
||||||
<td class="align-middle">{{obj.title}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans 'Recorded' %}</th>
|
|
||||||
<td class="align-middle">
|
|
||||||
{% if obj.recorded is None %}
|
|
||||||
<span title="{% trans 'Not recorded yet' %}">
|
|
||||||
{% fa5_icon 'bookmark' 'far' %}
|
|
||||||
</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="registered-bookmark" title="{% trans 'Recorded on '%} {{obj.recorded.timestamp}} {% trans 'by' %} {{obj.recorded.user}}">
|
|
||||||
{% fa5_icon 'bookmark' %}
|
|
||||||
</span>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans 'Last modified' %}</th>
|
|
||||||
<td class="align-middle">
|
|
||||||
{% if obj.modified %}
|
|
||||||
{{obj.modified.timestamp|default_if_none:""|naturalday}}
|
|
||||||
<br>
|
|
||||||
{{obj.modified.user.username}}
|
|
||||||
{% else %}
|
|
||||||
{{obj.created.timestamp|default_if_none:""|naturalday}}
|
|
||||||
<br>
|
|
||||||
{{obj.created.user.username}}
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">{% trans 'Shared with' %}</th>
|
|
||||||
<td class="align-middle">
|
|
||||||
{% for user in obj.users.all %}
|
|
||||||
{% include 'user/includes/contact_modal_button.html' %}
|
|
||||||
{% endfor %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-12 col-md-12 col-lg-6">
|
|
||||||
{% include 'map/geom_form.html' %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-12 col-md-12 col-lg-6">
|
|
||||||
{% include 'ema/detail/includes/states-before.html' %}
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-12 col-md-12 col-lg-6">
|
|
||||||
{% include 'ema/detail/includes/states-after.html' %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-12 col-md-12 col-lg-6">
|
|
||||||
{% include 'ema/detail/includes/actions.html' %}
|
|
||||||
</div>
|
|
||||||
<div class="col-sm-12 col-md-12 col-lg-6">
|
|
||||||
{% include 'ema/detail/includes/deadlines.html' %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-12 col-md-12 col-lg-6">
|
|
||||||
{% include 'ema/detail/includes/documents.html' %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
{% with 'btn-modal' as btn_class %}
|
|
||||||
{% include 'modal/modal_form_script.html' %}
|
|
||||||
{% endwith %}
|
|
||||||
|
|
||||||
{% endblock %}
|
|
@ -1,3 +0,0 @@
|
|||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
# Create your tests here.
|
|
33
ema/urls.py
33
ema/urls.py
@ -1,33 +0,0 @@
|
|||||||
"""
|
|
||||||
Author: Michel Peltriaux
|
|
||||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
|
|
||||||
Contact: michel.peltriaux@sgdnord.rlp.de
|
|
||||||
Created on: 19.08.21
|
|
||||||
|
|
||||||
"""
|
|
||||||
from django.urls import path
|
|
||||||
from ema.views import *
|
|
||||||
|
|
||||||
app_name = "ema"
|
|
||||||
urlpatterns = [
|
|
||||||
path("", index_view, name="index"),
|
|
||||||
path("new/", new_view, name="new"),
|
|
||||||
path("<id>", open_view, name="open"),
|
|
||||||
path('<id>/log', log_view, name='log'),
|
|
||||||
path('<id>/edit', edit_view, name='edit'),
|
|
||||||
path('<id>/remove', remove_view, name='remove'),
|
|
||||||
path('<id>/record', record_view, name='record'),
|
|
||||||
path('<id>/state/new', state_new_view, name='new-state'),
|
|
||||||
path('<id>/action/new', action_new_view, name='new-action'),
|
|
||||||
path('<id>/deadline/new', deadline_new_view, name="new-deadline"),
|
|
||||||
|
|
||||||
# Documents
|
|
||||||
# Document remove route can be found in konova/urls.py
|
|
||||||
path('<id>/document/new/', document_new_view, name='new-doc'),
|
|
||||||
|
|
||||||
# Generic state routes
|
|
||||||
path('state/<id>/remove', state_remove_view, name='state-remove'),
|
|
||||||
|
|
||||||
# Generic action routes
|
|
||||||
path('action/<id>/remove', action_remove_view, name='action-remove'),
|
|
||||||
]
|
|
285
ema/views.py
285
ema/views.py
@ -1,285 +0,0 @@
|
|||||||
from django.contrib.auth.decorators import login_required
|
|
||||||
from django.db.models import Sum
|
|
||||||
from django.http import HttpRequest
|
|
||||||
from django.shortcuts import render, get_object_or_404
|
|
||||||
from django.urls import reverse
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
|
||||||
|
|
||||||
import compensation
|
|
||||||
from compensation.forms import NewStateModalForm, NewActionModalForm, NewDeadlineModalForm
|
|
||||||
from ema.tables import EmaTable
|
|
||||||
from konova.contexts import BaseContext
|
|
||||||
from konova.decorators import conservation_office_group_required
|
|
||||||
from ema.models import Ema
|
|
||||||
from konova.forms import RemoveModalForm, NewDocumentForm, SimpleGeomForm, RecordForm
|
|
||||||
from konova.settings import DEFAULT_GROUP, ZB_GROUP, ETS_GROUP
|
|
||||||
from konova.utils.user_checks import in_group
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
def index_view(request: HttpRequest):
|
|
||||||
""" Renders the index view for EMAs
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
template = "generic_index.html"
|
|
||||||
emas = Ema.objects.filter(
|
|
||||||
deleted=None,
|
|
||||||
).order_by(
|
|
||||||
"-modified"
|
|
||||||
)
|
|
||||||
table = EmaTable(
|
|
||||||
request,
|
|
||||||
queryset=emas
|
|
||||||
)
|
|
||||||
context = {
|
|
||||||
"table": table,
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, template, context)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
@conservation_office_group_required
|
|
||||||
def new_view(request: HttpRequest):
|
|
||||||
""" Renders the form for a new EMA
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
template = "generic_index.html"
|
|
||||||
context = {}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, template, context)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
def open_view(request: HttpRequest, id: str):
|
|
||||||
""" Renders the detail view of an EMA
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The EMA id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
template = "ema/detail/view.html"
|
|
||||||
ema = get_object_or_404(Ema, id=id, deleted=None)
|
|
||||||
|
|
||||||
geom_form = SimpleGeomForm(instance=ema)
|
|
||||||
_user = request.user
|
|
||||||
is_data_shared = ema.is_shared_with(_user)
|
|
||||||
|
|
||||||
# Order states according to surface
|
|
||||||
before_states = ema.before_states.all().order_by("-surface")
|
|
||||||
after_states = ema.after_states.all().order_by("-surface")
|
|
||||||
|
|
||||||
# Precalculate logical errors between before- and after-states
|
|
||||||
# Sum() returns None in case of no states, so we catch that and replace it with 0 for easier handling
|
|
||||||
sum_before_states = before_states.aggregate(Sum("surface"))["surface__sum"] or 0
|
|
||||||
sum_after_states = after_states.aggregate(Sum("surface"))["surface__sum"] or 0
|
|
||||||
diff_states = abs(sum_before_states - sum_after_states)
|
|
||||||
|
|
||||||
context = {
|
|
||||||
"obj": ema,
|
|
||||||
"geom_form": geom_form,
|
|
||||||
"has_access": is_data_shared,
|
|
||||||
"before_states": before_states,
|
|
||||||
"after_states": after_states,
|
|
||||||
"sum_before_states": sum_before_states,
|
|
||||||
"sum_after_states": sum_after_states,
|
|
||||||
"diff_states": diff_states,
|
|
||||||
"is_default_member": in_group(_user, DEFAULT_GROUP),
|
|
||||||
"is_zb_member": in_group(_user, ZB_GROUP),
|
|
||||||
"is_ets_member": in_group(_user, ETS_GROUP),
|
|
||||||
"LANIS_LINK": ema.get_LANIS_link(),
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, template, context)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
def log_view(request: HttpRequest, id: str):
|
|
||||||
""" Renders a log view using modal
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The EMA's id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
ema = get_object_or_404(Ema, id=id)
|
|
||||||
template = "modal/modal_generic.html"
|
|
||||||
body_template = "log.html"
|
|
||||||
|
|
||||||
context = {
|
|
||||||
"modal_body_template": body_template,
|
|
||||||
"log": ema.log.all(),
|
|
||||||
"modal_title": _("Log"),
|
|
||||||
}
|
|
||||||
context = BaseContext(request, context).context
|
|
||||||
return render(request, template, context)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
def edit_view(request: HttpRequest, id: str):
|
|
||||||
get_object_or_404(Ema, id=id)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
def remove_view(request: HttpRequest, id: str):
|
|
||||||
""" Renders a modal view for removing the EMA
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The EMA's id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
ema = get_object_or_404(Ema, id=id)
|
|
||||||
form = RemoveModalForm(request.POST or None, instance=ema, user=request.user)
|
|
||||||
return form.process_request(
|
|
||||||
request=request,
|
|
||||||
msg_success=_("EMA removed"),
|
|
||||||
redirect_url=reverse("ema:index"),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
def record_view(request: HttpRequest, id: str):
|
|
||||||
""" Renders a modal view for recording the EMA
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The EMA's id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
ema = get_object_or_404(Ema, id=id)
|
|
||||||
form = RecordForm(request.POST or None, instance=ema, user=request.user)
|
|
||||||
return form.process_request(
|
|
||||||
request=request,
|
|
||||||
msg_success=_("EMA recorded"),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
def state_new_view(request: HttpRequest, id: str):
|
|
||||||
""" Renders a form for adding new states for an EMA
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The EMA's id to which the new state will be related
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
ema = get_object_or_404(Ema, id=id)
|
|
||||||
form = NewStateModalForm(request.POST or None, instance=ema, user=request.user)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
msg_success=_("State added")
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
def action_new_view(request: HttpRequest, id: str):
|
|
||||||
""" Renders a form for adding new actions for an EMA
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The EMA's id to which the new state will be related
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
ema = get_object_or_404(Ema, id=id)
|
|
||||||
form = NewActionModalForm(request.POST or None, instance=ema, user=request.user)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
msg_success=_("Action added")
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
def deadline_new_view(request: HttpRequest, id: str):
|
|
||||||
""" Renders a form for adding new states for an EMA
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The EMA's id to which the new state will be related
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
ema = get_object_or_404(Ema, id=id)
|
|
||||||
form = NewDeadlineModalForm(request.POST or None, instance=ema, user=request.user)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
msg_success=_("Deadline added")
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
def document_new_view(request: HttpRequest, id: str):
|
|
||||||
""" Renders a form for uploading new documents
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The EMA's id to which the new document will be related
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
ema = get_object_or_404(Ema, id=id)
|
|
||||||
form = NewDocumentForm(request.POST or None, request.FILES or None, instance=ema, user=request.user)
|
|
||||||
return form.process_request(
|
|
||||||
request,
|
|
||||||
msg_success=_("Document added")
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
def state_remove_view(request: HttpRequest, id: str):
|
|
||||||
""" Renders a form for removing an EMA state
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The state's id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
return compensation.views.compensation_views.state_remove_view(
|
|
||||||
request,
|
|
||||||
id
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
|
||||||
def action_remove_view(request: HttpRequest, id: str):
|
|
||||||
""" Renders a form for removing an EMA state
|
|
||||||
|
|
||||||
Args:
|
|
||||||
request (HttpRequest): The incoming request
|
|
||||||
id (str): The state's id
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
|
|
||||||
"""
|
|
||||||
# Reuses the route logic from compensation view
|
|
||||||
return compensation.views.compensation_views.action_remove_view(
|
|
||||||
request,
|
|
||||||
id
|
|
||||||
)
|
|
||||||
|
|
@ -203,8 +203,6 @@ class EditInterventionForm(NewInterventionForm):
|
|||||||
action=UserAction.EDITED
|
action=UserAction.EDITED
|
||||||
)
|
)
|
||||||
self.instance.log.add(user_action)
|
self.instance.log.add(user_action)
|
||||||
self.instance.modified = user_action
|
|
||||||
self.instance.save()
|
|
||||||
|
|
||||||
return self.instance
|
return self.instance
|
||||||
|
|
||||||
@ -383,8 +381,6 @@ class NewRevocationForm(BaseModalForm):
|
|||||||
document=document,
|
document=document,
|
||||||
created=created_action,
|
created=created_action,
|
||||||
)
|
)
|
||||||
self.instance.modified = edited_action
|
|
||||||
self.instance.save()
|
|
||||||
self.instance.log.add(edited_action)
|
self.instance.log.add(edited_action)
|
||||||
self.instance.legal.revocation = revocation
|
self.instance.legal.revocation = revocation
|
||||||
self.instance.legal.save()
|
self.instance.legal.save()
|
||||||
@ -557,8 +553,6 @@ class NewWithdrawForm(BaseModalForm):
|
|||||||
action=UserAction.CREATED
|
action=UserAction.CREATED
|
||||||
)
|
)
|
||||||
self.instance.log.add(user_action_edit)
|
self.instance.log.add(user_action_edit)
|
||||||
self.instance.modified = user_action_edit
|
|
||||||
self.instance.save()
|
|
||||||
|
|
||||||
# Create withdraw depending on Intervention or EcoAccount as the initial instance
|
# Create withdraw depending on Intervention or EcoAccount as the initial instance
|
||||||
if self.is_intervention_initially:
|
if self.is_intervention_initially:
|
||||||
|
@ -21,9 +21,9 @@ class ResponsibilityData(UuidModel):
|
|||||||
Holds intervention data about responsible organizations and their file numbers for this case
|
Holds intervention data about responsible organizations and their file numbers for this case
|
||||||
|
|
||||||
"""
|
"""
|
||||||
registration_office = models.ForeignKey(Organisation, on_delete=models.SET_NULL, null=True, related_name="+", blank=True)
|
registration_office = models.ForeignKey(Organisation, on_delete=models.SET_NULL, null=True, related_name="+")
|
||||||
registration_file_number = models.CharField(max_length=1000, blank=True, null=True)
|
registration_file_number = models.CharField(max_length=1000, blank=True, null=True)
|
||||||
conservation_office = models.ForeignKey(Organisation, on_delete=models.SET_NULL, null=True, related_name="+", blank=True)
|
conservation_office = models.ForeignKey(Organisation, on_delete=models.SET_NULL, null=True, related_name="+")
|
||||||
conservation_file_number = models.CharField(max_length=1000, blank=True, null=True)
|
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'")
|
handler = models.CharField(max_length=500, null=True, blank=True, help_text="Refers to 'Eingriffsverursacher'")
|
||||||
|
|
||||||
@ -115,6 +115,9 @@ class Intervention(BaseObject):
|
|||||||
related_name="+"
|
related_name="+"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Holds which intervention is simply a newer version of this dataset
|
||||||
|
next_version = models.ForeignKey("Intervention", null=True, blank=True, on_delete=models.DO_NOTHING)
|
||||||
|
|
||||||
# Users having access on this object
|
# Users having access on this object
|
||||||
users = models.ManyToManyField(User, help_text="Users having access (data shared with)")
|
users = models.ManyToManyField(User, help_text="Users having access (data shared with)")
|
||||||
access_token = models.CharField(
|
access_token = models.CharField(
|
||||||
@ -174,7 +177,7 @@ class Intervention(BaseObject):
|
|||||||
""" Quality check
|
""" Quality check
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
ret_msgs (list): Holds error messages
|
ret_msgs (list): True if quality acceptable, False otherwise
|
||||||
"""
|
"""
|
||||||
ret_msgs = []
|
ret_msgs = []
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ class InterventionTable(BaseTable):
|
|||||||
lm = tables.Column(
|
lm = tables.Column(
|
||||||
verbose_name=_("Last edit"),
|
verbose_name=_("Last edit"),
|
||||||
orderable=True,
|
orderable=True,
|
||||||
accessor="modified__timestamp",
|
accessor="created__timestamp",
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
# ToDo: Decide to keep actions column or to dismiss them
|
# ToDo: Decide to keep actions column or to dismiss them
|
||||||
@ -164,3 +164,23 @@ class InterventionTable(BaseTable):
|
|||||||
icn_class="fas fa-edit rlp-r-inv" if has_access else "far fa-edit",
|
icn_class="fas fa-edit rlp-r-inv" if has_access else "far fa-edit",
|
||||||
)
|
)
|
||||||
return format_html(html)
|
return format_html(html)
|
||||||
|
|
||||||
|
def render_ac(self, value, record):
|
||||||
|
"""
|
||||||
|
Renders possible actions for this record, such as delete.
|
||||||
|
"""
|
||||||
|
intervention = _("Intervention")
|
||||||
|
html = ""
|
||||||
|
html += self.render_open_btn(
|
||||||
|
_("Open {}").format(intervention),
|
||||||
|
reverse("intervention:open", args=(record.id,))
|
||||||
|
)
|
||||||
|
html += self.render_edit_btn(
|
||||||
|
_("Edit {}").format(intervention),
|
||||||
|
reverse("intervention:edit", args=(record.id,)),
|
||||||
|
)
|
||||||
|
html += self.render_delete_btn(
|
||||||
|
_("Delete {}").format(intervention),
|
||||||
|
reverse("intervention:remove", args=(record.id,)),
|
||||||
|
)
|
||||||
|
return format_html(html)
|
||||||
|
@ -94,7 +94,7 @@
|
|||||||
<th scope="row">{% trans 'Binding on' %}</th>
|
<th scope="row">{% trans 'Binding on' %}</th>
|
||||||
<td class="align-middle">{{intervention.legal.binding_date|default_if_none:""}}</td>
|
<td class="align-middle">{{intervention.legal.binding_date|default_if_none:""}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr {% if intervention.legal.revocation %}class="alert alert-danger" title="{% trans 'Exists' %}" {% endif %}>
|
<tr {% if intervention.legal.revocation %}class="alert alert-danger" title="{% trans 'Missing' %}" {% endif %}>
|
||||||
<th scope="row">{% trans 'Revocation' %}</th>
|
<th scope="row">{% trans 'Revocation' %}</th>
|
||||||
<td class="align-middle">{{intervention.legal.revocation.date|naturalday|default_if_none:""}}</td>
|
<td class="align-middle">{{intervention.legal.revocation.date|naturalday|default_if_none:""}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -33,6 +33,9 @@ def index_view(request: HttpRequest):
|
|||||||
# Filtering by user access is performed in table filter inside of InterventionTableFilter class
|
# Filtering by user access is performed in table filter inside of InterventionTableFilter class
|
||||||
interventions = Intervention.objects.filter(
|
interventions = Intervention.objects.filter(
|
||||||
deleted=None, # not deleted
|
deleted=None, # not deleted
|
||||||
|
next_version=None, # only newest versions
|
||||||
|
).order_by(
|
||||||
|
"-created__timestamp"
|
||||||
)
|
)
|
||||||
table = InterventionTable(
|
table = InterventionTable(
|
||||||
request=request,
|
request=request,
|
||||||
@ -270,10 +273,22 @@ def create_share_view(request: HttpRequest, id: str):
|
|||||||
"""
|
"""
|
||||||
intervention = get_object_or_404(Intervention, id=id)
|
intervention = get_object_or_404(Intervention, id=id)
|
||||||
form = ShareInterventionForm(request.POST or None, instance=intervention, request=request)
|
form = ShareInterventionForm(request.POST or None, instance=intervention, request=request)
|
||||||
return form.process_request(
|
if request.method == "POST":
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
messages.info(
|
||||||
request,
|
request,
|
||||||
msg_success=_("Share settings updated")
|
_("Share settings updated")
|
||||||
)
|
)
|
||||||
|
return redirect(request.META.get("HTTP_REFERER", "home"))
|
||||||
|
elif request.method == "GET":
|
||||||
|
context = {
|
||||||
|
"form": form,
|
||||||
|
}
|
||||||
|
context = BaseContext(request, context).context
|
||||||
|
return render(request, form.template, context)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@ -309,10 +324,28 @@ def new_revocation_view(request: HttpRequest, id: str):
|
|||||||
"""
|
"""
|
||||||
intervention = get_object_or_404(Intervention, id=id)
|
intervention = get_object_or_404(Intervention, id=id)
|
||||||
form = NewRevocationForm(request.POST or None, request.FILES or None, instance=intervention, user=request.user)
|
form = NewRevocationForm(request.POST or None, request.FILES or None, instance=intervention, user=request.user)
|
||||||
return form.process_request(
|
if request.method == "POST":
|
||||||
|
if form.is_valid():
|
||||||
|
form.save()
|
||||||
|
messages.info(
|
||||||
request,
|
request,
|
||||||
msg_success=_("Revocation added")
|
_("Revocation added")
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
messages.error(
|
||||||
|
request,
|
||||||
|
FORM_INVALID,
|
||||||
|
extra_tags="danger",
|
||||||
|
)
|
||||||
|
return redirect(request.META.get("HTTP_REFERER", "home"))
|
||||||
|
elif request.method == "GET":
|
||||||
|
context = {
|
||||||
|
"form": form,
|
||||||
|
}
|
||||||
|
context = BaseContext(request, context).context
|
||||||
|
return render(request, form.template, context)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@ -332,7 +365,7 @@ def log_view(request: HttpRequest, id: str):
|
|||||||
|
|
||||||
context = {
|
context = {
|
||||||
"modal_body_template": body_template,
|
"modal_body_template": body_template,
|
||||||
"log": intervention.log.all(),
|
"log": intervention.log.all().order_by("-timestamp"),
|
||||||
"modal_title": _("Log"),
|
"modal_title": _("Log"),
|
||||||
}
|
}
|
||||||
context = BaseContext(request, context).context
|
context = BaseContext(request, context).context
|
||||||
|
@ -22,7 +22,6 @@ from django.utils import timezone
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
from compensation.models import EcoAccount
|
from compensation.models import EcoAccount
|
||||||
from ema.models import Ema
|
|
||||||
from intervention.models import Intervention
|
from intervention.models import Intervention
|
||||||
from konova.contexts import BaseContext
|
from konova.contexts import BaseContext
|
||||||
from konova.models import Document, BaseObject
|
from konova.models import Document, BaseObject
|
||||||
@ -46,6 +45,7 @@ class BaseForm(forms.Form):
|
|||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.instance = kwargs.pop("instance", None)
|
self.instance = kwargs.pop("instance", None)
|
||||||
self.user = kwargs.pop("user", None)
|
self.user = kwargs.pop("user", None)
|
||||||
|
self.request = kwargs.pop("request", None)
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
# Check for required fields
|
# Check for required fields
|
||||||
@ -173,10 +173,6 @@ class BaseModalForm(BaseForm, BSModalForm):
|
|||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
if self.is_valid():
|
if self.is_valid():
|
||||||
if not is_ajax(request.META):
|
if not is_ajax(request.META):
|
||||||
# Modal forms send one POST for checking on data validity. This can be used to return possible errors
|
|
||||||
# on the form. A second POST (if no errors occured) is sent afterwards and needs to process the
|
|
||||||
# saving/commiting of the data to the database. is_ajax() performs this check. The first request is
|
|
||||||
# an ajax call, the second is a regular form POST.
|
|
||||||
self.save()
|
self.save()
|
||||||
messages.success(
|
messages.success(
|
||||||
request,
|
request,
|
||||||
@ -341,8 +337,6 @@ class NewDocumentForm(BaseModalForm):
|
|||||||
comment=_("Added document"),
|
comment=_("Added document"),
|
||||||
)
|
)
|
||||||
self.instance.log.add(edited_action)
|
self.instance.log.add(edited_action)
|
||||||
self.instance.modified = edited_action
|
|
||||||
self.instance.save()
|
|
||||||
|
|
||||||
return doc
|
return doc
|
||||||
|
|
||||||
@ -371,8 +365,7 @@ class RecordForm(BaseModalForm):
|
|||||||
|
|
||||||
implemented_cls_logic = {
|
implemented_cls_logic = {
|
||||||
Intervention,
|
Intervention,
|
||||||
EcoAccount,
|
EcoAccount
|
||||||
Ema,
|
|
||||||
}
|
}
|
||||||
instance_name = self.instance.__class__
|
instance_name = self.instance.__class__
|
||||||
if instance_name not in implemented_cls_logic:
|
if instance_name not in implemented_cls_logic:
|
||||||
|
@ -16,7 +16,6 @@ from django.db import models, transaction
|
|||||||
|
|
||||||
from compensation.settings import COMPENSATION_IDENTIFIER_TEMPLATE, COMPENSATION_IDENTIFIER_LENGTH, \
|
from compensation.settings import COMPENSATION_IDENTIFIER_TEMPLATE, COMPENSATION_IDENTIFIER_LENGTH, \
|
||||||
ECO_ACCOUNT_IDENTIFIER_TEMPLATE, ECO_ACCOUNT_IDENTIFIER_LENGTH
|
ECO_ACCOUNT_IDENTIFIER_TEMPLATE, ECO_ACCOUNT_IDENTIFIER_LENGTH
|
||||||
from ema.settings import EMA_ACCOUNT_IDENTIFIER_LENGTH, EMA_ACCOUNT_IDENTIFIER_TEMPLATE
|
|
||||||
from intervention.settings import INTERVENTION_IDENTIFIER_LENGTH, INTERVENTION_IDENTIFIER_TEMPLATE
|
from intervention.settings import INTERVENTION_IDENTIFIER_LENGTH, INTERVENTION_IDENTIFIER_TEMPLATE
|
||||||
from konova.utils.generators import generate_random_string
|
from konova.utils.generators import generate_random_string
|
||||||
from user.models import UserActionLogEntry, UserAction
|
from user.models import UserActionLogEntry, UserAction
|
||||||
@ -40,21 +39,7 @@ class BaseResource(UuidModel):
|
|||||||
"""
|
"""
|
||||||
A basic resource model, which defines attributes for every derived model
|
A basic resource model, which defines attributes for every derived model
|
||||||
"""
|
"""
|
||||||
created = models.ForeignKey(
|
created = models.ForeignKey(UserActionLogEntry, on_delete=models.SET_NULL, null=True, blank=True, related_name='+')
|
||||||
UserActionLogEntry,
|
|
||||||
on_delete=models.SET_NULL,
|
|
||||||
null=True,
|
|
||||||
blank=True,
|
|
||||||
related_name='+'
|
|
||||||
)
|
|
||||||
modified = models.ForeignKey(
|
|
||||||
UserActionLogEntry,
|
|
||||||
on_delete=models.SET_NULL,
|
|
||||||
null=True,
|
|
||||||
blank=True,
|
|
||||||
related_name='+',
|
|
||||||
help_text="Last modified"
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
@ -146,8 +131,6 @@ class BaseObject(BaseResource):
|
|||||||
"""
|
"""
|
||||||
from compensation.models import Compensation, EcoAccount
|
from compensation.models import Compensation, EcoAccount
|
||||||
from intervention.models import Intervention
|
from intervention.models import Intervention
|
||||||
from ema.models import Ema
|
|
||||||
|
|
||||||
definitions = {
|
definitions = {
|
||||||
Intervention: {
|
Intervention: {
|
||||||
"length": INTERVENTION_IDENTIFIER_LENGTH,
|
"length": INTERVENTION_IDENTIFIER_LENGTH,
|
||||||
@ -161,10 +144,6 @@ class BaseObject(BaseResource):
|
|||||||
"length": ECO_ACCOUNT_IDENTIFIER_LENGTH,
|
"length": ECO_ACCOUNT_IDENTIFIER_LENGTH,
|
||||||
"template": ECO_ACCOUNT_IDENTIFIER_TEMPLATE,
|
"template": ECO_ACCOUNT_IDENTIFIER_TEMPLATE,
|
||||||
},
|
},
|
||||||
Ema: {
|
|
||||||
"length": EMA_ACCOUNT_IDENTIFIER_LENGTH,
|
|
||||||
"template": EMA_ACCOUNT_IDENTIFIER_TEMPLATE,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.__class__ not in definitions:
|
if self.__class__ not in definitions:
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB |
@ -68,7 +68,6 @@ INSTALLED_APPS = [
|
|||||||
'organisation',
|
'organisation',
|
||||||
'news',
|
'news',
|
||||||
'user',
|
'user',
|
||||||
'ema',
|
|
||||||
]
|
]
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
INSTALLED_APPS += [
|
INSTALLED_APPS += [
|
||||||
|
@ -31,7 +31,7 @@ urlpatterns = [
|
|||||||
path('', home_view, name="home"),
|
path('', home_view, name="home"),
|
||||||
path('intervention/', include("intervention.urls")),
|
path('intervention/', include("intervention.urls")),
|
||||||
path('compensation/', include("compensation.urls")),
|
path('compensation/', include("compensation.urls")),
|
||||||
path('ema/', include("ema.urls")),
|
path('ema/', include("intervention.urls")), #ToDo
|
||||||
path('organisation/', include("organisation.urls")),
|
path('organisation/', include("organisation.urls")),
|
||||||
path('user/', include("user.urls")),
|
path('user/', include("user.urls")),
|
||||||
path('news/', include("news.urls")),
|
path('news/', include("news.urls")),
|
||||||
|
@ -24,11 +24,10 @@ class BaseTable(tables.tables.Table):
|
|||||||
add_new_entries = True
|
add_new_entries = True
|
||||||
add_new_url = None
|
add_new_url = None
|
||||||
title = None
|
title = None
|
||||||
subtitle = ""
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
attrs = {
|
attrs = {
|
||||||
"class": "table table-hover table-responsive-md table-responsive-sm",
|
"class": "table table-hover",
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, request: HttpRequest = None, filter_set=None, queryset=None, *args, **kwargs):
|
def __init__(self, request: HttpRequest = None, filter_set=None, queryset=None, *args, **kwargs):
|
||||||
|
@ -64,6 +64,7 @@ def home_view(request: HttpRequest):
|
|||||||
# First fetch all valid objects (undeleted, only newest versions)
|
# First fetch all valid objects (undeleted, only newest versions)
|
||||||
interventions = Intervention.objects.filter(
|
interventions = Intervention.objects.filter(
|
||||||
deleted=None,
|
deleted=None,
|
||||||
|
next_version=None,
|
||||||
)
|
)
|
||||||
# Then fetch only user related ones
|
# Then fetch only user related ones
|
||||||
user_interventions = interventions.filter(
|
user_interventions = interventions.filter(
|
||||||
@ -73,12 +74,14 @@ def home_view(request: HttpRequest):
|
|||||||
# Repeat for other objects
|
# Repeat for other objects
|
||||||
comps = Compensation.objects.filter(
|
comps = Compensation.objects.filter(
|
||||||
deleted=None,
|
deleted=None,
|
||||||
|
next_version=None,
|
||||||
)
|
)
|
||||||
user_comps = comps.filter(
|
user_comps = comps.filter(
|
||||||
intervention__users__in=[user]
|
intervention__users__in=[user]
|
||||||
)
|
)
|
||||||
eco_accs = EcoAccount.objects.filter(
|
eco_accs = EcoAccount.objects.filter(
|
||||||
deleted=None,
|
deleted=None,
|
||||||
|
next_version=None,
|
||||||
)
|
)
|
||||||
user_ecco_accs = eco_accs.filter(
|
user_ecco_accs = eco_accs.filter(
|
||||||
users__in=[user]
|
users__in=[user]
|
||||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -3,9 +3,7 @@
|
|||||||
<html lang="{{ language }}">
|
<html lang="{{ language }}">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<title>{{ base_title }}</title>
|
||||||
<title>{{ base_frontend_title }}</title>
|
|
||||||
<link rel="icon" type="image/ico" href="{% static 'images/ksp-favicon.ico' %}">
|
|
||||||
{% bootstrap_css %}
|
{% bootstrap_css %}
|
||||||
{% bootstrap_javascript jquery='full' %}
|
{% bootstrap_javascript jquery='full' %}
|
||||||
{% fontawesome_5_static %}
|
{% fontawesome_5_static %}
|
||||||
|
@ -5,21 +5,12 @@
|
|||||||
|
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<div class="col-md">
|
<div class="col-md">
|
||||||
{% if table.title %}
|
{% if table.title is not None %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<h3>
|
<h3>
|
||||||
{{ table.title }}
|
{{ table.title }}
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
{% if table.subtitle %}
|
|
||||||
<div class="row mb-2">
|
|
||||||
<div class="col-lg">
|
|
||||||
<small>
|
|
||||||
{{ table.subtitle }}
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{% if table.add_new_entries %}
|
{% if table.add_new_entries %}
|
||||||
|
@ -34,13 +34,13 @@
|
|||||||
{% trans 'Eco-account' %}
|
{% trans 'Eco-account' %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class=" menu-elem dropdown">
|
<li class=" menu-elem dropdown" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
|
||||||
<div class="btn nav-btn" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
|
<a class="nav-btn nav-link">
|
||||||
{% fa5_icon 'ellipsis-v' %}
|
{% fa5_icon 'ellipsis-v' %}
|
||||||
{% trans 'More' %}
|
{% trans 'More' %}
|
||||||
</div>
|
</a>
|
||||||
<div class="dropdown-menu">
|
<div class="dropdown-menu">
|
||||||
<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 '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-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-export' %} {% trans 'Export...' %}</a>
|
||||||
<a class="dropdown-item" href="{% url 'home' %}">{% fa5_icon 'file-alt' %} {% trans 'Reports' %}</a>
|
<a class="dropdown-item" href="{% url 'home' %}">{% fa5_icon 'file-alt' %} {% trans 'Reports' %}</a>
|
||||||
|
@ -74,11 +74,6 @@ class UserActionLogEntry(models.Model):
|
|||||||
)
|
)
|
||||||
comment = models.CharField(max_length=255, null=True, blank=True, help_text="Additional comment on this entry")
|
comment = models.CharField(max_length=255, null=True, blank=True, help_text="Additional comment on this entry")
|
||||||
|
|
||||||
class Meta:
|
|
||||||
ordering = (
|
|
||||||
"-timestamp",
|
|
||||||
)
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "{} | {} | {}".format(self.user.username, self.timestamp, self.action)
|
return "{} | {} | {}".format(self.user.username, self.timestamp, self.action)
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
{% block body %}
|
{% block body %}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6 col-lg-4 border">
|
<div class="col-md-6 col-lg-4 border">
|
||||||
<table class="table table-responsive">
|
<table class="table">
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">{% trans 'Username' %}</th>
|
<th scope="row">{% trans 'Username' %}</th>
|
||||||
<td>{{user.username}}</td>
|
<td>{{user.username}}</td>
|
||||||
|
Loading…
Reference in New Issue
Block a user