#35 Sanity command
* refactors "toggling" of recorded/checked state * introduces mark_as_edited() for RecordableObjectMixin
This commit is contained in:
		
							parent
							
								
									f62dd76d94
								
							
						
					
					
						commit
						4583a9f826
					
				@ -284,6 +284,8 @@ class EditCompensationForm(NewCompensationForm):
 | 
			
		||||
            self.instance.save()
 | 
			
		||||
 | 
			
		||||
            self.instance.log.add(action)
 | 
			
		||||
 | 
			
		||||
            intervention.mark_as_edited(user)
 | 
			
		||||
        return self.instance
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -271,6 +271,11 @@ class Compensation(AbstractCompensation, CEFMixin, CoherenceMixin):
 | 
			
		||||
        )
 | 
			
		||||
        return docs
 | 
			
		||||
 | 
			
		||||
    def add_new_action(self, form) -> CompensationAction:
 | 
			
		||||
        super().add_new_action(form)
 | 
			
		||||
        self.intervention.set_as_edited(form.user)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CompensationDocument(AbstractDocument):
 | 
			
		||||
    """
 | 
			
		||||
    Specializes document upload for revocations with certain path
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,7 @@ Created on: 16.11.21
 | 
			
		||||
"""
 | 
			
		||||
import shutil
 | 
			
		||||
 | 
			
		||||
from django.contrib.auth.models import User
 | 
			
		||||
from django.core.exceptions import ValidationError
 | 
			
		||||
from django.core.validators import MinValueValidator
 | 
			
		||||
from django.db import models, transaction
 | 
			
		||||
 | 
			
		||||
@ -274,7 +274,7 @@ class EcoAccountWorkflowTestCase(BaseWorkflowTestCase):
 | 
			
		||||
 | 
			
		||||
        # Now mock the eco account as it would be recorded (with invalid data)
 | 
			
		||||
        # Make sure the deductible surface is high enough for the request
 | 
			
		||||
        self.eco_account.toggle_recorded(self.superuser)
 | 
			
		||||
        self.eco_account.set_recorded(self.superuser)
 | 
			
		||||
        self.eco_account.refresh_from_db()
 | 
			
		||||
        self.eco_account.deductable_surface = test_surface + 1.00
 | 
			
		||||
        self.eco_account.save()
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,8 @@ from konova.decorators import *
 | 
			
		||||
from konova.forms import RemoveModalForm, SimpleGeomForm
 | 
			
		||||
from konova.utils.documents import get_document, remove_document
 | 
			
		||||
from konova.utils.generators import generate_qr_code
 | 
			
		||||
from konova.utils.message_templates import FORM_INVALID, IDENTIFIER_REPLACED, DATA_UNSHARED_EXPLANATION
 | 
			
		||||
from konova.utils.message_templates import FORM_INVALID, IDENTIFIER_REPLACED, DATA_UNSHARED_EXPLANATION, \
 | 
			
		||||
    CHECKED_RECORDED_RESET
 | 
			
		||||
from konova.utils.user_checks import in_group
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -130,8 +131,15 @@ def edit_view(request: HttpRequest, id: str):
 | 
			
		||||
    geom_form = SimpleGeomForm(request.POST or None, read_only=False, instance=comp)
 | 
			
		||||
    if request.method == "POST":
 | 
			
		||||
        if data_form.is_valid() and geom_form.is_valid():
 | 
			
		||||
            # Preserve state of intervention recorded/checked to determine whether the user must be informed or not
 | 
			
		||||
            # about a change of the recorded/checked state
 | 
			
		||||
            intervention_recorded = comp.intervention.recorded is not None
 | 
			
		||||
            intervention_checked = comp.intervention.checked is not None
 | 
			
		||||
 | 
			
		||||
            # The data form takes the geom form for processing, as well as the performing user
 | 
			
		||||
            comp = data_form.save(request.user, geom_form)
 | 
			
		||||
            if intervention_recorded or intervention_checked:
 | 
			
		||||
                messages.info(request, CHECKED_RECORDED_RESET)
 | 
			
		||||
            messages.success(request, _("Compensation {} edited").format(comp.identifier))
 | 
			
		||||
            return redirect("compensation:detail", id=comp.id)
 | 
			
		||||
        else:
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,7 @@ Created on: 15.11.21
 | 
			
		||||
