Merge branch 'master' into 138_New_map_client
This commit is contained in:
		
						commit
						c6e784e6d4
					
				@ -33,6 +33,7 @@ class KonovaCodeAdmin(admin.ModelAdmin):
 | 
			
		||||
        "is_selectable",
 | 
			
		||||
        "is_leaf",
 | 
			
		||||
        "parent",
 | 
			
		||||
        "found_in_codelists",
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    search_fields = [
 | 
			
		||||
@ -42,6 +43,12 @@ class KonovaCodeAdmin(admin.ModelAdmin):
 | 
			
		||||
        "short_name",
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    def found_in_codelists(self, obj):
 | 
			
		||||
        codelists = KonovaCodeList.objects.filter(
 | 
			
		||||
            codes__in=[obj]
 | 
			
		||||
        ).values_list("id", flat=True)
 | 
			
		||||
        codelists = "\n".join(str(x) for x in codelists)
 | 
			
		||||
        return codelists
 | 
			
		||||
 | 
			
		||||
#admin.site.register(KonovaCodeList, KonovaCodeListAdmin)
 | 
			
		||||
admin.site.register(KonovaCode, KonovaCodeAdmin)
 | 
			
		||||
 | 
			
		||||
@ -21,16 +21,30 @@ class AbstractCompensationAdmin(BaseObjectAdmin):
 | 
			
		||||
            "identifier",
 | 
			
		||||
            "title",
 | 
			
		||||
            "comment",
 | 
			
		||||
            "after_states",
 | 
			
		||||
            "before_states",
 | 
			
		||||
            "list_after_states",
 | 
			
		||||
            "list_before_states",
 | 
			
		||||
            "geometry",
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
    def get_readonly_fields(self, request, obj=None):
 | 
			
		||||
        return super().get_readonly_fields(request, obj) + [
 | 
			
		||||
            "after_states",
 | 
			
		||||
            "before_states",
 | 
			
		||||
            "list_after_states",
 | 
			
		||||
            "list_before_states",
 | 
			
		||||
            "geometry",
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
    def list_after_states(self, obj):
 | 
			
		||||
        states = obj.after_states.all()
 | 
			
		||||
        states = [str(state) for state in states]
 | 
			
		||||
        states = "\n".join(states)
 | 
			
		||||
        return states
 | 
			
		||||
 | 
			
		||||
    def list_before_states(self, obj):
 | 
			
		||||
        states = obj.before_states.all()
 | 
			
		||||
        states = [str(state) for state in states]
 | 
			
		||||
        states = "\n".join(states)
 | 
			
		||||
        return states
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CompensationAdmin(AbstractCompensationAdmin):
 | 
			
		||||
    autocomplete_fields = [
 | 
			
		||||
 | 
			
		||||
@ -418,6 +418,18 @@ class Compensation(AbstractCompensation, CEFMixin, CoherenceMixin):
 | 
			
		||||
        super().set_status_messages(request)
 | 
			
		||||
        return request
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def is_recorded(self):
 | 
			
		||||
        """ Getter for record status as property
 | 
			
		||||
 | 
			
		||||
        Since compensations inherit their record status from their intervention, the intervention's status is being
 | 
			
		||||
        returned
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        return self.intervention.is_recorded
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CompensationDocument(AbstractDocument):
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
@ -134,7 +134,7 @@ class CompensationTable(BaseTable, TableRenderMixin):
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        parcels = value.get_underlying_parcels().values_list(
 | 
			
		||||
            "gmrkng",
 | 
			
		||||
            "parcel_group__name",
 | 
			
		||||
            flat=True
 | 
			
		||||
        ).distinct()
 | 
			
		||||
        html = render_to_string(
 | 
			
		||||
@ -181,9 +181,7 @@ class CompensationTable(BaseTable, TableRenderMixin):
 | 
			
		||||
        """
 | 
			
		||||
        if value is None:
 | 
			
		||||
            value = User.objects.none()
 | 
			
		||||
        has_access = value.filter(
 | 
			
		||||
            id=self.user.id
 | 
			
		||||
        ).exists()
 | 
			
		||||
        has_access = record.is_shared_with(self.user)
 | 
			
		||||
 | 
			
		||||
        html = self.render_icn(
 | 
			
		||||
            tooltip=_("Full access granted") if has_access else _("Access not granted"),
 | 
			
		||||
@ -295,7 +293,7 @@ class EcoAccountTable(BaseTable, TableRenderMixin):
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        parcels = value.get_underlying_parcels().values_list(
 | 
			
		||||
            "gmrkng",
 | 
			
		||||
            "parcel_group__name",
 | 
			
		||||
            flat=True
 | 
			
		||||
        ).distinct()
 | 
			
		||||
        html = render_to_string(
 | 
			
		||||
@ -343,7 +341,7 @@ class EcoAccountTable(BaseTable, TableRenderMixin):
 | 
			
		||||
        html = ""
 | 
			
		||||
        # Do not use value in here, since value does use unprefetched 'users' manager, where record has already
 | 
			
		||||
        # prefetched users data
 | 
			
		||||
        has_access = self.user in record.users.all()
 | 
			
		||||
        has_access = record.is_shared_with(self.user)
 | 
			
		||||
        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",
 | 
			
		||||
 | 
			
		||||
@ -90,9 +90,15 @@
 | 
			
		||||
                    <tr>
 | 
			
		||||
                        <th scope="row">{% trans 'Last modified' %}</th>
 | 
			
		||||
                        <td class="align-middle">
 | 
			
		||||
                            {{obj.modified.timestamp|default_if_none:""|naturalday}}
 | 
			
		||||
                            <br>
 | 
			
		||||
                            {{obj.modified.user.username}}
 | 
			
		||||
                            {% if obj.modified %}
 | 
			
		||||
                                {{obj.modified.timestamp|default_if_none:""}}
 | 
			
		||||
                                <br>
 | 
			
		||||
                                {{obj.modified.user.username}}
 | 
			
		||||
                            {% else %}
 | 
			
		||||
                                {{obj.created.timestamp|default_if_none:""}}
 | 
			
		||||
                                <br>
 | 
			
		||||
                                {{obj.created.user.username}}
 | 
			
		||||
                            {% endif %}
 | 
			
		||||
                        </td>
 | 
			
		||||
                    </tr>
 | 
			
		||||
                    <tr>
 | 
			
		||||
 | 
			
		||||
@ -73,9 +73,15 @@
 | 
			
		||||
                    <tr>
 | 
			
		||||
                        <th scope="row">{% trans 'Last modified' %}</th>
 | 
			
		||||
                        <td class="align-middle">
 | 
			
		||||
                            {{obj.modified.timestamp|default_if_none:""|naturalday}}
 | 
			
		||||
                            <br>
 | 
			
		||||
                            {{obj.modified.user.username}}
 | 
			
		||||
                            {% if obj.modified %}
 | 
			
		||||
                                {{obj.modified.timestamp|default_if_none:""}}
 | 
			
		||||
                                <br>
 | 
			
		||||
                                {{obj.modified.user.username}}
 | 
			
		||||
                            {% else %}
 | 
			
		||||
                                {{obj.created.timestamp|default_if_none:""}}
 | 
			
		||||
                                <br>
 | 
			
		||||
                                {{obj.created.user.username}}
 | 
			
		||||
                            {% endif %}
 | 
			
		||||
                        </td>
 | 
			
		||||
                    </tr>
 | 
			
		||||
                    <tr>
 | 
			
		||||
 | 
			
		||||
@ -43,14 +43,7 @@
 | 
			
		||||
            {% include 'konova/includes/parcels.html' %}
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="row">
 | 
			
		||||
            <div class="col-sm-6 col-md-6 col-lg-6">
 | 
			
		||||
                <h4>{% trans 'Open in browser' %}</h4>
 | 
			
		||||
                {{ qrcode|safe }}
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col-sm-6 col-md-6 col-lg-6">
 | 
			
		||||
                <h4>{% trans 'View in LANIS' %}</h4>
 | 
			
		||||
                {{ qrcode_lanis|safe }}
 | 
			
		||||
            </div>
 | 
			
		||||
            {% include 'konova/includes/report/qrcodes.html' %}
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
@ -56,14 +56,7 @@
 | 
			
		||||
            {% include 'konova/includes/parcels.html' %}
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="row">
 | 
			
		||||
            <div class="col-sm-6 col-md-6 col-lg-6">
 | 
			
		||||
                <h4>{% trans 'Open in browser' %}</h4>
 | 
			
		||||
                {{ qrcode|safe }}
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col-sm-6 col-md-6 col-lg-6">
 | 
			
		||||
                <h4>{% trans 'View in LANIS' %}</h4>
 | 
			
		||||
                {{ qrcode_lanis|safe }}
 | 
			
		||||
            </div>
 | 
			
		||||
            {% include 'konova/includes/report/qrcodes.html' %}
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
@ -60,8 +60,9 @@ class CompensationWorkflowTestCase(BaseWorkflowTestCase):
 | 
			
		||||
 | 
			
		||||
        # Preserve the current number of intervention's compensations
 | 
			
		||||
        num_compensations = self.intervention.compensations.count()
 | 
			
		||||
        self.client_user.post(new_url, post_data)
 | 
			
		||||
        response = self.client_user.post(new_url, post_data)
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(302, response.status_code)
 | 
			
		||||
        self.intervention.refresh_from_db()
 | 
			
		||||
        self.assertEqual(num_compensations + 1, self.intervention.compensations.count())
 | 
			
		||||
        new_compensation = self.intervention.compensations.get(identifier=test_id)
 | 
			
		||||
@ -261,3 +262,26 @@ class CompensationWorkflowTestCase(BaseWorkflowTestCase):
 | 
			
		||||
        self.assertIn(recorded, self.compensation.log.all())
 | 
			
		||||
        self.assertEqual(pre_record_log_count + 1, self.compensation.log.count())
 | 
			
		||||
 | 
			
		||||
    def test_non_editable_after_recording(self):
 | 
			
		||||
        """ Tests that the compensation can not be edited after being recorded
 | 
			
		||||
 | 
			
		||||
        User must be redirected to another page
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        self.assertIsNotNone(self.compensation)
 | 
			
		||||
        self.assertFalse(self.compensation.is_recorded)
 | 
			
		||||
        edit_url = reverse("compensation:edit", args=(self.compensation.id,))
 | 
			
		||||
        response = self.client_user.get(edit_url)
 | 
			
		||||
        has_redirect = response.status_code == 302
 | 
			
		||||
        self.assertFalse(has_redirect)
 | 
			
		||||
 | 
			
		||||
        self.compensation.intervention.set_recorded(self.user)
 | 
			
		||||
        self.assertTrue(self.compensation.is_recorded)
 | 
			
		||||
 | 
			
		||||
        edit_url = reverse("compensation:edit", args=(self.compensation.id,))
 | 
			
		||||
        response = self.client_user.get(edit_url)
 | 
			
		||||
        has_redirect = response.status_code == 302
 | 
			
		||||
        self.assertTrue(has_redirect)
 | 
			
		||||
        self.compensation.intervention.set_unrecorded(self.user)
 | 
			
		||||
 | 
			
		||||
@ -302,3 +302,27 @@ class EcoAccountWorkflowTestCase(BaseWorkflowTestCase):
 | 
			
		||||
        self.assertEqual(pre_edit_account_log_count + 1, account.log.count())
 | 
			
		||||
        self.assertEqual(intervention.log.first().action, UserAction.EDITED)
 | 
			
		||||
        self.assertEqual(account.log.first().action, UserAction.EDITED)
 | 
			
		||||
 | 
			
		||||
    def test_non_editable_after_recording(self):
 | 
			
		||||
        """ Tests that the eco_account can not be edited after being recorded
 | 
			
		||||
 | 
			
		||||
        User must be redirected to another page
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        self.assertIsNotNone(self.eco_account)
 | 
			
		||||
        self.assertFalse(self.eco_account.is_recorded)
 | 
			
		||||
        edit_url = reverse("compensation:acc:edit", args=(self.eco_account.id,))
 | 
			
		||||
        response = self.client_user.get(edit_url)
 | 
			
		||||
        has_redirect = response.status_code == 302
 | 
			
		||||
        self.assertFalse(has_redirect)
 | 
			
		||||
 | 
			
		||||
        self.eco_account.set_recorded(self.user)
 | 
			
		||||
        self.assertTrue(self.eco_account.is_recorded)
 | 
			
		||||
 | 
			
		||||
        edit_url = reverse("compensation:acc:edit", args=(self.eco_account.id,))
 | 
			
		||||
        response = self.client_user.get(edit_url)
 | 
			
		||||
        has_redirect = response.status_code == 302
 | 
			
		||||
        self.assertTrue(has_redirect)
 | 
			
		||||
        self.eco_account.set_unrecorded(self.user)
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
from django.contrib.auth.decorators import login_required
 | 
			
		||||
from django.core.exceptions import ObjectDoesNotExist
 | 
			
		||||
from django.db.models import Sum
 | 
			
		||||
from django.http import HttpRequest, JsonResponse
 | 
			
		||||
from django.shortcuts import render
 | 
			
		||||
@ -22,7 +23,7 @@ from konova.utils.message_templates import FORM_INVALID, IDENTIFIER_REPLACED, DA
 | 
			
		||||
    CHECKED_RECORDED_RESET, COMPENSATION_ADDED_TEMPLATE, COMPENSATION_REMOVED_TEMPLATE, DOCUMENT_ADDED, \
 | 
			
		||||
    COMPENSATION_STATE_REMOVED, COMPENSATION_STATE_ADDED, COMPENSATION_ACTION_REMOVED, COMPENSATION_ACTION_ADDED, \
 | 
			
		||||
    DEADLINE_ADDED, DEADLINE_REMOVED, DOCUMENT_EDITED, COMPENSATION_STATE_EDITED, COMPENSATION_ACTION_EDITED, \
 | 
			
		||||
    DEADLINE_EDITED
 | 
			
		||||
    DEADLINE_EDITED, RECORDED_BLOCKS_EDIT, PARAMS_INVALID
 | 
			
		||||
from konova.utils.user_checks import in_group
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -69,6 +70,19 @@ def new_view(request: HttpRequest, intervention_id: str = None):
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    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":
 | 
			
		||||
@ -134,6 +148,13 @@ def edit_view(request: HttpRequest, id: str):
 | 
			
		||||
    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)
 | 
			
		||||
@ -596,14 +617,12 @@ def report_view(request: HttpRequest, id: str):
 | 
			
		||||
        instance=comp
 | 
			
		||||
    )
 | 
			
		||||
    parcels = comp.get_underlying_parcels()
 | 
			
		||||
    qrcode_img = generate_qr_code(
 | 
			
		||||
        request.build_absolute_uri(reverse("compensation:report", args=(id,))),
 | 
			
		||||
        10
 | 
			
		||||
    )
 | 
			
		||||
    qrcode_img_lanis = generate_qr_code(
 | 
			
		||||
        comp.get_LANIS_link(),
 | 
			
		||||
        7
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    qrcode_url = request.build_absolute_uri(reverse("compensation:report", args=(id,)))
 | 
			
		||||
    qrcode_img = generate_qr_code(qrcode_url, 10)
 | 
			
		||||
    qrcode_lanis_url = comp.get_LANIS_link()
 | 
			
		||||
    qrcode_img_lanis = generate_qr_code(qrcode_lanis_url, 7)
 | 
			
		||||
 | 
			
		||||
    # Order states by surface
 | 
			
		||||
    before_states = comp.before_states.all().order_by("-surface").prefetch_related("biotope_type")
 | 
			
		||||
    after_states = comp.after_states.all().order_by("-surface").prefetch_related("biotope_type")
 | 
			
		||||
@ -611,8 +630,14 @@ def report_view(request: HttpRequest, id: str):
 | 
			
		||||
 | 
			
		||||
    context = {
 | 
			
		||||
        "obj": comp,
 | 
			
		||||
        "qrcode": qrcode_img,
 | 
			
		||||
        "qrcode_lanis": qrcode_img_lanis,
 | 
			
		||||
        "qrcode": {
 | 
			
		||||
            "img": qrcode_img,
 | 
			
		||||
            "url": qrcode_url,
 | 
			
		||||
        },
 | 
			
		||||
        "qrcode_lanis": {
 | 
			
		||||
            "img": qrcode_img_lanis,
 | 
			
		||||
            "url": qrcode_lanis_url,
 | 
			
		||||
        },
 | 
			
		||||
        "has_access": False,  # disables action buttons during rendering
 | 
			
		||||
        "before_states": before_states,
 | 
			
		||||
        "after_states": after_states,
 | 
			
		||||
 | 
			
		||||
@ -35,7 +35,8 @@ from konova.utils.generators import generate_qr_code
 | 
			
		||||
from konova.utils.message_templates import IDENTIFIER_REPLACED, FORM_INVALID, DATA_UNSHARED, DATA_UNSHARED_EXPLANATION, \
 | 
			
		||||
    CANCEL_ACC_RECORDED_OR_DEDUCTED, DEDUCTION_REMOVED, DEDUCTION_ADDED, DOCUMENT_ADDED, COMPENSATION_STATE_REMOVED, \
 | 
			
		||||
    COMPENSATION_STATE_ADDED, COMPENSATION_ACTION_REMOVED, COMPENSATION_ACTION_ADDED, DEADLINE_ADDED, DEADLINE_REMOVED, \
 | 
			
		||||
    DEDUCTION_EDITED, DOCUMENT_EDITED, COMPENSATION_STATE_EDITED, COMPENSATION_ACTION_EDITED, DEADLINE_EDITED
 | 
			
		||||
    DEDUCTION_EDITED, DOCUMENT_EDITED, COMPENSATION_STATE_EDITED, COMPENSATION_ACTION_EDITED, DEADLINE_EDITED, \
 | 
			
		||||
    RECORDED_BLOCKS_EDIT
 | 
			
		||||
from konova.utils.user_checks import in_group
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -145,6 +146,13 @@ def edit_view(request: HttpRequest, id: str):
 | 
			
		||||
    template = "compensation/form/view.html"
 | 
			
		||||
    # Get object from db
 | 
			
		||||
    acc = get_object_or_404(EcoAccount, id=id)
 | 
			
		||||
    if acc.is_recorded:
 | 
			
		||||
        messages.info(
 | 
			
		||||
            request,
 | 
			
		||||
            RECORDED_BLOCKS_EDIT
 | 
			
		||||
        )
 | 
			
		||||
        return redirect("compensation:acc:detail", id=id)
 | 
			
		||||
 | 
			
		||||
    # Create forms, initialize with values from db/from POST request
 | 
			
		||||
    data_form = EditEcoAccountForm(request.POST or None, instance=acc)
 | 
			
		||||
    geom_form = SimpleGeomForm(request.POST or None, read_only=False, instance=acc)
 | 
			
		||||
@ -731,18 +739,16 @@ def report_view(request:HttpRequest, id: str):
 | 
			
		||||
        instance=acc
 | 
			
		||||
    )
 | 
			
		||||
    parcels = acc.get_underlying_parcels()
 | 
			
		||||
    qrcode_img = generate_qr_code(
 | 
			
		||||
        request.build_absolute_uri(reverse("ema:report", args=(id,))),
 | 
			
		||||
        10
 | 
			
		||||
    )
 | 
			
		||||
    qrcode_img_lanis = generate_qr_code(
 | 
			
		||||
        acc.get_LANIS_link(),
 | 
			
		||||
        7
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    qrcode_url = request.build_absolute_uri(reverse("ema:report", args=(id,)))
 | 
			
		||||
    qrcode_img = generate_qr_code(qrcode_url, 10)
 | 
			
		||||
    qrcode_lanis_url = acc.get_LANIS_link()
 | 
			
		||||
    qrcode_img_lanis = generate_qr_code(qrcode_lanis_url, 7)
 | 
			
		||||
 | 
			
		||||
    # Order states by surface
 | 
			
		||||
    before_states = acc.before_states.all().order_by("-surface").select_related("biotope_type__parent")
 | 
			
		||||
    after_states = acc.after_states.all().order_by("-surface").select_related("biotope_type__parent")
 | 
			
		||||
    actions = acc.actions.all().select_related("action_type__parent")
 | 
			
		||||
    actions = acc.actions.all().prefetch_related("action_type__parent")
 | 
			
		||||
 | 
			
		||||
    # Reduce amount of db fetched data to the bare minimum we need in the template (deduction's intervention id and identifier)
 | 
			
		||||
    deductions = acc.deductions.all()\
 | 
			
		||||
@ -752,8 +758,14 @@ def report_view(request:HttpRequest, id: str):
 | 
			
		||||
 | 
			
		||||
    context = {
 | 
			
		||||
        "obj": acc,
 | 
			
		||||
        "qrcode": qrcode_img,
 | 
			
		||||
        "qrcode_lanis": qrcode_img_lanis,
 | 
			
		||||
        "qrcode": {
 | 
			
		||||
            "img": qrcode_img,
 | 
			
		||||
            "url": qrcode_url,
 | 
			
		||||
        },
 | 
			
		||||
        "qrcode_lanis": {
 | 
			
		||||
            "img": qrcode_img_lanis,
 | 
			
		||||
            "url": qrcode_lanis_url,
 | 
			
		||||
        },
 | 
			
		||||
        "has_access": False,  # disables action buttons during rendering
 | 
			
		||||
        "before_states": before_states,
 | 
			
		||||
        "after_states": after_states,
 | 
			
		||||
 | 
			
		||||
@ -104,7 +104,7 @@ class EmaTable(BaseTable, TableRenderMixin):
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        parcels = value.get_underlying_parcels().values_list(
 | 
			
		||||
            "gmrkng",
 | 
			
		||||
            "parcel_group__name",
 | 
			
		||||
            flat=True
 | 
			
		||||
        ).distinct()
 | 
			
		||||
        html = render_to_string(
 | 
			
		||||
@ -151,9 +151,7 @@ class EmaTable(BaseTable, TableRenderMixin):
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        html = ""
 | 
			
		||||
        has_access = value.filter(
 | 
			
		||||
            id=self.user.id
 | 
			
		||||
        ).exists()
 | 
			
		||||
        has_access = record.is_shared_with(self.user)
 | 
			
		||||
 | 
			
		||||
        html += self.render_icn(
 | 
			
		||||
            tooltip=_("Full access granted") if has_access else _("Access not granted"),
 | 
			
		||||
 | 
			
		||||
@ -60,14 +60,13 @@
 | 
			
		||||
                        <th scope="row">{% trans 'Last modified' %}</th>
 | 
			
		||||
                        <td class="align-middle">
 | 
			
		||||
                            {% if obj.modified %}
 | 
			
		||||
                                {{obj.modified.timestamp|default_if_none:""|naturalday}}
 | 
			
		||||
                                {{obj.modified.timestamp|default_if_none:""}}
 | 
			
		||||
                                <br>
 | 
			
		||||
                                {{obj.modified.user.username}}
 | 
			
		||||
                            {% else %}
 | 
			
		||||
                                {{obj.created.timestamp|default_if_none:""|naturalday}}
 | 
			
		||||
                                {{obj.created.timestamp|default_if_none:""}}
 | 
			
		||||
                                <br>
 | 
			
		||||
                                {{obj.created.user.username}}
 | 
			
		||||
 | 
			
		||||
                            {% endif %}
 | 
			
		||||
                        </td>
 | 
			
		||||
                    </tr>
 | 
			
		||||
 | 
			
		||||
@ -43,14 +43,7 @@
 | 
			
		||||
            {% include 'konova/includes/parcels.html' %}
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="row">
 | 
			
		||||
            <div class="col-sm-6 col-md-6 col-lg-6">
 | 
			
		||||
                <h4>{% trans 'Open in browser' %}</h4>
 | 
			
		||||
                {{ qrcode|safe }}
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col-sm-6 col-md-6 col-lg-6">
 | 
			
		||||
                <h4>{% trans 'View in LANIS' %}</h4>
 | 
			
		||||
                {{ qrcode_lanis|safe }}
 | 
			
		||||
            </div>
 | 
			
		||||
            {% include 'konova/includes/report/qrcodes.html' %}
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
@ -117,6 +117,32 @@ class EmaWorkflowTestCase(BaseWorkflowTestCase):
 | 
			
		||||
        self.assertEqual(pre_edit_log_count + 1, self.ema.log.count())
 | 
			
		||||
        self.assertEqual(self.ema.log.first().action, UserAction.EDITED)
 | 
			
		||||
 | 
			
		||||
    def test_non_editable_after_recording(self):
 | 
			
		||||
        """ Tests that the EMA can not be edited after being recorded
 | 
			
		||||
 | 
			
		||||
        User must be redirected to another page
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        self.superuser.groups.add(self.groups.get(name=ETS_GROUP))
 | 
			
		||||
        self.assertIsNotNone(self.ema)
 | 
			
		||||
        self.ema.share_with_user(self.superuser)
 | 
			
		||||
        self.assertFalse(self.ema.is_recorded)
 | 
			
		||||
        edit_url = reverse("ema:edit", args=(self.ema.id,))
 | 
			
		||||
        response = self.client_user.get(edit_url)
 | 
			
		||||
        has_redirect = response.status_code == 302
 | 
			
		||||
        self.assertFalse(has_redirect)
 | 
			
		||||
 | 
			
		||||
        self.ema.set_recorded(self.superuser)
 | 
			
		||||
        self.assertTrue(self.ema.is_recorded)
 | 
			
		||||
 | 
			
		||||
        edit_url = reverse("ema:edit", args=(self.ema.id,))
 | 
			
		||||
        response = self.client_user.get(edit_url)
 | 
			
		||||
        has_redirect = response.status_code == 302
 | 
			
		||||
        self.assertTrue(has_redirect)
 | 
			
		||||
        self.ema.set_unrecorded(self.superuser)
 | 
			
		||||
        
 | 
			
		||||
    def test_recordability(self):
 | 
			
		||||
        """
 | 
			
		||||
        This tests if the recordability of the Ema is triggered by the quality of it's data (e.g. not all fields filled)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										33
									
								
								ema/views.py
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								ema/views.py
									
									
									
									
									
								
							@ -26,7 +26,7 @@ from konova.utils.generators import generate_qr_code
 | 
			
		||||
from konova.utils.message_templates import IDENTIFIER_REPLACED, FORM_INVALID, DATA_UNSHARED, DATA_UNSHARED_EXPLANATION, \
 | 
			
		||||
    DOCUMENT_ADDED, COMPENSATION_STATE_REMOVED, COMPENSATION_STATE_ADDED, COMPENSATION_ACTION_REMOVED, \
 | 
			
		||||
    COMPENSATION_ACTION_ADDED, DEADLINE_ADDED, DEADLINE_REMOVED, DOCUMENT_EDITED, COMPENSATION_STATE_EDITED, \
 | 
			
		||||
    COMPENSATION_ACTION_EDITED, DEADLINE_EDITED
 | 
			
		||||
    COMPENSATION_ACTION_EDITED, DEADLINE_EDITED, RECORDED_BLOCKS_EDIT
 | 
			
		||||
from konova.utils.user_checks import in_group
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -213,6 +213,13 @@ def edit_view(request: HttpRequest, id: str):
 | 
			
		||||
    template = "compensation/form/view.html"
 | 
			
		||||
    # Get object from db
 | 
			
		||||
    ema = get_object_or_404(Ema, id=id)
 | 
			
		||||
    if ema.is_recorded:
 | 
			
		||||
        messages.info(
 | 
			
		||||
            request,
 | 
			
		||||
            RECORDED_BLOCKS_EDIT
 | 
			
		||||
        )
 | 
			
		||||
        return redirect("ema:detail", id=id)
 | 
			
		||||
 | 
			
		||||
    # Create forms, initialize with values from db/from POST request
 | 
			
		||||
    data_form = EditEmaForm(request.POST or None, instance=ema)
 | 
			
		||||
    geom_form = SimpleGeomForm(request.POST or None, read_only=False, instance=ema)
 | 
			
		||||
@ -563,14 +570,12 @@ def report_view(request:HttpRequest, id: str):
 | 
			
		||||
        instance=ema,
 | 
			
		||||
    )
 | 
			
		||||
    parcels = ema.get_underlying_parcels()
 | 
			
		||||
    qrcode_img = generate_qr_code(
 | 
			
		||||
        request.build_absolute_uri(reverse("ema:report", args=(id,))),
 | 
			
		||||
        10
 | 
			
		||||
    )
 | 
			
		||||
    qrcode_img_lanis = generate_qr_code(
 | 
			
		||||
        ema.get_LANIS_link(),
 | 
			
		||||
        7
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    qrcode_url = request.build_absolute_uri(reverse("ema:report", args=(id,)))
 | 
			
		||||
    qrcode_img = generate_qr_code(qrcode_url, 10)
 | 
			
		||||
    qrcode_lanis_url = ema.get_LANIS_link()
 | 
			
		||||
    qrcode_img_lanis = generate_qr_code(qrcode_lanis_url, 7)
 | 
			
		||||
 | 
			
		||||
    # Order states by surface
 | 
			
		||||
    before_states = ema.before_states.all().order_by("-surface").prefetch_related("biotope_type")
 | 
			
		||||
    after_states = ema.after_states.all().order_by("-surface").prefetch_related("biotope_type")
 | 
			
		||||
@ -578,8 +583,14 @@ def report_view(request:HttpRequest, id: str):
 | 
			
		||||
 | 
			
		||||
    context = {
 | 
			
		||||
        "obj": ema,
 | 
			
		||||
        "qrcode": qrcode_img,
 | 
			
		||||
        "qrcode_lanis": qrcode_img_lanis,
 | 
			
		||||
        "qrcode": {
 | 
			
		||||
            "img": qrcode_img,
 | 
			
		||||
            "url": qrcode_url
 | 
			
		||||
        },
 | 
			
		||||
        "qrcode_lanis": {
 | 
			
		||||
            "img": qrcode_img_lanis,
 | 
			
		||||
            "url": qrcode_lanis_url
 | 
			
		||||
        },
 | 
			
		||||
        "has_access": False,  # disables action buttons during rendering
 | 
			
		||||
        "before_states": before_states,
 | 
			
		||||
        "after_states": after_states,
 | 
			
		||||
 | 
			
		||||
@ -25,12 +25,14 @@ class InterventionAdmin(BaseObjectAdmin):
 | 
			
		||||
            "checked",
 | 
			
		||||
            "recorded",
 | 
			
		||||
            "users",
 | 
			
		||||
            "geometry",
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
    def get_readonly_fields(self, request, obj=None):
 | 
			
		||||
        return super().get_readonly_fields(request, obj) + [
 | 
			
		||||
            "checked",
 | 
			
		||||
            "recorded",
 | 
			
		||||
            "geometry",
 | 
			
		||||
        ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -427,13 +427,22 @@ class NewDeductionModalForm(BaseModalForm):
 | 
			
		||||
        """
 | 
			
		||||
        super_result = super().is_valid()
 | 
			
		||||
        acc = self.cleaned_data["account"]
 | 
			
		||||
        intervention = self.cleaned_data["intervention"]
 | 
			
		||||
        objects_valid = True
 | 
			
		||||
 | 
			
		||||
        if not acc.recorded:
 | 
			
		||||
            self.add_error(
 | 
			
		||||
                "account",
 | 
			
		||||
                _("Eco-account {} is not recorded yet. You can only deduct from recorded accounts.").format(acc.identifier)
 | 
			
		||||
            )
 | 
			
		||||
            return False
 | 
			
		||||
            objects_valid = False
 | 
			
		||||
 | 
			
		||||
        if intervention.is_recorded:
 | 
			
		||||
            self.add_error(
 | 
			
		||||
                "intervention",
 | 
			
		||||
                _("Intervention {} is currently recorded. To change any data on it, the entry must be unrecorded.").format(intervention.identifier)
 | 
			
		||||
            )
 | 
			
		||||
            objects_valid = False
 | 
			
		||||
 | 
			
		||||
        rest_surface = self._get_available_surface(acc)
 | 
			
		||||
        form_surface = float(self.cleaned_data["surface"])
 | 
			
		||||
@ -447,7 +456,7 @@ class NewDeductionModalForm(BaseModalForm):
 | 
			
		||||
                    format_german_float(rest_surface),
 | 
			
		||||
                ),
 | 
			
		||||
            )
 | 
			
		||||
        return is_valid_surface and super_result
 | 
			
		||||
        return is_valid_surface and objects_valid and super_result
 | 
			
		||||
 | 
			
		||||
    def __create_deduction(self):
 | 
			
		||||
        """ Creates the deduction
 | 
			
		||||
 | 
			
		||||
@ -131,7 +131,7 @@ class InterventionTable(BaseTable, TableRenderMixin):
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        parcels = value.get_underlying_parcels().values_list(
 | 
			
		||||
            "gmrkng",
 | 
			
		||||
            "parcel_group__name",
 | 
			
		||||
            flat=True
 | 
			
		||||
        ).distinct()
 | 
			
		||||
        html = render_to_string(
 | 
			
		||||
@ -177,9 +177,7 @@ class InterventionTable(BaseTable, TableRenderMixin):
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        html = ""
 | 
			
		||||
        has_access = value.filter(
 | 
			
		||||
            id=self.user.id
 | 
			
		||||
        ).exists()
 | 
			
		||||
        has_access = record.is_shared_with(self.user)
 | 
			
		||||
 | 
			
		||||
        html += self.render_icn(
 | 
			
		||||
            tooltip=_("Full access granted") if has_access else _("Access not granted"),
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
{% extends 'base.html' %}
 | 
			
		||||
{% load i18n l10n static fontawesome_5 humanize %}
 | 
			
		||||
{% load i18n l10n static fontawesome_5 %}
 | 
			
		||||
 | 
			
		||||
{% block head %}
 | 
			
		||||
    {% comment %}
 | 
			
		||||
@ -106,9 +106,15 @@
 | 
			
		||||
                    <tr>
 | 
			
		||||
                        <th scope="row">{% trans 'Last modified' %}</th>
 | 
			
		||||
                        <td class="align-middle">
 | 
			
		||||
                            {{obj.created.timestamp|default_if_none:""|naturalday}}
 | 
			
		||||
                            <br>
 | 
			
		||||
                            {{obj.created.user.username}}
 | 
			
		||||
                            {% if obj.modified %}
 | 
			
		||||
                                {{obj.modified.timestamp|default_if_none:""}}
 | 
			
		||||
                                <br>
 | 
			
		||||
                                {{obj.modified.user.username}}
 | 
			
		||||
                            {% else %}
 | 
			
		||||
                                {{obj.created.timestamp|default_if_none:""}}
 | 
			
		||||
                                <br>
 | 
			
		||||
                                {{obj.created.user.username}}
 | 
			
		||||
                            {% endif %}
 | 
			
		||||
                        </td>
 | 
			
		||||
                    </tr>
 | 
			
		||||
                    <tr>
 | 
			
		||||
 | 
			
		||||
@ -102,14 +102,7 @@
 | 
			
		||||
            {% include 'konova/includes/parcels.html' %}
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="row">
 | 
			
		||||
            <div class="col-sm-6 col-md-6 col-lg-6">
 | 
			
		||||
                <h4>{% trans 'Open in browser' %}</h4>
 | 
			
		||||
                {{ qrcode|safe }}
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="col-sm-6 col-md-6 col-lg-6">
 | 
			
		||||
                <h4>{% trans 'View in LANIS' %}</h4>
 | 
			
		||||
                {{ qrcode_lanis|safe }}
 | 
			
		||||
            </div>
 | 
			
		||||
            {% include 'konova/includes/report/qrcodes.html' %}
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
@ -89,6 +89,30 @@ class InterventionWorkflowTestCase(BaseWorkflowTestCase):
 | 
			
		||||
        self.assertIn(self.superuser, obj.users.all())
 | 
			
		||||
        self.assertEqual(1, obj.users.count())
 | 
			
		||||
 | 
			
		||||
    def test_non_editable_after_recording(self):
 | 
			
		||||
        """ Tests that the intervention can not be edited after being recorded
 | 
			
		||||
 | 
			
		||||
        User must be redirected to another page
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        self.assertIsNotNone(self.intervention)
 | 
			
		||||
        self.assertFalse(self.intervention.is_recorded)
 | 
			
		||||
        edit_url = reverse("intervention:edit", args=(self.intervention.id,))
 | 
			
		||||
        response = self.client_user.get(edit_url)
 | 
			
		||||
        has_redirect = response.status_code == 302
 | 
			
		||||
        self.assertFalse(has_redirect)
 | 
			
		||||
 | 
			
		||||
        self.intervention.set_recorded(self.user)
 | 
			
		||||
        self.assertTrue(self.intervention.is_recorded)
 | 
			
		||||
 | 
			
		||||
        edit_url = reverse("intervention:edit", args=(self.intervention.id,))
 | 
			
		||||
        response = self.client_user.get(edit_url)
 | 
			
		||||
        has_redirect = response.status_code == 302
 | 
			
		||||
        self.assertTrue(has_redirect)
 | 
			
		||||
        self.intervention.set_unrecorded(self.user)
 | 
			
		||||
 | 
			
		||||
    def test_checkability(self):
 | 
			
		||||
        """ Tests that the intervention can only be checked if all required data has been added
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -80,7 +80,7 @@ class EgonGmlBuilder:
 | 
			
		||||
        Returns:
 | 
			
		||||
            str
 | 
			
		||||
        """
 | 
			
		||||
        gmrkng_code = "000000"
 | 
			
		||||
        gmrkng_code = "{0:06d}".format(int(parcel.parcel_group.key) or 0)
 | 
			
		||||
        flr_code = "{0:03d}".format(int(parcel.flr or 0))
 | 
			
		||||
        flrstckzhlr_code = "{0:05d}".format(int(parcel.flrstck_zhlr or 0))
 | 
			
		||||
        flrstcknnr_code = "{0:06d}".format(int(parcel.flrstck_nnr or 0))
 | 
			
		||||
@ -124,13 +124,13 @@ class EgonGmlBuilder:
 | 
			
		||||
                "oneo:ortsangabe": {
 | 
			
		||||
                    "oneo:Ortsangaben": {
 | 
			
		||||
                        "oneo:kreisSchluessel": {
 | 
			
		||||
                            "xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/588/{parcel.district.krs}",
 | 
			
		||||
                            "xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/588/{parcel.district.key}",
 | 
			
		||||
                        },
 | 
			
		||||
                        "oneo:gemeindeSchluessel": {
 | 
			
		||||
                            "xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/910/{parcel.district.gmnd}",
 | 
			
		||||
                            "xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/910/{parcel.municipal.key}",
 | 
			
		||||
                        },
 | 
			
		||||
                        "oneo:verbandsgemeindeSchluessel": {
 | 
			
		||||
                            "xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/589/{parcel.gmrkng}",
 | 
			
		||||
                            "xlink:href": f"http://register.naturschutz.rlp.de/repository/services/referenzliste/589/{None}",
 | 
			
		||||
                        },
 | 
			
		||||
                        "oneo:flurstuecksKennzeichen": self._gen_flurstuecksKennzeichen(parcel),
 | 
			
		||||
                    }
 | 
			
		||||
@ -156,6 +156,10 @@ class EgonGmlBuilder:
 | 
			
		||||
 | 
			
		||||
    def build_gml(self):
 | 
			
		||||
        comp_type, comp_type_code = self._gen_kompensationsArt()
 | 
			
		||||
        payment_date = self.intervention.payments.first().due_on
 | 
			
		||||
        if payment_date is not None:
 | 
			
		||||
            payment_date = payment_date.strftime(DEFAULT_DATE_FORMAT)
 | 
			
		||||
 | 
			
		||||
        xml_dict = {
 | 
			
		||||
            "wfs:FeatureCollection": {
 | 
			
		||||
                "@xmlns:wfs": "http://www.opengis.net/wfs",
 | 
			
		||||
@ -207,7 +211,7 @@ class EgonGmlBuilder:
 | 
			
		||||
                    },
 | 
			
		||||
                    "oneo:zulassung": {
 | 
			
		||||
                        "oneo:Zulassungstermin": {
 | 
			
		||||
                            "oneo:bauBeginn": self.intervention.payments.first().due_on.strftime(DEFAULT_DATE_FORMAT),
 | 
			
		||||
                            "oneo:bauBeginn": payment_date,
 | 
			
		||||
                            "oneo:erlass": self.intervention.legal.registration_date.strftime(DEFAULT_DATE_FORMAT),
 | 
			
		||||
                            "oneo:rechtsKraft": self.intervention.legal.binding_date.strftime(DEFAULT_DATE_FORMAT),
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
@ -18,7 +18,8 @@ from konova.utils.documents import remove_document, get_document
 | 
			
		||||
from konova.utils.generators import generate_qr_code
 | 
			
		||||
from konova.utils.message_templates import INTERVENTION_INVALID, FORM_INVALID, IDENTIFIER_REPLACED, \
 | 
			
		||||
    CHECKED_RECORDED_RESET, DEDUCTION_REMOVED, DEDUCTION_ADDED, REVOCATION_ADDED, REVOCATION_REMOVED, \
 | 
			
		||||
    COMPENSATION_REMOVED_TEMPLATE, DOCUMENT_ADDED, DEDUCTION_EDITED, REVOCATION_EDITED, DOCUMENT_EDITED
 | 
			
		||||
    COMPENSATION_REMOVED_TEMPLATE, DOCUMENT_ADDED, DEDUCTION_EDITED, REVOCATION_EDITED, DOCUMENT_EDITED, \
 | 
			
		||||
    RECORDED_BLOCKS_EDIT
 | 
			
		||||
from konova.utils.user_checks import in_group
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -302,6 +303,13 @@ def edit_view(request: HttpRequest, id: str):
 | 
			
		||||
    template = "intervention/form/view.html"
 | 
			
		||||
    # Get object from db
 | 
			
		||||
    intervention = get_object_or_404(Intervention, id=id)
 | 
			
		||||
    if intervention.is_recorded:
 | 
			
		||||
        messages.info(
 | 
			
		||||
            request,
 | 
			
		||||
            RECORDED_BLOCKS_EDIT
 | 
			
		||||
        )
 | 
			
		||||
        return redirect("intervention:detail", id=id)
 | 
			
		||||
 | 
			
		||||
    # Create forms, initialize with values from db/from POST request
 | 
			
		||||
    data_form = EditInterventionForm(request.POST or None, instance=intervention)
 | 
			
		||||
    geom_form = SimpleGeomForm(request.POST or None, read_only=False, instance=intervention)
 | 
			
		||||
@ -693,19 +701,22 @@ def report_view(request:HttpRequest, id: str):
 | 
			
		||||
    distinct_deductions = intervention.deductions.all().distinct(
 | 
			
		||||
        "account"
 | 
			
		||||
    )
 | 
			
		||||
    qrcode_img = generate_qr_code(
 | 
			
		||||
        request.build_absolute_uri(reverse("intervention:report", args=(id,))),
 | 
			
		||||
        10
 | 
			
		||||
    )
 | 
			
		||||
    qrcode_img_lanis = generate_qr_code(
 | 
			
		||||
        intervention.get_LANIS_link(),
 | 
			
		||||
        7
 | 
			
		||||
    )
 | 
			
		||||
    qrcode_url = request.build_absolute_uri(reverse("intervention:report", args=(id,)))
 | 
			
		||||
    qrcode_img = generate_qr_code(qrcode_url, 10)
 | 
			
		||||
    qrcode_lanis_url = intervention.get_LANIS_link()
 | 
			
		||||
    qrcode_img_lanis = generate_qr_code(qrcode_lanis_url, 7)
 | 
			
		||||
 | 
			
		||||
    context = {
 | 
			
		||||
        "obj": intervention,
 | 
			
		||||
        "deductions": distinct_deductions,
 | 
			
		||||
        "qrcode": qrcode_img,
 | 
			
		||||
        "qrcode_lanis": qrcode_img_lanis,
 | 
			
		||||
        "qrcode": {
 | 
			
		||||
            "img": qrcode_img,
 | 
			
		||||
            "url": qrcode_url,
 | 
			
		||||
        },
 | 
			
		||||
        "qrcode_lanis": {
 | 
			
		||||
            "img": qrcode_img_lanis,
 | 
			
		||||
            "url": qrcode_lanis_url,
 | 
			
		||||
        },
 | 
			
		||||
        "geom_form": geom_form,
 | 
			
		||||
        "parcels": parcels,
 | 
			
		||||
        TAB_TITLE_IDENTIFIER: tab_title,
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,8 @@ Created on: 22.07.21
 | 
			
		||||
"""
 | 
			
		||||
from django.contrib import admin
 | 
			
		||||
 | 
			
		||||
from konova.models import Geometry, Deadline, GeometryConflict, Parcel, District
 | 
			
		||||
from konova.models import Geometry, Deadline, GeometryConflict, Parcel, District, Municipal, ParcelGroup
 | 
			
		||||
from konova.sub_settings.lanis_settings import DEFAULT_SRID_RLP
 | 
			
		||||
from konova.utils.message_templates import COMPENSATION_REMOVED_TEMPLATE
 | 
			
		||||
from user.models import UserAction
 | 
			
		||||
 | 
			
		||||
@ -16,13 +17,28 @@ class GeometryAdmin(admin.ModelAdmin):
 | 
			
		||||
    list_display = [
 | 
			
		||||
        "id",
 | 
			
		||||
        "created",
 | 
			
		||||
        "st_area",
 | 
			
		||||
    ]
 | 
			
		||||
    readonly_fields = [
 | 
			
		||||
        "st_area",
 | 
			
		||||
        "created",
 | 
			
		||||
        "modified",
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    def st_area(self, obj):
 | 
			
		||||
        val = None
 | 
			
		||||
        geom = obj.geom
 | 
			
		||||
        if geom is not None:
 | 
			
		||||
            geom.transform(ct=DEFAULT_SRID_RLP)
 | 
			
		||||
            val = geom.area
 | 
			
		||||
        return val
 | 
			
		||||
    st_area.short_description = f"Area (srid={DEFAULT_SRID_RLP})"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ParcelAdmin(admin.ModelAdmin):
 | 
			
		||||
    list_display = [
 | 
			
		||||
        "id",
 | 
			
		||||
        "gmrkng",
 | 
			
		||||
        "parcel_group",
 | 
			
		||||
        "flr",
 | 
			
		||||
        "flrstck_nnr",
 | 
			
		||||
        "flrstck_zhlr",
 | 
			
		||||
@ -32,9 +48,27 @@ class ParcelAdmin(admin.ModelAdmin):
 | 
			
		||||
 | 
			
		||||
class DistrictAdmin(admin.ModelAdmin):
 | 
			
		||||
    list_display = [
 | 
			
		||||
        "name",
 | 
			
		||||
        "key",
 | 
			
		||||
        "id",
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MunicipalAdmin(admin.ModelAdmin):
 | 
			
		||||
    list_display = [
 | 
			
		||||
        "name",
 | 
			
		||||
        "key",
 | 
			
		||||
        "district",
 | 
			
		||||
        "id",
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ParcelGroupAdmin(admin.ModelAdmin):
 | 
			
		||||
    list_display = [
 | 
			
		||||
        "name",
 | 
			
		||||
        "key",
 | 
			
		||||
        "municipal",
 | 
			
		||||
        "id",
 | 
			
		||||
        "gmnd",
 | 
			
		||||
        "krs",
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -105,5 +139,7 @@ class BaseObjectAdmin(BaseResourceAdmin):
 | 
			
		||||
#admin.site.register(Geometry, GeometryAdmin)
 | 
			
		||||
#admin.site.register(Parcel, ParcelAdmin)
 | 
			
		||||
#admin.site.register(District, DistrictAdmin)
 | 
			
		||||
#admin.site.register(Municipal, MunicipalAdmin)
 | 
			
		||||
#admin.site.register(ParcelGroup, ParcelGroupAdmin)
 | 
			
		||||
#admin.site.register(GeometryConflict, GeometryConflictAdmin)
 | 
			
		||||
#admin.site.register(Deadline, DeadlineAdmin)
 | 
			
		||||
 | 
			
		||||
@ -52,14 +52,16 @@ class InterventionAutocomplete(Select2QuerySetView):
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        if self.request.user.is_anonymous:
 | 
			
		||||
        user = self.request.user
 | 
			
		||||
        if user.is_anonymous:
 | 
			
		||||
            return Intervention.objects.none()
 | 
			
		||||
        qs = Intervention.objects.filter(
 | 
			
		||||
            deleted=None,
 | 
			
		||||
            users__in=[self.request.user],
 | 
			
		||||
            Q(deleted=None) &
 | 
			
		||||
            Q(users__in=[user]) |
 | 
			
		||||
            Q(teams__in=user.teams.all())
 | 
			
		||||
        ).order_by(
 | 
			
		||||
            "identifier"
 | 
			
		||||
        )
 | 
			
		||||
        ).distinct()
 | 
			
		||||
        if self.q:
 | 
			
		||||
            qs = qs.filter(
 | 
			
		||||
                Q(identifier__icontains=self.q) |
 | 
			
		||||
 | 
			
		||||
@ -145,26 +145,20 @@ class GeoReferencedTableFilterMixin(django_filters.FilterSet):
 | 
			
		||||
    class Meta:
 | 
			
		||||
        abstract = True
 | 
			
		||||
 | 
			
		||||
    def _filter_parcel_reference(self, queryset, name, value, filter_value) -> QuerySet:
 | 
			
		||||
        """ Filters the parcel entries by a given filter_value.
 | 
			
		||||
 | 
			
		||||
        filter_value may already include further filter annotations like 'xy__icontains'
 | 
			
		||||
    def _filter_parcel_reference(self, queryset, filter_q) -> QuerySet:
 | 
			
		||||
        """ Filters the parcel entries by a given filter_q
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
            queryset ():
 | 
			
		||||
            name ():
 | 
			
		||||
            value ():
 | 
			
		||||
            filter_value ():
 | 
			
		||||
            queryset (QuerySet): The queryset
 | 
			
		||||
            filter_q (Q): The Q-style filter expression
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        _filter = {
 | 
			
		||||
            filter_value: value
 | 
			
		||||
        }
 | 
			
		||||
        matching_parcels = Parcel.objects.filter(
 | 
			
		||||
            **_filter
 | 
			
		||||
            filter_q
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        related_geoms = matching_parcels.values(
 | 
			
		||||
            "geometries"
 | 
			
		||||
        ).distinct()
 | 
			
		||||
@ -185,8 +179,9 @@ class GeoReferencedTableFilterMixin(django_filters.FilterSet):
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        matching_districts = District.objects.filter(
 | 
			
		||||
            krs__icontains=value
 | 
			
		||||
        )
 | 
			
		||||
            Q(name__icontains=value) |
 | 
			
		||||
            Q(key__icontains=value)
 | 
			
		||||
        ).distinct()
 | 
			
		||||
        matching_parcels = Parcel.objects.filter(
 | 
			
		||||
            district__in=matching_districts
 | 
			
		||||
        )
 | 
			
		||||
@ -209,7 +204,10 @@ class GeoReferencedTableFilterMixin(django_filters.FilterSet):
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        queryset = self._filter_parcel_reference(queryset, name, value, "gmrkng__icontains")
 | 
			
		||||
        queryset = self._filter_parcel_reference(
 | 
			
		||||
            queryset,
 | 
			
		||||
            Q(parcel_group__name__icontains=value) | Q(parcel_group__key__icontains=value),
 | 
			
		||||
        )
 | 
			
		||||
        return queryset
 | 
			
		||||
 | 
			
		||||
    def filter_parcel(self, queryset, name, value) -> QuerySet:
 | 
			
		||||
@ -224,7 +222,10 @@ class GeoReferencedTableFilterMixin(django_filters.FilterSet):
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        value = value.replace("-", "")
 | 
			
		||||
        queryset = self._filter_parcel_reference(queryset, name, value, "flr")
 | 
			
		||||
        queryset = self._filter_parcel_reference(
 | 
			
		||||
            queryset,
 | 
			
		||||
            Q(flr=value),
 | 
			
		||||
        )
 | 
			
		||||
        return queryset
 | 
			
		||||
 | 
			
		||||
    def filter_parcel_counter(self, queryset, name, value) -> QuerySet:
 | 
			
		||||
@ -239,7 +240,10 @@ class GeoReferencedTableFilterMixin(django_filters.FilterSet):
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        value = value.replace("-", "")
 | 
			
		||||
        queryset = self._filter_parcel_reference(queryset, name, value, "flrstck_zhlr")
 | 
			
		||||
        queryset = self._filter_parcel_reference(
 | 
			
		||||
            queryset,
 | 
			
		||||
            Q(flrstck_zhlr=value)
 | 
			
		||||
        )
 | 
			
		||||
        return queryset
 | 
			
		||||
 | 
			
		||||
    def filter_parcel_number(self, queryset, name, value) -> QuerySet:
 | 
			
		||||
@ -254,7 +258,10 @@ class GeoReferencedTableFilterMixin(django_filters.FilterSet):
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        value = value.replace("-", "")
 | 
			
		||||
        queryset = self._filter_parcel_reference(queryset, name, value, "flrstck_nnr")
 | 
			
		||||
        queryset = self._filter_parcel_reference(
 | 
			
		||||
            queryset,
 | 
			
		||||
            Q(flrstck_nnr=value),
 | 
			
		||||
        )
 | 
			
		||||
        return queryset
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -57,6 +57,8 @@ class BaseForm(forms.Form):
 | 
			
		||||
                self.has_required_fields = True
 | 
			
		||||
                break
 | 
			
		||||
 | 
			
		||||
        self.check_for_recorded_instance()
 | 
			
		||||
 | 
			
		||||
    @abstractmethod
 | 
			
		||||
    def save(self):
 | 
			
		||||
        # To be implemented in subclasses!
 | 
			
		||||
@ -136,6 +138,38 @@ class BaseForm(forms.Form):
 | 
			
		||||
        set_class = set_class.replace(cls, "")
 | 
			
		||||
        self.fields[field].widget.attrs["class"] = set_class
 | 
			
		||||
 | 
			
		||||
    def check_for_recorded_instance(self):
 | 
			
		||||
        """ Checks if the instance is recorded and runs some special logic if yes
 | 
			
		||||
 | 
			
		||||
        If the instance is recorded, the form shall not display any possibility to
 | 
			
		||||
        edit any data. Instead, the users should get some information about why they can not edit anything.
 | 
			
		||||
 | 
			
		||||
        There are situations where the form should be rendered regularly,
 | 
			
		||||
        e.g deduction forms for (recorded) eco accounts.
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        from intervention.forms.modalForms import NewDeductionModalForm, EditEcoAccountDeductionModalForm, \
 | 
			
		||||
            RemoveEcoAccountDeductionModalForm
 | 
			
		||||
        is_none = self.instance is None
 | 
			
		||||
        is_other_data_type = not isinstance(self.instance, BaseObject)
 | 
			
		||||
        is_deduction_form = isinstance(
 | 
			
		||||
            self,
 | 
			
		||||
            (
 | 
			
		||||
                NewDeductionModalForm,
 | 
			
		||||
                EditEcoAccountDeductionModalForm,
 | 
			
		||||
                RemoveEcoAccountDeductionModalForm,
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        if is_none or is_other_data_type or is_deduction_form:
 | 
			
		||||
            # Do nothing
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        if self.instance.is_recorded:
 | 
			
		||||
            self.template = "form/recorded_no_edit.html"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class RemoveForm(BaseForm):
 | 
			
		||||
    check = forms.BooleanField(
 | 
			
		||||
@ -400,7 +434,6 @@ class NewDocumentModalForm(BaseModalForm):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.form_title = _("Add new document")
 | 
			
		||||
        self.form_caption = _("")
 | 
			
		||||
        self.template = "modal/modal_form.html"
 | 
			
		||||
        self.form_attrs = {
 | 
			
		||||
            "enctype": "multipart/form-data",  # important for file upload
 | 
			
		||||
        }
 | 
			
		||||
@ -587,4 +620,12 @@ class RecordModalForm(BaseModalForm):
 | 
			
		||||
                    self.instance.set_unrecorded(self.user)
 | 
			
		||||
                else:
 | 
			
		||||
                    self.instance.set_recorded(self.user)
 | 
			
		||||
        return self.instance
 | 
			
		||||
        return self.instance
 | 
			
		||||
 | 
			
		||||
    def check_for_recorded_instance(self):
 | 
			
		||||
        """ Overwrite the check method for doing nothing on the RecordModalForm
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,7 @@ from compensation.models import CompensationState, Compensation, EcoAccount, Com
 | 
			
		||||
from ema.models import Ema
 | 
			
		||||
from intervention.models import Intervention
 | 
			
		||||
from konova.management.commands.setup import BaseKonovaCommand
 | 
			
		||||
from konova.models import Deadline, Geometry, Parcel, District
 | 
			
		||||
from konova.models import Deadline, Geometry, Parcel, District, Municipal, ParcelGroup
 | 
			
		||||
from user.models import UserActionLogEntry, UserAction
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -271,13 +271,26 @@ class Command(BaseKonovaCommand):
 | 
			
		||||
            self._write_success("No unused states found.")
 | 
			
		||||
        self._break_line()
 | 
			
		||||
 | 
			
		||||
    def __sanitize_parcel_sub_type(self, cls):
 | 
			
		||||
        unrelated_entries = cls.objects.filter(
 | 
			
		||||
            parcels=None,
 | 
			
		||||
        )
 | 
			
		||||
        num_unrelated_entries = unrelated_entries.count()
 | 
			
		||||
        cls_name = cls.__name__
 | 
			
		||||
        if num_unrelated_entries > 0:
 | 
			
		||||
            self._write_error(f"Found {num_unrelated_entries} unrelated {cls_name} entries. Delete now...")
 | 
			
		||||
            unrelated_entries.delete()
 | 
			
		||||
            self._write_success(f"Unrelated {cls_name} deleted.")
 | 
			
		||||
        else:
 | 
			
		||||
            self._write_success(f"No unrelated {cls_name} found.")
 | 
			
		||||
 | 
			
		||||
    def sanitize_parcels_and_districts(self):
 | 
			
		||||
        """ Removes unattached parcels and districts
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        self._write_warning("=== Sanitize parcels and districts ===")
 | 
			
		||||
        self._write_warning("=== Sanitize administrative spatial references ===")
 | 
			
		||||
        unrelated_parcels = Parcel.objects.filter(
 | 
			
		||||
            geometries=None,
 | 
			
		||||
        )
 | 
			
		||||
@ -289,16 +302,12 @@ class Command(BaseKonovaCommand):
 | 
			
		||||
        else:
 | 
			
		||||
            self._write_success("No unrelated parcels found.")
 | 
			
		||||
 | 
			
		||||
        unrelated_districts = District.objects.filter(
 | 
			
		||||
            parcels=None,
 | 
			
		||||
        )
 | 
			
		||||
        num_unrelated_districts = unrelated_districts.count()
 | 
			
		||||
        if num_unrelated_districts > 0:
 | 
			
		||||
            self._write_error(f"Found {num_unrelated_districts} unrelated district entries. Delete now...")
 | 
			
		||||
            unrelated_districts.delete()
 | 
			
		||||
            self._write_success("Unrelated districts deleted.")
 | 
			
		||||
        else:
 | 
			
		||||
            self._write_success("No unrelated districts found.")
 | 
			
		||||
 | 
			
		||||
        self._break_line()
 | 
			
		||||
        sub_types = [
 | 
			
		||||
            District,
 | 
			
		||||
            Municipal,
 | 
			
		||||
            ParcelGroup
 | 
			
		||||
        ]
 | 
			
		||||
        for sub_type in sub_types:
 | 
			
		||||
            self.__sanitize_parcel_sub_type(sub_type)
 | 
			
		||||
 | 
			
		||||
        self._break_line()
 | 
			
		||||
@ -5,6 +5,10 @@ Contact: michel.peltriaux@sgdnord.rlp.de
 | 
			
		||||
Created on: 04.01.22
 | 
			
		||||
 | 
			
		||||
"""
 | 
			
		||||
import datetime
 | 
			
		||||
 | 
			
		||||
from django.contrib.gis.db.models.functions import Area
 | 
			
		||||
 | 
			
		||||
from konova.management.commands.setup import BaseKonovaCommand
 | 
			
		||||
from konova.models import Geometry, Parcel, District
 | 
			
		||||
 | 
			
		||||
@ -23,12 +27,21 @@ class Command(BaseKonovaCommand):
 | 
			
		||||
        num_parcels_before = Parcel.objects.count()
 | 
			
		||||
        num_districts_before = District.objects.count()
 | 
			
		||||
        self._write_warning("=== Update parcels and districts ===")
 | 
			
		||||
        # Order geometries by size to process smaller once at first
 | 
			
		||||
        geometries = Geometry.objects.all().exclude(
 | 
			
		||||
            geom=None
 | 
			
		||||
        ).annotate(area=Area("geom")).order_by(
 | 
			
		||||
            'area'
 | 
			
		||||
        )
 | 
			
		||||
        self._write_warning(f"Process parcels for {geometries.count()} geometry entries now ...")
 | 
			
		||||
        i = 0
 | 
			
		||||
        num_geoms = geometries.count()
 | 
			
		||||
        for geometry in geometries:
 | 
			
		||||
            self._write_warning(f"--- {datetime.datetime.now()} Process {geometry.id} now ...")
 | 
			
		||||
            geometry.update_parcels()
 | 
			
		||||
            self._write_warning(f"--- Processed {geometry.get_underlying_parcels().count()} underlying parcels")
 | 
			
		||||
            i += 1
 | 
			
		||||
            self._write_warning(f"--- {i}/{num_geoms} processed")
 | 
			
		||||
 | 
			
		||||
        num_parcels_after = Parcel.objects.count()
 | 
			
		||||
        num_districts_after = District.objects.count()
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										71
									
								
								konova/migrations/0006_auto_20220411_0835.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								konova/migrations/0006_auto_20220411_0835.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,71 @@
 | 
			
		||||
# Generated by Django 3.1.3 on 2022-04-11 06:35
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
import django.db.models.deletion
 | 
			
		||||
import uuid
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('konova', '0005_auto_20220216_0856'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.CreateModel(
 | 
			
		||||
            name='Municipal',
 | 
			
		||||
            fields=[
 | 
			
		||||
                ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
 | 
			
		||||
                ('key', models.IntegerField(blank=True, help_text='Represents Gemeindeschlüssel', null=True)),
 | 
			
		||||
                ('name', models.CharField(blank=True, help_text='Gemeinde', max_length=1000, null=True)),
 | 
			
		||||
            ],
 | 
			
		||||
            options={
 | 
			
		||||
                'abstract': False,
 | 
			
		||||
            },
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.RenameField(
 | 
			
		||||
            model_name='district',
 | 
			
		||||
            old_name='krs',
 | 
			
		||||
            new_name='name',
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.RemoveField(
 | 
			
		||||
            model_name='district',
 | 
			
		||||
            name='gmnd',
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.RemoveField(
 | 
			
		||||
            model_name='parcel',
 | 
			
		||||
            name='gmrkng',
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AddField(
 | 
			
		||||
            model_name='district',
 | 
			
		||||
            name='key',
 | 
			
		||||
            field=models.IntegerField(blank=True, help_text='Represents Kreisschlüssel', null=True),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.CreateModel(
 | 
			
		||||
            name='ParcelGroup',
 | 
			
		||||
            fields=[
 | 
			
		||||
                ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
 | 
			
		||||
                ('key', models.IntegerField(blank=True, help_text='Represents Gemarkungsschlüssel', null=True)),
 | 
			
		||||
                ('name', models.CharField(blank=True, help_text='Gemarkung', max_length=1000, null=True)),
 | 
			
		||||
                ('municipal', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='konova.municipal')),
 | 
			
		||||
            ],
 | 
			
		||||
            options={
 | 
			
		||||
                'abstract': False,
 | 
			
		||||
            },
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AddField(
 | 
			
		||||
            model_name='municipal',
 | 
			
		||||
            name='district',
 | 
			
		||||
            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='konova.district'),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AddField(
 | 
			
		||||
            model_name='parcel',
 | 
			
		||||
            name='municipal',
 | 
			
		||||
            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='parcels', to='konova.municipal'),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AddField(
 | 
			
		||||
            model_name='parcel',
 | 
			
		||||
            name='parcel_group',
 | 
			
		||||
            field=models.ForeignKey(blank=True, help_text='Gemarkung', null=True, on_delete=django.db.models.deletion.SET_NULL, to='konova.parcelgroup'),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
							
								
								
									
										28
									
								
								konova/migrations/0007_auto_20220411_0848.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								konova/migrations/0007_auto_20220411_0848.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
			
		||||
# Generated by Django 3.1.3 on 2022-04-11 06:48
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('konova', '0006_auto_20220411_0835'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='district',
 | 
			
		||||
            name='key',
 | 
			
		||||
            field=models.CharField(blank=True, help_text='Represents Kreisschlüssel', max_length=255, null=True),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='municipal',
 | 
			
		||||
            name='key',
 | 
			
		||||
            field=models.CharField(blank=True, help_text='Represents Gemeindeschlüssel', max_length=255, null=True),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='parcelgroup',
 | 
			
		||||
            name='key',
 | 
			
		||||
            field=models.CharField(blank=True, help_text='Represents Gemarkungsschlüssel', max_length=255, null=True),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
							
								
								
									
										48
									
								
								konova/migrations/0008_auto_20220411_0914.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								konova/migrations/0008_auto_20220411_0914.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
			
		||||
# Generated by Django 3.1.3 on 2022-04-11 07:14
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('konova', '0007_auto_20220411_0848'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='municipal',
 | 
			
		||||
            name='key',
 | 
			
		||||
            field=models.CharField(blank=True, help_text='Represents Kreisschlüssel', max_length=255, null=True),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='municipal',
 | 
			
		||||
            name='name',
 | 
			
		||||
            field=models.CharField(blank=True, help_text='Kreis', max_length=1000, null=True),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='parcel',
 | 
			
		||||
            name='flr',
 | 
			
		||||
            field=models.IntegerField(blank=True, help_text='Flur', null=True),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='parcel',
 | 
			
		||||
            name='flrstck_nnr',
 | 
			
		||||
            field=models.IntegerField(blank=True, help_text='Flurstücksnenner', null=True),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='parcel',
 | 
			
		||||
            name='flrstck_zhlr',
 | 
			
		||||
            field=models.IntegerField(blank=True, help_text='Flurstückszähler', null=True),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='parcelgroup',
 | 
			
		||||
            name='key',
 | 
			
		||||
            field=models.CharField(blank=True, help_text='Represents Kreisschlüssel', max_length=255, null=True),
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='parcelgroup',
 | 
			
		||||
            name='name',
 | 
			
		||||
            field=models.CharField(blank=True, help_text='Kreis', max_length=1000, null=True),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
							
								
								
									
										19
									
								
								konova/migrations/0009_auto_20220411_1004.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								konova/migrations/0009_auto_20220411_1004.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
# Generated by Django 3.1.3 on 2022-04-11 08:04
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
import django.db.models.deletion
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
        ('konova', '0008_auto_20220411_0914'),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.AlterField(
 | 
			
		||||
            model_name='parcel',
 | 
			
		||||
            name='parcel_group',
 | 
			
		||||
            field=models.ForeignKey(blank=True, help_text='Gemarkung', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='parcels', to='konova.parcelgroup'),
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
@ -20,6 +20,9 @@ class Geometry(BaseResource):
 | 
			
		||||
    from konova.settings import DEFAULT_SRID
 | 
			
		||||
    geom = MultiPolygonField(null=True, blank=True, srid=DEFAULT_SRID)
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        return str(self.id)
 | 
			
		||||
 | 
			
		||||
    def save(self, *args, **kwargs):
 | 
			
		||||
        super().save(*args, **kwargs)
 | 
			
		||||
        self.check_for_conflicts()
 | 
			
		||||
@ -99,7 +102,7 @@ class Geometry(BaseResource):
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        from konova.models import Parcel, District, ParcelIntersection
 | 
			
		||||
        from konova.models import Parcel, District, ParcelIntersection, Municipal, ParcelGroup
 | 
			
		||||
        parcel_fetcher = ParcelWFSFetcher(
 | 
			
		||||
            geometry_id=self.id,
 | 
			
		||||
        )
 | 
			
		||||
@ -115,16 +118,28 @@ class Geometry(BaseResource):
 | 
			
		||||
            # which needs to be deleted and just keep the numerical values
 | 
			
		||||
            ## THIS CAN BE REMOVED IN THE FUTURE, WHEN 'Flur' WON'T OCCUR ANYMORE!
 | 
			
		||||
            flr_val = fetched_parcel["ave:flur"].replace("Flur ", "")
 | 
			
		||||
            district = District.objects.get_or_create(
 | 
			
		||||
                key=fetched_parcel["ave:kreisschl"],
 | 
			
		||||
                name=fetched_parcel["ave:kreis"],
 | 
			
		||||
            )[0]
 | 
			
		||||
            municipal = Municipal.objects.get_or_create(
 | 
			
		||||
                key=fetched_parcel["ave:gmdschl"],
 | 
			
		||||
                name=fetched_parcel["ave:gemeinde"],
 | 
			
		||||
                district=district,
 | 
			
		||||
            )[0]
 | 
			
		||||
            parcel_group = ParcelGroup.objects.get_or_create(
 | 
			
		||||
                key=fetched_parcel["ave:gemaschl"],
 | 
			
		||||
                name=fetched_parcel["ave:gemarkung"],
 | 
			
		||||
                municipal=municipal,
 | 
			
		||||
            )[0]
 | 
			
		||||
            parcel_obj = Parcel.objects.get_or_create(
 | 
			
		||||
                gmrkng=fetched_parcel["ave:gemarkung"],
 | 
			
		||||
                district=district,
 | 
			
		||||
                municipal=municipal,
 | 
			
		||||
                parcel_group=parcel_group,
 | 
			
		||||
                flr=flr_val,
 | 
			
		||||
                flrstck_nnr=fetched_parcel['ave:flstnrnen'],
 | 
			
		||||
                flrstck_zhlr=fetched_parcel['ave:flstnrzae'],
 | 
			
		||||
            )[0]
 | 
			
		||||
            district = District.objects.get_or_create(
 | 
			
		||||
                gmnd=fetched_parcel["ave:gemeinde"],
 | 
			
		||||
                krs=fetched_parcel["ave:kreis"],
 | 
			
		||||
            )[0]
 | 
			
		||||
            parcel_obj.district = district
 | 
			
		||||
            parcel_obj.updated_on = _now
 | 
			
		||||
            parcel_obj.save()
 | 
			
		||||
@ -155,9 +170,10 @@ class Geometry(BaseResource):
 | 
			
		||||
        parcels = self.parcels.filter(
 | 
			
		||||
            parcelintersection__calculated_on__isnull=False,
 | 
			
		||||
        ).prefetch_related(
 | 
			
		||||
            "district"
 | 
			
		||||
            "district",
 | 
			
		||||
            "municipal",
 | 
			
		||||
        ).order_by(
 | 
			
		||||
            "gmrkng",
 | 
			
		||||
            "municipal__name",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        return parcels
 | 
			
		||||
 | 
			
		||||
@ -289,6 +289,8 @@ class RecordableObjectMixin(models.Model):
 | 
			
		||||
        from user.models import UserActionLogEntry
 | 
			
		||||
        if self.recorded:
 | 
			
		||||
            return None
 | 
			
		||||
 | 
			
		||||
        self.unshare_with_default_users()
 | 
			
		||||
        action = UserActionLogEntry.get_recorded_action(user)
 | 
			
		||||
        self.recorded = action
 | 
			
		||||
        self.save()
 | 
			
		||||
@ -335,6 +337,15 @@ class RecordableObjectMixin(models.Model):
 | 
			
		||||
        """
 | 
			
		||||
        raise NotImplementedError("Implement this in the subclass!")
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def is_recorded(self):
 | 
			
		||||
        """ Getter for record status as property
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        return self.recorded is not None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CheckableObjectMixin(models.Model):
 | 
			
		||||
    # Checks - Refers to "Genehmigen" but optional
 | 
			
		||||
@ -608,6 +619,26 @@ class ShareableObjectMixin(models.Model):
 | 
			
		||||
        """
 | 
			
		||||
        raise NotImplementedError("Must be implemented in subclasses!")
 | 
			
		||||
 | 
			
		||||
    def unshare_with_default_users(self):
 | 
			
		||||
        """ Removes all shared users from direct shared access which are only default group users
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        from konova.utils.user_checks import is_default_group_only
 | 
			
		||||
        users = self.shared_users
 | 
			
		||||
        cleaned_users = []
 | 
			
		||||
        default_users = []
 | 
			
		||||
        for user in users:
 | 
			
		||||
            if not is_default_group_only(user):
 | 
			
		||||
                cleaned_users.append(user)
 | 
			
		||||
            else:
 | 
			
		||||
                default_users.append(user)
 | 
			
		||||
        self.share_with_user_list(cleaned_users)
 | 
			
		||||
 | 
			
		||||
        for user in default_users:
 | 
			
		||||
            celery_send_mail_shared_access_removed.delay(self.identifier, self.title, user.id)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class GeoReferencedMixin(models.Model):
 | 
			
		||||
    geometry = models.ForeignKey("konova.Geometry", null=True, blank=True, on_delete=models.SET_NULL)
 | 
			
		||||
 | 
			
		||||
@ -10,8 +10,64 @@ from django.db import models
 | 
			
		||||
from konova.models import UuidModel
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AdministrativeSpatialReference(models.Model):
 | 
			
		||||
    key = models.CharField(
 | 
			
		||||
        max_length=255,
 | 
			
		||||
        help_text="Represents Kreisschlüssel",
 | 
			
		||||
        null=True,
 | 
			
		||||
        blank=True
 | 
			
		||||
    )
 | 
			
		||||
    name = models.CharField(
 | 
			
		||||
        max_length=1000,
 | 
			
		||||
        help_text="Kreis",
 | 
			
		||||
        null=True,
 | 
			
		||||
        blank=True,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        abstract = True
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        return f"{self.name} ({self.key})"
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def table_str(self):
 | 
			
		||||
        return f"{self.name} ({self.key})"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class District(UuidModel, AdministrativeSpatialReference):
 | 
			
		||||
    """ The model District refers to "Kreis"
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Municipal(UuidModel, AdministrativeSpatialReference):
 | 
			
		||||
    """ The model Municipal refers to "Gemeinde"
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    district = models.ForeignKey(
 | 
			
		||||
        District,
 | 
			
		||||
        on_delete=models.SET_NULL,
 | 
			
		||||
        null=True,
 | 
			
		||||
        blank=True,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ParcelGroup(UuidModel, AdministrativeSpatialReference):
 | 
			
		||||
    """ The model ParcelGroup refers to "Gemarkung", which is defined as a loose group of parcels
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    municipal = models.ForeignKey(
 | 
			
		||||
        Municipal,
 | 
			
		||||
        on_delete=models.SET_NULL,
 | 
			
		||||
        null=True,
 | 
			
		||||
        blank=True,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Parcel(UuidModel):
 | 
			
		||||
    """ The Parcel model holds administrative data on the covered properties.
 | 
			
		||||
    """ The Parcel model holds administrative data on covered properties.
 | 
			
		||||
 | 
			
		||||
    Due to the unique but relevant naming of the administrative data, we have to use these namings as field
 | 
			
		||||
    names in german. Any try to translate them to English result in strange or insufficient translations.
 | 
			
		||||
@ -24,59 +80,34 @@ class Parcel(UuidModel):
 | 
			
		||||
    """
 | 
			
		||||
    geometries = models.ManyToManyField("konova.Geometry", blank=True, related_name="parcels", through='ParcelIntersection')
 | 
			
		||||
    district = models.ForeignKey("konova.District", on_delete=models.SET_NULL, null=True, blank=True, related_name="parcels")
 | 
			
		||||
    gmrkng = models.CharField(
 | 
			
		||||
        max_length=1000,
 | 
			
		||||
    municipal = models.ForeignKey("konova.Municipal", on_delete=models.SET_NULL, null=True, blank=True, related_name="parcels")
 | 
			
		||||
    parcel_group = models.ForeignKey(
 | 
			
		||||
        "konova.ParcelGroup",
 | 
			
		||||
        on_delete=models.SET_NULL,
 | 
			
		||||
        help_text="Gemarkung",
 | 
			
		||||
        null=True,
 | 
			
		||||
        blank=True,
 | 
			
		||||
        related_name="parcels"
 | 
			
		||||
    )
 | 
			
		||||
    flrstck_nnr = models.CharField(
 | 
			
		||||
        max_length=1000,
 | 
			
		||||
    flr = models.IntegerField(
 | 
			
		||||
        help_text="Flur",
 | 
			
		||||
        null=True,
 | 
			
		||||
        blank=True,
 | 
			
		||||
    )
 | 
			
		||||
    flrstck_nnr = models.IntegerField(
 | 
			
		||||
        help_text="Flurstücksnenner",
 | 
			
		||||
        null=True,
 | 
			
		||||
        blank=True,
 | 
			
		||||
    )
 | 
			
		||||
    flrstck_zhlr = models.CharField(
 | 
			
		||||
        max_length=1000,
 | 
			
		||||
    flrstck_zhlr = models.IntegerField(
 | 
			
		||||
        help_text="Flurstückszähler",
 | 
			
		||||
        null=True,
 | 
			
		||||
        blank=True,
 | 
			
		||||
    )
 | 
			
		||||
    flr = models.CharField(
 | 
			
		||||
        max_length=1000,
 | 
			
		||||
        help_text="Flur",
 | 
			
		||||
        null=True,
 | 
			
		||||
        blank=True,
 | 
			
		||||
    )
 | 
			
		||||
    updated_on = models.DateTimeField(auto_now_add=True)
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        return f"{self.gmrkng} | {self.flr} | {self.flrstck_zhlr} | {self.flrstck_nnr}"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class District(UuidModel):
 | 
			
		||||
    """ The model District holds more coarse information, such as Kreis, Verbandsgemeinde and Gemeinde.
 | 
			
		||||
 | 
			
		||||
    There might be the case that a geometry lies on a hundred Parcel entries but only on one District entry.
 | 
			
		||||
    Therefore a geometry can have a lot of relations to Parcel entries but only a few or only a single one to one
 | 
			
		||||
    District.
 | 
			
		||||
 | 
			
		||||
    """
 | 
			
		||||
    gmnd = models.CharField(
 | 
			
		||||
        max_length=1000,
 | 
			
		||||
        help_text="Gemeinde",
 | 
			
		||||
        null=True,
 | 
			
		||||
        blank=True,
 | 
			
		||||
    )
 | 
			
		||||
    krs = models.CharField(
 | 
			
		||||
        max_length=1000,
 | 
			
		||||
        help_text="Kreis",
 | 
			
		||||
        null=True,
 | 
			
		||||
        blank=True,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        return f"{self.gmnd} | {self.krs}"
 | 
			
		||||
        return f"{self.parcel_group} | {self.flr} | {self.flrstck_zhlr} | {self.flrstck_nnr}"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ParcelIntersection(UuidModel):
 | 
			
		||||
 | 
			
		||||
@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/3.1/ref/settings/
 | 
			
		||||
"""
 | 
			
		||||
import os
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
from django.conf.locale.de import formats as de_formats
 | 
			
		||||
 | 
			
		||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
 | 
			
		||||
BASE_DIR = os.path.dirname(
 | 
			
		||||
@ -162,9 +163,15 @@ LANGUAGES = [
 | 
			
		||||
 | 
			
		||||
USE_THOUSAND_SEPARATOR = True
 | 
			
		||||
 | 
			
		||||
# Regular python relevant date/datetime formatting
 | 
			
		||||
DEFAULT_DATE_TIME_FORMAT = '%d.%m.%Y %H:%M:%S'
 | 
			
		||||
DEFAULT_DATE_FORMAT = '%d.%m.%Y'
 | 
			
		||||
 | 
			
		||||
# Template relevant date/datetime formatting
 | 
			
		||||
# See the Note on here: https://docs.djangoproject.com/en/3.2/ref/templates/builtins/#date
 | 
			
		||||
de_formats.DATETIME_FORMAT = "d.m.Y, H:i"
 | 
			
		||||
de_formats.DATE_FORMAT = "d.m.Y"
 | 
			
		||||
 | 
			
		||||
TIME_ZONE = 'Europe/Berlin'
 | 
			
		||||
 | 
			
		||||
USE_I18N = True
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,6 @@ PAGE_SIZE_OPTIONS_TUPLES = [
 | 
			
		||||
    (50, 50),
 | 
			
		||||
    (100, 100),
 | 
			
		||||
]
 | 
			
		||||
PAGE_SIZE_DEFAULT = 5
 | 
			
		||||
PAGE_SIZE_DEFAULT = 10
 | 
			
		||||
PAGE_SIZE_MAX = 100
 | 
			
		||||
PAGE_DEFAULT = 1
 | 
			
		||||
 | 
			
		||||
@ -1,15 +1,36 @@
 | 
			
		||||
{% load i18n %}
 | 
			
		||||
{% load i18n l10n %}
 | 
			
		||||
<div class="table-container w-100 scroll-300">
 | 
			
		||||
    {% if parcels|length == 0 %}
 | 
			
		||||
    <article class="alert alert-info">
 | 
			
		||||
        {% trans 'Parcels can not be calculated, since no geometry is given.' %}
 | 
			
		||||
    </article>
 | 
			
		||||
    {% else %}
 | 
			
		||||
    <table class="table table-hover">
 | 
			
		||||
    <table id="upper-spatial-table" class="table table-hover">
 | 
			
		||||
        <thead>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <th scope="col">{% trans 'Kreis' %}</th>
 | 
			
		||||
                <th scope="col">{% trans 'Gemarkung' %}</th>
 | 
			
		||||
                <th scope="col">{% trans 'Municipal' %}</th>
 | 
			
		||||
                <th scope="col">{% trans 'Municipal key' %}</th>
 | 
			
		||||
                <th scope="col">{% trans 'District' %}</th>
 | 
			
		||||
                <th scope="col">{% trans 'District key' %}</th>
 | 
			
		||||
            </tr>
 | 
			
		||||
        </thead>
 | 
			
		||||
        <tbody>
 | 
			
		||||
        {% for municipal in municipals %}
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>{{municipal.name}}</td>
 | 
			
		||||
                <td>{{municipal.key|unlocalize}}</td>
 | 
			
		||||
                <td>{{municipal.district.name}}</td>
 | 
			
		||||
                <td>{{municipal.district.key|unlocalize}}</td>
 | 
			
		||||
            </tr>
 | 
			
		||||
        {% endfor %}
 | 
			
		||||
 | 
			
		||||
        </tbody>
 | 
			
		||||
    </table>
 | 
			
		||||
    <table id="lower-spatial-table" class="table table-hover">
 | 
			
		||||
        <thead>
 | 
			
		||||
            <tr>
 | 
			
		||||
                <th scope="col">{% trans 'Parcel group' %}</th>
 | 
			
		||||
                <th scope="col">{% trans 'Parcel group key' %}</th>
 | 
			
		||||
                <th scope="col">{% trans 'Parcel' %}</th>
 | 
			
		||||
                <th scope="col">{% trans 'Parcel counter' %}</th>
 | 
			
		||||
                <th scope="col">{% trans 'Parcel number' %}</th>
 | 
			
		||||
@ -18,11 +39,11 @@
 | 
			
		||||
        <tbody>
 | 
			
		||||
        {% for parcel in parcels %}
 | 
			
		||||
            <tr>
 | 
			
		||||
                <td>{{parcel.district.krs|default_if_none:"-"}}</td>
 | 
			
		||||
                <td>{{parcel.gmrkng|default_if_none:"-"}}</td>
 | 
			
		||||
                <td>{{parcel.flr|default_if_none:"-"}}</td>
 | 
			
		||||
                <td>{{parcel.flrstck_zhlr|default_if_none:"-"}}</td>
 | 
			
		||||
                <td>{{parcel.flrstck_nnr|default_if_none:"-"}}</td>
 | 
			
		||||
                <td>{{parcel.parcel_group.name|default_if_none:"-"}}</td>
 | 
			
		||||
                <td>{{parcel.parcel_group.key|default_if_none:"-"}}</td>
 | 
			
		||||
                <td>{{parcel.flr|default_if_none:"-"|unlocalize}}</td>
 | 
			
		||||
                <td>{{parcel.flrstck_zhlr|default_if_none:"-"|unlocalize}}</td>
 | 
			
		||||
                <td>{{parcel.flrstck_nnr|default_if_none:"-"|unlocalize}}</td>
 | 
			
		||||
            </tr>
 | 
			
		||||
        {% endfor %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,7 @@
 | 
			
		||||
            </h5>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="card-body">
 | 
			
		||||
            <div hx-trigger="every 2s" hx-get="{% url 'geometry-parcels' geom_form.instance.geometry.id %}" title="{% trans 'Loading...' %}">
 | 
			
		||||
            <div hx-trigger="load, every 5s" hx-get="{% url 'geometry-parcels' geom_form.instance.geometry.id %}">
 | 
			
		||||
                <div class="row justify-content-center">
 | 
			
		||||
                    <span class="spinner-border rlp-r-inv" role="status"></span>
 | 
			
		||||
                </div>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										19
									
								
								konova/templates/konova/includes/report/qrcodes.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								konova/templates/konova/includes/report/qrcodes.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
{% load i18n %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<div class="col-sm-6 col-md-6 col-lg-6">
 | 
			
		||||
    <button class="btn btn-outline-default col-sm-12">
 | 
			
		||||
        <a href="{{qrcode.url}}" target="_blank">
 | 
			
		||||
            <h4>{% trans 'Open in browser' %}</h4>
 | 
			
		||||
            {{ qrcode.img|safe }}
 | 
			
		||||
        </a>
 | 
			
		||||
    </button>
 | 
			
		||||
</div>
 | 
			
		||||
<div class="col-sm-6 col-md-6 col-lg-6">
 | 
			
		||||
    <button class="btn btn-outline-default col-sm-12">
 | 
			
		||||
        <a href="{{qrcode_lanis.url}}" target="_blank">
 | 
			
		||||
            <h4>{% trans 'View in LANIS' %}</h4>
 | 
			
		||||
            {{ qrcode_lanis.img|safe }}
 | 
			
		||||
        </a>
 | 
			
		||||
    </button>
 | 
			
		||||
</div>
 | 
			
		||||
@ -17,6 +17,7 @@ IDENTIFIER_REPLACED = _("The identifier '{}' had to be changed to '{}' since ano
 | 
			
		||||
ENTRY_REMOVE_MISSING_PERMISSION = _("Only conservation or registration office users are allowed to remove entries.")
 | 
			
		||||
MISSING_GROUP_PERMISSION = _("You need to be part of another user group.")
 | 
			
		||||
CHECKED_RECORDED_RESET = _("Status of Checked and Recorded reseted")
 | 
			
		||||
RECORDED_BLOCKS_EDIT = _("Entry is recorded. To edit data, the entry first needs to be unrecorded.")
 | 
			
		||||
 | 
			
		||||
# SHARE
 | 
			
		||||
DATA_UNSHARED = _("This data is not shared with you")
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ from compensation.models import Compensation, EcoAccount
 | 
			
		||||
from intervention.models import Intervention
 | 
			
		||||
from konova.contexts import BaseContext
 | 
			
		||||
from konova.decorators import any_group_check
 | 
			
		||||
from konova.models import Deadline, Geometry
 | 
			
		||||
from konova.models import Deadline, Geometry, Municipal
 | 
			
		||||
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
 | 
			
		||||
from news.models import ServerMessage
 | 
			
		||||
from konova.settings import SSO_SERVER_BASE
 | 
			
		||||
@ -130,8 +130,12 @@ def get_geom_parcels(request: HttpRequest, id: str):
 | 
			
		||||
        status_code = 200
 | 
			
		||||
 | 
			
		||||
    if parcels_available or no_geometry_given:
 | 
			
		||||
        parcels = parcels.order_by("-municipal", "flr", "flrstck_zhlr", "flrstck_nnr")
 | 
			
		||||
        municipals = parcels.order_by("municipal").distinct("municipal").values("municipal__id")
 | 
			
		||||
        municipals = Municipal.objects.filter(id__in=municipals)
 | 
			
		||||
        context = {
 | 
			
		||||
            "parcels": parcels,
 | 
			
		||||
            "municipals": municipals,
 | 
			
		||||
        }
 | 
			
		||||
        html = render_to_string(template, context, request)
 | 
			
		||||
        return HttpResponse(html, status=status_code)
 | 
			
		||||
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@ -15,18 +15,18 @@
 | 
			
		||||
#: konova/filters/mixins.py:107 konova/filters/mixins.py:108
 | 
			
		||||
#: konova/filters/mixins.py:120 konova/filters/mixins.py:121
 | 
			
		||||
#: konova/filters/mixins.py:134 konova/filters/mixins.py:135
 | 
			
		||||
#: konova/filters/mixins.py:270 konova/filters/mixins.py:316
 | 
			
		||||
#: konova/filters/mixins.py:354 konova/filters/mixins.py:355
 | 
			
		||||
#: konova/filters/mixins.py:386 konova/filters/mixins.py:387
 | 
			
		||||
#: konova/forms.py:143 konova/forms.py:244 konova/forms.py:315
 | 
			
		||||
#: konova/forms.py:359 konova/forms.py:369 konova/forms.py:382
 | 
			
		||||
#: konova/forms.py:394 konova/forms.py:412 user/forms.py:42
 | 
			
		||||
#: konova/filters/mixins.py:277 konova/filters/mixins.py:323
 | 
			
		||||
#: konova/filters/mixins.py:361 konova/filters/mixins.py:362
 | 
			
		||||
#: konova/filters/mixins.py:393 konova/filters/mixins.py:394
 | 
			
		||||
#: konova/forms.py:177 konova/forms.py:278 konova/forms.py:349
 | 
			
		||||
#: konova/forms.py:393 konova/forms.py:403 konova/forms.py:416
 | 
			
		||||
#: konova/forms.py:428 konova/forms.py:446 user/forms.py:42
 | 
			
		||||
#, fuzzy
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: PACKAGE VERSION\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: \n"
 | 
			
		||||
"POT-Creation-Date: 2022-03-03 12:08+0100\n"
 | 
			
		||||
"POT-Creation-Date: 2022-04-19 13:28+0200\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"
 | 
			
		||||
@ -52,7 +52,7 @@ msgstr "Bis"
 | 
			
		||||
#: intervention/forms/forms.py:102
 | 
			
		||||
#: intervention/templates/intervention/detail/view.html:56
 | 
			
		||||
#: intervention/templates/intervention/report/report.html:37
 | 
			
		||||
#: intervention/utils/quality.py:49 konova/filters/mixins.py:396
 | 
			
		||||
#: intervention/utils/quality.py:49 konova/filters/mixins.py:403
 | 
			
		||||
msgid "Conservation office"
 | 
			
		||||
msgstr "Eintragungsstelle"
 | 
			
		||||
 | 
			
		||||
@ -77,7 +77,7 @@ msgstr "Bericht generieren"
 | 
			
		||||
msgid "Select a timespan and the desired conservation office"
 | 
			
		||||
msgstr "Wählen Sie die Zeitspanne und die gewünschte Eintragungsstelle"
 | 
			
		||||
 | 
			
		||||
#: analysis/forms.py:69 konova/forms.py:191
 | 
			
		||||
#: analysis/forms.py:69 konova/forms.py:225
 | 
			
		||||
msgid "Continue"
 | 
			
		||||
msgstr "Weiter"
 | 
			
		||||
 | 
			
		||||
@ -154,7 +154,7 @@ msgstr "Geprüft"
 | 
			
		||||
#: analysis/templates/analysis/reports/includes/intervention/compensated_by.html:9
 | 
			
		||||
#: analysis/templates/analysis/reports/includes/intervention/laws.html:20
 | 
			
		||||
#: analysis/templates/analysis/reports/includes/old_data/amount.html:18
 | 
			
		||||
#: compensation/tables.py:46 compensation/tables.py:222
 | 
			
		||||
#: compensation/tables.py:46 compensation/tables.py:220
 | 
			
		||||
#: compensation/templates/compensation/detail/compensation/view.html:78
 | 
			
		||||
#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:31
 | 
			
		||||
#: compensation/templates/compensation/detail/eco_account/view.html:45
 | 
			
		||||
@ -294,7 +294,7 @@ msgid "Intervention"
 | 
			
		||||
msgstr "Eingriff"
 | 
			
		||||
 | 
			
		||||
#: analysis/templates/analysis/reports/includes/old_data/amount.html:34
 | 
			
		||||
#: compensation/tables.py:266
 | 
			
		||||
#: compensation/tables.py:264
 | 
			
		||||
#: compensation/templates/compensation/detail/eco_account/view.html:20
 | 
			
		||||
#: intervention/forms/modalForms.py:348 intervention/forms/modalForms.py:355
 | 
			
		||||
#: konova/templates/konova/includes/quickstart/ecoaccounts.html:4
 | 
			
		||||
@ -315,7 +315,7 @@ msgid "Show only unrecorded"
 | 
			
		||||
msgstr "Nur unverzeichnete anzeigen"
 | 
			
		||||
 | 
			
		||||
#: compensation/forms/forms.py:32 compensation/tables.py:25
 | 
			
		||||
#: compensation/tables.py:197 ema/tables.py:29 intervention/forms/forms.py:28
 | 
			
		||||
#: compensation/tables.py:195 ema/tables.py:29 intervention/forms/forms.py:28
 | 
			
		||||
#: intervention/tables.py:24
 | 
			
		||||
#: intervention/templates/intervention/detail/includes/compensations.html:30
 | 
			
		||||
msgid "Identifier"
 | 
			
		||||
@ -327,7 +327,7 @@ msgid "Generated automatically"
 | 
			
		||||
msgstr "Automatisch generiert"
 | 
			
		||||
 | 
			
		||||
#: compensation/forms/forms.py:44 compensation/tables.py:30
 | 
			
		||||
#: compensation/tables.py:202
 | 
			
		||||
#: compensation/tables.py:200
 | 
			
		||||
#: compensation/templates/compensation/detail/compensation/includes/documents.html:28
 | 
			
		||||
#: compensation/templates/compensation/detail/compensation/view.html:32
 | 
			
		||||
#: compensation/templates/compensation/detail/eco_account/includes/documents.html:28
 | 
			
		||||
@ -342,7 +342,7 @@ msgstr "Automatisch generiert"
 | 
			
		||||
#: intervention/templates/intervention/detail/includes/documents.html:28
 | 
			
		||||
#: intervention/templates/intervention/detail/view.html:31
 | 
			
		||||
#: intervention/templates/intervention/report/report.html:12
 | 
			
		||||
#: konova/forms.py:358
 | 
			
		||||
#: konova/forms.py:392
 | 
			
		||||
msgid "Title"
 | 
			
		||||
msgstr "Bezeichnung"
 | 
			
		||||
 | 
			
		||||
@ -369,7 +369,7 @@ msgstr "Kompensation XY; Flur ABC"
 | 
			
		||||
#: intervention/templates/intervention/detail/includes/documents.html:34
 | 
			
		||||
#: intervention/templates/intervention/detail/includes/payments.html:34
 | 
			
		||||
#: intervention/templates/intervention/detail/includes/revocation.html:38
 | 
			
		||||
#: konova/forms.py:393 konova/templates/konova/includes/comment_card.html:16
 | 
			
		||||
#: konova/forms.py:427 konova/templates/konova/includes/comment_card.html:16
 | 
			
		||||
msgid "Comment"
 | 
			
		||||
msgstr "Kommentar"
 | 
			
		||||
 | 
			
		||||
@ -441,7 +441,7 @@ msgstr "kompensiert Eingriff"
 | 
			
		||||
msgid "Select the intervention for which this compensation compensates"
 | 
			
		||||
msgstr "Wählen Sie den Eingriff, für den diese Kompensation bestimmt ist"
 | 
			
		||||
 | 
			
		||||
#: compensation/forms/forms.py:202 compensation/views/compensation.py:96
 | 
			
		||||
#: compensation/forms/forms.py:202 compensation/views/compensation.py:110
 | 
			
		||||
msgid "New compensation"
 | 
			
		||||
msgstr "Neue Kompensation"
 | 
			
		||||
 | 
			
		||||
@ -467,7 +467,7 @@ msgstr "Vereinbarungsdatum"
 | 
			
		||||
msgid "When did the parties agree on this?"
 | 
			
		||||
msgstr "Wann wurde dieses Ökokonto offiziell vereinbart?"
 | 
			
		||||
 | 
			
		||||
#: compensation/forms/forms.py:373 compensation/views/eco_account.py:107
 | 
			
		||||
#: compensation/forms/forms.py:373 compensation/views/eco_account.py:108
 | 
			
		||||
msgid "New Eco-Account"
 | 
			
		||||
msgstr "Neues Ökokonto"
 | 
			
		||||
 | 
			
		||||
@ -493,7 +493,7 @@ msgid "Due on which date"
 | 
			
		||||
msgstr "Zahlung wird an diesem Datum erwartet"
 | 
			
		||||
 | 
			
		||||
#: compensation/forms/modalForms.py:64 compensation/forms/modalForms.py:359
 | 
			
		||||
#: intervention/forms/modalForms.py:177 konova/forms.py:395
 | 
			
		||||
#: intervention/forms/modalForms.py:177 konova/forms.py:429
 | 
			
		||||
msgid "Additional comment, maximum {} letters"
 | 
			
		||||
msgstr "Zusätzlicher Kommentar, maximal {} Zeichen"
 | 
			
		||||
 | 
			
		||||
@ -538,7 +538,7 @@ msgstr "Neuer Zustand"
 | 
			
		||||
msgid "Insert data for the new state"
 | 
			
		||||
msgstr "Geben Sie die Daten des neuen Zustandes ein"
 | 
			
		||||
 | 
			
		||||
#: compensation/forms/modalForms.py:217 konova/forms.py:193
 | 
			
		||||
#: compensation/forms/modalForms.py:217 konova/forms.py:227
 | 
			
		||||
msgid "Object removed"
 | 
			
		||||
msgstr "Objekt entfernt"
 | 
			
		||||
 | 
			
		||||
@ -675,22 +675,22 @@ msgstr ""
 | 
			
		||||
"Es wurde bereits mehr Fläche abgebucht, als Sie nun als abbuchbar einstellen "
 | 
			
		||||
"wollen. Kontaktieren Sie die für die Abbuchungen verantwortlichen Nutzer!"
 | 
			
		||||
 | 
			
		||||
#: compensation/tables.py:35 compensation/tables.py:207 ema/tables.py:39
 | 
			
		||||
#: compensation/tables.py:35 compensation/tables.py:205 ema/tables.py:39
 | 
			
		||||
#: intervention/tables.py:34 konova/filters/mixins.py:98
 | 
			
		||||
msgid "Parcel gmrkng"
 | 
			
		||||
msgstr "Gemarkung"
 | 
			
		||||
 | 
			
		||||
#: compensation/tables.py:52 compensation/tables.py:228 ema/tables.py:50
 | 
			
		||||
#: compensation/tables.py:52 compensation/tables.py:226 ema/tables.py:50
 | 
			
		||||
#: intervention/tables.py:51
 | 
			
		||||
msgid "Editable"
 | 
			
		||||
msgstr "Freigegeben"
 | 
			
		||||
 | 
			
		||||
#: compensation/tables.py:58 compensation/tables.py:234 ema/tables.py:56
 | 
			
		||||
#: compensation/tables.py:58 compensation/tables.py:232 ema/tables.py:56
 | 
			
		||||
#: intervention/tables.py:57
 | 
			
		||||
msgid "Last edit"
 | 
			
		||||
msgstr "Zuletzt bearbeitet"
 | 
			
		||||
 | 
			
		||||
#: compensation/tables.py:89 compensation/tables.py:266 ema/tables.py:89
 | 
			
		||||
#: compensation/tables.py:89 compensation/tables.py:264 ema/tables.py:89
 | 
			
		||||
#: intervention/tables.py:88
 | 
			
		||||
msgid "Open {}"
 | 
			
		||||
msgstr "Öffne {}"
 | 
			
		||||
@ -713,32 +713,32 @@ msgstr "Am {} von {} geprüft worden"
 | 
			
		||||
msgid "Not recorded yet"
 | 
			
		||||
msgstr "Noch nicht verzeichnet"
 | 
			
		||||
 | 
			
		||||
#: compensation/tables.py:165 compensation/tables.py:326 ema/tables.py:136
 | 
			
		||||
#: compensation/tables.py:165 compensation/tables.py:324 ema/tables.py:136
 | 
			
		||||
#: intervention/tables.py:162
 | 
			
		||||
msgid "Recorded on {} by {}"
 | 
			
		||||
msgstr "Am {} von {} verzeichnet worden"
 | 
			
		||||
 | 
			
		||||
#: compensation/tables.py:189 compensation/tables.py:348 ema/tables.py:159
 | 
			
		||||
#: intervention/tables.py:185
 | 
			
		||||
#: compensation/tables.py:187 compensation/tables.py:346 ema/tables.py:157
 | 
			
		||||
#: intervention/tables.py:183
 | 
			
		||||
msgid "Full access granted"
 | 
			
		||||
msgstr "Für Sie freigegeben - Datensatz kann bearbeitet werden"
 | 
			
		||||
 | 
			
		||||
#: compensation/tables.py:189 compensation/tables.py:348 ema/tables.py:159
 | 
			
		||||
#: intervention/tables.py:185
 | 
			
		||||
#: compensation/tables.py:187 compensation/tables.py:346 ema/tables.py:157
 | 
			
		||||
#: intervention/tables.py:183
 | 
			
		||||
msgid "Access not granted"
 | 
			
		||||
msgstr "Nicht freigegeben - Datensatz nur lesbar"
 | 
			
		||||
 | 
			
		||||
#: compensation/tables.py:212
 | 
			
		||||
#: compensation/tables.py:210
 | 
			
		||||
#: compensation/templates/compensation/detail/eco_account/view.html:36
 | 
			
		||||
#: konova/templates/konova/widgets/progressbar.html:3
 | 
			
		||||
msgid "Available"
 | 
			
		||||
msgstr "Verfügbar"
 | 
			
		||||
 | 
			
		||||
#: compensation/tables.py:243
 | 
			
		||||
#: compensation/tables.py:241
 | 
			
		||||
msgid "Eco Accounts"
 | 
			
		||||
msgstr "Ökokonten"
 | 
			
		||||
 | 
			
		||||
#: compensation/tables.py:321
 | 
			
		||||
#: compensation/tables.py:319
 | 
			
		||||
msgid "Not recorded yet. Can not be used for deductions, yet."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Noch nicht verzeichnet. Kann noch nicht für Abbuchungen genutzt werden."
 | 
			
		||||
@ -871,7 +871,7 @@ msgstr "Dokumente"
 | 
			
		||||
#: compensation/templates/compensation/detail/eco_account/includes/documents.html:14
 | 
			
		||||
#: ema/templates/ema/detail/includes/documents.html:14
 | 
			
		||||
#: intervention/templates/intervention/detail/includes/documents.html:14
 | 
			
		||||
#: konova/forms.py:411
 | 
			
		||||
#: konova/forms.py:445
 | 
			
		||||
msgid "Add new document"
 | 
			
		||||
msgstr "Neues Dokument hinzufügen"
 | 
			
		||||
 | 
			
		||||
@ -879,7 +879,7 @@ msgstr "Neues Dokument hinzufügen"
 | 
			
		||||
#: 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
 | 
			
		||||
#: konova/forms.py:368
 | 
			
		||||
#: konova/forms.py:402
 | 
			
		||||
msgid "Created on"
 | 
			
		||||
msgstr "Erstellt"
 | 
			
		||||
 | 
			
		||||
@ -887,7 +887,7 @@ msgstr "Erstellt"
 | 
			
		||||
#: 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
 | 
			
		||||
#: konova/forms.py:474
 | 
			
		||||
#: konova/forms.py:507
 | 
			
		||||
msgid "Edit document"
 | 
			
		||||
msgstr "Dokument bearbeiten"
 | 
			
		||||
 | 
			
		||||
@ -1016,10 +1016,10 @@ msgstr "Verzeichnet am"
 | 
			
		||||
msgid "Last modified"
 | 
			
		||||
msgstr "Zuletzt bearbeitet"
 | 
			
		||||
 | 
			
		||||
#: compensation/templates/compensation/detail/compensation/view.html:100
 | 
			
		||||
#: compensation/templates/compensation/detail/eco_account/view.html:83
 | 
			
		||||
#: ema/templates/ema/detail/view.html:76
 | 
			
		||||
#: intervention/templates/intervention/detail/view.html:116
 | 
			
		||||
#: compensation/templates/compensation/detail/compensation/view.html:106
 | 
			
		||||
#: compensation/templates/compensation/detail/eco_account/view.html:89
 | 
			
		||||
#: ema/templates/ema/detail/view.html:75
 | 
			
		||||
#: intervention/templates/intervention/detail/view.html:122
 | 
			
		||||
msgid "Shared with"
 | 
			
		||||
msgstr "Freigegeben für"
 | 
			
		||||
 | 
			
		||||
@ -1067,7 +1067,7 @@ msgid "Recorded on"
 | 
			
		||||
msgstr "Verzeichnet am"
 | 
			
		||||
 | 
			
		||||
#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:65
 | 
			
		||||
#: intervention/forms/modalForms.py:481
 | 
			
		||||
#: intervention/forms/modalForms.py:490
 | 
			
		||||
#: intervention/templates/intervention/detail/includes/deductions.html:60
 | 
			
		||||
msgid "Edit Deduction"
 | 
			
		||||
msgstr "Abbuchung bearbeiten"
 | 
			
		||||
@ -1112,20 +1112,6 @@ msgstr "Maßnahmenträger"
 | 
			
		||||
msgid "Report"
 | 
			
		||||
msgstr "Bericht"
 | 
			
		||||
 | 
			
		||||
#: compensation/templates/compensation/report/compensation/report.html:45
 | 
			
		||||
#: compensation/templates/compensation/report/eco_account/report.html:58
 | 
			
		||||
#: ema/templates/ema/report/report.html:45
 | 
			
		||||
#: intervention/templates/intervention/report/report.html:104
 | 
			
		||||
msgid "Open in browser"
 | 
			
		||||
msgstr "Im Browser öffnen"
 | 
			
		||||
 | 
			
		||||
#: compensation/templates/compensation/report/compensation/report.html:49
 | 
			
		||||
#: compensation/templates/compensation/report/eco_account/report.html:62
 | 
			
		||||
#: ema/templates/ema/report/report.html:49
 | 
			
		||||
#: intervention/templates/intervention/report/report.html:108
 | 
			
		||||
msgid "View in LANIS"
 | 
			
		||||
msgstr "In LANIS öffnen"
 | 
			
		||||
 | 
			
		||||
#: compensation/templates/compensation/report/eco_account/report.html:24
 | 
			
		||||
msgid "Deductions for"
 | 
			
		||||
msgstr "Abbuchungen für"
 | 
			
		||||
@ -1155,72 +1141,72 @@ msgstr ""
 | 
			
		||||
msgid "Responsible data"
 | 
			
		||||
msgstr "Daten zu den verantwortlichen Stellen"
 | 
			
		||||
 | 
			
		||||
#: compensation/views/compensation.py:52
 | 
			
		||||
#: compensation/views/compensation.py:53
 | 
			
		||||
msgid "Compensations - Overview"
 | 
			
		||||
msgstr "Kompensationen - Übersicht"
 | 
			
		||||
 | 
			
		||||
#: compensation/views/compensation.py:151 konova/utils/message_templates.py:35
 | 
			
		||||
#: compensation/views/compensation.py:172 konova/utils/message_templates.py:36
 | 
			
		||||
msgid "Compensation {} edited"
 | 
			
		||||
msgstr "Kompensation {} bearbeitet"
 | 
			
		||||
 | 
			
		||||
#: compensation/views/compensation.py:161 compensation/views/eco_account.py:165
 | 
			
		||||
#: ema/views.py:233 intervention/views.py:327
 | 
			
		||||
#: compensation/views/compensation.py:182 compensation/views/eco_account.py:173
 | 
			
		||||
#: ema/views.py:240 intervention/views.py:335
 | 
			
		||||
msgid "Edit {}"
 | 
			
		||||
msgstr "Bearbeite {}"
 | 
			
		||||
 | 
			
		||||
#: compensation/views/compensation.py:240 compensation/views/eco_account.py:351
 | 
			
		||||
#: ema/views.py:194 intervention/views.py:531
 | 
			
		||||
#: compensation/views/compensation.py:261 compensation/views/eco_account.py:359
 | 
			
		||||
#: ema/views.py:194 intervention/views.py:539
 | 
			
		||||
msgid "Log"
 | 
			
		||||
msgstr "Log"
 | 
			
		||||
 | 
			
		||||
#: compensation/views/compensation.py:584 compensation/views/eco_account.py:719
 | 
			
		||||
#: ema/views.py:551 intervention/views.py:677
 | 
			
		||||
#: compensation/views/compensation.py:605 compensation/views/eco_account.py:727
 | 
			
		||||
#: ema/views.py:558 intervention/views.py:685
 | 
			
		||||
msgid "Report {}"
 | 
			
		||||
msgstr "Bericht {}"
 | 
			
		||||
 | 
			
		||||
#: compensation/views/eco_account.py:64
 | 
			
		||||
#: compensation/views/eco_account.py:65
 | 
			
		||||
msgid "Eco-account - Overview"
 | 
			
		||||
msgstr "Ökokonten - Übersicht"
 | 
			
		||||
 | 
			
		||||
#: compensation/views/eco_account.py:97
 | 
			
		||||
#: compensation/views/eco_account.py:98
 | 
			
		||||
msgid "Eco-Account {} added"
 | 
			
		||||
msgstr "Ökokonto {} hinzugefügt"
 | 
			
		||||
 | 
			
		||||
#: compensation/views/eco_account.py:155
 | 
			
		||||
#: compensation/views/eco_account.py:163
 | 
			
		||||
msgid "Eco-Account {} edited"
 | 
			
		||||
msgstr "Ökokonto {} bearbeitet"
 | 
			
		||||
 | 
			
		||||
#: compensation/views/eco_account.py:268
 | 
			
		||||
#: compensation/views/eco_account.py:276
 | 
			
		||||
msgid "Eco-account removed"
 | 
			
		||||
msgstr "Ökokonto entfernt"
 | 
			
		||||
 | 
			
		||||
#: compensation/views/eco_account.py:372 ema/views.py:275
 | 
			
		||||
#: intervention/views.py:630
 | 
			
		||||
#: compensation/views/eco_account.py:380 ema/views.py:282
 | 
			
		||||
#: intervention/views.py:638
 | 
			
		||||
msgid "{} unrecorded"
 | 
			
		||||
msgstr "{} entzeichnet"
 | 
			
		||||
 | 
			
		||||
#: compensation/views/eco_account.py:372 ema/views.py:275
 | 
			
		||||
#: intervention/views.py:630
 | 
			
		||||
#: compensation/views/eco_account.py:380 ema/views.py:282
 | 
			
		||||
#: intervention/views.py:638
 | 
			
		||||
msgid "{} recorded"
 | 
			
		||||
msgstr "{} verzeichnet"
 | 
			
		||||
 | 
			
		||||
#: compensation/views/eco_account.py:792 ema/views.py:617
 | 
			
		||||
#: intervention/views.py:428
 | 
			
		||||
#: compensation/views/eco_account.py:804 ema/views.py:628
 | 
			
		||||
#: intervention/views.py:436
 | 
			
		||||
msgid "{} has already been shared with you"
 | 
			
		||||
msgstr "{} wurde bereits für Sie freigegeben"
 | 
			
		||||
 | 
			
		||||
#: compensation/views/eco_account.py:797 ema/views.py:622
 | 
			
		||||
#: intervention/views.py:433
 | 
			
		||||
#: compensation/views/eco_account.py:809 ema/views.py:633
 | 
			
		||||
#: intervention/views.py:441
 | 
			
		||||
msgid "{} has been shared with you"
 | 
			
		||||
msgstr "{} ist nun für Sie freigegeben"
 | 
			
		||||
 | 
			
		||||
#: compensation/views/eco_account.py:804 ema/views.py:629
 | 
			
		||||
#: intervention/views.py:440
 | 
			
		||||
#: compensation/views/eco_account.py:816 ema/views.py:640
 | 
			
		||||
#: intervention/views.py:448
 | 
			
		||||
msgid "Share link invalid"
 | 
			
		||||
msgstr "Freigabelink ungültig"
 | 
			
		||||
 | 
			
		||||
#: compensation/views/eco_account.py:827 ema/views.py:652
 | 
			
		||||
#: intervention/views.py:463
 | 
			
		||||
#: compensation/views/eco_account.py:839 ema/views.py:663
 | 
			
		||||
#: intervention/views.py:471
 | 
			
		||||
msgid "Share settings updated"
 | 
			
		||||
msgstr "Freigabe Einstellungen aktualisiert"
 | 
			
		||||
 | 
			
		||||
@ -1260,11 +1246,11 @@ msgstr "EMAs - Übersicht"
 | 
			
		||||
msgid "EMA {} added"
 | 
			
		||||
msgstr "EMA {} hinzugefügt"
 | 
			
		||||
 | 
			
		||||
#: ema/views.py:223
 | 
			
		||||
#: ema/views.py:230
 | 
			
		||||
msgid "EMA {} edited"
 | 
			
		||||
msgstr "EMA {} bearbeitet"
 | 
			
		||||
 | 
			
		||||
#: ema/views.py:256
 | 
			
		||||
#: ema/views.py:263
 | 
			
		||||
msgid "EMA removed"
 | 
			
		||||
msgstr "EMA entfernt"
 | 
			
		||||
 | 
			
		||||
@ -1286,7 +1272,7 @@ msgstr "Mehrfachauswahl möglich"
 | 
			
		||||
#: intervention/forms/forms.py:86
 | 
			
		||||
#: intervention/templates/intervention/detail/view.html:48
 | 
			
		||||
#: intervention/templates/intervention/report/report.html:29
 | 
			
		||||
#: intervention/utils/quality.py:46 konova/filters/mixins.py:364
 | 
			
		||||
#: intervention/utils/quality.py:46 konova/filters/mixins.py:371
 | 
			
		||||
msgid "Registration office"
 | 
			
		||||
msgstr "Zulassungsbehörde"
 | 
			
		||||
 | 
			
		||||
@ -1326,7 +1312,7 @@ msgstr "Datum Zulassung bzw. Satzungsbeschluss"
 | 
			
		||||
msgid "Binding on"
 | 
			
		||||
msgstr "Datum Bestandskraft"
 | 
			
		||||
 | 
			
		||||
#: intervention/forms/forms.py:211 intervention/views.py:94
 | 
			
		||||
#: intervention/forms/forms.py:211 intervention/views.py:95
 | 
			
		||||
msgid "New intervention"
 | 
			
		||||
msgstr "Neuer Eingriff"
 | 
			
		||||
 | 
			
		||||
@ -1406,7 +1392,7 @@ msgstr "Kompensationen und Zahlungen geprüft"
 | 
			
		||||
msgid "Run check"
 | 
			
		||||
msgstr "Prüfung vornehmen"
 | 
			
		||||
 | 
			
		||||
#: intervention/forms/modalForms.py:264 konova/forms.py:515
 | 
			
		||||
#: intervention/forms/modalForms.py:264 konova/forms.py:548
 | 
			
		||||
msgid ""
 | 
			
		||||
"I, {} {}, confirm that all necessary control steps have been performed by "
 | 
			
		||||
"myself."
 | 
			
		||||
@ -1430,7 +1416,7 @@ msgstr "Neue Abbuchung"
 | 
			
		||||
msgid "Enter the information for a new deduction from a chosen eco-account"
 | 
			
		||||
msgstr "Geben Sie die Informationen für eine neue Abbuchung ein."
 | 
			
		||||
 | 
			
		||||
#: intervention/forms/modalForms.py:434
 | 
			
		||||
#: intervention/forms/modalForms.py:436
 | 
			
		||||
msgid ""
 | 
			
		||||
"Eco-account {} is not recorded yet. You can only deduct from recorded "
 | 
			
		||||
"accounts."
 | 
			
		||||
@ -1438,7 +1424,15 @@ msgstr ""
 | 
			
		||||
"Ökokonto {} ist noch nicht verzeichnet. Abbuchungen können nur von "
 | 
			
		||||
"verzeichneten Ökokonten erfolgen."
 | 
			
		||||
 | 
			
		||||
#: intervention/forms/modalForms.py:444
 | 
			
		||||
#: intervention/forms/modalForms.py:443
 | 
			
		||||
msgid ""
 | 
			
		||||
"Intervention {} is currently recorded. To change any data on it, the entry "
 | 
			
		||||
"must be unrecorded."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Eingriff {} ist verzeichnet. Der Eintrag muss erst entzeichnet werden um "
 | 
			
		||||
"fortfahren zu können."
 | 
			
		||||
 | 
			
		||||
#: intervention/forms/modalForms.py:453
 | 
			
		||||
msgid ""
 | 
			
		||||
"The account {} has not enough surface for a deduction of {} m². There are "
 | 
			
		||||
"only {} m² left"
 | 
			
		||||
@ -1538,27 +1532,27 @@ msgstr ""
 | 
			
		||||
"Kein Ausgleich jeglicher Art gefunden (Kompensation, Ersatzzahlung, "
 | 
			
		||||
"Abbuchung)"
 | 
			
		||||
 | 
			
		||||
#: intervention/views.py:51
 | 
			
		||||
#: intervention/views.py:52
 | 
			
		||||
msgid "Interventions - Overview"
 | 
			
		||||
msgstr "Eingriffe - Übersicht"
 | 
			
		||||
 | 
			
		||||
#: intervention/views.py:84
 | 
			
		||||
#: intervention/views.py:85
 | 
			
		||||
msgid "Intervention {} added"
 | 
			
		||||
msgstr "Eingriff {} hinzugefügt"
 | 
			
		||||
 | 
			
		||||
#: intervention/views.py:315
 | 
			
		||||
#: intervention/views.py:323
 | 
			
		||||
msgid "Intervention {} edited"
 | 
			
		||||
msgstr "Eingriff {} bearbeitet"
 | 
			
		||||
 | 
			
		||||
#: intervention/views.py:351
 | 
			
		||||
#: intervention/views.py:359
 | 
			
		||||
msgid "{} removed"
 | 
			
		||||
msgstr "{} entfernt"
 | 
			
		||||
 | 
			
		||||
#: intervention/views.py:484
 | 
			
		||||
#: intervention/views.py:492
 | 
			
		||||
msgid "Check performed"
 | 
			
		||||
msgstr "Prüfung durchgeführt"
 | 
			
		||||
 | 
			
		||||
#: intervention/views.py:635
 | 
			
		||||
#: intervention/views.py:643
 | 
			
		||||
msgid "There are errors on this intervention:"
 | 
			
		||||
msgstr "Es liegen Fehler in diesem Eingriff vor:"
 | 
			
		||||
 | 
			
		||||
@ -1588,6 +1582,7 @@ msgid "Search for file number"
 | 
			
		||||
msgstr "Nach Aktenzeichen suchen"
 | 
			
		||||
 | 
			
		||||
#: konova/filters/mixins.py:85
 | 
			
		||||
#: konova/templates/konova/includes/parcel_table.html:13
 | 
			
		||||
msgid "District"
 | 
			
		||||
msgstr "Kreis"
 | 
			
		||||
 | 
			
		||||
@ -1600,7 +1595,7 @@ msgid "Search for parcel gmrkng"
 | 
			
		||||
msgstr "Nach Gemarkung suchen"
 | 
			
		||||
 | 
			
		||||
#: konova/filters/mixins.py:111
 | 
			
		||||
#: konova/templates/konova/includes/parcel_table.html:13
 | 
			
		||||
#: konova/templates/konova/includes/parcel_table.html:34
 | 
			
		||||
msgid "Parcel"
 | 
			
		||||
msgstr "Flur"
 | 
			
		||||
 | 
			
		||||
@ -1609,7 +1604,7 @@ msgid "Search for parcel"
 | 
			
		||||
msgstr "Nach Flur suchen"
 | 
			
		||||
 | 
			
		||||
#: konova/filters/mixins.py:124
 | 
			
		||||
#: konova/templates/konova/includes/parcel_table.html:14
 | 
			
		||||
#: konova/templates/konova/includes/parcel_table.html:35
 | 
			
		||||
msgid "Parcel counter"
 | 
			
		||||
msgstr "Flurstückzähler"
 | 
			
		||||
 | 
			
		||||
@ -1618,7 +1613,7 @@ msgid "Search for parcel counter"
 | 
			
		||||
msgstr "Nach Flurstückzähler suchen"
 | 
			
		||||
 | 
			
		||||
#: konova/filters/mixins.py:138
 | 
			
		||||
#: konova/templates/konova/includes/parcel_table.html:15
 | 
			
		||||
#: konova/templates/konova/includes/parcel_table.html:36
 | 
			
		||||
msgid "Parcel number"
 | 
			
		||||
msgstr "Flurstücknenner"
 | 
			
		||||
 | 
			
		||||
@ -1626,19 +1621,19 @@ msgstr "Flurstücknenner"
 | 
			
		||||
msgid "Search for parcel number"
 | 
			
		||||
msgstr "Nach Flurstücknenner suchen"
 | 
			
		||||
 | 
			
		||||
#: konova/filters/mixins.py:269
 | 
			
		||||
#: konova/filters/mixins.py:276
 | 
			
		||||
msgid "Show unshared"
 | 
			
		||||
msgstr "Nicht freigegebene anzeigen"
 | 
			
		||||
 | 
			
		||||
#: konova/filters/mixins.py:315
 | 
			
		||||
#: konova/filters/mixins.py:322
 | 
			
		||||
msgid "Show recorded"
 | 
			
		||||
msgstr "Verzeichnete anzeigen"
 | 
			
		||||
 | 
			
		||||
#: konova/filters/mixins.py:365
 | 
			
		||||
#: konova/filters/mixins.py:372
 | 
			
		||||
msgid "Search for registration office"
 | 
			
		||||
msgstr "Nach Zulassungsbehörde suchen"
 | 
			
		||||
 | 
			
		||||
#: konova/filters/mixins.py:397
 | 
			
		||||
#: konova/filters/mixins.py:404
 | 
			
		||||
msgid "Search for conservation office"
 | 
			
		||||
msgstr "Nch Eintragungsstelle suchen"
 | 
			
		||||
 | 
			
		||||
@ -1646,65 +1641,65 @@ msgstr "Nch Eintragungsstelle suchen"
 | 
			
		||||
msgid "Save"
 | 
			
		||||
msgstr "Speichern"
 | 
			
		||||
 | 
			
		||||
#: konova/forms.py:71
 | 
			
		||||
#: konova/forms.py:73
 | 
			
		||||
msgid "Not editable"
 | 
			
		||||
msgstr "Nicht editierbar"
 | 
			
		||||
 | 
			
		||||
#: konova/forms.py:142 konova/forms.py:314
 | 
			
		||||
#: konova/forms.py:176 konova/forms.py:348
 | 
			
		||||
msgid "Confirm"
 | 
			
		||||
msgstr "Bestätige"
 | 
			
		||||
 | 
			
		||||
#: konova/forms.py:154 konova/forms.py:323
 | 
			
		||||
#: konova/forms.py:188 konova/forms.py:357
 | 
			
		||||
msgid "Remove"
 | 
			
		||||
msgstr "Löschen"
 | 
			
		||||
 | 
			
		||||
#: konova/forms.py:156
 | 
			
		||||
#: konova/forms.py:190
 | 
			
		||||
msgid "You are about to remove {} {}"
 | 
			
		||||
msgstr "Sie sind dabei {} {} zu löschen"
 | 
			
		||||
 | 
			
		||||
#: konova/forms.py:243 konova/utils/quality.py:44 konova/utils/quality.py:46
 | 
			
		||||
#: konova/forms.py:277 konova/utils/quality.py:44 konova/utils/quality.py:46
 | 
			
		||||
#: templates/form/collapsable/form.html:45
 | 
			
		||||
msgid "Geometry"
 | 
			
		||||
msgstr "Geometrie"
 | 
			
		||||
 | 
			
		||||
#: konova/forms.py:324
 | 
			
		||||
#: konova/forms.py:358
 | 
			
		||||
msgid "Are you sure?"
 | 
			
		||||
msgstr "Sind Sie sicher?"
 | 
			
		||||
 | 
			
		||||
#: konova/forms.py:370
 | 
			
		||||
#: konova/forms.py:404
 | 
			
		||||
msgid "When has this file been created? Important for photos."
 | 
			
		||||
msgstr "Wann wurde diese Datei erstellt oder das Foto aufgenommen?"
 | 
			
		||||
 | 
			
		||||
#: konova/forms.py:381
 | 
			
		||||
#: konova/forms.py:415
 | 
			
		||||
#: venv/lib/python3.7/site-packages/django/db/models/fields/files.py:231
 | 
			
		||||
msgid "File"
 | 
			
		||||
msgstr "Datei"
 | 
			
		||||
 | 
			
		||||
#: konova/forms.py:383
 | 
			
		||||
#: konova/forms.py:417
 | 
			
		||||
msgid "Allowed formats: pdf, jpg, png. Max size 15 MB."
 | 
			
		||||
msgstr "Formate: pdf, jpg, png. Maximal 15 MB."
 | 
			
		||||
 | 
			
		||||
#: konova/forms.py:449
 | 
			
		||||
#: konova/forms.py:482
 | 
			
		||||
msgid "Added document"
 | 
			
		||||
msgstr "Dokument hinzugefügt"
 | 
			
		||||
 | 
			
		||||
#: konova/forms.py:506
 | 
			
		||||
#: konova/forms.py:539
 | 
			
		||||
msgid "Confirm record"
 | 
			
		||||
msgstr "Verzeichnen bestätigen"
 | 
			
		||||
 | 
			
		||||
#: konova/forms.py:514
 | 
			
		||||
#: konova/forms.py:547
 | 
			
		||||
msgid "Record data"
 | 
			
		||||
msgstr "Daten verzeichnen"
 | 
			
		||||
 | 
			
		||||
#: konova/forms.py:521
 | 
			
		||||
#: konova/forms.py:554
 | 
			
		||||
msgid "Confirm unrecord"
 | 
			
		||||
msgstr "Entzeichnen bestätigen"
 | 
			
		||||
 | 
			
		||||
#: konova/forms.py:522
 | 
			
		||||
#: konova/forms.py:555
 | 
			
		||||
msgid "Unrecord data"
 | 
			
		||||
msgstr "Daten entzeichnen"
 | 
			
		||||
 | 
			
		||||
#: konova/forms.py:523
 | 
			
		||||
#: konova/forms.py:556
 | 
			
		||||
msgid "I, {} {}, confirm that this data must be unrecorded."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Ich, {} {}, bestätige, dass diese Daten wieder entzeichnet werden müssen."
 | 
			
		||||
@ -1745,11 +1740,11 @@ msgstr "Kontrolle am"
 | 
			
		||||
msgid "Other"
 | 
			
		||||
msgstr "Sonstige"
 | 
			
		||||
 | 
			
		||||
#: konova/sub_settings/django_settings.py:159
 | 
			
		||||
#: konova/sub_settings/django_settings.py:160
 | 
			
		||||
msgid "German"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: konova/sub_settings/django_settings.py:160
 | 
			
		||||
#: konova/sub_settings/django_settings.py:161
 | 
			
		||||
msgid "English"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
@ -1760,21 +1755,29 @@ msgstr ""
 | 
			
		||||
"wurde."
 | 
			
		||||
 | 
			
		||||
#: konova/templates/konova/includes/parcel_table.html:11
 | 
			
		||||
msgid "Kreis"
 | 
			
		||||
msgstr "Kreis"
 | 
			
		||||
msgid "Municipal"
 | 
			
		||||
msgstr "Gemeinde"
 | 
			
		||||
 | 
			
		||||
#: konova/templates/konova/includes/parcel_table.html:12
 | 
			
		||||
msgid "Gemarkung"
 | 
			
		||||
msgid "Municipal key"
 | 
			
		||||
msgstr "Gemeindeschlüssel"
 | 
			
		||||
 | 
			
		||||
#: konova/templates/konova/includes/parcel_table.html:14
 | 
			
		||||
msgid "District key"
 | 
			
		||||
msgstr "Kreisschlüssel"
 | 
			
		||||
 | 
			
		||||
#: konova/templates/konova/includes/parcel_table.html:32
 | 
			
		||||
msgid "Parcel group"
 | 
			
		||||
msgstr "Gemarkung"
 | 
			
		||||
 | 
			
		||||
#: konova/templates/konova/includes/parcel_table.html:33
 | 
			
		||||
msgid "Parcel group key"
 | 
			
		||||
msgstr "Gemarkungsschlüssel"
 | 
			
		||||
 | 
			
		||||
#: konova/templates/konova/includes/parcels.html:7
 | 
			
		||||
msgid "Spatial reference"
 | 
			
		||||
msgstr "Raumreferenz"
 | 
			
		||||
 | 
			
		||||
#: konova/templates/konova/includes/parcels.html:11
 | 
			
		||||
msgid "Loading..."
 | 
			
		||||
msgstr "Lade..."
 | 
			
		||||
 | 
			
		||||
#: konova/templates/konova/includes/quickstart/compensations.html:20
 | 
			
		||||
#: konova/templates/konova/includes/quickstart/ecoaccounts.html:20
 | 
			
		||||
#: konova/templates/konova/includes/quickstart/interventions.html:20
 | 
			
		||||
@ -1793,6 +1796,14 @@ msgstr "Neu"
 | 
			
		||||
msgid "Show"
 | 
			
		||||
msgstr "Anzeigen"
 | 
			
		||||
 | 
			
		||||
#: konova/templates/konova/includes/report/qrcodes.html:7
 | 
			
		||||
msgid "Open in browser"
 | 
			
		||||
msgstr "Im Browser öffnen"
 | 
			
		||||
 | 
			
		||||
#: konova/templates/konova/includes/report/qrcodes.html:15
 | 
			
		||||
msgid "View in LANIS"
 | 
			
		||||
msgstr "In LANIS öffnen"
 | 
			
		||||
 | 
			
		||||
#: konova/templates/konova/widgets/checkbox-tree-select.html:4
 | 
			
		||||
#: templates/generic_index.html:56
 | 
			
		||||
msgid "Search"
 | 
			
		||||
@ -1886,11 +1897,18 @@ msgstr "Hierfür müssen Sie einer anderen Nutzergruppe angehören!"
 | 
			
		||||
msgid "Status of Checked and Recorded reseted"
 | 
			
		||||
msgstr "'Geprüft'/'Verzeichnet' wurde zurückgesetzt"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:22
 | 
			
		||||
#: konova/utils/message_templates.py:20
 | 
			
		||||
msgid ""
 | 
			
		||||
"Entry is recorded. To edit data, the entry first needs to be unrecorded."
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Eintrag ist verzeichnet. Um Daten zu bearbeiten, muss der Eintrag erst "
 | 
			
		||||
"entzeichnet werden."
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:23
 | 
			
		||||
msgid "This data is not shared with you"
 | 
			
		||||
msgstr "Diese Daten sind für Sie nicht freigegeben"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:23
 | 
			
		||||
#: konova/utils/message_templates.py:24
 | 
			
		||||
msgid ""
 | 
			
		||||
"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 "
 | 
			
		||||
@ -1900,15 +1918,15 @@ msgstr ""
 | 
			
		||||
"bedeutet, dass Sie nur lesenden Zugriff hierauf haben und weder bearbeiten, "
 | 
			
		||||
"noch Prüfungen durchführen oder verzeichnen können."
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:26
 | 
			
		||||
#: konova/utils/message_templates.py:27
 | 
			
		||||
msgid "Unsupported file type"
 | 
			
		||||
msgstr "Dateiformat nicht unterstützt"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:27
 | 
			
		||||
#: konova/utils/message_templates.py:28
 | 
			
		||||
msgid "File too large"
 | 
			
		||||
msgstr "Datei zu groß"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:30
 | 
			
		||||
#: konova/utils/message_templates.py:31
 | 
			
		||||
msgid ""
 | 
			
		||||
"Action canceled. Eco account is recorded or deductions exist. Only "
 | 
			
		||||
"conservation office member can perform this action."
 | 
			
		||||
@ -1916,119 +1934,119 @@ msgstr ""
 | 
			
		||||
"Aktion abgebrochen. Ökokonto ist bereits verzeichnet oder Abbuchungen liegen "
 | 
			
		||||
"vor. Nur Eintragungsstellennutzer können diese Aktion jetzt durchführen."
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:33
 | 
			
		||||
#: konova/utils/message_templates.py:34
 | 
			
		||||
msgid "Compensation {} added"
 | 
			
		||||
msgstr "Kompensation {} hinzugefügt"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:34
 | 
			
		||||
#: konova/utils/message_templates.py:35
 | 
			
		||||
msgid "Compensation {} removed"
 | 
			
		||||
msgstr "Kompensation {} entfernt"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:36
 | 
			
		||||
#: konova/utils/message_templates.py:37
 | 
			
		||||
msgid "Added compensation action"
 | 
			
		||||
msgstr "Maßnahme hinzugefügt"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:37
 | 
			
		||||
#: konova/utils/message_templates.py:38
 | 
			
		||||
msgid "Added compensation state"
 | 
			
		||||
msgstr "Zustand hinzugefügt"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:40
 | 
			
		||||
#: konova/utils/message_templates.py:41
 | 
			
		||||
msgid "State removed"
 | 
			
		||||
msgstr "Zustand gelöscht"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:41
 | 
			
		||||
#: konova/utils/message_templates.py:42
 | 
			
		||||
msgid "State edited"
 | 
			
		||||
msgstr "Zustand bearbeitet"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:42
 | 
			
		||||
#: konova/utils/message_templates.py:43
 | 
			
		||||
msgid "State added"
 | 
			
		||||
msgstr "Zustand hinzugefügt"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:45
 | 
			
		||||
#: konova/utils/message_templates.py:46
 | 
			
		||||
msgid "Action added"
 | 
			
		||||
msgstr "Maßnahme hinzugefügt"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:46
 | 
			
		||||
#: konova/utils/message_templates.py:47
 | 
			
		||||
msgid "Action edited"
 | 
			
		||||
msgstr "Maßnahme bearbeitet"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:47
 | 
			
		||||
#: konova/utils/message_templates.py:48
 | 
			
		||||
msgid "Action removed"
 | 
			
		||||
msgstr "Maßnahme entfernt"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:50
 | 
			
		||||
#: konova/utils/message_templates.py:51
 | 
			
		||||
msgid "Deduction added"
 | 
			
		||||
msgstr "Abbuchung hinzugefügt"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:51
 | 
			
		||||
#: konova/utils/message_templates.py:52
 | 
			
		||||
msgid "Deduction edited"
 | 
			
		||||
msgstr "Abbuchung bearbeitet"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:52
 | 
			
		||||
#: konova/utils/message_templates.py:53
 | 
			
		||||
msgid "Deduction removed"
 | 
			
		||||
msgstr "Abbuchung entfernt"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:55
 | 
			
		||||
#: konova/utils/message_templates.py:56
 | 
			
		||||
msgid "Deadline added"
 | 
			
		||||
msgstr "Frist/Termin hinzugefügt"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:56
 | 
			
		||||
#: konova/utils/message_templates.py:57
 | 
			
		||||
msgid "Deadline edited"
 | 
			
		||||
msgstr "Frist/Termin bearbeitet"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:57
 | 
			
		||||
#: konova/utils/message_templates.py:58
 | 
			
		||||
msgid "Deadline removed"
 | 
			
		||||
msgstr "Frist/Termin gelöscht"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:60
 | 
			
		||||
#: konova/utils/message_templates.py:61
 | 
			
		||||
msgid "Payment added"
 | 
			
		||||
msgstr "Zahlung hinzugefügt"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:61
 | 
			
		||||
#: konova/utils/message_templates.py:62
 | 
			
		||||
msgid "Payment edited"
 | 
			
		||||
msgstr "Zahlung bearbeitet"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:62
 | 
			
		||||
#: konova/utils/message_templates.py:63
 | 
			
		||||
msgid "Payment removed"
 | 
			
		||||
msgstr "Zahlung gelöscht"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:65
 | 
			
		||||
#: konova/utils/message_templates.py:66
 | 
			
		||||
msgid "Revocation added"
 | 
			
		||||
msgstr "Widerspruch hinzugefügt"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:66
 | 
			
		||||
#: konova/utils/message_templates.py:67
 | 
			
		||||
msgid "Revocation edited"
 | 
			
		||||
msgstr "Widerspruch bearbeitet"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:67
 | 
			
		||||
#: konova/utils/message_templates.py:68
 | 
			
		||||
msgid "Revocation removed"
 | 
			
		||||
msgstr "Widerspruch entfernt"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:70
 | 
			
		||||
#: konova/utils/message_templates.py:71
 | 
			
		||||
msgid "Document '{}' deleted"
 | 
			
		||||
msgstr "Dokument '{}' gelöscht"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:71
 | 
			
		||||
#: konova/utils/message_templates.py:72
 | 
			
		||||
msgid "Document added"
 | 
			
		||||
msgstr "Dokument hinzugefügt"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:72
 | 
			
		||||
#: konova/utils/message_templates.py:73
 | 
			
		||||
msgid "Document edited"
 | 
			
		||||
msgstr "Dokument bearbeitet"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:75
 | 
			
		||||
#: konova/utils/message_templates.py:76
 | 
			
		||||
msgid "Edited general data"
 | 
			
		||||
msgstr "Allgemeine Daten bearbeitet"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:76
 | 
			
		||||
#: konova/utils/message_templates.py:77
 | 
			
		||||
msgid "Added deadline"
 | 
			
		||||
msgstr "Frist/Termin hinzugefügt"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:79
 | 
			
		||||
#: konova/utils/message_templates.py:80
 | 
			
		||||
msgid "Geometry conflict detected with {}"
 | 
			
		||||
msgstr "Geometriekonflikt mit folgenden Einträgen erkannt: {}"
 | 
			
		||||
 | 
			
		||||
#: konova/utils/message_templates.py:82
 | 
			
		||||
#: konova/utils/message_templates.py:83
 | 
			
		||||
msgid "This intervention has {} revocations"
 | 
			
		||||
msgstr "Dem Eingriff liegen {} Widersprüche vor"
 | 
			
		||||
 | 
			
		||||
@ -2355,6 +2373,25 @@ msgstr "Allgemeine Daten"
 | 
			
		||||
msgid "Cancel"
 | 
			
		||||
msgstr "Abbrechen"
 | 
			
		||||
 | 
			
		||||
#: templates/form/recorded_no_edit.html:9
 | 
			
		||||
msgid "This data is recorded"
 | 
			
		||||
msgstr "Daten sind verzeichnet"
 | 
			
		||||
 | 
			
		||||
#: templates/form/recorded_no_edit.html:14
 | 
			
		||||
msgid ""
 | 
			
		||||
"\n"
 | 
			
		||||
"        Whilst recorded the data is published publicly. If you wish to edit "
 | 
			
		||||
"any information on this data, the data needs\n"
 | 
			
		||||
"        to be unrecorded first. Do not forget to record it afterwards, "
 | 
			
		||||
"again.\n"
 | 
			
		||||
"        "
 | 
			
		||||
msgstr ""
 | 
			
		||||
"\n"
 | 
			
		||||
"Verzeichnete Daten sind öffentlich einsehbar. Wenn Sie Informationen "
 | 
			
		||||
"überarbeiten möchten muss dieser Datensatz zunächst entzeichnet werden. "
 | 
			
		||||
"Vergessen Sie nicht ihn anschließend wieder zu verzeichnen.\n"
 | 
			
		||||
" "
 | 
			
		||||
 | 
			
		||||
#: templates/form/table/generic_table_form_body.html:24
 | 
			
		||||
msgid "Fields with * are required."
 | 
			
		||||
msgstr "* sind Pflichtfelder."
 | 
			
		||||
@ -2435,13 +2472,16 @@ msgstr "Daten nicht veröffentlicht"
 | 
			
		||||
msgid ""
 | 
			
		||||
"\n"
 | 
			
		||||
"            The data you want to see is not recorded and might still be work "
 | 
			
		||||
"in progress. Please come back another time.\n"
 | 
			
		||||
"in progress or the legal binding date has\n"
 | 
			
		||||
"            not been reached yet. We can not publish this report as long as "
 | 
			
		||||
"revocations could occur.\n"
 | 
			
		||||
"            Please come back later.\n"
 | 
			
		||||
"            "
 | 
			
		||||
msgstr ""
 | 
			
		||||
"\n"
 | 
			
		||||
"            Diese Daten sind noch nicht veröffentlicht und können daher "
 | 
			
		||||
"aktuell nicht eingesehen werden. Schauen Sie zu einem späteren Zeitpunkt "
 | 
			
		||||
"wieder vorbei. \n"
 | 
			
		||||
"            Diese Daten sind noch nicht veröffentlicht und/oder haben das "
 | 
			
		||||
"Bestandskraftdatum noch nicht erreicht. Sie können daher aktuell nicht "
 | 
			
		||||
"eingesehen werden. Schauen Sie zu einem späteren Zeitpunkt wieder vorbei. \n"
 | 
			
		||||
"            "
 | 
			
		||||
 | 
			
		||||
#: templates/table/gmrkng_col.html:6
 | 
			
		||||
@ -2492,11 +2532,11 @@ msgstr "Neuen Token generieren"
 | 
			
		||||
msgid "A new token needs to be validated by an administrator!"
 | 
			
		||||
msgstr "Neue Tokens müssen durch Administratoren freigeschaltet werden!"
 | 
			
		||||
 | 
			
		||||
#: user/forms.py:168 user/forms.py:172 user/forms.py:323 user/forms.py:328
 | 
			
		||||
#: user/forms.py:168 user/forms.py:172 user/forms.py:332 user/forms.py:337
 | 
			
		||||
msgid "Team name"
 | 
			
		||||
msgstr "Team Name"
 | 
			
		||||
 | 
			
		||||
#: user/forms.py:179 user/forms.py:336 user/templates/user/team/index.html:30
 | 
			
		||||
#: user/forms.py:179 user/forms.py:345 user/templates/user/team/index.html:30
 | 
			
		||||
msgid "Description"
 | 
			
		||||
msgstr "Beschreibung"
 | 
			
		||||
 | 
			
		||||
@ -2540,11 +2580,15 @@ msgstr "Administratoren verwalten die Teamdaten und Mitglieder"
 | 
			
		||||
msgid "Selected admin ({}) needs to be a member of this team."
 | 
			
		||||
msgstr "Gewählter Administrator ({}) muss ein Mitglied des Teams sein."
 | 
			
		||||
 | 
			
		||||
#: user/forms.py:291 user/templates/user/team/index.html:51
 | 
			
		||||
#: user/forms.py:291 user/templates/user/team/index.html:54
 | 
			
		||||
msgid "Edit team"
 | 
			
		||||
msgstr "Team bearbeiten"
 | 
			
		||||
 | 
			
		||||
#: user/forms.py:347
 | 
			
		||||
#: user/forms.py:323 user/templates/user/team/index.html:50
 | 
			
		||||
msgid "Leave team"
 | 
			
		||||
msgstr "Team verlassen"
 | 
			
		||||
 | 
			
		||||
#: user/forms.py:356
 | 
			
		||||
msgid "Team"
 | 
			
		||||
msgstr "Team"
 | 
			
		||||
 | 
			
		||||
@ -2606,22 +2650,22 @@ msgid "Notification settings"
 | 
			
		||||
msgstr "Benachrichtigungen"
 | 
			
		||||
 | 
			
		||||
#: 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:61
 | 
			
		||||
msgid "API"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: user/templates/user/index.html:66
 | 
			
		||||
msgid "Manage teams"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: user/templates/user/index.html:69 user/templates/user/team/index.html:18
 | 
			
		||||
#: user/templates/user/index.html:61 user/templates/user/team/index.html:18
 | 
			
		||||
#: user/views.py:167
 | 
			
		||||
msgid "Teams"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: user/templates/user/index.html:66
 | 
			
		||||
msgid "See or edit your API token"
 | 
			
		||||
msgstr "API token einsehen oder neu generieren"
 | 
			
		||||
 | 
			
		||||
#: user/templates/user/index.html:69
 | 
			
		||||
msgid "API"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#: user/templates/user/team/index.html:20
 | 
			
		||||
msgid "Add new team"
 | 
			
		||||
msgstr "Neues Team hinzufügen"
 | 
			
		||||
@ -2630,7 +2674,7 @@ msgstr "Neues Team hinzufügen"
 | 
			
		||||
msgid "Members"
 | 
			
		||||
msgstr "Mitglieder"
 | 
			
		||||
 | 
			
		||||
#: user/templates/user/team/index.html:54
 | 
			
		||||
#: user/templates/user/team/index.html:57
 | 
			
		||||
msgid "Remove team"
 | 
			
		||||
msgstr "Team entfernen"
 | 
			
		||||
 | 
			
		||||
@ -2690,6 +2734,14 @@ msgstr "Team bearbeitet"
 | 
			
		||||
msgid "Team removed"
 | 
			
		||||
msgstr "Team gelöscht"
 | 
			
		||||
 | 
			
		||||
#: user/views.py:218
 | 
			
		||||
msgid "You are not a member of this team"
 | 
			
		||||
msgstr "Sie sind kein Mitglied dieses Teams"
 | 
			
		||||
 | 
			
		||||
#: user/views.py:225
 | 
			
		||||
msgid "Left Team"
 | 
			
		||||
msgstr "Team verlassen"
 | 
			
		||||
 | 
			
		||||
#: venv/lib/python3.7/site-packages/bootstrap4/components.py:17
 | 
			
		||||
#: venv/lib/python3.7/site-packages/bootstrap4/templates/bootstrap4/form_errors.html:3
 | 
			
		||||
#: venv/lib/python3.7/site-packages/bootstrap4/templates/bootstrap4/messages.html:4
 | 
			
		||||
@ -4189,5 +4241,14 @@ msgstr ""
 | 
			
		||||
msgid "Unable to connect to qpid with SASL mechanism %s"
 | 
			
		||||
msgstr ""
 | 
			
		||||
 | 
			
		||||
#~ msgid "Kreis"
 | 
			
		||||
#~ msgstr "Kreis"
 | 
			
		||||
 | 
			
		||||
#~ msgid "Gemarkung"
 | 
			
		||||
#~ msgstr "Gemarkung"
 | 
			
		||||
 | 
			
		||||
#~ msgid "Loading..."
 | 
			
		||||
#~ msgstr "Lade..."
 | 
			
		||||
 | 
			
		||||
#~ msgid "Who handles the eco-account"
 | 
			
		||||
#~ msgstr "Wer für die Herrichtung des Ökokontos verantwortlich ist"
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										19
									
								
								templates/form/recorded_no_edit.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								templates/form/recorded_no_edit.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
{% load i18n fontawesome_5 %}
 | 
			
		||||
 | 
			
		||||
<div class="p-5 col-sm-12">
 | 
			
		||||
    <h4>
 | 
			
		||||
        <span class="registered-bookmark">
 | 
			
		||||
            {% fa5_icon 'bookmark' %}
 | 
			
		||||
        </span>
 | 
			
		||||
        <span>
 | 
			
		||||
            {% trans 'This data is recorded' %}
 | 
			
		||||
        </span>
 | 
			
		||||
    </h4>
 | 
			
		||||
    <hr>
 | 
			
		||||
    <article>
 | 
			
		||||
        {% blocktrans %}
 | 
			
		||||
        Whilst recorded the data is published publicly. If you wish to edit any information on this data, the data needs
 | 
			
		||||
        to be unrecorded first. Do not forget to record it afterwards, again.
 | 
			
		||||
        {% endblocktrans %}
 | 
			
		||||
    </article>
 | 
			
		||||
</div>
 | 
			
		||||
@ -7,7 +7,9 @@
 | 
			
		||||
        <hr>
 | 
			
		||||
        <p class="lead">
 | 
			
		||||
            {% blocktrans %}
 | 
			
		||||
            The data you want to see is not recorded and might still be work in progress. Please come back another time.
 | 
			
		||||
            The data you want to see is not recorded and might still be work in progress or the legal binding date has
 | 
			
		||||
            not been reached yet. We can not publish this report as long as revocations could occur.
 | 
			
		||||
            Please come back later.
 | 
			
		||||
            {% endblocktrans %}
 | 
			
		||||
        </p>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
@ -74,6 +74,15 @@ class TeamAdmin(admin.ModelAdmin):
 | 
			
		||||
        "name",
 | 
			
		||||
        "description",
 | 
			
		||||
    ]
 | 
			
		||||
    filter_horizontal = [
 | 
			
		||||
        "users"
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
 | 
			
		||||
        if db_field.name == "admin":
 | 
			
		||||
            team_id = request.resolver_match.kwargs.get("object_id", None)
 | 
			
		||||
            kwargs["queryset"] = User.objects.filter(teams__id__in=[team_id])
 | 
			
		||||
        return super().formfield_for_foreignkey(db_field, request, **kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
admin.site.register(User, UserAdmin)
 | 
			
		||||
 | 
			
		||||
@ -317,6 +317,15 @@ class RemoveTeamModalForm(RemoveModalForm):
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class LeaveTeamModalForm(RemoveModalForm):
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super().__init__(*args, **kwargs)
 | 
			
		||||
        self.form_title = _("Leave team")
 | 
			
		||||
 | 
			
		||||
    def save(self):
 | 
			
		||||
        self.instance.remove_user(self.user)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TeamDataForm(BaseModalForm):
 | 
			
		||||
    name = forms.CharField(
 | 
			
		||||
        label_suffix="",
 | 
			
		||||
 | 
			
		||||
@ -93,3 +93,17 @@ class Team(UuidModel):
 | 
			
		||||
        """
 | 
			
		||||
        mailer = Mailer()
 | 
			
		||||
        mailer.send_mail_shared_data_deleted_team(obj_identifier, obj_title, self)
 | 
			
		||||
 | 
			
		||||
    def remove_user(self, user):
 | 
			
		||||
        """ Removes a user from the team
 | 
			
		||||
 | 
			
		||||
        Args:
 | 
			
		||||
            user (User): The user to be removed
 | 
			
		||||
 | 
			
		||||
        Returns:
 | 
			
		||||
 | 
			
		||||
        """
 | 
			
		||||
        self.users.remove(user)
 | 
			
		||||
        if self.admin == user:
 | 
			
		||||
            self.admin = self.users.first()
 | 
			
		||||
            self.save()
 | 
			
		||||
 | 
			
		||||
@ -10,7 +10,7 @@ import uuid
 | 
			
		||||
from django.db import models
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from konova.sub_settings.django_settings import DEFAULT_DATE_FORMAT, DEFAULT_DATE_TIME_FORMAT
 | 
			
		||||
from konova.sub_settings.django_settings import DEFAULT_DATE_TIME_FORMAT
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class UserAction(models.TextChoices):
 | 
			
		||||
 | 
			
		||||
@ -54,14 +54,6 @@
 | 
			
		||||
                        </button>
 | 
			
		||||
                    </a>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="row mb-2">
 | 
			
		||||
                    <a href="{% url 'user:api-token' %}" title="{% trans 'See or edit your API token' %}">
 | 
			
		||||
                        <button class="btn btn-default">
 | 
			
		||||
                            {% fa5_icon 'code' %}
 | 
			
		||||
                            <span>{% trans 'API' %}</span>
 | 
			
		||||
                        </button>
 | 
			
		||||
                    </a>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="row mb-2">
 | 
			
		||||
                    <a href="{% url 'user:team-index' %}" title="{% trans 'Manage teams' %}">
 | 
			
		||||
                        <button class="btn btn-default">
 | 
			
		||||
@ -70,6 +62,14 @@
 | 
			
		||||
                        </button>
 | 
			
		||||
                    </a>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="row mb-2">
 | 
			
		||||
                    <a href="{% url 'user:api-token' %}" title="{% trans 'See or edit your API token' %}">
 | 
			
		||||
                        <button class="btn btn-default">
 | 
			
		||||
                            {% fa5_icon 'code' %}
 | 
			
		||||
                            <span>{% trans 'API' %}</span>
 | 
			
		||||
                        </button>
 | 
			
		||||
                    </a>
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
@ -46,6 +46,9 @@
 | 
			
		||||
                            {% endfor %}
 | 
			
		||||
                        </td>
 | 
			
		||||
                        <td>
 | 
			
		||||
                            <button class="btn rlp-r btn-modal" data-form-url="{% url 'user:team-leave' team.id %}" title="{% trans 'Leave team' %}">
 | 
			
		||||
                                {% fa5_icon 'sign-out-alt' %}
 | 
			
		||||
                            </button>
 | 
			
		||||
                            {% if team.admin == user %}
 | 
			
		||||
                                <button class="btn rlp-r btn-modal" data-form-url="{% url 'user:team-edit' team.id %}" title="{% trans 'Edit team' %}">
 | 
			
		||||
                                    {% fa5_icon 'edit' %}
 | 
			
		||||
 | 
			
		||||
@ -20,5 +20,6 @@ urlpatterns = [
 | 
			
		||||
    path("team/<id>", data_team_view, name="team-data"),
 | 
			
		||||
    path("team/<id>/edit", edit_team_view, name="team-edit"),
 | 
			
		||||
    path("team/<id>/remove", remove_team_view, name="team-remove"),
 | 
			
		||||
    path("team/<id>/leave", leave_team_view, name="team-leave"),
 | 
			
		||||
 | 
			
		||||
]
 | 
			
		||||
@ -13,7 +13,7 @@ from django.utils.translation import gettext_lazy as _
 | 
			
		||||
from konova.contexts import BaseContext
 | 
			
		||||
from konova.decorators import any_group_check, default_group_required
 | 
			
		||||
from user.forms import UserNotificationForm, UserContactForm, UserAPITokenForm, NewTeamModalForm, EditTeamModalForm, \
 | 
			
		||||
    RemoveTeamModalForm, TeamDataForm
 | 
			
		||||
    RemoveTeamModalForm, TeamDataForm, LeaveTeamModalForm
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@login_required
 | 
			
		||||
@ -204,3 +204,24 @@ def remove_team_view(request: HttpRequest, id: str):
 | 
			
		||||
        _("Team removed"),
 | 
			
		||||
        redirect_url=reverse("user:team-index")
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@login_required
 | 
			
		||||
def leave_team_view(request: HttpRequest, id: str):
 | 
			
		||||
    team = get_object_or_404(Team, id=id)
 | 
			
		||||
    user = request.user
 | 
			
		||||
 | 
			
		||||
    is_user_team_member = team.users.filter(id=user.id).exists()
 | 
			
		||||
    if not is_user_team_member:
 | 
			
		||||
        messages.info(
 | 
			
		||||
            request,
 | 
			
		||||
            _("You are not a member of this team")
 | 
			
		||||
        )
 | 
			
		||||
        return redirect("user:team-index")
 | 
			
		||||
 | 
			
		||||
    form = LeaveTeamModalForm(request.POST or None, instance=team, request=request)
 | 
			
		||||
    return form.process_request(
 | 
			
		||||
        request,
 | 
			
		||||
        _("Left Team"),
 | 
			
		||||
        redirect_url=reverse("user:team-index")
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user