Skip to content

Commit 4abea9b

Browse files
[#267] Added UniquePartijIdentificatorValidator and fixed old tests
1 parent e7b6e5c commit 4abea9b

File tree

7 files changed

+349
-195
lines changed

7 files changed

+349
-195
lines changed

src/openklant/components/klantinteracties/api/serializers/partijen.py

+22-9
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@
4444
from openklant.components.klantinteracties.models.rekeningnummers import Rekeningnummer
4545
from openklant.components.klantinteracties.models.validators import (
4646
PartijIdentificatorValidator,
47+
UniquePartijIdentificatorValidator,
4748
)
48-
from openklant.utils.serializers import get_field_value
4949

5050

5151
class PartijForeignkeyBaseSerializer(serializers.HyperlinkedModelSerializer):
@@ -364,6 +364,7 @@ class PartijIdentificatorGroepTypeSerializer(GegevensGroepSerializer):
364364
class Meta:
365365
model = PartijIdentificator
366366
gegevensgroep = "partij_identificator"
367+
validators = [PartijIdentificatorValidator()]
367368

368369

369370
class PartijIdentificatorSerializer(
@@ -383,6 +384,13 @@ class PartijIdentificatorSerializer(
383384
"of ander extern register uniek identificeren."
384385
),
385386
)
387+
sub_identificator_van = PartijIdentificatorForeignkeySerializer(
388+
required=False,
389+
allow_null=True,
390+
help_text=_(
391+
"Partij-identificatoren TEST CONTROLLA die hoorde bij deze partij."
392+
),
393+
)
386394

387395
class Meta:
388396
model = PartijIdentificator
@@ -392,8 +400,8 @@ class Meta:
392400
"identificeerde_partij",
393401
"andere_partij_identificator",
394402
"partij_identificator",
403+
"sub_identificator_van",
395404
)
396-
397405
extra_kwargs = {
398406
"uuid": {"read_only": True},
399407
"url": {
@@ -402,15 +410,15 @@ class Meta:
402410
"help_text": "De unieke URL van deze partij indentificator binnen deze API.",
403411
},
404412
}
413+
validators = [UniquePartijIdentificatorValidator()]
405414

406415
def validate(self, attrs):
407-
partij_identificator = get_field_value(self, attrs, "partij_identificator")
408-
PartijIdentificatorValidator(
409-
code_register=partij_identificator["code_register"],
410-
code_objecttype=partij_identificator["code_objecttype"],
411-
code_soort_object_id=partij_identificator["code_soort_object_id"],
412-
object_id=partij_identificator["object_id"],
413-
).validate()
416+
if sub_identificator_van := attrs.get("sub_identificator_van", None):
417+
attrs["sub_identificator_van"] = PartijIdentificator.objects.filter(
418+
uuid=sub_identificator_van["uuid"]
419+
)
420+
421+
UniquePartijIdentificatorValidator()(attrs)
414422
return super().validate(attrs)
415423

416424
@transaction.atomic
@@ -425,6 +433,11 @@ def update(self, instance, validated_data):
425433

426434
@transaction.atomic
427435
def create(self, validated_data):
436+
if sub_identificator_van := validated_data.get("sub_identificator_van", None):
437+
validated_data["sub_identificator_van"] = (
438+
PartijIdentificator.objects.filter(uuid=sub_identificator_van["uuid"])
439+
)
440+
428441
partij_uuid = str(validated_data.pop("partij").get("uuid"))
429442
validated_data["partij"] = Partij.objects.get(uuid=partij_uuid)
430443

src/openklant/components/klantinteracties/api/tests/test_partijen.py

+20-7
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66
from vng_api_common.tests import reverse
77

88
from openklant.components.klantinteracties.models.constants import SoortPartij
9-
from openklant.components.klantinteracties.models.partijen import Partij
9+
from openklant.components.klantinteracties.models.partijen import (
10+
Partij,
11+
PartijIdentificator,
12+
)
1013
from openklant.components.klantinteracties.models.tests.factories.digitaal_adres import (
1114
DigitaalAdresFactory,
1215
)
@@ -1848,8 +1851,18 @@ def _get_detail_url(partij: Partij) -> str:
18481851
class PartijIdentificatorTests(APITestCase):
18491852
def test_list_partij_indetificator(self):
18501853
list_url = reverse("klantinteracties:partijidentificator-list")
1851-
PartijIdentificatorFactory.create_batch(2)
1852-
1854+
PartijIdentificator.objects.create(
1855+
partij_identificator_code_objecttype="natuurlijk_persoon",
1856+
partij_identificator_code_soort_object_id="bsn",
1857+
partij_identificator_object_id="296648875",
1858+
partij_identificator_code_register="brp",
1859+
)
1860+
PartijIdentificator.objects.create(
1861+
partij_identificator_code_objecttype="niet_natuurlijk_persoon",
1862+
partij_identificator_code_soort_object_id="rsin",
1863+
partij_identificator_object_id="296648875",
1864+
partij_identificator_code_register="hr",
1865+
)
18531866
response = self.client.get(list_url)
18541867

