From 0ef710626c828d537877129488741dcebdef0ba7 Mon Sep 17 00:00:00 2001 From: bart-maykin Date: Tue, 10 Oct 2023 17:58:32 +0200 Subject: [PATCH] :card_file_box: [#61] created Partij, Persoon, ContactPersoon and Organisatie models --- .../components/klantinteracties/__init__.py | 0 .../components/klantinteracties/apps.py | 5 + .../components/klantinteracties/constants.py | 60 +++ .../migrations/0001_initial.py | 364 ++++++++++++++++++ .../klantinteracties/migrations/__init__.py | 0 .../components/klantinteracties/models.py | 333 ++++++++++++++++ src/openklant/conf/base.py | 1 + 7 files changed, 763 insertions(+) create mode 100644 src/openklant/components/klantinteracties/__init__.py create mode 100644 src/openklant/components/klantinteracties/apps.py create mode 100644 src/openklant/components/klantinteracties/constants.py create mode 100644 src/openklant/components/klantinteracties/migrations/0001_initial.py create mode 100644 src/openklant/components/klantinteracties/migrations/__init__.py create mode 100644 src/openklant/components/klantinteracties/models.py diff --git a/src/openklant/components/klantinteracties/__init__.py b/src/openklant/components/klantinteracties/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/openklant/components/klantinteracties/apps.py b/src/openklant/components/klantinteracties/apps.py new file mode 100644 index 00000000..6de18f55 --- /dev/null +++ b/src/openklant/components/klantinteracties/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class KlantinteractiesConfig(AppConfig): + name = "openklant.components.klantinteracties" diff --git a/src/openklant/components/klantinteracties/constants.py b/src/openklant/components/klantinteracties/constants.py new file mode 100644 index 00000000..88a2ba0b --- /dev/null +++ b/src/openklant/components/klantinteracties/constants.py @@ -0,0 +1,60 @@ +from django.utils.translation import gettext_lazy as _ + +from djchoices import ChoiceItem, DjangoChoices + + +# TODO: change value when document gets updated: +# https://vng-realisatie.github.io/klantinteracties/informatiemodel/gegevenswoordenboek#detail_class_Model_Initiator +class Initiator(DjangoChoices): + gemeente = ChoiceItem("gemeente", _("Gemeente")) + klant = ChoiceItem("klant", _("Klant")) + vertegenwoordiger = ChoiceItem("vertegenwoordiger", _("Vertegenwoordiger")) + + +class Taakstatus(DjangoChoices): + te_verwerken = ChoiceItem("te_verwerken", _("Het verzoek is afgehandeld.")) + verwerkt = ChoiceItem("verwerkt", _("Het verzoek id buiten behandeling gesteld.")) + + +class SoortBezoekadres(DjangoChoices): + binnenlands_adres = ChoiceItem("binnenlands_adres", _("Binnenlands adres")) + buitenlands_adres = ChoiceItem("binnenlands_adres", _("Buitenlands adres")) + + +class AanduidingBijHuisnummer(DjangoChoices): + bij = ChoiceItem("bij", _("Bij")) + tegenover = ChoiceItem("tegenover", _("Tegenover")) + + +class SoortCorrespondentieadres(DjangoChoices): + postbusnummer = ChoiceItem("postbusnummer", _("Postbusnummer")) + antwoordnummer = ChoiceItem("antwoordnummer", _("Antwoordnummer")) + binnenlands_adres = ChoiceItem("binnenlands_adres", _("Binnenlands adres")) + buitenlands_adres = ChoiceItem("buitenlands_adres", _("Buitenlands adres")) + + +class SoortActor(DjangoChoices): + medewerker = ChoiceItem("medewerker", _("Medewerker")) + geautomatiseerde_actor = ChoiceItem( + "geautomatiseerde_actor", _("Geautomatiseerde actor") + ) + organisatorische_eenheid = ChoiceItem( + "organisatorische_eenheid", _("Organisatorische eenheid") + ) + + +class SoortInhoudsdeel(DjangoChoices): + informatieobject = ChoiceItem("informatieobject", _("Informatieobject")) + overig_object = ChoiceItem("overig_object", _("Overig object")) + tekst = ChoiceItem("tekst", _("Tekst")) + + +class SoortPartij(DjangoChoices): + persoon = ChoiceItem("persoon", _("Persoon")) + organisatie = ChoiceItem("organisatie", _("Organisatie")) + contactpersoon = ChoiceItem("contactpersoon", _("Contactpersoon")) + + +class Klantcontrol(DjangoChoices): + vertegenwoordiger = ChoiceItem("vertegenwoordiger", _("Vertegenwoordiger")) + klant = ChoiceItem("klant", _("Klant")) diff --git a/src/openklant/components/klantinteracties/migrations/0001_initial.py b/src/openklant/components/klantinteracties/migrations/0001_initial.py new file mode 100644 index 00000000..d311ec89 --- /dev/null +++ b/src/openklant/components/klantinteracties/migrations/0001_initial.py @@ -0,0 +1,364 @@ +# Generated by Django 3.2.18 on 2023-10-10 15:54 + +import django.core.validators +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="Partij", + fields=[ + ( + "id", + models.UUIDField( + default=uuid.uuid4, + help_text="Unieke (technische) identificatiecode van de partij.", + primary_key=True, + serialize=False, + unique=True, + ), + ), + ( + "nummer", + models.PositiveIntegerField( + help_text="Uniek identificerend nummer dat tijdens communicatie tussen mensen kan worden gebruikt om de specifieke partij aan te duiden.", + validators=[ + django.core.validators.MaxValueValidator(9999999999) + ], + verbose_name="Nummer", + ), + ), + ( + "interne_notitie", + models.CharField( + blank=True, + help_text="Mededelingen, aantekeningen of bijzonderheden over de partij, bedoeld voor intern gebruik.", + max_length=1000, + verbose_name="Interne notitie", + ), + ), + ( + "soort_partij", + models.CharField( + choices=[ + ("persoon", "Persoon"), + ("organisatie", "Organisatie"), + ("contactpersoon", "Contactpersoon"), + ], + help_text="Geeft aan van welke specifieke soort partij sprake is.", + max_length=14, + verbose_name="Soort partij", + ), + ), + ( + "indicatie_geheimhouding", + models.BooleanField( + help_text="Geeft aan of de verstrekker van partijgegevens heeft aangegeven dat deze gegevens als geheim beschouwd moeten worden.", + verbose_name="Indicatie geheimhouding", + ), + ), + ( + "voorkeurskanaal", + models.CharField( + blank=True, + help_text="Kanaal dat de partij bij voorkeur gebruikt voor contact met de gemeente.", + max_length=50, + verbose_name="Voorkeurskanaal", + ), + ), + ( + "voorkeurstaal", + models.CharField( + blank=True, + help_text="Taal waarin de partij bij voorkeur contact heeft met de gemeente.", + max_length=255, + verbose_name="Voorkeurstaal", + ), + ), + ( + "indicatie_actief", + models.BooleanField( + help_text="Geeft aan of de contactgegevens van de partij nog gebruikt morgen worden om contact op te nemen. Gegevens van niet-actieve partijen mogen hiervoor niet worden gebruikt.", + verbose_name="Indicatie actief", + ), + ), + ( + "correspondentieadres_nummeraanduiding_id", + models.UUIDField( + blank=True, + help_text="Identificatie van het adres bij de Basisregistratie Adressen en Gebouwen.", + unique=True, + verbose_name="Nummeraanduiding ID", + ), + ), + ( + "correspondentieadres_adresregel1", + models.CharField( + blank=True, + help_text="Eerste deel van het adres dat niet voorkomt in de Basisregistratie Adressen en Gebouwen.", + max_length=80, + verbose_name="Adresregel 1", + ), + ), + ( + "correspondentieadres_adresregel2", + models.CharField( + blank=True, + help_text="Tweede deel van het adres dat niet voorkomt in de Basisregistratie Adressen en Gebouwen.", + max_length=80, + verbose_name="Adresregel 2", + ), + ), + ( + "correspondentieadres_adresregel3", + models.CharField( + blank=True, + help_text="Derde deel van het adres dat niet voorkomt in de Basisregistratie Adressen en Gebouwen.", + max_length=80, + verbose_name="Adresregel 3", + ), + ), + ( + "correspondentieadres_land", + models.IntegerField( + blank=True, + help_text="Een code, opgenomen in Tabel 34, Landentabel, die het land (buiten Nederland) aangeeft alwaar de ingeschrevene verblijft.", + null=True, + validators=[django.core.validators.MaxValueValidator(9999)], + verbose_name="Land", + ), + ), + ( + "bezoekadres_nummeraanduiding_id", + models.UUIDField( + blank=True, + help_text="Identificatie van het adres bij de Basisregistratie Adressen en Gebouwen.", + unique=True, + verbose_name="Nummeraanduiding ID", + ), + ), + ( + "bezoekadres_adresregel1", + models.CharField( + blank=True, + help_text="Eerste deel van het adres dat niet voorkomt in de Basisregistratie Adressen en Gebouwen.", + max_length=80, + verbose_name="Adresregel 1", + ), + ), + ( + "bezoekadres_adresregel2", + models.CharField( + blank=True, + help_text="Tweede deel van het adres dat niet voorkomt in de Basisregistratie Adressen en Gebouwen.", + max_length=80, + verbose_name="Adresregel 2", + ), + ), + ( + "bezoekadres_adresregel3", + models.CharField( + blank=True, + help_text="Derde deel van het adres dat niet voorkomt in de Basisregistratie Adressen en Gebouwen.", + max_length=80, + verbose_name="Adresregel 3", + ), + ), + ( + "bezoekadres_land", + models.IntegerField( + blank=True, + help_text="Een code, opgenomen in Tabel 34, Landentabel, die het land (buiten Nederland) aangeeft alwaar de ingeschrevene verblijft.", + null=True, + validators=[django.core.validators.MaxValueValidator(9999)], + verbose_name="Land", + ), + ), + ], + options={ + "verbose_name": "partij", + "verbose_name_plural": "partijen", + }, + ), + migrations.CreateModel( + name="Persoon", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "contactnaam_voorletters", + models.CharField( + help_text="Een afkorting van de voornamen. Meestal de beginletter, maar in sommige gevallen de beginletter gecombineerd met de tweede letter van een voornaam.", + max_length=6, + verbose_name="Voorletters", + ), + ), + ( + "contactnaam_voornaam", + models.CharField( + blank=True, + help_text="De voornaam die de persoon wil gebruiken tijdens communicatie met de gemeente.", + max_length=200, + verbose_name="Voornaam", + ), + ), + ( + "contactnaam_voorvoegsel_achternaam", + models.CharField( + blank=True, + help_text="Een eventueel voorvoegsel dat hoort bij de achternaam die de persoon wil gebruiken tijdens communicatie met de gemeente.", + max_length=10, + verbose_name="Voorvoegsel achternaam", + ), + ), + ( + "contactnaam_achternaam", + models.CharField( + blank=True, + help_text="Een achternaam die de persoon wil gebruiken tijdens communicatie met de gemeente.", + max_length=200, + verbose_name="Achternaam", + ), + ), + ( + "partij", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="persoon", + to="klantinteracties.partij", + verbose_name="Partij", + ), + ), + ], + options={ + "verbose_name": "persoon", + "verbose_name_plural": "personen", + }, + ), + migrations.CreateModel( + name="Organisatie", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "naam", + models.CharField( + blank=True, + help_text="Naam van de organisatie.", + max_length=200, + verbose_name="Naam", + ), + ), + ( + "partij", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="organisatie", + to="klantinteracties.partij", + verbose_name="Partij", + ), + ), + ], + options={ + "verbose_name": "organisatie", + "verbose_name_plural": "organisaties", + }, + ), + migrations.CreateModel( + name="Contactpersoon", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "contactnaam_voorletters", + models.CharField( + help_text="Een afkorting van de voornamen. Meestal de beginletter, maar in sommige gevallen de beginletter gecombineerd met de tweede letter van een voornaam.", + max_length=6, + verbose_name="Voorletters", + ), + ), + ( + "contactnaam_voornaam", + models.CharField( + blank=True, + help_text="De voornaam die de persoon wil gebruiken tijdens communicatie met de gemeente.", + max_length=200, + verbose_name="Voornaam", + ), + ), + ( + "contactnaam_voorvoegsel_achternaam", + models.CharField( + blank=True, + help_text="Een eventueel voorvoegsel dat hoort bij de achternaam die de persoon wil gebruiken tijdens communicatie met de gemeente.", + max_length=10, + verbose_name="Voorvoegsel achternaam", + ), + ), + ( + "contactnaam_achternaam", + models.CharField( + blank=True, + help_text="Een achternaam die de persoon wil gebruiken tijdens communicatie met de gemeente.", + max_length=200, + verbose_name="Achternaam", + ), + ), + ( + "organisatie", + models.ForeignKey( + help_text="De organisatie waar een contactpersoon voor werkt.", + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="contact_personen", + to="klantinteracties.organisatie", + verbose_name="Organistatie", + ), + ), + ( + "partij", + models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + related_name="contact_persoon", + to="klantinteracties.partij", + verbose_name="Partij", + ), + ), + ], + options={ + "verbose_name": "contact persoon", + "verbose_name_plural": "contact personen", + }, + ), + ] diff --git a/src/openklant/components/klantinteracties/migrations/__init__.py b/src/openklant/components/klantinteracties/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/openklant/components/klantinteracties/models.py b/src/openklant/components/klantinteracties/models.py new file mode 100644 index 00000000..2afc01bf --- /dev/null +++ b/src/openklant/components/klantinteracties/models.py @@ -0,0 +1,333 @@ +import uuid + +from django.core.validators import MaxValueValidator +from django.db import models +from django.utils.translation import gettext_lazy as _ + +from vng_api_common.descriptors import GegevensGroepType + +from .constants import SoortPartij + + +class Partij(models.Model): + id = models.UUIDField( + primary_key=True, + unique=True, + default=uuid.uuid4, + help_text=_("Unieke (technische) identificatiecode van de partij."), + ) + nummer = models.PositiveIntegerField( + _("Nummer"), + help_text=_( + "Uniek identificerend nummer dat tijdens communicatie tussen mensen kan " + "worden gebruikt om de specifieke partij aan te duiden." + ), + validators=[MaxValueValidator(9999999999)], + ) + interne_notitie = models.CharField( + _("Interne notitie"), + help_text=_( + "Mededelingen, aantekeningen of bijzonderheden over de partij, bedoeld voor intern gebruik." + ), + max_length=1000, + blank=True, + ) + soort_partij = models.CharField( + _("Soort partij"), + help_text=_("Geeft aan van welke specifieke soort partij sprake is."), + max_length=14, + choices=SoortPartij.choices, + ) + indicatie_geheimhouding = models.BooleanField( + _("Indicatie geheimhouding"), + help_text=_( + "Geeft aan of de verstrekker van partijgegevens heeft aangegeven dat " + "deze gegevens als geheim beschouwd moeten worden." + ), + ) + voorkeurskanaal = models.CharField( + _("Voorkeurskanaal"), + help_text=_( + "Kanaal dat de partij bij voorkeur gebruikt voor contact met de gemeente." + ), + max_length=50, + blank=True, + ) + voorkeurstaal = models.CharField( + _("Voorkeurstaal"), + help_text=_( + "Taal waarin de partij bij voorkeur contact heeft met de gemeente." + ), + max_length=255, + blank=True, + ) + indicatie_actief = models.BooleanField( + _("Indicatie actief"), + help_text=_( + "Geeft aan of de contactgegevens van de partij nog gebruikt morgen worden om contact op te nemen. " + "Gegevens van niet-actieve partijen mogen hiervoor niet worden gebruikt." + ), + ) + + # Correspondentieadres model fields: + correspondentieadres_nummeraanduiding_id = models.UUIDField( + verbose_name=_("Nummeraanduiding ID"), + help_text=_( + "Identificatie van het adres bij de Basisregistratie Adressen en Gebouwen." + ), + unique=True, + blank=True, + ) + correspondentieadres_adresregel1 = models.CharField( + _("Adresregel 1"), + help_text=_( + "Eerste deel van het adres dat niet voorkomt in de Basisregistratie Adressen en Gebouwen." + ), + max_length=80, + blank=True, + ) + correspondentieadres_adresregel2 = models.CharField( + _("Adresregel 2"), + help_text=_( + "Tweede deel van het adres dat niet voorkomt in de Basisregistratie Adressen en Gebouwen." + ), + max_length=80, + blank=True, + ) + correspondentieadres_adresregel3 = models.CharField( + _("Adresregel 3"), + help_text=_( + "Derde deel van het adres dat niet voorkomt in de Basisregistratie Adressen en Gebouwen." + ), + max_length=80, + blank=True, + ) + correspondentieadres_land = models.IntegerField( + _("Land"), + help_text=_( + "Een code, opgenomen in Tabel 34, Landentabel, die het land (buiten Nederland) " + "aangeeft alwaar de ingeschrevene verblijft." + ), + validators=[MaxValueValidator(9999)], + blank=True, + null=True, + ) + + # Bezoekadres model fields: + bezoekadres_nummeraanduiding_id = models.UUIDField( + verbose_name=_("Nummeraanduiding ID"), + help_text=_( + "Identificatie van het adres bij de Basisregistratie Adressen en Gebouwen." + ), + unique=True, + blank=True, + ) + bezoekadres_adresregel1 = models.CharField( + _("Adresregel 1"), + help_text=_( + "Eerste deel van het adres dat niet voorkomt in de Basisregistratie Adressen en Gebouwen." + ), + max_length=80, + blank=True, + ) + bezoekadres_adresregel2 = models.CharField( + _("Adresregel 2"), + help_text=_( + "Tweede deel van het adres dat niet voorkomt in de Basisregistratie Adressen en Gebouwen." + ), + max_length=80, + blank=True, + ) + bezoekadres_adresregel3 = models.CharField( + _("Adresregel 3"), + help_text=_( + "Derde deel van het adres dat niet voorkomt in de Basisregistratie Adressen en Gebouwen." + ), + max_length=80, + blank=True, + ) + bezoekadres_land = models.IntegerField( + _("Land"), + help_text=_( + "Een code, opgenomen in Tabel 34, Landentabel, die het land (buiten Nederland) " + "aangeeft alwaar de ingeschrevene verblijft." + ), + validators=[MaxValueValidator(9999)], + blank=True, + null=True, + ) + + # Group types: + correspondentieadres = GegevensGroepType( + { + "nummeraanduiding id": correspondentieadres_nummeraanduiding_id, + "adresregel 1": correspondentieadres_adresregel1, + "adresregel 2": correspondentieadres_adresregel2, + "adresregel 3": correspondentieadres_adresregel3, + "land": correspondentieadres_land, + }, + ) + bezoekadres = GegevensGroepType( + { + "nummeraanduiding id": bezoekadres_nummeraanduiding_id, + "adresregel 1": bezoekadres_adresregel1, + "adresregel 2": bezoekadres_adresregel2, + "adresregel 3": bezoekadres_adresregel3, + "land": bezoekadres_land, + } + ) + + class Meta: + verbose_name = "partij" + verbose_name_plural = "partijen" + + +class Organisatie(models.Model): + partij = models.ForeignKey( + Partij, + on_delete=models.CASCADE, + verbose_name=_("Partij"), + related_name="organisatie", + null=True, + ) + naam = models.CharField( + _("Naam"), + help_text=_("Naam van de organisatie."), + max_length=200, + blank=True, + ) + + class Meta: + verbose_name = "organisatie" + verbose_name_plural = "organisaties" + + def __str__(self) -> str: + return self.naam + + +class Persoon(models.Model): + partij = models.ForeignKey( + Partij, + on_delete=models.CASCADE, + verbose_name=_("Partij"), + related_name="persoon", + null=True, + ) + # TODO: check if the max length is correct + contactnaam_voorletters = models.CharField( + _("Voorletters"), + help_text=_( + "Een afkorting van de voornamen. Meestal de beginletter, maar in sommige gevallen " + "de beginletter gecombineerd met de tweede letter van een voornaam." + ), + max_length=6, + ) + contactnaam_voornaam = models.CharField( + _("Voornaam"), + help_text=_( + "De voornaam die de persoon wil gebruiken tijdens communicatie met de gemeente." + ), + max_length=200, + blank=True, + ) + contactnaam_voorvoegsel_achternaam = models.CharField( + _("Voorvoegsel achternaam"), + help_text=_( + "Een eventueel voorvoegsel dat hoort bij de achternaam die de persoon " + "wil gebruiken tijdens communicatie met de gemeente." + ), + max_length=10, + blank=True, + ) + contactnaam_achternaam = models.CharField( + _("Achternaam"), + help_text=_( + "Een achternaam die de persoon wil gebruiken tijdens communicatie met de gemeente." + ), + max_length=200, + blank=True, + ) + + Contactnaam = GegevensGroepType( + { + "voorletters": contactnaam_voorletters, + "voornaam": contactnaam_voornaam, + "voorvoegsel achternaam": contactnaam_voorvoegsel_achternaam, + "achternaam": contactnaam_achternaam, + } + ) + + class Meta: + verbose_name = "persoon" + verbose_name_plural = "personen" + + def __str__(self) -> str: + return self.contactnaam_voorletters + + +class Contactpersoon(models.Model): + partij = models.ForeignKey( + Partij, + on_delete=models.CASCADE, + verbose_name=_("Partij"), + related_name="contact_persoon", + null=True, + ) + organisatie = models.ForeignKey( + Organisatie, + on_delete=models.CASCADE, + verbose_name=_("Organistatie"), + related_name="contact_personen", + help_text=_("De organisatie waar een contactpersoon voor werkt."), + null=True, + ) + # TODO: check if the max length is correct + contactnaam_voorletters = models.CharField( + _("Voorletters"), + help_text=_( + "Een afkorting van de voornamen. Meestal de beginletter, maar in sommige gevallen " + "de beginletter gecombineerd met de tweede letter van een voornaam." + ), + max_length=6, + ) + contactnaam_voornaam = models.CharField( + _("Voornaam"), + help_text=_( + "De voornaam die de persoon wil gebruiken tijdens communicatie met de gemeente." + ), + max_length=200, + blank=True, + ) + contactnaam_voorvoegsel_achternaam = models.CharField( + _("Voorvoegsel achternaam"), + help_text=_( + "Een eventueel voorvoegsel dat hoort bij de achternaam die de persoon " + "wil gebruiken tijdens communicatie met de gemeente." + ), + max_length=10, + blank=True, + ) + contactnaam_achternaam = models.CharField( + _("Achternaam"), + help_text=_( + "Een achternaam die de persoon wil gebruiken tijdens communicatie met de gemeente." + ), + max_length=200, + blank=True, + ) + + Contactnaam = GegevensGroepType( + { + "voorletters": contactnaam_voorletters, + "voornaam": contactnaam_voornaam, + "voorvoegsel achternaam": contactnaam_voorvoegsel_achternaam, + "achternaam": contactnaam_achternaam, + } + ) + + class Meta: + verbose_name = "contact persoon" + verbose_name_plural = "contact personen" + + def __str__(self) -> str: + return self.contactnaam_voorletters diff --git a/src/openklant/conf/base.py b/src/openklant/conf/base.py index 1dec9277..ab846f2e 100644 --- a/src/openklant/conf/base.py +++ b/src/openklant/conf/base.py @@ -137,6 +137,7 @@ "openklant.utils", "openklant.components.klanten", "openklant.components.contactmomenten", + "openklant.components.klantinteracties", ] MIDDLEWARE = [