Skip to content

Commit d812844

Browse files
committed
✨ [#147] Convenience endpoint for Klantcontact/Betrokkene/Onderwerpobject
to allow creation of these three resources in a single API call
1 parent 2886954 commit d812844

File tree

4 files changed

+235
-1
lines changed

4 files changed

+235
-1
lines changed

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

+52
Original file line numberDiff line numberDiff line change
@@ -537,3 +537,55 @@ def create(self, validated_data):
537537
)
538538

539539
return super().create(validated_data)
540+
541+
542+
class BetrokkeneConvenienceSerializer(BetrokkeneSerializer):
543+
def __init__(self, *args, **kwargs):
544+
super().__init__(*args, **kwargs)
545+
546+
self.fields["had_klantcontact"].read_only = True
547+
548+
549+
class OnderwerpobjectConvenienceSerializer(OnderwerpobjectSerializer):
550+
def __init__(self, *args, **kwargs):
551+
super().__init__(*args, **kwargs)
552+
553+
self.fields["klantcontact"].read_only = True
554+
555+
556+
class KlantContactBetrokkeneOnderwerpObjectSerializer(serializers.Serializer):
557+
klantcontact = KlantcontactSerializer()
558+
betrokkene = BetrokkeneConvenienceSerializer()
559+
onderwerpobject = OnderwerpobjectConvenienceSerializer()
560+
561+
@transaction.atomic
562+
def create(self, validated_data):
563+
"""
564+
Create the objects and use the original serializers to ensure all the correct
565+
fields show up in the response
566+
"""
567+
klantcontact_data = validated_data["klantcontact"]
568+
klantcontact = Klantcontact.objects.create(**klantcontact_data)
569+
570+
betrokkene_data = validated_data["betrokkene"]
571+
betrokkene_data["had_klantcontact"] = {"uuid": str(klantcontact.uuid)}
572+
# TODO for some reason `was_partij` is converted to `partij` by the serializer
573+
betrokkene_data.setdefault("was_partij", betrokkene_data.get("partij", None))
574+
betrokkene_serializer = BetrokkeneSerializer(data=betrokkene_data)
575+
betrokkene_serializer.is_valid()
576+
betrokkene = betrokkene_serializer.save()
577+
578+
onderwerpobject_data = validated_data["onderwerpobject"]
579+
onderwerpobject_data["klantcontact"] = {"uuid": str(klantcontact.uuid)}
580+
onderwerpobject_data.setdefault("was_klantcontact", None)
581+
onderwerpobject_serializer = OnderwerpobjectSerializer(
582+
data=onderwerpobject_data
583+
)
584+
onderwerpobject_serializer.is_valid()
585+
onderwerpobject = onderwerpobject_serializer.save()
586+
587+
return {
588+
"klantcontact": klantcontact,
589+
"betrokkene": betrokkene,
590+
"onderwerpobject": onderwerpobject,
591+
}

src/openklant/components/klantinteracties/api/urls.py

+6
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
ActorKlantcontactViewSet,
1919
BetrokkeneViewSet,
2020
BijlageViewSet,
21+
KlantContactBetrokkeneOnderwerpObjectViewSet,
2122
KlantcontactViewSet,
2223
OnderwerpobjectViewSet,
2324
)
@@ -48,6 +49,11 @@
4849
router.register("betrokkenen", BetrokkeneViewSet)
4950
router.register("onderwerpobjecten", OnderwerpobjectViewSet)
5051
router.register("bijlagen", BijlageViewSet)
52+
router.register(
53+
"klantcontact-convenience",
54+
KlantContactBetrokkeneOnderwerpObjectViewSet,
55+
basename="klantcontact-convenience",
56+
)
5157

5258
router.register("internetaken", InterneTaakViewSet)
5359

src/openklant/components/klantinteracties/api/viewsets/klantcontacten.py

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from django_filters.rest_framework import DjangoFilterBackend
22
from drf_spectacular.utils import extend_schema, extend_schema_view
3-
from rest_framework import viewsets
3+
from rest_framework import mixins, viewsets
44
from vng_api_common.pagination import DynamicPageSizePagination
55

