Ejemplo n.º 1
0
class TimeSlots(models.Model):
    name_id = models.CharField(
        help_text="Unique and computer-friendly name of time_slots",
        max_length=100,
        unique=True,
    )

    name = models.CharField(
        help_text="Human-readable name of the time_slots.",
        max_length=50
    )

    zero = models.DateTimeField(
        null=False,
        default=time_series_default_zero
    )

    frequency = RelativeDeltaField(
        null=False,
        default=default_relative_delta_hour
    )

    range_from = RelativeDeltaField(
        null=False,
        default=default_relative_delta_zero
    )

    range_to = RelativeDeltaField(
        null=False,
        default=default_relative_delta_hour
    )

    def clean(self):
        if self.frequency is None:
            raise forms.ValidationError('frequency cannot be null')

        if self.range_from is None:
            raise forms.ValidationError('range_from cannot be null')

        if self.range_to is None:
            raise forms.ValidationError('range_to cannot be null')

        if relative_delta_to_total_seconds(self.frequency) <= 0:
            raise forms.ValidationError('frequency must be positive interval ')

        if relative_delta_to_total_seconds(self.range_to) <= relative_delta_to_total_seconds(self.range_from):
            raise forms.ValidationError('range_to must be greater than range_from')

    def __str__(self):
        return self.name
Ejemplo n.º 2
0
class IntervalWithChoice(models.Model):
    CHOICES = [
        (relativedelta(months=1), '1 month'),
        ('P3M', '3 months'),
        (relativedelta(months=6), '6 months'),
    ]
    value = RelativeDeltaField(null=True, blank=True, choices=CHOICES)
def test_simple_annotation(dummy_intervals):
    one_month = Cast(
        Value(relativedelta(months=1), output_field=RelativeDeltaField()),
        DurationField()
    )
    q = Interval.objects.annotate(month_earlier=ExpressionWrapper(F('date') - one_month, output_field=DateField()))
    result = list(q.values_list('date', 'month_earlier'))
    assert result == [(date(2020, 3, 6), datetime(2020, 2, 6, 0, 0)),
                      (date(2020, 10, 6), datetime(2020, 9, 6, 0, 0))]
    assert 1 == q.filter(month_earlier__lt='2020-09-06').count()
    assert 2 == q.filter(month_earlier__lte='2020-09-06').count()
Ejemplo n.º 4
0
class Interval(models.Model):
    value = RelativeDeltaField(null=True, blank=True)
