Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[#2969] Create questions with OpenKlant2 #1574

Merged
merged 2 commits into from
Feb 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 17 additions & 15 deletions src/open_inwoner/accounts/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
from open_inwoner.haalcentraal.models import HaalCentraalConfig
from open_inwoner.haalcentraal.utils import update_brp_data_in_db
from open_inwoner.kvk.client import KvKClient
from open_inwoner.openklant.constants import KlantenServiceType
from open_inwoner.openklant.models import KlantenSysteemConfig
from open_inwoner.openklant.services import OpenKlant2Service, eSuiteKlantenService
from open_inwoner.utils.logentry import user_action

Expand Down Expand Up @@ -40,21 +42,21 @@ def update_user_on_login(sender, user, request, *args, **kwargs):
if user.login_type == LoginTypeChoices.eherkenning:
_update_eherkenning_user_from_kvk_api(user=user)

# OpenKlant2
try:
service = OpenKlant2Service()
except Exception:
logger.error("OpenKlant2 service failed to build")
else:
_update_user_from_openklant2(user=user, service=service, request=request)

# eSuite
try:
service = eSuiteKlantenService()
except Exception:
logger.error("eSuiteKlantenService failed to build")
else:
_update_user_from_esuite(user=user, service=service, request=request)
config = KlantenSysteemConfig.get_solo()
if config.primary_backend == KlantenServiceType.OPENKLANT2.value:
try:
service = OpenKlant2Service()
except Exception:
logger.error("OpenKlant2 service failed to build")
else:
_update_user_from_openklant2(user=user, service=service, request=request)
if config.primary_backend == KlantenServiceType.ESUITE.value:
try:
service = eSuiteKlantenService()
except Exception:
logger.error("eSuiteKlantenService failed to build")
else:
_update_user_from_esuite(user=user, service=service, request=request)


def _update_user_from_openklant2(
Expand Down
6 changes: 6 additions & 0 deletions src/open_inwoner/accounts/tests/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
from open_inwoner.haalcentraal.tests.mixins import HaalCentraalMixin
from open_inwoner.kvk.branches import get_kvk_branch_number
from open_inwoner.kvk.tests.factories import CertificateFactory
from open_inwoner.openklant.constants import KlantenServiceType
from open_inwoner.openklant.models import KlantenSysteemConfig
from open_inwoner.openklant.tests.data import MockAPIReadPatchData
from open_inwoner.utils.tests.helpers import AssertTimelineLogMixin

Expand Down Expand Up @@ -2039,6 +2041,10 @@ def setUpTestData(cls):
config.enable_notification_channel_choice = True
config.save()

klant_config = KlantenSysteemConfig.get_solo()
klant_config.primary_backend = KlantenServiceType.ESUITE.value
klant_config.save()

def test_update_hook_is_registered_on_login(self, m):
connected_functions = [receiver[1]() for receiver in user_logged_in.receivers]
self.assertIn(update_user_on_login, connected_functions)
Expand Down
2 changes: 1 addition & 1 deletion src/open_inwoner/cms/cases/views/status.py
Original file line number Diff line number Diff line change
Expand Up @@ -1006,7 +1006,7 @@ def _register_via_openklant2(self, form, config: OpenKlant2Config):
raise NotImplementedError

def _register_via_esuite(self, form, config: ESuiteKlantConfig):
assert config.has_api_configuration()
assert config.has_api_configuration

try:
ztc = ZaakTypeConfig.objects.filter_case_type(self.case.zaaktype).get()
Expand Down
2 changes: 0 additions & 2 deletions src/open_inwoner/cms/footer/cms_plugins.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,9 @@
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
Expand Down
4 changes: 2 additions & 2 deletions src/open_inwoner/cms/footer/tests/test_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@
class ContactFormTestCase(ClearCachesMixin, TestCase):
def setUp(self):
super().setUp()

# clear esuite_config
esuite_config = ESuiteKlantConfig.get_solo()
esuite_config.klanten_service = None
esuite_config.contactmomenten_service = None
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):
Expand All @@ -39,7 +39,7 @@ def test_form_link_is_shown_in_footer_when_has_configuration(self):
self.assertFalse(klant_config.has_contactform_configuration)

esuite_config = ESuiteKlantConfig.get_solo()
ContactFormSubjectFactory(config=esuite_config)
ContactFormSubjectFactory(esuite_config=esuite_config)

klant_config.register_contact_email = "example@example.com"
klant_config.save()
Expand Down
23 changes: 17 additions & 6 deletions src/open_inwoner/openklant/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -48,7 +56,7 @@ class Meta:
class ESuiteKlantConfigAdmin(OrderedInlineModelAdminMixin, SingletonModelAdmin):
form = ESuiteKlantConfigAdminForm
inlines = [
ContactFormSubjectInlineAdmin,
ContactFormSubjectInlineAdminESuite,
]
fieldsets = [
(
Expand Down Expand Up @@ -110,6 +118,9 @@ class Meta:
class OpenKlant2ConfigAdmin(SingletonModelAdmin):
model = OpenKlant2Config
form = OpenKlant2ConfigAdminForm
inlines = [
ContactFormSubjectInlineAdminOpenKlant,
]
fieldsets = [
(
_("API configuration"),
Expand Down
19 changes: 15 additions & 4 deletions src/open_inwoner/openklant/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
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.constants import KlantenServiceType
from open_inwoner.openklant.models import ContactFormSubject, KlantenSysteemConfig
from open_inwoner.openklant.views.utils import generate_question_answer_pair
from open_inwoner.utils.validators import DutchPhoneNumberValidator

Expand Down Expand Up @@ -57,9 +58,19 @@ 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()
klant_config = KlantenSysteemConfig.get_solo()
if klant_config.primary_backend == KlantenServiceType.OPENKLANT2.value:
subjects = ContactFormSubject.objects.filter(
esuite_subject_code__isnull=True
)
elif klant_config.primary_backend == KlantenServiceType.ESUITE.value:
subjects = ContactFormSubject.objects.filter(
esuite_subject_code__isnull=False
)
else:
subjects = ContactFormSubject.objects.none()

self.fields["subject"].queryset = subjects

if self.user.is_authenticated:
del self.fields["first_name"]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# 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", "0024_alter_klantensysteemconfig_primary_backend")]

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",
),
),
]
49 changes: 31 additions & 18 deletions src/open_inwoner/openklant/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ class ESuiteKlantConfig(SingletonModel):
class Meta:
verbose_name = _("eSuite Klant configuration")

@property
def has_api_configuration(self):
return all(getattr(self, f, "") for f in self.register_api_required_fields)

Expand All @@ -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()

Expand Down Expand Up @@ -213,6 +221,12 @@ class OpenKlant2Config(SingletonModel):
),
)

