""" Author: Michel Peltriaux Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany Contact: michel.peltriaux@sgdnord.rlp.de Created on: 17.11.20 """ from django.contrib.auth.models import User from django.contrib.gis.db import models from django.core.validators import MinValueValidator, MaxValueValidator from django.utils import timezone from django.utils.timezone import now from compensation.settings import COMPENSATION_IDENTIFIER_LENGTH, COMPENSATION_IDENTIFIER_TEMPLATE from intervention.models import Intervention, ResponsibilityData from konova.models import BaseObject, BaseResource, Geometry, UuidModel from konova.utils.generators import generate_random_string from organisation.models import Organisation class Payment(BaseResource): """ Holds data on a payment for an intervention (alternative to a classic compensation) """ amount = models.FloatField(validators=[MinValueValidator(limit_value=0.00)]) due_on = models.DateField(null=True) comment = models.CharField( max_length=1000, null=True, blank=True, help_text="Refers to german money transfer 'Verwendungszweck'", ) intervention = models.ForeignKey( Intervention, null=True, blank=True, on_delete=models.CASCADE, related_name='payments' ) class CompensationControl(BaseResource): """ Holds data on how a compensation shall be controlled """ deadline = models.ForeignKey("konova.Deadline", on_delete=models.SET_NULL, null=True, blank=True) type = models.CharField(max_length=500, null=True, blank=True) expected_result = models.CharField(max_length=500, null=True, blank=True, help_text="The expected outcome, that needs to be controlled") by_authority = models.ForeignKey(Organisation, null=True, blank=True, on_delete=models.SET_NULL) comment = models.TextField() class CompensationState(models.Model): """ Compensations must define the state of an area before and after the compensation. """ biotope_type = models.CharField(max_length=500, null=True, blank=True) surface = models.FloatField() class CompensationAction(BaseResource): """ Compensations include actions like planting trees, refreshing rivers and so on. """ action_type = models.CharField(max_length=500, null=True, blank=True) amount = models.FloatField() unit = models.CharField(max_length=100, null=True, blank=True) control = models.ForeignKey(CompensationControl, on_delete=models.SET_NULL, null=True, blank=True) class Compensation(BaseObject): """ The compensation holds information about which actions have to be performed until which date, who is in charge of this, which legal authority is the point of contact, and so on. """ responsible = models.OneToOneField( ResponsibilityData, on_delete=models.SET_NULL, null=True, blank=True, help_text="Holds data on responsible organizations ('Zulassungsbehörde', 'Eintragungsstelle') and handler", ) before_states = models.ManyToManyField(CompensationState, blank=True, related_name='+', help_text="Refers to 'Ausgangszustand Biotop'") after_states = models.ManyToManyField(CompensationState, blank=True, related_name='+', help_text="Refers to 'Zielzustand Biotop'") actions = models.ManyToManyField(CompensationAction, help_text="Refers to 'Maßnahmen'") deadlines = models.ManyToManyField("konova.Deadline", null=True, blank=True, related_name="+") geometry = models.ForeignKey(Geometry, null=True, blank=True, on_delete=models.SET_NULL) documents = models.ManyToManyField("konova.Document", blank=True) # Holds which intervention is simply a newer version of this dataset next_version = models.ForeignKey("Compensation", null=True, blank=True, on_delete=models.DO_NOTHING) intervention = models.ForeignKey( Intervention, on_delete=models.CASCADE, null=True, blank=True, related_name='compensations' ) @staticmethod def _generate_new_identifier() -> str: """ Generates a new identifier for the intervention object Returns: str """ curr_month = str(now().month) curr_year = str(now().year) rand_str = generate_random_string( length=COMPENSATION_IDENTIFIER_LENGTH, only_numbers=True, ) _str = "{}{}{}".format(curr_month, curr_year, rand_str) return COMPENSATION_IDENTIFIER_TEMPLATE.format(_str) def delete(self, *args, **kwargs): """ Custom delete functionality Does not delete from database but sets a timestamp for being deleted on and which user deleted the object Args: *args (): **kwargs (): Returns: """ _now = timezone.now() _user = kwargs.get("user", None) self.deleted_on = _now self.deleted_by = _user self.save() def save(self, *args, **kwargs): if self.identifier is None or len(self.identifier) == 0: # Create new identifier new_id = self._generate_new_identifier() while Compensation.objects.filter(identifier=new_id).exists(): new_id = self._generate_new_identifier() self.identifier = new_id super().save(*args, **kwargs) class EcoAccount(Compensation): """ An eco account is a kind of 'prepaid' compensation. It can be compared to an account that already has been filled with some kind of currency. From this account one is able to 'withdraw' currency for current projects. """ # Users having access on this object users = models.ManyToManyField(User) def __str__(self): return "{}".format(self.identifier) class EcoAccountWithdraw(BaseResource): """ A withdraw object for eco accounts """ account = models.ForeignKey( EcoAccount, on_delete=models.SET_NULL, null=True, blank=True, help_text="Withdrawn from", related_name="eco_withdraws", ) amount = models.FloatField( null=True, blank=True, help_text="Amount withdrawn (percentage)", validators=[ MinValueValidator(limit_value=0.00), MaxValueValidator(limit_value=100), ] ) intervention = models.ForeignKey( Intervention, on_delete=models.CASCADE, null=True, blank=True, help_text="Withdrawn for", related_name="eco_withdraws", ) def __str__(self): return "{} of {}".format(self.amount, self.account)