Compare commits

...

14 Commits

Author SHA1 Message Date
ae89f3d43c Fixing broken document migration
* adds changes to document migration to correctly migrate documents
2022-11-24 11:31:20 +01:00
44e21f4ed9 Document repair migration
* disables all migration parts despite document migration
   * running again with now fixed document migration handling, broken documents will be replaced with fixed ones
2022-11-24 07:37:23 +01:00
4f5c172449 Merge branch 'master' into 132_Old_entries
# Conflicts:
#	konova/models/geometry.py
2022-11-24 06:59:05 +01:00
7438cb34d1 Merge pull request 'hotfix_geometry_save_race_condition' (#246) from hotfix_geometry_save_race_condition into master
Reviewed-on: SGD-Nord/konova#246
2022-11-23 16:06:50 +01:00
79fd3ad29d API - Geometry empty
* removes mapping of empty geometry to None due to general switch to empty geometry usage
2022-11-23 16:05:27 +01:00
2ef643f4e0 Geometry race condition fix
* fixes race condition for geometry conflict and parcel calculation
* harmonizes empty geometries from None/MultiPolygonEmpty to MultiPolygonEmpty
2022-11-23 13:51:05 +01:00
67e79701cf Merge pull request '243_GDALException_on_null' (#244) from 243_GDALException_on_null into master
Reviewed-on: SGD-Nord/konova#244
2022-11-23 07:13:17 +01:00
a6a5bd5450 Further fixes
* fixes race condition on geometry conflict calculation if performed in background process
* simplifies access to smaller buffered geometry
* adds mapping of "qm"->"m2" for UnitChoice in API usage for backwards compatibility
2022-11-22 15:38:03 +01:00
5594250d59 #243 Feature without geometry
* fixes GDALException in case of provided feature (import) without geometry content
* modifies 500.html template to inform the user about the admins being informed automatically
2022-11-22 14:49:51 +01:00
d6e76f7a2a Hotfix
* adds missing migration
2022-11-18 16:22:24 +01:00
6833fc14cb Merge pull request 'Updates LANIS link' (#240) from lanis_link_fix into master
Reviewed-on: SGD-Nord/konova#240
2022-11-18 13:32:12 +01:00
0bc486502f Merge pull request '#238 Fix' (#239) from 238_Type_error_on_eco_account_edit into master
Reviewed-on: SGD-Nord/konova#239
2022-11-18 13:29:11 +01:00
689f3b6d28 Updates LANIS link
* changes LANIS link to new layer declaration
2022-11-18 13:28:13 +01:00
4138b056df #238 Fix
* adds casting from Decimal() to primitive float for proper calculation
2022-11-18 13:24:36 +01:00
31 changed files with 229 additions and 133 deletions

View File

@ -1,5 +1,5 @@
{
"eco_account": "CHANGE_BEFORE_RUN!!!",
"surface": 500.0,
"surface": 500.50,
"intervention": "CHANGE_BEFORE_RUN!!!"
}

View File

@ -1,5 +1,5 @@
{
"eco_account": "CHANGE_BEFORE_RUN!!!",
"surface": 523400.0,
"surface": 523400.50,
"intervention": "CHANGE_BEFORE_RUN!!!"
}

View File

@ -136,8 +136,6 @@ class AbstractModelAPISerializer:
geometry = geos.fromstr(geojson)
if geometry.srid != DEFAULT_SRID_RLP:
geometry.transform(DEFAULT_SRID_RLP)
if geometry.empty:
geometry = None
return geometry
def _get_obj_from_db(self, id, user):

View File

@ -11,7 +11,7 @@ from api.utils.serializer.v1.serializer import AbstractModelAPISerializerV1, Abs
from compensation.models import Compensation
from intervention.models import Intervention
from konova.models import Geometry
from konova.tasks import celery_update_parcels
from konova.tasks import celery_update_parcels, celery_check_for_geometry_conflicts
from konova.utils.message_templates import DATA_UNSHARED
from user.models import UserActionLogEntry
@ -128,6 +128,7 @@ class CompensationAPISerializerV1(AbstractModelAPISerializerV1, AbstractCompensa
obj.log.add(obj.created)
celery_update_parcels.delay(obj.geometry.id)
celery_check_for_geometry_conflicts.delay(obj.geometry.id)
return obj.id

View File

@ -13,7 +13,7 @@ from codelist.settings import CODELIST_CONSERVATION_OFFICE_ID, CODELIST_HANDLER_
from compensation.models import EcoAccount
from intervention.models import Legal, Responsibility, Handler
from konova.models import Geometry
from konova.tasks import celery_update_parcels
from konova.tasks import celery_update_parcels, celery_check_for_geometry_conflicts
from user.models import UserActionLogEntry
@ -150,6 +150,7 @@ class EcoAccountAPISerializerV1(AbstractModelAPISerializerV1,
obj.users.add(user)
celery_update_parcels.delay(obj.geometry.id)
celery_check_for_geometry_conflicts.delay(obj.geometry.id)
return obj.id

View File

@ -13,7 +13,7 @@ from codelist.settings import CODELIST_CONSERVATION_OFFICE_ID, CODELIST_HANDLER_
from ema.models import Ema
from intervention.models import Responsibility, Handler
from konova.models import Geometry
from konova.tasks import celery_update_parcels
from konova.tasks import celery_update_parcels, celery_check_for_geometry_conflicts
from user.models import UserActionLogEntry
@ -122,6 +122,7 @@ class EmaAPISerializerV1(AbstractModelAPISerializerV1, AbstractCompensationAPISe
obj.users.add(user)
celery_update_parcels.delay(obj.geometry.id)
celery_check_for_geometry_conflicts.delay(obj.geometry.id)
return obj.id

View File

@ -13,7 +13,7 @@ from api.utils.serializer.v1.serializer import AbstractModelAPISerializerV1, \
from compensation.models import Payment
from intervention.models import Intervention, Responsibility, Legal, Handler
from konova.models import Geometry
from konova.tasks import celery_update_parcels
from konova.tasks import celery_update_parcels, celery_check_for_geometry_conflicts
from user.models import UserActionLogEntry
@ -165,6 +165,7 @@ class InterventionAPISerializerV1(AbstractModelAPISerializerV1,
obj.log.add(obj.created)
celery_update_parcels.delay(obj.geometry.id)
celery_check_for_geometry_conflicts.delay(obj.geometry.id)
return obj.id

View File

@ -392,7 +392,8 @@ class AbstractCompensationAPISerializerV1Mixin:
self._konova_code_from_json(e, CODELIST_COMPENSATION_ACTION_DETAIL_ID) for e in entry["action_details"]
]
amount = float(entry["amount"])
unit = entry["unit"]
# Mapping of old "qm" into "m²"
unit = UnitChoices.m2.value if entry["unit"] == "qm" else entry["unit"]
comment = entry["comment"]
# Check on validity

View File

@ -129,12 +129,11 @@ class NewCompensationForm(AbstractCompensationForm,
self.initialize_form_field("identifier", identifier)
self.fields["identifier"].widget.attrs["url"] = reverse_lazy("compensation:new-id")
def __create_comp(self, user, geom_form) -> Compensation:
def __create_comp(self, user):
""" Creates the compensation from form data
Args:
user (User): The performing user
geom_form (SimpleGeomForm): The geometry form
Returns:
comp (Compensation): The compensation object
@ -150,8 +149,6 @@ class NewCompensationForm(AbstractCompensationForm,
# Create log entry
action = UserActionLogEntry.get_created_action(user)
# Process the geometry form
geometry = geom_form.save(action)
# Finally create main object
comp = Compensation.objects.create(
@ -162,18 +159,23 @@ class NewCompensationForm(AbstractCompensationForm,
is_cef=is_cef,
is_coherence_keeping=is_coherence_keeping,
is_pik=is_pik,
geometry=geometry,
comment=comment,
)
# Add the log entry to the main objects log list
comp.log.add(action)
return comp
return comp, action
def save(self, user: User, geom_form: SimpleGeomForm):
with transaction.atomic():
comp = self.__create_comp(user, geom_form)
comp, action = self.__create_comp(user)
comp.intervention.mark_as_edited(user, edit_comment=COMPENSATION_ADDED_TEMPLATE.format(comp.identifier))
# Process the geometry form
geometry = geom_form.save(action)
comp.geometry = geometry
comp.save()
return comp
@ -205,6 +207,9 @@ class EditCompensationForm(NewCompensationForm):
def save(self, user: User, geom_form: SimpleGeomForm):
with transaction.atomic():
# Create log entry
action = UserActionLogEntry.get_edited_action(user)
# Fetch data from cleaned POST values
identifier = self.cleaned_data.get("identifier", None)
title = self.cleaned_data.get("title", None)
@ -214,17 +219,9 @@ class EditCompensationForm(NewCompensationForm):
is_pik = self.cleaned_data.get("is_pik", None)
comment = self.cleaned_data.get("comment", None)
# Create log entry
action = UserActionLogEntry.get_edited_action(user)
# Process the geometry form
geometry = geom_form.save(action)
# Finally create main object
self.instance.identifier = identifier
self.instance.title = title
self.instance.intervention = intervention
self.instance.geometry = geometry
self.instance.is_cef = is_cef
self.instance.is_coherence_keeping = is_coherence_keeping
self.instance.comment = comment
@ -233,6 +230,11 @@ class EditCompensationForm(NewCompensationForm):
self.instance.save()
self.instance.log.add(action)
intervention.mark_as_edited(user, self.request, EDITED_GENERAL_DATA)
return self.instance
# Process the geometry form (NOT ATOMIC TRANSACTION DUE TO CELERY!)
geometry = geom_form.save(action)
self.instance.geometry = geometry
self.instance.save()
return self.instance

View File

@ -94,8 +94,6 @@ class NewEcoAccountForm(AbstractCompensationForm, CompensationResponsibleFormMix
# Create log entry
action = UserActionLogEntry.get_created_action(user)
# Process the geometry form
geometry = geom_form.save(action)
handler = Handler.objects.create(
type=handler_type,
@ -119,7 +117,6 @@ class NewEcoAccountForm(AbstractCompensationForm, CompensationResponsibleFormMix
responsible=responsible,
deductable_surface=surface,
created=action,
geometry=geometry,
comment=comment,
is_pik=is_pik,
legal=legal
@ -129,6 +126,10 @@ class NewEcoAccountForm(AbstractCompensationForm, CompensationResponsibleFormMix
# Add the log entry to the main objects log list
acc.log.add(action)
# Process the geometry form
geometry = geom_form.save(action)
acc.geometry = geometry
acc.save()
acc.update_deductable_rest()
return acc
@ -185,9 +186,6 @@ class EditEcoAccountForm(NewEcoAccountForm):
# Create log entry
action = UserActionLogEntry.get_edited_action(user)
# Process the geometry form
geometry = geom_form.save(action)
# Update responsible data
self.instance.responsible.handler.type = handler_type
self.instance.responsible.handler.detail = handler_detail
@ -204,7 +202,6 @@ class EditEcoAccountForm(NewEcoAccountForm):
self.instance.identifier = identifier
self.instance.title = title
self.instance.deductable_surface = surface
self.instance.geometry = geometry
self.instance.comment = comment
self.instance.is_pik = is_pik
self.instance.modified = action
@ -213,6 +210,10 @@ class EditEcoAccountForm(NewEcoAccountForm):
# Add the log entry to the main objects log list
self.instance.log.add(action)
# Process the geometry form (NOT ATOMIC TRANSACTION DUE TO CELERY!)
geometry = geom_form.save(action)
self.instance.geometry = geometry
self.instance.save()
self.instance.update_deductable_rest()
return self.instance

View File

@ -0,0 +1,18 @@
# Generated by Django 3.1.3 on 2022-11-18 15:20
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('compensation', '0013_auto_20221117_0819'),
]
operations = [
migrations.AlterField(
model_name='compensationaction',
name='unit',
field=models.CharField(blank=True, choices=[('cm', 'cm'), ('m', 'm'), ('m2', ''), ('m3', ''), ('km', 'km'), ('ha', 'ha'), ('pcs', 'Pieces')], max_length=100, null=True),
),
]

View File

@ -118,8 +118,15 @@ class EcoAccount(AbstractCompensation, ShareableObjectMixin, RecordableObjectMix
intervention__deleted=None,
)
deductions_surfaces = deductions.aggregate(Sum("surface"))["surface__sum"] or 0
available_surfaces = self.deductable_surface or deductions_surfaces ## no division by zero
ret_val = available_surfaces - deductions_surfaces
available_surface = self.deductable_surface
if available_surface is None:
# Fallback!
available_surface = deductions_surfaces
else:
available_surface = float(available_surface)
ret_val = available_surface - deductions_surfaces
return ret_val

View File

@ -188,7 +188,7 @@ class EcoAccountWorkflowTestCase(BaseWorkflowTestCase):
# Prepare data for deduction creation
deduct_url = reverse("compensation:acc:new-deduction", args=(self.eco_account.id,))
test_surface = 10.00
test_surface = 10.50
post_data = {
"surface": test_surface,
"account": self.eco_account.id,
@ -207,7 +207,7 @@ class EcoAccountWorkflowTestCase(BaseWorkflowTestCase):
# Make sure the deductible surface is valid for the request
self.eco_account.set_recorded(self.superuser)
self.eco_account.refresh_from_db()
self.eco_account.deductable_surface = test_surface + 1.00
self.eco_account.deductable_surface = test_surface + 1.0
self.eco_account.save()
self.assertIsNotNone(self.eco_account.recorded)
self.assertGreater(self.eco_account.deductable_surface, test_surface)
@ -244,7 +244,7 @@ class EcoAccountWorkflowTestCase(BaseWorkflowTestCase):
deduction = EcoAccountDeduction.objects.create(
intervention=self.intervention,
account=self.eco_account,
surface=0
surface=1.10
)
self.assertEqual(1, self.intervention.deductions.count())
self.assertEqual(1, self.eco_account.deductions.count())

View File

@ -64,8 +64,6 @@ class NewEmaForm(AbstractCompensationForm, CompensationResponsibleFormMixin, Pik
# Create log entry
action = UserActionLogEntry.get_created_action(user)
# Process the geometry form
geometry = geom_form.save(action)
handler = Handler.objects.create(
type=handler_type,
@ -83,7 +81,6 @@ class NewEmaForm(AbstractCompensationForm, CompensationResponsibleFormMixin, Pik
title=title,
responsible=responsible,
created=action,
geometry=geometry,
comment=comment,
is_pik=is_pik,
)
@ -93,6 +90,11 @@ class NewEmaForm(AbstractCompensationForm, CompensationResponsibleFormMixin, Pik
# Add the log entry to the main objects log list
acc.log.add(action)
# Process the geometry form (NOT ATOMIC TRANSACTION DUE TO CELERY!)
geometry = geom_form.save(action)
acc.geometry = geometry
acc.save()
return acc
@ -141,8 +143,6 @@ class EditEmaForm(NewEmaForm):
# Create log entry
action = UserActionLogEntry.get_edited_action(user)
# Process the geometry form
geometry = geom_form.save(action)
# Update responsible data
self.instance.responsible.handler.type = handler_type
@ -155,7 +155,6 @@ class EditEmaForm(NewEmaForm):
# Update main oject data
self.instance.identifier = identifier
self.instance.title = title
self.instance.geometry = geometry
self.instance.comment = comment
self.instance.is_pik = is_pik
self.instance.modified = action
@ -163,6 +162,11 @@ class EditEmaForm(NewEmaForm):
# Add the log entry to the main objects log list
self.instance.log.add(action)
# Process the geometry form (NOT ATOMIC TRANSACTION DUE TO CELERY!)
geometry = geom_form.save(action)
self.instance.geometry = geometry
self.instance.save()
return self.instance

View File

@ -263,9 +263,6 @@ class NewInterventionForm(BaseForm):
handler=handler,
)
# Process the geometry form
geometry = geom_form.save(action)
# Finally create main object, holding the other objects
intervention = Intervention.objects.create(
identifier=identifier,
@ -273,7 +270,6 @@ class NewInterventionForm(BaseForm):
responsible=responsibility_data,
legal=legal_data,
created=action,
geometry=geometry,
comment=comment,
)
@ -282,6 +278,12 @@ class NewInterventionForm(BaseForm):
# Add the performing user as the first user having access to the data
intervention.share_with_user(user)
# Process the geometry form (NOT ATOMIC TRANSACTION DUE TO CELERY!)
geometry = geom_form.save(action)
intervention.geometry = geometry
intervention.save()
return intervention
@ -370,9 +372,6 @@ class EditInterventionForm(NewInterventionForm):
user_action = self.instance.mark_as_edited(user, edit_comment=EDITED_GENERAL_DATA)
geometry = geom_form.save(user_action)
self.instance.geometry = geometry
self.instance.log.add(user_action)
self.instance.identifier = identifier
@ -381,5 +380,10 @@ class EditInterventionForm(NewInterventionForm):
self.instance.modified = user_action
self.instance.save()
# Process the geometry form (NOT ATOMIC TRANSACTION DUE TO CELERY!)
geometry = geom_form.save(user_action)
self.instance.geometry = geometry
self.instance.save()
return self.instance

View File

@ -11,7 +11,7 @@ import json
import pika
import xmltodict
from django.db.models import Sum
from django.utils import formats
from django.utils import formats, timezone
from intervention.settings import EGON_RABBITMQ_HOST, EGON_RABBITMQ_USER, EGON_RABBITMQ_PW, EGON_RABBITMQ_PORT
from konova.sub_settings.django_settings import DEFAULT_DATE_FORMAT
@ -43,7 +43,6 @@ class EgonExporter:
"nachricht": self.gml_builder.gml,
}
msg = json.dumps(msg)
print(msg)
credentials = pika.PlainCredentials(EGON_RABBITMQ_USER, EGON_RABBITMQ_PW)
params = pika.ConnectionParameters(
EGON_RABBITMQ_HOST,
@ -59,6 +58,7 @@ class EgonExporter:
body=msg.encode("utf-8"),
)
conn.close()
print(f"Successfully sent EGON data for {self.intervention.identifier}")
class EgonGmlBuilder:
@ -164,6 +164,8 @@ class EgonGmlBuilder:
payment_date = None
if payment is not None:
payment_date = payment.due_on
if payment_date is None:
payment_date = timezone.datetime.fromisoformat("1970-01-01")
payment_date = payment_date.strftime(DEFAULT_DATE_FORMAT)
cons_office = self.intervention.responsible.conservation_office

View File

@ -15,7 +15,7 @@ from django.utils.translation import gettext_lazy as _
from konova.forms.base_form import BaseForm
from konova.models import Geometry
from konova.tasks import celery_update_parcels
from konova.tasks import celery_update_parcels, celery_check_for_geometry_conflicts
from konova.sub_settings.lanis_settings import DEFAULT_SRID_RLP
from user.models import UserActionLogEntry
@ -63,6 +63,7 @@ class SimpleGeomForm(BaseForm):
geom = self.data["geom"]
if geom is None or len(geom) == 0:
# empty geometry is a valid geometry
self.cleaned_data["geom"] = MultiPolygon(srid=DEFAULT_SRID_RLP).ewkt
return is_valid
geom = json.loads(geom)
@ -82,7 +83,12 @@ class SimpleGeomForm(BaseForm):
"MultiPolygon25D",
]
for feature in features_json:
feature_geom = json.dumps(feature.get("geometry", feature))
feature_geom = feature.get("geometry", feature)
if feature_geom is None:
# Fallback for rare cases where a feature does not contain any geometry
continue
feature_geom = json.dumps(feature_geom)
g = gdal.OGRGeometry(feature_geom, srs=DEFAULT_SRID_RLP)
flatten_geometry = g.coord_dim > 2
@ -101,6 +107,8 @@ class SimpleGeomForm(BaseForm):
return is_valid
features.append(polygon)
# Unionize all geometry features into one new MultiPolygon
form_geom = MultiPolygon(srid=DEFAULT_SRID_RLP)
for feature in features:
form_geom = form_geom.union(feature)
@ -141,8 +149,9 @@ class SimpleGeomForm(BaseForm):
geom=self.cleaned_data.get("geom", MultiPolygon(srid=DEFAULT_SRID_RLP)),
created=action,
)
# Start the parcel update procedure in a background process
# Start parcel update and geometry conflict checking procedure in a background process
celery_update_parcels.delay(geometry.id)
celery_check_for_geometry_conflicts.delay(geometry.id)
return geometry
def __flatten_geom_to_2D(self, geom):

View File

@ -3,7 +3,7 @@ from abc import abstractmethod
import psycopg2
from django.contrib.auth.models import Group
from django.contrib.gis.geos import GEOSException, MultiPolygon, Polygon, MultiPoint, MultiLineString
from django.core.exceptions import ObjectDoesNotExist
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
from django.core.files.uploadedfile import UploadedFile
from django.utils.timezone import make_aware
@ -95,16 +95,18 @@ class BaseMigrater:
doc_title = "Migrierte Datei"
doc_date = doc_date or "1970-01-01"
# Ensure problematic characters not present in lookup file name
clean_file_name = file.name.replace("§", "")
doc_file = self.__find_migrated_file_recursive(
document_cls,
instance,
file.name
clean_file_name
)
if doc_file is not None:
doc_file.delete()
else:
print(f"------ Could not find file, that should have been migrated already. Adding new version anyway: {doc_path}")
print(f"------ Could not find file, that should have been migrated already for {instance.identifier}. Adding new version anyway: {doc_path}")
doc = document_cls.objects.create(
title=doc_title,
@ -132,6 +134,14 @@ class BaseMigrater:
return self.__find_migrated_file_recursive(document_cls, instance, file_name_tmp)
else:
return None
except MultipleObjectsReturned:
doc_files = document_cls.objects.filter(
instance=instance,
file__icontains=file_name_tmp
)
for doc in doc_files:
doc.delete()
return None
def _migrate_log(self, instance, db_result: tuple):
identifier = f"'{db_result[0]}'"

View File

@ -16,6 +16,7 @@ class CompensationMigrater(BaseMigrater):
def migrate(self):
self.connect_db()
cursor = self.db_connection.cursor()
#el = "'KOM-1568808121948'" # Test purposes
empty_str = "''"
cursor.execute(
'select '
@ -57,32 +58,33 @@ class CompensationMigrater(BaseMigrater):
identifier=kom_identifier
)[0]
compensation.title = kom_title
compensation.comment = kom_comment
try:
compensation = self._migrate_interventions_reference(compensation, kom)
except ObjectDoesNotExist:
compensation.delete()
unsuccessfull_compensations[kom_identifier] = "EIV does not exist"
continue
#compensation.title = kom_title
#compensation.comment = kom_comment
### FOR INITIAL RECONSTRUCTION OF EIV-KOM RELATIONSHIP
#try:
# compensation = self._migrate_interventions_reference(compensation, kom)
#except ObjectDoesNotExist:
# compensation.delete()
# unsuccessfull_compensations[kom_identifier] = "EIV does not exist"
# continue
compensation = self._migrate_par_7_data(compensation, kom)
compensation = self._migrate_responsibility(compensation, kom)
compensation = self._migrate_compensation_type(compensation, kom)
compensation = self._migrate_states(compensation, kom)
compensation = self._migrate_deadlines(compensation, kom)
compensation = self._migrate_action_control_deadlines(compensation, kom)
compensation = self._migrate_actions(compensation, kom)
compensation = self._migrate_log(compensation, kom)
#compensation = self._migrate_par_7_data(compensation, kom)
#compensation = self._migrate_responsibility(compensation, kom)
#compensation = self._migrate_compensation_type(compensation, kom)
#compensation = self._migrate_states(compensation, kom)
#compensation = self._migrate_deadlines(compensation, kom)
#compensation = self._migrate_action_control_deadlines(compensation, kom)
#compensation = self._migrate_actions(compensation, kom)
#compensation = self._migrate_log(compensation, kom)
compensation = self._migrate_documents(compensation, CompensationDocument, kom)
compensation.save()
num_processed += 1
compensation = self._migrate_geometry(compensation, kom)
compensation.save()
print("The following KOMs could not be migrated: ")
for kom, val in unsuccessfull_compensations.items():
print(kom)
#compensation = self._migrate_geometry(compensation, kom)
#compensation.save()
#print("The following KOMs could not be migrated: ")
#for kom, val in unsuccessfull_compensations.items():
# print(kom)
cursor.close()
def _migrate_interventions_reference(self, compensation, kom):

View File

@ -21,7 +21,7 @@ from user.models import UserActionLogEntry
class EcoAccountMigrater(CompensationMigrater):
def migrate(self):
el = "'OEK-1488450234228'"
#el = "'OEK-1611234357085'" # Test purposes
self.connect_db()
cursor = self.db_connection.cursor()
cursor.execute(
@ -61,25 +61,25 @@ class EcoAccountMigrater(CompensationMigrater):
identifier=oek_identifier
)[0]
eco_account.title = oek_title
eco_account.prevent_recording = False
eco_account.comment = oek_comment
eco_account = self._migrate_legal(eco_account, oek)
eco_account = self._migrate_states(eco_account, oek)
eco_account = self._migrate_responsibility(eco_account, oek)
eco_account = self._migrate_deadlines(eco_account, oek)
eco_account = self._migrate_action_control_deadlines(eco_account, oek)
eco_account = self._migrate_actions(eco_account, oek)
eco_account = self._migrate_log(eco_account, oek)
eco_account = self._migrate_recorded(eco_account, oek)
eco_account = self._migrate_deductions(eco_account, oek)
#eco_account.title = oek_title
#eco_account.prevent_recording = False
#eco_account.comment = oek_comment
#eco_account = self._migrate_legal(eco_account, oek)
#eco_account = self._migrate_states(eco_account, oek)
#eco_account = self._migrate_responsibility(eco_account, oek)
#eco_account = self._migrate_deadlines(eco_account, oek)
#eco_account = self._migrate_action_control_deadlines(eco_account, oek)
#eco_account = self._migrate_actions(eco_account, oek)
#eco_account = self._migrate_log(eco_account, oek)
#eco_account = self._migrate_recorded(eco_account, oek)
#eco_account = self._migrate_deductions(eco_account, oek)
eco_account = self._migrate_documents(eco_account, EcoAccountDocument, oek)
eco_account.save()
num_processed += 1
eco_account = self._migrate_geometry(eco_account, oek)
eco_account.save()
#eco_account = self._migrate_geometry(eco_account, oek)
#eco_account.save()
cursor.close()
def _migrate_geometry(self, instance, db_result: tuple):

View File

@ -16,6 +16,7 @@ class EmaMigrater(CompensationMigrater):
def migrate(self):
self.connect_db()
cursor = self.db_connection.cursor()
#el = "'EMA-1469083068361'" # Test purposes
cursor.execute(
'select '
'om."KENNUNG", '
@ -54,24 +55,24 @@ class EmaMigrater(CompensationMigrater):
identifier=ema_identifier
)[0]
ema_obj.title = ema_title
ema_obj.comment = ema_comment
ema_obj = self._migrate_responsibility(ema_obj, ema)
ema_obj = self._migrate_compensation_type(ema_obj, ema)
ema_obj = self._migrate_states(ema_obj, ema)
ema_obj = self._migrate_deadlines(ema_obj, ema)
ema_obj = self._migrate_action_control_deadlines(ema_obj, ema)
ema_obj = self._migrate_actions(ema_obj, ema)
ema_obj = self._migrate_finance_volume_to_comment(ema_obj, ema)
ema_obj = self._migrate_log(ema_obj, ema)
#ema_obj.title = ema_title
#ema_obj.comment = ema_comment
#ema_obj = self._migrate_responsibility(ema_obj, ema)
#ema_obj = self._migrate_compensation_type(ema_obj, ema)
#ema_obj = self._migrate_states(ema_obj, ema)
#ema_obj = self._migrate_deadlines(ema_obj, ema)
#ema_obj = self._migrate_action_control_deadlines(ema_obj, ema)
#ema_obj = self._migrate_actions(ema_obj, ema)
#ema_obj = self._migrate_finance_volume_to_comment(ema_obj, ema)
#ema_obj = self._migrate_log(ema_obj, ema)
ema_obj = self._migrate_documents(ema_obj, EmaDocument, ema)
ema_obj = self._migrate_recorded(ema_obj, ema)
#ema_obj = self._migrate_recorded(ema_obj, ema)
ema_obj.save()
num_processed += 1
ema_obj = self._migrate_geometry(ema_obj, ema)
ema_obj.save()
#ema_obj = self._migrate_geometry(ema_obj, ema)
#ema_obj.save()
cursor.close()

View File

@ -10,6 +10,7 @@ from codelist.settings import CODELIST_LAW_ID, CODELIST_PROCESS_TYPE_ID, CODELIS
CODELIST_CONSERVATION_OFFICE_ID, CODELIST_REGISTRATION_OFFICE_ID
from compensation.models import Payment
from intervention.models import Intervention, InterventionDocument, Legal, Handler, Responsibility, Revocation
from intervention.utils.egon_export import EgonExporter
from konova.management.commands.kspMigrater.base_migrater import BaseMigrater
from konova.settings import ETS_GROUP
@ -146,7 +147,7 @@ class InterventionMigrater(BaseMigrater):
def migrate(self):
self.connect_db()
el = "'EIV-1380625802430'"
#el = "'EIV-1613988897199'" # Test purposes
cursor = self.db_connection.cursor()
cursor.execute(
'select '
@ -167,7 +168,8 @@ class InterventionMigrater(BaseMigrater):
'zt.erlass as Zulassungsdatum, '
'zt.rechtskraft as Bestandskraftdatum, '
'zt.baubeginn as ersatzzahlungstermin, '
'eiv.ersatzzahlung '
'eiv.ersatzzahlung, '
'v.status '
'from "OBJ_MASTER" om '
'left join "LINFOS" linf on om."GISPADID"=linf."GISPADID" '
'left join eiv on om."GISPADID"=eiv.gispadid '
@ -178,11 +180,11 @@ class InterventionMigrater(BaseMigrater):
'left join adressrolle adr on om."GISPADID"=adr."GISPADID" '
'left join "Aufwertung" auf on om."GISPADID"=auf."GISPADID" '
'left join zulassungstermin zt on eiv.zulassung=zt.id '
'left join vorgang v on om."GISPADID"=v.gispadid '
'where '
'om."OKL"=7730085 and '
'om.archiv=false and '
'om.nicht_vollstaendig=0 and '
f'om."KENNUNG"={el}'
'om.nicht_vollstaendig=0'
)
all_eivs = cursor.fetchall()
@ -207,9 +209,20 @@ class InterventionMigrater(BaseMigrater):
#intervention = self._migrate_revocation(intervention, eiv)
intervention.save()
process_state = eiv[18] or 0
requested_state = process_state == 100 or process_state == 300 # 100='privat', 300='bereitgestellt'
payments_exist = intervention.payments.exists()
if requested_state and payments_exist:
egon_exporter = EgonExporter(intervention)
try:
egon_exporter.export_to_rabbitmq()
except TypeError as e:
print(e)
continue
#intervention = self._migrate_geometry(intervention, eiv)
#intervention = self._migrate_intervention_payment(intervention, eiv)
intervention.save()
#intervention.save()
num_processed += 1

View File

@ -8,7 +8,7 @@ from konova.management.commands.setup import BaseKonovaCommand
class Command(BaseKonovaCommand):
help = "Migrates from KSP database to Konova"
help = "Migrates from KSP to Konova"
db_connection = None
def add_arguments(self, parser):
@ -20,9 +20,9 @@ class Command(BaseKonovaCommand):
try:
migraters = [
InterventionMigrater(options),
#CompensationMigrater(options),
#EmaMigrater(options),
#EcoAccountMigrater(options),
CompensationMigrater(options),
EmaMigrater(options),
EcoAccountMigrater(options),
#InterventionRecordedMigrater(options),
#UserMigrater(options),
]

View File

@ -9,16 +9,15 @@ import json
from time import sleep
from django.contrib.gis.db.models import MultiPolygonField
from django.contrib.gis.geos import Polygon
from django.core.exceptions import MultipleObjectsReturned
from django.db import models
from django.db import models, transaction
from django.utils import timezone
from konova.models import BaseResource, UuidModel
from konova.sub_settings.lanis_settings import DEFAULT_SRID_RLP
from konova.utils.wfs.spatial import ParcelWFSFetcher
from konova.utils.mutex import cache_lock
from konova.tasks import celery_check_for_geometry_conflicts
from konova.utils.wfs.spatial import ParcelWFSFetcher
class Geometry(BaseResource):
@ -32,7 +31,18 @@ class Geometry(BaseResource):
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
celery_check_for_geometry_conflicts.delay(self.id)
@property
def geom_small_buffered(self):
"""
Returns a smaller buffered version of the geometry.
Can be used to shrink the geometry used for intersection purposes to avoid intersection detection on
neighbouring geometries.
Returns:
"""
return self.geom.buffer(-0.001)
def check_for_conflicts(self):
""" Checks for new geometry overlaps
@ -47,9 +57,8 @@ class Geometry(BaseResource):
return None
self.recheck_existing_conflicts()
overlapping_geoms = Geometry.objects.filter(
geom__intersects=self.geom,
geom__intersects=self.geom_small_buffered,
).exclude(
id=self.id
).distinct()
@ -71,14 +80,14 @@ class Geometry(BaseResource):
"""
all_conflicts_as_conflicting = self.conflicts_geometries.all()
still_conflicting_conflicts = all_conflicts_as_conflicting.filter(
affected_geometry__geom__intersects=self.geom
affected_geometry__geom__intersects=self.geom_small_buffered
)
resolved_conflicts = all_conflicts_as_conflicting.exclude(id__in=still_conflicting_conflicts)
resolved_conflicts.delete()
all_conflicted_by_conflicts = self.conflicted_by_geometries.all()
still_conflicting_conflicts = all_conflicted_by_conflicts.filter(
conflicting_geometry__geom__intersects=self.geom
conflicting_geometry__geom__intersects=self.geom_small_buffered
)
resolved_conflicts = all_conflicted_by_conflicts.exclude(id__in=still_conflicting_conflicts)
resolved_conflicts.delete()
@ -110,6 +119,11 @@ class Geometry(BaseResource):
"""
from konova.models import Parcel, District, ParcelIntersection, Municipal, ParcelGroup
if self.geom.empty:
# Nothing to do
return
parcel_fetcher = ParcelWFSFetcher(
geometry_id=self.id,
)

View File

@ -15,7 +15,7 @@ DEFAULT_SRID_RLP = 25832
# Needed to redirect to LANIS
## Values to be inserted are [zoom_level, x_coord, y_coord]
LANIS_LINK_TEMPLATE = "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/index.php?lang=de&zl={}&x={}&y={}&bl=tk_rlp_tms_grau&bo=1&lo=0.8,0.8,0.8,0.6,0.8,0.8,0.8,0.8,0.8&layers=eiv_f,eiv_l,eiv_p,kom_f,kom_l,kom_p,oek_f,ema_f,mae&service=kartendienste_naturschutz"
LANIS_LINK_TEMPLATE = "https://geodaten.naturschutz.rlp.de/kartendienste_naturschutz/index.php?lang=de&zl={}&x={}&y={}&bl=tk_rlp_tms_grau&bo=1&lo=0.8,0.8,0.8,0.6,0.8,0.8,0.8,0.8,0.8&layers=eiv_recorded,eiv_unrecorded,kom_recorded,kom_unrecorded,oek_recorded,oek_unrecorded,ema_recorded,ema_unrecorded,mae&service=kartendienste_naturschutz"
## This look up table (LUT) defines different zoom levels on the size of the calculate area of a geometry.
LANIS_ZOOM_LUT = {
1000000000: 6,

View File

@ -17,11 +17,17 @@
</div>
</div>
<div class="card-body">
{% if geom_form.instance.geometry %}
<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>
</div>
{% else %}
<div class="alert alert-danger">
{% translate 'No geometry entry found on database. Please contact an admin!' %}
</div>
{% endif %}
</div>
</div>
</div>

View File

@ -91,7 +91,7 @@ class ParcelWFSFetcher(AbstractWFSFetcher):
geom = Geometry.objects.filter(
id=self.geometry_id
).annotate(
smaller=Func(F('geom'), -0.001, function="ST_Buffer")
smaller=Func(F('geom'), -0.001, function="ST_Buffer") # same as geometry.geom_small_buffered but for QuerySet
).annotate(
gml=AsGML(MakeValid('smaller'))
).first()

View File

@ -32,16 +32,16 @@ def get_geom_parcels(request: HttpRequest, id: str):
parcels = geom.get_underlying_parcels()
geos_geom = geom.geom
parcels_are_currently_calculated = geos_geom is not None and geos_geom.area > 0 and len(parcels) == 0
geometry_exists = not geos_geom.empty
parcels_are_currently_calculated = geometry_exists and geos_geom.area > 0 and len(parcels) == 0
parcels_available = len(parcels) > 0
no_geometry_given = geos_geom is None
if parcels_are_currently_calculated:
# Parcels are being calculated right now. Change the status code, so polling stays active for fetching
# resutls after the calculation
status_code = 200
if parcels_available or no_geometry_given:
if parcels_available or not geometry_exists:
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)

Binary file not shown.

View File

@ -2307,8 +2307,8 @@ msgid "Server Error"
msgstr ""
#: templates/500.html:10
msgid "Something happened. We are working on it!"
msgstr "Irgendetwas ist passiert. Wir arbeiten daran!"
msgid "Something happened. Admins have been informed. We are working on it!"
msgstr "Irgendetwas ist passiert. Die Administratoren wurden informiert. Wir arbeiten daran!"
#: templates/email/api/verify_token.html:7
msgid "Hello support"

View File

@ -7,7 +7,7 @@
<h1 class="display-4">{% trans 'Server Error' %}</h1>
<hr>
<p class="lead">
{% trans 'Something happened. We are working on it!' %}
{% trans 'Something happened. Admins have been informed. We are working on it!' %}
</p>
</div>
{% endblock %}