"""
 | 
			
		||||
import shutil
 | 
			
		||||
 | 
			
		||||
from django.contrib.auth.models import User
 | 
			
		||||
from django.db import models
 | 
			
		||||
from django.db.models import QuerySet
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -348,10 +348,7 @@ class EditInterventionForm(NewInterventionForm):
 | 
			
		||||
            self.instance.save()
 | 
			
		||||
 | 
			
		||||
            # Uncheck and unrecord intervention due to changed data
 | 
			
		||||
            if self.instance.checked:
 | 
			
		||||
                self.instance.set_unchecked()
 | 
			
		||||
            if self.instance.recorded:
 | 
			
		||||
                self.instance.set_unrecorded(user)
 | 
			
		||||
            self.instance.mark_as_edited(user)
 | 
			
		||||
 | 
			
		||||
        return self.instance
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -225,7 +225,7 @@ class CheckModalForm(BaseModalForm):
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        with transaction.atomic():
 | 
			
		||||
            self.instance.toggle_checked(self.user)
 | 
			
		||||
            self.instance.set_checked(self.user)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class NewDeductionModalForm(BaseModalForm):
 | 
			
		||||
 | 
			
		||||
@ -138,40 +138,33 @@ class Intervention(BaseObject, ShareableObjectMixin, RecordableObjectMixin, Chec
 | 
			
		||||
        )
 | 
			
		||||
        return revoc_docs, regular_docs
 | 
			
		||||
 | 
			
		||||
    def toggle_recorded(self, user: User):
 | 
			
		||||
        """ Toggle the recorded state
 | 
			
		||||
    def set_unchecked(self):
 | 
			
		||||
        log_entry = super().set_unchecked()
 | 
			
		||||
        self.add_log_entry_to_compensations(log_entry)
 | 
			
		||||
 | 
			
		||||
        For interventions the recorded action needs to be added to their compensation objects as well
 | 
			
		||||
    def set_checked(self, user: User) -> UserActionLogEntry:
 | 
			
		||||
        log_entry = super().set_checked(user)
 | 
			
		||||
        self.add_log_entry_to_compensations(log_entry)
 | 
			
		||||
        return log_entry
 | 
			
		||||
 | 
			
		||||
    def set_unrecorded(self, user: User):
 | 
			
		||||
        log_entry = super().set_unrecorded(user)
 | 
			
		||||
        self.add_log_entry_to_compensations(log_entry)
 | 
			
		||||
 | 
			
		||||
    def set_recorded(self, user: User) -> UserActionLogEntry:
 | 
			
		||||
        log_entry = super().set_recorded(user)
 | 
			
		||||
        self.add_log_entry_to_compensations(log_entry)
 | 
			
		||||
        return log_entry
 | 
			
		||||
 | 
			
		||||
    def add_log_entry_to_compensations(self, log_entry: UserActionLogEntry):
 | 
			
		||||
        """ Adds the log entry to related compensations
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
            user (User): The performing user
 | 
			
		||||
            log_entry (UserActionLogEntry): The log entry
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        log_entry = super().toggle_recorded(user)
 | 
			
		||||
 | 
			
		||||
        # Add this action to the linked compensation logs as well
 | 
			
		||||
        comps = self.compensations.all()
 | 
			
		||||
        for comp in comps:
 | 
			
		||||
            comp.log.add(log_entry)
 | 
			
		||||
 | 
			
		||||
    def toggle_checked(self, user: User) -> UserActionLogEntry:
 | 
			
		||||
        """ Toggle the checked state
 | 
			
		||||
 | 
			
		||||
        For interventions the checked action needs to be added to their compensation objects as well
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
            user (User): The performing user
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        log_entry = super().toggle_checked(user)
 | 
			
		||||
        # Leave if the log_entry is None (means "unchecked")
 | 
			
		||||
        if log_entry is None:
 | 
			
		||||
            return
 | 
			
		||||
        # Add this action to the linked compensation logs as well
 | 
			
		||||
        comps = self.compensations.all()
 | 
			
		||||
        for comp in comps:
 | 
			
		||||
            comp.log.add(log_entry)
 | 
			
		||||