register_api_required_fields = ("service",)

@property
def has_api_configuration(self):
return all(getattr(self, f, False) for f in self.register_api_required_fields)

class Meta:
verbose_name = _("OpenKlant2 configuration")

Expand Down Expand Up @@ -309,25 +323,24 @@ 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?
return False
match self.primary_backend:
case KlantenServiceType.ESUITE.value:
config = ESuiteKlantConfig.get_solo()
case KlantenServiceType.OPENKLANT2.value:
config = OpenKlant2Config.get_solo()
case _:
config = None
return getattr(config, "has_api_configuration", 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:
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
return False
contactform_subjects = ContactFormSubject.objects.filter(
esuite_subject_code__isnull=False
if self.primary_backend == KlantenServiceType.ESUITE.value
else True
)
return self.contact_registration_enabled and contactform_subjects.exists()
20 changes: 17 additions & 3 deletions src/open_inwoner/openklant/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,20 @@ def get_fetch_parameters(

return None

@property
def supports_anonymous_questions(self):
match self.config:
case ESuiteKlantConfig():
return True
case OpenKlant2Config():
return False
case _:
raise ValueError("Unsupported backend for KlantenService")


class eSuiteKlantenService(KlantenService):
config: ESuiteKlantConfig
supports_anonymous_questions: bool = True

def __init__(self, config: ESuiteKlantConfig | None = None):
self.config = config or ESuiteKlantConfig.get_solo()
Expand Down Expand Up @@ -574,10 +585,12 @@ 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 ",
Expand All @@ -593,7 +606,7 @@ def _get_kcm_subject(
kcm.contactmoment.url,
exc_info=exc,
)
return e_suite_subject_code
return esuite_subject_code

return subject.subject

Expand Down Expand Up @@ -843,6 +856,7 @@ def from_klantcontact_and_answer(
class OpenKlant2Service(KlantenService):
config: OpenKlant2Config
client: OpenKlant2Client
supports_anonymous_questions: bool = False

def __init__(self, config: OpenKlant2Config | None = None):
self.config = config or OpenKlant2Config.get_solo()
Expand Down
Loading
Loading