Merge branch 'master' into 132_Old_entries

# Conflicts:
#	compensation/models/action.py
This commit is contained in:
mpeltriaux 2022-11-18 07:42:26 +01:00
commit ef1d1610ac
24 changed files with 377 additions and 130 deletions

View File

@ -17,6 +17,7 @@ from compensation.models import Compensation, Payment, EcoAccountDeduction, EcoA
from intervention.models import Intervention
from konova.models import Geometry
from konova.sub_settings.django_settings import BASE_DIR, DEFAULT_DATE_FORMAT
from konova.sub_settings.lanis_settings import DEFAULT_SRID_RLP
class TimespanReport:
@ -333,7 +334,7 @@ class TimespanReport:
return Geometry.objects.filter(
id__in=ids
).annotate(
geom_cast=Cast("geom", MultiPolygonField())
geom_cast=Cast("geom", MultiPolygonField(srid=DEFAULT_SRID_RLP))
).annotate(
num=NumGeometries("geom_cast")
).aggregate(

View File

@ -81,13 +81,15 @@ class EcoAccountAdmin(AbstractCompensationAdmin):
]
filter_horizontal = [
"users"
"users",
"teams",
]
def get_fields(self, request, obj=None):
return super().get_fields(request, obj) + [
"deductable_surface",
"users"
"users",
"teams",
]

View File

@ -0,0 +1,26 @@
# Generated by Django 3.1.3 on 2022-11-16 12:22
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('user', '0006_auto_20220815_0759'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('compensation', '0011_ecoaccount_deductable_rest'),
]
operations = [
migrations.AlterField(
model_name='ecoaccount',
name='teams',
field=models.ManyToManyField(blank=True, help_text='Teams having access (data shared with)', to='user.Team'),
),
migrations.AlterField(
model_name='ecoaccount',
name='users',
field=models.ManyToManyField(blank=True, help_text='Users having access (data shared with)', to=settings.AUTH_USER_MODEL),
),
]

View File

@ -0,0 +1,35 @@
# Generated by Django 3.1.3 on 2022-11-17 07:19
from django.db import migrations
from compensation.models import UnitChoices
def harmonize_action_units(apps, schema_editor):
"""
CompensationAction units (based on UnitChoices) can be mixed up at this point where
* qm represents and
* m2 represents
We drop qm in support of m2
"""
CompensationAction = apps.get_model("compensation", "CompensationAction")
actions = CompensationAction.objects.filter(
unit="qm"
)
for action in actions:
action.unit = UnitChoices.m2
action.save()
class Migration(migrations.Migration):
dependencies = [
('compensation', '0012_auto_20221116_1322'),
]
operations = [
migrations.RunPython(harmonize_action_units),
]

View File

@ -19,9 +19,9 @@ class UnitChoices(models.TextChoices):
"""
cm = "cm", _("cm")
m = "m", _("m")
km = "km", _("km")
m2 = "m2", _("")
m3 = "m3", _("")
km = "km", _("km")
ha = "ha", _("ha")
st = "pcs", _("Pieces") # pieces

View File

@ -124,7 +124,7 @@
{% endfor %}
<hr>
{% if has_access %}
{% for user in obj.users.all %}
{% for user in obj.intervention.shared_users %}
{% include 'user/includes/contact_modal_button.html' %}
{% endfor %}
{% else %}

View File

@ -6,12 +6,14 @@ from ema.models import Ema
class EmaAdmin(AbstractCompensationAdmin):
filter_horizontal = [
"users"
"users",
"teams",
]
def get_fields(self, request, obj=None):
return super().get_fields(request, obj) + [
"users"
"users",
"teams",
]
admin.site.register(Ema, EmaAdmin)

View File

@ -0,0 +1,26 @@
# Generated by Django 3.1.3 on 2022-11-16 12:22
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('user', '0006_auto_20220815_0759'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('ema', '0007_auto_20220815_1030'),
]
operations = [
migrations.AlterField(
model_name='ema',
name='teams',
field=models.ManyToManyField(blank=True, help_text='Teams having access (data shared with)', to='user.Team'),
),
migrations.AlterField(
model_name='ema',
name='users',
field=models.ManyToManyField(blank=True, help_text='Users having access (data shared with)', to=settings.AUTH_USER_MODEL),
),
]

View File

@ -14,7 +14,8 @@ class InterventionAdmin(BaseObjectAdmin):
]
filter_horizontal = [
"users"
"users",
"teams",
]
def get_fields(self, request, obj=None):
@ -25,6 +26,7 @@ class InterventionAdmin(BaseObjectAdmin):
"checked",
"recorded",
"users",
"teams",
"geometry",
]

View File

@ -11,3 +11,22 @@ from konova.forms.modals import NewDocumentModalForm
class NewInterventionDocumentModalForm(NewDocumentModalForm):
document_model = InterventionDocument
def save(self, *args, **kwargs):
""" Extension of regular NewDocumentModalForm
Checks whether payments exist on the intervention and sends the data to EGON
Args:
*args ():
**kwargs ():
Returns:
"""
doc = super().save(*args, **kwargs)
if self.instance.payments.exists():
self.instance.send_data_to_egon()
return doc

View File

@ -0,0 +1,26 @@
# Generated by Django 3.1.3 on 2022-11-16 12:22
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('user', '0006_auto_20220815_0759'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('intervention', '0007_auto_20220815_1030'),
]
operations = [
migrations.AlterField(
model_name='intervention',
name='teams',
field=models.ManyToManyField(blank=True, help_text='Teams having access (data shared with)', to='user.Team'),
),
migrations.AlterField(
model_name='intervention',
name='users',
field=models.ManyToManyField(blank=True, help_text='Users having access (data shared with)', to=settings.AUTH_USER_MODEL),
),
]

View File

@ -20,6 +20,11 @@
</div>
</div>
</div>
{% if has_payment_without_document %}
<div class="alert alert-danger mb-0">
{% trans 'You entered a payment. Please upload the legal document which defines the payment`s amount.' %}
</div>
{% endif %}
<div class="card-body scroll-300 p-2">
<table class="table table-hover">
<thead>

View File

@ -11,7 +11,7 @@ from django.core.exceptions import ObjectDoesNotExist
from django.urls import reverse
from compensation.models import Payment, EcoAccountDeduction
from intervention.models import Intervention
from intervention.models import Intervention, InterventionDocument
from konova.settings import ETS_GROUP, ZB_GROUP
from konova.tests.test_views import BaseWorkflowTestCase
from user.models import UserActionLogEntry, UserAction
@ -153,13 +153,16 @@ class InterventionWorkflowTestCase(BaseWorkflowTestCase):
payment = Payment.objects.create(amount=10.00, due_on=None, comment="No due date because test")
self.intervention.payments.add(payment)
# Since there is a payment, we need to add a dummy document (mocking a legal document for payment info)
document = self.create_dummy_document(InterventionDocument, self.intervention)
# Run request again
self.client_user.post(check_url, post_data)
# Update intervention from db
self.intervention.refresh_from_db()
# We expect the intervention to be checked now and contains the proper data
# We expect the intervention to be checked now and contain the proper data
# Attention: We check the timestamp only on the date, not the time, since the microseconds delay would result
# in an unwanted assertion error
checked = self.intervention.checked
@ -209,6 +212,9 @@ class InterventionWorkflowTestCase(BaseWorkflowTestCase):
payment = Payment.objects.create(amount=10.00, due_on=None, comment="No due date because test")
self.intervention.payments.add(payment)
# Since there is a payment, we need to add a dummy document (mocking a legal document for payment info)
document = self.create_dummy_document(InterventionDocument, self.intervention)
# Run request again
self.client_user.post(record_url, post_data)

View File

@ -21,8 +21,21 @@ class InterventionQualityChecker(AbstractQualityChecker):
self._check_legal_data()
self._check_compensations()
self._check_geometry()
self._check_payment_documents()
self.valid = len(self.messages) == 0
def _check_payment_documents(self):
""" Checks existence of documents in case of payments
There should be at least one legal document which defines the payment's total amount.
Returns:
"""
has_payment_without_document = self.obj.payments.exists() and not self.obj.get_documents()[1].exists()
if has_payment_without_document:
self._add_missing_attr_name(_("Documents"))
def _check_responsible_data(self):
""" Checks data quality of related Responsibility

