diff --git a/requirements/base.in b/requirements/base.in index 85404fb146..4a65809223 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -50,6 +50,7 @@ django-mailer django-image-cropping django-log-outgoing-requests xsdata +django-setup-configuration # django cms django-cms diff --git a/requirements/base.txt b/requirements/base.txt index 3d5746d504..8447121044 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -115,6 +115,7 @@ django==4.2.10 # django-relativedelta # django-sekizai # django-sendfile2 + # django-setup-configuration # django-simple-certmanager # django-sniplates # django-solo @@ -237,6 +238,8 @@ django-sessionprofile==1.0 # via # -r requirements/base.in # django-digid-eherkenning +django-setup-configuration==0.1.0 + # via -r requirements/base.in django-simple-certmanager==1.4.1 # via # django-digid-eherkenning diff --git a/requirements/ci.txt b/requirements/ci.txt index 2c3f02038d..8eb45f7925 100644 --- a/requirements/ci.txt +++ b/requirements/ci.txt @@ -192,6 +192,7 @@ django==4.2.10 # django-relativedelta # django-sekizai # django-sendfile2 + # django-setup-configuration # django-simple-certmanager # django-sniplates # django-solo @@ -399,6 +400,10 @@ django-sessionprofile==1.0 # -c requirements/base.txt # -r requirements/base.txt # django-digid-eherkenning +django-setup-configuration==0.1.0 + # via + # -c requirements/base.txt + # -r requirements/base.txt django-simple-certmanager==1.4.1 # via # -c requirements/base.txt diff --git a/requirements/dev.txt b/requirements/dev.txt index 949a18cdea..3f828b0a9b 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -230,6 +230,7 @@ django==4.2.10 # django-relativedelta # django-sekizai # django-sendfile2 + # django-setup-configuration # django-silk # django-simple-certmanager # django-sniplates @@ -442,6 +443,10 @@ django-sessionprofile==1.0 # -c requirements/ci.txt # -r requirements/ci.txt # django-digid-eherkenning +django-setup-configuration==0.1.0 + # via + # -c requirements/ci.txt + # -r requirements/ci.txt django-silk==5.1.0 # via -r requirements/dev.in django-simple-certmanager==1.4.1 diff --git a/src/open_inwoner/cms/cases/views/status.py b/src/open_inwoner/cms/cases/views/status.py index 31956ef8ea..21f29ccd06 100644 --- a/src/open_inwoner/cms/cases/views/status.py +++ b/src/open_inwoner/cms/cases/views/status.py @@ -938,10 +938,8 @@ def register_by_api(self, form, config: OpenKlantConfig): if ztc and ztc.contact_subject_code: data["onderwerp"] = ztc.contact_subject_code - if contactmomenten_client := build_client_openklant("contactmomenten"): - contactmoment = contactmomenten_client.create_contactmoment( - data, klant=klant - ) + if contactmoment_client := build_client_openklant("contactmomenten"): + contactmoment = contactmoment_client.create_contactmoment(data, klant=klant) if contactmoment: self.log_system_action( "registered contactmoment by API", user=self.request.user diff --git a/src/open_inwoner/conf/app/setup_configuration.py b/src/open_inwoner/conf/app/setup_configuration.py new file mode 100644 index 0000000000..b55a19b8a5 --- /dev/null +++ b/src/open_inwoner/conf/app/setup_configuration.py @@ -0,0 +1,103 @@ +from ..utils import config + +SETUP_CONFIGURATION_STEPS = [ + "open_inwoner.configurations.bootstrap.zgw.ZakenAPIConfigurationStep", + "open_inwoner.configurations.bootstrap.zgw.CatalogiAPIConfigurationStep", + "open_inwoner.configurations.bootstrap.zgw.DocumentenAPIConfigurationStep", + "open_inwoner.configurations.bootstrap.zgw.FormulierenAPIConfigurationStep", + "open_inwoner.configurations.bootstrap.zgw.ZGWAPIsConfigurationStep", + "open_inwoner.configurations.bootstrap.kic.KlantenAPIConfigurationStep", + "open_inwoner.configurations.bootstrap.kic.ContactmomentenAPIConfigurationStep", + "open_inwoner.configurations.bootstrap.kic.KICAPIsConfigurationStep", +] +OIP_ORGANIZATION = config("OIP_ORGANIZATION", "") + +# ZGW configuration variables +ZGW_CONFIG_ENABLE = config("ZGW_CONFIG_ENABLE", default=True) +ZGW_CONFIG_ZAKEN_API_ROOT = config("ZGW_CONFIG_ZAKEN_API_ROOT", "") +if ZGW_CONFIG_ZAKEN_API_ROOT and not ZGW_CONFIG_ZAKEN_API_ROOT.endswith("/"): + ZGW_CONFIG_ZAKEN_API_ROOT = f"{ZGW_CONFIG_ZAKEN_API_ROOT.strip()}/" +ZGW_CONFIG_ZAKEN_OAS_URL = ZGW_CONFIG_ZAKEN_API_ROOT # this is still required by the form, but not actually used +ZGW_CONFIG_ZAKEN_API_CLIENT_ID = config("ZGW_CONFIG_ZAKEN_API_CLIENT_ID", "") +ZGW_CONFIG_ZAKEN_API_SECRET = config("ZGW_CONFIG_ZAKEN_API_SECRET", "") +ZGW_CONFIG_CATALOGI_API_ROOT = config("ZGW_CONFIG_CATALOGI_API_ROOT", "") +if ZGW_CONFIG_CATALOGI_API_ROOT and not ZGW_CONFIG_CATALOGI_API_ROOT.endswith("/"): + ZGW_CONFIG_CATALOGI_API_ROOT = f"{ZGW_CONFIG_CATALOGI_API_ROOT.strip()}/" +ZGW_CONFIG_CATALOGI_OAS_URL = ZGW_CONFIG_CATALOGI_API_ROOT # this is still required by the form, but not actually used +ZGW_CONFIG_CATALOGI_API_CLIENT_ID = config("ZGW_CONFIG_CATALOGI_API_CLIENT_ID", "") +ZGW_CONFIG_CATALOGI_API_SECRET = config("ZGW_CONFIG_CATALOGI_API_SECRET", "") +ZGW_CONFIG_DOCUMENTEN_API_ROOT = config("ZGW_CONFIG_DOCUMENTEN_API_ROOT", "") +if ZGW_CONFIG_DOCUMENTEN_API_ROOT and not ZGW_CONFIG_DOCUMENTEN_API_ROOT.endswith("/"): + ZGW_CONFIG_DOCUMENTEN_API_ROOT = f"{ZGW_CONFIG_DOCUMENTEN_API_ROOT.strip()}/" +ZGW_CONFIG_DOCUMENTEN_OAS_URL = ZGW_CONFIG_DOCUMENTEN_API_ROOT # this is still required by the form, but not actually used +ZGW_CONFIG_DOCUMENTEN_API_CLIENT_ID = config("ZGW_CONFIG_DOCUMENTEN_API_CLIENT_ID", "") +ZGW_CONFIG_DOCUMENTEN_API_SECRET = config("ZGW_CONFIG_DOCUMENTEN_API_SECRET", "") +ZGW_CONFIG_FORMULIEREN_API_ROOT = config("ZGW_CONFIG_FORMULIEREN_API_ROOT", "") +if ZGW_CONFIG_FORMULIEREN_API_ROOT and not ZGW_CONFIG_FORMULIEREN_API_ROOT.endswith( + "/" +): + ZGW_CONFIG_FORMULIEREN_API_ROOT = f"{ZGW_CONFIG_FORMULIEREN_API_ROOT.strip()}/" +ZGW_CONFIG_FORMULIEREN_OAS_URL = ZGW_CONFIG_FORMULIEREN_API_ROOT # this is still required by the form, but not actually used +ZGW_CONFIG_FORMULIEREN_API_CLIENT_ID = config( + "ZGW_CONFIG_FORMULIEREN_API_CLIENT_ID", "" +) +ZGW_CONFIG_FORMULIEREN_API_SECRET = config("ZGW_CONFIG_FORMULIEREN_API_SECRET", "") +# ZGW config options +ZGW_CONFIG_ZAAK_MAX_CONFIDENTIALITY = config( + "ZGW_CONFIG_ZAAK_MAX_CONFIDENTIALITY", None +) +ZGW_CONFIG_DOCUMENT_MAX_CONFIDENTIALITY = config( + "ZGW_CONFIG_DOCUMENT_MAX_CONFIDENTIALITY", None +) +ZGW_CONFIG_ACTION_REQUIRED_DEADLINE_DAYS = config("ACTION_REQUIRED_DEADLINE_DAYS", None) +ZGW_CONFIG_ALLOWED_FILE_EXTENSIONS = config("ZGW_CONFIG_ALLOWED_FILE_EXTENSIONS", None) +ZGW_CONFIG_MIJN_AANVRAGEN_TITLE_TEXT = config( + "ZGW_CONFIG_MIJN_AANVRAGEN_TITLE_TEXT", None +) +ZGW_CONFIG_ENABLE_CATEGORIES_FILTERING_WITH_ZAKEN = config( + "ZGW_CONFIG_ENABLE_CATEGORIES_FILTERING_WITH_ZAKEN", None +) +ZGW_CONFIG_SKIP_NOTIFICATION_STATUSTYPE_INFORMEREN = config( + "ZGW_CONFIG_SKIP_NOTIFICATION_STATUSTYPE_INFORMEREN", None +) +ZGW_CONFIG_REFORMAT_ESUITE_ZAAK_IDENTIFICATIE = config( + "ZGW_CONFIG_REFORMAT_ESUITE_ZAAK_IDENTIFICATIE", None +) +ZGW_CONFIG_FETCH_EHERKENNING_ZAKEN_WITH_RSIN = config( + "ZGW_CONFIG_FETCH_EHERKENNING_ZAKEN_WITH_RSIN", None +) + +# KIC configuration variables +KIC_CONFIG_ENABLE = config("KIC_CONFIG_ENABLE", default=True) +KIC_CONFIG_KLANTEN_API_ROOT = config("KIC_CONFIG_KLANTEN_API_ROOT", "") +if KIC_CONFIG_KLANTEN_API_ROOT and not KIC_CONFIG_KLANTEN_API_ROOT.endswith("/"): + KIC_CONFIG_KLANTEN_API_ROOT = f"{KIC_CONFIG_KLANTEN_API_ROOT.strip()}/" +KIC_CONFIG_KLANTEN_OAS_URL = KIC_CONFIG_KLANTEN_API_ROOT # this is still required by the form, but not actually used +KIC_CONFIG_KLANTEN_API_CLIENT_ID = config("KIC_CONFIG_KLANTEN_API_CLIENT_ID", "") +KIC_CONFIG_KLANTEN_API_SECRET = config("KIC_CONFIG_KLANTEN_API_SECRET", "") +KIC_CONFIG_CONTACTMOMENTEN_API_ROOT = config("KIC_CONFIG_CONTACTMOMENTEN_API_ROOT", "") +if ( + KIC_CONFIG_CONTACTMOMENTEN_API_ROOT + and not KIC_CONFIG_CONTACTMOMENTEN_API_ROOT.endswith("/") +): + KIC_CONFIG_CONTACTMOMENTEN_API_ROOT = ( + f"{KIC_CONFIG_CONTACTMOMENTEN_API_ROOT.strip()}/" + ) +KIC_CONFIG_CONTACTMOMENTEN_OAS_URL = KIC_CONFIG_CONTACTMOMENTEN_API_ROOT # this is still required by the form, but not actually used +KIC_CONFIG_CONTACTMOMENTEN_API_CLIENT_ID = config( + "KIC_CONFIG_CONTACTMOMENTEN_API_CLIENT_ID", "" +) +KIC_CONFIG_CONTACTMOMENTEN_API_SECRET = config( + "KIC_CONFIG_CONTACTMOMENTEN_API_SECRET", "" +) +KIC_CONFIG_REGISTER_EMAIL = config("KIC_CONFIG_REGISTER_EMAIL", None) +KIC_CONFIG_REGISTER_CONTACT_MOMENT = config("KIC_CONFIG_REGISTER_CONTACT_MOMENT", None) +KIC_CONFIG_REGISTER_BRONORGANISATIE_RSIN = config( + "KIC_CONFIG_REGISTER_BRONORGANISATIE_RSIN", None +) +KIC_CONFIG_REGISTER_CHANNEL = config("KIC_CONFIG_REGISTER_CHANNEL", None) +KIC_CONFIG_REGISTER_TYPE = config("KIC_CONFIG_REGISTER_TYPE", None) +KIC_CONFIG_REGISTER_EMPLOYEE_ID = config("KIC_CONFIG_REGISTER_EMPLOYEE_ID", None) +KIC_CONFIG_USE_RSIN_FOR_INNNNPID_QUERY_PARAMETER = config( + "KIC_CONFIG_USE_RSIN_FOR_INNNNPID_QUERY_PARAMETER", None +) diff --git a/src/open_inwoner/conf/base.py b/src/open_inwoner/conf/base.py index d6d5480f64..72cafd55fd 100644 --- a/src/open_inwoner/conf/base.py +++ b/src/open_inwoner/conf/base.py @@ -201,6 +201,7 @@ "mailer", "log_outgoing_requests", "formtools", + "django_setup_configuration", # Project applications. "open_inwoner.components", "open_inwoner.kvk", @@ -929,6 +930,10 @@ } } +# +# django-setup-configuration +# +from .app.setup_configuration import * # noqa # # Project specific settings diff --git a/src/open_inwoner/configurations/bootstrap/__init__.py b/src/open_inwoner/configurations/bootstrap/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/open_inwoner/configurations/bootstrap/kic.py b/src/open_inwoner/configurations/bootstrap/kic.py new file mode 100644 index 0000000000..d48d47401e --- /dev/null +++ b/src/open_inwoner/configurations/bootstrap/kic.py @@ -0,0 +1,167 @@ +from django.conf import settings + +import requests +from django_setup_configuration.configuration import BaseConfigurationStep +from django_setup_configuration.exceptions import SelfTestFailed +from zgw_consumers.constants import APITypes, AuthTypes +from zgw_consumers.models import Service + +from open_inwoner.openklant.clients import build_client +from open_inwoner.openklant.models import OpenKlantConfig +from open_inwoner.utils.api import ClientError + + +class KlantenAPIConfigurationStep(BaseConfigurationStep): + """ + Configure the required Service to establish a connection with the Klanten API + """ + + verbose_name = "Klanten API configuration" + required_settings = [ + "KIC_CONFIG_KLANTEN_API_ROOT", + "KIC_CONFIG_KLANTEN_API_CLIENT_ID", + "KIC_CONFIG_KLANTEN_API_SECRET", + ] + enable_setting = "KIC_CONFIG_ENABLE" + + def is_configured(self) -> bool: + return Service.objects.filter( + api_root=settings.KIC_CONFIG_KLANTEN_API_ROOT + ).exists() + + def configure(self): + organization = settings.OIP_ORGANIZATION or settings.ENVIRONMENT + org_label = f"Open Inwoner {organization}".strip() + + Service.objects.update_or_create( + api_root=settings.KIC_CONFIG_KLANTEN_API_ROOT, + defaults={ + "label": "Klanten API", + "api_type": APITypes.kc, + "oas": settings.KIC_CONFIG_KLANTEN_API_ROOT, + "auth_type": AuthTypes.zgw, + "client_id": settings.KIC_CONFIG_KLANTEN_API_CLIENT_ID, + "secret": settings.KIC_CONFIG_KLANTEN_API_SECRET, + "user_id": settings.KIC_CONFIG_KLANTEN_API_CLIENT_ID, + "user_representation": org_label, + }, + ) + + def test_configuration(self): + """ + actual testing is done in final step + """ + + +class ContactmomentenAPIConfigurationStep(BaseConfigurationStep): + """ + Configure the required Service to establish a connection with the Contactmomenten API + """ + + verbose_name = "Contactmomenten API configuration" + required_settings = [ + "KIC_CONFIG_CONTACTMOMENTEN_API_ROOT", + "KIC_CONFIG_CONTACTMOMENTEN_API_CLIENT_ID", + "KIC_CONFIG_CONTACTMOMENTEN_API_SECRET", + ] + enable_setting = "KIC_CONFIG_ENABLE" + + def is_configured(self) -> bool: + return Service.objects.filter( + api_root=settings.KIC_CONFIG_CONTACTMOMENTEN_API_ROOT + ).exists() + + def configure(self): + organization = settings.OIP_ORGANIZATION or settings.ENVIRONMENT + org_label = f"Open Inwoner {organization}".strip() + + Service.objects.update_or_create( + api_root=settings.KIC_CONFIG_CONTACTMOMENTEN_API_ROOT, + defaults={ + "label": "Contactmomenten API", + "api_type": APITypes.cmc, + "oas": settings.KIC_CONFIG_CONTACTMOMENTEN_API_ROOT, + "auth_type": AuthTypes.zgw, + "client_id": settings.KIC_CONFIG_CONTACTMOMENTEN_API_CLIENT_ID, + "secret": settings.KIC_CONFIG_CONTACTMOMENTEN_API_SECRET, + "user_id": settings.KIC_CONFIG_CONTACTMOMENTEN_API_CLIENT_ID, + "user_representation": org_label, + }, + ) + + def test_configuration(self): + """ + actual testing is done in final step + """ + + +class KICAPIsConfigurationStep(BaseConfigurationStep): + """ + Configure the KIC settings and set any feature flags or other options if specified + """ + + verbose_name = "Klantinteractie APIs configuration" + enable_setting = "KIC_CONFIG_ENABLE" + + def is_configured(self) -> bool: + kic_config = OpenKlantConfig.get_solo() + return bool(kic_config.klanten_service) and bool( + kic_config.contactmomenten_service + ) + + def configure(self): + config = OpenKlantConfig.get_solo() + config.klanten_service = Service.objects.get( + api_root=settings.KIC_CONFIG_KLANTEN_API_ROOT + ) + config.contactmomenten_service = Service.objects.get( + api_root=settings.KIC_CONFIG_CONTACTMOMENTEN_API_ROOT + ) + + if settings.KIC_CONFIG_REGISTER_EMAIL: + config.register_email = settings.KIC_CONFIG_REGISTER_EMAIL + if settings.KIC_CONFIG_REGISTER_CONTACT_MOMENT is not None: + config.register_contact_moment = settings.KIC_CONFIG_REGISTER_CONTACT_MOMENT + if settings.KIC_CONFIG_REGISTER_BRONORGANISATIE_RSIN: + config.register_bronorganisatie_rsin = ( + settings.KIC_CONFIG_REGISTER_BRONORGANISATIE_RSIN + ) + if settings.KIC_CONFIG_REGISTER_CHANNEL: + config.register_channel = settings.KIC_CONFIG_REGISTER_CHANNEL + if settings.KIC_CONFIG_REGISTER_TYPE: + config.register_type = settings.KIC_CONFIG_REGISTER_TYPE + if settings.KIC_CONFIG_REGISTER_EMPLOYEE_ID: + config.register_employee_id = settings.KIC_CONFIG_REGISTER_EMPLOYEE_ID + if settings.KIC_CONFIG_USE_RSIN_FOR_INNNNPID_QUERY_PARAMETER is not None: + config.use_rsin_for_innNnpId_query_parameter = ( + settings.KIC_CONFIG_USE_RSIN_FOR_INNNNPID_QUERY_PARAMETER + ) + + config.save() + + def test_configuration(self): + """ + make requests to the APIs and verify that a connection can be made + """ + klanten_client = build_client("klanten") + contactmoment_client = build_client("contactmomenten") + + try: + response = klanten_client.get( + "klanten", params={"subjectNatuurlijkPersoon__inpBsn": "000000000"} + ) + response.raise_for_status() + except (ClientError, requests.RequestException) as exc: + raise SelfTestFailed( + "Could not retrieve list of klanten from Klanten API." + ) from exc + + try: + response = contactmoment_client.get( + "contactmomenten", params={"identificatie": "00000"} + ) + response.raise_for_status() + except (ClientError, requests.RequestException) as exc: + raise SelfTestFailed( + "Could not retrieve list of objectcontactmomenten from Contactmomenten API." + ) from exc diff --git a/src/open_inwoner/configurations/bootstrap/zgw.py b/src/open_inwoner/configurations/bootstrap/zgw.py new file mode 100644 index 0000000000..8e65cfde89 --- /dev/null +++ b/src/open_inwoner/configurations/bootstrap/zgw.py @@ -0,0 +1,295 @@ +from django.conf import settings + +import requests +from django_setup_configuration.configuration import BaseConfigurationStep +from django_setup_configuration.exceptions import SelfTestFailed +from zgw_consumers.constants import APITypes, AuthTypes +from zgw_consumers.models import Service + +from open_inwoner.openzaak.clients import build_client +from open_inwoner.openzaak.models import OpenZaakConfig +from open_inwoner.utils.api import ClientError + + +class ZakenAPIConfigurationStep(BaseConfigurationStep): + """ + Configure the required Service to establish a connection with the Zaken API + """ + + verbose_name = "Zaken API configuration" + required_settings = [ + "ZGW_CONFIG_ZAKEN_API_ROOT", + "ZGW_CONFIG_ZAKEN_API_CLIENT_ID", + "ZGW_CONFIG_ZAKEN_API_SECRET", + ] + enable_setting = "ZGW_CONFIG_ENABLE" + + def is_configured(self) -> bool: + return Service.objects.filter( + api_root=settings.ZGW_CONFIG_ZAKEN_API_ROOT + ).exists() + + def configure(self): + organization = settings.OIP_ORGANIZATION or settings.ENVIRONMENT + org_label = f"Open Inwoner {organization}".strip() + + Service.objects.update_or_create( + api_root=settings.ZGW_CONFIG_ZAKEN_API_ROOT, + defaults={ + "label": "Zaken API", + "api_type": APITypes.zrc, + "oas": settings.ZGW_CONFIG_ZAKEN_API_ROOT, + "auth_type": AuthTypes.zgw, + "client_id": settings.ZGW_CONFIG_ZAKEN_API_CLIENT_ID, + "secret": settings.ZGW_CONFIG_ZAKEN_API_SECRET, + "user_id": settings.ZGW_CONFIG_ZAKEN_API_CLIENT_ID, + "user_representation": org_label, + }, + ) + + def test_configuration(self): + """ + actual testing is done in final step + """ + + +class CatalogiAPIConfigurationStep(BaseConfigurationStep): + """ + Configure the required Service to establish a connection with the Catalogi API + """ + + verbose_name = "Catalogi API configuration" + required_settings = [ + "ZGW_CONFIG_CATALOGI_API_ROOT", + "ZGW_CONFIG_CATALOGI_API_CLIENT_ID", + "ZGW_CONFIG_CATALOGI_API_SECRET", + ] + enable_setting = "ZGW_CONFIG_ENABLE" + + def is_configured(self) -> bool: + return Service.objects.filter( + api_root=settings.ZGW_CONFIG_CATALOGI_API_ROOT + ).exists() + + def configure(self): + organization = settings.OIP_ORGANIZATION or settings.ENVIRONMENT + org_label = f"Open Inwoner {organization}".strip() + + Service.objects.update_or_create( + api_root=settings.ZGW_CONFIG_CATALOGI_API_ROOT, + defaults={ + "label": "Catalogi API", + "api_type": APITypes.ztc, + "oas": settings.ZGW_CONFIG_CATALOGI_API_ROOT, + "auth_type": AuthTypes.zgw, + "client_id": settings.ZGW_CONFIG_CATALOGI_API_CLIENT_ID, + "secret": settings.ZGW_CONFIG_CATALOGI_API_SECRET, + "user_id": settings.ZGW_CONFIG_CATALOGI_API_CLIENT_ID, + "user_representation": org_label, + }, + ) + + def test_configuration(self): + """ + actual testing is done in final step + """ + + +class DocumentenAPIConfigurationStep(BaseConfigurationStep): + """ + Configure the required Service to establish a connection with the Documenten API + """ + + verbose_name = "Documenten API configuration" + required_settings = [ + "ZGW_CONFIG_DOCUMENTEN_API_ROOT", + "ZGW_CONFIG_DOCUMENTEN_API_CLIENT_ID", + "ZGW_CONFIG_DOCUMENTEN_API_SECRET", + ] + enable_setting = "ZGW_CONFIG_ENABLE" + + def is_configured(self) -> bool: + return Service.objects.filter( + api_root=settings.ZGW_CONFIG_DOCUMENTEN_API_ROOT + ).exists() + + def configure(self): + organization = settings.OIP_ORGANIZATION or settings.ENVIRONMENT + org_label = f"Open Inwoner {organization}".strip() + + Service.objects.update_or_create( + api_root=settings.ZGW_CONFIG_DOCUMENTEN_API_ROOT, + defaults={ + "label": "Documenten API", + "api_type": APITypes.drc, + "oas": settings.ZGW_CONFIG_DOCUMENTEN_API_ROOT, + "auth_type": AuthTypes.zgw, + "client_id": settings.ZGW_CONFIG_DOCUMENTEN_API_CLIENT_ID, + "secret": settings.ZGW_CONFIG_DOCUMENTEN_API_SECRET, + "user_id": settings.ZGW_CONFIG_DOCUMENTEN_API_CLIENT_ID, + "user_representation": org_label, + }, + ) + + def test_configuration(self): + """ + actual testing is done in final step + """ + + +class FormulierenAPIConfigurationStep(BaseConfigurationStep): + """ + Configure the required Service to establish a connection with the Formulieren API + """ + + verbose_name = "Formulieren APIs configuration" + required_settings = [ + "ZGW_CONFIG_FORMULIEREN_API_ROOT", + "ZGW_CONFIG_FORMULIEREN_API_CLIENT_ID", + "ZGW_CONFIG_FORMULIEREN_API_SECRET", + ] + enable_setting = "ZGW_CONFIG_ENABLE" + + def is_configured(self) -> bool: + return Service.objects.filter( + api_root=settings.ZGW_CONFIG_FORMULIEREN_API_ROOT + ).exists() + + def configure(self): + organization = settings.OIP_ORGANIZATION or settings.ENVIRONMENT + org_label = f"Open Inwoner {organization}".strip() + + Service.objects.update_or_create( + api_root=settings.ZGW_CONFIG_FORMULIEREN_API_ROOT, + defaults={ + "label": "Formulieren API", + "api_type": APITypes.orc, + "oas": settings.ZGW_CONFIG_FORMULIEREN_API_ROOT, + "auth_type": AuthTypes.zgw, + "client_id": settings.ZGW_CONFIG_FORMULIEREN_API_CLIENT_ID, + "secret": settings.ZGW_CONFIG_FORMULIEREN_API_SECRET, + "user_id": settings.ZGW_CONFIG_FORMULIEREN_API_CLIENT_ID, + "user_representation": org_label, + }, + ) + + def test_configuration(self): + """ + actual testing is done in final step + """ + + +class ZGWAPIsConfigurationStep(BaseConfigurationStep): + """ + Configure the ZGW settings and set any feature flags or other options if specified + """ + + verbose_name = "ZGW APIs configuration" + enable_setting = "ZGW_CONFIG_ENABLE" + + def is_configured(self) -> bool: + zgw_config = OpenZaakConfig.get_solo() + return ( + bool(zgw_config.zaak_service) + and bool(zgw_config.catalogi_service) + and bool(zgw_config.document_service) + and bool(zgw_config.form_service) + ) + + def configure(self): + config = OpenZaakConfig.get_solo() + config.zaak_service = Service.objects.get( + api_root=settings.ZGW_CONFIG_ZAKEN_API_ROOT + ) + config.catalogi_service = Service.objects.get( + api_root=settings.ZGW_CONFIG_CATALOGI_API_ROOT + ) + config.document_service = Service.objects.get( + api_root=settings.ZGW_CONFIG_DOCUMENTEN_API_ROOT + ) + config.form_service = Service.objects.get( + api_root=settings.ZGW_CONFIG_FORMULIEREN_API_ROOT + ) + + # General config options + if settings.ZGW_CONFIG_ZAAK_MAX_CONFIDENTIALITY: + config.zaak_max_confidentiality = ( + settings.ZGW_CONFIG_ZAAK_MAX_CONFIDENTIALITY + ) + if settings.ZGW_CONFIG_DOCUMENT_MAX_CONFIDENTIALITY: + config.document_max_confidentiality = ( + settings.ZGW_CONFIG_DOCUMENT_MAX_CONFIDENTIALITY + ) + if settings.ZGW_CONFIG_ACTION_REQUIRED_DEADLINE_DAYS: + config.action_required_deadline_days = ( + settings.ZGW_CONFIG_ACTION_REQUIRED_DEADLINE_DAYS + ) + if settings.ZGW_CONFIG_ALLOWED_FILE_EXTENSIONS: + config.allowed_file_extensions = settings.ZGW_CONFIG_ALLOWED_FILE_EXTENSIONS + if settings.ZGW_CONFIG_MIJN_AANVRAGEN_TITLE_TEXT: + config.title_text = settings.ZGW_CONFIG_MIJN_AANVRAGEN_TITLE_TEXT + + # Feature flags + if settings.ZGW_CONFIG_ENABLE_CATEGORIES_FILTERING_WITH_ZAKEN is not None: + config.enable_categories_filtering_with_zaken = ( + settings.ZGW_CONFIG_ENABLE_CATEGORIES_FILTERING_WITH_ZAKEN + ) + + # eSuite specific options + if settings.ZGW_CONFIG_SKIP_NOTIFICATION_STATUSTYPE_INFORMEREN is not None: + config.skip_notification_statustype_informeren = ( + settings.ZGW_CONFIG_SKIP_NOTIFICATION_STATUSTYPE_INFORMEREN + ) + if settings.ZGW_CONFIG_REFORMAT_ESUITE_ZAAK_IDENTIFICATIE is not None: + config.reformat_esuite_zaak_identificatie = ( + settings.ZGW_CONFIG_REFORMAT_ESUITE_ZAAK_IDENTIFICATIE + ) + if settings.ZGW_CONFIG_FETCH_EHERKENNING_ZAKEN_WITH_RSIN is not None: + config.fetch_eherkenning_zaken_with_rsin = ( + settings.ZGW_CONFIG_FETCH_EHERKENNING_ZAKEN_WITH_RSIN + ) + + config.save() + + def test_configuration(self): + """ + make requests to each API and verify that a connection can be made + """ + zaken_client = build_client("zaak") + catalogi_client = build_client("catalogi") + documenten_client = build_client("document") + forms_client = build_client("form") + + try: + response = zaken_client.get("statussen") + response.raise_for_status() + except (ClientError, requests.RequestException) as exc: + raise SelfTestFailed( + "Could not retrieve list of statussen from Zaken API." + ) from exc + + try: + response = catalogi_client.get("zaaktypen") + response.raise_for_status() + except (ClientError, requests.RequestException) as exc: + raise SelfTestFailed( + "Could not retrieve list of zaaktypen from Catalogi API." + ) from exc + + try: + response = documenten_client.get("objectinformatieobjecten") + response.raise_for_status() + except (ClientError, requests.RequestException) as exc: + raise SelfTestFailed( + "Could not retrieve list of ObjectInformatieObjecten from Documenten API." + ) from exc + + try: + response = forms_client.get( + "openstaande-inzendingen", params={"bsn": "000000000"} + ) + response.raise_for_status() + except (ClientError, requests.RequestException) as exc: + raise SelfTestFailed( + "Could not retrieve list of open submissions from Formulieren API." + ) from exc diff --git a/src/open_inwoner/configurations/tests/bootstrap/__init__.py b/src/open_inwoner/configurations/tests/bootstrap/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/open_inwoner/configurations/tests/bootstrap/test_setup_kic_config.py b/src/open_inwoner/configurations/tests/bootstrap/test_setup_kic_config.py new file mode 100644 index 0000000000..b0c4cae846 --- /dev/null +++ b/src/open_inwoner/configurations/tests/bootstrap/test_setup_kic_config.py @@ -0,0 +1,155 @@ +from django.test import TestCase, override_settings + +import requests +import requests_mock +from django_setup_configuration.exceptions import SelfTestFailed + +from open_inwoner.openklant.models import OpenKlantConfig + +from ...bootstrap.kic import ( + ContactmomentenAPIConfigurationStep, + KICAPIsConfigurationStep, + KlantenAPIConfigurationStep, +) + +KLANTEN_API_ROOT = "https://openklant.local/klanten/api/v1/" +CONTACTMOMENTEN_API_ROOT = "https://openklant.local/contactmomenten/api/v1/" + + +@override_settings( + OIP_ORGANIZATION="Maykin", + KIC_CONFIG_KLANTEN_API_ROOT=KLANTEN_API_ROOT, + KIC_CONFIG_KLANTEN_API_CLIENT_ID="open-inwoner-test", + KIC_CONFIG_KLANTEN_API_SECRET="klanten-secret", + KIC_CONFIG_CONTACTMOMENTEN_API_ROOT=CONTACTMOMENTEN_API_ROOT, + KIC_CONFIG_CONTACTMOMENTEN_API_CLIENT_ID="open-inwoner-test", + KIC_CONFIG_CONTACTMOMENTEN_API_SECRET="contactmomenten-secret", + KIC_CONFIG_REGISTER_EMAIL="admin@oip.org", + KIC_CONFIG_REGISTER_CONTACT_MOMENT=True, + KIC_CONFIG_REGISTER_BRONORGANISATIE_RSIN="837194569", + KIC_CONFIG_REGISTER_CHANNEL="email", + KIC_CONFIG_REGISTER_TYPE="bericht", + KIC_CONFIG_REGISTER_EMPLOYEE_ID="1234", + KIC_CONFIG_USE_RSIN_FOR_INNNNPID_QUERY_PARAMETER=False, +) +class KICConfigurationTests(TestCase): + def test_configure(self): + KlantenAPIConfigurationStep().configure() + ContactmomentenAPIConfigurationStep().configure() + configuration = KICAPIsConfigurationStep() + + configuration.configure() + + config = OpenKlantConfig.get_solo() + klanten_service = config.klanten_service + contactmomenten_service = config.contactmomenten_service + + self.assertEqual(klanten_service.api_root, KLANTEN_API_ROOT) + self.assertEqual(klanten_service.client_id, "open-inwoner-test") + self.assertEqual(klanten_service.secret, "klanten-secret") + self.assertEqual(contactmomenten_service.api_root, CONTACTMOMENTEN_API_ROOT) + self.assertEqual(contactmomenten_service.client_id, "open-inwoner-test") + self.assertEqual(contactmomenten_service.secret, "contactmomenten-secret") + + self.assertEqual(config.register_email, "admin@oip.org") + self.assertEqual(config.register_contact_moment, True) + self.assertEqual(config.register_bronorganisatie_rsin, "837194569") + self.assertEqual(config.register_channel, "email") + self.assertEqual(config.register_type, "bericht") + self.assertEqual(config.register_employee_id, "1234") + self.assertEqual(config.use_rsin_for_innNnpId_query_parameter, False) + + @override_settings( + OIP_ORGANIZATION=None, + KIC_CONFIG_REGISTER_EMAIL=None, + KIC_CONFIG_REGISTER_CONTACT_MOMENT=None, + KIC_CONFIG_REGISTER_BRONORGANISATIE_RSIN=None, + KIC_CONFIG_REGISTER_CHANNEL=None, + KIC_CONFIG_REGISTER_TYPE=None, + KIC_CONFIG_REGISTER_EMPLOYEE_ID=None, + KIC_CONFIG_USE_RSIN_FOR_INNNNPID_QUERY_PARAMETER=None, + ) + def test_configure_use_defaults(self): + KlantenAPIConfigurationStep().configure() + ContactmomentenAPIConfigurationStep().configure() + configuration = KICAPIsConfigurationStep() + + configuration.configure() + + config = OpenKlantConfig.get_solo() + klanten_service = config.klanten_service + contactmomenten_service = config.contactmomenten_service + + self.assertEqual(klanten_service.api_root, KLANTEN_API_ROOT) + self.assertEqual(klanten_service.client_id, "open-inwoner-test") + self.assertEqual(klanten_service.secret, "klanten-secret") + self.assertEqual(contactmomenten_service.api_root, CONTACTMOMENTEN_API_ROOT) + self.assertEqual(contactmomenten_service.client_id, "open-inwoner-test") + self.assertEqual(contactmomenten_service.secret, "contactmomenten-secret") + + self.assertEqual(config.register_email, "") + self.assertEqual(config.register_contact_moment, False) + self.assertEqual(config.register_bronorganisatie_rsin, "") + self.assertEqual(config.register_channel, "contactformulier") + self.assertEqual(config.register_type, "Melding") + self.assertEqual(config.register_employee_id, "") + self.assertEqual(config.use_rsin_for_innNnpId_query_parameter, True) + + @requests_mock.Mocker() + def test_configuration_check_ok(self, m): + KlantenAPIConfigurationStep().configure() + ContactmomentenAPIConfigurationStep().configure() + configuration = KICAPIsConfigurationStep() + + configuration.configure() + + m.get(f"{KLANTEN_API_ROOT}klanten", json=[]) + m.get(f"{CONTACTMOMENTEN_API_ROOT}contactmomenten", json=[]) + + configuration.test_configuration() + + status_request, zaaktype_request = m.request_history + + self.assertEqual( + status_request.url, + f"{KLANTEN_API_ROOT}klanten?subjectNatuurlijkPersoon__inpBsn=000000000", + ) + self.assertEqual( + zaaktype_request.url, + f"{CONTACTMOMENTEN_API_ROOT}contactmomenten?identificatie=00000", + ) + + @requests_mock.Mocker() + def test_configuration_check_failures(self, m): + KlantenAPIConfigurationStep().configure() + ContactmomentenAPIConfigurationStep().configure() + configuration = KICAPIsConfigurationStep() + configuration.configure() + + mock_kwargs = ( + {"exc": requests.ConnectTimeout}, + {"exc": requests.ConnectionError}, + {"status_code": 404}, + {"status_code": 403}, + {"status_code": 500}, + ) + for mock_config in mock_kwargs: + with self.subTest(mock=mock_config): + m.get(f"{KLANTEN_API_ROOT}klanten", **mock_config) + + with self.assertRaises(SelfTestFailed): + configuration.test_configuration() + + def test_is_configured(self): + configs = [ + KlantenAPIConfigurationStep(), + ContactmomentenAPIConfigurationStep(), + KICAPIsConfigurationStep(), + ] + for config in configs: + with self.subTest(config=config.verbose_name): + self.assertFalse(config.is_configured()) + + config.configure() + + self.assertTrue(config.is_configured()) diff --git a/src/open_inwoner/configurations/tests/bootstrap/test_setup_zgw_config.py b/src/open_inwoner/configurations/tests/bootstrap/test_setup_zgw_config.py new file mode 100644 index 0000000000..c3009f4f0d --- /dev/null +++ b/src/open_inwoner/configurations/tests/bootstrap/test_setup_zgw_config.py @@ -0,0 +1,232 @@ +from django.test import TestCase, override_settings +from django.utils.translation import gettext as _ + +import requests +import requests_mock +from django_setup_configuration.exceptions import SelfTestFailed +from zgw_consumers.api_models.constants import VertrouwelijkheidsAanduidingen + +from open_inwoner.openzaak.models import ( + OpenZaakConfig, + generate_default_file_extensions, +) + +from ...bootstrap.zgw import ( + CatalogiAPIConfigurationStep, + DocumentenAPIConfigurationStep, + FormulierenAPIConfigurationStep, + ZakenAPIConfigurationStep, + ZGWAPIsConfigurationStep, +) + +ZAKEN_API_ROOT = "https://openzaak.local/zaken/api/v1/" +CATALOGI_API_ROOT = "https://openzaak.local/catalogi/api/v1/" +DOCUMENTEN_API_ROOT = "https://openzaak.local/documenten/api/v1/" +FORMULIEREN_API_ROOT = "https://esuite.local.net/formulieren-provider/api/v1/" + + +@override_settings( + OIP_ORGANIZATION="Maykin", + ZGW_CONFIG_ZAKEN_API_ROOT=ZAKEN_API_ROOT, + ZGW_CONFIG_ZAKEN_API_CLIENT_ID="open-inwoner-test", + ZGW_CONFIG_ZAKEN_API_SECRET="zaken-secret", + ZGW_CONFIG_CATALOGI_API_ROOT=CATALOGI_API_ROOT, + ZGW_CONFIG_CATALOGI_API_CLIENT_ID="open-inwoner-test", + ZGW_CONFIG_CATALOGI_API_SECRET="catalogi-secret", + ZGW_CONFIG_DOCUMENTEN_API_ROOT=DOCUMENTEN_API_ROOT, + ZGW_CONFIG_DOCUMENTEN_API_CLIENT_ID="open-inwoner-test", + ZGW_CONFIG_DOCUMENTEN_API_SECRET="documenten-secret", + ZGW_CONFIG_FORMULIEREN_API_ROOT=FORMULIEREN_API_ROOT, + ZGW_CONFIG_FORMULIEREN_API_CLIENT_ID="open-inwoner-test", + ZGW_CONFIG_FORMULIEREN_API_SECRET="forms-secret", + ZGW_CONFIG_ZAAK_MAX_CONFIDENTIALITY=VertrouwelijkheidsAanduidingen.vertrouwelijk, + ZGW_CONFIG_DOCUMENT_MAX_CONFIDENTIALITY=VertrouwelijkheidsAanduidingen.zaakvertrouwelijk, + ZGW_CONFIG_ACTION_REQUIRED_DEADLINE_DAYS=12, + ZGW_CONFIG_ALLOWED_FILE_EXTENSIONS=[".pdf", ".txt"], + ZGW_CONFIG_MIJN_AANVRAGEN_TITLE_TEXT="title text", + ZGW_CONFIG_ENABLE_CATEGORIES_FILTERING_WITH_ZAKEN=True, + ZGW_CONFIG_SKIP_NOTIFICATION_STATUSTYPE_INFORMEREN=True, + ZGW_CONFIG_REFORMAT_ESUITE_ZAAK_IDENTIFICATIE=True, + ZGW_CONFIG_FETCH_EHERKENNING_ZAKEN_WITH_RSIN=False, +) +class ZGWConfigurationTests(TestCase): + def test_configure(self): + ZakenAPIConfigurationStep().configure() + CatalogiAPIConfigurationStep().configure() + DocumentenAPIConfigurationStep().configure() + FormulierenAPIConfigurationStep().configure() + configuration = ZGWAPIsConfigurationStep() + + configuration.configure() + + config = OpenZaakConfig.get_solo() + zaak_service = config.zaak_service + catalogi_service = config.catalogi_service + document_service = config.document_service + form_service = config.form_service + + self.assertEqual(zaak_service.api_root, ZAKEN_API_ROOT) + self.assertEqual(zaak_service.client_id, "open-inwoner-test") + self.assertEqual(zaak_service.secret, "zaken-secret") + self.assertEqual(catalogi_service.api_root, CATALOGI_API_ROOT) + self.assertEqual(catalogi_service.client_id, "open-inwoner-test") + self.assertEqual(catalogi_service.secret, "catalogi-secret") + self.assertEqual(document_service.api_root, DOCUMENTEN_API_ROOT) + self.assertEqual(document_service.client_id, "open-inwoner-test") + self.assertEqual(document_service.secret, "documenten-secret") + self.assertEqual(form_service.api_root, FORMULIEREN_API_ROOT) + self.assertEqual(form_service.client_id, "open-inwoner-test") + self.assertEqual(form_service.secret, "forms-secret") + + self.assertEqual( + config.zaak_max_confidentiality, + VertrouwelijkheidsAanduidingen.vertrouwelijk, + ) + self.assertEqual( + config.document_max_confidentiality, + VertrouwelijkheidsAanduidingen.zaakvertrouwelijk, + ) + self.assertEqual(config.action_required_deadline_days, 12) + self.assertEqual(config.allowed_file_extensions, [".pdf", ".txt"]) + self.assertEqual(config.title_text, "title text") + self.assertEqual(config.enable_categories_filtering_with_zaken, True) + self.assertEqual(config.skip_notification_statustype_informeren, True) + self.assertEqual(config.reformat_esuite_zaak_identificatie, True) + self.assertEqual(config.fetch_eherkenning_zaken_with_rsin, False) + + @override_settings( + OIP_ORGANIZATION=None, + ZGW_CONFIG_ZAAK_MAX_CONFIDENTIALITY=None, + ZGW_CONFIG_DOCUMENT_MAX_CONFIDENTIALITY=None, + ZGW_CONFIG_ACTION_REQUIRED_DEADLINE_DAYS=None, + ZGW_CONFIG_ALLOWED_FILE_EXTENSIONS=None, + ZGW_CONFIG_MIJN_AANVRAGEN_TITLE_TEXT=None, + ZGW_CONFIG_ENABLE_CATEGORIES_FILTERING_WITH_ZAKEN=None, + ZGW_CONFIG_SKIP_NOTIFICATION_STATUSTYPE_INFORMEREN=None, + ZGW_CONFIG_REFORMAT_ESUITE_ZAAK_IDENTIFICATIE=None, + ZGW_CONFIG_FETCH_EHERKENNING_ZAKEN_WITH_RSIN=None, + ) + def test_configure_use_defaults(self): + ZakenAPIConfigurationStep().configure() + CatalogiAPIConfigurationStep().configure() + DocumentenAPIConfigurationStep().configure() + FormulierenAPIConfigurationStep().configure() + configuration = ZGWAPIsConfigurationStep() + + configuration.configure() + + config = OpenZaakConfig.get_solo() + zaak_service = config.zaak_service + catalogi_service = config.catalogi_service + document_service = config.document_service + form_service = config.form_service + + self.assertEqual(zaak_service.api_root, ZAKEN_API_ROOT) + self.assertEqual(zaak_service.client_id, "open-inwoner-test") + self.assertEqual(zaak_service.secret, "zaken-secret") + self.assertEqual(catalogi_service.api_root, CATALOGI_API_ROOT) + self.assertEqual(catalogi_service.client_id, "open-inwoner-test") + self.assertEqual(catalogi_service.secret, "catalogi-secret") + self.assertEqual(document_service.api_root, DOCUMENTEN_API_ROOT) + self.assertEqual(document_service.client_id, "open-inwoner-test") + self.assertEqual(document_service.secret, "documenten-secret") + self.assertEqual(form_service.api_root, FORMULIEREN_API_ROOT) + self.assertEqual(form_service.client_id, "open-inwoner-test") + self.assertEqual(form_service.secret, "forms-secret") + + # Defaults should be used + self.assertEqual( + config.zaak_max_confidentiality, VertrouwelijkheidsAanduidingen.openbaar + ) + self.assertEqual( + config.document_max_confidentiality, VertrouwelijkheidsAanduidingen.openbaar + ) + self.assertEqual(config.action_required_deadline_days, 15) + self.assertEqual( + config.allowed_file_extensions, generate_default_file_extensions() + ) + self.assertEqual( + config.title_text, + _("Hier vindt u een overzicht van al uw lopende en afgeronde aanvragen."), + ) + self.assertEqual(config.enable_categories_filtering_with_zaken, False) + self.assertEqual(config.skip_notification_statustype_informeren, False) + self.assertEqual(config.reformat_esuite_zaak_identificatie, False) + self.assertEqual(config.fetch_eherkenning_zaken_with_rsin, True) + + @requests_mock.Mocker() + def test_configuration_check_ok(self, m): + ZakenAPIConfigurationStep().configure() + CatalogiAPIConfigurationStep().configure() + DocumentenAPIConfigurationStep().configure() + FormulierenAPIConfigurationStep().configure() + configuration = ZGWAPIsConfigurationStep() + + configuration.configure() + + m.get(f"{ZAKEN_API_ROOT}statussen", json=[]) + m.get(f"{CATALOGI_API_ROOT}zaaktypen", json=[]) + m.get(f"{DOCUMENTEN_API_ROOT}objectinformatieobjecten", json=[]) + m.get( + f"{FORMULIEREN_API_ROOT}openstaande-inzendingen", + json=[], + ) + + configuration.test_configuration() + + ( + status_request, + zaaktype_request, + oio_request, + inzendingen_request, + ) = m.request_history + + self.assertEqual(status_request.url, f"{ZAKEN_API_ROOT}statussen") + self.assertEqual(zaaktype_request.url, f"{CATALOGI_API_ROOT}zaaktypen") + self.assertEqual( + oio_request.url, f"{DOCUMENTEN_API_ROOT}objectinformatieobjecten" + ) + self.assertEqual( + inzendingen_request.url, + f"{FORMULIEREN_API_ROOT}openstaande-inzendingen?bsn=000000000", + ) + + @requests_mock.Mocker() + def test_configuration_check_failures(self, m): + ZakenAPIConfigurationStep().configure() + CatalogiAPIConfigurationStep().configure() + DocumentenAPIConfigurationStep().configure() + FormulierenAPIConfigurationStep().configure() + configuration = ZGWAPIsConfigurationStep() + + configuration.configure() + + mock_kwargs = ( + {"exc": requests.ConnectTimeout}, + {"exc": requests.ConnectionError}, + {"status_code": 404}, + {"status_code": 403}, + {"status_code": 500}, + ) + for mock_config in mock_kwargs: + with self.subTest(mock=mock_config): + m.get(f"{ZAKEN_API_ROOT}statussen", **mock_config) + + with self.assertRaises(SelfTestFailed): + configuration.test_configuration() + + def test_is_configured(self): + configs = [ + ZakenAPIConfigurationStep(), + CatalogiAPIConfigurationStep(), + DocumentenAPIConfigurationStep(), + FormulierenAPIConfigurationStep(), + ZGWAPIsConfigurationStep(), + ] + for config in configs: + with self.subTest(config=config.verbose_name): + self.assertFalse(config.is_configured()) + + config.configure() + + self.assertTrue(config.is_configured()) diff --git a/src/open_inwoner/openklant/views/contactform.py b/src/open_inwoner/openklant/views/contactform.py index 7301d37bc5..361c92b9ab 100644 --- a/src/open_inwoner/openklant/views/contactform.py +++ b/src/open_inwoner/openklant/views/contactform.py @@ -208,10 +208,8 @@ def register_by_api(self, form, config: OpenKlantConfig): } contactmoment = None - if contactmomenten_client := build_client("contactmomenten"): - contactmoment = contactmomenten_client.create_contactmoment( - data, klant=klant - ) + if contactmoment_client := build_client("contactmomenten"): + contactmoment = contactmoment_client.create_contactmoment(data, klant=klant) if contactmoment: self.log_system_action(