@ -202,7 +195,8 @@ class Intervention(BaseObject, ShareableObjectMixin, RecordableObjectMixin, Chec
 | 
			
		||||
            self.log.add(edited_action)
 | 
			
		||||
            self.modified = edited_action
 | 
			
		||||
            self.save()
 | 
			
		||||
            return pay
 | 
			
		||||
        self.mark_as_edited(user)
 | 
			
		||||
        return pay
 | 
			
		||||
 | 
			
		||||
    def add_revocation(self, form):
 | 
			
		||||
        """ Adds a new revocation to the intervention
 | 
			
		||||
@ -237,6 +231,7 @@ class Intervention(BaseObject, ShareableObjectMixin, RecordableObjectMixin, Chec
 | 
			
		||||
                    file=form_data["file"],
 | 
			
		||||
                    instance=revocation
 | 
			
		||||
                )
 | 
			
		||||
            self.mark_as_edited(user)
 | 
			
		||||
        return revocation
 | 
			
		||||
 | 
			
		||||
    def add_deduction(self, form):
 | 
			
		||||
@ -266,8 +261,23 @@ class Intervention(BaseObject, ShareableObjectMixin, RecordableObjectMixin, Chec
 | 
			
		||||
                surface=form_data["surface"],
 | 
			
		||||
                created=user_action_create,
 | 
			
		||||
            )
 | 
			
		||||
            self.mark_as_edited(user)
 | 
			
		||||
        return deduction
 | 
			
		||||
 | 
			
		||||
    def mark_as_edited(self, performing_user: User):
 | 
			
		||||
        """ In case the object or a related object changed, internal processes need to be started, such as
 | 
			
		||||
        unrecord and uncheck
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
            performing_user (User): The user which performed the editing action
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        super().mark_as_edited(performing_user)
 | 
			
		||||
        if self.checked:
 | 
			
		||||
            self.set_unchecked()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class InterventionDocument(AbstractDocument):
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
@ -485,5 +485,8 @@ class RecordModalForm(BaseModalForm):
 | 
			
		||||
    def save(self):
 | 
			
		||||
        with transaction.atomic():
 | 
			
		||||
            if self.cleaned_data["confirm"]:
 | 
			
		||||
                self.instance.toggle_recorded(self.user)
 | 
			
		||||
                if self.instance.recorded:
 | 
			
		||||
                    self.instance.set_unrecorded(self.user)
 | 
			
		||||
                else:
 | 
			
		||||
                    self.instance.set_recorded(self.user)
 | 
			
		||||
        return self.instance
 | 
			
		||||
@ -203,6 +203,8 @@ class RecordableObjectMixin(models.Model):
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        if not self.recorded:
 | 
			
		||||
            return None
 | 
			
		||||
        action = UserActionLogEntry.get_unrecorded_action(user)
 | 
			
		||||
        self.recorded = None
 | 
			
		||||
        self.save()
 | 
			
		||||
@ -218,26 +220,27 @@ class RecordableObjectMixin(models.Model):
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        if self.recorded:
 | 
			
		||||
            return None
 | 
			
		||||
        action = UserActionLogEntry.get_recorded_action(user)
 | 
			
		||||
        self.recorded = action
 | 
			
		||||
        self.save()
 | 
			
		||||
        self.log.add(action)
 | 
			
		||||
        return action
 | 
			
		||||
 | 
			
		||||
    def toggle_recorded(self, user: User) -> UserActionLogEntry:
 | 
			
		||||
        """ Un/Record intervention
 | 
			
		||||
    def mark_as_edited(self, performing_user: User):
 | 
			
		||||
        """ In case the object or a related object changed, internal processes need to be started, such as
 | 
			
		||||
        unrecord and uncheck
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
            user (User): Performing user
 | 
			
		||||
            performing_user (User): The user which performed the editing action
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        if not self.recorded:
 | 
			
		||||
            ret_log_entry = self.set_recorded(user)
 | 
			
		||||
        else:
 | 
			
		||||
            ret_log_entry = self.set_unrecorded(user)
 | 
			
		||||
        return ret_log_entry
 | 
			
		||||
 | 
			
		||||
        if self.recorded:
 | 
			
		||||
            self.set_unrecorded(performing_user)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CheckableObjectMixin(models.Model):
 | 
			
		||||
@ -262,6 +265,9 @@ class CheckableObjectMixin(models.Model):
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        if not self.checked:
 | 
			
		||||
            # Nothing to do
 | 
			
		||||
            return
 | 
			
		||||
        # Do not .delete() the checked attribute! Just set it to None, since a delete() would kill it out of the
 | 
			
		||||
        # log history, which is not what we want!
 | 
			
		||||
        self.checked = None
 | 
			
		||||
@ -277,27 +283,15 @@ class CheckableObjectMixin(models.Model):
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        if self.checked:
 | 
			
		||||
            # Nothing to do
 | 
			
		||||
            return
 | 
			
		||||
        action = UserActionLogEntry.get_checked_action(user)
 | 
			
		||||
        self.checked = action
 | 
			
		||||
        self.save()
 | 
			
		||||
        self.log.add(action)
 | 
			
		||||
        return action
 | 
			
		||||
 | 
			
		||||
    def toggle_checked(self, user: User) -> UserActionLogEntry:
 | 
			
		||||
        """ Un/Record intervention
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
            user (User): Performing user
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        if not self.checked:
 | 
			
		||||
            ret_log_entry = self.set_checked(user)
 | 
			
		||||
        else:
 | 
			
		||||
            ret_log_entry = self.set_unchecked()
 | 
			
		||||
        return ret_log_entry
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ShareableObjectMixin(models.Model):
 | 
			
		||||
    # Users having access on this object
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user