View File

@ -157,6 +157,8 @@ def detail_view(request: HttpRequest, id: str):
if last_checked:
last_checked_tooltip = DATA_CHECKED_PREVIOUSLY_TEMPLATE.format(last_checked.get_timestamp_str_formatted(), last_checked.user)
has_payment_without_document = intervention.payments.exists() and not intervention.get_documents()[1].exists()
context = {
"obj": intervention,
"last_checked": last_checked,
@ -168,6 +170,7 @@ def detail_view(request: HttpRequest, id: str):
"is_zb_member": in_group(_user, ZB_GROUP),
"is_ets_member": in_group(_user, ETS_GROUP),
"LANIS_LINK": intervention.get_LANIS_link(),
"has_payment_without_document": has_payment_without_document,
TAB_TITLE_IDENTIFIER: f"{intervention.identifier} - {intervention.title}",
}

View File

@ -46,7 +46,7 @@ class GeoReferencedTableFilterMixin(django_filters.FilterSet):
),
)
# Parcel
p = django_filters.CharFilter(
p = django_filters.NumberFilter(
method="filter_parcel",
label=_(""),
label_suffix=_(""),
@ -59,7 +59,7 @@ class GeoReferencedTableFilterMixin(django_filters.FilterSet):
),
)
# Parcel counter
pc = django_filters.CharFilter(
pc = django_filters.NumberFilter(
method="filter_parcel_counter",
label=_(""),
label_suffix=_(""),
@ -73,7 +73,7 @@ class GeoReferencedTableFilterMixin(django_filters.FilterSet):
)
# Parcel counter
pn = django_filters.CharFilter(
pn = django_filters.NumberFilter(
method="filter_parcel_number",
label=_(""),
label_suffix=_(""),
@ -165,7 +165,6 @@ class GeoReferencedTableFilterMixin(django_filters.FilterSet):
Returns:
"""
value = value.replace("-", "")
queryset = self._filter_parcel_reference(
queryset,
Q(flr=value),
@ -183,7 +182,6 @@ class GeoReferencedTableFilterMixin(django_filters.FilterSet):
Returns:
"""
value = value.replace("-", "")
queryset = self._filter_parcel_reference(
queryset,
Q(flrstck_zhlr=value)
@ -201,7 +199,6 @@ class GeoReferencedTableFilterMixin(django_filters.FilterSet):
Returns:
"""
value = value.replace("-", "")
queryset = self._filter_parcel_reference(
queryset,
Q(flrstck_nnr=value),

View File

@ -10,6 +10,7 @@ import json
from django.contrib.gis import gdal
from django.contrib.gis.forms import MultiPolygonField
from django.contrib.gis.geos import MultiPolygon, Polygon
from django.contrib.gis.geos.prototypes.io import WKTWriter
from django.utils.translation import gettext_lazy as _
from konova.forms.base_form import BaseForm
@ -74,9 +75,21 @@ class SimpleGeomForm(BaseForm):
# this case)
features = []
features_json = geom.get("features", [])
accepted_ogr_types = [
"Polygon",
"Polygon25D",
"MultiPolygon",
"MultiPolygon25D",
]
for feature in features_json:
g = gdal.OGRGeometry(json.dumps(feature.get("geometry", feature)), srs=DEFAULT_SRID_RLP)
if g.geom_type not in ["Polygon", "MultiPolygon"]:
feature_geom = json.dumps(feature.get("geometry", feature))
g = gdal.OGRGeometry(feature_geom, srs=DEFAULT_SRID_RLP)
flatten_geometry = g.coord_dim > 2
if flatten_geometry:
g = self.__flatten_geom_to_2D(g)
if g.geom_type not in accepted_ogr_types:
self.add_error("geom", _("Only surfaces allowed. Points or lines must be buffered."))
is_valid = False
return is_valid
@ -131,3 +144,13 @@ class SimpleGeomForm(BaseForm):
# Start the parcel update procedure in a background process
celery_update_parcels.delay(geometry.id)
return geometry
def __flatten_geom_to_2D(self, geom):
"""
Enforces a given OGRGeometry from higher dimensions into 2D
"""
wkt_w = WKTWriter(dim=2)
g_wkt = wkt_w.write(geom.geos).decode("utf-8")
geom = gdal.OGRGeometry(g_wkt)
return geom

View File

@ -434,8 +434,16 @@ class CheckableObjectMixin(models.Model):
class ShareableObjectMixin(models.Model):
# Users having access on this object
users = models.ManyToManyField("user.User", help_text="Users having access (data shared with)")
teams = models.ManyToManyField("user.Team", help_text="Teams having access (data shared with)")
users = models.ManyToManyField(
"user.User",
help_text="Users having access (data shared with)",
blank=True
)
teams = models.ManyToManyField(
"user.Team",
help_text="Teams having access (data shared with)",
blank=True
)
access_token = models.CharField(
max_length=255,
null=True,

View File

@ -115,6 +115,19 @@ class BaseTestCase(TestCase):
"""
return f"{prefix}{generate_random_string(3, True)}"
def create_dummy_document(self, DocumentModel, instance):
""" Creates a document db entry which can be used for tests
"""
doc = DocumentModel.objects.create(
title="TEST_doc",
comment="",
file=None,
date_of_creation="1970-01-01",
instance=instance,
)
return doc
def create_dummy_intervention(self):
""" Creates an intervention which can be used for tests

View File

@ -92,11 +92,14 @@ class Mailer:
msg
)
def send_mail_shared_access_given_team(self, obj_identifier, obj_title, team):
def send_mail_shared_access_given_team(self, obj_identifier, obj_title, team, users_to_notify):
""" Send a mail if a team just got access to the object
Args:
obj_identifier (str): The object identifier
obj_title (str): Title of the main object
team (Team): Team to be notified
users_to_notify (QueryDict): Contains the team users which should be notified
Returns:
@ -108,18 +111,21 @@ class Mailer:
"EMAIL_REPLY_TO": EMAIL_REPLY_TO,
}
msg = render_to_string("email/sharing/shared_access_given_team.html", context)
user_mail_address = team.users.values_list("email", flat=True)
user_mail_address = users_to_notify.values_list("email", flat=True)
self.send(
user_mail_address,
_("{} - Shared access given").format(obj_identifier),
msg
)
def send_mail_shared_access_removed_team(self, obj_identifier, obj_title, team):
def send_mail_shared_access_removed_team(self, obj_identifier, obj_title, team, users_to_notify):
""" Send a mail if a team just lost access to the object
Args:
obj_identifier (str): The object identifier
obj_title (str): Title of the main object
team (Team): Team to be notified
users_to_notify (QueryDict): Contains the team users which should be notified
Returns:
@ -131,18 +137,21 @@ class Mailer:
"EMAIL_REPLY_TO": EMAIL_REPLY_TO,
}
msg = render_to_string("email/sharing/shared_access_removed_team.html", context)
user_mail_address = team.users.values_list("email", flat=True)
user_mail_address = users_to_notify.values_list("email", flat=True)
self.send(
user_mail_address,
_("{} - Shared access removed").format(obj_identifier),
msg
)
def send_mail_shared_data_unrecorded_team(self, obj_identifier, obj_title, team):
def send_mail_shared_data_unrecorded_team(self, obj_identifier, obj_title, team, users_to_notify):
""" Send a mail if data has just been unrecorded
Args:
obj_identifier (str): The object identifier
obj_title (str): Title of the main object
team (Team): Team to be notified
users_to_notify (QueryDict): Contains the team users which should be notified
Returns:
@ -154,18 +163,21 @@ class Mailer:
"EMAIL_REPLY_TO": EMAIL_REPLY_TO,
}
msg = render_to_string("email/recording/shared_data_unrecorded_team.html", context)
user_mail_address = team.users.values_list("email", flat=True)
user_mail_address = users_to_notify.values_list("email", flat=True)
self.send(
user_mail_address,
_("{} - Shared data unrecorded").format(obj_identifier),
msg
)
def send_mail_shared_data_recorded_team(self, obj_identifier, obj_title, team):
def send_mail_shared_data_recorded_team(self, obj_identifier, obj_title, team, users_to_notify):
""" Send a mail if data has just been recorded
Args:
obj_identifier (str): The object identifier
obj_title (str): Title of the main object
team (Team): Team to be notified
users_to_notify (QueryDict): Contains the team users which should be notified
Returns:
@ -177,18 +189,21 @@ class Mailer:
"EMAIL_REPLY_TO": EMAIL_REPLY_TO,
}
msg = render_to_string("email/recording/shared_data_recorded_team.html", context)
user_mail_address = team.users.values_list("email", flat=True)
user_mail_address = users_to_notify.values_list("email", flat=True)
self.send(
user_mail_address,
_("{} - Shared data recorded").format(obj_identifier),
msg
)
def send_mail_shared_data_checked_team(self, obj_identifier, obj_title, team):
def send_mail_shared_data_checked_team(self, obj_identifier, obj_title, team, users_to_notify):
""" Send a mail if data has just been checked
Args:
obj_identifier (str): The object identifier
obj_title (str): Title of the main object
team (Team): Team to be notified
users_to_notify (QueryDict): Contains the team users which should be notified
Returns:
@ -200,14 +215,14 @@ class Mailer:
"EMAIL_REPLY_TO": EMAIL_REPLY_TO,
}
msg = render_to_string("email/checking/shared_data_checked_team.html", context)
user_mail_address = team.users.values_list("email", flat=True)
user_mail_address = users_to_notify.values_list("email", flat=True)
self.send(
user_mail_address,
_("{} - Shared data checked").format(obj_identifier),
msg
)
def send_mail_deduction_changed_team(self, obj_identifier, obj_title, team, data_changes):
def send_mail_deduction_changed_team(self, obj_identifier, obj_title, team, data_changes, users_to_notify):
""" Send a mail if deduction has been changed
Args:
@ -215,7 +230,7 @@ class Mailer:
obj_title (str): Title of the main object
team (Team): Team to be notified
data_changes (dict): Contains the old|new changes of the deduction changes
users_to_notify (QueryDict): Contains the team users which should be notified
Returns:
"""
@ -227,14 +242,14 @@ class Mailer:
"data_changes": data_changes,
}
msg = render_to_string("email/other/deduction_changed_team.html", context)
user_mail_address = team.users.values_list("email", flat=True)
user_mail_address = users_to_notify.values_list("email", flat=True)
self.send(
user_mail_address,
_("{} - Deduction changed").format(obj_identifier),
msg
)
def send_mail_shared_data_deleted_team(self, obj_identifier, obj_title, team):
def send_mail_shared_data_deleted_team(self, obj_identifier, obj_title, team, users_to_notify):
""" Send a mail if data has just been deleted
Args:
@ -250,7 +265,7 @@ class Mailer:
"EMAIL_REPLY_TO": EMAIL_REPLY_TO,
}
msg = render_to_string("email/deleting/shared_data_deleted_team.html", context)
user_mail_address = team.users.values_list("email", flat=True)
user_mail_address = users_to_notify.values_list("email", flat=True)
self.send(
user_mail_address,
_("{} - Shared data deleted").format(obj_identifier),

Binary file not shown.

View File

@ -43,7 +43,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-10-11 16:39+0200\n"
"POT-Creation-Date: 2022-11-16 13:36+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -204,7 +204,7 @@ msgstr "Geprüft"
#: compensation/templates/compensation/detail/compensation/view.html:93
#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:31
#: compensation/templates/compensation/detail/eco_account/view.html:45
#: ema/tables.py:44 ema/templates/ema/detail/view.html:35
#: ema/tables.py:41 ema/templates/ema/detail/view.html:35
#: intervention/tables.py:44
#: intervention/templates/intervention/detail/view.html:87
#: user/models/user_action.py:22
@ -357,7 +357,7 @@ msgid "Show only unrecorded"
msgstr "Nur unverzeichnete anzeigen"
#: compensation/forms/compensation.py:30 compensation/tables/compensation.py:23
#: compensation/tables/eco_account.py:23 ema/tables.py:29
#: compensation/tables/eco_account.py:23 ema/tables.py:26
#: intervention/forms/intervention.py:29 intervention/tables.py:23
#: intervention/templates/intervention/detail/includes/compensations.html:30
msgid "Identifier"
@ -376,12 +376,12 @@ msgstr "Automatisch generiert"
#: compensation/templates/compensation/detail/eco_account/view.html:32
#: compensation/templates/compensation/report/compensation/report.html:12
#: compensation/templates/compensation/report/eco_account/report.html:12
#: ema/tables.py:34 ema/templates/ema/detail/includes/documents.html:28
#: ema/tables.py:31 ema/templates/ema/detail/includes/documents.html:28
#: ema/templates/ema/detail/view.html:31
#: ema/templates/ema/report/report.html:12
#: intervention/forms/intervention.py:41 intervention/tables.py:28
#: intervention/templates/intervention/detail/includes/compensations.html:33
#: intervention/templates/intervention/detail/includes/documents.html:28
#: intervention/templates/intervention/detail/includes/documents.html:33
#: intervention/templates/intervention/detail/view.html:31
#: intervention/templates/intervention/report/report.html:12
#: konova/forms/modals/document_form.py:24
@ -411,7 +411,7 @@ msgstr "Kompensation XY; Flur ABC"
#: ema/templates/ema/detail/includes/documents.html:34
#: intervention/forms/intervention.py:199
#: intervention/forms/modals/revocation.py:45
#: intervention/templates/intervention/detail/includes/documents.html:34
#: intervention/templates/intervention/detail/includes/documents.html:39
#: intervention/templates/intervention/detail/includes/payments.html:34
#: intervention/templates/intervention/detail/includes/revocation.html:38
#: konova/forms/modals/document_form.py:59
@ -473,13 +473,15 @@ msgstr "Neues Ökokonto"
msgid "Eco-Account XY; Location ABC"
msgstr "Ökokonto XY; Flur ABC"
#: compensation/forms/eco_account.py:141
#: compensation/forms/eco_account.py:143
msgid "Edit Eco-Account"
msgstr "Ökokonto bearbeiten"
#: compensation/forms/eco_account.py:224
#: compensation/forms/eco_account.py:228
msgid "The account can not be removed, since there are still deductions."
msgstr "Das Ökokonto kann nicht entfernt werden, da hierzu noch Abbuchungen vorliegen."
msgstr ""
"Das Ökokonto kann nicht entfernt werden, da hierzu noch Abbuchungen "
"vorliegen."
#: compensation/forms/mixins.py:37
#: compensation/templates/compensation/detail/eco_account/view.html:63
@ -754,54 +756,42 @@ msgstr ""
"wollen. Kontaktieren Sie die für die Abbuchungen verantwortlichen Nutzer!"
#: compensation/tables/compensation.py:33 compensation/tables/eco_account.py:33
#: ema/tables.py:39 intervention/tables.py:33
#: ema/tables.py:36 intervention/tables.py:33
#: konova/filters/mixins/geo_reference.py:42
msgid "Parcel gmrkng"
msgstr "Gemarkung"
#: compensation/tables/compensation.py:50 compensation/tables/eco_account.py:54
#: ema/tables.py:50 intervention/tables.py:50
#: ema/tables.py:47 intervention/tables.py:50
msgid "Editable"
msgstr "Freigegeben"
#: compensation/tables/compensation.py:56 compensation/tables/eco_account.py:60
#: ema/tables.py:56 intervention/tables.py:56
#: ema/tables.py:53 intervention/tables.py:56
msgid "Last edit"
msgstr "Zuletzt bearbeitet"
#: compensation/tables/compensation.py:87 compensation/tables/eco_account.py:92
#: ema/tables.py:89 intervention/tables.py:87
#: ema/tables.py:86 intervention/tables.py:87
msgid "Open {}"
msgstr "Öffne {}"
#: compensation/tables/compensation.py:163
#: compensation/tables/compensation.py:141
#: compensation/templates/compensation/detail/compensation/view.html:96
#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:58
#: compensation/templates/compensation/detail/eco_account/view.html:48
#: ema/tables.py:130 ema/templates/ema/detail/view.html:38
#: intervention/tables.py:161
#: ema/tables.py:105 ema/templates/ema/detail/view.html:38
#: intervention/tables.py:139
#: intervention/templates/intervention/detail/view.html:90
msgid "Not recorded yet"
msgstr "Noch nicht verzeichnet"
#: compensation/tables/compensation.py:166
#: compensation/tables/eco_account.py:153 ema/tables.py:133
#: intervention/tables.py:164
#: compensation/tables/compensation.py:144
#: compensation/tables/eco_account.py:131 ema/tables.py:108
#: intervention/tables.py:142
msgid "Recorded on {} by {}"
msgstr "Am {} von {} verzeichnet worden"
#: compensation/tables/compensation.py:186
#: compensation/tables/eco_account.py:175 ema/tables.py:154
#: intervention/tables.py:185
msgid "Full access granted"
msgstr "Für Sie freigegeben - Datensatz kann bearbeitet werden"
#: compensation/tables/compensation.py:186
#: compensation/tables/eco_account.py:175 ema/tables.py:154
#: intervention/tables.py:185
msgid "Access not granted"
msgstr "Nicht freigegeben - Datensatz nur lesbar"
#: compensation/tables/eco_account.py:38
#: compensation/templates/compensation/detail/eco_account/view.html:36
#: konova/templates/konova/widgets/progressbar.html:3
@ -812,7 +802,7 @@ msgstr "Verfügbar"
msgid "Eco Accounts"
msgstr "Ökokonten"
#: compensation/tables/eco_account.py:150
#: compensation/tables/eco_account.py:128
msgid "Not recorded yet. Can not be used for deductions, yet."
msgstr ""
"Noch nicht verzeichnet. Kann noch nicht für Abbuchungen genutzt werden."
@ -861,7 +851,7 @@ msgstr "Menge"
#: ema/templates/ema/detail/includes/states-before.html:40
#: intervention/templates/intervention/detail/includes/compensations.html:38
#: intervention/templates/intervention/detail/includes/deductions.html:39
#: intervention/templates/intervention/detail/includes/documents.html:39
#: intervention/templates/intervention/detail/includes/documents.html:44
#: intervention/templates/intervention/detail/includes/payments.html:39
#: intervention/templates/intervention/detail/includes/revocation.html:43
#: templates/log.html:10 user/templates/user/team/index.html:33
@ -995,7 +985,7 @@ msgstr "Neues Dokument hinzufügen"
#: compensation/templates/compensation/detail/compensation/includes/documents.html:31
#: compensation/templates/compensation/detail/eco_account/includes/documents.html:31
#: ema/templates/ema/detail/includes/documents.html:31
#: intervention/templates/intervention/detail/includes/documents.html:31
#: intervention/templates/intervention/detail/includes/documents.html:36
#: konova/forms/modals/document_form.py:34
msgid "Created on"
msgstr "Erstellt"
@ -1003,7 +993,7 @@ msgstr "Erstellt"
#: compensation/templates/compensation/detail/compensation/includes/documents.html:63
#: compensation/templates/compensation/detail/eco_account/includes/documents.html:61
#: ema/templates/ema/detail/includes/documents.html:61
#: intervention/templates/intervention/detail/includes/documents.html:65
#: intervention/templates/intervention/detail/includes/documents.html:70
#: konova/forms/modals/document_form.py:139
msgid "Edit document"
msgstr "Dokument bearbeiten"
@ -1011,7 +1001,7 @@ msgstr "Dokument bearbeiten"
#: compensation/templates/compensation/detail/compensation/includes/documents.html:66
#: compensation/templates/compensation/detail/eco_account/includes/documents.html:64
#: ema/templates/ema/detail/includes/documents.html:64
#: intervention/templates/intervention/detail/includes/documents.html:68
#: intervention/templates/intervention/detail/includes/documents.html:73
msgid "Remove document"
msgstr "Dokument löschen"
@ -1287,8 +1277,8 @@ msgid "Compensation {} edited"
msgstr "Kompensation {} bearbeitet"
#: compensation/views/compensation/compensation.py:185
#: compensation/views/eco_account/eco_account.py:159 ema/views/ema.py:211
#: intervention/views/intervention.py:225
#: compensation/views/eco_account/eco_account.py:159 ema/views/ema.py:210
#: intervention/views/intervention.py:228
msgid "Edit {}"
msgstr "Bearbeite {}"
@ -1314,7 +1304,7 @@ msgstr "Ökokonto {} bearbeitet"
msgid "Eco-account removed"
msgstr "Ökokonto entfernt"
#: ema/forms.py:42 ema/views/ema.py:94
#: ema/forms.py:42 ema/views/ema.py:93
msgid "New EMA"
msgstr "Neue EMA hinzufügen"
@ -1322,11 +1312,11 @@ msgstr "Neue EMA hinzufügen"
msgid "Edit EMA"
msgstr "Bearbeite EMA"
#: ema/tables.py:65 templates/navbars/navbar.html:43
#: ema/tables.py:62 templates/navbars/navbar.html:43
msgid "Payment funded compensations"
msgstr "Ersatzzahlungsmaßnahmen (EMA)"
#: ema/tables.py:66
#: ema/tables.py:63
msgid "EMA explanation"
msgstr ""
"EMA sind Kompensationen, die durch Ersatzzahlungen finanziert wurden. "
@ -1334,7 +1324,7 @@ msgstr ""
"Maßnahmen aus Ersatzzahlungen, die nach 2015 rechtskräftig wurden, werden "
"durch die Stiftung Natur und Umwelt verwaltet."
#: ema/tables.py:89 templates/navbars/navbar.html:43
#: ema/tables.py:86 templates/navbars/navbar.html:43
msgid "EMA"
msgstr ""
@ -1342,19 +1332,19 @@ msgstr ""
msgid "Payment funded compensation"
msgstr "Ersatzzahlungsmaßnahme"
#: ema/views/ema.py:51
#: ema/views/ema.py:50
msgid "EMAs - Overview"
msgstr "EMAs - Übersicht"
#: ema/views/ema.py:84
#: ema/views/ema.py:83
msgid "EMA {} added"
msgstr "EMA {} hinzugefügt"
#: ema/views/ema.py:201
#: ema/views/ema.py:200
msgid "EMA {} edited"
msgstr "EMA {} bearbeitet"
#: ema/views/ema.py:235
#: ema/views/ema.py:234
msgid "EMA removed"
msgstr "EMA entfernt"
@ -1564,6 +1554,13 @@ msgstr "Ökokonto gelöscht! Abbuchung ungültig!"
msgid "Eco-account not recorded! Deduction invalid!"
msgstr "Ökokonto nicht verzeichnet! Abbuchung ungültig!"
#: intervention/templates/intervention/detail/includes/documents.html:25
msgid ""
"You entered a payment. Please upload the legal document which defines the "
"payment`s amount."
msgstr ""
"Sie haben Ersatzzahlungen angegeben. Laden Sie bitte den Zahlungsbescheid als Dokument hoch."
#: intervention/templates/intervention/detail/includes/payments.html:8
#: intervention/templates/intervention/report/report.html:69
msgid "Payments"
@ -1648,11 +1645,11 @@ msgstr "Eingriffe - Übersicht"
msgid "Intervention {} added"
msgstr "Eingriff {} hinzugefügt"
#: intervention/views/intervention.py:213
#: intervention/views/intervention.py:216
msgid "Intervention {} edited"
msgstr "Eingriff {} bearbeitet"
#: intervention/views/intervention.py:250
#: intervention/views/intervention.py:253
msgid "{} removed"
msgstr "{} entfernt"
@ -1686,7 +1683,7 @@ msgid "Search for file number"
msgstr "Nach Aktenzeichen suchen"
#: konova/filters/mixins/geo_reference.py:29
#: konova/templates/konova/includes/parcels/parcel_table_frame.html:18
#: konova/templates/konova/includes/parcels/parcel_table_frame.html:19
msgid "District"
msgstr "Kreis"
@ -1699,7 +1696,7 @@ msgid "Search for parcel gmrkng"
msgstr "Nach Gemarkung suchen"
#: konova/filters/mixins/geo_reference.py:55
#: konova/templates/konova/includes/parcels/parcel_table_frame.html:39
#: konova/templates/konova/includes/parcels/parcel_table_frame.html:40
msgid "Parcel"
msgstr "Flur"
@ -1708,7 +1705,7 @@ msgid "Search for parcel"
msgstr "Nach Flur suchen"
#: konova/filters/mixins/geo_reference.py:68
#: konova/templates/konova/includes/parcels/parcel_table_frame.html:40
#: konova/templates/konova/includes/parcels/parcel_table_frame.html:41
msgid "Parcel counter"
msgstr "Flurstückzähler"
@ -1717,7 +1714,7 @@ msgid "Search for parcel counter"
msgstr "Nach Flurstückzähler suchen"
#: konova/filters/mixins/geo_reference.py:82
#: konova/templates/konova/includes/parcels/parcel_table_frame.html:41
#: konova/templates/konova/includes/parcels/parcel_table_frame.html:42
msgid "Parcel number"
msgstr "Flurstücknenner"
@ -1873,37 +1870,37 @@ msgstr ""
msgid "English"
msgstr ""
#: konova/templates/konova/includes/parcels/parcel_table_frame.html:5
#: konova/templates/konova/includes/parcels/parcel_table_frame.html:6
msgid "Parcels can not be calculated, since no geometry is given."
msgstr ""
"Flurstücke können nicht berechnet werden, da keine Geometrie eingegeben "
"wurde."
#: konova/templates/konova/includes/parcels/parcel_table_frame.html:11
#: konova/templates/konova/includes/parcels/parcel_table_frame.html:12
msgid "Parcels found"
msgstr "Flurstücke"
#: konova/templates/konova/includes/parcels/parcel_table_frame.html:16
#: konova/templates/konova/includes/parcels/parcel_table_frame.html:17
msgid "Municipal"
msgstr "Gemeinde"
#: konova/templates/konova/includes/parcels/parcel_table_frame.html:17
#: konova/templates/konova/includes/parcels/parcel_table_frame.html:18
msgid "Municipal key"
msgstr "Gemeindeschlüssel"
#: konova/templates/konova/includes/parcels/parcel_table_frame.html:19
#: konova/templates/konova/includes/parcels/parcel_table_frame.html:20
msgid "District key"
msgstr "Kreisschlüssel"
#: konova/templates/konova/includes/parcels/parcel_table_frame.html:37
#: konova/templates/konova/includes/parcels/parcel_table_frame.html:38
msgid "Parcel group"
msgstr "Gemarkung"
#: konova/templates/konova/includes/parcels/parcel_table_frame.html:38
#: konova/templates/konova/includes/parcels/parcel_table_frame.html:39
msgid "Parcel group key"
msgstr "Gemarkungsschlüssel"
#: konova/templates/konova/includes/parcels/parcels.html:7
#: konova/templates/konova/includes/parcels/parcels.html:9
msgid "Spatial reference"
msgstr "Raumreferenz"
@ -1951,39 +1948,39 @@ msgstr "In Zwischenablage kopiert"
msgid "Search"
msgstr "Suchen"
#: konova/utils/mailer.py:68 konova/utils/mailer.py:137
#: konova/utils/mailer.py:68 konova/utils/mailer.py:143
msgid "{} - Shared access removed"
msgstr "{} - Zugriff entzogen"
#: konova/utils/mailer.py:91 konova/utils/mailer.py:114
#: konova/utils/mailer.py:91 konova/utils/mailer.py:117
msgid "{} - Shared access given"
msgstr "{} - Zugriff freigegeben"
#: konova/utils/mailer.py:160 konova/utils/mailer.py:302
#: konova/utils/mailer.py:169 konova/utils/mailer.py:317
msgid "{} - Shared data unrecorded"
msgstr "{} - Freigegebene Daten entzeichnet"
#: konova/utils/mailer.py:183 konova/utils/mailer.py:279
#: konova/utils/mailer.py:195 konova/utils/mailer.py:294
msgid "{} - Shared data recorded"
msgstr "{} - Freigegebene Daten verzeichnet"
#: konova/utils/mailer.py:206 konova/utils/mailer.py:348
#: konova/utils/mailer.py:221 konova/utils/mailer.py:363
msgid "{} - Shared data checked"
msgstr "{} - Freigegebene Daten geprüft"
#: konova/utils/mailer.py:233 konova/utils/mailer.py:376
#: konova/utils/mailer.py:248 konova/utils/mailer.py:391
msgid "{} - Deduction changed"
msgstr "{} - Abbuchung geändert"
#: konova/utils/mailer.py:256 konova/utils/mailer.py:325
#: konova/utils/mailer.py:271 konova/utils/mailer.py:340
msgid "{} - Shared data deleted"
msgstr "{} - Freigegebene Daten gelöscht"
#: konova/utils/mailer.py:397 templates/email/api/verify_token.html:4
#: konova/utils/mailer.py:412 templates/email/api/verify_token.html:4
msgid "Request for new API token"
msgstr "Anfrage für neuen API Token"
#: konova/utils/mailer.py:420
#: konova/utils/mailer.py:435
msgid "Resubmission - {}"
msgstr "Wiedervorlage - {}"
@ -2225,7 +2222,15 @@ msgstr "{} wurde erfolgreich vom Nutzer {} geprüft! {}"
msgid "missing"
msgstr "fehlend"
#: konova/views/home.py:78 templates/navbars/navbar.html:16
#: konova/utils/tables.py:218
msgid "Full access granted"
msgstr "Für Sie freigegeben - Datensatz kann bearbeitet werden"
#: konova/utils/tables.py:218
msgid "Access not granted"
msgstr "Nicht freigegeben - Datensatz nur lesbar"
#: konova/views/home.py:79 templates/navbars/navbar.html:16
msgid "Home"
msgstr "Home"
@ -2670,7 +2675,7 @@ msgstr ""
msgid "User"
msgstr "Nutzer"
#: templates/map/geom_form.html:9
#: templates/map/geom_form.html:11 templates/table/gmrkng_col.html:4
msgid "No geometry added, yet."
msgstr "Keine Geometrie vorhanden"
@ -2725,7 +2730,7 @@ msgstr ""
"vorbei. \n"
" "
#: templates/table/gmrkng_col.html:6
#: templates/table/gmrkng_col.html:12
msgid ""
"If the geometry is not empty, the parcels are currently recalculated. Please "
"refresh this page in a few moments."
@ -2897,35 +2902,27 @@ msgstr ""
" "
#: user/templates/user/index.html:42
msgid "Change default configuration for your KSP map"
msgstr "Karteneinstellungen ändern"
#: user/templates/user/index.html:45
msgid "Map settings"
msgstr "Karte"
#: user/templates/user/index.html:50
msgid "Change notification configurations"
msgstr "Benachrichtigungseinstellungen ändern"
#: user/templates/user/index.html:53
#: user/templates/user/index.html:45
msgid "Notification settings"
msgstr "Benachrichtigungen"
#: user/templates/user/index.html:58
#: user/templates/user/index.html:50
msgid "Manage teams"
msgstr ""
#: user/templates/user/index.html:61 user/templates/user/team/index.html:19
#: user/templates/user/index.html:53 user/templates/user/team/index.html:19
#: user/views.py:171
msgid "Teams"
msgstr ""
#: user/templates/user/index.html:66
#: user/templates/user/index.html:58
msgid "See or edit your API token"
msgstr "API token einsehen oder neu generieren"
#: user/templates/user/index.html:69
#: user/templates/user/index.html:61
msgid "API"
msgstr ""
@ -4508,6 +4505,12 @@ msgstr ""
msgid "Unable to connect to qpid with SASL mechanism %s"
msgstr ""
#~ msgid "Change default configuration for your KSP map"
#~ msgstr "Karteneinstellungen ändern"
#~ msgid "Map settings"
#~ msgstr "Karte"
#~ msgid "There are errors on this intervention:"
#~ msgstr "Es liegen Fehler in diesem Eingriff vor:"

View File

@ -17,15 +17,15 @@ class TeamAdminAutocomplete(Select2QuerySetView):
def get_queryset(self):
if self.request.user.is_anonymous:
return User.objects.none()
qs = User.objects.filter(
id__in=self.forwarded.get("members", [])
).exclude(
id__in=self.forwarded.get("admins", [])
)
if self.q:
# Due to privacy concerns only a full username match will return the proper user entry
qs = qs.filter(
name__icontains=self.q
username__icontains=self.q
)
qs = qs.order_by(
"username"

View File

@ -2,6 +2,7 @@ from django.db import models
from konova.models import UuidModel, DeletableObjectMixin
from konova.utils.mailer import Mailer
from user.enums import UserNotificationEnum
from user.models import UserActionLogEntry
@ -41,7 +42,10 @@ class Team(UuidModel, DeletableObjectMixin):
"""
mailer = Mailer()
mailer.send_mail_shared_access_given_team(obj_identifier, obj_title, self)
users_to_notify = self.users.filter(
notifications__in=[UserNotificationEnum.NOTIFY_ON_SHARED_ACCESS_GAINED.value]
)
mailer.send_mail_shared_access_given_team(obj_identifier, obj_title, self, users_to_notify)
def send_mail_shared_access_removed(self, obj_identifier, obj_title):
""" Sends a mail to the team members in case of removed shared access
@ -54,7 +58,10 @@ class Team(UuidModel, DeletableObjectMixin):
"""
mailer = Mailer()
mailer.send_mail_shared_access_removed_team(obj_identifier, obj_title, self)
users_to_notify = self.users.filter(
notifications__in=[UserNotificationEnum.NOTIFY_ON_SHARED_ACCESS_REMOVED.value]
)
mailer.send_mail_shared_access_removed_team(obj_identifier, obj_title, self, users_to_notify)
def send_mail_shared_data_unrecorded(self, obj_identifier, obj_title):
""" Sends a mail to the team members in case of unrecorded data
@ -67,7 +74,10 @@ class Team(UuidModel, DeletableObjectMixin):
"""
mailer = Mailer()
mailer.send_mail_shared_data_unrecorded_team(obj_identifier, obj_title, self)
users_to_notify = self.users.filter(
notifications__in=[UserNotificationEnum.NOTIFY_ON_SHARED_DATA_RECORDED.value]
)
mailer.send_mail_shared_data_unrecorded_team(obj_identifier, obj_title, self, users_to_notify)
def send_mail_shared_data_recorded(self, obj_identifier, obj_title):
""" Sends a mail to the team members in case of unrecorded data
@ -80,7 +90,10 @@ class Team(UuidModel, DeletableObjectMixin):
"""
mailer = Mailer()
mailer.send_mail_shared_data_recorded_team(obj_identifier, obj_title, self)
users_to_notify = self.users.filter(
notifications__in=[UserNotificationEnum.NOTIFY_ON_SHARED_DATA_RECORDED.value]
)
mailer.send_mail_shared_data_recorded_team(obj_identifier, obj_title, self, users_to_notify)
def send_mail_shared_data_checked(self, obj_identifier, obj_title):
""" Sends a mail to the team members in case of checked data
@ -93,7 +106,10 @@ class Team(UuidModel, DeletableObjectMixin):
"""
mailer = Mailer()
mailer.send_mail_shared_data_checked_team(obj_identifier, obj_title, self)
users_to_notify = self.users.filter(
notifications__in=[UserNotificationEnum.NOTIFY_ON_SHARED_DATA_CHECKED.value]
)
mailer.send_mail_shared_data_checked_team(obj_identifier, obj_title, self, users_to_notify)
def send_mail_deduction_changed(self, obj_identifier, obj_title, data_changes):
""" Sends a mail to the team members in case of changed deduction values
@ -107,7 +123,10 @@ class Team(UuidModel, DeletableObjectMixin):
"""
mailer = Mailer()
mailer.send_mail_deduction_changed_team(obj_identifier, obj_title, self, data_changes)
users_to_notify = self.users.filter(
notifications__in=[UserNotificationEnum.NOTIFY_ON_DEDUCTION_CHANGES.value]
)
mailer.send_mail_deduction_changed_team(obj_identifier, obj_title, self, data_changes, users_to_notify)
def send_mail_shared_data_deleted(self, obj_identifier, obj_title):
""" Sends a mail to the team members in case of deleted data
@ -120,7 +139,10 @@ class Team(UuidModel, DeletableObjectMixin):
"""
mailer = Mailer()
mailer.send_mail_shared_data_deleted_team(obj_identifier, obj_title, self)
users_to_notify = self.users.filter(
notifications__in=[UserNotificationEnum.NOTIFY_ON_SHARED_DATA_DELETED.value]
)
mailer.send_mail_shared_data_deleted_team(obj_identifier, obj_title, self, users_to_notify)
def remove_user(self, user):
""" Removes a user from the team