diff --git a/src/openklant/components/klantinteracties/api/serializers/digitaal_adres.py b/src/openklant/components/klantinteracties/api/serializers/digitaal_adres.py index 868a7b3d..f45ccca3 100644 --- a/src/openklant/components/klantinteracties/api/serializers/digitaal_adres.py +++ b/src/openklant/components/klantinteracties/api/serializers/digitaal_adres.py @@ -1,7 +1,7 @@ from django.db import transaction from django.utils.translation import gettext_lazy as _ -from rest_framework import serializers +from rest_framework import serializers, validators from openklant.components.klantinteracties.api.serializers.constants import ( SERIALIZER_PATH, @@ -79,6 +79,7 @@ class Meta: "verstrekt_door_partij", "adres", "soort_digitaal_adres", + "is_standaard_adres", "omschrijving", ) extra_kwargs = { @@ -90,6 +91,20 @@ class Meta: }, } + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + if "soort_digitaal_adres" in self.fields: + # Avoid validating the UniqueConstraint for `soort_digitaal_adres` with + # `is_standaard_adres=True`. We want to enforce the constraint at the database + # level, but not via the API, because setting a new default sets all other + # `is_standaard_adres=False` (via DigitaalAdres.save) + self.fields["soort_digitaal_adres"].validators = [ + validator + for validator in self.fields["soort_digitaal_adres"].validators + if not isinstance(validator, validators.UniqueValidator) + ] + def validate_adres(self, adres): """ Define the validator here, to avoid DRF spectacular marking the format for diff --git a/src/openklant/components/klantinteracties/migrations/0022_digitaaladres_is_standaard_adres_and_more.py b/src/openklant/components/klantinteracties/migrations/0022_digitaaladres_is_standaard_adres_and_more.py new file mode 100644 index 00000000..5f07c294 --- /dev/null +++ b/src/openklant/components/klantinteracties/migrations/0022_digitaaladres_is_standaard_adres_and_more.py @@ -0,0 +1,30 @@ +# Generated by Django 4.2.15 on 2024-10-31 08:27 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("klantinteracties", "0021_alter_digitaaladres_betrokkene"), + ] + + operations = [ + migrations.AddField( + model_name="digitaaladres", + name="is_standaard_adres", + field=models.BooleanField( + default=False, + help_text="Geeft aan of dit digitaal adres het standaard adres is voor het `soort_digitaal_adres`", + verbose_name="Is standaard adres", + ), + ), + migrations.AddConstraint( + model_name="digitaaladres", + constraint=models.UniqueConstraint( + condition=models.Q(("is_standaard_adres", True)), + fields=("partij", "soort_digitaal_adres"), + name="unique_default_per_partij_and_soort", + ), + ), + ] diff --git a/src/openklant/components/klantinteracties/models/digitaal_adres.py b/src/openklant/components/klantinteracties/models/digitaal_adres.py index 157544af..3c8321c4 100644 --- a/src/openklant/components/klantinteracties/models/digitaal_adres.py +++ b/src/openklant/components/klantinteracties/models/digitaal_adres.py @@ -40,6 +40,13 @@ class DigitaalAdres(APIMixin, models.Model): max_length=255, choices=SoortDigitaalAdres.choices, ) + is_standaard_adres = models.BooleanField( + _("Is standaard adres"), + help_text=_( + "Geeft aan of dit digitaal adres het standaard adres is voor het `soort_digitaal_adres`" + ), + default=False, + ) adres = models.CharField( _("adres"), help_text=_( @@ -55,6 +62,25 @@ class DigitaalAdres(APIMixin, models.Model): class Meta: verbose_name = _("digitaal adres") + constraints = [ + models.UniqueConstraint( + fields=["partij", "soort_digitaal_adres"], + condition=models.Q(is_standaard_adres=True), + name="unique_default_per_partij_and_soort", + ) + ] def __str__(self): return f"{self.betrokkene} - {self.adres}" + + def save(self, *args, **kwargs): + if self.is_standaard_adres: + # Because there can only be one default address per `soort_digitaal_adres` + # and `partij`, mark all other addresses as non-default + DigitaalAdres.objects.filter( + soort_digitaal_adres=self.soort_digitaal_adres, + partij=self.partij, + is_standaard_adres=True, + ).update(is_standaard_adres=False) + + super().save(*args, **kwargs) diff --git a/src/openklant/components/klantinteracties/openapi.yaml b/src/openklant/components/klantinteracties/openapi.yaml index 6575bb24..c9fe60b5 100644 --- a/src/openklant/components/klantinteracties/openapi.yaml +++ b/src/openklant/components/klantinteracties/openapi.yaml @@ -3463,6 +3463,10 @@ components: - $ref: '#/components/schemas/SoortDigitaalAdresEnum' description: Typering van het digitale adres die aangeeft via welk(e) kanaal of kanalen met dit adres contact kan worden opgenomen. + isStandaardAdres: + type: boolean + description: Geeft aan of dit digitaal adres het standaard adres is voor + het `soort_digitaal_adres` omschrijving: type: string description: Omschrijving van het digitaal adres. @@ -4868,6 +4872,10 @@ components: - $ref: '#/components/schemas/SoortDigitaalAdresEnum' description: Typering van het digitale adres die aangeeft via welk(e) kanaal of kanalen met dit adres contact kan worden opgenomen. + isStandaardAdres: + type: boolean + description: Geeft aan of dit digitaal adres het standaard adres is voor + het `soort_digitaal_adres` omschrijving: type: string description: Omschrijving van het digitaal adres.