diff --git a/src/open_inwoner/cms/footer/cms_plugins.py b/src/open_inwoner/cms/footer/cms_plugins.py index 8d7f3db3fc..ac9002c75b 100644 --- a/src/open_inwoner/cms/footer/cms_plugins.py +++ b/src/open_inwoner/cms/footer/cms_plugins.py @@ -11,13 +11,13 @@ class FooterPagesPlugin(CMSPluginBase): name = _("Pages List") render_template = "cms/footer/footer_pages_plugin.html" - # cache = False def render(self, context, instance, placeholder): - # TODO move options to plugin model config = SiteConfiguration.get_solo() klant_config = KlantenSysteemConfig.get_solo() context["flatpages"] = config.get_ordered_flatpages - context["has_form_configuration"] = klant_config.has_contactform_configuration + context["has_form_configuration"] = klant_config.has_contactform_configuration( + user=context["user"] + ) return context diff --git a/src/open_inwoner/cms/footer/tests/test_plugin.py b/src/open_inwoner/cms/footer/tests/test_plugin.py index 5475368f8a..5c8550e833 100644 --- a/src/open_inwoner/cms/footer/tests/test_plugin.py +++ b/src/open_inwoner/cms/footer/tests/test_plugin.py @@ -1,6 +1,7 @@ from django.test import TestCase from django.utils.translation import gettext as _ +from open_inwoner.accounts.tests.factories import UserFactory from open_inwoner.cms.footer.cms_plugins import FooterPagesPlugin from open_inwoner.cms.tests import cms_tools from open_inwoner.openklant.constants import KlantenServiceType @@ -12,6 +13,9 @@ class ContactFormTestCase(ClearCachesMixin, TestCase): def setUp(self): super().setUp() + + self.user = UserFactory() + # clear esuite_config esuite_config = ESuiteKlantConfig.get_solo() esuite_config.klanten_service = None @@ -19,13 +23,12 @@ def setUp(self): esuite_config.register_bronorganisatie_rsin = "" esuite_config.register_type = "" esuite_config.register_employee_id = "" - esuite_config.send_email_confirmation = True esuite_config.save() def test_no_form_link_shown_in_footer_if_not_has_configuration(self): # set nothing klant_config = KlantenSysteemConfig.get_solo() - self.assertFalse(klant_config.has_contactform_configuration) + self.assertFalse(klant_config.has_contactform_configuration(user=self.user)) html, context = cms_tools.render_plugin(FooterPagesPlugin) @@ -36,7 +39,7 @@ def test_form_link_is_shown_in_footer_when_has_configuration(self): klant_config.primary_backend = KlantenServiceType.ESUITE.value klant_config.save() - self.assertFalse(klant_config.has_contactform_configuration) + self.assertFalse(klant_config.has_contactform_configuration(user=self.user)) esuite_config = ESuiteKlantConfig.get_solo() ContactFormSubjectFactory(config=esuite_config) @@ -44,7 +47,7 @@ def test_form_link_is_shown_in_footer_when_has_configuration(self): klant_config.register_contact_email = "example@example.com" klant_config.save() - self.assertTrue(klant_config.has_contactform_configuration) + self.assertTrue(klant_config.has_contactform_configuration(user=self.user)) html, context = cms_tools.render_plugin(FooterPagesPlugin) diff --git a/src/open_inwoner/openklant/admin.py b/src/open_inwoner/openklant/admin.py index 36d8dcfcb1..de5af6be93 100644 --- a/src/open_inwoner/openklant/admin.py +++ b/src/open_inwoner/openklant/admin.py @@ -17,27 +17,35 @@ class ContactFormSubjectForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.fields["subject_code"].widget.attrs["placeholder"] = _( - "Must be configured if E-suite is used" - ) + if esuite_subject_code := self.fields.get("esuite_subject_code", None): + esuite_subject_code.widget.attrs["placeholder"] = _( + "Must be configured if E-suite is used" + ) class Meta: model = ContactFormSubject fields = ( "subject", - "subject_code", + "esuite_subject_code", ) class ContactFormSubjectInlineAdmin(OrderedTabularInline): model = ContactFormSubject form = ContactFormSubjectForm - fields = ("subject", "subject_code", "order", "move_up_down_links") readonly_fields = ("order", "move_up_down_links") ordering = ("order",) extra = 0 +class ContactFormSubjectInlineAdminESuite(ContactFormSubjectInlineAdmin): + fields = ("subject", "esuite_subject_code", "order", "move_up_down_links") + + +class ContactFormSubjectInlineAdminOpenKlant(ContactFormSubjectInlineAdmin): + fields = ("subject", "order", "move_up_down_links") + + class ESuiteKlantConfigAdminForm(forms.ModelForm): class Meta: model = ESuiteKlantConfig @@ -48,7 +56,7 @@ class Meta: class ESuiteKlantConfigAdmin(OrderedInlineModelAdminMixin, SingletonModelAdmin): form = ESuiteKlantConfigAdminForm inlines = [ - ContactFormSubjectInlineAdmin, + ContactFormSubjectInlineAdminESuite, ] fieldsets = [ ( @@ -110,6 +118,9 @@ class Meta: class OpenKlant2ConfigAdmin(SingletonModelAdmin): model = OpenKlant2Config form = OpenKlant2ConfigAdminForm + inlines = [ + ContactFormSubjectInlineAdminOpenKlant, + ] fieldsets = [ ( _("API configuration"), diff --git a/src/open_inwoner/openklant/forms.py b/src/open_inwoner/openklant/forms.py index 3a6d32bd36..fdb25f7b9d 100644 --- a/src/open_inwoner/openklant/forms.py +++ b/src/open_inwoner/openklant/forms.py @@ -2,7 +2,7 @@ from django.utils.translation import gettext_lazy as _ from open_inwoner.accounts.models import User -from open_inwoner.openklant.models import ContactFormSubject, ESuiteKlantConfig +from open_inwoner.openklant.models import ContactFormSubject from open_inwoner.openklant.views.utils import generate_question_answer_pair from open_inwoner.utils.validators import DutchPhoneNumberValidator @@ -57,9 +57,7 @@ def __init__(self, user, request_session, *args, **kwargs): self.user = user self.request_session = request_session - # TODO: check for primary_backend? What in case of OK2? - config = ESuiteKlantConfig.get_solo() - self.fields["subject"].queryset = config.contactformsubject_set.all() + self.fields["subject"].queryset = ContactFormSubject.objects.all() if self.user.is_authenticated: del self.fields["first_name"] diff --git a/src/open_inwoner/openklant/migrations/0024_rename_subject_code_contactformsubject_esuite_subject_code_and_more.py b/src/open_inwoner/openklant/migrations/0024_rename_subject_code_contactformsubject_esuite_subject_code_and_more.py new file mode 100644 index 0000000000..6995b65222 --- /dev/null +++ b/src/open_inwoner/openklant/migrations/0024_rename_subject_code_contactformsubject_esuite_subject_code_and_more.py @@ -0,0 +1,51 @@ +# Generated by Django 4.2.18 on 2025-01-29 09:48 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("openklant", "0023_remove_esuiteklantconfig_register_contact_moment_and_more"), + ] + + operations = [ + migrations.RenameField( + model_name="contactformsubject", + old_name="subject_code", + new_name="esuite_subject_code", + ), + migrations.RemoveField( + model_name="contactformsubject", + name="config", + ), + migrations.AddField( + model_name="contactformsubject", + name="esuite_config", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="openklant.esuiteklantconfig", + ), + ), + migrations.AlterField( + model_name="contactformsubject", + name="esuite_subject_code", + field=models.CharField( + blank=True, + max_length=255, + null=True, + verbose_name="e-Suite 'onderwerp' code", + ), + ), + migrations.AddField( + model_name="contactformsubject", + name="openklant_config", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="openklant.openklant2config", + ), + ), + ] diff --git a/src/open_inwoner/openklant/models.py b/src/open_inwoner/openklant/models.py index 94956f16d2..9704b2609d 100644 --- a/src/open_inwoner/openklant/models.py +++ b/src/open_inwoner/openklant/models.py @@ -7,6 +7,7 @@ from solo.models import SingletonModel from zgw_consumers.constants import APITypes +from open_inwoner.accounts.models import User from open_inwoner.utils.validators import validate_array_contents_non_empty from .constants import KlantenServiceType @@ -117,17 +118,24 @@ class ContactFormSubject(OrderedModel): verbose_name=_("Onderwerp"), max_length=255, ) - subject_code = models.CharField( + esuite_subject_code = models.CharField( verbose_name=_("e-Suite 'onderwerp' code"), max_length=255, + null=True, blank=True, ) - config = models.ForeignKey( + esuite_config = models.ForeignKey( "ESuiteKlantConfig", + null=True, + on_delete=models.CASCADE, + ) + openklant_config = models.ForeignKey( + "OpenKlant2Config", + null=True, on_delete=models.CASCADE, ) - order_with_respect_to = "config" + order_with_respect_to = "esuite_config" objects = OrderedModelManager() @@ -213,6 +221,11 @@ class OpenKlant2Config(SingletonModel): ), ) + register_api_required_fields = ("service",) + + def has_api_configuration(self): + return all(getattr(self, f, "") for f in self.register_api_required_fields) + class Meta: verbose_name = _("OpenKlant2 configuration") @@ -285,24 +298,23 @@ def __str__(self): @property def has_api_configuration(self) -> bool: if self.primary_backend == KlantenServiceType.ESUITE.value: - esuite_config = ESuiteKlantConfig.get_solo() - return esuite_config.has_api_configuration() - - # TODO: support `has_api_configuration` check for OK2? + config = ESuiteKlantConfig.get_solo() + return config.has_api_configuration() + if self.primary_backend == KlantenServiceType.OPENKLANT2.value: + config = OpenKlant2Config.get_solo() + return config.has_api_configuration() return False @property def contact_registration_enabled(self) -> bool: return bool(self.register_contact_email or self.has_api_configuration) - @property - def has_contactform_configuration(self) -> bool: + def has_contactform_configuration(self, user: User) -> bool: if not self.contact_registration_enabled: return False - if self.primary_backend == KlantenServiceType.ESUITE.value: esuite_config = ESuiteKlantConfig.get_solo() return esuite_config.contactformsubject_set.exists() - - # TODO: check conditions for OK2 + if self.primary_backend == KlantenServiceType.OPENKLANT2.value: + return user.is_authenticated return False diff --git a/src/open_inwoner/openklant/services.py b/src/open_inwoner/openklant/services.py index e520fb6ffa..bd17104e2f 100644 --- a/src/open_inwoner/openklant/services.py +++ b/src/open_inwoner/openklant/services.py @@ -574,10 +574,10 @@ def _get_kcm_subject( e-suite code or 3. return the the e-suite subject code if no mapping exists """ - e_suite_subject_code = getattr(kcm.contactmoment, "onderwerp", "") + esuite_subject_code = getattr(kcm.contactmoment, "onderwerp", "") try: - subject = ContactFormSubject.objects.get(subject_code=e_suite_subject_code) + subject = ContactFormSubject.objects.get(esuite_subject_code=esuite_subject_code) except ContactFormSubject.MultipleObjectsReturned as exc: logger.warning( "Multiple OIP subjects mapped to the same e-suite subject code for ", @@ -593,7 +593,7 @@ def _get_kcm_subject( kcm.contactmoment.url, exc_info=exc, ) - return e_suite_subject_code + return esuite_subject_code return subject.subject diff --git a/src/open_inwoner/openklant/tests/data.py b/src/open_inwoner/openklant/tests/data.py index bd502130e2..6859d2957e 100644 --- a/src/open_inwoner/openklant/tests/data.py +++ b/src/open_inwoner/openklant/tests/data.py @@ -576,6 +576,135 @@ def install_mocks_digid(self, m) -> "MockAPICreateData": ] return self + def install_mocks_openklant(self, m): + self.digid_user = DigidUserFactory() + m.get( + "http://localhost:8338/klantinteracties/api/v1/partijen?partijIdentificator__codeSoortObjectId=bsn&partijIdentificator__codeRegister=brp&partijIdentificator__codeObjecttype=natuurlijk_persoon&partijIdentificator__objectId=123456782&soortPartij=persoon", + headers={"Content-Type": "application/json"}, + json={ + "count": 1, + "next": None, + "previous": None, + "results": [ + { + "uuid": "7260ea01-12c0-4750-8fd1-dfa777818837", + }, + ], + }, + status_code=200, + ) + m.get( + "http://localhost:8338/klantinteracties/api/v1/partijen?partijIdentificator__codeSoortObjectId=bsn&partijIdentificator__codeRegister=brp&partijIdentificator__codeObjecttype=natuurlijk_persoon&partijIdentificator__objectId=100000001&soortPartij=persoon", + headers={"Content-Type": "application/json"}, + json={ + "count": 1, + "next": None, + "previous": None, + "results": [ + { + "uuid": "7260ea01-12c0-4750-8fd1-dfa777818837", + }, + ], + }, + status_code=200, + ) + + m.get( + "http://localhost:8338/klantinteracties/api/v1/partijen/7260ea01-12c0-4750-8fd1-dfa777818837?expand=digitaleAdressen%2Cbetrokkenen%2Cbetrokkenen.hadKlantcontact", + headers={"Content-Type": "application/json"}, + json={ + "uuid": "7260ea01-12c0-4750-8fd1-dfa777818837", + "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", + } + }, + }, + ) + m.get( + "http://localhost:8338/klantinteracties/api/v1/partijen/7260ea01-12c0-4750-8fd1-dfa777818837?expand=digitaleAdressen", + headers={"Content-Type": "application/json"}, + json={ + "count": 0, + "next": None, + "previous": None, + "results": [], + }, + ) + + klantcontact = { + "uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f", + "url": "http://example.com", + "gingOverOnderwerpobjecten": [], + "hadBetrokkenActoren": [], + "omvatteBijlagen": [], + "hadBetrokkenen": [], + "leiddeTotInterneTaken": [], + "nummer": "007", + "kanaal": "email", + "onderwerp": "Aanvraag", + "inhoud": "Hoe gaat het?", + "taal": "nl", + "vertrouwelijk": False, + "plaatsgevondenOp": "2019-08-24T14:15:22Z", + } + betrokkene = { + "uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f", + "url": "http://example.com", + "wasPartij": { + "uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f", + "url": "http://example.com", + }, + "hadKlantcontact": { + "uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f", + "url": "http://example.com", + }, + "digitaleAdressen": [{}], + "volledigeNaam": "John Doe", + "rol": "medewerker", + "initiator": True, + } + interne_taak = { + "uuid": "095be615-a8ad-4c33-8e9c-c7612fbf6c9f", + "url": "http://example.com", + "gevraagdeHandeling": "", + "aanleidinggevendKlantcontact": { + "uuid": klantcontact["uuid"], + "url": "http://example.com", + }, + "status": "te_verwerken", + "toegewezenOp": "2019-08-24T14:15:22Z", + } + + self.matchers = [ + m.post( + "http://localhost:8338/klantinteracties/api/v1/betrokkenen", + headers={"Content-Type": "application/json"}, + json=betrokkene, + ), + m.post( + "http://localhost:8338/klantinteracties/api/v1/klantcontacten", + headers={"Content-Type": "application/json"}, + json=klantcontact, + ), + m.post( + "http://localhost:8338/klantinteracties/api/v1/internetaken", + headers={"Content-Type": "application/json"}, + json=interne_taak, + ), + ] + def install_mocks_digid_missing_contact_info(self, m) -> "MockAPICreateData": self.matchers = [ m.get( diff --git a/src/open_inwoner/openklant/tests/factories.py b/src/open_inwoner/openklant/tests/factories.py index abc3d54a4d..e7da22248d 100644 --- a/src/open_inwoner/openklant/tests/factories.py +++ b/src/open_inwoner/openklant/tests/factories.py @@ -18,7 +18,7 @@ class Meta: model = "openklant.ContactFormSubject" subject = factory.Faker("sentence") - subject_code = factory.Faker("word") + esuite_subject_code = factory.Faker("word") class KlantContactMomentAnswerFactory(factory.django.DjangoModelFactory): diff --git a/src/open_inwoner/openklant/tests/test_contactform.py b/src/open_inwoner/openklant/tests/test_contactform.py index 0bf5f63697..84cff21941 100644 --- a/src/open_inwoner/openklant/tests/test_contactform.py +++ b/src/open_inwoner/openklant/tests/test_contactform.py @@ -1,6 +1,7 @@ from unittest.mock import patch from django.contrib import messages +from django.contrib.auth.models import AnonymousUser from django.core import mail from django.test import modify_settings from django.urls import reverse @@ -12,9 +13,16 @@ from open_inwoner.accounts.tests.factories import UserFactory from open_inwoner.openklant.api_models import KlantContactRol from open_inwoner.openklant.constants import KlantenServiceType -from open_inwoner.openklant.models import ESuiteKlantConfig, KlantenSysteemConfig +from open_inwoner.openklant.models import ( + ESuiteKlantConfig, + KlantenSysteemConfig, + OpenKlant2Config, +) from open_inwoner.openklant.tests.data import MockAPICreateData -from open_inwoner.openklant.tests.factories import ContactFormSubjectFactory +from open_inwoner.openklant.tests.factories import ( + ContactFormSubjectFactory, + OpenKlant2ConfigFactory, +) from open_inwoner.openklant.views.contactform import ContactFormView from open_inwoner.openzaak.tests.factories import ServiceFactory from open_inwoner.utils.test import ClearCachesMixin, DisableRequestLogMixin @@ -69,24 +77,24 @@ def setUp(self): # bypass CMS for rendering form template directly via ContactFormView ContactFormView.template_name = "pages/contactform/form.html" - def test_singleton_has_configuration_method( - self, m, mock_captcha, mock_send_confirm - ): + def test_contactform_configuration_esuite(self, m, mock_captcha, mock_send_confirm): # use cleared (from setUp() klant_config = KlantenSysteemConfig.get_solo() esuite_config = ESuiteKlantConfig.get_solo() - self.assertFalse(klant_config.has_contactform_configuration) + anon_user = UserFactory() + + self.assertFalse(klant_config.has_contactform_configuration(user=anon_user)) # set email on glogal config and create subject for eSuite backend klant_config.register_contact_email = "example@example.com" - ContactFormSubjectFactory(config=esuite_config) + ContactFormSubjectFactory(esuite_config=esuite_config) - self.assertTrue(klant_config.has_contactform_configuration) + self.assertTrue(klant_config.has_contactform_configuration(user=anon_user)) # subject but nothing else klant_config.register_contact_email = "" - self.assertFalse(klant_config.has_contactform_configuration) + self.assertFalse(klant_config.has_contactform_configuration(user=anon_user)) # API and subject esuite_config.register_contact_moment = True @@ -97,7 +105,34 @@ def test_singleton_has_configuration_method( esuite_config.register_employee_id = "FooVonBar" esuite_config.save() - self.assertTrue(klant_config.has_contactform_configuration) + self.assertTrue(klant_config.has_contactform_configuration(user=anon_user)) + + mock_send_confirm.assert_not_called() + + def test_contactform_configuration_openklant( + self, m, mock_captcha, mock_send_confirm + ): + klant_config = KlantenSysteemConfig.get_solo() + klant_config.primary_backend = KlantenServiceType.OPENKLANT2.value + klant_config.save() + + user = AnonymousUser() + + # set email on glogal config + klant_config.register_contact_email = "example@example.com" + + self.assertFalse(klant_config.has_contactform_configuration(user=user)) + + # configure API service + openklant_config = OpenKlant2Config.get_solo() + openklant_config.service = ServiceFactory() + + self.assertFalse(klant_config.has_contactform_configuration(user=user)) + + # openklant requires authenticated user + user = UserFactory() + + self.assertTrue(klant_config.has_contactform_configuration(user=user)) mock_send_confirm.assert_not_called() @@ -105,8 +140,9 @@ def test_no_form_shown_if_no_contactform_configuration( self, m, mock_captcha, mock_send_confirm ): # set nothing + anon_user = AnonymousUser() klant_config = KlantenSysteemConfig.get_solo() - self.assertFalse(klant_config.has_contactform_configuration) + self.assertFalse(klant_config.has_contactform_configuration(user=anon_user)) response = self.app.get(self.url) self.assertContains(response, _("Contact formulier niet geconfigureerd.")) @@ -120,7 +156,7 @@ def test_anon_form_requires_either_email_or_phonenumber( config.save() config = ESuiteKlantConfig.get_solo() - subject = ContactFormSubjectFactory(config=config) + subject = ContactFormSubjectFactory(esuite_config=config) response = self.app.get(self.url) form = response.forms["contactmoment-form"] @@ -161,7 +197,7 @@ def test_regular_auth_form_fills_email_and_phonenumber( config.save() config = ESuiteKlantConfig.get_solo() - subject = ContactFormSubjectFactory(config=config) + subject = ContactFormSubjectFactory(esuite_config=config) user = UserFactory() @@ -189,8 +225,8 @@ def test_expected_ordered_subjects_are_shown( config.save() config = ESuiteKlantConfig.get_solo() - subject_1 = ContactFormSubjectFactory(config=config) - subject_2 = ContactFormSubjectFactory(config=config) + subject_1 = ContactFormSubjectFactory(esuite_config=config) + subject_2 = ContactFormSubjectFactory(esuite_config=config) response = self.app.get(self.url) form = response.forms["contactmoment-form"] @@ -229,7 +265,7 @@ def test_register_contactmoment_via_email(self, m, mock_captcha, mock_send_confi config.save() esuite_config = ESuiteKlantConfig.get_solo() - subject = ContactFormSubjectFactory(config=esuite_config) + subject = ContactFormSubjectFactory(esuite_config=esuite_config) response = self.app.get(self.url) form = response.forms["contactmoment-form"] @@ -265,7 +301,7 @@ def test_register_contactmoment_via_email(self, m, mock_captcha, mock_send_confi mock_send_confirm.assert_called_once_with("foo@example.com", subject.subject) - def test_register_contactmoment_for_anon_user_via_api( + def test_register_contactmoment_for_anon_user_via_api_esuite( self, m, mock_captcha, mock_send_confirm ): MockAPICreateData.setUpServices() @@ -286,9 +322,9 @@ def test_register_contactmoment_for_anon_user_via_api( data.install_mocks_anon(m) subject = ContactFormSubjectFactory( - config=esuite_config, subject="Aanvraag document", - subject_code="afdeling-xyz", + esuite_subject_code="afdeling-xyz", + esuite_config=esuite_config, ) response = self.app.get(self.url) @@ -332,9 +368,50 @@ def test_register_contactmoment_for_anon_user_via_api( }, }, ) - self.assertTimelineLog("registered contactmoment by API") + self.assertTimelineLog("registered contactmoment via eSuite") mock_send_confirm.assert_called_once_with("foo@example.com", subject.subject) + def test_register_contactmoment_for_anon_user_via_api_openklant( + self, m, mock_captcha, mock_send_confirm + ): + MockAPICreateData.setUpServices() + data = MockAPICreateData() + data.install_mocks_openklant(m) + + OpenKlant2ConfigFactory() + + config = KlantenSysteemConfig.get_solo() + config.primary_backend = KlantenServiceType.OPENKLANT2.value + config.register_contact_via_api = True + config.send_email_confirmation = True + config.save() + + subject = ContactFormSubjectFactory(subject="Aanvraag") + + response = self.app.get(self.url, user=data.digid_user) + form = response.forms["contactmoment-form"] + form["subject"].select(text=subject.subject) + form["question"] = "What?" + + response = form.submit().follow() + + msgs = list(response.context["messages"]) + self.assertEqual(len(msgs), 1) + self.assertEqual(str(msgs[0]), _("Vraag verstuurd!")) + self.assertEqual(msgs[0].level, messages.SUCCESS) + + self.assertEqual(len(mail.outbox), 0) + + self.assertTrue(data.matchers[0].called_once, str(m)) + self.assertTrue(data.matchers[1].called_once, str(m)) + self.assertTrue(data.matchers[2].called_once, str(m)) + + log_dump = self.getTimelineLogDump() + self.assertIn("registered question via OpenKlant", log_dump) + mock_send_confirm.assert_called_once_with( + data.digid_user.email, subject.subject + ) + @patch("open_inwoner.openklant.forms.generate_question_answer_pair") def test_register_contactmoment_for_anon_user_via_api_does_not_send_empty_email_or_telephone( self, m, mock_captcha2, mock_captcha, mock_send_confirm @@ -359,9 +436,9 @@ def test_register_contactmoment_for_anon_user_via_api_does_not_send_empty_email_ data.install_mocks_anon_without_klant(m) subject = ContactFormSubjectFactory( - config=esuite_config, subject="Aanvraag document", - subject_code="afdeling-xyz", + esuite_subject_code="afdeling-xyz", + esuite_config=esuite_config, ) for contact_details in ( @@ -422,9 +499,9 @@ def test_register_contactmoment_for_bsn_user_via_api( data.install_mocks_digid(m) subject = ContactFormSubjectFactory( - config=esuite_config, subject="Aanvraag document", - subject_code="afdeling-xyz", + esuite_subject_code="afdeling-xyz", + esuite_config=esuite_config, ) response = self.app.get(self.url, user=data.user) @@ -479,7 +556,7 @@ def test_register_contactmoment_for_bsn_user_via_api( ) self.assertTimelineLog("retrieved klant for BSN or KVK user") - self.assertTimelineLog("registered contactmoment by API") + self.assertTimelineLog("registered contactmoment via eSuite") mock_send_confirm.assert_called_once_with("foo@example.com", subject.subject) def test_register_contactmoment_for_bsn_user_via_api_without_id( @@ -503,9 +580,9 @@ def test_register_contactmoment_for_bsn_user_via_api_without_id( data.install_mocks_digid(m) subject = ContactFormSubjectFactory( - config=esuite_config, subject="Aanvraag document", - subject_code="afdeling-xyz", + esuite_subject_code="afdeling-xyz", + esuite_config=esuite_config, ) response = self.app.get(self.url, user=data.user) @@ -575,9 +652,9 @@ def test_register_contactmoment_for_kvk_or_rsin_user_via_api( ) subject = ContactFormSubjectFactory( - config=esuite_config, subject="Aanvraag document", - subject_code="afdeling-xyz", + esuite_subject_code="afdeling-xyz", + esuite_config=esuite_config, ) response = self.app.get(self.url, user=data.eherkenning_user) @@ -642,7 +719,7 @@ def test_register_contactmoment_for_kvk_or_rsin_user_via_api( ) self.assertTimelineLog("retrieved klant for BSN or KVK user") - self.assertTimelineLog("registered contactmoment by API") + self.assertTimelineLog("registered contactmoment via eSuite") mock_send_confirm.assert_called_once_with( "foo@example.com", subject.subject @@ -670,9 +747,9 @@ def test_register_contactmoment_for_bsn_user_via_api_and_update_klant( data.install_mocks_digid_missing_contact_info(m) subject = ContactFormSubjectFactory( - config=esuite_config, subject="Aanvraag document", - subject_code="afdeling-xyz", + esuite_subject_code="afdeling-xyz", + esuite_config=esuite_config, ) response = self.app.get(self.url, user=data.user) @@ -733,7 +810,7 @@ def test_register_contactmoment_for_bsn_user_via_api_and_update_klant( self.assertTimelineLog( "patched klant from user with missing fields: emailadres, telefoonnummer" ) - self.assertTimelineLog("registered contactmoment by API") + self.assertTimelineLog("registered contactmoment via eSuite") mock_send_confirm.assert_called_once_with(data.user.email, subject.subject) mock_send_confirm.reset_mock() @@ -779,9 +856,9 @@ def test_register_contactmoment_for_kvk_or_rsin_user_via_api_and_update_klant( ) subject = ContactFormSubjectFactory( - config=config, subject="Aanvraag document", - subject_code="afdeling-xyz", + esuite_subject_code="afdeling-xyz", + esuite_config=config, ) response = self.app.get(self.url, user=data.eherkenning_user) @@ -844,7 +921,7 @@ def test_register_contactmoment_for_kvk_or_rsin_user_via_api_and_update_klant( self.assertTimelineLog( "patched klant from user with missing fields: emailadres, telefoonnummer" ) - self.assertTimelineLog("registered contactmoment by API") + self.assertTimelineLog("registered contactmoment via eSuite") mock_send_confirm.assert_called_once_with( data.eherkenning_user.email, subject.subject @@ -876,9 +953,9 @@ def test_send_email_confirmation_is_configurable( data.install_mocks_anon(m) subject = ContactFormSubjectFactory( - config=esuite_config, subject="Aanvraag document", - subject_code="afdeling-xyz", + esuite_subject_code="afdeling-xyz", + esuite_config=esuite_config, ) for send in [True, False]: with self.subTest(send=send): diff --git a/src/open_inwoner/openklant/tests/test_esuite_vragen_service.py b/src/open_inwoner/openklant/tests/test_esuite_vragen_service.py index cd154c93e4..4e19cf06e6 100644 --- a/src/open_inwoner/openklant/tests/test_esuite_vragen_service.py +++ b/src/open_inwoner/openklant/tests/test_esuite_vragen_service.py @@ -28,8 +28,8 @@ def setUp(self): self.contactformsubject = ContactFormSubject.objects.create( subject="oip_subject", - subject_code="e_suite_subject_code", - config=klanten_config, + esuite_subject_code="e_suite_subject_code", + esuite_config=klanten_config, ) def test_list_questions_returns_expected_rows(self, m): diff --git a/src/open_inwoner/openklant/tests/test_views.py b/src/open_inwoner/openklant/tests/test_views.py index c045f2e9b2..1fa5c6f213 100644 --- a/src/open_inwoner/openklant/tests/test_views.py +++ b/src/open_inwoner/openklant/tests/test_views.py @@ -72,8 +72,8 @@ def setUp(self): # for testing replacement of e-suite "onderwerp" code with OIP configured subject self.contactformsubject = ContactFormSubject.objects.create( subject="oip_subject", - subject_code="e_suite_subject_code", - config=klant_config, + esuite_subject_code="e_suite_subject_code", + esuite_config=klant_config, ) def test_contactmoment_list_bsn( @@ -612,8 +612,8 @@ def test_contactmoment_list_subject_duplicate_esuite_codes( ContactFormSubject.objects.create( subject="control_subject_for_duplicate_code", - subject_code=self.contactformsubject.subject_code, - config=ESuiteKlantConfig.get_solo(), + esuite_subject_code=self.contactformsubject.esuite_subject_code, + esuite_config=ESuiteKlantConfig.get_solo(), ) detail_url_esuite = reverse( @@ -723,7 +723,7 @@ def test_contactmoment_list_subject_no_mapping_fallback( "identification": cm_data["identificatie"], "api_source_url": cm_data["url"], "api_source_uuid": uuid_from_url(cm_data["url"]), - "subject": self.contactformsubject.subject_code, + "subject": self.contactformsubject.esuite_subject_code, "question_text": cm_data["tekst"], "answer_text": cm_data["antwoord"], "registered_date": datetime.fromisoformat(cm_data["registratiedatum"]), diff --git a/src/open_inwoner/openklant/views/contactform.py b/src/open_inwoner/openklant/views/contactform.py index 97a89dca22..1ce66fd4a2 100644 --- a/src/open_inwoner/openklant/views/contactform.py +++ b/src/open_inwoner/openklant/views/contactform.py @@ -28,6 +28,7 @@ KlantenSysteemConfig, OpenKlant2Config, ) +from open_inwoner.openklant.services import OpenKlant2Service from open_inwoner.openklant.views.utils import generate_question_answer_pair from open_inwoner.openklant.wrap import get_fetch_parameters from open_inwoner.utils.views import CommonPageMixin, LogMixin @@ -93,7 +94,9 @@ def get_initial(self): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) config = KlantenSysteemConfig.get_solo() - context["has_form_configuration"] = config.has_contactform_configuration + context["has_form_configuration"] = config.has_contactform_configuration( + user=self.request.user + ) return context def set_result_message(self, success: bool): @@ -176,9 +179,29 @@ def register_by_api(self, form, config: KlantenSysteemConfig): ) return self._register_via_openklant2(form, config=OpenKlant2Config.get_solo()) - # TODO def _register_via_openklant2(self, form: ContactForm, config: OpenKlant2Config): - raise NotImplementedError + user = self.request.user + service = OpenKlant2Service(config=config) + + partij, created = service.get_or_create_partij_for_user( + fetch_params=service.get_fetch_parameters(user=user), + user=user, + ) + + cleaned_data = form.cleaned_data + question = cleaned_data["question"] + subject = cleaned_data["subject"].subject + + question = service.create_question( + partij_uuid=partij["uuid"], question=question, subject=subject + ) + + self.log_system_action( + "registered question via OpenKlant", user=self.request.user + ) + + # TODO: get email from partij + return True, getattr(user, "email", None) def _register_via_esuite( self, @@ -201,7 +224,7 @@ def _register_via_esuite( ) return False, getattr(klant, "emailadres", None) self.log_system_action( - "registered contactmoment by API", user=self.request.user + "registered contactmoment via eSuite", user=self.request.user ) return True, getattr(klant, "emailadres", None) @@ -250,7 +273,7 @@ def _create_contactmoment( return subject = form_data["subject"].subject - subject_code = form_data["subject"].subject_code + subject_code = form_data["subject"].esuite_subject_code text = form_data["question"] if not klant: