diff --git a/compensation/forms/compensation.py b/compensation/forms/compensation.py index bb1532d6..b3ceb03f 100644 --- a/compensation/forms/compensation.py +++ b/compensation/forms/compensation.py @@ -168,6 +168,17 @@ class NewCompensationForm(AbstractCompensationForm, comp.log.add(action) return comp, action + def is_valid(self): + valid = super().is_valid() + intervention = self.cleaned_data.get("intervention", None) + valid &= not intervention.is_recorded + if not valid: + self.add_error( + "intervention", + _("This intervention is currently recorded. You cannot add further compensations as long as it is recorded.") + ) + return valid + def save(self, user: User, geom_form: SimpleGeomForm): with transaction.atomic(): comp, action = self.__create_comp(user) diff --git a/compensation/models/compensation.py b/compensation/models/compensation.py index 49accd46..eebd2b38 100644 --- a/compensation/models/compensation.py +++ b/compensation/models/compensation.py @@ -510,6 +510,12 @@ class Compensation(AbstractCompensation, CEFMixin, CoherenceMixin, PikMixin): return retval + @property + def checked(self): + if self.intervention: + return self.intervention.checked + return None + class CompensationDocument(AbstractDocument): """ diff --git a/compensation/urls/compensation.py b/compensation/urls/compensation.py index adec4b7f..b410ac78 100644 --- a/compensation/urls/compensation.py +++ b/compensation/urls/compensation.py @@ -17,19 +17,20 @@ from compensation.views.compensation.action import NewCompensationActionView, Ed RemoveCompensationActionView from compensation.views.compensation.state import NewCompensationStateView, EditCompensationStateView, \ RemoveCompensationStateView -from compensation.views.compensation.compensation import new_view, edit_view, \ - remove_view, CompensationIndexView, CompensationIdentifierGeneratorView, CompensationDetailView +from compensation.views.compensation.compensation import \ + remove_view, CompensationIndexView, CompensationIdentifierGeneratorView, CompensationDetailView, \ + NewCompensationFormView, EditCompensationFormView from compensation.views.compensation.log import CompensationLogView urlpatterns = [ # Main compensation path("", CompensationIndexView.as_view(), name="index"), path('new/id', CompensationIdentifierGeneratorView.as_view(), name='new-id'), - path('new/', new_view, name='new'), - path('new', new_view, name='new'), + path('new/', NewCompensationFormView.as_view(), name='new'), + path('new', NewCompensationFormView.as_view(), name='new'), path('', CompensationDetailView.as_view(), name='detail'), path('/log', CompensationLogView.as_view(), name='log'), - path('/edit', edit_view, name='edit'), + path('/edit', EditCompensationFormView.as_view(), name='edit'), path('/remove', remove_view, name='remove'), path('/state/new', NewCompensationStateView.as_view(), name='new-state'), diff --git a/compensation/views/compensation/compensation.py b/compensation/views/compensation/compensation.py index 2403d2b8..c9baedb0 100644 --- a/compensation/views/compensation/compensation.py +++ b/compensation/views/compensation/compensation.py @@ -18,15 +18,12 @@ from compensation.forms.compensation import EditCompensationForm, NewCompensatio from compensation.models import Compensation from compensation.tables.compensation import CompensationTable from intervention.models import Intervention -from konova.contexts import BaseContext from konova.decorators import shared_access_required, default_group_required, login_required_modal -from konova.forms import SimpleGeomForm from konova.forms.modals import RemoveModalForm -from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER from konova.utils.message_templates import COMPENSATION_REMOVED_TEMPLATE, DATA_CHECKED_PREVIOUSLY_TEMPLATE, \ - RECORDED_BLOCKS_EDIT, CHECK_STATE_RESET, FORM_INVALID, PARAMS_INVALID, IDENTIFIER_REPLACED, \ - COMPENSATION_ADDED_TEMPLATE, GEOMETRY_SIMPLIFIED, GEOMETRIES_IGNORED_TEMPLATE -from konova.views.base import BaseIndexView, BaseIdentifierGeneratorView + RECORDED_BLOCKS_EDIT, PARAMS_INVALID +from konova.views.base import BaseIndexView, BaseIdentifierGeneratorView, BaseNewSpatialLocatedObjectFormView, \ + BaseEditSpatialLocatedObjectFormView from konova.views.detail import BaseDetailView @@ -44,74 +41,55 @@ class CompensationIndexView(LoginRequiredMixin, BaseIndexView): return qs -@login_required -@default_group_required -@shared_access_required(Intervention, "intervention_id") -def new_view(request: HttpRequest, intervention_id: str = None): - """ - Renders a view for a new compensation creation +class NewCompensationFormView(BaseNewSpatialLocatedObjectFormView): + _FORM_CLS = NewCompensationForm + _MODEL_CLS = Compensation + _TEMPLATE = "compensation/form/view.html" + _TAB_TITLE = _("New Compensation") + _REDIRECT_URL = "compensation:detail" - Args: - request (HttpRequest): The incoming request - - Returns: - - """ - template = "compensation/form/view.html" - if intervention_id is not None: - try: - intervention = Intervention.objects.get(id=intervention_id) - except ObjectDoesNotExist: - messages.error(request, PARAMS_INVALID) - return redirect("home") - if intervention.is_recorded: - messages.info( - request, - RECORDED_BLOCKS_EDIT - ) - return redirect("intervention:detail", id=intervention_id) - - data_form = NewCompensationForm(request.POST or None, intervention_id=intervention_id) - geom_form = SimpleGeomForm(request.POST or None, read_only=False) - if request.method == "POST": - if data_form.is_valid() and geom_form.is_valid(): - generated_identifier = data_form.cleaned_data.get("identifier", None) - comp = data_form.save(request.user, geom_form) - if generated_identifier != comp.identifier: - messages.info( - request, - IDENTIFIER_REPLACED.format( - generated_identifier, - comp.identifier - ) - ) - messages.success(request, COMPENSATION_ADDED_TEMPLATE.format(comp.identifier)) - if geom_form.has_geometry_simplified(): - messages.info( - request, - GEOMETRY_SIMPLIFIED - ) - - num_ignored_geometries = geom_form.get_num_geometries_ignored() - if num_ignored_geometries > 0: - messages.info( - request, - GEOMETRIES_IGNORED_TEMPLATE.format(num_ignored_geometries) - ) - - return redirect("compensation:detail", id=comp.id) + def _user_has_shared_access(self, user, **kwargs): + # On a new compensation make sure the intervention (if call came directly through an intervention's detail + # view) is shared with the user + intervention_id = kwargs.get("intervention_id", None) + if not intervention_id: + return True else: - messages.error(request, FORM_INVALID, extra_tags="danger",) - else: - # For clarification: nothing in this case - pass - context = { - "form": data_form, - "geom_form": geom_form, - TAB_TITLE_IDENTIFIER: _("New compensation"), - } - context = BaseContext(request, context).context - return render(request, template, context) + intervention = get_object_or_404(Intervention, id=intervention_id) + return intervention.is_shared_with(user) + + def _user_has_permission(self, user): + # User has to be an ets user + return user.is_default_user() + + def dispatch(self, request, *args, **kwargs): + # Make sure there is an existing intervention based on the given id + # Compensations can not exist without an intervention + intervention_id = kwargs.get("intervention_id", None) + if intervention_id: + try: + intervention = Intervention.objects.get(id=intervention_id) + if intervention.is_recorded: + messages.info( + request, + RECORDED_BLOCKS_EDIT + ) + return redirect("intervention:detail", id=intervention_id) + except ObjectDoesNotExist: + messages.error(request, PARAMS_INVALID, extra_tags="danger") + return redirect("home") + return super().dispatch(request, *args, **kwargs) + + +class EditCompensationFormView(BaseEditSpatialLocatedObjectFormView): + _MODEL_CLS = Compensation + _FORM_CLS = EditCompensationForm + _TEMPLATE = "compensation/form/view.html" + _REDIRECT_URL = "compensation:detail" + + def _user_has_permission(self, user): + # User has to be an ets user + return user.is_default_user() class CompensationIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGeneratorView): @@ -119,71 +97,6 @@ class CompensationIdentifierGeneratorView(LoginRequiredMixin, BaseIdentifierGene _REDIRECT_URL = "compensation:index" -@login_required -@default_group_required -@shared_access_required(Compensation, "id") -def edit_view(request: HttpRequest, id: str): - """ - Renders a view for editing compensations - - Args: - request (HttpRequest): The incoming request - - Returns: - - """ - template = "compensation/form/view.html" - # Get object from db - comp = get_object_or_404(Compensation, id=id) - if comp.is_recorded: - messages.info( - request, - RECORDED_BLOCKS_EDIT - ) - return redirect("compensation:detail", id=id) - - # Create forms, initialize with values from db/from POST request - data_form = EditCompensationForm(request.POST or None, instance=comp) - 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 checked to determine whether the user must be informed or not - # about a change of the check state - intervention_is_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_is_checked: - messages.info(request, CHECK_STATE_RESET) - messages.success(request, _("Compensation {} edited").format(comp.identifier)) - if geom_form.has_geometry_simplified(): - messages.info( - request, - GEOMETRY_SIMPLIFIED - ) - - num_ignored_geometries = geom_form.get_num_geometries_ignored() - if num_ignored_geometries > 0: - messages.info( - request, - GEOMETRIES_IGNORED_TEMPLATE.format(num_ignored_geometries) - ) - - return redirect("compensation:detail", id=comp.id) - else: - messages.error(request, FORM_INVALID, extra_tags="danger",) - else: - # For clarification: nothing in this case - pass - context = { - "form": data_form, - "geom_form": geom_form, - TAB_TITLE_IDENTIFIER: _("Edit {}").format(comp.identifier), - } - context = BaseContext(request, context).context - return render(request, template, context) - - class CompensationDetailView(BaseDetailView): _MODEL_CLS = Compensation _TEMPLATE = "compensation/detail/compensation/view.html" diff --git a/konova/views/base.py b/konova/views/base.py index 4961f84d..266ddee0 100644 --- a/konova/views/base.py +++ b/konova/views/base.py @@ -225,10 +225,19 @@ class BaseNewSpatialLocatedObjectFormView(BaseSpatialLocatedObjectFormView): context = self._get_additional_context_data() context = BaseContext(request, additional_context=context).context + context.update( + { + "form": form, + "geom_form": geom_form, + TAB_TITLE_IDENTIFIER: self._TAB_TITLE, + } + ) return render(request, self._TEMPLATE, context) class BaseEditSpatialLocatedObjectFormView(BaseSpatialLocatedObjectFormView): + _TAB_TITLE = _("Edit {}") + def get(self, request: HttpRequest, id: str): obj = get_object_or_404( self._MODEL_CLS, @@ -252,7 +261,7 @@ class BaseEditSpatialLocatedObjectFormView(BaseSpatialLocatedObjectFormView): { "form": form, "geom_form": geom_form, - TAB_TITLE_IDENTIFIER: self._TAB_TITLE, + TAB_TITLE_IDENTIFIER: self._TAB_TITLE.format(obj.identifier), } ) return render(request, self._TEMPLATE, context) diff --git a/locale/de/LC_MESSAGES/django.mo b/locale/de/LC_MESSAGES/django.mo index d35d6028..c9a22673 100644 Binary files a/locale/de/LC_MESSAGES/django.mo and b/locale/de/LC_MESSAGES/django.mo differ diff --git a/locale/de/LC_MESSAGES/django.po b/locale/de/LC_MESSAGES/django.po index 37b506cb..d7e46d3b 100644 --- a/locale/de/LC_MESSAGES/django.po +++ b/locale/de/LC_MESSAGES/django.po @@ -45,7 +45,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-10-19 12:52+0200\n" +"POT-Creation-Date: 2025-10-19 13:56+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -448,11 +448,19 @@ msgid "Select the intervention for which this compensation compensates" msgstr "Wählen Sie den Eingriff, für den diese Kompensation bestimmt ist" #: compensation/forms/compensation.py:114 -#: compensation/views/compensation/compensation.py:111 +#: compensation/views/compensation/compensation.py:161 msgid "New compensation" msgstr "Neue Kompensation" -#: compensation/forms/compensation.py:190 +#: compensation/forms/compensation.py:179 +msgid "" +"This intervention is currently recorded. You cannot add further " +"compensations as long as it is recorded." +msgstr "" +"Dieser Eingriff ist derzeit verzeichnet. " +"Sie können keine weiteren Kompensationen hinzufügen, so lange er verzeichnet ist." + +#: compensation/forms/compensation.py:202 msgid "Edit compensation" msgstr "Bearbeite Kompensation" @@ -1288,18 +1296,25 @@ msgstr "" msgid "Responsible data" msgstr "Daten zu den verantwortlichen Stellen" -#: compensation/views/compensation/compensation.py:34 +#: compensation/views/compensation/compensation.py:35 msgid "Compensations - Overview" msgstr "Kompensationen - Übersicht" -#: compensation/views/compensation/compensation.py:158 +#: compensation/views/compensation/compensation.py:52 +#, fuzzy +#| msgid "New compensation" +msgid "New Compensation" +msgstr "Neue Kompensation" + +#: compensation/views/compensation/compensation.py:208 #: konova/utils/message_templates.py:40 msgid "Compensation {} edited" msgstr "Kompensation {} bearbeitet" -#: compensation/views/compensation/compensation.py:181 -#: compensation/views/eco_account/eco_account.py:159 ema/views/ema.py:213 -#: intervention/views/intervention.py:59 intervention/views/intervention.py:186 +#: compensation/views/compensation/compensation.py:231 +#: compensation/views/eco_account/eco_account.py:159 ema/views/ema.py:59 +#: intervention/views/intervention.py:59 intervention/views/intervention.py:179 +#: konova/views/base.py:239 msgid "Edit {}" msgstr "Bearbeite {}" @@ -1319,8 +1334,7 @@ msgstr "Ökokonto {} bearbeitet" msgid "Eco-account removed" msgstr "Ökokonto entfernt" -#: ema/forms.py:42 ema/tests/unit/test_forms.py:27 ema/views/ema.py:92 -#: ema/views/ema.py:102 +#: ema/forms.py:42 ema/tests/unit/test_forms.py:27 ema/views/ema.py:42 msgid "New EMA" msgstr "Neue EMA hinzufügen" @@ -1348,19 +1362,11 @@ msgstr "" msgid "Payment funded compensation" msgstr "Ersatzzahlungsmaßnahme" -#: ema/views/ema.py:31 +#: ema/views/ema.py:26 msgid "EMAs - Overview" msgstr "EMAs - Übersicht" -#: ema/views/ema.py:70 -msgid "EMA {} added" -msgstr "EMA {} hinzugefügt" - -#: ema/views/ema.py:190 -msgid "EMA {} edited" -msgstr "EMA {} bearbeitet" - -#: ema/views/ema.py:237 +#: ema/views/ema.py:138 msgid "EMA removed" msgstr "EMA entfernt" @@ -1664,11 +1670,11 @@ msgstr "Prüfung durchgeführt" msgid "Interventions - Overview" msgstr "Eingriffe - Übersicht" -#: intervention/views/intervention.py:161 +#: intervention/views/intervention.py:154 msgid "Intervention {} edited" msgstr "Eingriff {} bearbeitet" -#: intervention/views/intervention.py:211 +#: intervention/views/intervention.py:204 msgid "{} removed" msgstr "{} entfernt" @@ -2306,7 +2312,7 @@ msgstr "" msgid "{} added" msgstr "{} hinzugefügt" -#: konova/views/base.py:274 +#: konova/views/base.py:281 msgid "{} edited" msgstr "{} bearbeitet" @@ -3151,3 +3157,9 @@ msgstr "Sie sind kein Mitglied dieses Teams" #: user/views/views.py:204 msgid "Left Team" msgstr "Team verlassen" + +#~ msgid "EMA {} added" +#~ msgstr "EMA {} hinzugefügt" + +#~ msgid "EMA {} edited" +#~ msgstr "EMA {} bearbeitet"