#36 Quality checks

* adds unchecking/unrecording of interventions in case of post-check|post-record editing
This commit is contained in:
mpeltriaux 2021-10-25 17:39:39 +02:00
parent 1c3ab898cc
commit 4a4c9ad049
8 changed files with 137 additions and 44 deletions

View File

@ -221,11 +221,12 @@ class Compensation(AbstractCompensation):
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if self.identifier is None or len(self.identifier) == 0: if self.identifier is None or len(self.identifier) == 0:
# Create new identifier # Create new identifier is none was given
new_id = self.generate_new_identifier() self.identifier = self.generate_new_identifier()
while Compensation.objects.filter(identifier=new_id).exists():
new_id = self.generate_new_identifier() # Before saving, make sure a given identifier has not been taken already in the meanwhile
self.identifier = new_id while Compensation.objects.filter(identifier=self.identifier).exclude(id=self.id).exists():
self.identifier = self.generate_new_identifier()
super().save(*args, **kwargs) super().save(*args, **kwargs)
def get_LANIS_link(self) -> str: def get_LANIS_link(self) -> str:
@ -368,11 +369,12 @@ class EcoAccount(AbstractCompensation, RecordableMixin):
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
if self.identifier is None or len(self.identifier) == 0: if self.identifier is None or len(self.identifier) == 0:
# Create new identifier # Create new identifier if none was given
new_id = self.generate_new_identifier() self.identifier = self.generate_new_identifier()
while EcoAccount.objects.filter(identifier=new_id).exists():
new_id = self.generate_new_identifier() # Before saving, make sure the given identifier is not used, yet
self.identifier = new_id while EcoAccount.objects.filter(identifier=self.identifier).exclude(id=self.id).exists():
self.identifier = self.generate_new_identifier()
super().save(*args, **kwargs) super().save(*args, **kwargs)
@property @property

View File

@ -355,5 +355,9 @@ class EditInterventionForm(NewInterventionForm):
self.instance.modified = user_action self.instance.modified = user_action
self.instance.save() self.instance.save()
# Uncheck and unrecord intervention due to changed data
self.instance.set_unchecked(user)
self.instance.set_unrecorded(user)
return self.instance return self.instance

View File

@ -17,7 +17,7 @@ from codelist.settings import CODELIST_REGISTRATION_OFFICE_ID, CODELIST_CONSERVA
from intervention.managers import InterventionManager from intervention.managers import InterventionManager
from intervention.utils.quality import InterventionQualityChecker from intervention.utils.quality import InterventionQualityChecker
from konova.models import BaseObject, Geometry, UuidModel, BaseResource, AbstractDocument, \ from konova.models import BaseObject, Geometry, UuidModel, BaseResource, AbstractDocument, \
generate_document_file_upload_path, RecordableMixin generate_document_file_upload_path, RecordableMixin, CheckableMixin
from konova.settings import DEFAULT_SRID_RLP, LANIS_LINK_TEMPLATE, LANIS_ZOOM_LUT from konova.settings import DEFAULT_SRID_RLP, LANIS_LINK_TEMPLATE, LANIS_ZOOM_LUT
from konova.utils import generators from konova.utils import generators
from user.models import UserActionLogEntry from user.models import UserActionLogEntry
@ -171,7 +171,7 @@ class LegalData(UuidModel):
revocation = models.OneToOneField(Revocation, null=True, blank=True, help_text="Refers to 'Widerspruch am'", on_delete=models.SET_NULL) revocation = models.OneToOneField(Revocation, null=True, blank=True, help_text="Refers to 'Widerspruch am'", on_delete=models.SET_NULL)
class Intervention(BaseObject, RecordableMixin): class Intervention(BaseObject, RecordableMixin, CheckableMixin):
""" """
Interventions are e.g. construction sites where nature used to be. Interventions are e.g. construction sites where nature used to be.
""" """
@ -273,11 +273,11 @@ class Intervention(BaseObject, RecordableMixin):
""" """
if self.identifier is None or len(self.identifier) == 0: if self.identifier is None or len(self.identifier) == 0:
# No identifier given # No identifier given by the user
self.identifier = self.generate_new_identifier() self.identifier = self.generate_new_identifier()
# Before saving, make sure the set identifier is not used, yet # Before saving, make sure the given identifier is not used in the meanwhile
while Intervention.objects.filter(identifier=self.identifier).exists(): while Intervention.objects.filter(identifier=self.identifier).exclude(id=self.id).exists():
self.identifier = self.generate_new_identifier() self.identifier = self.generate_new_identifier()
super().save(*args, **kwargs) super().save(*args, **kwargs)

