diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8684a0e61..f0867b97f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - test-type: [main, elastic] + test-type: [main, elastic, openklant] services: postgres: @@ -70,6 +70,8 @@ jobs: --exclude-tag=elastic elif [ "${{ matrix.test-type }}" = "elastic" ]; then coverage run -p src/manage.py test src --tag=elastic --exclude-tag=e2e + elif [ "${{ matrix.test-type }}" = "openklant" ]; then + coverage run -m pytest --block-network --record-mode=none -vvv src/openklant2 else echo "Error: Unknown test type '${{ matrix.test-type }}'" exit 1 @@ -98,7 +100,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v5 with: - python-version: "3.11" + python-version: '3.11' - name: Install coverage.py # We only need coverage, but we need to match the version that was used # to generate the coverage files. Grab it from the dependencies. @@ -110,6 +112,7 @@ jobs: run: | mv coverages/main/.coverage* . mv coverages/elastic/.coverage* . + mv coverages/openklant/.coverage* . coverage combine - name: Publish coverage report uses: codecov/codecov-action@v3 @@ -169,8 +172,7 @@ jobs: uses: actions/cache@v3 with: path: /home/runner/.cache/ms-playwright - key: - ${{ runner.os }}-${{ matrix.browser }}-playwright-${{ hashFiles('requirements/ci.txt') }} + key: ${{ runner.os }}-${{ matrix.browser }}-playwright-${{ hashFiles('requirements/ci.txt') }} - name: Install playwright deps run: playwright install --with-deps ${{ matrix.browser }} diff --git a/requirements/ci.txt b/requirements/ci.txt index 04551a979..19c6e6116 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -657,6 +657,7 @@ idna==3.7 # -r requirements/base.txt # email-validator # requests + # yarl imagesize==1.4.1 # via sphinx inflection==0.5.1 @@ -751,6 +752,8 @@ mozilla-django-oidc-db==0.14.1 # via # -c requirements/base.txt # -r requirements/base.txt +multidict==6.0.5 + # via yarl mypy-extensions==1.0.0 # via black notifications-api-common==0.2.2 @@ -890,6 +893,10 @@ pyrsistent==0.18.0 # -r requirements/base.txt # jsonschema pytest==8.1.1 + # via + # -r requirements/test-tools.in + # pytest-recording +pytest-recording==0.13.2 # via -r requirements/test-tools.in python-crontab==3.0.0 # via @@ -933,6 +940,7 @@ pyyaml==6.0 # drf-spectacular # gemma-zds-client # tablib + # vcrpy # zgw-consumers-oas qrcode==6.1 # via @@ -1088,6 +1096,10 @@ uwsgi==2.0.23 # via # -c requirements/base.txt # -r requirements/base.txt +vcrpy==6.0.1 + # via + # -r requirements/test-tools.in + # pytest-recording vine==5.1.0 # via # -c requirements/base.txt @@ -1128,6 +1140,7 @@ wrapt==1.14.1 # -r requirements/base.txt # astroid # elastic-apm + # vcrpy xlrd==2.0.1 # via # -c requirements/base.txt @@ -1147,6 +1160,8 @@ xsdata==23.8 # via # -c requirements/base.txt # -r requirements/base.txt +yarl==1.9.8 + # via vcrpy zgw-consumers==0.35.1 # via # -c requirements/base.txt diff --git a/requirements/dev.in b/requirements/dev.in index d7c284cf5..aa757d1dd 100644 --- a/requirements/dev.in +++ b/requirements/dev.in @@ -12,3 +12,7 @@ django-debug-toolbar # performance testing / profiling locust django-silk + +# VCR +pytest-recording +vcrpy diff --git a/requirements/dev.txt b/requirements/dev.txt index 3ac7b710c..3da20986d 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -735,6 +735,7 @@ idna==3.7 # -r requirements/ci.txt # email-validator # requests + # yarl imagesize==1.4.1 # via # -c requirements/ci.txt @@ -855,6 +856,11 @@ mozilla-django-oidc-db==0.14.1 # -r requirements/ci.txt msgpack==1.0.7 # via locust +multidict==6.0.5 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # yarl mypy-extensions==1.0.0 # via # -c requirements/ci.txt @@ -1032,6 +1038,12 @@ pytest==8.1.1 # via # -c requirements/ci.txt # -r requirements/ci.txt + # pytest-recording +pytest-recording==0.13.2 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # -r requirements/dev.in python-crontab==3.0.0 # via # -c requirements/ci.txt @@ -1075,6 +1087,7 @@ pyyaml==6.0 # drf-spectacular # gemma-zds-client # tablib + # vcrpy # zgw-consumers-oas pyzmq==25.1.2 # via locust @@ -1286,6 +1299,12 @@ uwsgi==2.0.23 # via # -c requirements/ci.txt # -r requirements/ci.txt +vcrpy==6.0.1 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # -r requirements/dev.in + # pytest-recording vine==5.1.0 # via # -c requirements/ci.txt @@ -1341,6 +1360,7 @@ wrapt==1.14.1 # -r requirements/ci.txt # astroid # elastic-apm + # vcrpy xlrd==2.0.1 # via # -c requirements/ci.txt @@ -1360,6 +1380,11 @@ xsdata==23.8 # via # -c requirements/ci.txt # -r requirements/ci.txt +yarl==1.9.8 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt + # vcrpy zgw-consumers==0.35.1 # via # -c requirements/ci.txt diff --git a/requirements/test-tools.in b/requirements/test-tools.in index 9e8c57b8a..80c5bbe87 100644 --- a/requirements/test-tools.in +++ b/requirements/test-tools.in @@ -24,3 +24,7 @@ pyopenssl # Debug and Docs django-extensions + +# VCR +pytest-recording +vcrpy diff --git a/src/openklant2/README.md b/src/openklant2/README.md new file mode 100644 index 000000000..a7aa0df93 --- /dev/null +++ b/src/openklant2/README.md @@ -0,0 +1,27 @@ +# Open Klant 2 API Client + +This Python package provides a client for interacting with Open Klant 2 services. It simplifies the process of making requests to the API and handling responses. + +## Usage + +```python +from openklant2 import OpenKlant2Client + +client = OpenKlant2Client(api_root="https://openklant.maykin.nl/klantinteracties", token="your_api_token") + +# Get user data +partijen = client.Partij.list() +print(partijen) +``` + +## Testing + +### Re-recording VCR cassettes + +The tests rely on VCR cassettes which are included in the repo. To dynamically create +an OpenKlant service and run the tests against it, run the following command: + +```bash +$ cd src/openklant2 +$ ./regenerate_vcr_fixtures.sh +``` diff --git a/src/openklant2/__init__.py b/src/openklant2/__init__.py new file mode 100644 index 000000000..db0d6afe5 --- /dev/null +++ b/src/openklant2/__init__.py @@ -0,0 +1,3 @@ +from openklant2.client import OpenKlant2Client + +__all__ = ["OpenKlant2Client"] diff --git a/src/openklant2/_resources/__init__.py b/src/openklant2/_resources/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/openklant2/_resources/base.py b/src/openklant2/_resources/base.py new file mode 100644 index 000000000..919238ef7 --- /dev/null +++ b/src/openklant2/_resources/base.py @@ -0,0 +1,155 @@ +import json +from typing import Any, Dict, List, Mapping, MutableMapping, TypeGuard, TypeVar, Union + +import pydantic +import requests +from ape_pie import APIClient + +from openklant2.exceptions import ( + BadRequest, + Forbidden, + InvalidJSONResponse, + NonJSONResponse, + NotFound, + ResponseError, + StructuredErrorResponse, + Unauthorized, +) +from openklant2.types.error import ( + ErrorResponseBodyValidator, + ValidationErrorResponseBodyValidator, +) + +T = TypeVar("T") + +ResourceResponse = MutableMapping[str, Any] + + +JSONPrimitive = Union[str, int, None, float] +JSONValue = Union[JSONPrimitive, "JSONObject", List["JSONValue"]] +JSONObject = Dict[str, JSONValue] + + +class ResourceMixin: + http_client: APIClient + + def __init__(self, http_client: APIClient): + self.http_client = http_client + + @staticmethod + def process_response(response: requests.Response) -> TypeGuard[JSONValue]: + response_data = None + try: + content_type = response.headers.get("Content-Type", "") + # Note: there are currently no non-JSON responses defined in the + # spec, the obvious example would be e.g. something like a blob + # download. Until such endpoints are encountered, we treat non-JSON + # as an error. + if not content_type.lower().startswith("application/json"): + raise NonJSONResponse(response) + + response_data = response.json() + except (requests.exceptions.JSONDecodeError, json.JSONDecodeError): + raise InvalidJSONResponse(response) + + match response.status_code: + case code if code >= 200 and code < 300 and response_data: + return response_data + case code if code >= 400 and code < 500 and response_data: + validator = ErrorResponseBodyValidator + exc_class = StructuredErrorResponse + match code: + case 400: + validator = ValidationErrorResponseBodyValidator + exc_class = BadRequest + case 401: + exc_class = Unauthorized + case 403: + exc_class = Forbidden + case 404: + exc_class = NotFound + case _: + pass + + try: + validator.validate_python(response_data) + raise exc_class(response, response_data) + except pydantic.ValidationError: + # JSON body, but not in an expected schema. Fall through to generic ErrorResponse + pass + case _: + pass + + raise ResponseError(response, msg="Error response") + + def _get( + self, + path: str, + headers: Mapping | None = None, + params: Mapping | None = None, + ) -> requests.Response: + + return self.http_client.request("get", path, headers=headers, params=params) + + def _post( + self, + path: str, + headers: Mapping | None = None, + params: Mapping | None = None, + data: Any = None, + ) -> requests.Response: + return self.http_client.request( + "post", path, headers=headers, json=data, params=params + ) + + def _put( + self, + path: str, + headers: Mapping | None = None, + params: Mapping | None = None, + data: Any = None, + ) -> requests.Response: + return self.http_client.request( + "put", path, headers=headers, json=data, params=params + ) + + def _delete( + self, + path: str, + headers: Mapping | None = None, + params: Mapping | None = None, + ) -> requests.Response: + return self.http_client.request( + "delete", + path, + headers=headers, + params=params, + ) + + def _patch( + self, + path: str, + headers: Mapping | None = None, + params: Mapping | None = None, + data: Any = None, + ) -> requests.Response: + return self.http_client.request( + "patch", + path, + headers=headers, + params=params, + json=data, + ) + + def _options( + self, + path: str, + headers: Mapping | None = None, + params: Mapping | None = None, + ) -> requests.Response: + return self.http_client.request( + "delete", + path, + headers=headers, + params=params, + ) diff --git a/src/openklant2/_resources/digitaal_adres.py b/src/openklant2/_resources/digitaal_adres.py new file mode 100644 index 000000000..5bd78d0d7 --- /dev/null +++ b/src/openklant2/_resources/digitaal_adres.py @@ -0,0 +1,37 @@ +import uuid +from typing import cast + +from ape_pie import APIClient + +from openklant2._resources.base import ResourceMixin +from openklant2.types.pagination import PaginatedResponseBody +from openklant2.types.resources.digitaal_adres import ( + CreateDigitaalAdresData, + DigitaalAdres, + ListDigitaalAdresParams, +) + + +class DigitaalAdresResource(ResourceMixin): + http_client: APIClient + base_path: str = "/digitaleadressen" + + def list( + self, *, params: ListDigitaalAdresParams | None = None + ) -> PaginatedResponseBody[DigitaalAdres]: + response = self._get(self.base_path, params=params) + return cast( + PaginatedResponseBody[DigitaalAdres], self.process_response(response) + ) + + def retrieve(self, /, uuid: str | uuid.UUID) -> DigitaalAdres: + response = self._get(f"{self.base_path}/{str(uuid)}") + return cast(DigitaalAdres, self.process_response(response)) + + def create( + self, + *, + data: CreateDigitaalAdresData, + ) -> DigitaalAdres: + response = self._post(self.base_path, data=data) + return cast(DigitaalAdres, self.process_response(response)) diff --git a/src/openklant2/_resources/partij.py b/src/openklant2/_resources/partij.py new file mode 100644 index 000000000..c97cbe74e --- /dev/null +++ b/src/openklant2/_resources/partij.py @@ -0,0 +1,62 @@ +import uuid +from typing import Optional, cast + +from ape_pie import APIClient + +from openklant2._resources.base import ResourceMixin +from openklant2.types.pagination import PaginatedResponseBody +from openklant2.types.resources.partij import ( + CreatePartijContactpersoonData, + CreatePartijOrganisatieData, + CreatePartijPersoonData, + Partij, + PartijListParams, + PartijRetrieveParams, +) + + +class PartijResource(ResourceMixin): + http_client: APIClient + base_path: str = "/partijen" + + def list( + self, *, params: PartijListParams | None = None + ) -> PaginatedResponseBody[Partij]: + response = self._get(self.base_path, params=params) + return cast(PaginatedResponseBody[Partij], self.process_response(response)) + + def retrieve( + self, /, uuid: str | uuid.UUID, *, params: Optional[PartijRetrieveParams] = None + ) -> Partij: + response = self._get(f"{self.base_path}/{str(uuid)}", params=params) + return cast(Partij, self.process_response(response)) + + # Partij is polymorphic on "soortPartij", with varying fields for Persoon, Organisatie and ContactPersoon + def create_organisatie(self, *, data: CreatePartijOrganisatieData) -> Partij: + return self._create(data=data) + + def create_persoon( + self, + *, + data: CreatePartijPersoonData, + ) -> Partij: + return cast(Partij, self._create(data=data)) + + def create_contactpersoon( + self, + *, + data: CreatePartijContactpersoonData, + ) -> Partij: + return cast(Partij, self._create(data=data)) + + def _create( + self, + *, + data: ( + CreatePartijPersoonData + | CreatePartijOrganisatieData + | CreatePartijContactpersoonData + ), + ) -> Partij: + response = self._post(self.base_path, data=data) + return cast(Partij, self.process_response(response)) diff --git a/src/openklant2/_resources/partij_identificator.py b/src/openklant2/_resources/partij_identificator.py new file mode 100644 index 000000000..39f095b9b --- /dev/null +++ b/src/openklant2/_resources/partij_identificator.py @@ -0,0 +1,37 @@ +import uuid +from typing import cast + +from ape_pie import APIClient + +from openklant2._resources.base import ResourceMixin +from openklant2.types.pagination import PaginatedResponseBody +from openklant2.types.resources.partij_identificator import ( + CreatePartijIdentificatorData, + ListPartijIdentificatorenParams, + PartijIdentificator, +) + + +class PartijIdentificatorResource(ResourceMixin): + http_client: APIClient + base_path: str = "/partij-identificatoren" + + def list( + self, *, params: ListPartijIdentificatorenParams | None = None + ) -> PaginatedResponseBody[PartijIdentificator]: + response = self._get(self.base_path, params=params) + return cast( + PaginatedResponseBody[PartijIdentificator], self.process_response(response) + ) + + def retrieve(self, /, uuid: str | uuid.UUID) -> PartijIdentificator: + response = self._get(f"{self.base_path}/{str(uuid)}") + return cast(PartijIdentificator, self.process_response(response)) + + def create( + self, + *, + data: CreatePartijIdentificatorData, + ) -> PartijIdentificator: + response = self._post(self.base_path, data=data) + return cast(PartijIdentificator, self.process_response(response)) diff --git a/src/openklant2/client.py b/src/openklant2/client.py new file mode 100644 index 000000000..23ac02526 --- /dev/null +++ b/src/openklant2/client.py @@ -0,0 +1,20 @@ +from ape_pie import APIClient + +from openklant2._resources.digitaal_adres import DigitaalAdresResource +from openklant2._resources.partij import PartijResource +from openklant2._resources.partij_identificator import PartijIdentificatorResource + + +class OpenKlant2Client: + http_client: APIClient + partij: PartijResource + + def __init__(self, token: str, api_root: str): + self.http_client = APIClient( + request_kwargs={"headers": {"Authorization": f"Token {token}"}}, + base_url=api_root, + ) + + self.partij = PartijResource(self.http_client) + self.partij_identificator = PartijIdentificatorResource(self.http_client) + self.digitaal_adres = DigitaalAdresResource(self.http_client) diff --git a/src/openklant2/docker-compose.yaml b/src/openklant2/docker-compose.yaml new file mode 100644 index 000000000..cfa375a3a --- /dev/null +++ b/src/openklant2/docker-compose.yaml @@ -0,0 +1,36 @@ +# This docker-compose is used internally in the testsuite to dynamically spin up +# an OpenKlant2 backend, seed it with known data, and record VCR fixtures. Be +# sure to verify any changes here are consistent with +version: '3' + +services: + db: + image: postgres + environment: + - POSTGRES_HOST_AUTH_METHOD=trust + + web: + image: maykinmedia/open-klant:${OPEN_KLANT_IMAGE_TAG:-latest} + environment: &web-env + - DJANGO_SETTINGS_MODULE=openklant.conf.docker + - IS_HTTPS=no + - DB_NAME=postgres + - DB_USER=postgres + - DB_HOST=db + - ALLOWED_HOSTS=* + - CACHE_DEFAULT=redis:6379/0 + - CACHE_AXES=redis:6379/0 + - SUBPATH=${SUBPATH:-/} + - SECRET_KEY=${SECRET_KEY:-django-insecure-f8s@b*ds4t84-q_2#c0j0506@!l2q6r5_pq5e!vm^_9c*#^66b} + - CELERY_BROKER_URL=redis://redis:6379/0 + - CELERY_RESULT_BACKEND=redis://redis:6379/0 + - DISABLE_2FA=true + ports: + # Use a somewhat arbitrary port to avoid clashes + - 8338:8000 + depends_on: + - db + - redis + + redis: + image: redis diff --git a/src/openklant2/exceptions.py b/src/openklant2/exceptions.py new file mode 100644 index 000000000..f90184e33 --- /dev/null +++ b/src/openklant2/exceptions.py @@ -0,0 +1,112 @@ +import pprint +from typing import Literal, cast + +from requests import Response + +from openklant2.types.error import ( + ErrorResponseBody, + InvalidParam, + ValidationErrorResponseBody, +) + + +class OpenKlant2Exception(Exception): + """Base exception for all client-related errors.""" + + pass + + +class ResponseError(OpenKlant2Exception): + """A response was received, but it was erroneous in some aspect.""" + + response: Response + + def __init__(self, response: Response, msg: str): + self.response = response + super().__init__(msg) + + +class NonJSONResponse(ResponseError): + """Response was unexpectedly not in JSON.""" + + def __init__(self, response: Response): + super().__init__( + response, + f"The content type of this response was {response.headers.get('Content-Type')}, but " + " application/json was expected.", + ) + + +class InvalidJSONResponse(ResponseError): + """Response was marked as JSON but contained malformed content.""" + + def __init__(self, response: Response): + super().__init__( + response, + "The response content-type was marked as JSON, but cannot be decoded", + ) + + +class StructuredErrorResponse(ResponseError): + """An error response with a well-known JSON object describing the error.""" + + type: str + code: str + title: str + status: int + detail: str + instance: str + + def __init__(self, response: Response, body: ErrorResponseBody): + self.type = body["type"] + self.code = body["code"] + self.title = body["title"] + self.status = body["status"] + self.detail = body["detail"] + self.instance = body["instance"] + + super().__init__( + response, + f'status={self.status} code={self.code} title="{self.title}"', + ) + + +class ClientError(StructuredErrorResponse): + pass + + +class BadRequest(ClientError): + code: Literal[400] + invalidParams: list[InvalidParam] + + def __init__(self, response: Response, body: ValidationErrorResponseBody): + self.invalidParams = body["invalidParams"] + + invalid_params_formatted = "" + if self.invalidParams: + invalid_params_formatted = "\nInvalid parameters:\n" + invalid_params_formatted += "\n".join( + pprint.pformat(param) for param in self.invalidParams + ) + + StructuredErrorResponse.__init__( + self, + response, + cast(ErrorResponseBody, body), + ) + OpenKlant2Exception.__init__( + self, + f'status={body["status"]} code={body["status"]} title="{body["title"]}":{invalid_params_formatted}', + ) + + +class NotFound(ClientError): + code: Literal[404] + + +class Unauthorized(ClientError): + code: Literal[401] + + +class Forbidden(ClientError): + code: Literal[403] diff --git a/src/openklant2/factories/__init__.py b/src/openklant2/factories/__init__.py new file mode 100644 index 000000000..52b6b8169 --- /dev/null +++ b/src/openklant2/factories/__init__.py @@ -0,0 +1,11 @@ +from .partij import ( + CreatePartijContactPersoonDataFactory, + CreatePartijOrganisatieDataFactory, + CreatePartijPersoonDataFactory, +) + +__all__ = [ + "CreatePartijPersoonDataFactory", + "CreatePartijOrganisatieDataFactory", + "CreatePartijContactPersoonDataFactory", +] diff --git a/src/openklant2/factories/common.py b/src/openklant2/factories/common.py new file mode 100644 index 000000000..7b3dd5ed0 --- /dev/null +++ b/src/openklant2/factories/common.py @@ -0,0 +1,9 @@ +import factory +import factory.faker + + +class ForeignKeyRef(factory.Factory): + class Meta: + model = dict + + uuid = factory.Faker("uuid4") diff --git a/src/openklant2/factories/digitaal_adres.py b/src/openklant2/factories/digitaal_adres.py new file mode 100644 index 000000000..5a3ae1bb3 --- /dev/null +++ b/src/openklant2/factories/digitaal_adres.py @@ -0,0 +1,18 @@ +import factory +import factory.faker + +from openklant2.factories.common import ForeignKeyRef +from openklant2.factories.helpers import validator +from openklant2.types.resources.digitaal_adres import CreateDigitaalAdresDataValidator + + +@validator(CreateDigitaalAdresDataValidator) +class CreateDigitaalAdresDataFactory(factory.Factory): + class Meta: + model = dict + + adres = factory.Faker("address") + omschrijving = factory.Faker("word") + soortDigitaalAdres = factory.Faker("word") + verstrektDoorBetrokkene = factory.SubFactory(ForeignKeyRef) + verstrektDoorPartij = factory.SubFactory(ForeignKeyRef) diff --git a/src/openklant2/factories/helpers.py b/src/openklant2/factories/helpers.py new file mode 100644 index 000000000..4c00b0713 --- /dev/null +++ b/src/openklant2/factories/helpers.py @@ -0,0 +1,15 @@ +import factory +from pydantic import TypeAdapter + + +def validator(validator: TypeAdapter): + def decorator(cls: type[factory.Factory]): + @factory.post_generation + def validate(obj, *args, **kwargs): + validator.validate_python(obj) + + setattr(cls, "post_generation_validator", validate) + + return cls + + return decorator diff --git a/src/openklant2/factories/partij.py b/src/openklant2/factories/partij.py new file mode 100644 index 000000000..a6361c281 --- /dev/null +++ b/src/openklant2/factories/partij.py @@ -0,0 +1,88 @@ +import factory +import factory.faker +from factory import fuzzy + +from openklant2.factories.common import ForeignKeyRef +from openklant2.factories.helpers import validator +from openklant2.types.iso_639_2 import LanguageCode +from openklant2.types.resources.partij import ( + CreatePartijContactpersoonDataValidator, + CreatePartijOrganisatieDataValidator, + CreatePartijPersoonDataValidator, +) + + +class ContactnaamFactory(factory.Factory): + class Meta: + model = dict + + voorletters = factory.Faker("prefix") + voornaam = factory.Faker("first_name") + voorvoegselAchternaam = factory.Faker("prefix") + achternaam = factory.Faker("last_name") + + +class PartijIdentificatieOrganisatieFactory(factory.Factory): + class Meta: + model = dict + + naam = factory.Faker("company") + + +class PartijIdentificatiePersoonFactory(factory.Factory): + class Meta: + model = dict + + contactnaam = factory.SubFactory(ContactnaamFactory) + + +class PartijIdentificatieContactpersoonFactory(factory.Factory): + class Meta: + model = dict + + class Params: + werkte_voor_partij = None + + contactnaam = factory.SubFactory(ContactnaamFactory) + werkteVoorPartij = factory.SubFactory(ForeignKeyRef) + + +class CreatePartijBaseFactory(factory.Factory): + class Meta: + model = dict + abstract = True + + digitaleAdressen = None + voorkeursDigitaalAdres = None + rekeningnummers = None + voorkeursRekeningnummer = None + indicatieGeheimhouding = fuzzy.FuzzyChoice([True, False]) + indicatieActief = fuzzy.FuzzyChoice([True, False]) + voorkeurstaal = fuzzy.FuzzyChoice(LanguageCode.__args__) + + +@validator(CreatePartijPersoonDataValidator) +class CreatePartijPersoonDataFactory(CreatePartijBaseFactory): + class Meta: + model = dict + + soortPartij = "persoon" + partijIdentificatie = factory.SubFactory(PartijIdentificatiePersoonFactory) + + +@validator(CreatePartijOrganisatieDataValidator) +class CreatePartijOrganisatieDataFactory(CreatePartijBaseFactory): + class Meta: + model = dict + + soortPartij = "organisatie" + partijIdentificatie = factory.SubFactory(PartijIdentificatieOrganisatieFactory) + + +@validator(CreatePartijContactpersoonDataValidator) +class CreatePartijContactPersoonDataFactory(CreatePartijBaseFactory): + class Meta: + model = dict + + soortPartij = "contactpersoon" + partijIdentificatie = factory.SubFactory(PartijIdentificatieContactpersoonFactory) diff --git a/src/openklant2/regenerate_vcr_fixtures.sh b/src/openklant2/regenerate_vcr_fixtures.sh new file mode 100755 index 000000000..61adce79d --- /dev/null +++ b/src/openklant2/regenerate_vcr_fixtures.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +delete_path=$(realpath ./tests/cassettes) + +# Display the full path and ask for confirmation +echo "You are about to recursively delete all VCR cassettes from the following directory:" +echo "$delete_path" +read -p "Are you sure you want to proceed? (y/N): " confirm + +if [[ $confirm == [yY] || $confirm == [yY][eE][sS] ]]; then + echo "Deleting directory..." + rm -rf "$delete_path" + echo "Directory deleted." +else + echo "Operation cancelled." + exit 0 +fi + +pytest --with-openklant-service --record-mode=all -vvv diff --git a/src/openklant2/tests/__init__.py b/src/openklant2/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/openklant2/tests/cassettes/test_digitaal_adres/test_create_digitaal_adres.yaml b/src/openklant2/tests/cassettes/test_digitaal_adres/test_create_digitaal_adres.yaml new file mode 100644 index 000000000..cd84b470c --- /dev/null +++ b/src/openklant2/tests/cassettes/test_digitaal_adres/test_create_digitaal_adres.yaml @@ -0,0 +1,85 @@ +interactions: +- request: + body: '{"digitaleAdressen": null, "voorkeursDigitaalAdres": null, "rekeningnummers": + null, "voorkeursRekeningnummer": null, "indicatieGeheimhouding": false, "indicatieActief": + false, "voorkeurstaal": "lam", "soortPartij": "persoon", "partijIdentificatie": + {"contactnaam": {"voorletters": "Ms.", "voornaam": "Amanda", "voorvoegselAchternaam": + "Mr.", "achternaam": "Thompson"}}}' + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + Content-Length: + - '369' + Content-Type: + - application/json + method: POST + uri: http://localhost:8338/klantinteracties/api/v1/partijen + response: + body: + string: '{"uuid":"d25fe744-1d32-4854-a644-d916bb89e7ca","url":"http://localhost:8338/klantinteracties/api/v1/partijen/d25fe744-1d32-4854-a644-d916bb89e7ca","nummer":"0000000001","interneNotitie":"","betrokkenen":[],"categorieRelaties":[],"digitaleAdressen":[],"voorkeursDigitaalAdres":null,"vertegenwoordigden":[],"rekeningnummers":[],"voorkeursRekeningnummer":null,"partijIdentificatoren":[],"soortPartij":"persoon","indicatieGeheimhouding":false,"voorkeurstaal":"lam","indicatieActief":false,"bezoekadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"correspondentieadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"partijIdentificatie":{"contactnaam":{"voorletters":"Ms.","voornaam":"Amanda","voorvoegselAchternaam":"Mr.","achternaam":"Thompson"},"volledigeNaam":"Amanda + Mr. Thompson"}}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '868' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Location: + - http://localhost:8338/klantinteracties/api/v1/partijen/d25fe744-1d32-4854-a644-d916bb89e7ca + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 201 + message: Created +- request: + body: '{"verstrektDoorBetrokkene": null, "verstrektDoorPartij": {"uuid": "d25fe744-1d32-4854-a644-d916bb89e7ca"}, + "adres": "foo@bar.com", "omschrijving": "professional", "soortDigitaalAdres": + "email"}' + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + Content-Length: + - '193' + Content-Type: + - application/json + method: POST + uri: http://localhost:8338/klantinteracties/api/v1/digitaleadressen + response: + body: + string: '{"uuid":"b79b550d-6dee-4340-aee7-3a61d73fc170","url":"http://localhost:8338/klantinteracties/api/v1/digitaleadressen/b79b550d-6dee-4340-aee7-3a61d73fc170","verstrektDoorBetrokkene":null,"verstrektDoorPartij":{"uuid":"d25fe744-1d32-4854-a644-d916bb89e7ca","url":"http://localhost:8338/klantinteracties/api/v1/partijen/d25fe744-1d32-4854-a644-d916bb89e7ca"},"adres":"foo@bar.com","soortDigitaalAdres":"email","omschrijving":"professional"}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '437' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Location: + - http://localhost:8338/klantinteracties/api/v1/digitaleadressen/b79b550d-6dee-4340-aee7-3a61d73fc170 + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 201 + message: Created +version: 1 diff --git a/src/openklant2/tests/cassettes/test_digitaal_adres/test_list_digitaal_adres.yaml b/src/openklant2/tests/cassettes/test_digitaal_adres/test_list_digitaal_adres.yaml new file mode 100644 index 000000000..c81eb300e --- /dev/null +++ b/src/openklant2/tests/cassettes/test_digitaal_adres/test_list_digitaal_adres.yaml @@ -0,0 +1,119 @@ +interactions: +- request: + body: '{"digitaleAdressen": null, "voorkeursDigitaalAdres": null, "rekeningnummers": + null, "voorkeursRekeningnummer": null, "indicatieGeheimhouding": true, "indicatieActief": + false, "voorkeurstaal": "kam", "soortPartij": "persoon", "partijIdentificatie": + {"contactnaam": {"voorletters": "Mr.", "voornaam": "Sara", "voorvoegselAchternaam": + "Ms.", "achternaam": "Gonzalez"}}}' + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + Content-Length: + - '366' + Content-Type: + - application/json + method: POST + uri: http://localhost:8338/klantinteracties/api/v1/partijen + response: + body: + string: '{"uuid":"71ab1bf9-ec22-4227-afcc-b126af6e42cc","url":"http://localhost:8338/klantinteracties/api/v1/partijen/71ab1bf9-ec22-4227-afcc-b126af6e42cc","nummer":"0000000001","interneNotitie":"","betrokkenen":[],"categorieRelaties":[],"digitaleAdressen":[],"voorkeursDigitaalAdres":null,"vertegenwoordigden":[],"rekeningnummers":[],"voorkeursRekeningnummer":null,"partijIdentificatoren":[],"soortPartij":"persoon","indicatieGeheimhouding":true,"voorkeurstaal":"kam","indicatieActief":false,"bezoekadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"correspondentieadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"partijIdentificatie":{"contactnaam":{"voorletters":"Mr.","voornaam":"Sara","voorvoegselAchternaam":"Ms.","achternaam":"Gonzalez"},"volledigeNaam":"Sara + Ms. Gonzalez"}}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '863' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Location: + - http://localhost:8338/klantinteracties/api/v1/partijen/71ab1bf9-ec22-4227-afcc-b126af6e42cc + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 201 + message: Created +- request: + body: '{"adres": "57418 Steven Well\nRyanville, FM 15879", "omschrijving": "moment", + "soortDigitaalAdres": "first", "verstrektDoorBetrokkene": null, "verstrektDoorPartij": + {"uuid": "71ab1bf9-ec22-4227-afcc-b126af6e42cc"}}' + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + Content-Length: + - '214' + Content-Type: + - application/json + method: POST + uri: http://localhost:8338/klantinteracties/api/v1/digitaleadressen + response: + body: + string: '{"uuid":"daa22885-087e-4c83-b866-6dccc7f7780d","url":"http://localhost:8338/klantinteracties/api/v1/digitaleadressen/daa22885-087e-4c83-b866-6dccc7f7780d","verstrektDoorBetrokkene":null,"verstrektDoorPartij":{"uuid":"71ab1bf9-ec22-4227-afcc-b126af6e42cc","url":"http://localhost:8338/klantinteracties/api/v1/partijen/71ab1bf9-ec22-4227-afcc-b126af6e42cc"},"adres":"57418 + Steven Well\nRyanville, FM 15879","soortDigitaalAdres":"first","omschrijving":"moment"}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '458' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Location: + - http://localhost:8338/klantinteracties/api/v1/digitaleadressen/daa22885-087e-4c83-b866-6dccc7f7780d + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 201 + message: Created +- request: + body: null + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + method: GET + uri: http://localhost:8338/klantinteracties/api/v1/digitaleadressen + response: + body: + string: '{"count":1,"next":null,"previous":null,"results":[{"uuid":"daa22885-087e-4c83-b866-6dccc7f7780d","url":"http://localhost:8338/klantinteracties/api/v1/digitaleadressen/daa22885-087e-4c83-b866-6dccc7f7780d","verstrektDoorBetrokkene":null,"verstrektDoorPartij":{"uuid":"71ab1bf9-ec22-4227-afcc-b126af6e42cc","url":"http://localhost:8338/klantinteracties/api/v1/partijen/71ab1bf9-ec22-4227-afcc-b126af6e42cc"},"adres":"57418 + Steven Well\nRyanville, FM 15879","soortDigitaalAdres":"first","omschrijving":"moment","_expand":{}}]}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '523' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 200 + message: OK +version: 1 diff --git a/src/openklant2/tests/cassettes/test_digitaal_adres/test_retrieve_digitaal_adres.yaml b/src/openklant2/tests/cassettes/test_digitaal_adres/test_retrieve_digitaal_adres.yaml new file mode 100644 index 000000000..09a272bf5 --- /dev/null +++ b/src/openklant2/tests/cassettes/test_digitaal_adres/test_retrieve_digitaal_adres.yaml @@ -0,0 +1,119 @@ +interactions: +- request: + body: '{"digitaleAdressen": null, "voorkeursDigitaalAdres": null, "rekeningnummers": + null, "voorkeursRekeningnummer": null, "indicatieGeheimhouding": false, "indicatieActief": + true, "voorkeurstaal": "nbl", "soortPartij": "persoon", "partijIdentificatie": + {"contactnaam": {"voorletters": "Mrs.", "voornaam": "Amy", "voorvoegselAchternaam": + "Ms.", "achternaam": "Carr"}}}' + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + Content-Length: + - '362' + Content-Type: + - application/json + method: POST + uri: http://localhost:8338/klantinteracties/api/v1/partijen + response: + body: + string: '{"uuid":"fed3a630-ac73-4ee0-9766-a8da217adc66","url":"http://localhost:8338/klantinteracties/api/v1/partijen/fed3a630-ac73-4ee0-9766-a8da217adc66","nummer":"0000000001","interneNotitie":"","betrokkenen":[],"categorieRelaties":[],"digitaleAdressen":[],"voorkeursDigitaalAdres":null,"vertegenwoordigden":[],"rekeningnummers":[],"voorkeursRekeningnummer":null,"partijIdentificatoren":[],"soortPartij":"persoon","indicatieGeheimhouding":false,"voorkeurstaal":"nbl","indicatieActief":true,"bezoekadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"correspondentieadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"partijIdentificatie":{"contactnaam":{"voorletters":"Mrs.","voornaam":"Amy","voorvoegselAchternaam":"Ms.","achternaam":"Carr"},"volledigeNaam":"Amy + Ms. Carr"}}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '854' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Location: + - http://localhost:8338/klantinteracties/api/v1/partijen/fed3a630-ac73-4ee0-9766-a8da217adc66 + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 201 + message: Created +- request: + body: '{"adres": "501 Acosta Place Suite 226\nAnnafurt, GA 19642", "omschrijving": + "treat", "soortDigitaalAdres": "occur", "verstrektDoorBetrokkene": null, "verstrektDoorPartij": + {"uuid": "fed3a630-ac73-4ee0-9766-a8da217adc66"}}' + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + Content-Length: + - '221' + Content-Type: + - application/json + method: POST + uri: http://localhost:8338/klantinteracties/api/v1/digitaleadressen + response: + body: + string: '{"uuid":"894299a7-bbe9-421f-a2e9-ed9c06be5e8e","url":"http://localhost:8338/klantinteracties/api/v1/digitaleadressen/894299a7-bbe9-421f-a2e9-ed9c06be5e8e","verstrektDoorBetrokkene":null,"verstrektDoorPartij":{"uuid":"fed3a630-ac73-4ee0-9766-a8da217adc66","url":"http://localhost:8338/klantinteracties/api/v1/partijen/fed3a630-ac73-4ee0-9766-a8da217adc66"},"adres":"501 + Acosta Place Suite 226\nAnnafurt, GA 19642","soortDigitaalAdres":"occur","omschrijving":"treat"}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '465' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Location: + - http://localhost:8338/klantinteracties/api/v1/digitaleadressen/894299a7-bbe9-421f-a2e9-ed9c06be5e8e + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 201 + message: Created +- request: + body: null + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + method: GET + uri: http://localhost:8338/klantinteracties/api/v1/digitaleadressen/894299a7-bbe9-421f-a2e9-ed9c06be5e8e + response: + body: + string: '{"uuid":"894299a7-bbe9-421f-a2e9-ed9c06be5e8e","url":"http://localhost:8338/klantinteracties/api/v1/digitaleadressen/894299a7-bbe9-421f-a2e9-ed9c06be5e8e","verstrektDoorBetrokkene":null,"verstrektDoorPartij":{"uuid":"fed3a630-ac73-4ee0-9766-a8da217adc66","url":"http://localhost:8338/klantinteracties/api/v1/partijen/fed3a630-ac73-4ee0-9766-a8da217adc66"},"adres":"501 + Acosta Place Suite 226\nAnnafurt, GA 19642","soortDigitaalAdres":"occur","omschrijving":"treat"}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, PUT, PATCH, DELETE, HEAD, OPTIONS + Content-Length: + - '465' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 200 + message: OK +version: 1 diff --git a/src/openklant2/tests/cassettes/test_partij/test_create_contactpersoon.yaml b/src/openklant2/tests/cassettes/test_partij/test_create_contactpersoon.yaml new file mode 100644 index 000000000..7a4625c6d --- /dev/null +++ b/src/openklant2/tests/cassettes/test_partij/test_create_contactpersoon.yaml @@ -0,0 +1,85 @@ +interactions: +- request: + body: '{"digitaleAdressen": null, "voorkeursDigitaalAdres": null, "rekeningnummers": + null, "voorkeursRekeningnummer": null, "indicatieGeheimhouding": false, "indicatieActief": + true, "voorkeurstaal": "tiv", "soortPartij": "organisatie", "partijIdentificatie": + {"naam": "Test Organisatie"}}' + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + Content-Length: + - '281' + Content-Type: + - application/json + method: POST + uri: http://localhost:8338/klantinteracties/api/v1/partijen + response: + body: + string: '{"uuid":"b742bf52-b6ed-41ea-a5f0-51677af6804d","url":"http://localhost:8338/klantinteracties/api/v1/partijen/b742bf52-b6ed-41ea-a5f0-51677af6804d","nummer":"0000000001","interneNotitie":"","betrokkenen":[],"categorieRelaties":[],"digitaleAdressen":[],"voorkeursDigitaalAdres":null,"vertegenwoordigden":[],"rekeningnummers":[],"voorkeursRekeningnummer":null,"partijIdentificatoren":[],"soortPartij":"organisatie","indicatieGeheimhouding":false,"voorkeurstaal":"tiv","indicatieActief":true,"bezoekadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"correspondentieadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"partijIdentificatie":{"naam":"Test + Organisatie"}}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '749' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Location: + - http://localhost:8338/klantinteracties/api/v1/partijen/b742bf52-b6ed-41ea-a5f0-51677af6804d + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 201 + message: Created +- request: + body: '{"soortPartij": "contactpersoon", "digitaleAdressen": null, "rekeningnummers": + null, "voorkeursRekeningnummer": null, "voorkeurstaal": "nld", "indicatieActief": + true, "indicatieGeheimhouding": false, "voorkeursDigitaalAdres": null, "partijIdentificatie": + {"contactnaam": null, "werkteVoorPartij": {"uuid": "b742bf52-b6ed-41ea-a5f0-51677af6804d"}}}' + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + Content-Length: + - '347' + Content-Type: + - application/json + method: POST + uri: http://localhost:8338/klantinteracties/api/v1/partijen + response: + body: + string: '{"uuid":"7d014229-967c-4fda-b3a6-3be830044bb8","url":"http://localhost:8338/klantinteracties/api/v1/partijen/7d014229-967c-4fda-b3a6-3be830044bb8","nummer":"0000000002","interneNotitie":"","betrokkenen":[],"categorieRelaties":[],"digitaleAdressen":[],"voorkeursDigitaalAdres":null,"vertegenwoordigden":[],"rekeningnummers":[],"voorkeursRekeningnummer":null,"partijIdentificatoren":[],"soortPartij":"contactpersoon","indicatieGeheimhouding":false,"voorkeurstaal":"nld","indicatieActief":true,"bezoekadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"correspondentieadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"partijIdentificatie":{"uuid":"56973fe0-f12b-469a-b5dc-e0a6e8e9eb5c","werkteVoorPartij":{"uuid":"b742bf52-b6ed-41ea-a5f0-51677af6804d","url":"http://localhost:8338/klantinteracties/api/v1/partijen/b742bf52-b6ed-41ea-a5f0-51677af6804d"},"contactnaam":{"voorletters":"","voornaam":"","voorvoegselAchternaam":"","achternaam":""},"volledigeNaam":""}}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '1048' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Location: + - http://localhost:8338/klantinteracties/api/v1/partijen/7d014229-967c-4fda-b3a6-3be830044bb8 + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 201 + message: Created +version: 1 diff --git a/src/openklant2/tests/cassettes/test_partij/test_create_organisatie.yaml b/src/openklant2/tests/cassettes/test_partij/test_create_organisatie.yaml new file mode 100644 index 000000000..5cc40d4f7 --- /dev/null +++ b/src/openklant2/tests/cassettes/test_partij/test_create_organisatie.yaml @@ -0,0 +1,44 @@ +interactions: +- request: + body: '{"digitaleAdressen": null, "voorkeursDigitaalAdres": null, "rekeningnummers": + null, "voorkeursRekeningnummer": null, "voorkeurstaal": "nld", "indicatieActief": + true, "indicatieGeheimhouding": false, "soortPartij": "organisatie", "partijIdentificatie": + {"naam": "AcmeCorp Ltd"}}' + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + Content-Length: + - '277' + Content-Type: + - application/json + method: POST + uri: http://localhost:8338/klantinteracties/api/v1/partijen + response: + body: + string: '{"uuid":"6c459ca7-1829-4eea-811e-98ab56a2c2c6","url":"http://localhost:8338/klantinteracties/api/v1/partijen/6c459ca7-1829-4eea-811e-98ab56a2c2c6","nummer":"0000000001","interneNotitie":"","betrokkenen":[],"categorieRelaties":[],"digitaleAdressen":[],"voorkeursDigitaalAdres":null,"vertegenwoordigden":[],"rekeningnummers":[],"voorkeursRekeningnummer":null,"partijIdentificatoren":[],"soortPartij":"organisatie","indicatieGeheimhouding":false,"voorkeurstaal":"nld","indicatieActief":true,"bezoekadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"correspondentieadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"partijIdentificatie":{"naam":"AcmeCorp + Ltd"}}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '745' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Location: + - http://localhost:8338/klantinteracties/api/v1/partijen/6c459ca7-1829-4eea-811e-98ab56a2c2c6 + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 201 + message: Created +version: 1 diff --git a/src/openklant2/tests/cassettes/test_partij/test_create_persoon.yaml b/src/openklant2/tests/cassettes/test_partij/test_create_persoon.yaml new file mode 100644 index 000000000..139670d36 --- /dev/null +++ b/src/openklant2/tests/cassettes/test_partij/test_create_persoon.yaml @@ -0,0 +1,43 @@ +interactions: +- request: + body: '{"digitaleAdressen": null, "voorkeursDigitaalAdres": null, "rekeningnummers": + null, "voorkeursRekeningnummer": null, "voorkeurstaal": "nld", "indicatieActief": + true, "indicatieGeheimhouding": false, "soortPartij": "persoon", "partijIdentificatie": + {"contactnaam": null}}' + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + Content-Length: + - '270' + Content-Type: + - application/json + method: POST + uri: http://localhost:8338/klantinteracties/api/v1/partijen + response: + body: + string: '{"uuid":"c1016c72-80e5-4c9c-a996-4f2dea2817c6","url":"http://localhost:8338/klantinteracties/api/v1/partijen/c1016c72-80e5-4c9c-a996-4f2dea2817c6","nummer":"0000000001","interneNotitie":"","betrokkenen":[],"categorieRelaties":[],"digitaleAdressen":[],"voorkeursDigitaalAdres":null,"vertegenwoordigden":[],"rekeningnummers":[],"voorkeursRekeningnummer":null,"partijIdentificatoren":[],"soortPartij":"persoon","indicatieGeheimhouding":false,"voorkeurstaal":"nld","indicatieActief":true,"bezoekadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"correspondentieadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"partijIdentificatie":{"contactnaam":{"voorletters":"","voornaam":"","voorvoegselAchternaam":"","achternaam":""},"volledigeNaam":""}}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '828' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Location: + - http://localhost:8338/klantinteracties/api/v1/partijen/c1016c72-80e5-4c9c-a996-4f2dea2817c6 + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 201 + message: Created +version: 1 diff --git a/src/openklant2/tests/cassettes/test_partij/test_create_with_bad_request_exception.yaml b/src/openklant2/tests/cassettes/test_partij/test_create_with_bad_request_exception.yaml new file mode 100644 index 000000000..7d3eebdd2 --- /dev/null +++ b/src/openklant2/tests/cassettes/test_partij/test_create_with_bad_request_exception.yaml @@ -0,0 +1,45 @@ +interactions: +- request: + body: '{}' + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + Content-Length: + - '2' + Content-Type: + - application/json + method: POST + uri: http://localhost:8338/klantinteracties/api/v1/partijen + response: + body: + string: '{"type":"http://localhost:8338/ref/fouten/ValidationError/","code":"invalid","title":"Invalid + input.","status":400,"detail":"","instance":"urn:uuid:3dd5b8ca-9d3e-410d-8cdb-b2986117ce62","invalidParams":[{"name":"digitaleAdressen","code":"required","reason":"Dit + veld is vereist."},{"name":"voorkeursDigitaalAdres","code":"required","reason":"Dit + veld is vereist."},{"name":"rekeningnummers","code":"required","reason":"Dit + veld is vereist."},{"name":"voorkeursRekeningnummer","code":"required","reason":"Dit + veld is vereist."},{"name":"soortPartij","code":"required","reason":"Dit veld + is vereist."},{"name":"indicatieActief","code":"required","reason":"Dit veld + is vereist."}]}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '678' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 400 + message: Bad Request +version: 1 diff --git a/src/openklant2/tests/cassettes/test_partij/test_list_partijen.yaml b/src/openklant2/tests/cassettes/test_partij/test_list_partijen.yaml new file mode 100644 index 000000000..a42de8773 --- /dev/null +++ b/src/openklant2/tests/cassettes/test_partij/test_list_partijen.yaml @@ -0,0 +1,123 @@ +interactions: +- request: + body: '{"digitaleAdressen": null, "voorkeursDigitaalAdres": null, "rekeningnummers": + null, "voorkeursRekeningnummer": null, "indicatieGeheimhouding": false, "indicatieActief": + true, "voorkeurstaal": "crp", "soortPartij": "persoon", "partijIdentificatie": + {"contactnaam": {"voorletters": "Dr.", "voornaam": "Test Persoon", "voorvoegselAchternaam": + "Mrs.", "achternaam": "Gamble"}}}' + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + Content-Length: + - '373' + Content-Type: + - application/json + method: POST + uri: http://localhost:8338/klantinteracties/api/v1/partijen + response: + body: + string: '{"uuid":"6b6c2e30-258a-4861-8241-0337fccedd42","url":"http://localhost:8338/klantinteracties/api/v1/partijen/6b6c2e30-258a-4861-8241-0337fccedd42","nummer":"0000000001","interneNotitie":"","betrokkenen":[],"categorieRelaties":[],"digitaleAdressen":[],"voorkeursDigitaalAdres":null,"vertegenwoordigden":[],"rekeningnummers":[],"voorkeursRekeningnummer":null,"partijIdentificatoren":[],"soortPartij":"persoon","indicatieGeheimhouding":false,"voorkeurstaal":"crp","indicatieActief":true,"bezoekadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"correspondentieadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"partijIdentificatie":{"contactnaam":{"voorletters":"Dr.","voornaam":"Test + Persoon","voorvoegselAchternaam":"Mrs.","achternaam":"Gamble"},"volledigeNaam":"Test + Persoon Mrs. Gamble"}}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '877' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Location: + - http://localhost:8338/klantinteracties/api/v1/partijen/6b6c2e30-258a-4861-8241-0337fccedd42 + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 201 + message: Created +- request: + body: '{"digitaleAdressen": null, "voorkeursDigitaalAdres": null, "rekeningnummers": + null, "voorkeursRekeningnummer": null, "indicatieGeheimhouding": false, "indicatieActief": + true, "voorkeurstaal": "tiv", "soortPartij": "organisatie", "partijIdentificatie": + {"naam": "Test Organisatie"}}' + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + Content-Length: + - '281' + Content-Type: + - application/json + method: POST + uri: http://localhost:8338/klantinteracties/api/v1/partijen + response: + body: + string: '{"uuid":"b5245fcc-88ea-44df-b6f9-b98facc04d48","url":"http://localhost:8338/klantinteracties/api/v1/partijen/b5245fcc-88ea-44df-b6f9-b98facc04d48","nummer":"0000000002","interneNotitie":"","betrokkenen":[],"categorieRelaties":[],"digitaleAdressen":[],"voorkeursDigitaalAdres":null,"vertegenwoordigden":[],"rekeningnummers":[],"voorkeursRekeningnummer":null,"partijIdentificatoren":[],"soortPartij":"organisatie","indicatieGeheimhouding":false,"voorkeurstaal":"tiv","indicatieActief":true,"bezoekadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"correspondentieadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"partijIdentificatie":{"naam":"Test + Organisatie"}}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '749' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Location: + - http://localhost:8338/klantinteracties/api/v1/partijen/b5245fcc-88ea-44df-b6f9-b98facc04d48 + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 201 + message: Created +- request: + body: null + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + method: GET + uri: http://localhost:8338/klantinteracties/api/v1/partijen + response: + body: + string: '{"count":2,"next":null,"previous":null,"results":[{"uuid":"b5245fcc-88ea-44df-b6f9-b98facc04d48","url":"http://localhost:8338/klantinteracties/api/v1/partijen/b5245fcc-88ea-44df-b6f9-b98facc04d48","nummer":"0000000002","interneNotitie":"","betrokkenen":[],"categorieRelaties":[],"digitaleAdressen":[],"voorkeursDigitaalAdres":null,"vertegenwoordigden":[],"rekeningnummers":[],"voorkeursRekeningnummer":null,"partijIdentificatoren":[],"soortPartij":"organisatie","indicatieGeheimhouding":false,"voorkeurstaal":"tiv","indicatieActief":true,"bezoekadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"correspondentieadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"partijIdentificatie":{"naam":"Test + Organisatie"},"_expand":{}},{"uuid":"6b6c2e30-258a-4861-8241-0337fccedd42","url":"http://localhost:8338/klantinteracties/api/v1/partijen/6b6c2e30-258a-4861-8241-0337fccedd42","nummer":"0000000001","interneNotitie":"","betrokkenen":[],"categorieRelaties":[],"digitaleAdressen":[],"voorkeursDigitaalAdres":null,"vertegenwoordigden":[],"rekeningnummers":[],"voorkeursRekeningnummer":null,"partijIdentificatoren":[],"soortPartij":"persoon","indicatieGeheimhouding":false,"voorkeurstaal":"crp","indicatieActief":true,"bezoekadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"correspondentieadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"partijIdentificatie":{"contactnaam":{"voorletters":"Dr.","voornaam":"Test + Persoon","voorvoegselAchternaam":"Mrs.","achternaam":"Gamble"},"volledigeNaam":"Test + Persoon Mrs. Gamble"},"_expand":{}}]}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '1705' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 200 + message: OK +version: 1 diff --git a/src/openklant2/tests/cassettes/test_partij/test_retrieve_partij[betrokkenen.hadKlantcontact].yaml b/src/openklant2/tests/cassettes/test_partij/test_retrieve_partij[betrokkenen.hadKlantcontact].yaml new file mode 100644 index 000000000..76f85822d --- /dev/null +++ b/src/openklant2/tests/cassettes/test_partij/test_retrieve_partij[betrokkenen.hadKlantcontact].yaml @@ -0,0 +1,80 @@ +interactions: +- request: + body: '{"digitaleAdressen": null, "voorkeursDigitaalAdres": null, "rekeningnummers": + null, "voorkeursRekeningnummer": null, "indicatieGeheimhouding": false, "indicatieActief": + true, "voorkeurstaal": "crp", "soortPartij": "persoon", "partijIdentificatie": + {"contactnaam": {"voorletters": "Dr.", "voornaam": "Test Persoon", "voorvoegselAchternaam": + "Mrs.", "achternaam": "Gamble"}}}' + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + Content-Length: + - '373' + Content-Type: + - application/json + method: POST + uri: http://localhost:8338/klantinteracties/api/v1/partijen + response: + body: + string: '{"uuid":"8a40b09e-8bae-4048-8c46-e618376d01fc","url":"http://localhost:8338/klantinteracties/api/v1/partijen/8a40b09e-8bae-4048-8c46-e618376d01fc","nummer":"0000000001","interneNotitie":"","betrokkenen":[],"categorieRelaties":[],"digitaleAdressen":[],"voorkeursDigitaalAdres":null,"vertegenwoordigden":[],"rekeningnummers":[],"voorkeursRekeningnummer":null,"partijIdentificatoren":[],"soortPartij":"persoon","indicatieGeheimhouding":false,"voorkeurstaal":"crp","indicatieActief":true,"bezoekadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"correspondentieadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"partijIdentificatie":{"contactnaam":{"voorletters":"Dr.","voornaam":"Test + Persoon","voorvoegselAchternaam":"Mrs.","achternaam":"Gamble"},"volledigeNaam":"Test + Persoon Mrs. Gamble"}}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '877' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Location: + - http://localhost:8338/klantinteracties/api/v1/partijen/8a40b09e-8bae-4048-8c46-e618376d01fc + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 201 + message: Created +- request: + body: null + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + method: GET + uri: http://localhost:8338/klantinteracties/api/v1/partijen/8a40b09e-8bae-4048-8c46-e618376d01fc?expand=betrokkenen.hadKlantcontact + response: + body: + string: '{"uuid":"8a40b09e-8bae-4048-8c46-e618376d01fc","url":"http://localhost:8338/klantinteracties/api/v1/partijen/8a40b09e-8bae-4048-8c46-e618376d01fc","nummer":"0000000001","interneNotitie":"","betrokkenen":[],"categorieRelaties":[],"digitaleAdressen":[],"voorkeursDigitaalAdres":null,"vertegenwoordigden":[],"rekeningnummers":[],"voorkeursRekeningnummer":null,"partijIdentificatoren":[],"soortPartij":"persoon","indicatieGeheimhouding":false,"voorkeurstaal":"crp","indicatieActief":true,"bezoekadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"correspondentieadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"partijIdentificatie":{"contactnaam":{"voorletters":"Dr.","voornaam":"Test + Persoon","voorvoegselAchternaam":"Mrs.","achternaam":"Gamble"},"volledigeNaam":"Test + Persoon Mrs. Gamble"}}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, PUT, PATCH, DELETE, HEAD, OPTIONS + Content-Length: + - '877' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 200 + message: OK +version: 1 diff --git a/src/openklant2/tests/cassettes/test_partij/test_retrieve_partij[betrokkenen].yaml b/src/openklant2/tests/cassettes/test_partij/test_retrieve_partij[betrokkenen].yaml new file mode 100644 index 000000000..597ba65e1 --- /dev/null +++ b/src/openklant2/tests/cassettes/test_partij/test_retrieve_partij[betrokkenen].yaml @@ -0,0 +1,80 @@ +interactions: +- request: + body: '{"digitaleAdressen": null, "voorkeursDigitaalAdres": null, "rekeningnummers": + null, "voorkeursRekeningnummer": null, "indicatieGeheimhouding": false, "indicatieActief": + true, "voorkeurstaal": "crp", "soortPartij": "persoon", "partijIdentificatie": + {"contactnaam": {"voorletters": "Dr.", "voornaam": "Test Persoon", "voorvoegselAchternaam": + "Mrs.", "achternaam": "Gamble"}}}' + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + Content-Length: + - '373' + Content-Type: + - application/json + method: POST + uri: http://localhost:8338/klantinteracties/api/v1/partijen + response: + body: + string: '{"uuid":"40e6c3e8-25ee-4d34-9b16-0fb13320c8d6","url":"http://localhost:8338/klantinteracties/api/v1/partijen/40e6c3e8-25ee-4d34-9b16-0fb13320c8d6","nummer":"0000000001","interneNotitie":"","betrokkenen":[],"categorieRelaties":[],"digitaleAdressen":[],"voorkeursDigitaalAdres":null,"vertegenwoordigden":[],"rekeningnummers":[],"voorkeursRekeningnummer":null,"partijIdentificatoren":[],"soortPartij":"persoon","indicatieGeheimhouding":false,"voorkeurstaal":"crp","indicatieActief":true,"bezoekadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"correspondentieadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"partijIdentificatie":{"contactnaam":{"voorletters":"Dr.","voornaam":"Test + Persoon","voorvoegselAchternaam":"Mrs.","achternaam":"Gamble"},"volledigeNaam":"Test + Persoon Mrs. Gamble"}}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '877' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Location: + - http://localhost:8338/klantinteracties/api/v1/partijen/40e6c3e8-25ee-4d34-9b16-0fb13320c8d6 + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 201 + message: Created +- request: + body: null + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + method: GET + uri: http://localhost:8338/klantinteracties/api/v1/partijen/40e6c3e8-25ee-4d34-9b16-0fb13320c8d6?expand=betrokkenen + response: + body: + string: '{"uuid":"40e6c3e8-25ee-4d34-9b16-0fb13320c8d6","url":"http://localhost:8338/klantinteracties/api/v1/partijen/40e6c3e8-25ee-4d34-9b16-0fb13320c8d6","nummer":"0000000001","interneNotitie":"","betrokkenen":[],"categorieRelaties":[],"digitaleAdressen":[],"voorkeursDigitaalAdres":null,"vertegenwoordigden":[],"rekeningnummers":[],"voorkeursRekeningnummer":null,"partijIdentificatoren":[],"soortPartij":"persoon","indicatieGeheimhouding":false,"voorkeurstaal":"crp","indicatieActief":true,"bezoekadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"correspondentieadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"partijIdentificatie":{"contactnaam":{"voorletters":"Dr.","voornaam":"Test + Persoon","voorvoegselAchternaam":"Mrs.","achternaam":"Gamble"},"volledigeNaam":"Test + Persoon Mrs. Gamble"}}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, PUT, PATCH, DELETE, HEAD, OPTIONS + Content-Length: + - '877' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 200 + message: OK +version: 1 diff --git a/src/openklant2/tests/cassettes/test_partij/test_retrieve_partij[categorieRelaties].yaml b/src/openklant2/tests/cassettes/test_partij/test_retrieve_partij[categorieRelaties].yaml new file mode 100644 index 000000000..071e2e17d --- /dev/null +++ b/src/openklant2/tests/cassettes/test_partij/test_retrieve_partij[categorieRelaties].yaml @@ -0,0 +1,80 @@ +interactions: +- request: + body: '{"digitaleAdressen": null, "voorkeursDigitaalAdres": null, "rekeningnummers": + null, "voorkeursRekeningnummer": null, "indicatieGeheimhouding": false, "indicatieActief": + true, "voorkeurstaal": "crp", "soortPartij": "persoon", "partijIdentificatie": + {"contactnaam": {"voorletters": "Dr.", "voornaam": "Test Persoon", "voorvoegselAchternaam": + "Mrs.", "achternaam": "Gamble"}}}' + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + Content-Length: + - '373' + Content-Type: + - application/json + method: POST + uri: http://localhost:8338/klantinteracties/api/v1/partijen + response: + body: + string: '{"uuid":"b39cc5ad-1433-47a7-9107-df6af3acd697","url":"http://localhost:8338/klantinteracties/api/v1/partijen/b39cc5ad-1433-47a7-9107-df6af3acd697","nummer":"0000000001","interneNotitie":"","betrokkenen":[],"categorieRelaties":[],"digitaleAdressen":[],"voorkeursDigitaalAdres":null,"vertegenwoordigden":[],"rekeningnummers":[],"voorkeursRekeningnummer":null,"partijIdentificatoren":[],"soortPartij":"persoon","indicatieGeheimhouding":false,"voorkeurstaal":"crp","indicatieActief":true,"bezoekadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"correspondentieadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"partijIdentificatie":{"contactnaam":{"voorletters":"Dr.","voornaam":"Test + Persoon","voorvoegselAchternaam":"Mrs.","achternaam":"Gamble"},"volledigeNaam":"Test + Persoon Mrs. Gamble"}}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '877' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Location: + - http://localhost:8338/klantinteracties/api/v1/partijen/b39cc5ad-1433-47a7-9107-df6af3acd697 + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 201 + message: Created +- request: + body: null + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + method: GET + uri: http://localhost:8338/klantinteracties/api/v1/partijen/b39cc5ad-1433-47a7-9107-df6af3acd697?expand=categorieRelaties + response: + body: + string: '{"uuid":"b39cc5ad-1433-47a7-9107-df6af3acd697","url":"http://localhost:8338/klantinteracties/api/v1/partijen/b39cc5ad-1433-47a7-9107-df6af3acd697","nummer":"0000000001","interneNotitie":"","betrokkenen":[],"categorieRelaties":[],"digitaleAdressen":[],"voorkeursDigitaalAdres":null,"vertegenwoordigden":[],"rekeningnummers":[],"voorkeursRekeningnummer":null,"partijIdentificatoren":[],"soortPartij":"persoon","indicatieGeheimhouding":false,"voorkeurstaal":"crp","indicatieActief":true,"bezoekadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"correspondentieadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"partijIdentificatie":{"contactnaam":{"voorletters":"Dr.","voornaam":"Test + Persoon","voorvoegselAchternaam":"Mrs.","achternaam":"Gamble"},"volledigeNaam":"Test + Persoon Mrs. Gamble"}}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, PUT, PATCH, DELETE, HEAD, OPTIONS + Content-Length: + - '877' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 200 + message: OK +version: 1 diff --git a/src/openklant2/tests/cassettes/test_partij/test_retrieve_partij[digitaleAdressen].yaml b/src/openklant2/tests/cassettes/test_partij/test_retrieve_partij[digitaleAdressen].yaml new file mode 100644 index 000000000..f8068e672 --- /dev/null +++ b/src/openklant2/tests/cassettes/test_partij/test_retrieve_partij[digitaleAdressen].yaml @@ -0,0 +1,80 @@ +interactions: +- request: + body: '{"digitaleAdressen": null, "voorkeursDigitaalAdres": null, "rekeningnummers": + null, "voorkeursRekeningnummer": null, "indicatieGeheimhouding": false, "indicatieActief": + true, "voorkeurstaal": "crp", "soortPartij": "persoon", "partijIdentificatie": + {"contactnaam": {"voorletters": "Dr.", "voornaam": "Test Persoon", "voorvoegselAchternaam": + "Mrs.", "achternaam": "Gamble"}}}' + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + Content-Length: + - '373' + Content-Type: + - application/json + method: POST + uri: http://localhost:8338/klantinteracties/api/v1/partijen + response: + body: + string: '{"uuid":"3249fd33-cafd-4554-8f61-4912697bf321","url":"http://localhost:8338/klantinteracties/api/v1/partijen/3249fd33-cafd-4554-8f61-4912697bf321","nummer":"0000000001","interneNotitie":"","betrokkenen":[],"categorieRelaties":[],"digitaleAdressen":[],"voorkeursDigitaalAdres":null,"vertegenwoordigden":[],"rekeningnummers":[],"voorkeursRekeningnummer":null,"partijIdentificatoren":[],"soortPartij":"persoon","indicatieGeheimhouding":false,"voorkeurstaal":"crp","indicatieActief":true,"bezoekadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"correspondentieadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"partijIdentificatie":{"contactnaam":{"voorletters":"Dr.","voornaam":"Test + Persoon","voorvoegselAchternaam":"Mrs.","achternaam":"Gamble"},"volledigeNaam":"Test + Persoon Mrs. Gamble"}}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '877' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Location: + - http://localhost:8338/klantinteracties/api/v1/partijen/3249fd33-cafd-4554-8f61-4912697bf321 + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 201 + message: Created +- request: + body: null + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + method: GET + uri: http://localhost:8338/klantinteracties/api/v1/partijen/3249fd33-cafd-4554-8f61-4912697bf321?expand=digitaleAdressen + response: + body: + string: '{"uuid":"3249fd33-cafd-4554-8f61-4912697bf321","url":"http://localhost:8338/klantinteracties/api/v1/partijen/3249fd33-cafd-4554-8f61-4912697bf321","nummer":"0000000001","interneNotitie":"","betrokkenen":[],"categorieRelaties":[],"digitaleAdressen":[],"voorkeursDigitaalAdres":null,"vertegenwoordigden":[],"rekeningnummers":[],"voorkeursRekeningnummer":null,"partijIdentificatoren":[],"soortPartij":"persoon","indicatieGeheimhouding":false,"voorkeurstaal":"crp","indicatieActief":true,"bezoekadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"correspondentieadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"partijIdentificatie":{"contactnaam":{"voorletters":"Dr.","voornaam":"Test + Persoon","voorvoegselAchternaam":"Mrs.","achternaam":"Gamble"},"volledigeNaam":"Test + Persoon Mrs. Gamble"}}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, PUT, PATCH, DELETE, HEAD, OPTIONS + Content-Length: + - '877' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 200 + message: OK +version: 1 diff --git a/src/openklant2/tests/cassettes/test_partij_identificator/test_create_partij_identificator.yaml b/src/openklant2/tests/cassettes/test_partij_identificator/test_create_partij_identificator.yaml new file mode 100644 index 000000000..7d2f4ee1a --- /dev/null +++ b/src/openklant2/tests/cassettes/test_partij_identificator/test_create_partij_identificator.yaml @@ -0,0 +1,87 @@ +interactions: +- request: + body: '{"digitaleAdressen": null, "voorkeursDigitaalAdres": null, "rekeningnummers": + null, "voorkeursRekeningnummer": null, "indicatieGeheimhouding": false, "indicatieActief": + true, "voorkeurstaal": "crp", "soortPartij": "persoon", "partijIdentificatie": + {"contactnaam": {"voorletters": "Dr.", "voornaam": "Test Persoon", "voorvoegselAchternaam": + "Mrs.", "achternaam": "Gamble"}}}' + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + Content-Length: + - '373' + Content-Type: + - application/json + method: POST + uri: http://localhost:8338/klantinteracties/api/v1/partijen + response: + body: + string: '{"uuid":"ce8ac2d2-1f4e-4cde-888f-474c708f6754","url":"http://localhost:8338/klantinteracties/api/v1/partijen/ce8ac2d2-1f4e-4cde-888f-474c708f6754","nummer":"0000000001","interneNotitie":"","betrokkenen":[],"categorieRelaties":[],"digitaleAdressen":[],"voorkeursDigitaalAdres":null,"vertegenwoordigden":[],"rekeningnummers":[],"voorkeursRekeningnummer":null,"partijIdentificatoren":[],"soortPartij":"persoon","indicatieGeheimhouding":false,"voorkeurstaal":"crp","indicatieActief":true,"bezoekadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"correspondentieadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"partijIdentificatie":{"contactnaam":{"voorletters":"Dr.","voornaam":"Test + Persoon","voorvoegselAchternaam":"Mrs.","achternaam":"Gamble"},"volledigeNaam":"Test + Persoon Mrs. Gamble"}}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '877' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Location: + - http://localhost:8338/klantinteracties/api/v1/partijen/ce8ac2d2-1f4e-4cde-888f-474c708f6754 + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 201 + message: Created +- request: + body: '{"identificeerdePartij": {"uuid": "ce8ac2d2-1f4e-4cde-888f-474c708f6754"}, + "partijIdentificator": {"codeObjecttype": "PERSOON", "codeSoortObjectId": "BSN", + "objectId": "123456789", "codeRegister": "BRP"}, "anderePartijIdentificator": + "optional_identifier_123"}' + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + Content-Length: + - '260' + Content-Type: + - application/json + method: POST + uri: http://localhost:8338/klantinteracties/api/v1/partij-identificatoren + response: + body: + string: '{"uuid":"46b5924e-e956-4eec-95d1-efea72a46628","url":"http://localhost:8338/klantinteracties/api/v1/partij-identificatoren/46b5924e-e956-4eec-95d1-efea72a46628","identificeerdePartij":{"uuid":"ce8ac2d2-1f4e-4cde-888f-474c708f6754","url":"http://localhost:8338/klantinteracties/api/v1/partijen/ce8ac2d2-1f4e-4cde-888f-474c708f6754"},"anderePartijIdentificator":"optional_identifier_123","partijIdentificator":{"codeObjecttype":"PERSOON","codeSoortObjectId":"BSN","objectId":"123456789","codeRegister":"BRP"}}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '507' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Location: + - http://localhost:8338/klantinteracties/api/v1/partij-identificatoren/46b5924e-e956-4eec-95d1-efea72a46628 + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 201 + message: Created +version: 1 diff --git a/src/openklant2/tests/cassettes/test_partij_identificator/test_list_partij_identificator.yaml b/src/openklant2/tests/cassettes/test_partij_identificator/test_list_partij_identificator.yaml new file mode 100644 index 000000000..e8b7ab14d --- /dev/null +++ b/src/openklant2/tests/cassettes/test_partij_identificator/test_list_partij_identificator.yaml @@ -0,0 +1,119 @@ +interactions: +- request: + body: '{"digitaleAdressen": null, "voorkeursDigitaalAdres": null, "rekeningnummers": + null, "voorkeursRekeningnummer": null, "indicatieGeheimhouding": false, "indicatieActief": + true, "voorkeurstaal": "crp", "soortPartij": "persoon", "partijIdentificatie": + {"contactnaam": {"voorletters": "Dr.", "voornaam": "Test Persoon", "voorvoegselAchternaam": + "Mrs.", "achternaam": "Gamble"}}}' + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + Content-Length: + - '373' + Content-Type: + - application/json + method: POST + uri: http://localhost:8338/klantinteracties/api/v1/partijen + response: + body: + string: '{"uuid":"7782a309-a3cb-48ac-a1f4-80faea457811","url":"http://localhost:8338/klantinteracties/api/v1/partijen/7782a309-a3cb-48ac-a1f4-80faea457811","nummer":"0000000001","interneNotitie":"","betrokkenen":[],"categorieRelaties":[],"digitaleAdressen":[],"voorkeursDigitaalAdres":null,"vertegenwoordigden":[],"rekeningnummers":[],"voorkeursRekeningnummer":null,"partijIdentificatoren":[],"soortPartij":"persoon","indicatieGeheimhouding":false,"voorkeurstaal":"crp","indicatieActief":true,"bezoekadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"correspondentieadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"partijIdentificatie":{"contactnaam":{"voorletters":"Dr.","voornaam":"Test + Persoon","voorvoegselAchternaam":"Mrs.","achternaam":"Gamble"},"volledigeNaam":"Test + Persoon Mrs. Gamble"}}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '877' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Location: + - http://localhost:8338/klantinteracties/api/v1/partijen/7782a309-a3cb-48ac-a1f4-80faea457811 + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 201 + message: Created +- request: + body: '{"identificeerdePartij": {"uuid": "7782a309-a3cb-48ac-a1f4-80faea457811"}, + "partijIdentificator": {"codeObjecttype": "PERSOON", "codeSoortObjectId": "BSN", + "objectId": "123456789", "codeRegister": "BRP"}, "anderePartijIdentificator": + "optional_identifier_123"}' + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + Content-Length: + - '260' + Content-Type: + - application/json + method: POST + uri: http://localhost:8338/klantinteracties/api/v1/partij-identificatoren + response: + body: + string: '{"uuid":"db60dfe6-217c-4040-a462-b603b1c9bf36","url":"http://localhost:8338/klantinteracties/api/v1/partij-identificatoren/db60dfe6-217c-4040-a462-b603b1c9bf36","identificeerdePartij":{"uuid":"7782a309-a3cb-48ac-a1f4-80faea457811","url":"http://localhost:8338/klantinteracties/api/v1/partijen/7782a309-a3cb-48ac-a1f4-80faea457811"},"anderePartijIdentificator":"optional_identifier_123","partijIdentificator":{"codeObjecttype":"PERSOON","codeSoortObjectId":"BSN","objectId":"123456789","codeRegister":"BRP"}}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '507' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Location: + - http://localhost:8338/klantinteracties/api/v1/partij-identificatoren/db60dfe6-217c-4040-a462-b603b1c9bf36 + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 201 + message: Created +- request: + body: null + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + method: GET + uri: http://localhost:8338/klantinteracties/api/v1/partij-identificatoren + response: + body: + string: '{"count":1,"next":null,"previous":null,"results":[{"uuid":"db60dfe6-217c-4040-a462-b603b1c9bf36","url":"http://localhost:8338/klantinteracties/api/v1/partij-identificatoren/db60dfe6-217c-4040-a462-b603b1c9bf36","identificeerdePartij":{"uuid":"7782a309-a3cb-48ac-a1f4-80faea457811","url":"http://localhost:8338/klantinteracties/api/v1/partijen/7782a309-a3cb-48ac-a1f4-80faea457811"},"anderePartijIdentificator":"optional_identifier_123","partijIdentificator":{"codeObjecttype":"PERSOON","codeSoortObjectId":"BSN","objectId":"123456789","codeRegister":"BRP"}}]}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '559' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 200 + message: OK +version: 1 diff --git a/src/openklant2/tests/cassettes/test_partij_identificator/test_retrieve_partij_identificator.yaml b/src/openklant2/tests/cassettes/test_partij_identificator/test_retrieve_partij_identificator.yaml new file mode 100644 index 000000000..9eed82d0e --- /dev/null +++ b/src/openklant2/tests/cassettes/test_partij_identificator/test_retrieve_partij_identificator.yaml @@ -0,0 +1,119 @@ +interactions: +- request: + body: '{"digitaleAdressen": null, "voorkeursDigitaalAdres": null, "rekeningnummers": + null, "voorkeursRekeningnummer": null, "indicatieGeheimhouding": false, "indicatieActief": + true, "voorkeurstaal": "crp", "soortPartij": "persoon", "partijIdentificatie": + {"contactnaam": {"voorletters": "Dr.", "voornaam": "Test Persoon", "voorvoegselAchternaam": + "Mrs.", "achternaam": "Gamble"}}}' + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + Content-Length: + - '373' + Content-Type: + - application/json + method: POST + uri: http://localhost:8338/klantinteracties/api/v1/partijen + response: + body: + string: '{"uuid":"b410bf0c-f2c2-4fb2-9e47-232e8b3c4996","url":"http://localhost:8338/klantinteracties/api/v1/partijen/b410bf0c-f2c2-4fb2-9e47-232e8b3c4996","nummer":"0000000001","interneNotitie":"","betrokkenen":[],"categorieRelaties":[],"digitaleAdressen":[],"voorkeursDigitaalAdres":null,"vertegenwoordigden":[],"rekeningnummers":[],"voorkeursRekeningnummer":null,"partijIdentificatoren":[],"soortPartij":"persoon","indicatieGeheimhouding":false,"voorkeurstaal":"crp","indicatieActief":true,"bezoekadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"correspondentieadres":{"nummeraanduidingId":"","adresregel1":"","adresregel2":"","adresregel3":"","land":""},"partijIdentificatie":{"contactnaam":{"voorletters":"Dr.","voornaam":"Test + Persoon","voorvoegselAchternaam":"Mrs.","achternaam":"Gamble"},"volledigeNaam":"Test + Persoon Mrs. Gamble"}}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '877' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Location: + - http://localhost:8338/klantinteracties/api/v1/partijen/b410bf0c-f2c2-4fb2-9e47-232e8b3c4996 + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 201 + message: Created +- request: + body: '{"identificeerdePartij": {"uuid": "b410bf0c-f2c2-4fb2-9e47-232e8b3c4996"}, + "partijIdentificator": {"codeObjecttype": "PERSOON", "codeSoortObjectId": "BSN", + "objectId": "123456789", "codeRegister": "BRP"}, "anderePartijIdentificator": + "optional_identifier_123"}' + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + Content-Length: + - '260' + Content-Type: + - application/json + method: POST + uri: http://localhost:8338/klantinteracties/api/v1/partij-identificatoren + response: + body: + string: '{"uuid":"490a86c2-cf60-4ef9-8d28-76faf9b4cdcf","url":"http://localhost:8338/klantinteracties/api/v1/partij-identificatoren/490a86c2-cf60-4ef9-8d28-76faf9b4cdcf","identificeerdePartij":{"uuid":"b410bf0c-f2c2-4fb2-9e47-232e8b3c4996","url":"http://localhost:8338/klantinteracties/api/v1/partijen/b410bf0c-f2c2-4fb2-9e47-232e8b3c4996"},"anderePartijIdentificator":"optional_identifier_123","partijIdentificator":{"codeObjecttype":"PERSOON","codeSoortObjectId":"BSN","objectId":"123456789","codeRegister":"BRP"}}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, POST, HEAD, OPTIONS + Content-Length: + - '507' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Location: + - http://localhost:8338/klantinteracties/api/v1/partij-identificatoren/490a86c2-cf60-4ef9-8d28-76faf9b4cdcf + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 201 + message: Created +- request: + body: null + headers: + Authorization: + - Token b2eb1da9861da88743d72a3fb4344288fe2cba44 + method: GET + uri: http://localhost:8338/klantinteracties/api/v1/partij-identificatoren/490a86c2-cf60-4ef9-8d28-76faf9b4cdcf + response: + body: + string: '{"uuid":"490a86c2-cf60-4ef9-8d28-76faf9b4cdcf","url":"http://localhost:8338/klantinteracties/api/v1/partij-identificatoren/490a86c2-cf60-4ef9-8d28-76faf9b4cdcf","identificeerdePartij":{"uuid":"b410bf0c-f2c2-4fb2-9e47-232e8b3c4996","url":"http://localhost:8338/klantinteracties/api/v1/partijen/b410bf0c-f2c2-4fb2-9e47-232e8b3c4996"},"anderePartijIdentificator":"optional_identifier_123","partijIdentificator":{"codeObjecttype":"PERSOON","codeSoortObjectId":"BSN","objectId":"123456789","codeRegister":"BRP"}}' + headers: + API-version: + - 0.0.3 + Allow: + - GET, PUT, PATCH, DELETE, HEAD, OPTIONS + Content-Length: + - '507' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 200 + message: OK +version: 1 diff --git a/src/openklant2/tests/conftest.py b/src/openklant2/tests/conftest.py new file mode 100644 index 000000000..70ebb444c --- /dev/null +++ b/src/openklant2/tests/conftest.py @@ -0,0 +1,56 @@ +import pytest + +from openklant2.tests.helpers import OpenKlantServiceManager + + +def pytest_addoption(parser): + parser.addoption( + "--with-openklant-service", + action="store_true", + default=False, + help="Whether to seed a fresh OpenKlant Docker instance for each test", + ) + + +@pytest.fixture(scope="session", autouse=True) +def openklant_service_singleton(request): + # Depending on whether we're working with a live service or not, we either + # spawn the service and yield the running service, or simply return a + # regular instance for the purposes of using the client factory in the + # client fixture. We split the fixtures up because the service singleton + # should be session-scoped, spawning the service at the start of the run + # and tearing it down at completion of the run. + # + # The client fixture below, by cotrast, should reset the database state for each test. + service = OpenKlantServiceManager() + if request.config.getoption("--with-openklant-service"): + with service.live_service() as running_service: + yield running_service + else: + yield service + + +@pytest.fixture() +def client(request, openklant_service_singleton: OpenKlantServiceManager): + if request.config.getoption("--with-openklant-service"): + # We're running against a live server: clean the state for the test + with openklant_service_singleton.clean_state() as client: + yield client + else: + # We're running in VCR mode: simply return a client + yield openklant_service_singleton.client_factory() + + +@pytest.fixture(scope="session") +def vcr_config(): + return { + "match_on": [ + "method", + "scheme", + "host", + "port", + "path", + "query", + # "body", + ], + } diff --git a/src/openklant2/tests/helpers.py b/src/openklant2/tests/helpers.py new file mode 100644 index 000000000..e0022cd50 --- /dev/null +++ b/src/openklant2/tests/helpers.py @@ -0,0 +1,240 @@ +import json +import logging +import subprocess +import time +from contextlib import contextmanager +from pathlib import Path +from urllib.parse import urljoin + +import requests + +from openklant2.client import OpenKlant2Client + +BASE_DIR = Path(__file__).parent.parent.resolve() + +logger = logging.getLogger(__name__) + + +class OpenKlantServiceManager: + _in_server_context: bool = False + _django_service_name: str = "web" + _api_root: str = "http://localhost:8338" + _api_path: str = "/klantinteracties/api/v1" + _api_token: str = "b2eb1da9861da88743d72a3fb4344288fe2cba44" + _docker_compose_project_name: str = "openklant2-api-test" + _docker_compose_path: Path = BASE_DIR / "docker-compose.yaml" + + def _docker_compose( + self, + *args: str, + check: bool = True, + input: str | None = None, + ): + input_data = {"text": True, "input": input} if input else {} + try: + return subprocess.run( + args=[ + "docker-compose", + "-f", + str(self._docker_compose_path), + "-p", + self._docker_compose_project_name, + *args, + ], + check=check, + capture_output=True, + **input_data, + ) + except subprocess.CalledProcessError as exc: + logger.exception( + "Unable to execute command", + exc_info=True, + extra={"stderr": exc.stderr, "stdout": exc.stdout}, + ) + raise + + def _manage_py( + self, + *args: str, + input: str | None = None, + ): + self._docker_compose( + "run", + "--rm", + self._django_service_name, + "python", + "src/manage.py", + *args, + input=input, + ) + + def _service_teardown(self): + self._docker_compose("kill", check=False) + self._docker_compose("down", "-v") + self._docker_compose("rm", "-f") + + def _service_init(self): + self._docker_compose("up", "-d") + self._wait_for_response() + self._manage_py("migrate") + + def reset_db_state(self): + self._manage_py("flush", "--no-input") + self._load_fixture_from_json_string(self._generate_token_fixture()) + + def _load_fixture_from_json_string(self, fixture: str): + self._manage_py( + "loaddata", + "--format", + "json", + "-", # i.e. stdin + input=fixture, + ) + + def _generate_token_fixture(self): + return json.dumps( + [ + { + "model": "token.tokenauth", + "pk": 1, + "fields": { + "token": self._api_token, + "contact_person": "Boaty McBoatface", + "email": "boaty@mcboatface.com", + "organization": "", + "last_modified": "2024-08-22T07:43:21.837Z", + "created": "2024-08-22T07:43:21.837Z", + "application": "", + "administration": "", + }, + } + ] + ) + + def _wait_for_response(self, interval=0.5, max_wait=60): + start_time = time.time() + while True: + try: + response = requests.get(self._api_root) + return response + except requests.RequestException: + logger.debug("Exception while checking for liveness", exc_info=True) + elapsed_time = time.time() - start_time + if elapsed_time > max_wait: + logger.info("Max wait time exceeded.") + raise RuntimeError( + f"Maximum wait for service to be healthy exceeded: {elapsed_time} > {max_wait}" + ) + + time.sleep(interval) + + def setUp(self): + if self._in_server_context: + raise RuntimeError( + "You cannot have multiple server contexts active at the same time" + ) + + self._in_server_context = True + self._service_teardown() + self._service_init() + + def tearDown(self): + self._service_teardown() + self._in_server_context = False + + @property + def api_root(self): + return urljoin( + self._api_root, + self._api_path, + ) + + def client_factory(self): + return OpenKlant2Client( + api_root=self.api_root, + token=self._api_token, + ) + + def clean_state(self): + """Yield a client configured to talk a live OpenKlant service. + + Note that this requires the live server to have been spawned, + either imperatively: + + service.setUp() + with service.clean_state() as client: + client.do_stuff() + + service.tearDown() + + ... or using the live_service() context manager: + + with service.live_server_manager() as live_service: + with live_service.clean_state() as client: + client.do_something() + + """ + if not self._in_server_context: + raise RuntimeError( + "You must execute this context within the server context" + ) + + @contextmanager + def clean_state_manager(*args, **kwds): + self.reset_db_state() + yield self.client_factory() + + return clean_state_manager() + + def live_service(self): + """Context manager to spawn a live OpenKlant service and clean it up upon completion. + + You will commonly nest a clean_state() context manager within the live_service block, + for instance: + + with service.live_server_manager() as live_service: + with live_service.clean_state() as client: + client.do_something() + """ + + @contextmanager + def live_server_manager(*args, **kwds): + try: + self.setUp() + yield self + finally: + self.tearDown() + + return live_server_manager() + + +class LiveOpenKlantTestMixin: + _service: OpenKlantServiceManager + use_live_service: bool = False + + @classmethod + def should_bypass_live_server(cls) -> bool: + return cls.use_live_service + + @property + def openklant_client(self) -> OpenKlant2Client: + return self._service.client_factory() + + def reset_db(self): + if not self.should_bypass_live_server(): + self._service.reset_db_state() + + @classmethod + def setUpClass(cls): + cls._service = OpenKlantServiceManager() + + if not cls.should_bypass_live_server(): + cls._service.setUp() + + @classmethod + def tearDownClass(cls) -> None: + if not cls.should_bypass_live_server(): + cls._service.tearDown() + + def setUp(self): + self.reset_db() diff --git a/src/openklant2/tests/test_digitaal_adres.py b/src/openklant2/tests/test_digitaal_adres.py new file mode 100644 index 000000000..33de77d7a --- /dev/null +++ b/src/openklant2/tests/test_digitaal_adres.py @@ -0,0 +1,58 @@ +import pytest +from pydantic import TypeAdapter + +from openklant2.factories.digitaal_adres import CreateDigitaalAdresDataFactory +from openklant2.factories.partij import CreatePartijPersoonDataFactory +from openklant2.types.pagination import PaginatedResponseBody +from openklant2.types.resources import Partij +from openklant2.types.resources.digitaal_adres import ( + CreateDigitaalAdresDataValidator, + DigitaalAdres, + DigitaalAdresValidator, +) + + +@pytest.fixture() +def een_partij(client) -> Partij: + data = CreatePartijPersoonDataFactory() + return client.partij.create_persoon(data=data) + + +@pytest.fixture() +def een_digitaal_adres(client, een_partij) -> Partij: + data = CreateDigitaalAdresDataFactory( + verstrektDoorBetrokkene=None, + verstrektDoorPartij__uuid=een_partij["uuid"], + ) + return client.digitaal_adres.create(data=data) + + +@pytest.mark.vcr +def test_create_digitaal_adres(client, een_partij) -> None: + data = CreateDigitaalAdresDataValidator.validate_python( + { + "adres": "foo@bar.com", + "omschrijving": "professional", + "soortDigitaalAdres": "email", + "verstrektDoorBetrokkene": None, + "verstrektDoorPartij": {"uuid": een_partij["uuid"]}, + } + ) + resp = client.digitaal_adres.create( + data=data, + ) + + DigitaalAdresValidator.validate_python(resp) + + +@pytest.mark.usefixtures("een_digitaal_adres") +@pytest.mark.vcr +def test_list_digitaal_adres(client) -> None: + resp = client.digitaal_adres.list() + TypeAdapter(PaginatedResponseBody[DigitaalAdres]).validate_python(resp) + + +@pytest.mark.vcr +def test_retrieve_digitaal_adres(client, een_digitaal_adres) -> None: + resp = client.digitaal_adres.retrieve(een_digitaal_adres["uuid"]) + TypeAdapter(DigitaalAdres).validate_python(resp) diff --git a/src/openklant2/tests/test_partij.py b/src/openklant2/tests/test_partij.py new file mode 100644 index 000000000..11f1b006d --- /dev/null +++ b/src/openklant2/tests/test_partij.py @@ -0,0 +1,260 @@ +import textwrap + +import pytest +from pydantic import TypeAdapter + +from openklant2.exceptions import BadRequest +from openklant2.factories.partij import ( + CreatePartijContactPersoonDataFactory, + CreatePartijOrganisatieDataFactory, + CreatePartijPersoonDataFactory, +) +from openklant2.types import PaginatedResponseBody +from openklant2.types.resources import ( + CreatePartijContactpersoonDataValidator, + CreatePartijOrganisatieDataValidator, + CreatePartijPersoonDataValidator, + Partij, + PartijValidator, +) + + +@pytest.fixture() +def een_persoon(client): + data = { + "digitaleAdressen": None, + "voorkeursDigitaalAdres": None, + "rekeningnummers": None, + "voorkeursRekeningnummer": None, + "indicatieGeheimhouding": False, + "indicatieActief": True, + "voorkeurstaal": "crp", + "soortPartij": "persoon", + "partijIdentificatie": { + "contactnaam": { + "voorletters": "Dr.", + "voornaam": "Test Persoon", + "voorvoegselAchternaam": "Mrs.", + "achternaam": "Gamble", + } + }, + } + return client.partij.create_persoon(data=data) + + +@pytest.fixture() +def een_organisatie(client): + data = { + "digitaleAdressen": None, + "voorkeursDigitaalAdres": None, + "rekeningnummers": None, + "voorkeursRekeningnummer": None, + "indicatieGeheimhouding": False, + "indicatieActief": True, + "voorkeurstaal": "tiv", + "soortPartij": "organisatie", + "partijIdentificatie": {"naam": "Test Organisatie"}, + } + return client.partij.create_organisatie(data=data) + + +@pytest.mark.vcr +@pytest.mark.usefixtures("een_persoon", "een_organisatie") +def test_list_partijen(client): + resp = client.partij.list() + + TypeAdapter(PaginatedResponseBody[Partij]).validate_python(resp) + + +@pytest.mark.vcr +@pytest.mark.parametrize( + "expand", + ( + "betrokkenen", + "betrokkenen.hadKlantcontact", + "categorieRelaties", + "digitaleAdressen", + ), +) +def test_retrieve_partij(client, een_persoon, expand): + resp = client.partij.retrieve( + een_persoon["uuid"], + params={"expand": [expand]}, + ) + + PartijValidator.validate_python(resp) + + +@pytest.mark.vcr +def test_create_persoon(client) -> None: + data = CreatePartijPersoonDataValidator.validate_python( + { + "soortPartij": "persoon", + "digitaleAdressen": None, + "rekeningnummers": None, + "voorkeursRekeningnummer": None, + "soortPartij": "persoon", + "voorkeurstaal": "nld", + "indicatieActief": True, + "indicatieGeheimhouding": False, + "voorkeursDigitaalAdres": None, + "partijIdentificatie": {"contactnaam": None}, + } + ) + resp = client.partij.create_persoon( + data=data, + ) + + PartijValidator.validate_python(resp) + + +@pytest.mark.vcr +def test_create_contactpersoon(client, een_organisatie): + data = CreatePartijContactpersoonDataValidator.validate_python( + { + "soortPartij": "contactpersoon", + "digitaleAdressen": None, + "rekeningnummers": None, + "voorkeursRekeningnummer": None, + "voorkeurstaal": "nld", + "indicatieActief": True, + "indicatieGeheimhouding": False, + "voorkeursDigitaalAdres": None, + "partijIdentificatie": { + "contactnaam": None, + "werkteVoorPartij": {"uuid": een_organisatie["uuid"]}, + }, + } + ) + resp = client.partij.create_contactpersoon( + data={ + "soortPartij": "contactpersoon", + "digitaleAdressen": None, + "rekeningnummers": None, + "voorkeursRekeningnummer": None, + "voorkeurstaal": "nld", + "indicatieActief": True, + "indicatieGeheimhouding": False, + "voorkeursDigitaalAdres": None, + "partijIdentificatie": { + "contactnaam": None, + "werkteVoorPartij": {"uuid": een_organisatie["uuid"]}, + }, + }, + ) + + PartijValidator.validate_python(resp) + + +@pytest.mark.vcr +def test_create_organisatie(client): + data = CreatePartijOrganisatieDataValidator.validate_python( + { + "soortPartij": "organisatie", + "digitaleAdressen": None, + "rekeningnummers": None, + "voorkeursRekeningnummer": None, + "voorkeurstaal": "nld", + "indicatieActief": True, + "indicatieGeheimhouding": False, + "voorkeursDigitaalAdres": None, + "partijIdentificatie": {"naam": "AcmeCorp Ltd"}, + } + ) + resp = client.partij.create_organisatie( + data=data, + ) + + PartijValidator.validate_python(resp) + + +@pytest.mark.vcr +def test_create_with_bad_request_exception(client): + with pytest.raises(BadRequest) as exc_info: + client.partij.create_organisatie( + data={}, + ) + + got = ( + exc_info.value.status, + exc_info.value.code, + exc_info.value.title, + exc_info.value.invalidParams, + str(exc_info.value), + ) + want = ( + 400, + "invalid", + "Invalid input.", + [ + { + "name": "digitaleAdressen", + "code": "required", + "reason": "Dit veld is vereist.", + }, + { + "name": "voorkeursDigitaalAdres", + "code": "required", + "reason": "Dit veld is vereist.", + }, + { + "name": "rekeningnummers", + "code": "required", + "reason": "Dit veld is vereist.", + }, + { + "name": "voorkeursRekeningnummer", + "code": "required", + "reason": "Dit veld is vereist.", + }, + { + "name": "soortPartij", + "code": "required", + "reason": "Dit veld is vereist.", + }, + { + "name": "indicatieActief", + "code": "required", + "reason": "Dit veld is vereist.", + }, + ], + textwrap.dedent( + """ + status=400 code=400 title="Invalid input.": + Invalid parameters: + {'code': 'required', + 'name': 'digitaleAdressen', + 'reason': 'Dit veld is vereist.'} + {'code': 'required', + 'name': 'voorkeursDigitaalAdres', + 'reason': 'Dit veld is vereist.'} + {'code': 'required', + 'name': 'rekeningnummers', + 'reason': 'Dit veld is vereist.'} + {'code': 'required', + 'name': 'voorkeursRekeningnummer', + 'reason': 'Dit veld is vereist.'} + {'code': 'required', 'name': 'soortPartij', 'reason': 'Dit veld is vereist.'} + {'code': 'required', + 'name': 'indicatieActief', + 'reason': 'Dit veld is vereist.'} + """ + ).strip(), + ) + + assert got == want + + +def test_factory_partij_persoon_data(): + data = CreatePartijPersoonDataFactory.build() + CreatePartijPersoonDataValidator.validate_python(data) + + +def test_factory_partij_organisatie_data(): + data = CreatePartijOrganisatieDataFactory.build() + CreatePartijOrganisatieDataValidator.validate_python(data) + + +def test_factory_partij_contactpersoon_data(): + data = CreatePartijContactPersoonDataFactory.build() + CreatePartijContactpersoonDataValidator.validate_python(data) diff --git a/src/openklant2/tests/test_partij_identificator.py b/src/openklant2/tests/test_partij_identificator.py new file mode 100644 index 000000000..e128c40af --- /dev/null +++ b/src/openklant2/tests/test_partij_identificator.py @@ -0,0 +1,82 @@ +import pytest +from pydantic import TypeAdapter + +from openklant2.types.pagination import PaginatedResponseBody +from openklant2.types.resources import Partij +from openklant2.types.resources.partij_identificator import ( + CreatePartijIdentificatorDataValidator, + PartijIdentificator, + PartijIdentificatorValidator, +) + + +@pytest.fixture() +def een_persoon(client) -> Partij: + data = { + "digitaleAdressen": None, + "voorkeursDigitaalAdres": None, + "rekeningnummers": None, + "voorkeursRekeningnummer": None, + "indicatieGeheimhouding": False, + "indicatieActief": True, + "voorkeurstaal": "crp", + "soortPartij": "persoon", + "partijIdentificatie": { + "contactnaam": { + "voorletters": "Dr.", + "voornaam": "Test Persoon", + "voorvoegselAchternaam": "Mrs.", + "achternaam": "Gamble", + } + }, + } + return client.partij.create_persoon(data=data) + + +@pytest.fixture() +def een_partij_identificator(client, een_persoon) -> Partij: + data = { + "identificeerdePartij": {"uuid": een_persoon["uuid"]}, + "partijIdentificator": { + "codeObjecttype": "PERSOON", + "codeSoortObjectId": "BSN", + "objectId": "123456789", + "codeRegister": "BRP", + }, + "anderePartijIdentificator": "optional_identifier_123", + } + return client.partij_identificator.create(data=data) + + +@pytest.mark.vcr +def test_create_partij_identificator(client, een_persoon) -> None: + data = CreatePartijIdentificatorDataValidator.validate_python( + { + "identificeerdePartij": {"uuid": een_persoon["uuid"]}, + "partijIdentificator": { + "codeObjecttype": "PERSOON", + "codeSoortObjectId": "BSN", + "objectId": "123456789", + "codeRegister": "BRP", + }, + "anderePartijIdentificator": "optional_identifier_123", + } + ) + resp = client.partij_identificator.create( + data=data, + ) + + PartijIdentificatorValidator.validate_python(resp) + + +@pytest.mark.usefixtures("een_partij_identificator") +@pytest.mark.vcr +def test_list_partij_identificator(client) -> None: + resp = client.partij_identificator.list() + TypeAdapter(PaginatedResponseBody[PartijIdentificator]).validate_python(resp) + + +@pytest.mark.vcr +def test_retrieve_partij_identificator(client, een_partij_identificator) -> None: + resp = client.partij_identificator.retrieve(een_partij_identificator["uuid"]) + TypeAdapter(PartijIdentificator).validate_python(resp) diff --git a/src/openklant2/types/__init__.py b/src/openklant2/types/__init__.py new file mode 100644 index 000000000..a2a064431 --- /dev/null +++ b/src/openklant2/types/__init__.py @@ -0,0 +1,21 @@ +from .common import CreateAdres +from .error import ( + ErrorResponseBody, + ErrorResponseBodyValidator, + InvalidParam, + ValidationErrorResponseBody, + ValidationErrorResponseBodyValidator, +) +from .iso_639_2 import LanguageCode +from .pagination import PaginatedResponseBody + +__all__ = [ + "ErrorResponseBodyValidator", + "ValidationErrorResponseBodyValidator", + "CreateAdres", + "LanguageCode", + "PaginatedResponseBody", + "InvalidParam", + "ErrorResponseBody", + "ValidationErrorResponseBody", +] diff --git a/src/openklant2/types/common.py b/src/openklant2/types/common.py new file mode 100644 index 000000000..99cc853bf --- /dev/null +++ b/src/openklant2/types/common.py @@ -0,0 +1,28 @@ +from typing import NotRequired, Required + +from typing_extensions import TypedDict + + +class CreateAdres(TypedDict): + nummeraanduidingId: Required[str | None] + adresregel1: NotRequired[str] + adresregel2: NotRequired[str] + adresregel3: NotRequired[str] + land: NotRequired[str] + + +class Adres(TypedDict): + nummeraanduidingId: str + adresregel1: str + adresregel2: str + adresregel3: str + land: str + + +class ForeignKeyRef(TypedDict): + uuid: str + + +class FullForeigKeyRef(TypedDict): + uuid: str + url: str diff --git a/src/openklant2/types/error.py b/src/openklant2/types/error.py new file mode 100644 index 000000000..31aebe7e3 --- /dev/null +++ b/src/openklant2/types/error.py @@ -0,0 +1,28 @@ +from typing import Literal + +from pydantic import TypeAdapter +from typing_extensions import TypedDict + + +class InvalidParam(TypedDict): + name: str + code: str + reason: str + + +class ErrorResponseBody(TypedDict): + type: str + code: str + title: str + status: int + detail: str + instance: str + + +class ValidationErrorResponseBody(ErrorResponseBody): + status: Literal[400] + invalidParams: list[InvalidParam] + + +ErrorResponseBodyValidator = TypeAdapter(ErrorResponseBody) +ValidationErrorResponseBodyValidator = TypeAdapter(ValidationErrorResponseBody) diff --git a/src/openklant2/types/iso_639_2.py b/src/openklant2/types/iso_639_2.py new file mode 100644 index 000000000..0426d70df --- /dev/null +++ b/src/openklant2/types/iso_639_2.py @@ -0,0 +1,510 @@ +from typing import Literal + +LanguageCode = Literal[ + "abk", + "ace", + "ach", + "ada", + "ady", + "afa", + "afh", + "afr", + "ain", + "aka", + "akk", + "alb", + "sqi", + "ale", + "alg", + "alt", + "amh", + "ang", + "anp", + "apa", + "ara", + "arc", + "arg", + "arm", + "hye", + "arn", + "arp", + "art", + "arw", + "asm", + "ast", + "ath", + "aus", + "ava", + "ave", + "awa", + "aym", + "aze", + "bad", + "bai", + "bak", + "bal", + "bam", + "ban", + "baq", + "eus", + "bas", + "bat", + "bej", + "bel", + "bem", + "ben", + "ber", + "bho", + "bih", + "bik", + "bin", + "bis", + "bla", + "bnt", + "tib", + "bod", + "bos", + "bra", + "bre", + "btk", + "bua", + "bug", + "bul", + "bur", + "mya", + "byn", + "cad", + "cai", + "car", + "cat", + "cau", + "ceb", + "cel", + "cze", + "ces", + "cha", + "chb", + "che", + "chg", + "chi", + "zho", + "chk", + "chm", + "chn", + "cho", + "chp", + "chr", + "chu", + "chv", + "chy", + "cmc", + "cnr", + "cop", + "cor", + "cos", + "cpe", + "cpf", + "cpp", + "cre", + "crh", + "crp", + "csb", + "cus", + "wel", + "cym", + "dak", + "dan", + "dar", + "day", + "del", + "den", + "ger", + "deu", + "dgr", + "din", + "div", + "doi", + "dra", + "dsb", + "dua", + "dum", + "dut", + "nld", + "dyu", + "dzo", + "efi", + "egy", + "eka", + "gre", + "ell", + "elx", + "eng", + "enm", + "epo", + "est", + "ewe", + "ewo", + "fan", + "fao", + "per", + "fas", + "fat", + "fij", + "fil", + "fin", + "fiu", + "fon", + "fre", + "fra", + "frm", + "fro", + "frr", + "frs", + "fry", + "ful", + "fur", + "gaa", + "gay", + "gba", + "gem", + "geo", + "kat", + "gez", + "gil", + "gla", + "gle", + "glg", + "glv", + "gmh", + "goh", + "gon", + "gor", + "got", + "grb", + "grc", + "grn", + "gsw", + "guj", + "gwi", + "hai", + "hat", + "hau", + "haw", + "heb", + "her", + "hil", + "him", + "hin", + "hit", + "hmn", + "hmo", + "hrv", + "hsb", + "hun", + "hup", + "iba", + "ibo", + "ice", + "isl", + "ido", + "iii", + "ijo", + "iku", + "ile", + "ilo", + "ina", + "inc", + "ind", + "ine", + "inh", + "ipk", + "ira", + "iro", + "ita", + "jav", + "jbo", + "jpn", + "jpr", + "jrb", + "kaa", + "kab", + "kac", + "kal", + "kam", + "kan", + "kar", + "kas", + "kau", + "kaw", + "kaz", + "kbd", + "kha", + "khi", + "khm", + "kho", + "kik", + "kin", + "kir", + "kmb", + "kok", + "kom", + "kon", + "kor", + "kos", + "kpe", + "krc", + "krl", + "kro", + "kru", + "kua", + "kum", + "kur", + "kut", + "lad", + "lah", + "lam", + "lao", + "lat", + "lav", + "lez", + "lim", + "lin", + "lit", + "lol", + "loz", + "ltz", + "lua", + "lub", + "lug", + "lui", + "lun", + "luo", + "lus", + "mac", + "mkd", + "mad", + "mag", + "mah", + "mai", + "mak", + "mal", + "man", + "mao", + "mri", + "map", + "mar", + "mas", + "may", + "msa", + "mdf", + "mdr", + "men", + "mga", + "mic", + "min", + "mis", + "mkh", + "mlg", + "mlt", + "mnc", + "mni", + "mno", + "moh", + "mon", + "mos", + "mul", + "mun", + "mus", + "mwl", + "mwr", + "myn", + "myv", + "nah", + "nai", + "nap", + "nau", + "nav", + "nbl", + "nde", + "ndo", + "nds", + "nep", + "new", + "nia", + "nic", + "niu", + "nno", + "nob", + "nog", + "non", + "nor", + "nqo", + "nso", + "nub", + "nwc", + "nya", + "nym", + "nyn", + "nyo", + "nzi", + "oci", + "oji", + "ori", + "orm", + "osa", + "oss", + "ota", + "oto", + "paa", + "pag", + "pal", + "pam", + "pan", + "pap", + "pau", + "peo", + "phi", + "phn", + "pli", + "pol", + "pon", + "por", + "pra", + "pro", + "pus", + "que", + "raj", + "rap", + "rar", + "roa", + "roh", + "rom", + "rum", + "ron", + "run", + "rup", + "rus", + "sad", + "sag", + "sah", + "sai", + "sal", + "sam", + "san", + "sas", + "sat", + "scn", + "sco", + "sel", + "sem", + "sga", + "sgn", + "shn", + "sid", + "sin", + "sio", + "sit", + "sla", + "slo", + "slk", + "slv", + "sma", + "sme", + "smi", + "smj", + "smn", + "smo", + "sms", + "sna", + "snd", + "snk", + "sog", + "som", + "son", + "sot", + "spa", + "srd", + "srn", + "srp", + "srr", + "ssa", + "ssw", + "suk", + "sun", + "sus", + "sux", + "swa", + "swe", + "syc", + "syr", + "tah", + "tai", + "tam", + "tat", + "tel", + "tem", + "ter", + "tet", + "tgk", + "tgl", + "tha", + "tig", + "tir", + "tiv", + "tkl", + "tlh", + "tli", + "tmh", + "tog", + "ton", + "tpi", + "tsi", + "tsn", + "tso", + "tuk", + "tum", + "tup", + "tur", + "tut", + "tvl", + "twi", + "tyv", + "udm", + "uga", + "uig", + "ukr", + "umb", + "und", + "urd", + "uzb", + "vai", + "ven", + "vie", + "vol", + "vot", + "wak", + "wal", + "war", + "was", + "wen", + "wln", + "wol", + "xal", + "xho", + "yao", + "yap", + "yid", + "yor", + "ypk", + "zap", + "zbl", + "zen", + "zgh", + "zha", + "znd", + "zul", + "zun", + "zxx", + "zza", +] +"""ISO 639-2 alpha-3 language codes.""" diff --git a/src/openklant2/types/pagination.py b/src/openklant2/types/pagination.py new file mode 100644 index 000000000..f1b761e3e --- /dev/null +++ b/src/openklant2/types/pagination.py @@ -0,0 +1,12 @@ +from typing import Generic, Required, TypeVar + +from typing_extensions import TypedDict + +T = TypeVar("T") + + +class PaginatedResponseBody(Generic[T], TypedDict): + count: Required[int] + next: Required[str | None] + previous: Required[str | None] + results: Required[list[T]] diff --git a/src/openklant2/types/resources/__init__.py b/src/openklant2/types/resources/__init__.py new file mode 100644 index 000000000..2e7682529 --- /dev/null +++ b/src/openklant2/types/resources/__init__.py @@ -0,0 +1,35 @@ +from .partij import ( + CreateContactnaam, + CreatePartijContactpersoonData, + CreatePartijContactpersoonDataValidator, + CreatePartijDataBase, + CreatePartijIdentificatieContactpersoon, + CreatePartijIdentificatieOrganisatie, + CreatePartijIdentificatiePersoon, + CreatePartijOrganisatieData, + CreatePartijOrganisatieDataValidator, + CreatePartijPersoonData, + CreatePartijPersoonDataValidator, + Partij, + PartijListParams, + PartijRetrieveParams, + PartijValidator, +) + +__all__ = [ + "CreateContactnaam", + "CreatePartijDataBase", + "CreatePartijIdentificatiePersoon", + "CreatePartijIdentificatieContactpersoon", + "CreatePartijIdentificatieOrganisatie", + "CreatePartijPersoonData", + "CreatePartijContactpersoonData", + "CreatePartijOrganisatieData", + "Partij", + "PartijListParams", + "PartijRetrieveParams", + "PartijValidator", + "CreatePartijPersoonDataValidator", + "CreatePartijOrganisatieDataValidator", + "CreatePartijContactpersoonDataValidator", +] diff --git a/src/openklant2/types/resources/digitaal_adres.py b/src/openklant2/types/resources/digitaal_adres.py new file mode 100644 index 000000000..a0b39afef --- /dev/null +++ b/src/openklant2/types/resources/digitaal_adres.py @@ -0,0 +1,37 @@ +from pydantic import TypeAdapter +from typing_extensions import TypedDict + +from openklant2.types.common import ForeignKeyRef, FullForeigKeyRef + +# +# Input +# + + +class CreateDigitaalAdresData(TypedDict): + verstrektDoorBetrokkene: ForeignKeyRef | None + verstrektDoorPartij: ForeignKeyRef | None + adres: str + omschrijving: str + soortDigitaalAdres: str + + +class ListDigitaalAdresParams(TypedDict): + page: int + + +# +# Output +# + + +class DigitaalAdres(TypedDict): + verstrektDoorBetrokkene: FullForeigKeyRef | None + verstrektDoorPartij: FullForeigKeyRef | None + adres: str + omschrijving: str + soortDigitaalAdres: str + + +CreateDigitaalAdresDataValidator = TypeAdapter(CreateDigitaalAdresData) +DigitaalAdresValidator = TypeAdapter(DigitaalAdres) diff --git a/src/openklant2/types/resources/partij.py b/src/openklant2/types/resources/partij.py new file mode 100644 index 000000000..d3833a537 --- /dev/null +++ b/src/openklant2/types/resources/partij.py @@ -0,0 +1,157 @@ +from typing import Literal, NotRequired, Required + +from pydantic import TypeAdapter +from typing_extensions import TypedDict + +from openklant2.types.common import Adres, CreateAdres, ForeignKeyRef +from openklant2.types.iso_639_2 import LanguageCode +from openklant2.types.resources.digitaal_adres import DigitaalAdres + +# +# Input types +# + + +class CreateContactnaam(TypedDict): + voorletters: str + voornaam: str + voorvoegselAchternaam: str + achternaam: str + + +# Note this is polymorphic, concrete types below +class CreatePartijDataBase(TypedDict): + nummer: NotRequired[str] + interneNotitie: NotRequired[str] + digitaleAdressen: Required[list[ForeignKeyRef] | None] + voorkeursDigitaalAdres: Required[ForeignKeyRef | None] + rekeningnummers: Required[list[ForeignKeyRef] | None] + voorkeursRekeningnummer: Required[ForeignKeyRef | None] + voorkeurstaal: LanguageCode + indicatieActief: bool + indicatieGeheimhouding: bool + correspondentieadres: NotRequired[CreateAdres] + bezoekadres: NotRequired[CreateAdres | None] + + +class CreatePartijIdentificatiePersoon(TypedDict): + contactnaam: Required[CreateContactnaam | None] + + +class CreatePartijIdentificatieContactpersoon(TypedDict): + contactnaam: Required[CreateContactnaam | None] + werkteVoorPartij: ForeignKeyRef + + +class CreatePartijIdentificatieOrganisatie(TypedDict): + naam: Required[str] + + +class CreatePartijPersoonData(CreatePartijDataBase): + soortPartij: Literal["persoon"] + partijIdentificatie: CreatePartijIdentificatiePersoon + + +class CreatePartijContactpersoonData(CreatePartijDataBase): + soortPartij: Literal["contactpersoon"] + partijIdentificatie: CreatePartijIdentificatieContactpersoon + + +class CreatePartijOrganisatieData(CreatePartijDataBase): + soortPartij: Literal["organisatie"] + partijIdentificatie: CreatePartijIdentificatieOrganisatie + + +class PartijListParams(TypedDict, total=False): + page: int + vertegenwoordigdePartij__url: str + partijIdentificator__codeObjecttype: str + partijIdentificator__codeRegister: str + partijIdentificator__codeSoortObjectId: str + partijIdentificator__objectId: str + soortPartij: Literal["organisatie", "persoon", "contactpersoon"] + expand: NotRequired[ + list[ + Literal[ + "betrokkenen", + "betrokkenen.hadKlantcontact", + "categorieRelaties", + "digitaleAdressen", + ] + ] + ] + + +class PartijRetrieveParams(TypedDict): + expand: NotRequired[ + list[ + Literal[ + "betrokkenen", + "betrokkenen.hadKlantcontact", + "categorieRelaties", + "digitaleAdressen", + ] + ] + ] + + +# +# Output types +# + + +class Contactnaam(TypedDict): + voorletters: str + voornaam: str + voorvoegselAchternaam: str + achternaam: str + + +class PartijIdentificatiePersoon(TypedDict): + contactnaam: Contactnaam | None + + +class PartijIdentificatieOrganisatie(TypedDict): + naam: str + + +class PartijIdentificatieContactpersoon(TypedDict): + contactnaam: Contactnaam | None + + +class PartijExpand(TypedDict, total=False): + digitaleAdressen: list[DigitaalAdres] + # TODO: betrokkenen, categorie_relaties + + +class Partij(TypedDict): + uuid: str + nummer: str + url: str + interneNotitie: str + digitaleAdressen: list[ForeignKeyRef] + voorkeursDigitaalAdres: ForeignKeyRef | None + rekeningnummers: list[ForeignKeyRef] + voorkeursRekeningnummer: ForeignKeyRef | None + voorkeurstaal: LanguageCode + indicatieActief: bool + indicatieGeheimhouding: bool + correspondentieadres: Adres | None + bezoekadres: Adres | None + soortPartij: Literal["organisatie", "persoon", "contactpersoon"] + partijIdentificatie: ( + PartijIdentificatieContactpersoon + | PartijIdentificatiePersoon + | PartijIdentificatieOrganisatie + ) + _expand: NotRequired[PartijExpand] + + +# +# Validators +# + +PartijValidator = TypeAdapter(Partij) +CreatePartijPersoonDataValidator = TypeAdapter(CreatePartijPersoonData) +CreatePartijOrganisatieDataValidator = TypeAdapter(CreatePartijOrganisatieData) +CreatePartijContactpersoonDataValidator = TypeAdapter(CreatePartijContactpersoonData) diff --git a/src/openklant2/types/resources/partij_identificator.py b/src/openklant2/types/resources/partij_identificator.py new file mode 100644 index 000000000..66604ef58 --- /dev/null +++ b/src/openklant2/types/resources/partij_identificator.py @@ -0,0 +1,53 @@ +from typing import NotRequired + +from pydantic import TypeAdapter +from typing_extensions import TypedDict + +# +# Input +# + + +class PartijIdentificatorObject(TypedDict): + codeObjecttype: str + codeSoortObjectId: str + objectId: str + codeRegister: str + + +class CreateIdentificeerdePartij(TypedDict): + uuid: str + + +class CreatePartijIdentificatorData(TypedDict): + identificeerdePartij: CreateIdentificeerdePartij + partijIdentificator: PartijIdentificatorObject + anderePartijIdentificator: NotRequired[str] + + +class ListPartijIdentificatorenParams(TypedDict, total=False): + page: int + partijIdentificatorCodeObjecttype: str + partijIdentificatorCodeRegister: str + partijIdentificatorCodeSoortObjectId: str + partijIdentificatorObjectId: str + + +# +# Output +# + + +class IdentificerendePartij(TypedDict): + uuid: str + url: str + + +class PartijIdentificator(TypedDict): + identificeerdePartij: IdentificerendePartij + partijIdentificator: PartijIdentificatorObject + anderePartijIdentificator: NotRequired[str] + + +CreatePartijIdentificatorDataValidator = TypeAdapter(CreatePartijIdentificatorData) +PartijIdentificatorValidator = TypeAdapter(PartijIdentificator) diff --git a/src/openklant2/utils/__init__.py b/src/openklant2/utils/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/openklant2/utils/test.py b/src/openklant2/utils/test.py new file mode 100644 index 000000000..e69de29bb