66
from openklant.components.klantinteracties.api.filterset.klantcontacten import (
@@ -13,6 +13,7 @@
1313
ActorKlantcontactSerializer,
1414
BetrokkeneSerializer,
1515
BijlageSerializer,
16+
KlantContactBetrokkeneOnderwerpObjectSerializer,
1617
KlantcontactSerializer,
1718
OnderwerpobjectSerializer,
1819
)
@@ -262,3 +263,23 @@ class ActorKlantcontactViewSet(viewsets.ModelViewSet):
262263
filterset_class = ActorKlantcontactFilterSet
263264
authentication_classes = (TokenAuthentication,)
264265
permission_classes = (TokenPermissions,)
266+
267+
268+
@extend_schema(tags=["klantcontact-convenience"])
269+
@extend_schema_view(
270+
create=extend_schema(
271+
summary="Maak een KlantContact, Betrokkene en een OnderwerpObject aan.",
272+
description="Maak een KlantContact, Betrokkene en een OnderwerpObject aan.",
273+
),
274+
)
275+
class KlantContactBetrokkeneOnderwerpObjectViewSet(
276+
mixins.CreateModelMixin, viewsets.GenericViewSet
277+
):
278+
"""
279+
Convenience endpoint om in één request een Betrokkene, KlantContact en een OnderwerpObject
280+
aan te maken. De aangemaakte objecten worden automatisch aan elkaar gekoppeld.
281+
"""
282+
283+
serializer_class = KlantContactBetrokkeneOnderwerpObjectSerializer
284+
authentication_classes = (TokenAuthentication,)
285+
permission_classes = (TokenPermissions,)

src/openklant/components/klantinteracties/openapi.yaml