18551868
self.assertEqual(response.status_code, status.HTTP_200_OK)
@@ -2121,7 +2134,7 @@ def test_invalid_validation_partij_identificator_code_objecttype(self):
21212134
self.assertEqual(response.data["title"], "Invalid input.")
21222135
self.assertEqual(
21232136
response.data["invalid_params"][0]["name"],
2124-
"partijIdentificatorCodeObjecttype",
2137+
"partijIdentificator.nonFieldErrors",
21252138
)
21262139
self.assertEqual(response.data["invalid_params"][0]["code"], "invalid")
21272140
self.assertEqual(
@@ -2149,7 +2162,7 @@ def test_invalid_validation_partij_identificator_code_soort_object_id(self):
21492162
self.assertEqual(response.data["title"], "Invalid input.")
21502163
self.assertEqual(
21512164
response.data["invalid_params"][0]["name"],
2152-
"partijIdentificatorCodeSoortObjectId",
2165+
"partijIdentificator.nonFieldErrors",
21532166
)
21542167
self.assertEqual(response.data["invalid_params"][0]["code"], "invalid")
21552168
self.assertEqual(
@@ -2177,7 +2190,7 @@ def test_invalid_validation_partij_identificator_object_id(self):
21772190
self.assertEqual(response.data["title"], "Invalid input.")
21782191
self.assertEqual(
21792192
response.data["invalid_params"][0]["name"],
2180-
"partijIdentificatorObjectId",
2193+
"partijIdentificator.nonFieldErrors",
21812194
)
21822195
self.assertEqual(response.data["invalid_params"][0]["code"], "invalid")
21832196
self.assertEqual(
@@ -2205,7 +2218,7 @@ def test_invalid_overig_code_objecttype_validation_partij_identificator(self):
22052218
self.assertEqual(response.data["title"], "Invalid input.")
22062219
self.assertEqual(
22072220
response.data["invalid_params"][0]["name"],
2208-
"partijIdentificatorCodeObjecttype",
2221+
"partijIdentificator.nonFieldErrors",
22092222
)
22102223
self.assertEqual(response.data["invalid_params"][0]["code"], "invalid")
22112224
self.assertEqual(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Generated by Django 4.2.17 on 2025-02-17 14:01
2+
3+
from django.db import migrations, models
4+
import django.db.models.deletion
5+
6+
7+
class Migration(migrations.Migration):
8+
9+
dependencies = [
10+
(
11+
"klantinteracties",
12+
"0027_alter_betrokkene_bezoekadres_nummeraanduiding_id_and_more",
13+
),
14+
]
15+
16+
operations = [
17+
migrations.AddField(
18+
model_name="partijidentificator",
19+
name="sub_identificator_van",
20+
field=models.ForeignKey(
21+
blank=True,
22+
help_text="Expresses that one PartijIdentificator is bound to another one",
23+
null=True,
24+
on_delete=django.db.models.deletion.SET_NULL,
25+
related_name="parent_partij_identificator",
26+
to="klantinteracties.partijidentificator",
27+
verbose_name="sub identificator van",
28+
),
29+
),
30+
migrations.AddConstraint(
31+
model_name="partijidentificator",
32+
constraint=models.CheckConstraint(
33+
check=models.Q(
34+
("sub_identificator_van", models.F("id")), _negated=True
35+
),
36+
name="check_sub_identificator_van_not_self",
37+
),
38+
),
39+
migrations.AddConstraint(
40+
model_name="partijidentificator",
41+
constraint=models.UniqueConstraint(
42+
condition=models.Q(("sub_identificator_van__isnull", False)),
43+
fields=(
44+
"sub_identificator_van",
45+
"partij_identificator_code_objecttype",
46+
"partij_identificator_code_soort_object_id",
47+
"partij_identificator_object_id",
48+
"partij_identificator_code_register",
49+
),
50+
name="non_scoped_identificator_globally_unique",
51+
),
52+
),
53+
migrations.AddConstraint(
54+
model_name="partijidentificator",
55+
constraint=models.UniqueConstraint(
56+
condition=models.Q(("sub_identificator_van__isnull", True)),
57+
fields=(
58+
"partij_identificator_code_objecttype",
59+
"partij_identificator_code_soort_object_id",
60+
"partij_identificator_object_id",
61+
"partij_identificator_code_register",
62+
),
63+
name="scoped_identificator_globally_unique",
64+
),
65+
),
66+
]

src/openklant/components/klantinteracties/models/partijen.py

+44-11
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
SoortPartij,
1818
)
1919
from .mixins import BezoekadresMixin, ContactnaamMixin, CorrespondentieadresMixin
20-
from .validators import PartijIdentificatorValidator
20+
from .validators import PartijIdentificatorValidator, UniquePartijIdentificatorValidator
2121

2222

2323
class Partij(APIMixin, BezoekadresMixin, CorrespondentieadresMixin):
@@ -335,6 +335,15 @@ class PartijIdentificator(models.Model):
335335
"Unieke (technische) identificatiecode van de partij-identificator."
336336
),
337337
)
338+
sub_identificator_van = models.ForeignKey(
339+
"self",
340+
on_delete=models.SET_NULL,
341+
verbose_name=_("sub identificator van"),
342+
help_text=_("Expresses that one PartijIdentificator is bound to another one"),
343+
blank=True,
344+
null=True,
345+
related_name="parent_partij_identificator",
346+
)
338347
partij = models.ForeignKey(
339348
Partij,
340349
on_delete=models.CASCADE,
@@ -406,22 +415,46 @@ class PartijIdentificator(models.Model):
406415
class Meta:
407416
verbose_name = _("partij identificator")
408417
verbose_name_plural = _("partij identificatoren")
418+
constraints = [
419+
models.CheckConstraint(
420+
check=~models.Q(sub_identificator_van=models.F("id")),
421+
name="check_sub_identificator_van_not_self",
422+
),
423+
models.UniqueConstraint(
424+
fields=[
425+
"sub_identificator_van",
426+
"partij_identificator_code_objecttype",
427+
"partij_identificator_code_soort_object_id",
428+
"partij_identificator_object_id",
429+
"partij_identificator_code_register",
430+
],
431+
condition=models.Q(sub_identificator_van__isnull=False),
432+
name="scoped_identificator_globally_unique",
433+
),
434+
models.UniqueConstraint(
435+
fields=[
436+
"partij_identificator_code_objecttype",
437+
"partij_identificator_code_soort_object_id",
438+
"partij_identificator_object_id",
439+
"partij_identificator_code_register",
440+
],
441+
name="non_scoped_identificator_globally_unique",
442+
condition=models.Q(sub_identificator_van__isnull=True),
443+
),
444+
]
409445

410446
def __str__(self):
411447
soort_object = self.partij_identificator_code_soort_object_id
412448
object = self.partij_identificator_object_id
413449

414450
return f"{soort_object} - {object}"
415451

416-
def save(self, *args, **kwargs):
417-
self.full_clean()
418-
super().save(*args, **kwargs)
419-
420452
def clean(self):
421453
super().clean()
422-
PartijIdentificatorValidator(
423-
code_register=self.partij_identificator_code_register,
424-
code_objecttype=self.partij_identificator_code_objecttype,
425-
code_soort_object_id=self.partij_identificator_code_soort_object_id,
426-
object_id=self.partij_identificator_object_id,
427-
).validate()
454+
PartijIdentificatorValidator()(self.partij_identificator)
455+
UniquePartijIdentificatorValidator()(
456+
{
457+
"sub_identificator_van": self.sub_identificator_van,
458+
"partij_identificator": self.partij_identificator,
459+
}
460+
)

src/openklant/components/klantinteracties/models/tests/factories/partijen.py

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ class PartijIdentificatorFactory(factory.django.DjangoModelFactory):
8484
uuid = factory.Faker("uuid4")
8585
partij = factory.SubFactory(PartijFactory)
8686
andere_partij_identificator = factory.Faker("word")
87+
sub_identificator_van = None
8788

8889
class Meta:
8990
model = PartijIdentificator

0 commit comments

Comments
 (0)