Ejemplo n.º 5
0
class ResultaatType(models.Model):
    """
    Het betreft de indeling of groepering van resultaten van zaken van hetzelfde
    ZAAKTYPE naar hun aard, zoals 'verleend', 'geweigerd', 'verwerkt', et cetera.

    Toelichting objecttype
    Elke zaak heeft een resultaat. In een aantal gevallen valt dit resultaat samen met een besluit:
    ‘Evenementenvergunning verleend’, ‘Energiesubsidie geweigerd’, et cetera. Het komt echter
    ook voor dat zaken worden afgehandeld zonder dat er een besluit wordt genomen. Dit is
    bijvoorbeeld het geval bij aangiften (geboorte, verhuizing), meldingen (openbare ruimte), maar
    ook bij het intrekken van een aanvraag. Het resultaat van een zaak is van groot belang voor de
    archivering: het resultaattype bepaalt mede of de zaak en het bijbehorende dossier moeten
    worden vernietigd (na enige termijn) of blijvend bewaard moeten worden (en na enige termijn
    ‘overgebracht’ worden naar een archiefbewaarplaats). Met RESULTAATTYPE worden de
    mogelijke resultaten benoemd bij het desbetreffende zaaktype. Daarmee is het archiefregime
    bepaald voor het gehele zaakdossier: alle informatie over en documenten bij de zaken van het
    ZAAKTYPE.
    In uitzonderingsgevallen kan er sprake van zijn dat documenten van een bepaald
    INFORMATIEOBJECTTYPE in zaakdossiers bij zaken van het ZAAKTYPE een afwijkend
    archiefregime hebben ten opzichte van het zaakdossier. Privacy-gevoeligheid kan er reden
    voor zijn om documenten van een ZAAKINFORMATIEOBJECTTYPE eerder te vernietigen dan het
    zaakdossier als geheel. Specifieke wetgeving, zoals die voor de BAG, leidt er daarentegen toe
    dat een Omgevingsvergunning (activiteit bouwen) ten eeuwige dage bewaard moet blijven
    terwijl het zaakdossier na 20 jaar vernietigd dient te worden. De relatiesoort ‘RESULTAATTYPE
    bepaalt afwijkend archiefregime van ZAAK-INFORMATIEOBJECT-TYPE’ geeft de mogelijkheid
    deze uitzonderingsgevallen te documenteren.
    """

    uuid = models.UUIDField(unique=True,
                            default=uuid.uuid4,
                            help_text="Unieke resource identifier (UUID4)")
    zaaktype = models.ForeignKey(
        "catalogi.ZaakType",
        verbose_name=_("is relevant voor"),
        on_delete=models.CASCADE,
        related_name="resultaattypen",
        help_text=
        _("URL-referentie naar het ZAAKTYPE van ZAAKen waarin resultaten van dit RESULTAATTYPE bereikt kunnen worden."
          ),
    )

    # core data - used by ZRC to calculate archival-related dates
    omschrijving = models.CharField(
        _("omschrijving"),
        max_length=20,
        help_text=_(
            "Omschrijving van de aard van resultaten van het RESULTAATTYPE."),
    )
    resultaattypeomschrijving = models.URLField(
        _("resultaattypeomschrijving"),
        max_length=1000,
        help_text=
        _("Algemeen gehanteerde omschrijving van de aard van resultaten van het RESULTAATTYPE. "
          "Dit moet een URL-referentie zijn naar de referenlijst van generieke "
          "resultaattypeomschrijvingen. Im ImZTC heet dit 'omschrijving generiek'"
          ),
    )
    omschrijving_generiek = models.CharField(
        _("omschrijving generiek"),
        max_length=20,
        blank=True,
        editable=False,
        help_text=
        _("Gecachete tekstuele waarde van de generieke resultaattypeomschrijving."
          ),
    )

    # TODO: validate that this matches the Zaaktype.procestype
    selectielijstklasse = models.URLField(
        _("selectielijstklasse"),
        max_length=1000,
        help_text=
        _("URL-referentie naar de, voor het archiefregime bij het RESULTAATTYPE relevante, "
          "categorie in de Selectielijst Archiefbescheiden (RESULTAAT in de Selectielijst API) "
          "van de voor het ZAAKTYPE verantwoordelijke overheidsorganisatie."),
    )

    # derived fields from selectielijstklasse
    archiefnominatie = models.CharField(
        _("archiefnominatie"),
        default="",
        choices=Archiefnominatie.choices,
        max_length=20,
        blank=True,
        help_text=_(
            "Aanduiding die aangeeft of ZAAKen met een resultaat van "
            "dit RESULTAATTYPE blijvend moeten worden bewaard of "
            "(op termijn) moeten worden vernietigd. Indien niet expliciet "
            "opgegeven wordt dit gevuld vanuit de selectielijst."),
    )

    archiefactietermijn = RelativeDeltaField(
        _("archiefactietermijn"),
        null=True,
        blank=True,
        help_text=_(
            "De termijn, na het vervallen van het bedrjfsvoeringsbelang, "
            "waarna het zaakdossier (de ZAAK met alle bijbehorende "
            "INFORMATIEOBJECTen) van een ZAAK met een resultaat van dit "
            "RESULTAATTYPE vernietigd of overgebracht (naar een "
            "archiefbewaarplaats) moet worden. Voor te vernietigen "
            "dossiers betreft het de in die Selectielijst genoemde "
            "bewaartermjn. Voor blijvend te bewaren zaakdossiers "
            "betreft het de termijn vanaf afronding van de zaak tot "
            "overbrenging (de procestermijn is dan nihil)."),
    )

    # TODO: validate dependencies between fields
    brondatum_archiefprocedure_afleidingswijze = models.CharField(
        _("afleidingswijze brondatum"),
        max_length=20,
        choices=Afleidingswijze.choices,
        help_text=_("Wijze van bepalen van de brondatum."),
    )
    # TODO: this could/should be validated against a remote OAS 3.0!
    brondatum_archiefprocedure_datumkenmerk = models.CharField(
        _("datumkenmerk"),
        max_length=80,
        blank=True,
        help_text=_("Naam van de attribuutsoort van het procesobject dat "
                    "bepalend is voor het einde van de procestermijn."),
    )
    brondatum_archiefprocedure_einddatum_bekend = models.BooleanField(
        _("einddatum bekend"),
        default=False,
        help_text=_(
            "Indicatie dat de einddatum van het procesobject gedurende "
            "de uitvoering van de zaak bekend moet worden. Indien deze "
            "nog niet bekend is en deze waarde staat op `true`, dan "
            "kan de zaak (nog) niet afgesloten worden."),
    )
    brondatum_archiefprocedure_objecttype = models.CharField(
        _("objecttype"),
        max_length=80,
        blank=True,
        choices=ZaakobjectTypes.choices,
        help_text=
        _("Het soort object in de registratie dat het procesobject representeert."
          ),
    )
    # TODO: standardize content so that consumers understand this?
    brondatum_archiefprocedure_registratie = models.CharField(
        _("registratie"),
        max_length=80,
        blank=True,
        help_text=
        _("De naam van de registratie waarvan het procesobject deel uit maakt."
          ),
    )
    brondatum_archiefprocedure_procestermijn = RelativeDeltaField(
        _("procestermijn"),
        null=True,
        blank=True,
        help_text=_(
            "De periode dat het zaakdossier na afronding van de zaak "
            "actief gebruikt en/of geraadpleegd wordt ter ondersteuning "
            "van de taakuitoefening van de organisatie. Enkel relevant "
            "indien de afleidingswijze 'termijn' is."),
    )

    brondatum_archiefprocedure = GegevensGroepType(
        {
            "afleidingswijze": brondatum_archiefprocedure_afleidingswijze,
            "datumkenmerk": brondatum_archiefprocedure_datumkenmerk,
            "einddatum_bekend": brondatum_archiefprocedure_einddatum_bekend,
            "objecttype": brondatum_archiefprocedure_objecttype,
            "registratie": brondatum_archiefprocedure_registratie,
            "procestermijn": brondatum_archiefprocedure_procestermijn,
        },
        optional=("datumkenmerk", "einddatum_bekend", "objecttype",
                  "registratie"),
        none_for_empty=True,
    )

    # meta-information - this is mostly informative
    toelichting = models.TextField(
        _("toelichting"),
        blank=True,
        help_text=_(
            "Een toelichting op dit RESULTAATTYPE en het belang hiervan "
            "voor ZAAKen waarin een resultaat van dit RESULTAATTYPE wordt geselecteerd."
        ),
    )

    # 'old' fields, not actively used at the moment

    bepaalt_afwijkend_archiefregime_van = models.ManyToManyField(
        "catalogi.ZaakInformatieObjectType",
        verbose_name=_("bepaalt afwijkend archiefregime van"),
        through="catalogi.ZaakInformatieobjectTypeArchiefregime",
        blank=True,
        related_name="resultaattypes",
        help_text=
        _("Informatieobjecten van een ZAAKINFORMATIEOBJECTTYPE bij zaken van een ZAAKTYPE waarvan, op grond van "
          "resultaten van een RESULTAATTYPE bij dat ZAAKTYPE, de archiveringskenmerken afwijken van de "
          "archiveringskenmerken van het ZAAKTYPE."),
    )
    heeft_verplichte_zot = models.ManyToManyField(
        "catalogi.ZaakObjectType",
        verbose_name=_("heeft verplichte"),
        blank=True,
        help_text=_(
            "De ZAAKOBJECTTYPEn die verplicht gerelateerd moeten zijn aan ZAAKen van dit ZAAKTYPE voordat een "
            "resultaat van dit RESULTAATTYPE kan worden gezet."),
    )
    heeft_verplichte_ziot = models.ManyToManyField(
        "catalogi.ZaakInformatieObjectType",
        verbose_name=_("heeft verplichte zaakinformatie objecttype"),
        blank=True,
        related_name="resultaattypen",  # TODO needs a better related name
        help_text=
        _("De INFORMATIEOBJECTTYPEn die verplicht aanwezig moeten zijn in het zaakdossier van ZAAKen van dit "
          "ZAAKTYPE voordat een resultaat van dit RESULTAATTYPE kan worden gezet."
          ),
    )
    heeft_voor_brondatum_archiefprocedure_relevante = models.ForeignKey(
        "catalogi.Eigenschap",
        verbose_name=_("heeft voor brondatum archiefprocedure relevante"),
        blank=True,
        null=True,
        on_delete=models.CASCADE,
        help_text=_(
            "De EIGENSCHAP die bepalend is voor het moment waarop de Archiefactietermijn start voor een ZAAK "
            "met een resultaat van dit RESULTAATTYPE."),
    )

    class Meta:
        unique_together = ("zaaktype", "omschrijving")
        verbose_name = _("resultaattype")
        verbose_name_plural = _("resultaattypen")

    def save(self, *args, **kwargs):
        """
        Save some derived fields into local object as a means of caching.
        """
        if not self.omschrijving_generiek and self.resultaattypeomschrijving:
            response = requests.get(self.resultaattypeomschrijving).json()
            self.omschrijving_generiek = response["omschrijving"]

        # derive the default archiefnominatie
        if not self.archiefnominatie and self.selectielijstklasse:
            selectielijstklasse = self.get_selectielijstklasse()
            self.archiefnominatie = selectielijstklasse["waardering"]

        if not self.archiefactietermijn and self.selectielijstklasse:
            selectielijstklasse = self.get_selectielijstklasse()
            self.archiefactietermijn = selectielijstklasse["bewaartermijn"]

        super().save(*args, **kwargs)

    def __str__(self):
        return f"{self.zaaktype} - {self.omschrijving}"

    def get_selectielijstklasse(self):
        if not hasattr(self, "_selectielijstklasse"):
            # selectielijstklasse should've been validated at this point by either
            # forms or serializers
            response = requests.get(self.selectielijstklasse)
            response.raise_for_status()
            self._selectielijstklasse = response.json()
        return self._selectielijstklasse
 def test_none_value_survives_to_python(self):
     self.assertIsNone(RelativeDeltaField().to_python(None))
