diff --git a/src/openapi.yaml b/src/openapi.yaml index 9545d4b..2c42973 100644 --- a/src/openapi.yaml +++ b/src/openapi.yaml @@ -2023,6 +2023,117 @@ paths: summary: Alle VERZOEKen opvragen. description: Alle VERZOEKen opvragen. parameters: + - name: identificatie + in: query + description: De unieke identificatie van het VERZOEK binnen de organisatie + die verantwoordelijk is voor de behandeling van het VERZOEK. + required: false + schema: + type: string + - name: bronorganisatie + in: query + description: Het RSIN van de Niet-natuurlijk persoon zijnde de organisatie + die de klantinteractie heeft gecreeerd. Dit moet een geldig RSIN zijn van + 9 nummers en voldoen aan https://nl.wikipedia.org/wiki/Burgerservicenummer#11-proef + required: false + schema: + type: string + - name: externeIdentificatie + in: query + description: De identificatie van het VERZOEK buiten de eigen organisatie. + required: false + schema: + type: string + - name: registratiedatum + in: query + description: De datum en het tijdstip waarop het VERZOEK is geregistreerd. + required: false + schema: + type: string + - name: registratiedatum__gt + in: query + description: De datum en het tijdstip waarop het VERZOEK is geregistreerd. + required: false + schema: + type: string + - name: registratiedatum__gte + in: query + description: De datum en het tijdstip waarop het VERZOEK is geregistreerd. + required: false + schema: + type: string + - name: registratiedatum__lt + in: query + description: De datum en het tijdstip waarop het VERZOEK is geregistreerd. + required: false + schema: + type: string + - name: registratiedatum__lte + in: query + description: De datum en het tijdstip waarop het VERZOEK is geregistreerd. + required: false + schema: + type: string + - name: voorkeurskanaal + in: query + description: Het communicatiekanaal dat voor opvolging van het VERZOEK de + voorkeur heeft van de KLANT. + required: false + schema: + type: string + - name: tekst + in: query + description: Een toelichting die inhoudelijk het VERZOEK van de KLANT beschrijft. + required: false + schema: + type: string + - name: status + in: query + description: De waarden van de typering van de voortgang van afhandeling van + een VERZOEK. + required: false + schema: + type: string + enum: + - ontvangen + - in_behandeling + - afgehandeld + - afgewezen + - ingetrokken + - name: inTeTrekkenVerzoek + in: query + description: URL-referentie naar het (eerdere) VERZOEK dat door dit VERZOEK + wordt verzocht ingetrokken te worden. + required: false + schema: + type: string + format: uri + - name: intrekkendeVerzoek + in: query + description: URL-referentie naar het (latere) VERZOEK waarin verzocht wordt + dit VERZOEK in te trekken. Dit veld is alleen leesbaar en wordt automatisch + gezet wanneer er een ander VERZOEK wordt aangemaakt dat dit VERZOEK intrekt. + required: false + schema: + type: string + format: uri + - name: aangevuldeVerzoek + in: query + description: URL-referentie naar het (eerdere) VERZOEK dat door dit VERZOEK + wordt aangevuld. + required: false + schema: + type: string + format: uri + - name: aanvullendeVerzoek + in: query + description: URL-referentie naar het (latere) VERZOEK waarin dit VERZOEK wordt + aangevuld. Dit veld is alleen leesbaar en wordt automatisch gezet indien + een ander VERZOEK wordt aangemaakt dat dit VERZOEK aanvult. + required: false + schema: + type: string + format: uri - name: page in: query description: Een pagina binnen de gepagineerde set resultaten. @@ -2060,6 +2171,18 @@ paths: type: array items: $ref: '#/components/schemas/Verzoek' + '400': + description: Bad request + headers: + API-version: + schema: + type: string + description: 'Geeft een specifieke API-versie aan in de context van + een specifieke aanroep. Voorbeeld: 1.2.1.' + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ValidatieFout' '401': description: Unauthorized headers: diff --git a/src/swagger2.0.json b/src/swagger2.0.json index db8ad16..6ed7c82 100644 --- a/src/swagger2.0.json +++ b/src/swagger2.0.json @@ -2347,6 +2347,122 @@ "summary": "Alle VERZOEKen opvragen.", "description": "Alle VERZOEKen opvragen.", "parameters": [ + { + "name": "identificatie", + "in": "query", + "description": "De unieke identificatie van het VERZOEK binnen de organisatie die verantwoordelijk is voor de behandeling van het VERZOEK.", + "required": false, + "type": "string" + }, + { + "name": "bronorganisatie", + "in": "query", + "description": "Het RSIN van de Niet-natuurlijk persoon zijnde de organisatie die de klantinteractie heeft gecreeerd. Dit moet een geldig RSIN zijn van 9 nummers en voldoen aan https://nl.wikipedia.org/wiki/Burgerservicenummer#11-proef", + "required": false, + "type": "string" + }, + { + "name": "externeIdentificatie", + "in": "query", + "description": "De identificatie van het VERZOEK buiten de eigen organisatie.", + "required": false, + "type": "string" + }, + { + "name": "registratiedatum", + "in": "query", + "description": "De datum en het tijdstip waarop het VERZOEK is geregistreerd.", + "required": false, + "type": "string" + }, + { + "name": "registratiedatum__gt", + "in": "query", + "description": "De datum en het tijdstip waarop het VERZOEK is geregistreerd.", + "required": false, + "type": "string" + }, + { + "name": "registratiedatum__gte", + "in": "query", + "description": "De datum en het tijdstip waarop het VERZOEK is geregistreerd.", + "required": false, + "type": "string" + }, + { + "name": "registratiedatum__lt", + "in": "query", + "description": "De datum en het tijdstip waarop het VERZOEK is geregistreerd.", + "required": false, + "type": "string" + }, + { + "name": "registratiedatum__lte", + "in": "query", + "description": "De datum en het tijdstip waarop het VERZOEK is geregistreerd.", + "required": false, + "type": "string" + }, + { + "name": "voorkeurskanaal", + "in": "query", + "description": "Het communicatiekanaal dat voor opvolging van het VERZOEK de voorkeur heeft van de KLANT.", + "required": false, + "type": "string" + }, + { + "name": "tekst", + "in": "query", + "description": "Een toelichting die inhoudelijk het VERZOEK van de KLANT beschrijft.", + "required": false, + "type": "string" + }, + { + "name": "status", + "in": "query", + "description": "De waarden van de typering van de voortgang van afhandeling van een VERZOEK.", + "required": false, + "type": "string", + "enum": [ + "ontvangen", + "in_behandeling", + "afgehandeld", + "afgewezen", + "ingetrokken" + ] + }, + { + "name": "inTeTrekkenVerzoek", + "in": "query", + "description": "URL-referentie naar het (eerdere) VERZOEK dat door dit VERZOEK wordt verzocht ingetrokken te worden.", + "required": false, + "type": "string", + "format": "uri" + }, + { + "name": "intrekkendeVerzoek", + "in": "query", + "description": "URL-referentie naar het (latere) VERZOEK waarin verzocht wordt dit VERZOEK in te trekken. Dit veld is alleen leesbaar en wordt automatisch gezet wanneer er een ander VERZOEK wordt aangemaakt dat dit VERZOEK intrekt.", + "required": false, + "type": "string", + "format": "uri" + }, + { + "name": "aangevuldeVerzoek", + "in": "query", + "description": "URL-referentie naar het (eerdere) VERZOEK dat door dit VERZOEK wordt aangevuld.", + "required": false, + "type": "string", + "format": "uri" + }, + { + "name": "aanvullendeVerzoek", + "in": "query", + "description": "URL-referentie naar het (latere) VERZOEK waarin dit VERZOEK wordt aangevuld. Dit veld is alleen leesbaar en wordt automatisch gezet indien een ander VERZOEK wordt aangemaakt dat dit VERZOEK aanvult.", + "required": false, + "type": "string", + "format": "uri" + }, { "name": "page", "in": "query", @@ -2395,6 +2511,20 @@ } } }, + "400": { + "description": "Bad request", + "schema": { + "$ref": "#/definitions/ValidatieFout" + }, + "headers": { + "API-version": { + "schema": { + "type": "string" + }, + "description": "Geeft een specifieke API-versie aan in de context van een specifieke aanroep. Voorbeeld: 1.2.1." + } + } + }, "401": { "description": "Unauthorized", "schema": { diff --git a/src/verzoeken/api/filters.py b/src/verzoeken/api/filters.py index 7f6cc26..7d1b709 100644 --- a/src/verzoeken/api/filters.py +++ b/src/verzoeken/api/filters.py @@ -1,16 +1,65 @@ +from django.utils.translation import ugettext_lazy as _ + from django_filters import filters +from vng_api_common.filters import URLModelChoiceFilter from vng_api_common.filtersets import FilterSet from vng_api_common.utils import get_help_text from verzoeken.datamodel.models import ( KlantVerzoek, ObjectVerzoek, + Verzoek, VerzoekContactMoment, VerzoekInformatieObject, VerzoekProduct, ) +class VerzoekFilter(FilterSet): + class Meta: + model = Verzoek + fields = { + "identificatie": ["exact"], + "bronorganisatie": ["exact"], + "externe_identificatie": ["exact"], + "registratiedatum": ["exact", "gt", "gte", "lt", "lte"], + "voorkeurskanaal": ["exact"], + "tekst": ["exact"], + "status": ["exact"], + "in_te_trekken_verzoek": ["exact"], + "intrekkende_verzoek": ["exact"], + "aangevulde_verzoek": ["exact"], + "aanvullende_verzoek": ["exact"], + } + + @classmethod + def filter_for_field(cls, f, name, lookup_expr): + # Needed because `intrekkende_verzoek` and `aanvullende_verzoek` + # are reverse OneToOne relations + if f.name == "intrekkende_verzoek": + filter = URLModelChoiceFilter() + filter.field_name = "intrekkende_verzoek" + filter.extra["help_text"] = _( + "URL-referentie naar het (latere) VERZOEK waarin verzocht wordt " + "dit VERZOEK in te trekken. Dit veld is alleen leesbaar en wordt " + "automatisch gezet wanneer er een ander VERZOEK wordt aangemaakt " + "dat dit VERZOEK intrekt." + ) + filter.queryset = Verzoek.objects.all() + elif f.name == "aanvullende_verzoek": + filter = URLModelChoiceFilter() + filter.field_name = "aanvullende_verzoek" + filter.extra["help_text"] = _( + "URL-referentie naar het (latere) VERZOEK waarin dit VERZOEK " + "wordt aangevuld. Dit veld is alleen leesbaar en wordt automatisch " + "gezet indien een ander VERZOEK wordt aangemaakt dat dit VERZOEK aanvult." + ) + filter.queryset = Verzoek.objects.all() + else: + filter = super().filter_for_field(f, name, lookup_expr) + return filter + + class ObjectVerzoekFilter(FilterSet): class Meta: model = ObjectVerzoek diff --git a/src/verzoeken/api/tests/test_verzoek.py b/src/verzoeken/api/tests/test_verzoek.py index 4362afd..9332ce7 100644 --- a/src/verzoeken/api/tests/test_verzoek.py +++ b/src/verzoeken/api/tests/test_verzoek.py @@ -126,3 +126,254 @@ def test_pagination_page_param(self): self.assertEqual(response_data["count"], 2) self.assertIsNone(response_data["previous"]) self.assertIsNone(response_data["next"]) + + +class VerzoekFilterTests(JWTAuthMixin, APITestCase): + heeft_alle_autorisaties = True + maxDiff = None + + def test_filter_identificatie(self): + VerzoekFactory.create(identificatie="000000000") + VerzoekFactory.create(identificatie="123456782") + url = reverse(Verzoek) + + response = self.client.get(url, {"identificatie": "000000000"}) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + response_data = response.json() + self.assertEqual(response_data["count"], 1) + + result = response_data["results"][0] + self.assertEqual(result["identificatie"], "000000000") + + def test_filter_bronorganisatie(self): + VerzoekFactory.create(bronorganisatie="000000000") + VerzoekFactory.create(bronorganisatie="123456782") + url = reverse(Verzoek) + + response = self.client.get(url, {"bronorganisatie": "000000000"}) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + response_data = response.json() + self.assertEqual(response_data["count"], 1) + + result = response_data["results"][0] + self.assertEqual(result["bronorganisatie"], "000000000") + + def test_filter_externe_identificatie(self): + VerzoekFactory.create(externe_identificatie="000000000") + VerzoekFactory.create(externe_identificatie="123456782") + url = reverse(Verzoek) + + response = self.client.get(url, {"externe_identificatie": "000000000"}) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + response_data = response.json() + self.assertEqual(response_data["count"], 1) + + result = response_data["results"][0] + self.assertEqual(result["externeIdentificatie"], "000000000") + + def test_filter_registratiedatum(self): + VerzoekFactory.create(registratiedatum=make_aware(datetime(2019, 1, 1))) + VerzoekFactory.create(registratiedatum=make_aware(datetime(2020, 1, 1))) + url = reverse(Verzoek) + + response = self.client.get(url, {"registratiedatum": "2020-01-01T00:00:00Z"}) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + response_data = response.json() + self.assertEqual(response_data["count"], 1) + + result = response_data["results"][0] + self.assertEqual(result["registratiedatum"], "2020-01-01T00:00:00Z") + + def test_filter_registratiedatum__gt(self): + VerzoekFactory.create(registratiedatum=make_aware(datetime(2019, 1, 1))) + VerzoekFactory.create(registratiedatum=make_aware(datetime(2020, 1, 1))) + url = reverse(Verzoek) + + response = self.client.get( + url, {"registratiedatum__gt": "2019-01-01T00:00:00Z"} + ) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + response_data = response.json() + self.assertEqual(response_data["count"], 1) + + result = response_data["results"][0] + self.assertEqual(result["registratiedatum"], "2020-01-01T00:00:00Z") + + def test_filter_registratiedatum__gte(self): + VerzoekFactory.create(registratiedatum=make_aware(datetime(2019, 1, 1))) + VerzoekFactory.create(registratiedatum=make_aware(datetime(2020, 1, 1))) + url = reverse(Verzoek) + + response = self.client.get( + url, {"registratiedatum__gte": "2020-01-01T00:00:00Z"} + ) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + response_data = response.json() + self.assertEqual(response_data["count"], 1) + + result = response_data["results"][0] + self.assertEqual(result["registratiedatum"], "2020-01-01T00:00:00Z") + + def test_filter_registratiedatum__lt(self): + VerzoekFactory.create(registratiedatum=make_aware(datetime(2019, 1, 1))) + VerzoekFactory.create(registratiedatum=make_aware(datetime(2020, 1, 1))) + url = reverse(Verzoek) + + response = self.client.get( + url, {"registratiedatum__lt": "2020-01-01T00:00:00Z"} + ) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + response_data = response.json() + self.assertEqual(response_data["count"], 1) + + result = response_data["results"][0] + self.assertEqual(result["registratiedatum"], "2019-01-01T00:00:00Z") + + def test_filter_registratiedatum__lte(self): + VerzoekFactory.create(registratiedatum=make_aware(datetime(2019, 1, 1))) + VerzoekFactory.create(registratiedatum=make_aware(datetime(2020, 1, 1))) + url = reverse(Verzoek) + + response = self.client.get( + url, {"registratiedatum__lte": "2019-01-01T00:00:00Z"} + ) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + response_data = response.json() + self.assertEqual(response_data["count"], 1) + + result = response_data["results"][0] + self.assertEqual(result["registratiedatum"], "2019-01-01T00:00:00Z") + + def test_filter_voorkeurskanaal(self): + VerzoekFactory.create(voorkeurskanaal="kanaal1") + VerzoekFactory.create(voorkeurskanaal="kanaal2") + url = reverse(Verzoek) + + response = self.client.get(url, {"voorkeurskanaal": "kanaal2"}) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + response_data = response.json() + self.assertEqual(response_data["count"], 1) + + result = response_data["results"][0] + self.assertEqual(result["voorkeurskanaal"], "kanaal2") + + def test_filter_tekst(self): + VerzoekFactory.create(tekst="sometext1") + VerzoekFactory.create(tekst="sometext2") + url = reverse(Verzoek) + + response = self.client.get(url, {"tekst": "sometext2"}) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + response_data = response.json() + self.assertEqual(response_data["count"], 1) + + result = response_data["results"][0] + self.assertEqual(result["tekst"], "sometext2") + + def test_filter_status(self): + VerzoekFactory.create(status=VerzoekStatus.afgehandeld) + VerzoekFactory.create(status=VerzoekStatus.afgewezen) + url = reverse(Verzoek) + + response = self.client.get(url, {"status": VerzoekStatus.afgewezen}) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + response_data = response.json() + self.assertEqual(response_data["count"], 1) + + result = response_data["results"][0] + self.assertEqual(result["status"], VerzoekStatus.afgewezen) + + def test_filter_in_te_trekken_verzoek(self): + verzoek1, verzoek2 = VerzoekFactory.create_batch(2) + VerzoekFactory.create(in_te_trekken_verzoek=verzoek1) + verzoek3 = VerzoekFactory.create(in_te_trekken_verzoek=verzoek2) + url = reverse(Verzoek) + + response = self.client.get( + url, + {"in_te_trekken_verzoek": f"http://testserver.com{reverse(verzoek2)}"}, + HTTP_HOST="testserver.com", + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + response_data = response.json() + self.assertEqual(response_data["count"], 1) + + result = response_data["results"][0] + self.assertEqual(result["url"], f"http://testserver.com{reverse(verzoek3)}") + self.assertEqual( + result["inTeTrekkenVerzoek"], f"http://testserver.com{reverse(verzoek2)}" + ) + + def test_filter_intrekkende_verzoek(self): + verzoek1, verzoek2 = VerzoekFactory.create_batch(2) + VerzoekFactory.create(in_te_trekken_verzoek=verzoek1) + verzoek3 = VerzoekFactory.create(in_te_trekken_verzoek=verzoek2) + url = reverse(Verzoek) + + response = self.client.get( + url, + {"intrekkende_verzoek": f"http://testserver.com{reverse(verzoek3)}"}, + HTTP_HOST="testserver.com", + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + response_data = response.json() + self.assertEqual(response_data["count"], 1) + + result = response_data["results"][0] + self.assertEqual(result["url"], f"http://testserver.com{reverse(verzoek2)}") + self.assertEqual( + result["intrekkendeVerzoek"], f"http://testserver.com{reverse(verzoek3)}" + ) + + def test_filter_aangevulde_verzoek(self): + verzoek1, verzoek2 = VerzoekFactory.create_batch(2) + VerzoekFactory.create(aangevulde_verzoek=verzoek1) + verzoek3 = VerzoekFactory.create(aangevulde_verzoek=verzoek2) + url = reverse(Verzoek) + + response = self.client.get( + url, + {"aangevulde_verzoek": f"http://testserver.com{reverse(verzoek2)}"}, + HTTP_HOST="testserver.com", + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + response_data = response.json() + self.assertEqual(response_data["count"], 1) + + result = response_data["results"][0] + self.assertEqual(result["url"], f"http://testserver.com{reverse(verzoek3)}") + self.assertEqual( + result["aangevuldeVerzoek"], f"http://testserver.com{reverse(verzoek2)}" + ) + + def test_filter_aanvullende_verzoek(self): + verzoek1, verzoek2 = VerzoekFactory.create_batch(2) + VerzoekFactory.create(aangevulde_verzoek=verzoek1) + verzoek3 = VerzoekFactory.create(aangevulde_verzoek=verzoek2) + url = reverse(Verzoek) + + response = self.client.get( + url, + {"aanvullende_verzoek": f"http://testserver.com{reverse(verzoek3)}"}, + HTTP_HOST="testserver.com", + ) + self.assertEqual(response.status_code, status.HTTP_200_OK) + response_data = response.json() + self.assertEqual(response_data["count"], 1) + + result = response_data["results"][0] + self.assertEqual(result["url"], f"http://testserver.com{reverse(verzoek2)}") + self.assertEqual( + result["aanvullendeVerzoek"], f"http://testserver.com{reverse(verzoek3)}" + ) diff --git a/src/verzoeken/api/viewsets.py b/src/verzoeken/api/viewsets.py index d1273ad..ba7b421 100644 --- a/src/verzoeken/api/viewsets.py +++ b/src/verzoeken/api/viewsets.py @@ -34,6 +34,7 @@ KlantVerzoekFilter, ObjectVerzoekFilter, VerzoekContactMomentFilter, + VerzoekFilter, VerzoekInformatieObjectFilter, VerzoekProductFilter, ) @@ -98,6 +99,7 @@ class VerzoekViewSet( serializer_class = VerzoekSerializer lookup_field = "uuid" permission_classes = (AuthScopesRequired,) + filterset_class = VerzoekFilter pagination_class = PageNumberPagination required_scopes = { "list": SCOPE_VERZOEKEN_ALLES_LEZEN, diff --git a/src/verzoeken/datamodel/models.py b/src/verzoeken/datamodel/models.py index 10129a5..40fe46a 100644 --- a/src/verzoeken/datamodel/models.py +++ b/src/verzoeken/datamodel/models.py @@ -63,7 +63,7 @@ class Verzoek(APIMixin, models.Model): ) status = models.CharField( max_length=20, - choices=VerzoekStatus, + choices=VerzoekStatus.choices, help_text="De waarden van de typering van de voortgang van afhandeling van een VERZOEK.", ) in_te_trekken_verzoek = models.OneToOneField(