From b81dde6a98c94f4896c20fd6dbcf3d87d7ea2ff8 Mon Sep 17 00:00:00 2001 From: Paul Schilling Date: Thu, 2 Nov 2023 10:13:24 +0100 Subject: [PATCH] [#1827] Show second status for cases --- src/open_inwoner/cms/cases/views/cases.py | 13 ++++- src/open_inwoner/cms/cases/views/status.py | 55 ++++++++++++++----- .../openzaak/tests/test_case_detail.py | 51 +++++++++++++++-- 3 files changed, 98 insertions(+), 21 deletions(-) diff --git a/src/open_inwoner/cms/cases/views/cases.py b/src/open_inwoner/cms/cases/views/cases.py index fe1405fa3a..ac5b805eac 100644 --- a/src/open_inwoner/cms/cases/views/cases.py +++ b/src/open_inwoner/cms/cases/views/cases.py @@ -1,7 +1,10 @@ from django.urls import reverse +from django.utils.functional import cached_property from django.utils.translation import gettext_lazy as _ from django.views.generic import TemplateView +from view_breadcrumbs import BaseBreadcrumbMixin + from open_inwoner.htmx.mixins import RequiresHtmxMixin from open_inwoner.openzaak.cases import fetch_cases, preprocess_data from open_inwoner.openzaak.formapi import fetch_open_submissions @@ -13,11 +16,19 @@ from .mixins import CaseAccessMixin, CaseLogMixin, OuterCaseAccessMixin -class OuterCaseListView(OuterCaseAccessMixin, CommonPageMixin, TemplateView): +class OuterCaseListView( + OuterCaseAccessMixin, CommonPageMixin, BaseBreadcrumbMixin, TemplateView +): """View on the case list while content is loaded via htmx""" template_name = "pages/cases/list_outer.html" + @cached_property + def crumbs(self): + return [ + (_("Mijn aanvragen"), reverse("cases:index")), + ] + def page_title(self): return _("Mijn aanvragen") diff --git a/src/open_inwoner/cms/cases/views/status.py b/src/open_inwoner/cms/cases/views/status.py index 0615b0654a..96e759416e 100644 --- a/src/open_inwoner/cms/cases/views/status.py +++ b/src/open_inwoner/cms/cases/views/status.py @@ -116,32 +116,26 @@ def get_context_data(self, **kwargs): config = OpenZaakConfig.get_solo() status_translate = StatusTranslation.objects.get_lookup() + # fetch data associated with `self.case` documents = self.get_case_document_files(self.case) - statuses = fetch_status_history(self.case.url) + # NOTE maybe this should be cached? + statustypen = fetch_status_types_no_cache(self.case.zaaktype.url) statustype_config_mapping = { zaaktype_statustype.statustype_url: zaaktype_statustype for zaaktype_statustype in ZaakTypeStatusTypeConfig.objects.all() } - # NOTE maybe this should be cached? - statustypen = fetch_status_types_no_cache(self.case.zaaktype.url) - end_statustype = next( - ( - status_type - for status_type in statustypen - if status_type.is_eindstatus - ), - None, - ) - end_statustype_data = None - - # NOTE we cannot sort on the Status.datum_status_gezet (datetime) because eSuite returns zeros as the time component of the datetime, - # so we're going with the observation that on both OpenZaak and eSuite the returned list is ordered 'oldest-last' + # NOTE we cannot sort on the Status.datum_status_gezet (datetime) because eSuite + # returns zeros as the time component of the datetime, so we're going with the + # observation that on both OpenZaak and eSuite the returned list is ordered 'oldest-last' # here we want it 'oldest-first' so we reverse() it instead of sort()-ing statuses.reverse() + if len(statuses) == 1: + self.add_second_status_preview(statuses, statustypen) + status_types = defaultdict(list) for status in statuses: status_types[status.statustype].append(status) @@ -157,6 +151,8 @@ def get_context_data(self, **kwargs): # The end status data is not passed if the end status has been reached, # because in that case the end status data is already included in `statuses` + end_statustype = next((s for s in statustypen if s.is_eindstatus), None) + end_statustype_data = None if not status_types.get(end_statustype.url): end_statustype_data = { "label": status_translate( @@ -206,6 +202,35 @@ def get_context_data(self, **kwargs): context["case"] = None return context + def add_second_status_preview(self, statuses: list, statustypen: list) -> None: + """ + Update `statuses` with second (upcoming) status + + As the second status is not yet available, a mock is created, using `self.case` + and the second statustype from `statustypen` + + Note: we cannot assume that the "second" statustype has the `volgnummer` 2; + hence we get all statustype_numbers, sort in ascending order, and let + the "second" statustype be that with `volgnummer == statustype_numbers[1]` + """ + statustype_numbers = [s.volgnummer for s in statustypen] + statustype_numbers.sort() + + second_status_type = next( + filter( + lambda s: s.volgnummer == statustype_numbers[1] and not s.is_eindstatus, + statustypen, + ), + None, + ) + if not second_status_type: + return + + second_status = Status( + url="#", zaak=self.case, statustype=second_status_type.url + ) + statuses.append(second_status) + def get_upload_info_context(self, case: Zaak): if not case: return {} diff --git a/src/open_inwoner/openzaak/tests/test_case_detail.py b/src/open_inwoner/openzaak/tests/test_case_detail.py index bac41a4e45..df778253b3 100644 --- a/src/open_inwoner/openzaak/tests/test_case_detail.py +++ b/src/open_inwoner/openzaak/tests/test_case_detail.py @@ -75,7 +75,9 @@ def setUpTestData(cls): kwargs={"object_id": "d8bbdeb7-770f-4ca9-b1ea-77b4730bf67d"}, ) - # openzaak resources + # + # zaken + # cls.zaak = generate_oas_component( "zrc", "schemas/Zaak", @@ -124,6 +126,9 @@ def setUpTestData(cls): beginGeldigheid="2020-09-25", versiedatum="2020-09-25", ) + # + # statuses + # cls.status_new = generate_oas_component( "zrc", "schemas/Status", @@ -136,12 +141,15 @@ def setUpTestData(cls): cls.status_finish = generate_oas_component( "zrc", "schemas/Status", - url=f"{ZAKEN_ROOT}statussen/3da89990-c7fc-476a-ad13-c9023450083c", + url=f"{ZAKEN_ROOT}statussen/29ag1264-c4he-249j-bc24-jip862tle833", zaak=cls.zaak["url"], - statustype=f"{CATALOGI_ROOT}statustypen/e3798107-ab27-4c3c-977d-744516671fe4", + statustype=f"{CATALOGI_ROOT}statustypen/d4839012-gh35-3a8d-866h-444uy935acv7", datumStatusGezet="2021-03-12", statustoelichting="", ) + # + # status types + # cls.status_type_new = generate_oas_component( "ztc", "schemas/StatusType", @@ -154,6 +162,19 @@ def setUpTestData(cls): volgnummer=1, isEindstatus=False, ) + # no associated status (for testing `add_second_status_preview`) + cls.status_type_in_behandeling = generate_oas_component( + "ztc", + "schemas/StatusType", + url=f"{CATALOGI_ROOT}statustypen/167cb935-ac8a-428e-8cca-5abda0da47c7", + zaaktype=cls.zaaktype["url"], + catalogus=f"{CATALOGI_ROOT}catalogussen/1b643db-81bb-d71bd5a2317a", + omschrijving="In behandeling", + omschrijvingGeneriek="some content", + statustekst="", + volgnummer=3, + isEindstatus=False, + ) cls.status_type_finish = generate_oas_component( "ztc", "schemas/StatusType", @@ -163,7 +184,7 @@ def setUpTestData(cls): omschrijving="Finish", omschrijvingGeneriek="some content", statustekst="", - volgnummer=2, + volgnummer=4, isEindstatus=True, ) cls.user_role = generate_oas_component( @@ -314,6 +335,7 @@ def _setUpMocks(self, m, use_eindstatus=True): self.informatie_object_invisible, self.zaaktype_informatie_object_type, self.status_type_new, + self.status_type_in_behandeling, self.status_type_finish, ]: m.get(resource["url"], json=resource) @@ -361,9 +383,16 @@ def _setUpMocks(self, m, use_eindstatus=True): f"{DOCUMENTEN_ROOT}enkelvoudiginformatieobjecten/014c38fe-b010-4412-881c-3000032fb812/download", text="document content", ) + # TODO m.get( f"{CATALOGI_ROOT}statustypen?zaaktype={self.zaaktype['url']}", - json=paginated_response([self.status_type_new, self.status_type_finish]), + json=paginated_response( + [ + self.status_type_new, + self.status_type_in_behandeling, + self.status_type_finish, + ] + ), ) def test_status_is_retrieved_when_user_logged_in_via_digid(self, m): @@ -436,6 +465,11 @@ def test_pass_endstatus_type_data_if_endstatus_not_reached(self, m): status_indicator=StatusIndicators.warning, status_indicator_text="foo", ) + ZaakTypeStatusTypeConfigFactory.create( + statustype_url=self.status_type_in_behandeling["url"], + status_indicator=StatusIndicators.success, + status_indicator_text="zap", + ) ZaakTypeStatusTypeConfigFactory.create( statustype_url=self.status_type_finish["url"], status_indicator=StatusIndicators.success, @@ -473,6 +507,13 @@ def test_pass_endstatus_type_data_if_endstatus_not_reached(self, m): "status_indicator": "warning", "status_indicator_text": "foo", }, + # preview of second (upcoming) status + { + "date": None, + "label": "In behandeling", + "status_indicator": "success", + "status_indicator_text": "zap", + }, ], # only one visible information object "documents": [self.informatie_object_file],