View File

@ -15,7 +15,7 @@ from konova.sub_settings.django_settings import DEFAULT_DATE_FORMAT
from konova.utils.documents import remove_document, get_document from konova.utils.documents import remove_document, get_document
from konova.utils.generators import generate_qr_code from konova.utils.generators import generate_qr_code
from konova.utils.message_templates import INTERVENTION_INVALID, FORM_INVALID, IDENTIFIER_REPLACED, \ from konova.utils.message_templates import INTERVENTION_INVALID, FORM_INVALID, IDENTIFIER_REPLACED, \
DATA_UNSHARED_EXPLANATION DATA_UNSHARED_EXPLANATION, CHECKED_RECORDED_RESET
from konova.utils.user_checks import in_group from konova.utils.user_checks import in_group
@ -270,8 +270,13 @@ def edit_view(request: HttpRequest, id: str):
if request.method == "POST": if request.method == "POST":
if data_form.is_valid() and geom_form.is_valid(): if data_form.is_valid() and geom_form.is_valid():
# The data form takes the geom form for processing, as well as the performing user # The data form takes the geom form for processing, as well as the performing user
# Save the current state of recorded|checked to inform the user in case of a status reset due to editing
i_rec = intervention.recorded is not None
i_check = intervention.checked is not None
intervention = data_form.save(request.user, geom_form) intervention = data_form.save(request.user, geom_form)
messages.success(request, _("Intervention {} edited").format(intervention.identifier)) messages.success(request, _("Intervention {} edited").format(intervention.identifier))
if i_check or i_rec:
messages.info(request, CHECKED_RECORDED_RESET)
return redirect("intervention:detail", id=intervention.id) return redirect("intervention:detail", id=intervention.id)
else: else:
messages.error(request, FORM_INVALID, extra_tags="danger",) messages.error(request, FORM_INVALID, extra_tags="danger",)

View File

@ -321,6 +321,40 @@ class RecordableMixin:
Provides functionality related to un/recording of data Provides functionality related to un/recording of data
""" """
def set_unrecorded(self, user: User):
""" Perform unrecording
Args:
user (User): Performing user
Returns:
"""
action = UserActionLogEntry.objects.create(
user=user,
action=UserAction.UNRECORDED
)
self.recorded = None
self.save()
self.log.add(action)
def set_recorded(self, user: User):
""" Perform recording
Args:
user (User): Performing user
Returns:
"""
action = UserActionLogEntry.objects.create(
user=user,
action=UserAction.RECORDED
)
self.recorded = action
self.save()
self.log.add(action)
def toggle_recorded(self, user: User): def toggle_recorded(self, user: User):
""" Un/Record intervention """ Un/Record intervention
@ -331,16 +365,55 @@ class RecordableMixin:
""" """
if not self.recorded: if not self.recorded:
action = UserActionLogEntry.objects.create( self.set_recorded(user)
user=user,
action=UserAction.RECORDED
)
self.recorded = action
else: else:
action = UserActionLogEntry.objects.create( self.set_unrecorded(user)
user=user,
action=UserAction.UNRECORDED
) class CheckableMixin:
self.recorded = None """ Mixin to be combined with BaseObject class
Provides functionality related to un/checking of data
"""
def set_unchecked(self, user: User):
""" Perform unrecording
Args:
Returns:
"""
self.checked = None
self.save()
def set_checked(self, user: User):
""" Perform checking
Args:
user (User): Performing user
Returns:
"""
action = UserActionLogEntry.objects.create(
user=user,
action=UserAction.CHECKED
)
self.checked = action
self.save() self.save()
self.log.add(action) self.log.add(action)
def toggle_checked(self, user: User):
""" Un/Record intervention
Args:
user (User): Performing user
Returns:
"""
if not self.checked:
self.set_checked(user)
else:
self.set_unchecked(user)