+155
Original file line numberDiff line numberDiff line change
@@ -1547,6 +1547,28 @@ paths:
15471547
responses:
15481548
'204':
15491549
description: No response body
1550+
/klantcontact-convenience:
1551+
post:
1552+
operationId: klantcontactConvenienceCreate
1553+
description: Maak een KlantContact, Betrokkene en een OnderwerpObject aan.
1554+
summary: Maak een KlantContact, Betrokkene en een OnderwerpObject aan.
1555+
tags:
1556+
- klantcontact-convenience
1557+
requestBody:
1558+
content:
1559+
application/json:
1560+
schema:
1561+
$ref: '#/components/schemas/KlantContactBetrokkeneOnderwerpObject'
1562+
required: true
1563+
security:
1564+
- tokenAuth: []
1565+
responses:
1566+
'201':
1567+
content:
1568+
application/json:
1569+
schema:
1570+
$ref: '#/components/schemas/KlantContactBetrokkeneOnderwerpObject'
1571+
description: ''
15501572
/klantcontacten:
15511573
get:
15521574
operationId: klantcontactenList
@@ -2986,6 +3008,87 @@ components:
29863008
- uuid
29873009
- volledigeNaam
29883010
- wasPartij
3011+
BetrokkeneConvenience:
3012+
type: object
3013+
description: |-
3014+
Set gegevensgroepdata from validated nested data.
3015+
3016+
Usage: include the mixin on the ModelSerializer that has gegevensgroepen.
3017+
properties:
3018+
uuid:
3019+
type: string
3020+
format: uuid
3021+
readOnly: true
3022+
description: Unieke (technische) identificatiecode van de betrokkene bij
3023+
klantcontact.
3024+
url:
3025+
type: string
3026+
format: uri
3027+
readOnly: true
3028+
description: De unieke URL van deze betrokkene binnen deze API.
3029+
wasPartij:
3030+
allOf:
3031+
- $ref: '#/components/schemas/PartijForeignKey'
3032+
nullable: true
3033+
description: Betrokkene bij klantcontact die een partij was.
3034+
hadKlantcontact:
3035+
allOf:
3036+
- $ref: '#/components/schemas/KlantcontactForeignKey'
3037+
readOnly: true
3038+
description: Het klantcontact waar deze persoon of organisatie bij betrokken
3039+
was.
3040+
digitaleAdressen:
3041+
type: array
3042+
items:
3043+
$ref: '#/components/schemas/DigitaalAdresForeignKey'
3044+
readOnly: true
3045+
description: Digitale adressen van de betrokkene bij klantcontact.
3046+
bezoekadres:
3047+
allOf:
3048+
- $ref: '#/components/schemas/Bezoekadres'
3049+
nullable: true
3050+
description: Adres waarop de betrokkene bij klantcontact in naar aanleiding
3051+
van dat contact af te leggen bezoeken wil ontvangen. Dit mag afwijken
3052+
van voor de verstrekker eventueel in een basisregistratie bekende adressen.
3053+
correspondentieadres:
3054+
allOf:
3055+
- $ref: '#/components/schemas/BetrokkeneCorrespondentieadres'
3056+
nullable: true
3057+
description: Adres waarop de betrokkene bij klantcontact naar aanleiding
3058+
van dat contact te versturen post wil ontvangen. Dit mag afwijken van
3059+
voor de verstrekker eventueel in een basisregistratie bekende adressen.
3060+
contactnaam:
3061+
allOf:
3062+
- $ref: '#/components/schemas/Contactnaam'
3063+
nullable: true
3064+
description: Naam die de betrokkene bij klantcontact tijdens vervolghandelingen
3065+
naar aanleiding van dat contact wil gebruiken. Deze mag afwijken van eventueel
3066+
in de Basisregistratie Personen (BRP) bekende naam van de betrokkene.
3067+
volledigeNaam:
3068+
type: string
3069+
readOnly: true
3070+
description: De voledige naam van de betrokkene.
3071+
rol:
3072+
allOf:
3073+
- $ref: '#/components/schemas/RolEnum'
3074+
description: Rol die de betrokkene bij klantcontact tijdens dat contact
3075+
vervulde.
3076+
organisatienaam:
3077+
type: string
3078+
description: Naam van de organisatie waarmee de betrokkene bij klantcontact
3079+
een relatie had.
3080+
maxLength: 200
3081+
initiator:
3082+
type: boolean
3083+
required:
3084+
- digitaleAdressen
3085+
- hadKlantcontact
3086+
- initiator
3087+
- rol
3088+
- url
3089+
- uuid
3090+
- volledigeNaam
3091+
- wasPartij
29893092
BetrokkeneCorrespondentieadres:
29903093
type: object
29913094
description: |-
@@ -3549,6 +3652,19 @@ components:
35493652
required:
35503653
- url
35513654
- uuid
3655+
KlantContactBetrokkeneOnderwerpObject:
3656+
type: object
3657+
properties:
3658+
klantcontact:
3659+
$ref: '#/components/schemas/Klantcontact'
3660+
betrokkene:
3661+
$ref: '#/components/schemas/BetrokkeneConvenience'
3662+
onderwerpobject:
3663+
$ref: '#/components/schemas/OnderwerpobjectConvenience'
3664+
required:
3665+
- betrokkene
3666+
- klantcontact
3667+
- onderwerpobject
35523668
Klantcontact:
35533669
type: object
35543670
properties:
@@ -3699,6 +3815,45 @@ components:
36993815
- url
37003816
- uuid
37013817
- wasKlantcontact
3818+
OnderwerpobjectConvenience:
3819+
type: object
3820+
description: |-
3821+
Set gegevensgroepdata from validated nested data.
3822+
3823+
Usage: include the mixin on the ModelSerializer that has gegevensgroepen.
3824+
properties:
3825+
uuid:
3826+
type: string
3827+
format: uuid
3828+
readOnly: true
3829+
description: Unieke (technische) identificatiecode van het onderwerpdeel.
3830+
url:
3831+
type: string
3832+
format: uri
3833+
readOnly: true
3834+
description: De unieke URL van dit klantcontact binnen deze API.
3835+
klantcontact:
3836+
allOf:
3837+
- $ref: '#/components/schemas/KlantcontactForeignKey'
3838+
readOnly: true
3839+
nullable: true
3840+
description: '''Klantcontact'' ging over ''Onderwerpobject'''
3841+
wasKlantcontact:
3842+
allOf:
3843+
- $ref: '#/components/schemas/KlantcontactForeignKey'
3844+
nullable: true
3845+
description: '''Onderwerpobject'' was ''Klantcontact'''
3846+
onderwerpobjectidentificator:
3847+
allOf:
3848+
- $ref: '#/components/schemas/Onderwerpobjectidentificator'
3849+
nullable: true
3850+
description: Gegevens die een onderwerpobject in een extern register uniek
3851+
identificeren.
3852+
required:
3853+
- klantcontact
3854+
- url
3855+
- uuid
3856+
- wasKlantcontact
37023857
OnderwerpobjectForeignKey:
37033858
type: object
37043859
properties:

0 commit comments

Comments
 (0)