From 6e72745e7b7fb182c4197fa06ee0946a252527d1 Mon Sep 17 00:00:00 2001 From: Paul Schilling Date: Thu, 5 Dec 2024 12:03:18 +0100 Subject: [PATCH] [#2899] Create MVP configuration model for OpenKlant2 --- src/open_inwoner/openklant/admin.py | 62 ++++++++- .../0016_klanteninteractiesconfig.py | 53 ++++++++ .../migrations/0017_kic_esuite_openklant2.py | 23 ++++ .../0018_alter_contactformsubject_config.py | 23 ++++ src/open_inwoner/openklant/models.py | 119 ++++++++++-------- .../scss/admin/_admin_inlines.scss | 17 +++ .../scss/admin/admin_overrides.scss | 1 + 7 files changed, 244 insertions(+), 54 deletions(-) create mode 100644 src/open_inwoner/openklant/migrations/0016_klanteninteractiesconfig.py create mode 100644 src/open_inwoner/openklant/migrations/0017_kic_esuite_openklant2.py create mode 100644 src/open_inwoner/openklant/migrations/0018_alter_contactformsubject_config.py create mode 100644 src/open_inwoner/scss/admin/_admin_inlines.scss diff --git a/src/open_inwoner/openklant/admin.py b/src/open_inwoner/openklant/admin.py index bca5941f29..614546dcad 100644 --- a/src/open_inwoner/openklant/admin.py +++ b/src/open_inwoner/openklant/admin.py @@ -5,7 +5,13 @@ from ordered_model.admin import OrderedInlineModelAdminMixin, OrderedTabularInline from solo.admin import SingletonModelAdmin -from .models import ContactFormSubject, KlantContactMomentAnswer, OpenKlantConfig +from .models import ( + ContactFormSubject, + KlantContactMomentAnswer, + KlantenInteractiesConfig, + OpenKlant2Config, + OpenKlantConfig, +) class ContactFormSubjectForm(forms.ModelForm): @@ -49,8 +55,8 @@ def clean(self, *args, **kwargs): self.add_error(field_name, msg) -@admin.register(OpenKlantConfig) -class OpenKlantConfigAdmin(OrderedInlineModelAdminMixin, SingletonModelAdmin): +class OpenKlantConfigAdmin(admin.StackedInline): + model = OpenKlantConfig form = OpenKlantConfigAdminForm inlines = [ ContactFormSubjectInlineAdmin, @@ -108,3 +114,53 @@ class KlantContactMomentAnswerAdmin(admin.ModelAdmin): ] list_filter = ["is_seen"] list_display = ["user", "contactmoment_url", "is_seen"] + + +# +# OpenKlant2 +# + + +class OpenKlant2ConfigAdminForm(forms.ModelForm): + class Meta: + model = OpenKlantConfig + fields = "__all__" + + +class OpenKlant2Config2Admin(admin.StackedInline): + model = OpenKlant2Config + form = OpenKlant2ConfigAdminForm + fieldsets = [ + ( + _("API configuration"), + { + "fields": [ + "service", + ] + }, + ), + ( + _("Vragen"), + { + "fields": [ + "mijn_vragen_kanaal", + "mijn_vragen_organisatie_naam", + "mijn_vragen_actor", + "interne_taak_gevraagde_handeling", + "interne_taak_toelichting", + ] + }, + ), + ] + + class Media: + css = {"all": ("css/custom_admin.css",)} + + +@admin.register(KlantenInteractiesConfig) +class KlantenInteractiesConfigAdmin(OrderedInlineModelAdminMixin, SingletonModelAdmin): + inlines = [ + OpenKlant2Config2Admin, + OpenKlantConfigAdmin, + ContactFormSubjectInlineAdmin, + ] diff --git a/src/open_inwoner/openklant/migrations/0016_klanteninteractiesconfig.py b/src/open_inwoner/openklant/migrations/0016_klanteninteractiesconfig.py new file mode 100644 index 0000000000..8575b5ad06 --- /dev/null +++ b/src/open_inwoner/openklant/migrations/0016_klanteninteractiesconfig.py @@ -0,0 +1,53 @@ +# Generated by Django 4.2.16 on 2025-01-06 16:30 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("openklant", "0015_openklant2config"), + ] + + operations = [ + migrations.CreateModel( + name="KlantenInteractiesConfig", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ], + options={ + "verbose_name": "Configuratie Klanten Interacties", + }, + ), + migrations.AddField( + model_name="openklantconfig", + name="config", + field=models.OneToOneField( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="openklant.klanteninteractiesconfig", + ), + ), + migrations.AlterModelOptions( + name="openklantconfig", + options={"verbose_name": "eSuite configuration"}, + ), + migrations.AddField( + model_name="openklant2config", + name="config", + field=models.OneToOneField( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="openklant.klanteninteractiesconfig", + ), + ), + ] diff --git a/src/open_inwoner/openklant/migrations/0017_kic_esuite_openklant2.py b/src/open_inwoner/openklant/migrations/0017_kic_esuite_openklant2.py new file mode 100644 index 0000000000..822f7fdcf1 --- /dev/null +++ b/src/open_inwoner/openklant/migrations/0017_kic_esuite_openklant2.py @@ -0,0 +1,23 @@ +from django.db import migrations + + +def embed_kic_configurations(apps, _): + kic_config_model = apps.get_model("openklant", "KlantenInteractiesConfig") + kic_config = kic_config_model.objects.create() + + esuite_model = apps.get_model("openklant", "OpenKlantConfig") + for config in esuite_model.objects.all(): + config.config = kic_config + config.save() + + ok2_model = apps.get_model("openklant", "OpenKlant2Config") + for config in ok2_model.objects.all(): + config.config = kic_config + config.save() + + +class Migration(migrations.Migration): + dependencies = [("openklant", "0016_klanteninteractiesconfig")] + operations = [ + migrations.RunPython(embed_kic_configurations, migrations.RunPython.noop) + ] diff --git a/src/open_inwoner/openklant/migrations/0018_alter_contactformsubject_config.py b/src/open_inwoner/openklant/migrations/0018_alter_contactformsubject_config.py new file mode 100644 index 0000000000..4360942dab --- /dev/null +++ b/src/open_inwoner/openklant/migrations/0018_alter_contactformsubject_config.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.16 on 2025-01-06 16:56 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("openklant", "0017_kic_esuite_openklant2"), + ] + + operations = [ + migrations.AlterField( + model_name="contactformsubject", + name="config", + field=models.ForeignKey( + null=True, + on_delete=django.db.models.deletion.CASCADE, + to="openklant.klanteninteractiesconfig", + ), + ), + ] diff --git a/src/open_inwoner/openklant/models.py b/src/open_inwoner/openklant/models.py index 2f20e55502..c3ef3ee9e1 100644 --- a/src/open_inwoner/openklant/models.py +++ b/src/open_inwoner/openklant/models.py @@ -17,9 +17,14 @@ def get_queryset(self): class OpenKlantConfig(SingletonModel): """ - Global configuration and defaults for Klant & Contactmomenten APIs + Configuration and defaults for eSuite Klant & Contactmomenten APIs """ + config = models.OneToOneField( + "KlantenInteractiesConfig", + null=True, + on_delete=models.CASCADE, + ) klanten_service = models.OneToOneField( "zgw_consumers.Service", verbose_name=_("Klanten API"), @@ -120,7 +125,7 @@ class OpenKlantConfig(SingletonModel): objects = OpenKlantConfigManager() class Meta: - verbose_name = _("Open Klant configuration") + verbose_name = _("eSuite configuration") def has_register(self) -> bool: return self.register_email or self.has_api_configuration() @@ -132,52 +137,13 @@ def has_api_configuration(self): return all(getattr(self, f, "") for f in self.register_api_required_fields) -class OpenKlant2ConfigManager(models.Manager): - def get_queryset(self): - qs = super().get_queryset() - return qs.select_related("service") - - -class OpenKlant2Config(models.Model): - service = models.OneToOneField( - "zgw_consumers.Service", - verbose_name=_("Klanten API"), - on_delete=models.PROTECT, - related_name="+", - ) - - # Vragen - mijn_vragen_kanaal = models.CharField( - verbose_name=_("Mijn vragen kanaal"), - default="", - blank=True, - ) - mijn_vragen_organisatie_naam = models.CharField( - verbose_name=_("Mijn vragen organisatie naam"), - default="", - blank=True, - ) - mijn_vragen_actor = models.CharField( - verbose_name=_("Mijn vragen actor"), - default="", - blank=True, - ) - interne_taak_gevraagde_handeling = models.CharField( - verbose_name=_("Interne taak gevraagde handeling"), - default="", - blank=True, - ) - interne_taak_toelichting = models.CharField( - verbose_name=_("Interne taak toelichting"), - default="", - blank=True, +class ContactFormSubject(OrderedModel): + config = models.ForeignKey( + "KlantenInteractiesConfig", + null=True, + on_delete=models.CASCADE, ) - class Meta: - verbose_name = _("OpenKlant2 configuration") - - -class ContactFormSubject(OrderedModel): subject = models.CharField( verbose_name=_("Onderwerp"), max_length=255, @@ -187,11 +153,6 @@ class ContactFormSubject(OrderedModel): max_length=255, blank=True, ) - # FK for easy inline admins - config = models.ForeignKey( - OpenKlantConfig, - on_delete=models.CASCADE, - ) order_with_respect_to = "config" @@ -229,3 +190,59 @@ class Meta: verbose_name = _("KlantContactMoment") verbose_name_plural = _("KlantContactMomenten") unique_together = [["user", "contactmoment_url"]] + + +class OpenKlant2ConfigManager(models.Manager): + def get_queryset(self): + qs = super().get_queryset() + return qs.select_related("service") + + +class OpenKlant2Config(models.Model): + config = models.OneToOneField( + "KlantenInteractiesConfig", + null=True, + on_delete=models.CASCADE, + ) + + service = models.OneToOneField( + "zgw_consumers.Service", + verbose_name=_("Klanten API"), + on_delete=models.PROTECT, + related_name="+", + ) + + # Vragen + mijn_vragen_kanaal = models.CharField( + verbose_name=_("Mijn vragen kanaal"), + default="", + blank=True, + ) + mijn_vragen_organisatie_naam = models.CharField( + verbose_name=_("Mijn vragen organisatie naam"), + default="", + blank=True, + ) + mijn_vragen_actor = models.CharField( + verbose_name=_("Mijn vragen actor"), + default="", + blank=True, + ) + interne_taak_gevraagde_handeling = models.CharField( + verbose_name=_("Interne taak gevraagde handeling"), + default="", + blank=True, + ) + interne_taak_toelichting = models.CharField( + verbose_name=_("Interne taak toelichting"), + default="", + blank=True, + ) + + class Meta: + verbose_name = _("OpenKlant2 configuration") + + +class KlantenInteractiesConfig(SingletonModel): + class Meta: + verbose_name = _("Configuratie Klanten Interacties") diff --git a/src/open_inwoner/scss/admin/_admin_inlines.scss b/src/open_inwoner/scss/admin/_admin_inlines.scss new file mode 100644 index 0000000000..545a8e6967 --- /dev/null +++ b/src/open_inwoner/scss/admin/_admin_inlines.scss @@ -0,0 +1,17 @@ +.inline-group { + margin-bottom: 16px; + + border: 1px solid #ddd; + border-radius: 5px; + + > fieldset > h2 { + margin-bottom: 5px; + background-color: #498fc9; + } +} + +.inline-related { + h3 { + display: none; + } +} diff --git a/src/open_inwoner/scss/admin/admin_overrides.scss b/src/open_inwoner/scss/admin/admin_overrides.scss index 2c988225bd..eaacb77a28 100644 --- a/src/open_inwoner/scss/admin/admin_overrides.scss +++ b/src/open_inwoner/scss/admin/admin_overrides.scss @@ -3,6 +3,7 @@ //Internal @import './admin_theme'; +@import './admin_inlines'; @import './app_overrides'; @import './ck_editor'; @import '../components/Map/Map.scss';