View File

@ -14,4 +14,6 @@ INTERVENTION_INVALID = _("There are errors in this intervention.")
IDENTIFIER_REPLACED = _("The identifier '{}' had to be changed to '{}' since another entry has been added in the meanwhile, which uses this identifier") IDENTIFIER_REPLACED = _("The identifier '{}' had to be changed to '{}' since another entry has been added in the meanwhile, which uses this identifier")
DATA_UNSHARED = _("This data is not shared with you") DATA_UNSHARED = _("This data is not shared with you")
DATA_UNSHARED_EXPLANATION = _("Remember: This data has not been shared with you, yet. This means you can only read but can not edit or perform any actions like running a check or recording.") DATA_UNSHARED_EXPLANATION = _("Remember: This data has not been shared with you, yet. This means you can only read but can not edit or perform any actions like running a check or recording.")
MISSING_GROUP_PERMISSION = _("You need to be part of another user group.") MISSING_GROUP_PERMISSION = _("You need to be part of another user group.")
CHECKED_RECORDED_RESET = _("Status of Checked and Recorded reseted")

Binary file not shown.

View File

@ -19,7 +19,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-10-25 14:13+0200\n" "POT-Creation-Date: 2021-10-25 17:10+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -41,7 +41,8 @@ msgstr "Bis"
#: compensation/templates/compensation/detail/eco_account/view.html:58 #: compensation/templates/compensation/detail/eco_account/view.html:58
#: compensation/templates/compensation/report/eco_account/report.html:16 #: compensation/templates/compensation/report/eco_account/report.html:16
#: compensation/utils/quality.py:100 ema/templates/ema/detail/view.html:42 #: compensation/utils/quality.py:100 ema/templates/ema/detail/view.html:42
#: ema/templates/ema/report/report.html:16 intervention/forms/forms.py:101 #: ema/templates/ema/report/report.html:16 ema/utils/quality.py:26
#: intervention/forms/forms.py:101
#: intervention/templates/intervention/detail/view.html:56 #: intervention/templates/intervention/detail/view.html:56
#: intervention/templates/intervention/report/report.html:37 #: intervention/templates/intervention/report/report.html:37
#: intervention/utils/quality.py:49 #: intervention/utils/quality.py:49
@ -373,7 +374,8 @@ msgstr "Zusätzlicher Kommentar"
#: compensation/templates/compensation/detail/eco_account/view.html:62 #: compensation/templates/compensation/detail/eco_account/view.html:62
#: compensation/templates/compensation/report/eco_account/report.html:20 #: compensation/templates/compensation/report/eco_account/report.html:20
#: compensation/utils/quality.py:102 ema/templates/ema/detail/view.html:46 #: compensation/utils/quality.py:102 ema/templates/ema/detail/view.html:46
#: ema/templates/ema/report/report.html:20 intervention/forms/forms.py:129 #: ema/templates/ema/report/report.html:20 ema/utils/quality.py:28
#: intervention/forms/forms.py:129
#: intervention/templates/intervention/detail/view.html:60 #: intervention/templates/intervention/detail/view.html:60
#: intervention/templates/intervention/report/report.html:41 #: intervention/templates/intervention/report/report.html:41
#: intervention/utils/quality.py:42 #: intervention/utils/quality.py:42
@ -1030,7 +1032,8 @@ msgstr ""
"Die abbuchbare Fläche darf die Gesamtfläche der Zielzustände nicht " "Die abbuchbare Fläche darf die Gesamtfläche der Zielzustände nicht "
"überschreiten" "überschreiten"
#: compensation/utils/quality.py:104 intervention/utils/quality.py:55 #: compensation/utils/quality.py:104 ema/utils/quality.py:30
#: intervention/utils/quality.py:55
msgid "Responsible data" msgid "Responsible data"
msgstr "Daten zu den verantwortlichen Stellen" msgstr "Daten zu den verantwortlichen Stellen"
@ -1044,7 +1047,7 @@ msgstr "Kompensation {} bearbeitet"
#: compensation/views/compensation_views.py:216 #: compensation/views/compensation_views.py:216
#: compensation/views/eco_account_views.py:290 ema/views.py:178 #: compensation/views/eco_account_views.py:290 ema/views.py:178
#: intervention/views.py:447 #: intervention/views.py:448
msgid "Log" msgid "Log"
msgstr "Log" msgstr "Log"
@ -1098,16 +1101,16 @@ msgid "Deduction removed"
msgstr "Abbuchung entfernt" msgstr "Abbuchung entfernt"
#: compensation/views/eco_account_views.py:310 ema/views.py:252 #: compensation/views/eco_account_views.py:310 ema/views.py:252
#: intervention/views.py:487 #: intervention/views.py:488
msgid "{} unrecorded" msgid "{} unrecorded"
msgstr "{} entzeichnet" msgstr "{} entzeichnet"
#: compensation/views/eco_account_views.py:310 ema/views.py:252 #: compensation/views/eco_account_views.py:310 ema/views.py:252
#: intervention/views.py:487 #: intervention/views.py:488
msgid "{} recorded" msgid "{} recorded"
msgstr "{} verzeichnet" msgstr "{} verzeichnet"
#: compensation/views/eco_account_views.py:455 intervention/views.py:469 #: compensation/views/eco_account_views.py:455 intervention/views.py:470
msgid "Deduction added" msgid "Deduction added"
msgstr "Abbuchung hinzugefügt" msgstr "Abbuchung hinzugefügt"
@ -1436,39 +1439,43 @@ msgstr "Es existiert ein Widerspruch vom {}"
msgid "Intervention {} edited" msgid "Intervention {} edited"
msgstr "Eingriff {} bearbeitet" msgstr "Eingriff {} bearbeitet"
#: intervention/views.py:306 #: intervention/views.py:275
msgid "Status of Checked and Recorded reseted"
msgstr "'Geprüft' und 'Verzeichnet' sind zurückgesetzt worden"
#: intervention/views.py:307
msgid "{} removed" msgid "{} removed"
msgstr "{} entfernt" msgstr "{} entfernt"
#: intervention/views.py:327 #: intervention/views.py:328
msgid "Revocation removed" msgid "Revocation removed"
msgstr "Widerspruch entfernt" msgstr "Widerspruch entfernt"
#: intervention/views.py:353 #: intervention/views.py:354
msgid "{} has already been shared with you" msgid "{} has already been shared with you"
msgstr "{} wurde bereits für Sie freigegeben" msgstr "{} wurde bereits für Sie freigegeben"
#: intervention/views.py:358 #: intervention/views.py:359
msgid "{} has been shared with you" msgid "{} has been shared with you"
msgstr "{} ist nun für Sie freigegeben" msgstr "{} ist nun für Sie freigegeben"
#: intervention/views.py:365 #: intervention/views.py:366
msgid "Share link invalid" msgid "Share link invalid"
msgstr "Freigabelink ungültig" msgstr "Freigabelink ungültig"
#: intervention/views.py:386 #: intervention/views.py:387
msgid "Share settings updated" msgid "Share settings updated"
msgstr "Freigabe Einstellungen aktualisiert" msgstr "Freigabe Einstellungen aktualisiert"
#: intervention/views.py:405 #: intervention/views.py:406
msgid "Check performed" msgid "Check performed"
msgstr "Prüfung durchgeführt" msgstr "Prüfung durchgeführt"
#: intervention/views.py:425 #: intervention/views.py:426
msgid "Revocation added" msgid "Revocation added"
msgstr "Widerspruch hinzugefügt" msgstr "Widerspruch hinzugefügt"
#: intervention/views.py:492 #: intervention/views.py:493
msgid "There are errors on this intervention:" msgid "There are errors on this intervention:"
msgstr "Es liegen Fehler in diesem Eingriff vor:" msgstr "Es liegen Fehler in diesem Eingriff vor:"