Skip to content

Commit

Permalink
[2863] Integrate OpenKlant2 service with contactmoment detail view
Browse files Browse the repository at this point in the history
  • Loading branch information
pi-sigma committed Nov 7, 2024
1 parent 5aba3cc commit 8111c9d
Show file tree
Hide file tree
Showing 6 changed files with 311 additions and 73 deletions.
24 changes: 16 additions & 8 deletions src/open_inwoner/accounts/views/contactmoments.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
from view_breadcrumbs import BaseBreadcrumbMixin

from open_inwoner.accounts.models import User
from open_inwoner.openklant.constants import KlantenServiceType
from open_inwoner.openklant.models import KlantContactMomentAnswer
from open_inwoner.openklant.services import (
KlantenService,
OpenKlant2Service,
Question,
QuestionValidator,
ZaakWithApiGroup,
Expand Down Expand Up @@ -87,9 +89,11 @@ def get_fetch_parameters(
class KlantContactMomentBaseView(
CommonPageMixin, BaseBreadcrumbMixin, KlantContactMomentAccessMixin, TemplateView
):
def get_service(self) -> VragenService:
# TODO: Refactor to support both OpenKlant2 and eSuite services at once
return eSuiteVragenService()
def get_service(self, service_type: str) -> VragenService:
if service_type == KlantenServiceType.esuite:
return eSuiteVragenService()
elif service_type == KlantenServiceType.openklant2:
return OpenKlant2Service()

def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
Expand Down Expand Up @@ -131,9 +135,9 @@ def get_anchors(self) -> list:

def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
service = self.get_service()
questions = service.list_questions(
self.get_fetch_params(service), user=self.request.user
esuite_service = self.get_service(KlantenServiceType.esuite)
questions = esuite_service.list_questions(
self.get_fetch_params(esuite_service), user=self.request.user
)
ctx["contactmomenten"] = [
QuestionValidator.validate_python(q) for q in questions
Expand Down Expand Up @@ -162,7 +166,11 @@ def get_anchors(self) -> list:

def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
service = self.get_service()

if KlantenServiceType.esuite in self.request.path:
service = self.get_service(service_type=KlantenServiceType.esuite)
elif KlantenServiceType.openklant2 in self.request.path:
service = self.get_service(service_type=KlantenServiceType.openklant2)

kcm, zaak = service.retrieve_question(
self.get_fetch_params(service), kwargs["kcm_uuid"], user=self.request.user
Expand All @@ -173,7 +181,7 @@ def get_context_data(self, **kwargs):
QuestionValidator.validate_python(kcm)

local_kcm, created = KlantContactMomentAnswer.objects.get_or_create( # noqa
user=self.request.user, contactmoment_url=kcm["case_detail_url"]
user=self.request.user, contactmoment_url=kcm["url"]
)
if not local_kcm.is_seen:
local_kcm.is_seen = True
Expand Down
2 changes: 1 addition & 1 deletion src/open_inwoner/cms/cases/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
name="contactmoment_list",
),
path(
"contactmomenten/<str:kcm_uuid>/",
"contactmomenten/<str:api_source>/<str:kcm_uuid>/",
KlantContactMomentDetailView.as_view(),
name="contactmoment_detail",
),
Expand Down
8 changes: 8 additions & 0 deletions src/open_inwoner/openklant/constants.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from dataclasses import dataclass

from django.db import models
from django.utils.translation import gettext_lazy as _

Expand All @@ -17,3 +19,9 @@ def safe_label(cls, value, default=""):
if default:
return default
return str(value).replace("_", " ").title()


@dataclass
class KlantenServiceType:
esuite = "esuite"
openklant2 = "openklant2"
67 changes: 60 additions & 7 deletions src/open_inwoner/openklant/services.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import uuid
from typing import Iterable, Literal, NotRequired, Protocol, Self

from django.conf import settings
from django.urls import reverse
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
Expand Down Expand Up @@ -31,7 +32,7 @@
KlantCreateData,
ObjectContactMoment,
)
from open_inwoner.openklant.constants import Status
from open_inwoner.openklant.constants import KlantenServiceType, Status
from open_inwoner.openklant.models import (
ContactFormSubject,
KlantContactMomentAnswer,
Expand All @@ -49,6 +50,7 @@
from open_inwoner.openzaak.models import ZGWApiGroupConfig
from open_inwoner.utils.api import ClientError, get_json_response
from open_inwoner.utils.logentry import system_action
from open_inwoner.utils.time import instance_is_new
from openklant2.client import OpenKlant2Client
from openklant2.types.resources.digitaal_adres import DigitaalAdres
from openklant2.types.resources.klant_contact import (
Expand Down Expand Up @@ -85,11 +87,13 @@ class Question(TypedDict):
question_text: str
answer_text: str | None
status: str

new_answer_available: bool
case_detail_url: str
channel: str

# metadata
api_source: str
new_answer_available: bool = False
url: str


QuestionValidator = TypeAdapter(Question)

Expand Down Expand Up @@ -603,10 +607,15 @@ def _get_question_data(
"subject": self._get_kcm_subject(kcm) or "",
"registered_date": kcm.contactmoment.registratiedatum,
"status": str(Status.safe_label(kcm.contactmoment.status, _("Onbekend"))),
"case_detail_url": reverse(
"cases:contactmoment_detail", kwargs={"kcm_uuid": kcm.uuid}
),
"channel": kcm.contactmoment.kanaal.title(),
"api_source": KlantenServiceType.esuite,
"url": reverse(
"cases:contactmoment_detail",
kwargs={
"api_source": KlantenServiceType.esuite,
"kcm_uuid": kcm.uuid,
},
),
}

def fetch_klantcontactmomenten(
Expand Down Expand Up @@ -1237,3 +1246,47 @@ def questions_for_partij(self, partij_uuid: str) -> list[OpenKlant2Question]:

question_objs.sort(key=lambda o: o.plaatsgevonden_op)
return question_objs

def retrieve_question(
self,
fetch_params: FetchParameters,
question_uuid: str,
user: User, # is this needed?
) -> tuple[Question | None, ZaakWithApiGroup | None]: # noqa: E704
if bsn := fetch_params.get("user_bsn"):
partij = self.find_persoon_for_bsn(bsn)
elif kvk_or_rsin := fetch_params.get("user_kvk_or_rsin"):
partij = self.find_organisatie_for_kvk(kvk_or_rsin)

all_questions = self.questions_for_partij(partij_uuid=partij["uuid"])
question = next(
q for q in all_questions if q.question_kcm_uuid == question_uuid
)

# TODO
# should return (Question, zaak_with_api_group); the latter is left out until a
# standard for linking klantcontact + zaak is agreed upon
# see https://github.com/Klantinteractie-Servicesysteem/KISS-frontend/issues/808#issuecomment-2357637675
return self._reformat_question(question), None

def _reformat_question(self, question_ok2: OpenKlant2Question) -> Question:
return {
"identification": question_ok2.nummer,
"subject": question_ok2.onderwerp,
"registered_date": question_ok2.plaatsgevonden_op,
"question_text": question_ok2.question,
"answer_text": question_ok2.answer.answer,
"status": "",
"channel": question_ok2.kanaal,
"case_detail_url": getattr(question_ok2, "zaak_url", None),
"api_source": KlantenServiceType.openklant2,
"new_answer_available": self._has_new_answer_available(question_ok2),
}

def _has_new_answer_available(self, question: Question) -> bool:
answer_is_recent = instance_is_new(
question.answer,
"plaatsgevonden_op",
datetime.timedelta(days=settings.CONTACTMOMENT_NEW_DAYS),
)
return answer_is_recent and not question.answer.viewed
Loading

0 comments on commit 8111c9d

Please sign in to comment.