""" Author: Michel Peltriaux Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany Contact: michel.peltriaux@sgdnord.rlp.de Created on: 24.01.22 """ from django.db import transaction from django.db.models import QuerySet from api.utils.serializer.v1.serializer import AbstractModelAPISerializerV1, \ ResponsibilityAPISerializerV1Mixin, LegalAPISerializerV1Mixin, DeductableAPISerializerV1Mixin from compensation.models import Payment from intervention.models import Intervention, Responsibility, Legal from konova.models import Geometry from konova.tasks import celery_update_parcels from user.models import UserActionLogEntry class InterventionAPISerializerV1(AbstractModelAPISerializerV1, ResponsibilityAPISerializerV1Mixin, LegalAPISerializerV1Mixin, DeductableAPISerializerV1Mixin): model = Intervention def _compensations_to_json(self, qs: QuerySet): return list( qs.values( "id", "identifier", "title" ) ) def _payments_to_json(self, qs: QuerySet): """ Serializes payments into json Args: qs (QuerySet): A queryset of Payment entries Returns: serialized_json (list) """ return list(qs.values("amount", "due_on", "comment")) def _extend_properties_data(self, entry): self.properties_data["responsible"] = self._responsible_to_json(entry.responsible) self.properties_data["legal"] = self._legal_to_json(entry.legal) self.properties_data["compensations"] = self._compensations_to_json(entry.compensations.all()) self.properties_data["payments"] = self._payments_to_json(entry.payments.all()) self.properties_data["deductions"] = self._deductions_to_json(entry.deductions.all()) def _initialize_objects(self, json_model, user): """ Initializes all needed objects from the json_model data Does not persist data to the DB! Args: json_model (dict): The json data user (User): The API user Returns: obj (Intervention) """ create_action = UserActionLogEntry.get_created_action(user, comment="API Import") # Create geometry json_geom = self._create_geometry_from_json(json_model) geometry = Geometry() geometry.geom = json_geom geometry.created = create_action # Create linked objects obj = Intervention() resp = Responsibility() legal = Legal() created = create_action obj.legal = legal obj.created = created obj.geometry = geometry obj.responsible = resp return obj def _set_payments(self, obj, payment_data): """ Sets the linked Payment data according to the given payment_data Args: obj (Compensation): The Compensation object payment_data (dict): The posted payment_data Returns: obj (intervention) """ if payment_data is None: return obj payments = [] for entry in payment_data: due_on = entry["due_on"] amount = float(entry["amount"]) comment = entry["comment"] # Check on validity if amount <= 0: raise ValueError("Payment amount must be > 0") no_due_on = due_on is None or len(due_on) == 0 no_comment = comment is None or len(comment) == 0 if no_due_on and no_comment: raise ValueError("If no due_on can be provided, you need to explain why using the comment") # If this exact data is already existing, we do not create it new. Instead put it's id in the list of # entries, we will use to set the new actions pre_existing_payment = obj.payments.filter( amount=amount, due_on=due_on, comment=comment, ).exclude( id__in=payments ).first() if pre_existing_payment is not None: payments.append(pre_existing_payment.id) else: # Create and add id to list new_payment = Payment.objects.create( amount=amount, due_on=due_on, comment=comment, ) payments.append(new_payment.id) payments = Payment.objects.filter( id__in=payments ) obj.payments.set(payments) return obj def create_model_from_json(self, json_model, user): """ Creates a new entry for the model based on the contents of json_model Args: json_model (dict): The json containing data user (User): The API user Returns: created_id (str): The id of the newly created Intervention entry """ with transaction.atomic(): obj = self._initialize_objects(json_model, user) # Fill in data to objects properties = json_model["properties"] obj.identifier = obj.generate_new_identifier() obj.title = properties["title"] self._set_responsibility(obj, properties["responsible"]) self._set_legal(obj, properties["legal"]) obj.responsible.save() obj.geometry.save() obj.legal.save() obj.save() obj.users.add(user) obj.log.add(obj.created) celery_update_parcels.delay(obj.geometry.id) return obj.id def update_model_from_json(self, id, json_model, user): """ Updates an entry for the model based on the contents of json_model Args: id (str): The object's id json_model (dict): The json containing data user (User): The API user Returns: created_id (str): The id of the newly created Intervention entry """ with transaction.atomic(): update_action = UserActionLogEntry.get_edited_action(user, "API update") obj = self._get_obj_from_db(id, user) # Fill in data to objects properties = json_model["properties"] obj.title = properties["title"] self._set_responsibility(obj, properties.get("responsible", None)) self._set_legal(obj, properties.get("legal", None)) self._set_payments(obj, properties.get("payments", None)) obj.geometry.geom = self._create_geometry_from_json(json_model) obj.geometry.modified = update_action obj.responsible.save() obj.geometry.save() obj.legal.save() obj.save() obj.mark_as_edited(user) celery_update_parcels.delay(obj.geometry.id) return obj.id