Ejemplo n.º 7
0
class Interval(models.Model):
    value = RelativeDeltaField(null=True, blank=True)
    date = models.DateField(default=datetime.date(2020, 10, 21))
Ejemplo n.º 8
0
class Resultaat(models.Model):
    uuid = models.UUIDField(_("uuid"), default=uuid.uuid4)

    # relations/tree
    # The tree is modelled via a simple self-FK because it cannot have arbitrary depth
    proces_type = models.ForeignKey("ProcesType",
                                    on_delete=models.CASCADE,
                                    verbose_name=_("procestype"))
    generiek_resultaat = models.ForeignKey(
        "self",
        null=True,
        blank=True,
        on_delete=models.CASCADE,
        limit_choices_to={"generiek_resultaat__isnull": True},
        verbose_name=_("generiek resultaat"),
        help_text=
        _("Voor specifieke resultaten, geef aan bij welk generiek resultaat deze hoort"
          ),
    )

    nummer = models.PositiveSmallIntegerField(
        _("nummer"),
        help_text=_(
            "Nummer van het resultaat. Dit wordt samengesteld met het procestype en "
            "generiek resultaat indien van toepassing."),
    )
    naam = models.CharField(_("naam"),
                            max_length=40,
                            help_text=_("Benaming van het procestype"))
    omschrijving = models.CharField(
        _("omschrijving"),
        max_length=150,
        blank=True,
        help_text=_("Omschrijving van het specifieke resultaat"),
    )
    herkomst = models.CharField(
        _("herkomst"),
        max_length=200,
        help_text=
        _("Voorbeeld: 'Risicoanalyse', 'Systeemanalyse' of verwijzing naar Wet- en regelgeving"
          ),
    )
    waardering = models.CharField(_("waardering"),
                                  max_length=50,
                                  choices=Archiefnominatie.choices)
    procestermijn = models.CharField(_("procestermijn"),
                                     max_length=50,
                                     choices=Procestermijnen.choices,
                                     blank=True)
    bewaartermijn = RelativeDeltaField(_("bewaartermijn"),
                                       null=True,
                                       blank=True)
    toelichting = models.TextField(_("toelichting"), blank=True)

    # relevant domains
    algemeen_bestuur_en_inrichting_organisatie = models.BooleanField(
        _("algemeen bestuur en inrichting organisatie"), default=False)
    bedrijfsvoering_en_personeel = models.BooleanField(
        _("bedrijfsvoering en personeel"), default=False)
    publieke_informatie_en_registratie = models.BooleanField(
        _("publieke informatie en registratie"), default=False)
    burgerzaken = models.BooleanField(_("burgerzaken"), default=False)
    veiligheid = models.BooleanField(_("veiligheid"), default=False)
    verkeer_en_vervoer = models.BooleanField(_("verkeer en vervoer"),
                                             default=False)
    economie = models.BooleanField(_("economie"), default=False)
    onderwijs = models.BooleanField(_("onderwijs"), default=False)
    sport_cultuur_en_recreatie = models.BooleanField(
        _("sport, cultuur en recreatie"), default=False)
    sociaal_domein = models.BooleanField(_("sociaal domein"), default=False)
    volksgezonheid_en_milieu = models.BooleanField(
        _("volksgezonheid en milieu"), default=False)
    vhrosv = models.BooleanField(_("VHROSV"), default=False)
    heffen_belastingen = models.BooleanField(_("heffen belastingen etc."),
                                             default=False)
    alle_taakgebieden = models.BooleanField(_("alle taakgebieden"),
                                            default=False)
    procestermijn_opmerking = models.CharField(
        _("procestermijn opmerking"),
        max_length=20,
        blank=True,
        help_text=_("Voorbeeld: '25 jaar', '30 jaar, '5 of 10 jaar'"),
    )

    objects = ResultaatQuerySet.as_manager()

    class Meta:
        verbose_name = _("resultaat")
        verbose_name_plural = _("resultaten")
        unique_together = ("proces_type", "generiek_resultaat", "nummer")

    def __str__(self):
        return f"{self.volledig_nummer} - {self.naam}"

    def clean(self):
        super().clean()

        if self.specifiek:
            if not self.omschrijving:
                raise ValidationError(
                    {
                        "omschrijving":
                        _("Omschrijving is een verplicht veld voor specifieke resultaten"
                          )
                    },
                    code="required",
                )
            if self.proces_type_id != self.generiek_resultaat.proces_type_id:
                raise ValidationError(
                    {
                        "proces_type":
                        _("Het procestype moet hetzelfde zijn als het procestype van het "
                          "generiek resultaat.")
                    },
                    code="invalid",
                )
        elif self.generiek and self.omschrijving:
            raise ValidationError(
                {
                    "omschrijving":
                    _("Omschrijving mag niet opgegeven worden voor generieke resultaten"
                      )
                },
                code="forbidden",
            )

    @property
    def generiek(self) -> bool:
        return self.generiek_resultaat_id is None

    @property
    def specifiek(self) -> bool:
        return not self.generiek

    @property
    def volledig_nummer(self) -> str:
        """
        Calculate the complete number of the result.
        """
        generiek_resultaat_nr = (f".{self.generiek_resultaat.nummer}"
                                 if self.specifiek else "")
        return f"{self.proces_type.nummer}{generiek_resultaat_nr}.{self.nummer}"