diff --git a/requirements/base.txt b/requirements/base.txt index 9b55a473..a4ed7b8a 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -57,7 +57,7 @@ click-plugins==1.1.1 # via celery click-repl==0.3.0 # via celery -commonground-api-common==2.1.2 +commonground-api-common==2.4.1 # via open-api-framework coreapi==2.3.3 # via commonground-api-common @@ -100,7 +100,6 @@ django==4.2.17 # drf-nested-routers # drf-spectacular # drf-spectacular-sidecar - # drf-yasg # maykin-2fa # mozilla-django-oidc # mozilla-django-oidc-db @@ -172,7 +171,6 @@ djangorestframework==3.15.2 # djangorestframework-inclusions # drf-nested-routers # drf-spectacular - # drf-yasg # notifications-api-common # open-api-framework djangorestframework-camel-case==1.4.2 @@ -186,11 +184,11 @@ djangorestframework-inclusions==1.2.0 drf-nested-routers==0.94.1 # via commonground-api-common drf-spectacular==0.27.2 - # via open-api-framework + # via + # commonground-api-common + # open-api-framework drf-spectacular-sidecar==2024.7.1 # via drf-spectacular -drf-yasg==1.21.7 - # via commonground-api-common ecs-logging==2.2.0 # via elastic-apm elastic-apm==6.23.0 @@ -208,9 +206,7 @@ humanize==4.10.0 idna==3.7 # via requests inflection==0.5.1 - # via - # drf-spectacular - # drf-yasg + # via drf-spectacular iso-639==0.4.5 # via commonground-api-common isodate==0.6.1 @@ -245,8 +241,6 @@ orderedmultidict==1.0.1 # via furl oyaml==1.0 # via commonground-api-common -packaging==24.1 - # via drf-yasg phonenumberslite==8.13.42 # via django-two-factor-auth prometheus-client==0.20.0 @@ -286,13 +280,10 @@ python-dotenv==1.0.1 # open-api-framework # pydantic-settings pytz==2024.1 - # via - # drf-yasg - # flower + # via flower pyyaml==6.0.1 # via # drf-spectacular - # drf-yasg # oyaml # pydantic-settings qrcode==7.4.2 @@ -345,7 +336,6 @@ uritemplate==4.1.1 # via # coreapi # drf-spectacular - # drf-yasg urllib3==2.2.2 # via # elastic-apm diff --git a/requirements/ci.txt b/requirements/ci.txt index e11bd608..1f533b77 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -117,7 +117,7 @@ click-repl==0.3.0 # celery codecov==2.1.13 # via -r requirements/test-tools.in -commonground-api-common==2.1.2 +commonground-api-common==2.4.1 # via # -c requirements/base.txt # -r requirements/base.txt @@ -181,7 +181,6 @@ django==4.2.17 # drf-nested-routers # drf-spectacular # drf-spectacular-sidecar - # drf-yasg # maykin-2fa # mozilla-django-oidc # mozilla-django-oidc-db @@ -320,7 +319,6 @@ djangorestframework==3.15.2 # djangorestframework-inclusions # drf-nested-routers # drf-spectacular - # drf-yasg # notifications-api-common # open-api-framework djangorestframework-camel-case==1.4.2 @@ -354,17 +352,13 @@ drf-spectacular==0.27.2 # via # -c requirements/base.txt # -r requirements/base.txt + # commonground-api-common # open-api-framework drf-spectacular-sidecar==2024.7.1 # via # -c requirements/base.txt # -r requirements/base.txt # drf-spectacular -drf-yasg==1.21.7 - # via - # -c requirements/base.txt - # -r requirements/base.txt - # commonground-api-common ecs-logging==2.2.0 # via # -c requirements/base.txt @@ -421,7 +415,6 @@ inflection==0.5.1 # -c requirements/base.txt # -r requirements/base.txt # drf-spectacular - # drf-yasg iniconfig==2.0.0 # via pytest iso-639==0.4.5 @@ -522,10 +515,7 @@ oyaml==1.0 # commonground-api-common packaging==24.1 # via - # -c requirements/base.txt - # -r requirements/base.txt # black - # drf-yasg # pytest # sphinx pathspec==0.12.1 @@ -633,14 +623,12 @@ pytz==2024.1 # via # -c requirements/base.txt # -r requirements/base.txt - # drf-yasg # flower pyyaml==6.0.1 # via # -c requirements/base.txt # -r requirements/base.txt # drf-spectacular - # drf-yasg # oyaml # pydantic-settings # vcrpy @@ -768,7 +756,6 @@ uritemplate==4.1.1 # -r requirements/base.txt # coreapi # drf-spectacular - # drf-yasg urllib3==2.2.2 # via # -c requirements/base.txt diff --git a/requirements/dev.txt b/requirements/dev.txt index d4c28599..f9135f69 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -138,7 +138,7 @@ codecov==2.1.13 # via # -c requirements/ci.txt # -r requirements/ci.txt -commonground-api-common==2.1.2 +commonground-api-common==2.4.1 # via # -c requirements/ci.txt # -r requirements/ci.txt @@ -216,7 +216,6 @@ django==4.2.17 # drf-nested-routers # drf-spectacular # drf-spectacular-sidecar - # drf-yasg # maykin-2fa # mozilla-django-oidc # mozilla-django-oidc-db @@ -361,7 +360,6 @@ djangorestframework==3.15.2 # djangorestframework-inclusions # drf-nested-routers # drf-spectacular - # drf-yasg # notifications-api-common # open-api-framework djangorestframework-camel-case==1.4.2 @@ -397,17 +395,13 @@ drf-spectacular==0.27.2 # via # -c requirements/ci.txt # -r requirements/ci.txt + # commonground-api-common # open-api-framework drf-spectacular-sidecar==2024.7.1 # via # -c requirements/ci.txt # -r requirements/ci.txt # drf-spectacular -drf-yasg==1.21.7 - # via - # -c requirements/ci.txt - # -r requirements/ci.txt - # commonground-api-common ecs-logging==2.2.0 # via # -c requirements/ci.txt @@ -480,7 +474,6 @@ inflection==0.5.1 # -c requirements/ci.txt # -r requirements/ci.txt # drf-spectacular - # drf-yasg iniconfig==2.0.0 # via # -c requirements/ci.txt @@ -603,7 +596,6 @@ packaging==24.1 # -r requirements/ci.txt # black # build - # drf-yasg # pytest # sphinx pathspec==0.12.1 @@ -743,14 +735,12 @@ pytz==2024.1 # via # -c requirements/ci.txt # -r requirements/ci.txt - # drf-yasg # flower pyyaml==6.0.1 # via # -c requirements/ci.txt # -r requirements/ci.txt # drf-spectacular - # drf-yasg # oyaml # pydantic-settings # vcrpy @@ -923,7 +913,6 @@ uritemplate==4.1.1 # -r requirements/ci.txt # coreapi # drf-spectacular - # drf-yasg urllib3==2.2.2 # via # -c requirements/ci.txt diff --git a/src/openklant/components/contactgegevens/openapi.yaml b/src/openklant/components/contactgegevens/openapi.yaml index 34a5d744..ade2386b 100644 --- a/src/openklant/components/contactgegevens/openapi.yaml +++ b/src/openklant/components/contactgegevens/openapi.yaml @@ -340,6 +340,8 @@ components: format: uri readOnly: true description: De unieke URL van deze actor binnen deze API. + minLength: 1 + maxLength: 1000 handelsnaam: type: string description: De naam waaronder een bedrijf of vestiging handelt. @@ -375,18 +377,6 @@ components: - uuid OrganisatieAdres: type: object - description: |- - Generate a serializer out of a GegevensGroepType. - - Usage:: - - >>> class VerlengingSerializer(GegevensGroepSerializer): - ... class Meta: - ... model = Zaak - ... gegevensgroep = 'verlenging' - >>> - - Where ``Zaak.verlenging`` is a :class:``GegevensGroepType``. properties: nummeraanduidingId: type: string @@ -477,6 +467,8 @@ components: format: uri readOnly: true description: De unieke URL van deze actor binnen deze API. + minLength: 1 + maxLength: 1000 handelsnaam: type: string description: De naam waaronder een bedrijf of vestiging handelt. @@ -523,6 +515,8 @@ components: format: uri readOnly: true description: De unieke URL van deze organisatie binnen deze API. + minLength: 1 + maxLength: 1000 geboortedatum: type: string format: date @@ -587,6 +581,8 @@ components: format: uri readOnly: true description: De unieke URL van deze organisatie binnen deze API. + minLength: 1 + maxLength: 1000 geboortedatum: type: string format: date @@ -641,18 +637,6 @@ components: - uuid PersoonAdres: type: object - description: |- - Generate a serializer out of a GegevensGroepType. - - Usage:: - - >>> class VerlengingSerializer(GegevensGroepSerializer): - ... class Meta: - ... model = Zaak - ... gegevensgroep = 'verlenging' - >>> - - Where ``Zaak.verlenging`` is a :class:``GegevensGroepType``. properties: nummeraanduidingId: type: string diff --git a/src/openklant/components/klantinteracties/api/serializers/partijen.py b/src/openklant/components/klantinteracties/api/serializers/partijen.py index e8ed89bf..5894696b 100644 --- a/src/openklant/components/klantinteracties/api/serializers/partijen.py +++ b/src/openklant/components/klantinteracties/api/serializers/partijen.py @@ -42,6 +42,10 @@ Vertegenwoordigden, ) from openklant.components.klantinteracties.models.rekeningnummers import Rekeningnummer +from openklant.components.klantinteracties.models.validators import ( + PartijIdentificatorValidator, +) +from openklant.utils.serializers import get_field_value class PartijForeignkeyBaseSerializer(serializers.HyperlinkedModelSerializer): @@ -399,6 +403,16 @@ class Meta: }, } + def validate(self, attrs): + partij_identificator = get_field_value(self, attrs, "partij_identificator") + PartijIdentificatorValidator( + code_register=partij_identificator["code_register"], + code_objecttype=partij_identificator["code_objecttype"], + code_soort_object_id=partij_identificator["code_soort_object_id"], + object_id=partij_identificator["object_id"], + ).validate() + return super().validate(attrs) + @transaction.atomic def update(self, instance, validated_data): if "partij" in validated_data: diff --git a/src/openklant/components/klantinteracties/api/tests/test_filters.py b/src/openklant/components/klantinteracties/api/tests/test_filters.py index 8b597bc2..2a9d3c80 100644 --- a/src/openklant/components/klantinteracties/api/tests/test_filters.py +++ b/src/openklant/components/klantinteracties/api/tests/test_filters.py @@ -694,16 +694,17 @@ def test_filter_vertegenwoordigde_partij_url(self): def test_filter_partij_identificator_code_objecttype(self): partij, partij2 = PartijFactory.create_batch(2) PartijIdentificatorFactory.create( - partij=partij, partij_identificator_code_objecttype="one" + partij=partij, partij_identificator_code_objecttype="natuurlijk_persoon" ) PartijIdentificatorFactory.create( - partij=partij2, partij_identificator_code_objecttype="two" + partij=partij2, + partij_identificator_code_objecttype="niet_natuurlijk_persoon", ) with self.subTest("happy flow"): response = self.client.get( self.url, - {"partijIdentificator__codeObjecttype": "two"}, + {"partijIdentificator__codeObjecttype": "niet_natuurlijk_persoon"}, ) self.assertEqual(response.status_code, status.HTTP_200_OK) @@ -724,16 +725,16 @@ def test_filter_partij_identificator_code_objecttype(self): def test_filter_identificator_soort_object_id(self): partij, partij2 = PartijFactory.create_batch(2) PartijIdentificatorFactory.create( - partij=partij, partij_identificator_code_soort_object_id="one" + partij=partij, partij_identificator_code_soort_object_id="bsn" ) PartijIdentificatorFactory.create( - partij=partij2, partij_identificator_code_soort_object_id="two" + partij=partij2, partij_identificator_code_soort_object_id="kvk_nummer" ) with self.subTest("happy flow"): response = self.client.get( self.url, - {"partijIdentificator__codeSoortObjectId": "one"}, + {"partijIdentificator__codeSoortObjectId": "bsn"}, ) self.assertEqual(response.status_code, status.HTTP_200_OK) @@ -756,16 +757,20 @@ def test_filter_identificator_soort_object_id(self): def test_filter_identificator_object_id(self): partij, partij2 = PartijFactory.create_batch(2) PartijIdentificatorFactory.create( - partij=partij, partij_identificator_object_id="one" + partij=partij, + partij_identificator_code_soort_object_id="bsn", + partij_identificator_object_id="296648875", ) PartijIdentificatorFactory.create( - partij=partij2, partij_identificator_object_id="two" + partij=partij2, + partij_identificator_code_soort_object_id="bsn", + partij_identificator_object_id="111222333", ) with self.subTest("happy flow"): response = self.client.get( self.url, - {"partijIdentificator__objectId": "one"}, + {"partijIdentificator__objectId": "296648875"}, ) self.assertEqual(response.status_code, status.HTTP_200_OK) @@ -786,16 +791,16 @@ def test_filter_identificator_object_id(self): def test_filter_identificator_code_register(self): partij, partij2 = PartijFactory.create_batch(2) PartijIdentificatorFactory.create( - partij=partij, partij_identificator_code_register="one" + partij=partij, partij_identificator_code_register="brp" ) PartijIdentificatorFactory.create( - partij=partij2, partij_identificator_code_register="two" + partij=partij2, partij_identificator_code_register="hr" ) with self.subTest("happy flow"): response = self.client.get( self.url, - {"partijIdentificator__code_register": "two"}, + {"partijIdentificator__code_register": "hr"}, ) self.assertEqual(response.status_code, status.HTTP_200_OK) diff --git a/src/openklant/components/klantinteracties/api/tests/test_partijen.py b/src/openklant/components/klantinteracties/api/tests/test_partijen.py index 03bc9bf3..fa925abd 100644 --- a/src/openklant/components/klantinteracties/api/tests/test_partijen.py +++ b/src/openklant/components/klantinteracties/api/tests/test_partijen.py @@ -1877,10 +1877,10 @@ def test_create_partij_indetificator(self): "identificeerdePartij": {"uuid": str(partij.uuid)}, "anderePartijIdentificator": "anderePartijIdentificator", "partijIdentificator": { - "codeObjecttype": "codeObjecttype", - "codeSoortObjectId": "codeSoortObjectId", - "objectId": "objectId", - "codeRegister": "codeRegister", + "codeObjecttype": "natuurlijk_persoon", + "codeSoortObjectId": "bsn", + "objectId": "296648875", + "codeRegister": "brp", }, } @@ -1893,10 +1893,10 @@ def test_create_partij_indetificator(self): self.assertEqual( data["partijIdentificator"], { - "codeObjecttype": "codeObjecttype", - "codeSoortObjectId": "codeSoortObjectId", - "objectId": "objectId", - "codeRegister": "codeRegister", + "codeObjecttype": "natuurlijk_persoon", + "codeSoortObjectId": "bsn", + "objectId": "296648875", + "codeRegister": "brp", }, ) @@ -1905,10 +1905,10 @@ def test_update_partij_indetificator(self): partij_identificator = PartijIdentificatorFactory.create( partij=partij, andere_partij_identificator="anderePartijIdentificator", - partij_identificator_code_objecttype="codeObjecttype", - partij_identificator_code_soort_object_id="codeSoortObjectId", - partij_identificator_object_id="objectId", - partij_identificator_code_register="codeRegister", + partij_identificator_code_objecttype="natuurlijk_persoon", + partij_identificator_code_soort_object_id="bsn", + partij_identificator_object_id="296648875", + partij_identificator_code_register="brp", ) detail_url = reverse( @@ -1923,10 +1923,10 @@ def test_update_partij_indetificator(self): self.assertEqual( data["partijIdentificator"], { - "codeObjecttype": "codeObjecttype", - "codeSoortObjectId": "codeSoortObjectId", - "objectId": "objectId", - "codeRegister": "codeRegister", + "codeObjecttype": "natuurlijk_persoon", + "codeSoortObjectId": "bsn", + "objectId": "296648875", + "codeRegister": "brp", }, ) @@ -1934,10 +1934,10 @@ def test_update_partij_indetificator(self): "identificeerdePartij": {"uuid": str(partij2.uuid)}, "anderePartijIdentificator": "changed", "partijIdentificator": { - "codeObjecttype": "changed", - "codeSoortObjectId": "changed", - "objectId": "changed", - "codeRegister": "changed", + "codeObjecttype": "natuurlijk_persoon", + "codeSoortObjectId": "bsn", + "objectId": "296648875", + "codeRegister": "brp", }, } @@ -1950,10 +1950,10 @@ def test_update_partij_indetificator(self): self.assertEqual( data["partijIdentificator"], { - "codeObjecttype": "changed", - "codeSoortObjectId": "changed", - "objectId": "changed", - "codeRegister": "changed", + "codeObjecttype": "natuurlijk_persoon", + "codeSoortObjectId": "bsn", + "objectId": "296648875", + "codeRegister": "brp", }, ) @@ -1962,10 +1962,10 @@ def test_partial_update_partij_indetificator(self): partij_identificator = PartijIdentificatorFactory.create( partij=partij, andere_partij_identificator="anderePartijIdentificator", - partij_identificator_code_objecttype="codeObjecttype", - partij_identificator_code_soort_object_id="codeSoortObjectId", - partij_identificator_object_id="objectId", - partij_identificator_code_register="codeRegister", + partij_identificator_code_objecttype="natuurlijk_persoon", + partij_identificator_code_soort_object_id="bsn", + partij_identificator_object_id="296648875", + partij_identificator_code_register="brp", ) detail_url = reverse( @@ -1980,10 +1980,10 @@ def test_partial_update_partij_indetificator(self): self.assertEqual( data["partijIdentificator"], { - "codeObjecttype": "codeObjecttype", - "codeSoortObjectId": "codeSoortObjectId", - "objectId": "objectId", - "codeRegister": "codeRegister", + "codeObjecttype": "natuurlijk_persoon", + "codeSoortObjectId": "bsn", + "objectId": "296648875", + "codeRegister": "brp", }, ) @@ -2000,10 +2000,10 @@ def test_partial_update_partij_indetificator(self): self.assertEqual( data["partijIdentificator"], { - "codeObjecttype": "codeObjecttype", - "codeSoortObjectId": "codeSoortObjectId", - "objectId": "objectId", - "codeRegister": "codeRegister", + "codeObjecttype": "natuurlijk_persoon", + "codeSoortObjectId": "bsn", + "objectId": "296648875", + "codeRegister": "brp", }, ) @@ -2021,6 +2021,262 @@ def test_destroy_partij_identificator(self): data = response.json() self.assertEqual(data["count"], 0) + def test_invalid_choice_partij_identificator_code_register(self): + url = reverse("klantinteracties:partijidentificator-list") + partij = PartijFactory.create() + data = { + "identificeerdePartij": {"uuid": str(partij.uuid)}, + "anderePartijIdentificator": "anderePartijIdentificator", + "partijIdentificator": { + "codeObjecttype": "natuurlijk_persoon", + "codeSoortObjectId": "bsn", + "objectId": "296648875", + "codeRegister": "test", + }, + } + response = self.client.post(url, data) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(response.data["code"], "invalid") + self.assertEqual(response.data["title"], "Invalid input.") + self.assertEqual( + response.data["invalid_params"][0]["name"], + "partijIdentificator.codeRegister", + ) + self.assertEqual(response.data["invalid_params"][0]["code"], "invalid_choice") + self.assertEqual( + response.data["invalid_params"][0]["reason"], + '"test" is een ongeldige keuze.', + ) + + def test_invalid_choice_partij_identificator_code_objecttype(self): + url = reverse("klantinteracties:partijidentificator-list") + partij = PartijFactory.create() + data = { + "identificeerdePartij": {"uuid": str(partij.uuid)}, + "anderePartijIdentificator": "anderePartijIdentificator", + "partijIdentificator": { + "codeObjecttype": "test", + "codeSoortObjectId": "bsn", + "objectId": "296648875", + "codeRegister": "brp", + }, + } + response = self.client.post(url, data) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(response.data["code"], "invalid") + self.assertEqual(response.data["title"], "Invalid input.") + self.assertEqual( + response.data["invalid_params"][0]["name"], + "partijIdentificator.codeObjecttype", + ) + self.assertEqual(response.data["invalid_params"][0]["code"], "invalid_choice") + self.assertEqual( + response.data["invalid_params"][0]["reason"], + '"test" is een ongeldige keuze.', + ) + + def test_invalid_choice_partij_identificator_code_soort_object_id(self): + url = reverse("klantinteracties:partijidentificator-list") + partij = PartijFactory.create() + data = { + "identificeerdePartij": {"uuid": str(partij.uuid)}, + "anderePartijIdentificator": "anderePartijIdentificator", + "partijIdentificator": { + "codeObjecttype": "natuurlijk_persoon", + "codeSoortObjectId": "test", + "objectId": "296648875", + "codeRegister": "brp", + }, + } + response = self.client.post(url, data) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(response.data["code"], "invalid") + self.assertEqual(response.data["title"], "Invalid input.") + self.assertEqual( + response.data["invalid_params"][0]["name"], + "partijIdentificator.codeSoortObjectId", + ) + self.assertEqual(response.data["invalid_params"][0]["code"], "invalid_choice") + self.assertEqual( + response.data["invalid_params"][0]["reason"], + '"test" is een ongeldige keuze.', + ) + + def test_invalid_validation_partij_identificator_code_objecttype(self): + url = reverse("klantinteracties:partijidentificator-list") + partij = PartijFactory.create() + data = { + "identificeerdePartij": {"uuid": str(partij.uuid)}, + "anderePartijIdentificator": "anderePartijIdentificator", + "partijIdentificator": { + "codeObjecttype": "niet_natuurlijk_persoon", + "codeSoortObjectId": "bsn", + "objectId": "296648875", + "codeRegister": "brp", + }, + } + response = self.client.post(url, data) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(response.data["code"], "invalid") + self.assertEqual(response.data["title"], "Invalid input.") + self.assertEqual( + response.data["invalid_params"][0]["name"], + "partijIdentificatorCodeObjecttype", + ) + self.assertEqual(response.data["invalid_params"][0]["code"], "invalid") + self.assertEqual( + response.data["invalid_params"][0]["reason"], + "voor `codeRegister` brp zijn alleen deze waarden toegestaan: ['natuurlijk_persoon']", + ) + + def test_invalid_validation_partij_identificator_code_soort_object_id(self): + url = reverse("klantinteracties:partijidentificator-list") + partij = PartijFactory.create() + data = { + "identificeerdePartij": {"uuid": str(partij.uuid)}, + "anderePartijIdentificator": "anderePartijIdentificator", + "partijIdentificator": { + "codeObjecttype": "natuurlijk_persoon", + "codeSoortObjectId": "kvk_nummer", + "objectId": "296648875", + "codeRegister": "brp", + }, + } + + response = self.client.post(url, data) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(response.data["code"], "invalid") + self.assertEqual(response.data["title"], "Invalid input.") + self.assertEqual( + response.data["invalid_params"][0]["name"], + "partijIdentificatorCodeSoortObjectId", + ) + self.assertEqual(response.data["invalid_params"][0]["code"], "invalid") + self.assertEqual( + response.data["invalid_params"][0]["reason"], + "voor `codeObjecttype` natuurlijk_persoon zijn alleen deze waarden toegestaan: ['bsn', 'overig']", + ) + + def test_invalid_validation_partij_identificator_object_id(self): + url = reverse("klantinteracties:partijidentificator-list") + partij = PartijFactory.create() + data = { + "identificeerdePartij": {"uuid": str(partij.uuid)}, + "anderePartijIdentificator": "anderePartijIdentificator", + "partijIdentificator": { + "codeObjecttype": "natuurlijk_persoon", + "codeSoortObjectId": "bsn", + "objectId": "12", + "codeRegister": "brp", + }, + } + + response = self.client.post(url, data) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(response.data["code"], "invalid") + self.assertEqual(response.data["title"], "Invalid input.") + self.assertEqual( + response.data["invalid_params"][0]["name"], + "partijIdentificatorObjectId", + ) + self.assertEqual(response.data["invalid_params"][0]["code"], "invalid") + self.assertEqual( + response.data["invalid_params"][0]["reason"], + "Deze waarde is ongeldig, reden: Waarde moet 9 tekens lang zijn", + ) + + def test_invalid_overig_code_objecttype_validation_partij_identificator(self): + # Overig no validation + url = reverse("klantinteracties:partijidentificator-list") + partij = PartijFactory.create() + data = { + "identificeerdePartij": {"uuid": str(partij.uuid)}, + "anderePartijIdentificator": "anderePartijIdentificator", + "partijIdentificator": { + "codeObjecttype": "overig", + "codeSoortObjectId": "bsn", + "objectId": "296648875", + "codeRegister": "brp", + }, + } + response = self.client.post(url, data) + self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) + self.assertEqual(response.data["code"], "invalid") + self.assertEqual(response.data["title"], "Invalid input.") + self.assertEqual( + response.data["invalid_params"][0]["name"], + "partijIdentificatorCodeObjecttype", + ) + self.assertEqual(response.data["invalid_params"][0]["code"], "invalid") + self.assertEqual( + response.data["invalid_params"][0]["reason"], + "voor `codeRegister` brp zijn alleen deze waarden toegestaan: ['natuurlijk_persoon']", + ) + + def test_valid_validation_partij_identificator(self): + # All validations pass + url = reverse("klantinteracties:partijidentificator-list") + partij = PartijFactory.create() + data = { + "identificeerdePartij": {"uuid": str(partij.uuid)}, + "anderePartijIdentificator": "anderePartijIdentificator", + "partijIdentificator": { + "codeObjecttype": "natuurlijk_persoon", + "codeSoortObjectId": "bsn", + "objectId": "296648875", + "codeRegister": "brp", + }, + } + response = self.client.post(url, data) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual( + response.data["partij_identificator"]["code_objecttype"], + "natuurlijk_persoon", + ) + self.assertEqual( + response.data["partij_identificator"]["code_soort_object_id"], + "bsn", + ) + self.assertEqual( + response.data["partij_identificator"]["object_id"], "296648875" + ) + self.assertEqual( + response.data["partij_identificator"]["code_register"], + "brp", + ) + + def test_valid_overig_code_register_validation_partij_identificator(self): + # Overig no validation + url = reverse("klantinteracties:partijidentificator-list") + partij = PartijFactory.create() + data = { + "identificeerdePartij": {"uuid": str(partij.uuid)}, + "anderePartijIdentificator": "anderePartijIdentificator", + "partijIdentificator": { + "codeObjecttype": "natuurlijk_persoon", + "codeSoortObjectId": "bsn", + "objectId": "296648875", + "codeRegister": "overig", + }, + } + response = self.client.post(url, data) + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual( + response.data["partij_identificator"]["code_objecttype"], + "natuurlijk_persoon", + ) + self.assertEqual( + response.data["partij_identificator"]["code_soort_object_id"], + "bsn", + ) + self.assertEqual( + response.data["partij_identificator"]["object_id"], "296648875" + ) + self.assertEqual( + response.data["partij_identificator"]["code_register"], + "overig", + ) + class CategorieRelatieTests(APITestCase): def test_list_categorie_relatie(self): diff --git a/src/openklant/components/klantinteracties/migrations/0025_alter_partijidentificator_partij_identificator_code_objecttype_and_more.py b/src/openklant/components/klantinteracties/migrations/0025_alter_partijidentificator_partij_identificator_code_objecttype_and_more.py new file mode 100644 index 00000000..6bfe1e60 --- /dev/null +++ b/src/openklant/components/klantinteracties/migrations/0025_alter_partijidentificator_partij_identificator_code_objecttype_and_more.py @@ -0,0 +1,57 @@ +# Generated by Django 4.2.15 on 2025-01-15 15:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("klantinteracties", "0024_alter_digitaaladres_is_standaard_adres"), + ] + + operations = [ + migrations.AlterField( + model_name="partijidentificator", + name="partij_identificator_code_objecttype", + field=models.CharField( + blank=True, + choices=[ + ("natuurlijk_persoon", "NatuurlijkPersoon"), + ("niet_natuurlijk_persoon", "NietNatuurlijkPersoon"), + ("vestiging", "Vestiging"), + ("overig", "Overig"), + ], + help_text="Type van het object, bijvoorbeeld: 'natuurlijk_persoon'.", + max_length=200, + verbose_name="objecttype", + ), + ), + migrations.AlterField( + model_name="partijidentificator", + name="partij_identificator_code_register", + field=models.CharField( + blank=True, + choices=[("brp", "BRP"), ("hr", "HR"), ("overig", "Overig")], + help_text="Binnen het landschap van registers unieke omschrijving van het register waarin het object is geregistreerd, bijvoorbeeld: 'BRP'.", + max_length=200, + verbose_name="register", + ), + ), + migrations.AlterField( + model_name="partijidentificator", + name="partij_identificator_code_soort_object_id", + field=models.CharField( + blank=True, + choices=[ + ("bsn", "Bsn"), + ("vestigingsnummer", "Vestigingsnummer"), + ("kvk_nummer", "KvkNummer"), + ("rsin", "Rsin"), + ("overig", "Overig"), + ], + help_text="Naam van de eigenschap die het object identificeert, bijvoorbeeld: 'bsn'.", + max_length=200, + verbose_name="soort object ID", + ), + ), + ] diff --git a/src/openklant/components/klantinteracties/models/constants.py b/src/openklant/components/klantinteracties/models/constants.py index 19172c59..74751e56 100644 --- a/src/openklant/components/klantinteracties/models/constants.py +++ b/src/openklant/components/klantinteracties/models/constants.py @@ -45,3 +45,24 @@ class SoortPartij(TextChoices): class Klantcontrol(TextChoices): vertegenwoordiger = "vertegenwoordiger", _("Vertegenwoordiger") klant = "klant", _("Klant") + + +class PartijIdentificatorCodeSoortObjectId(TextChoices): + bsn = "bsn", _("Bsn") + vestigingsnummer = "vestigingsnummer", _("Vestigingsnummer") + kvk_nummer = "kvk_nummer", _("KvkNummer") + rsin = "rsin", _("Rsin") + overig = "overig", _("Overig") + + +class PartijIdentificatorCodeObjectType(TextChoices): + natuurlijk_persoon = "natuurlijk_persoon", _("NatuurlijkPersoon") + niet_natuurlijk_persoon = "niet_natuurlijk_persoon", _("NietNatuurlijkPersoon") + vestiging = "vestiging", _("Vestiging") + overig = "overig", _("Overig") + + +class PartijIdentificatorCodeRegister(TextChoices): + brp = "brp", _("BRP") + hr = "hr", _("HR") + overig = "overig", _("Overig") diff --git a/src/openklant/components/klantinteracties/models/partijen.py b/src/openklant/components/klantinteracties/models/partijen.py index 790bd632..1ab6cd90 100644 --- a/src/openklant/components/klantinteracties/models/partijen.py +++ b/src/openklant/components/klantinteracties/models/partijen.py @@ -10,8 +10,14 @@ from openklant.components.utils.mixins import APIMixin from openklant.components.utils.number_generator import number_generator -from .constants import SoortPartij +from .constants import ( + PartijIdentificatorCodeObjectType, + PartijIdentificatorCodeRegister, + PartijIdentificatorCodeSoortObjectId, + SoortPartij, +) from .mixins import BezoekadresMixin, ContactnaamMixin, CorrespondentieadresMixin +from .validators import PartijIdentificatorValidator class Partij(APIMixin, BezoekadresMixin, CorrespondentieadresMixin): @@ -349,17 +355,17 @@ class PartijIdentificator(models.Model): # Partij-identificator fields partij_identificator_code_objecttype = models.CharField( _("objecttype"), - help_text=_( - "Type van het object, bijvoorbeeld: 'INGESCHREVEN NATUURLIJK PERSOON'." - ), + help_text=_("Type van het object, bijvoorbeeld: 'natuurlijk_persoon'."), + choices=PartijIdentificatorCodeObjectType.choices, max_length=200, blank=True, ) partij_identificator_code_soort_object_id = models.CharField( _("soort object ID"), help_text=_( - "Naam van de eigenschap die het object identificeert, bijvoorbeeld: 'Burgerservicenummer'." + "Naam van de eigenschap die het object identificeert, bijvoorbeeld: 'bsn'." ), + choices=PartijIdentificatorCodeSoortObjectId.choices, max_length=200, blank=True, ) @@ -378,6 +384,7 @@ class PartijIdentificator(models.Model): "het object is geregistreerd, bijvoorbeeld: 'BRP'." ), max_length=200, + choices=PartijIdentificatorCodeRegister.choices, blank=True, ) @@ -405,3 +412,16 @@ def __str__(self): object = self.partij_identificator_object_id return f"{soort_object} - {object}" + + def save(self, *args, **kwargs): + self.full_clean() + super().save(*args, **kwargs) + + def clean(self): + super().clean() + PartijIdentificatorValidator( + code_register=self.partij_identificator_code_register, + code_objecttype=self.partij_identificator_code_objecttype, + code_soort_object_id=self.partij_identificator_code_soort_object_id, + object_id=self.partij_identificator_object_id, + ).validate() diff --git a/src/openklant/components/klantinteracties/models/validators.py b/src/openklant/components/klantinteracties/models/validators.py new file mode 100644 index 00000000..353d027c --- /dev/null +++ b/src/openklant/components/klantinteracties/models/validators.py @@ -0,0 +1,151 @@ +from django.core.exceptions import ValidationError +from django.utils.translation import gettext_lazy as _ + +from vng_api_common.validators import ( + BaseIdentifierValidator, + validate_bsn, + validate_rsin, +) + +from .constants import ( + PartijIdentificatorCodeObjectType, + PartijIdentificatorCodeRegister, + PartijIdentificatorCodeSoortObjectId, +) + +VESTIGINGSNUMMER_LENGTH = 12 +KVK_NUMMER_LENGTH = 8 + + +class PartijIdentificatorValidator: + + NATUURLIJK_PERSOON = [ + PartijIdentificatorCodeSoortObjectId.bsn.value, + PartijIdentificatorCodeSoortObjectId.overig.value, + ] + VESTIGING = [ + PartijIdentificatorCodeSoortObjectId.vestigingsnummer.value, + PartijIdentificatorCodeSoortObjectId.overig.value, + ] + NIET_NATUURLIJK_PERSOON = [ + PartijIdentificatorCodeSoortObjectId.rsin.value, + PartijIdentificatorCodeSoortObjectId.kvk_nummer.value, + PartijIdentificatorCodeSoortObjectId.overig.value, + ] + + ALLOWED_OBJECT_TYPES_FOR_CODE_OBJECTTYPE = { + PartijIdentificatorCodeObjectType.natuurlijk_persoon.value: NATUURLIJK_PERSOON, + PartijIdentificatorCodeObjectType.vestiging.value: VESTIGING, + PartijIdentificatorCodeObjectType.niet_natuurlijk_persoon.value: NIET_NATUURLIJK_PERSOON, + } + + ALLOWED_OBJECT_TYPES_FOR_REGISTRIES = { + PartijIdentificatorCodeRegister.brp: [ + PartijIdentificatorCodeObjectType.natuurlijk_persoon.value, + ], + PartijIdentificatorCodeRegister.hr: [ + PartijIdentificatorCodeObjectType.vestiging.value, + PartijIdentificatorCodeObjectType.niet_natuurlijk_persoon.value, + ], + } + + def __init__( + self, + code_register: str, + code_objecttype: str, + code_soort_object_id: str, + object_id: str, + ) -> None: + """Initialize validator""" + self.code_register = code_register + self.code_objecttype = code_objecttype + self.code_soort_object_id = code_soort_object_id + self.object_id = object_id + + def validate(self) -> None: + """Run all validations""" + self.validate_code_objecttype() + self.validate_code_soort_object_id() + self.validate_object_id() + + def validate_code_objecttype(self) -> None: + """Validates the codeObjecttype based on the provided codeRegister""" + if not self.code_objecttype: + return + + # pass if top level is null or 'overig' + if ( + not self.code_register + or self.code_register == PartijIdentificatorCodeRegister.overig + ): + return + if self.code_objecttype not in ( + choices := self.ALLOWED_OBJECT_TYPES_FOR_REGISTRIES[self.code_register] + ): + raise ValidationError( + { + "partij_identificator_code_objecttype": _( + "voor `codeRegister` {code_register} zijn alleen deze waarden toegestaan: {choices}" + ).format(code_register=self.code_register, choices=choices) + } + ) + + def validate_code_soort_object_id(self) -> None: + """Validates the codeSoortObjectId based on register and codeObjecttype""" + if not self.code_soort_object_id: + return + + # pass if top level is null or 'overig' + if ( + not self.code_objecttype + or self.code_objecttype == PartijIdentificatorCodeObjectType.overig + ): + return + + if self.code_soort_object_id not in ( + choices := self.ALLOWED_OBJECT_TYPES_FOR_CODE_OBJECTTYPE.get( + self.code_objecttype, [] + ) + ): + + raise ValidationError( + { + "partij_identificator_code_soort_object_id": _( + "voor `codeObjecttype` {code_objecttype} zijn alleen deze waarden toegestaan: {choices}" + ).format(code_objecttype=self.code_objecttype, choices=choices) + } + ) + + def validate_object_id(self) -> None: + """Validates the object_id based on the codeSoortObjectId""" + if not self.object_id: + return + + try: + match self.code_soort_object_id: + case PartijIdentificatorCodeSoortObjectId.bsn: + validate_bsn(self.object_id) + case PartijIdentificatorCodeSoortObjectId.vestigingsnummer: + validator = BaseIdentifierValidator( + self.object_id, + identifier_length=VESTIGINGSNUMMER_LENGTH, + ) + validator.validate() + case PartijIdentificatorCodeSoortObjectId.rsin: + validate_rsin(self.object_id) + case PartijIdentificatorCodeSoortObjectId.kvk_nummer: + validator = BaseIdentifierValidator( + self.object_id, + identifier_length=KVK_NUMMER_LENGTH, + ) + validator.validate() + case PartijIdentificatorCodeSoortObjectId.overig: + return + except ValidationError as error: + raise ValidationError( + { + "partij_identificator_object_id": _( + "Deze waarde is ongeldig, reden: %s" % (error.message) + ) + } + ) diff --git a/src/openklant/components/klantinteracties/openapi.yaml b/src/openklant/components/klantinteracties/openapi.yaml index 5e7512d8..415c1319 100644 --- a/src/openklant/components/klantinteracties/openapi.yaml +++ b/src/openklant/components/klantinteracties/openapi.yaml @@ -88,7 +88,6 @@ paths: application/json: schema: $ref: '#/components/schemas/Actor' - required: true security: - tokenAuth: [] responses: @@ -141,7 +140,6 @@ paths: application/json: schema: $ref: '#/components/schemas/Actor' - required: true security: - tokenAuth: [] responses: @@ -2077,14 +2075,41 @@ paths: name: partijIdentificatorCodeObjecttype schema: type: string + title: Objecttype + enum: + - natuurlijk_persoon + - niet_natuurlijk_persoon + - overig + - vestiging + description: |+ + Type van het object, bijvoorbeeld: 'natuurlijk_persoon'. + - in: query name: partijIdentificatorCodeRegister schema: type: string + title: Register + enum: + - brp + - hr + - overig + description: |+ + Binnen het landschap van registers unieke omschrijving van het register waarin het object is geregistreerd, bijvoorbeeld: 'BRP'. + - in: query name: partijIdentificatorCodeSoortObjectId schema: type: string + title: Soort object ID + enum: + - bsn + - kvk_nummer + - overig + - rsin + - vestigingsnummer + description: |+ + Naam van de eigenschap die het object identificeert, bijvoorbeeld: 'bsn'. + - in: query name: partijIdentificatorObjectId schema: @@ -2381,7 +2406,6 @@ paths: application/json: schema: $ref: '#/components/schemas/Partij' - required: true security: - tokenAuth: [] responses: @@ -2450,7 +2474,6 @@ paths: application/json: schema: $ref: '#/components/schemas/Partij' - required: true security: - tokenAuth: [] responses: @@ -2847,45 +2870,16 @@ paths: components: schemas: Actor: - type: object - description: |- - Set gegevensgroepdata from validated nested data. - - Usage: include the mixin on the ModelSerializer that has gegevensgroepen. - properties: - uuid: - type: string - format: uuid - readOnly: true - description: Unieke (technische) identificatiecode van de actor. - url: - type: string - format: uri - readOnly: true - description: De unieke URL van deze actor binnen deze API. - naam: - type: string - description: Naam van de actor. - maxLength: 200 - soortActor: - allOf: - - $ref: '#/components/schemas/SoortActorEnum' - description: Geeft aan van welke specifieke soort actor sprake is. - indicatieActief: - type: boolean - description: Geeft aan of aan de actor nog betrokken mag worden bij nieuwe - klantcontacten. Voor niet-actieve is dit niet toegestaan. - actoridentificator: - allOf: - - $ref: '#/components/schemas/Actoridentificator' - nullable: true - description: Gegevens die een actorwerpobject in een extern register uniek - identificeren. - required: - - naam - - soortActor - - url - - uuid + oneOf: + - $ref: '#/components/schemas/medewerker_ActorSerializer' + - $ref: '#/components/schemas/geautomatiseerde_actor_ActorSerializer' + - $ref: '#/components/schemas/organisatorische_eenheid_ActorSerializer' + discriminator: + propertyName: soortActor + mapping: + medewerker: '#/components/schemas/medewerker_ActorSerializer' + geautomatiseerde_actor: '#/components/schemas/geautomatiseerde_actor_ActorSerializer' + organisatorische_eenheid: '#/components/schemas/organisatorische_eenheid_ActorSerializer' ActorForeignKey: type: object properties: @@ -2898,6 +2892,8 @@ components: format: uri readOnly: true description: De unieke URL van deze actor binnen deze API. + minLength: 1 + maxLength: 1000 required: - url - uuid @@ -2914,6 +2910,8 @@ components: format: uri readOnly: true description: De unieke URL van deze actor klantcontact binnen deze API. + minLength: 1 + maxLength: 1000 actor: allOf: - $ref: '#/components/schemas/ActorForeignKey' @@ -2929,18 +2927,6 @@ components: - uuid Actoridentificator: type: object - description: |- - Generate a serializer out of a GegevensGroepType. - - Usage:: - - >>> class VerlengingSerializer(GegevensGroepSerializer): - ... class Meta: - ... model = Zaak - ... gegevensgroep = 'verlenging' - >>> - - Where ``Zaak.verlenging`` is a :class:``GegevensGroepType``. properties: objectId: type: string @@ -2962,6 +2948,173 @@ components: description: 'Naam van de eigenschap die het object identificeert, bijvoorbeeld: ''Burgerservicenummer''.' maxLength: 200 + Base_ActorSerializer: + type: object + description: |- + Set gegevensgroepdata from validated nested data. + + Usage: include the mixin on the ModelSerializer that has gegevensgroepen. + properties: + uuid: + type: string + format: uuid + readOnly: true + description: Unieke (technische) identificatiecode van de actor. + url: + type: string + format: uri + readOnly: true + description: De unieke URL van deze actor binnen deze API. + minLength: 1 + maxLength: 1000 + naam: + type: string + description: Naam van de actor. + maxLength: 200 + soortActor: + allOf: + - $ref: '#/components/schemas/SoortActorEnum' + description: Geeft aan van welke specifieke soort actor sprake is. + indicatieActief: + type: boolean + description: Geeft aan of aan de actor nog betrokken mag worden bij nieuwe + klantcontacten. Voor niet-actieve is dit niet toegestaan. + actoridentificator: + allOf: + - $ref: '#/components/schemas/Actoridentificator' + nullable: true + description: Gegevens die een actorwerpobject in een extern register uniek + identificeren. + required: + - naam + - soortActor + - url + - uuid + Base_PartijSerializer: + type: object + description: |- + Set gegevensgroepdata from validated nested data. + + Usage: include the mixin on the ModelSerializer that has gegevensgroepen. + properties: + uuid: + type: string + format: uuid + readOnly: true + description: Unieke (technische) identificatiecode van de partij. + url: + type: string + format: uri + readOnly: true + description: De unieke URL van deze partij binnen deze API. + minLength: 1 + maxLength: 1000 + nummer: + type: string + description: Uniek identificerend nummer dat tijdens communicatie tussen + mensen kan worden gebruikt om de specifieke partij aan te duiden. + maxLength: 10 + interneNotitie: + type: string + description: Mededelingen, aantekeningen of bijzonderheden over de partij, + bedoeld voor intern gebruik. + maxLength: 1000 + betrokkenen: + type: array + items: + $ref: '#/components/schemas/BetrokkeneForeignKey' + readOnly: true + description: Betrokkene bij klantcontact die een partij was. + categorieRelaties: + type: array + items: + $ref: '#/components/schemas/CategorieRelatieForeignKey' + readOnly: true + description: 'De Categorie relaties van een partij: Let op: Dit attribuut + is EXPERIMENTEEL.' + digitaleAdressen: + type: array + items: + $ref: '#/components/schemas/DigitaalAdresForeignKey' + nullable: true + description: Digitaal adresen dat een partij verstrekte voor gebruik bij + toekomstig contact met de gemeente. + voorkeursDigitaalAdres: + allOf: + - $ref: '#/components/schemas/DigitaalAdresForeignKey' + nullable: true + description: Digitaal adres waarop een partij bij voorkeur door de gemeente + benaderd wordt. + vertegenwoordigden: + type: array + items: + $ref: '#/components/schemas/PartijForeignKey' + readOnly: true + description: Partijen die een andere partijen vertegenwoordigden. + rekeningnummers: + type: array + items: + $ref: '#/components/schemas/RekeningnummerForeignKey' + nullable: true + description: Rekeningnummers van een partij + voorkeursRekeningnummer: + allOf: + - $ref: '#/components/schemas/RekeningnummerForeignKey' + nullable: true + description: Rekeningsnummer die een partij bij voorkeur gebruikt. + partijIdentificatoren: + type: array + items: + $ref: '#/components/schemas/PartijIdentificatorForeignkey' + readOnly: true + description: Partij-identificatoren die hoorde bij deze partij. + soortPartij: + allOf: + - $ref: '#/components/schemas/SoortPartijEnum' + description: Geeft aan van welke specifieke soort partij sprake is. + indicatieGeheimhouding: + type: boolean + nullable: true + description: Geeft aan of de verstrekker van partijgegevens heeft aangegeven + dat deze gegevens als geheim beschouwd moeten worden. Als dit niet aangegeven + is dan wordt dit ingevuld als `null`. + voorkeurstaal: + type: string + description: 'Taal, in ISO 639-2/B formaat, waarin de partij bij voorkeur + contact heeft met de gemeente. Voorbeeld: nld. Zie: https://www.iso.org/standard/4767.html' + maxLength: 3 + indicatieActief: + type: boolean + description: 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. + bezoekadres: + allOf: + - $ref: '#/components/schemas/PartijBezoekadres' + nullable: true + description: Adres waarop de partij door gemeente bezocht wil worden. Dit + mag afwijken van voor de verstrekker eventueel in een basisregistratie + bekende adressen. + correspondentieadres: + allOf: + - $ref: '#/components/schemas/PartijCorrespondentieadres' + nullable: true + description: Adres waarop de partij post van de gemeente wil ontvangen. + Dit mag afwijken van voor de verstrekker eventueel in een basisregistratie + bekende adressen. + required: + - betrokkenen + - categorieRelaties + - digitaleAdressen + - indicatieActief + - partijIdentificatoren + - rekeningnummers + - soortPartij + - url + - uuid + - vertegenwoordigden + - voorkeursDigitaalAdres + - voorkeursRekeningnummer Betrokkene: type: object description: |- @@ -2980,6 +3133,8 @@ components: format: uri readOnly: true description: De unieke URL van deze betrokkene binnen deze API. + minLength: 1 + maxLength: 1000 wasPartij: allOf: - $ref: '#/components/schemas/PartijForeignKey' @@ -3044,18 +3199,6 @@ components: - wasPartij BetrokkeneCorrespondentieadres: type: object - description: |- - Generate a serializer out of a GegevensGroepType. - - Usage:: - - >>> class VerlengingSerializer(GegevensGroepSerializer): - ... class Meta: - ... model = Zaak - ... gegevensgroep = 'verlenging' - >>> - - Where ``Zaak.verlenging`` is a :class:``GegevensGroepType``. properties: nummeraanduidingId: type: string @@ -3096,6 +3239,8 @@ components: format: uri readOnly: true description: De unieke URL van deze betrokkene binnen deze API. + minLength: 1 + maxLength: 1000 required: - url - uuid @@ -3117,6 +3262,8 @@ components: format: uri readOnly: true description: De unieke URL van deze betrokkene binnen deze API. + minLength: 1 + maxLength: 1000 wasPartij: allOf: - $ref: '#/components/schemas/PartijForeignKey' @@ -3182,18 +3329,6 @@ components: - wasPartij Bezoekadres: type: object - description: |- - Generate a serializer out of a GegevensGroepType. - - Usage:: - - >>> class VerlengingSerializer(GegevensGroepSerializer): - ... class Meta: - ... model = Zaak - ... gegevensgroep = 'verlenging' - >>> - - Where ``Zaak.verlenging`` is a :class:``GegevensGroepType``. properties: nummeraanduidingId: type: string @@ -3238,6 +3373,8 @@ components: format: uri readOnly: true description: De unieke URL van dit klantcontact binnen deze API. + minLength: 1 + maxLength: 1000 wasBijlageVanKlantcontact: allOf: - $ref: '#/components/schemas/KlantcontactForeignKey' @@ -3265,23 +3402,13 @@ components: format: uri readOnly: true description: De unieke URL van deze bijlage binnen deze API. + minLength: 1 + maxLength: 1000 required: - url - uuid BijlageIdentificator: type: object - description: |- - Generate a serializer out of a GegevensGroepType. - - Usage:: - - >>> class VerlengingSerializer(GegevensGroepSerializer): - ... class Meta: - ... model = Zaak - ... gegevensgroep = 'verlenging' - >>> - - Where ``Zaak.verlenging`` is a :class:``GegevensGroepType``. properties: objectId: type: string @@ -3303,6 +3430,9 @@ components: description: 'Naam van de eigenschap die het object identificeert, bijvoorbeeld: ''Burgerservicenummer''.' maxLength: 200 + BlankEnum: + enum: + - '' Categorie: type: object description: 'Let op: Dit endpoint is EXPERIMENTEEL.' @@ -3317,6 +3447,8 @@ components: format: uri readOnly: true description: De unieke URL van deze categorie binnen deze API. + minLength: 1 + maxLength: 1000 naam: type: string description: Naam van de categorie. @@ -3337,6 +3469,8 @@ components: format: uri readOnly: true description: De unieke URL van deze categorie binnen deze API. + minLength: 1 + maxLength: 1000 naam: type: string readOnly: true @@ -3359,6 +3493,8 @@ components: format: uri readOnly: true description: De unieke URL van deze categorie binnen deze API. + minLength: 1 + maxLength: 1000 partij: allOf: - $ref: '#/components/schemas/PartijForeignkeyBase' @@ -3403,6 +3539,8 @@ components: format: uri readOnly: true description: De unieke URL van deze categorie binnen deze API. + minLength: 1 + maxLength: 1000 categorieNaam: type: string nullable: true @@ -3426,20 +3564,83 @@ components: - categorieNaam - url - uuid + CodeObjecttypeEnum: + enum: + - natuurlijk_persoon + - niet_natuurlijk_persoon + - vestiging + - overig + type: string + CodeRegisterEnum: + enum: + - brp + - hr + - overig + type: string + CodeSoortObjectIdEnum: + enum: + - bsn + - vestigingsnummer + - kvk_nummer + - rsin + - overig + type: string Contactnaam: type: object - description: |- - Generate a serializer out of a GegevensGroepType. - - Usage:: - - >>> class VerlengingSerializer(GegevensGroepSerializer): - ... class Meta: - ... model = Zaak - ... gegevensgroep = 'verlenging' - >>> + properties: + voorletters: + type: string + description: Een afkorting van de voornamen. Meestal de beginletter, maar + in sommige gevallen de beginletter gecombineerd met de tweede letter van + een voornaam. + maxLength: 10 + voornaam: + type: string + description: De voornaam die de persoon wil gebruiken tijdens communicatie + met de gemeente. + maxLength: 200 + voorvoegselAchternaam: + type: string + description: Een eventueel voorvoegsel dat hoort bij de achternaam die de + persoon wil gebruiken tijdens communicatie met de gemeente. + maxLength: 10 + achternaam: + type: string + description: Een achternaam die de persoon wil gebruiken tijdens communicatie + met de gemeente. + maxLength: 200 + Contactpersoon: + type: object + description: |- + Set gegevensgroepdata from validated nested data. - Where ``Zaak.verlenging`` is a :class:``GegevensGroepType``. + Usage: include the mixin on the ModelSerializer that has gegevensgroepen. + properties: + uuid: + type: string + format: uuid + description: Unieke (technische) identificatiecode van de contactpersoon. + werkteVoorPartij: + allOf: + - $ref: '#/components/schemas/PartijPolymorphic' + nullable: true + description: Organisatie waarvoor een contactpersoon werkte. + contactnaam: + allOf: + - $ref: '#/components/schemas/ContactpersoonPersoon' + nullable: true + description: Naam die een contactpersoon wil gebruiken tijdens contact met + de gemeente. Deze mag afwijken van de eventueel in de Basisregistratie + Personen (BRP) bekende naam van de contactpersoon. + volledigeNaam: + type: string + readOnly: true + description: De voledige naam van het constact persoon. + required: + - volledigeNaam + - werkteVoorPartij + ContactpersoonPersoon: + type: object properties: voorletters: type: string @@ -3475,6 +3676,8 @@ components: format: uri readOnly: true description: De unieke URL van dit digitaal adres binnen deze API. + minLength: 1 + maxLength: 1000 verstrektDoorBetrokkene: allOf: - $ref: '#/components/schemas/BetrokkeneForeignKey' @@ -3527,6 +3730,8 @@ components: format: uri readOnly: true description: De unieke URL van dit digitaal adres binnen deze API. + minLength: 1 + maxLength: 1000 required: - url - uuid @@ -3612,6 +3817,20 @@ components: readOnly: true description: 'De Categorie relaties van een partij: Let op: Dit attribuut is EXPERIMENTEEL.' + GeautomatiseerdeActor: + type: object + properties: + functie: + type: string + description: Functie van de geautomatiseerde actor of beschrijving van de + werkzaamheden die deze uitvoert. + maxLength: 40 + omschrijving: + type: string + description: Omschrijving van de geautomatiseerde actor. + maxLength: 200 + required: + - functie InterneTaak: type: object properties: @@ -3625,6 +3844,8 @@ components: format: uri readOnly: true description: De unieke URL van deze interne taak binnen deze API. + minLength: 1 + maxLength: 1000 nummer: type: string description: Uniek identificerend nummer dat tijdens communicatie tussen @@ -3690,6 +3911,8 @@ components: format: uri readOnly: true description: De unieke URL van deze interne taak binnen deze API. + minLength: 1 + maxLength: 1000 required: - url - uuid @@ -3707,6 +3930,8 @@ components: format: uri readOnly: true description: De unieke URL van dit klantcontact binnen deze API. + minLength: 1 + maxLength: 1000 gingOverOnderwerpobjecten: type: array items: @@ -3802,6 +4027,8 @@ components: format: uri readOnly: true description: De unieke URL van dit klantcontact binnen deze API. + minLength: 1 + maxLength: 1000 required: - url - uuid @@ -3816,6 +4043,30 @@ components: $ref: '#/components/schemas/OnderwerpobjectKlantcontactReadOnly' required: - klantcontact + Medewerker: + type: object + properties: + functie: + type: string + description: Functie van de geautomatiseerde actor of beschrijving van de + werkzaamheden die deze uitvoert. + maxLength: 40 + emailadres: + type: string + format: email + title: E-mailadres + description: Elektronisch postadres waaronder de MEDEWERKER in de regel + bereikbaar is. + maxLength: 254 + telefoonnummer: + type: string + description: Telefoonnummer waaronder de MEDEWERKER in de regel bereikbaar + is. + pattern: (0[8-9]00[0-9]{4,7})|(0[1-9][0-9]{8})|(\+[0-9]{9,20}|1400|140[0-9]{2,3}) + maxLength: 20 + required: + - functie + - telefoonnummer Onderwerpobject: type: object description: |- @@ -3833,6 +4084,8 @@ components: format: uri readOnly: true description: De unieke URL van dit klantcontact binnen deze API. + minLength: 1 + maxLength: 1000 klantcontact: allOf: - $ref: '#/components/schemas/KlantcontactForeignKey' @@ -3866,6 +4119,8 @@ components: format: uri readOnly: true description: De unieke URL van dit onderwerp object binnen deze API. + minLength: 1 + maxLength: 1000 required: - url - uuid @@ -3886,6 +4141,8 @@ components: format: uri readOnly: true description: De unieke URL van dit klantcontact binnen deze API. + minLength: 1 + maxLength: 1000 klantcontact: allOf: - $ref: '#/components/schemas/KlantcontactForeignKey' @@ -3910,18 +4167,6 @@ components: - wasKlantcontact Onderwerpobjectidentificator: type: object - description: |- - Generate a serializer out of a GegevensGroepType. - - Usage:: - - >>> class VerlengingSerializer(GegevensGroepSerializer): - ... class Meta: - ... model = Zaak - ... gegevensgroep = 'verlenging' - >>> - - Where ``Zaak.verlenging`` is a :class:``GegevensGroepType``. properties: objectId: type: string @@ -3943,6 +4188,38 @@ components: description: 'Naam van de eigenschap die het object identificeert, bijvoorbeeld: ''Burgerservicenummer''.' maxLength: 200 + Organisatie: + type: object + properties: + naam: + type: string + description: Naam van de organisatie. + maxLength: 200 + OrganisatorischeEenheid: + type: object + properties: + omschrijving: + type: string + description: Omschrijving van de geautomatiseerde actor. + maxLength: 200 + emailadres: + type: string + format: email + title: E-mailadres + description: Elektronisch postadres waaronder de MEDEWERKER in de regel + bereikbaar is. + maxLength: 254 + faxnummer: + type: string + description: Faxnummer waaronder de organisatorische eenheid in de regel + bereikbaar is. + maxLength: 20 + telefoonnummer: + type: string + description: Telefoonnummer waaronder de MEDEWERKER in de regel bereikbaar + is. + pattern: (0[8-9]00[0-9]{4,7})|(0[1-9][0-9]{8})|(\+[0-9]{9,20}|1400|140[0-9]{2,3}) + maxLength: 20 PaginatedActorKlantcontactList: type: object required: @@ -4335,142 +4612,18 @@ components: items: $ref: '#/components/schemas/Vertegenwoordigden' Partij: - type: object - description: |- - Set gegevensgroepdata from validated nested data. - - Usage: include the mixin on the ModelSerializer that has gegevensgroepen. - properties: - uuid: - type: string - format: uuid - readOnly: true - description: Unieke (technische) identificatiecode van de partij. - url: - type: string - format: uri - readOnly: true - description: De unieke URL van deze partij binnen deze API. - nummer: - type: string - description: Uniek identificerend nummer dat tijdens communicatie tussen - mensen kan worden gebruikt om de specifieke partij aan te duiden. - maxLength: 10 - interneNotitie: - type: string - description: Mededelingen, aantekeningen of bijzonderheden over de partij, - bedoeld voor intern gebruik. - maxLength: 1000 - betrokkenen: - type: array - items: - $ref: '#/components/schemas/BetrokkeneForeignKey' - readOnly: true - description: Betrokkene bij klantcontact die een partij was. - categorieRelaties: - type: array - items: - $ref: '#/components/schemas/CategorieRelatieForeignKey' - readOnly: true - description: 'De Categorie relaties van een partij: Let op: Dit attribuut - is EXPERIMENTEEL.' - digitaleAdressen: - type: array - items: - $ref: '#/components/schemas/DigitaalAdresForeignKey' - nullable: true - description: Digitaal adresen dat een partij verstrekte voor gebruik bij - toekomstig contact met de gemeente. - voorkeursDigitaalAdres: - allOf: - - $ref: '#/components/schemas/DigitaalAdresForeignKey' - nullable: true - description: Digitaal adres waarop een partij bij voorkeur door de gemeente - benaderd wordt. - vertegenwoordigden: - type: array - items: - $ref: '#/components/schemas/PartijForeignKey' - readOnly: true - description: Partijen die een andere partijen vertegenwoordigden. - rekeningnummers: - type: array - items: - $ref: '#/components/schemas/RekeningnummerForeignKey' - nullable: true - description: Rekeningnummers van een partij - voorkeursRekeningnummer: - allOf: - - $ref: '#/components/schemas/RekeningnummerForeignKey' - nullable: true - description: Rekeningsnummer die een partij bij voorkeur gebruikt. - partijIdentificatoren: - type: array - items: - $ref: '#/components/schemas/PartijIdentificatorForeignkey' - readOnly: true - description: Partij-identificatoren die hoorde bij deze partij. - soortPartij: - allOf: - - $ref: '#/components/schemas/SoortPartijEnum' - description: Geeft aan van welke specifieke soort partij sprake is. - indicatieGeheimhouding: - type: boolean - nullable: true - description: Geeft aan of de verstrekker van partijgegevens heeft aangegeven - dat deze gegevens als geheim beschouwd moeten worden. Als dit niet aangegeven - is dan wordt dit ingevuld als `null`. - voorkeurstaal: - type: string - description: 'Taal, in ISO 639-2/B formaat, waarin de partij bij voorkeur - contact heeft met de gemeente. Voorbeeld: nld. Zie: https://www.iso.org/standard/4767.html' - maxLength: 3 - indicatieActief: - type: boolean - description: 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. - bezoekadres: - allOf: - - $ref: '#/components/schemas/PartijBezoekadres' - nullable: true - description: Adres waarop de partij door gemeente bezocht wil worden. Dit - mag afwijken van voor de verstrekker eventueel in een basisregistratie - bekende adressen. - correspondentieadres: - allOf: - - $ref: '#/components/schemas/PartijCorrespondentieadres' - nullable: true - description: Adres waarop de partij post van de gemeente wil ontvangen. - Dit mag afwijken van voor de verstrekker eventueel in een basisregistratie - bekende adressen. - required: - - betrokkenen - - categorieRelaties - - digitaleAdressen - - indicatieActief - - partijIdentificatoren - - rekeningnummers - - soortPartij - - url - - uuid - - vertegenwoordigden - - voorkeursDigitaalAdres - - voorkeursRekeningnummer + oneOf: + - $ref: '#/components/schemas/contactpersoon_PartijSerializer' + - $ref: '#/components/schemas/persoon_PartijSerializer' + - $ref: '#/components/schemas/organisatie_PartijSerializer' + discriminator: + propertyName: soortPartij + mapping: + contactpersoon: '#/components/schemas/contactpersoon_PartijSerializer' + persoon: '#/components/schemas/persoon_PartijSerializer' + organisatie: '#/components/schemas/organisatie_PartijSerializer' PartijBezoekadres: type: object - description: |- - Generate a serializer out of a GegevensGroepType. - - Usage:: - - >>> class VerlengingSerializer(GegevensGroepSerializer): - ... class Meta: - ... model = Zaak - ... gegevensgroep = 'verlenging' - >>> - - Where ``Zaak.verlenging`` is a :class:``GegevensGroepType``. properties: nummeraanduidingId: type: string @@ -4500,18 +4653,6 @@ components: minLength: 4 PartijCorrespondentieadres: type: object - description: |- - Generate a serializer out of a GegevensGroepType. - - Usage:: - - >>> class VerlengingSerializer(GegevensGroepSerializer): - ... class Meta: - ... model = Zaak - ... gegevensgroep = 'verlenging' - >>> - - Where ``Zaak.verlenging`` is a :class:``GegevensGroepType``. properties: nummeraanduidingId: type: string @@ -4551,6 +4692,8 @@ components: format: uri readOnly: true description: De unieke URL van deze partij binnen deze API. + minLength: 1 + maxLength: 1000 required: - url - uuid @@ -4566,6 +4709,8 @@ components: format: uri readOnly: true description: De unieke URL van deze partij binnen deze API. + minLength: 1 + maxLength: 1000 required: - url - uuid @@ -4586,6 +4731,8 @@ components: format: uri readOnly: true description: De unieke URL van deze partij indentificator binnen deze API. + minLength: 1 + maxLength: 1000 identificeerdePartij: allOf: - $ref: '#/components/schemas/PartijForeignKey' @@ -4620,82 +4767,67 @@ components: format: uri readOnly: true description: De unieke URL van deze partij indentificator binnen deze API. + minLength: 1 + maxLength: 1000 required: - url - uuid PartijIdentificatorGroepType: type: object - description: |- - Generate a serializer out of a GegevensGroepType. - - Usage:: - - >>> class VerlengingSerializer(GegevensGroepSerializer): - ... class Meta: - ... model = Zaak - ... gegevensgroep = 'verlenging' - >>> - - Where ``Zaak.verlenging`` is a :class:``GegevensGroepType``. properties: codeObjecttype: - type: string title: Objecttype - description: 'Type van het object, bijvoorbeeld: ''INGESCHREVEN NATUURLIJK - PERSOON''.' - maxLength: 200 + description: 'Type van het object, bijvoorbeeld: ''natuurlijk_persoon''.' + oneOf: + - $ref: '#/components/schemas/CodeObjecttypeEnum' + - $ref: '#/components/schemas/BlankEnum' codeSoortObjectId: - type: string title: Soort object ID description: 'Naam van de eigenschap die het object identificeert, bijvoorbeeld: - ''Burgerservicenummer''.' - maxLength: 200 + ''bsn''.' + oneOf: + - $ref: '#/components/schemas/CodeSoortObjectIdEnum' + - $ref: '#/components/schemas/BlankEnum' objectId: type: string description: 'Waarde van de eigenschap die het object identificeert, bijvoorbeeld: ''123456788''.' maxLength: 200 codeRegister: - type: string title: Register description: 'Binnen het landschap van registers unieke omschrijving van het register waarin het object is geregistreerd, bijvoorbeeld: ''BRP''.' - maxLength: 200 - PatchedActor: + oneOf: + - $ref: '#/components/schemas/CodeRegisterEnum' + - $ref: '#/components/schemas/BlankEnum' + PartijPolymorphic: type: object - description: |- - Set gegevensgroepdata from validated nested data. - - Usage: include the mixin on the ModelSerializer that has gegevensgroepen. properties: uuid: type: string format: uuid - readOnly: true - description: Unieke (technische) identificatiecode van de actor. + description: Unieke (technische) identificatiecode van de partij. url: type: string format: uri readOnly: true - description: De unieke URL van deze actor binnen deze API. - naam: - type: string - description: Naam van de actor. - maxLength: 200 - soortActor: - allOf: - - $ref: '#/components/schemas/SoortActorEnum' - description: Geeft aan van welke specifieke soort actor sprake is. - indicatieActief: - type: boolean - description: Geeft aan of aan de actor nog betrokken mag worden bij nieuwe - klantcontacten. Voor niet-actieve is dit niet toegestaan. - actoridentificator: - allOf: - - $ref: '#/components/schemas/Actoridentificator' - nullable: true - description: Gegevens die een actorwerpobject in een extern register uniek - identificeren. + description: De unieke URL van deze partij binnen deze API. + minLength: 1 + maxLength: 1000 + required: + - url + - uuid + PatchedActor: + oneOf: + - $ref: '#/components/schemas/medewerker_ActorSerializer' + - $ref: '#/components/schemas/geautomatiseerde_actor_ActorSerializer' + - $ref: '#/components/schemas/organisatorische_eenheid_ActorSerializer' + discriminator: + propertyName: soortActor + mapping: + medewerker: '#/components/schemas/medewerker_ActorSerializer' + geautomatiseerde_actor: '#/components/schemas/geautomatiseerde_actor_ActorSerializer' + organisatorische_eenheid: '#/components/schemas/organisatorische_eenheid_ActorSerializer' PatchedActorKlantcontact: type: object properties: @@ -4709,6 +4841,8 @@ components: format: uri readOnly: true description: De unieke URL van deze actor klantcontact binnen deze API. + minLength: 1 + maxLength: 1000 actor: allOf: - $ref: '#/components/schemas/ActorForeignKey' @@ -4735,6 +4869,8 @@ components: format: uri readOnly: true description: De unieke URL van deze betrokkene binnen deze API. + minLength: 1 + maxLength: 1000 wasPartij: allOf: - $ref: '#/components/schemas/PartijForeignKey' @@ -4805,6 +4941,8 @@ components: format: uri readOnly: true description: De unieke URL van dit klantcontact binnen deze API. + minLength: 1 + maxLength: 1000 wasBijlageVanKlantcontact: allOf: - $ref: '#/components/schemas/KlantcontactForeignKey' @@ -4830,6 +4968,8 @@ components: format: uri readOnly: true description: De unieke URL van deze categorie binnen deze API. + minLength: 1 + maxLength: 1000 naam: type: string description: Naam van de categorie. @@ -4848,6 +4988,8 @@ components: format: uri readOnly: true description: De unieke URL van deze categorie binnen deze API. + minLength: 1 + maxLength: 1000 partij: allOf: - $ref: '#/components/schemas/PartijForeignkeyBase' @@ -4886,6 +5028,8 @@ components: format: uri readOnly: true description: De unieke URL van dit digitaal adres binnen deze API. + minLength: 1 + maxLength: 1000 verstrektDoorBetrokkene: allOf: - $ref: '#/components/schemas/BetrokkeneForeignKey' @@ -4932,6 +5076,8 @@ components: format: uri readOnly: true description: De unieke URL van deze interne taak binnen deze API. + minLength: 1 + maxLength: 1000 nummer: type: string description: Uniek identificerend nummer dat tijdens communicatie tussen @@ -4992,6 +5138,8 @@ components: format: uri readOnly: true description: De unieke URL van dit klantcontact binnen deze API. + minLength: 1 + maxLength: 1000 gingOverOnderwerpobjecten: type: array items: @@ -5079,6 +5227,8 @@ components: format: uri readOnly: true description: De unieke URL van dit klantcontact binnen deze API. + minLength: 1 + maxLength: 1000 klantcontact: allOf: - $ref: '#/components/schemas/KlantcontactForeignKey' @@ -5096,115 +5246,16 @@ components: description: Gegevens die een onderwerpobject in een extern register uniek identificeren. PatchedPartij: - type: object - description: |- - Set gegevensgroepdata from validated nested data. - - Usage: include the mixin on the ModelSerializer that has gegevensgroepen. - properties: - uuid: - type: string - format: uuid - readOnly: true - description: Unieke (technische) identificatiecode van de partij. - url: - type: string - format: uri - readOnly: true - description: De unieke URL van deze partij binnen deze API. - nummer: - type: string - description: Uniek identificerend nummer dat tijdens communicatie tussen - mensen kan worden gebruikt om de specifieke partij aan te duiden. - maxLength: 10 - interneNotitie: - type: string - description: Mededelingen, aantekeningen of bijzonderheden over de partij, - bedoeld voor intern gebruik. - maxLength: 1000 - betrokkenen: - type: array - items: - $ref: '#/components/schemas/BetrokkeneForeignKey' - readOnly: true - description: Betrokkene bij klantcontact die een partij was. - categorieRelaties: - type: array - items: - $ref: '#/components/schemas/CategorieRelatieForeignKey' - readOnly: true - description: 'De Categorie relaties van een partij: Let op: Dit attribuut - is EXPERIMENTEEL.' - digitaleAdressen: - type: array - items: - $ref: '#/components/schemas/DigitaalAdresForeignKey' - nullable: true - description: Digitaal adresen dat een partij verstrekte voor gebruik bij - toekomstig contact met de gemeente. - voorkeursDigitaalAdres: - allOf: - - $ref: '#/components/schemas/DigitaalAdresForeignKey' - nullable: true - description: Digitaal adres waarop een partij bij voorkeur door de gemeente - benaderd wordt. - vertegenwoordigden: - type: array - items: - $ref: '#/components/schemas/PartijForeignKey' - readOnly: true - description: Partijen die een andere partijen vertegenwoordigden. - rekeningnummers: - type: array - items: - $ref: '#/components/schemas/RekeningnummerForeignKey' - nullable: true - description: Rekeningnummers van een partij - voorkeursRekeningnummer: - allOf: - - $ref: '#/components/schemas/RekeningnummerForeignKey' - nullable: true - description: Rekeningsnummer die een partij bij voorkeur gebruikt. - partijIdentificatoren: - type: array - items: - $ref: '#/components/schemas/PartijIdentificatorForeignkey' - readOnly: true - description: Partij-identificatoren die hoorde bij deze partij. - soortPartij: - allOf: - - $ref: '#/components/schemas/SoortPartijEnum' - description: Geeft aan van welke specifieke soort partij sprake is. - indicatieGeheimhouding: - type: boolean - nullable: true - description: Geeft aan of de verstrekker van partijgegevens heeft aangegeven - dat deze gegevens als geheim beschouwd moeten worden. Als dit niet aangegeven - is dan wordt dit ingevuld als `null`. - voorkeurstaal: - type: string - description: 'Taal, in ISO 639-2/B formaat, waarin de partij bij voorkeur - contact heeft met de gemeente. Voorbeeld: nld. Zie: https://www.iso.org/standard/4767.html' - maxLength: 3 - indicatieActief: - type: boolean - description: 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. - bezoekadres: - allOf: - - $ref: '#/components/schemas/PartijBezoekadres' - nullable: true - description: Adres waarop de partij door gemeente bezocht wil worden. Dit - mag afwijken van voor de verstrekker eventueel in een basisregistratie - bekende adressen. - correspondentieadres: - allOf: - - $ref: '#/components/schemas/PartijCorrespondentieadres' - nullable: true - description: Adres waarop de partij post van de gemeente wil ontvangen. - Dit mag afwijken van voor de verstrekker eventueel in een basisregistratie - bekende adressen. + oneOf: + - $ref: '#/components/schemas/contactpersoon_PartijSerializer' + - $ref: '#/components/schemas/persoon_PartijSerializer' + - $ref: '#/components/schemas/organisatie_PartijSerializer' + discriminator: + propertyName: soortPartij + mapping: + contactpersoon: '#/components/schemas/contactpersoon_PartijSerializer' + persoon: '#/components/schemas/persoon_PartijSerializer' + organisatie: '#/components/schemas/organisatie_PartijSerializer' PatchedPartijIdentificator: type: object description: |- @@ -5222,6 +5273,8 @@ components: format: uri readOnly: true description: De unieke URL van deze partij indentificator binnen deze API. + minLength: 1 + maxLength: 1000 identificeerdePartij: allOf: - $ref: '#/components/schemas/PartijForeignKey' @@ -5252,6 +5305,8 @@ components: format: uri readOnly: true description: De unieke URL van deze rekeningnummer binnen deze API. + minLength: 1 + maxLength: 1000 partij: allOf: - $ref: '#/components/schemas/PartijForeignKey' @@ -5285,6 +5340,8 @@ components: format: uri readOnly: true description: De unieke URL van deze vertegenwoordigden binnen deze API. + minLength: 1 + maxLength: 1000 vertegenwoordigendePartij: allOf: - $ref: '#/components/schemas/PartijForeignKey' @@ -5293,6 +5350,51 @@ components: allOf: - $ref: '#/components/schemas/PartijForeignKey' description: '''Partij'' vertegenwoordigd wordt door een andere ''Partij''.' + Persoon: + type: object + description: |- + Set gegevensgroepdata from validated nested data. + + Usage: include the mixin on the ModelSerializer that has gegevensgroepen. + properties: + contactnaam: + allOf: + - $ref: '#/components/schemas/PersoonContact' + nullable: true + description: Naam die een persoon wil gebruiken tijdens contact met de gemeente. + Deze mag afwijken van de eventueel in de Basisregistratie Personen (BRP) + bekende naam van de persoon. + volledigeNaam: + type: string + readOnly: true + description: De voledige naam van het persoon. + required: + - contactnaam + - volledigeNaam + PersoonContact: + type: object + properties: + voorletters: + type: string + description: Een afkorting van de voornamen. Meestal de beginletter, maar + in sommige gevallen de beginletter gecombineerd met de tweede letter van + een voornaam. + maxLength: 10 + voornaam: + type: string + description: De voornaam die de persoon wil gebruiken tijdens communicatie + met de gemeente. + maxLength: 200 + voorvoegselAchternaam: + type: string + description: Een eventueel voorvoegsel dat hoort bij de achternaam die de + persoon wil gebruiken tijdens communicatie met de gemeente. + maxLength: 10 + achternaam: + type: string + description: Een achternaam die de persoon wil gebruiken tijdens communicatie + met de gemeente. + maxLength: 200 Rekeningnummer: type: object properties: @@ -5306,6 +5408,8 @@ components: format: uri readOnly: true description: De unieke URL van deze rekeningnummer binnen deze API. + minLength: 1 + maxLength: 1000 partij: allOf: - $ref: '#/components/schemas/PartijForeignKey' @@ -5343,6 +5447,8 @@ components: format: uri readOnly: true description: De unieke URL van deze rekeningnummer binnen deze API. + minLength: 1 + maxLength: 1000 required: - url - uuid @@ -5387,6 +5493,8 @@ components: format: uri readOnly: true description: De unieke URL van deze vertegenwoordigden binnen deze API. + minLength: 1 + maxLength: 1000 vertegenwoordigendePartij: allOf: - $ref: '#/components/schemas/PartijForeignKey' @@ -5400,6 +5508,60 @@ components: - uuid - vertegenwoordigdePartij - vertegenwoordigendePartij + actor_identificatie_GeautomatiseerdeActor: + type: object + properties: + actorIdentificatie: + $ref: '#/components/schemas/GeautomatiseerdeActor' + actor_identificatie_Medewerker: + type: object + properties: + actorIdentificatie: + $ref: '#/components/schemas/Medewerker' + actor_identificatie_OrganisatorischeEenheid: + type: object + properties: + actorIdentificatie: + $ref: '#/components/schemas/OrganisatorischeEenheid' + contactpersoon_PartijSerializer: + allOf: + - $ref: '#/components/schemas/Base_PartijSerializer' + - $ref: '#/components/schemas/partij_identificatie_Contactpersoon' + geautomatiseerde_actor_ActorSerializer: + allOf: + - $ref: '#/components/schemas/Base_ActorSerializer' + - $ref: '#/components/schemas/actor_identificatie_GeautomatiseerdeActor' + medewerker_ActorSerializer: + allOf: + - $ref: '#/components/schemas/Base_ActorSerializer' + - $ref: '#/components/schemas/actor_identificatie_Medewerker' + organisatie_PartijSerializer: + allOf: + - $ref: '#/components/schemas/Base_PartijSerializer' + - $ref: '#/components/schemas/partij_identificatie_Organisatie' + organisatorische_eenheid_ActorSerializer: + allOf: + - $ref: '#/components/schemas/Base_ActorSerializer' + - $ref: '#/components/schemas/actor_identificatie_OrganisatorischeEenheid' + partij_identificatie_Contactpersoon: + type: object + properties: + partijIdentificatie: + $ref: '#/components/schemas/Contactpersoon' + partij_identificatie_Organisatie: + type: object + properties: + partijIdentificatie: + $ref: '#/components/schemas/Organisatie' + partij_identificatie_Persoon: + type: object + properties: + partijIdentificatie: + $ref: '#/components/schemas/Persoon' + persoon_PartijSerializer: + allOf: + - $ref: '#/components/schemas/Base_PartijSerializer' + - $ref: '#/components/schemas/partij_identificatie_Persoon' securitySchemes: tokenAuth: type: apiKey diff --git a/src/openklant/components/klantinteracties/tests/test_validators.py b/src/openklant/components/klantinteracties/tests/test_validators.py new file mode 100644 index 00000000..7179ed09 --- /dev/null +++ b/src/openklant/components/klantinteracties/tests/test_validators.py @@ -0,0 +1,339 @@ +from django.core.exceptions import ValidationError +from django.test import TestCase + +from openklant.components.klantinteracties.models.constants import ( + PartijIdentificatorCodeObjectType, + PartijIdentificatorCodeRegister, + PartijIdentificatorCodeSoortObjectId, +) +from openklant.components.klantinteracties.models.validators import ( + PartijIdentificatorValidator, +) + + +class PartijIdentificatorValidatorTests(TestCase): + def test_valid(self): + validator = PartijIdentificatorValidator( + code_objecttype=PartijIdentificatorCodeObjectType.natuurlijk_persoon.value, + code_soort_object_id=PartijIdentificatorCodeSoortObjectId.bsn.value, + object_id="296648875", + code_register=PartijIdentificatorCodeRegister.brp.value, + ) + validator.validate() + + # Start section validate_code_objecttype + + def test_valid_code_objecttype_null(self): + validator = PartijIdentificatorValidator( + code_objecttype="", + code_soort_object_id=PartijIdentificatorCodeSoortObjectId.bsn.value, + object_id="296648875", + code_register=PartijIdentificatorCodeRegister.brp.value, + ) + validator.validate_code_objecttype() + + def test_valid_code_objecttype_top_level_null_or_overig(self): + validator = PartijIdentificatorValidator( + code_objecttype=PartijIdentificatorCodeObjectType.natuurlijk_persoon.value, + code_soort_object_id=PartijIdentificatorCodeSoortObjectId.bsn.value, + object_id="296648875", + code_register="", + ) + validator.validate_code_objecttype() + + validator = PartijIdentificatorValidator( + code_objecttype=PartijIdentificatorCodeObjectType.natuurlijk_persoon.value, + code_soort_object_id=PartijIdentificatorCodeSoortObjectId.bsn.value, + object_id="296648875", + code_register=PartijIdentificatorCodeRegister.overig.value, + ) + validator.validate_code_objecttype() + + def test_invalid_code_objecttype_not_found_in_top_level(self): + with self.assertRaises(ValidationError) as error: + validator = PartijIdentificatorValidator( + code_objecttype=PartijIdentificatorCodeObjectType.niet_natuurlijk_persoon.value, + code_soort_object_id=PartijIdentificatorCodeSoortObjectId.bsn.value, + object_id="296648875", + code_register=PartijIdentificatorCodeRegister.brp.value, + ) + validator.validate_code_objecttype() + + details = error.exception.message_dict + self.assertEqual( + details["partij_identificator_code_objecttype"][0], + "voor `codeRegister` brp zijn alleen deze waarden toegestaan: ['natuurlijk_persoon']", + ) + + # Start section validate_code_soort_object_id + + def test_valid_code_soort_object_id_null(self): + validator = PartijIdentificatorValidator( + code_objecttype=PartijIdentificatorCodeObjectType.natuurlijk_persoon.value, + code_soort_object_id="", + object_id="12345678", + code_register=PartijIdentificatorCodeRegister.brp.value, + ) + validator.validate_code_soort_object_id() + + def test_valid_code_soort_object_id_top_level_null_or_overig(self): + validator = PartijIdentificatorValidator( + code_objecttype="", + code_soort_object_id=PartijIdentificatorCodeSoortObjectId.bsn.value, + object_id="296648875", + code_register=PartijIdentificatorCodeRegister.brp.value, + ) + validator.validate_code_soort_object_id() + + validator = PartijIdentificatorValidator( + code_objecttype=PartijIdentificatorCodeObjectType.overig.value, + code_soort_object_id=PartijIdentificatorCodeSoortObjectId.bsn.value, + object_id="296648875", + code_register=PartijIdentificatorCodeRegister.brp.value, + ) + validator.validate_code_soort_object_id() + + def test_invalid_code_soort_object_id_not_found_in_top_level(self): + with self.assertRaises(ValidationError) as error: + validator = PartijIdentificatorValidator( + code_objecttype=PartijIdentificatorCodeObjectType.natuurlijk_persoon.value, + code_soort_object_id=PartijIdentificatorCodeSoortObjectId.rsin.value, + object_id="296648875", + code_register=PartijIdentificatorCodeRegister.brp.value, + ) + validator.validate_code_soort_object_id() + details = error.exception.message_dict + self.assertEqual( + details["partij_identificator_code_soort_object_id"][0], + "voor `codeObjecttype` natuurlijk_persoon zijn alleen deze waarden toegestaan: ['bsn', 'overig']", + ) + + # Start section validate_object_id + + def test_valid_object_id_null(self): + validator = PartijIdentificatorValidator( + code_objecttype=PartijIdentificatorCodeObjectType.natuurlijk_persoon.value, + code_soort_object_id=PartijIdentificatorCodeSoortObjectId.bsn.value, + object_id="", + code_register=PartijIdentificatorCodeRegister.brp.value, + ) + validator.validate_object_id() + + def test_valid_object_id_top_level_null_or_overig(self): + validator = PartijIdentificatorValidator( + code_objecttype=PartijIdentificatorCodeObjectType.natuurlijk_persoon.value, + code_soort_object_id="", + object_id="1123", + code_register=PartijIdentificatorCodeRegister.brp.value, + ) + validator.validate_object_id() + + validator = PartijIdentificatorValidator( + code_objecttype=PartijIdentificatorCodeObjectType.natuurlijk_persoon.value, + code_soort_object_id=PartijIdentificatorCodeSoortObjectId.overig.value, + object_id="1123", + code_register=PartijIdentificatorCodeRegister.brp.value, + ) + validator.validate_object_id() + + def test_valid_object_id_bsn(self): + validator = PartijIdentificatorValidator( + code_objecttype=PartijIdentificatorCodeObjectType.natuurlijk_persoon.value, + code_soort_object_id=PartijIdentificatorCodeSoortObjectId.bsn.value, + object_id="296648875", + code_register=PartijIdentificatorCodeRegister.brp.value, + ) + validator.validate_object_id() + + def test_valid_object_id_vestigingsnummer(self): + validator = PartijIdentificatorValidator( + code_objecttype=PartijIdentificatorCodeObjectType.vestiging.value, + code_soort_object_id=PartijIdentificatorCodeSoortObjectId.vestigingsnummer.value, + object_id="296648875154", + code_register=PartijIdentificatorCodeRegister.brp.value, + ) + validator.validate_object_id() + + def test_valid_object_id_rsin(self): + validator = PartijIdentificatorValidator( + code_objecttype=PartijIdentificatorCodeObjectType.niet_natuurlijk_persoon.value, + code_soort_object_id=PartijIdentificatorCodeSoortObjectId.rsin.value, + object_id="296648875", + code_register=PartijIdentificatorCodeRegister.brp.value, + ) + validator.validate_object_id() + + def test_valid_object_id_kvk_nummer(self): + validator = PartijIdentificatorValidator( + code_objecttype=PartijIdentificatorCodeObjectType.niet_natuurlijk_persoon.value, + code_soort_object_id=PartijIdentificatorCodeSoortObjectId.kvk_nummer.value, + object_id="12345678", + code_register=PartijIdentificatorCodeRegister.brp.value, + ) + validator.validate_object_id() + + def test_invalid_object_id_len_bsn(self): + with self.assertRaises(ValidationError) as error: + validator = PartijIdentificatorValidator( + code_objecttype=PartijIdentificatorCodeObjectType.natuurlijk_persoon.value, + code_soort_object_id=PartijIdentificatorCodeSoortObjectId.bsn.value, + object_id="123", + code_register=PartijIdentificatorCodeRegister.brp.value, + ) + validator.validate_object_id() + details = error.exception.message_dict + self.assertEqual( + details["partij_identificator_object_id"][0], + "Deze waarde is ongeldig, reden: Waarde moet 9 tekens lang zijn", + ) + + def test_invalid_object_id_digit_bsn(self): + with self.assertRaises(ValidationError) as error: + validator = PartijIdentificatorValidator( + code_objecttype=PartijIdentificatorCodeObjectType.natuurlijk_persoon.value, + code_soort_object_id=PartijIdentificatorCodeSoortObjectId.bsn.value, + object_id="123TEST123", + code_register=PartijIdentificatorCodeRegister.brp.value, + ) + validator.validate_object_id() + details = error.exception.message_dict + self.assertEqual( + details["partij_identificator_object_id"][0], + "Deze waarde is ongeldig, reden: Voer een numerieke waarde in", + ) + + def test_invalid_object_id_proef11_bsn(self): + with self.assertRaises(ValidationError) as error: + validator = PartijIdentificatorValidator( + code_objecttype=PartijIdentificatorCodeObjectType.natuurlijk_persoon.value, + code_soort_object_id=PartijIdentificatorCodeSoortObjectId.bsn.value, + object_id="123456789", + code_register=PartijIdentificatorCodeRegister.brp.value, + ) + validator.validate_object_id() + details = error.exception.message_dict + self.assertEqual( + details["partij_identificator_object_id"][0], + "Deze waarde is ongeldig, reden: Onjuist BSN nummer", + ) + + def test_allowed_cases(self): + valid_cases = [ + [ + PartijIdentificatorCodeRegister.brp.value, + PartijIdentificatorCodeObjectType.natuurlijk_persoon.value, + PartijIdentificatorCodeSoortObjectId.bsn.value, + "296648875", + ], + [ + PartijIdentificatorCodeRegister.brp.value, + PartijIdentificatorCodeObjectType.natuurlijk_persoon.value, + PartijIdentificatorCodeSoortObjectId.overig.value, + "123456", + ], + [ + PartijIdentificatorCodeRegister.hr.value, + PartijIdentificatorCodeObjectType.vestiging.value, + PartijIdentificatorCodeSoortObjectId.vestigingsnummer.value, + "123456789878", + ], + [ + PartijIdentificatorCodeRegister.hr.value, + PartijIdentificatorCodeObjectType.vestiging.value, + PartijIdentificatorCodeSoortObjectId.overig.value, + "296648875", + ], + [ + PartijIdentificatorCodeRegister.hr.value, + PartijIdentificatorCodeObjectType.niet_natuurlijk_persoon.value, + PartijIdentificatorCodeSoortObjectId.rsin.value, + "296648875", + ], + [ + PartijIdentificatorCodeRegister.hr.value, + PartijIdentificatorCodeObjectType.niet_natuurlijk_persoon.value, + PartijIdentificatorCodeSoortObjectId.kvk_nummer.value, + "12345678", + ], + [ + PartijIdentificatorCodeRegister.hr.value, + PartijIdentificatorCodeObjectType.niet_natuurlijk_persoon.value, + PartijIdentificatorCodeSoortObjectId.overig.value, + "296648875", + ], + [ + PartijIdentificatorCodeRegister.overig.value, + PartijIdentificatorCodeObjectType.natuurlijk_persoon.value, + PartijIdentificatorCodeSoortObjectId.bsn.value, + "296648875", + ], + [ + "", + "", + "", + "", + ], + [ + PartijIdentificatorCodeRegister.brp.value, + "", + "", + "", + ], + [ + "", + PartijIdentificatorCodeObjectType.natuurlijk_persoon.value, + "", + "", + ], + [ + PartijIdentificatorCodeRegister.overig.value, + PartijIdentificatorCodeObjectType.natuurlijk_persoon.value, + "", + "", + ], + [ + PartijIdentificatorCodeRegister.overig.value, + PartijIdentificatorCodeObjectType.overig.value, + PartijIdentificatorCodeSoortObjectId.overig.value, + "296648875", + ], + ] + for case in valid_cases: + validator = PartijIdentificatorValidator( + code_register=case[0], + code_objecttype=case[1], + code_soort_object_id=case[2], + object_id=case[3], + ) + validator.validate() + + def test_not_allowed_cases(self): + invalid_cases = [ + [ + PartijIdentificatorCodeRegister.brp.value, + PartijIdentificatorCodeObjectType.niet_natuurlijk_persoon.value, + PartijIdentificatorCodeSoortObjectId.bsn.value, + "296648875", + ], + [ + PartijIdentificatorCodeRegister.brp.value, + PartijIdentificatorCodeObjectType.natuurlijk_persoon.value, + PartijIdentificatorCodeSoortObjectId.kvk_nummer.value, + "296648875", + ], + [ + PartijIdentificatorCodeRegister.brp.value, + PartijIdentificatorCodeObjectType.overig.value, + PartijIdentificatorCodeSoortObjectId.bsn.value, + "296648875", + ], + ] + for case in invalid_cases: + with self.assertRaises(ValidationError): + validator = PartijIdentificatorValidator( + code_register=case[0], + code_objecttype=case[1], + code_soort_object_id=case[2], + object_id=case[3], + ) + validator.validate() diff --git a/src/openklant/fixtures/klantinteracties.json b/src/openklant/fixtures/klantinteracties.json index 9decafbd..36b1c834 100644 --- a/src/openklant/fixtures/klantinteracties.json +++ b/src/openklant/fixtures/klantinteracties.json @@ -340,10 +340,10 @@ "uuid": "dd328a2e-7b8e-4809-be28-f9f894c11c34", "partij": 1, "andere_partij_identificator": "", - "partij_identificator_code_objecttype": "INGESCHREVEN NATUURLIJK PERSOON", - "partij_identificator_code_soort_object_id": "Burgerservicenummer", - "partij_identificator_object_id": "123456788", - "partij_identificator_code_register": "BRP" + "partij_identificator_code_objecttype": "natuurlijk_persoon", + "partij_identificator_code_soort_object_id": "bsn", + "partij_identificator_object_id": "296648875", + "partij_identificator_code_register": "brp" } }, {