diff --git a/src/open_inwoner/cms/cases/views/cases.py b/src/open_inwoner/cms/cases/views/cases.py index 398854d7ca..9c9508d870 100644 --- a/src/open_inwoner/cms/cases/views/cases.py +++ b/src/open_inwoner/cms/cases/views/cases.py @@ -1,15 +1,20 @@ +import concurrent.futures +import logging +from dataclasses import dataclass + 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 zgw_consumers.concurrent import parallel from open_inwoner.htmx.mixins import RequiresHtmxMixin +from open_inwoner.openzaak.api_models import Zaak from open_inwoner.openzaak.cases import preprocess_data -from open_inwoner.openzaak.clients import build_zaken_client from open_inwoner.openzaak.formapi import fetch_open_submissions -from open_inwoner.openzaak.models import OpenZaakConfig +from open_inwoner.openzaak.models import OpenZaakConfig, ZGWApiGroupConfig from open_inwoner.openzaak.types import UniformCase from open_inwoner.openzaak.utils import get_user_fetch_parameters from open_inwoner.utils.mixins import PaginationMixin @@ -17,6 +22,21 @@ from .mixins import CaseAccessMixin, CaseLogMixin, OuterCaseAccessMixin +logger = logging.getLogger(__name__) + + +@dataclass(frozen=True) +class ZaakWithApiGroup(UniformCase): + zaak: Zaak + api_group: ZGWApiGroupConfig + + @property + def identifier(self): + return self.zaak.url + + def process_data(self) -> dict: + return {**self.zaak.process_data(), "api_group": self.api_group} + class OuterCaseListView( OuterCaseAccessMixin, CommonPageMixin, BaseBreadcrumbMixin, TemplateView @@ -55,17 +75,36 @@ class InnerCaseListView( def page_title(self): return _("Mijn aanvragen") - def get_cases(self): - client = build_zaken_client() - - if client is None: - return [] - - raw_cases = client.fetch_cases(**get_user_fetch_parameters(self.request)) - - preprocessed_cases = preprocess_data(raw_cases) + def get_cases_for_api_group(self, group: ZGWApiGroupConfig): + raw_cases = group.zaken_client.fetch_cases( + **get_user_fetch_parameters(self.request) + ) + preprocessed_cases = preprocess_data(raw_cases, group) return preprocessed_cases + def get_cases(self) -> list[ZaakWithApiGroup]: + all_api_groups = list(ZGWApiGroupConfig.objects.all()) + with parallel() as executor: + futures = [ + executor.submit(self.get_cases_for_api_group, group) + for group in all_api_groups + ] + + cases = [] + for task in concurrent.futures.as_completed(futures): + try: + group_for_task = all_api_groups[futures.index(task)] + for row in task.result(): + cases.append( + ZaakWithApiGroup(zaak=row, api_group=group_for_task) + ) + except BaseException: + logger.exception("Error fetching and pre-processing cases") + + # Ensure stable sorting for pagination and testing purposes + cases.sort(key=lambda c: all_api_groups.index(c.api_group)) + return cases + def get_submissions(self): subs = fetch_open_submissions(self.request.user.bsn) subs.sort(key=lambda sub: sub.datum_laatste_wijziging, reverse=True) diff --git a/src/open_inwoner/openzaak/cases.py b/src/open_inwoner/openzaak/cases.py index 26d892d955..25045f708b 100644 --- a/src/open_inwoner/openzaak/cases.py +++ b/src/open_inwoner/openzaak/cases.py @@ -6,19 +6,14 @@ from zgw_consumers.concurrent import parallel from .api_models import Zaak -from .clients import ( - CatalogiClient, - ZakenClient, - build_catalogi_client, - build_zaken_client, -) -from .models import ZaakTypeConfig, ZaakTypeStatusTypeConfig +from .clients import CatalogiClient, ZakenClient +from .models import ZaakTypeConfig, ZaakTypeStatusTypeConfig, ZGWApiGroupConfig from .utils import is_zaak_visible logger = logging.getLogger(__name__) -def resolve_zaak_type(case: Zaak, client: CatalogiClient | None = None) -> None: +def resolve_zaak_type(case: Zaak, client: CatalogiClient) -> None: """ Resolve `case.zaaktype` (`str`) to a `ZaakType(ZGWModel)` object @@ -26,7 +21,6 @@ def resolve_zaak_type(case: Zaak, client: CatalogiClient | None = None) -> None: is only made for new case type urls """ case_type_url = case.zaaktype - client = client or build_catalogi_client() if client: case_type = client.fetch_single_case_type(case_type_url) case.zaaktype = case_type @@ -36,7 +30,6 @@ def resolve_status(case: Zaak, client: ZakenClient | None = None) -> None: """ Resolve `case.status` (`str`) to a `Status(ZGWModel)` object """ - client = client or build_zaken_client() if client: case.status = client.fetch_single_status(case.status) @@ -46,7 +39,6 @@ def resolve_status_type(case: Zaak, client: CatalogiClient | None = None) -> Non Resolve `case.status.statustype` (`str`) to a `StatusType(ZGWModel)` object """ statustype_url = case.status.statustype - client = client or build_catalogi_client() if client: case.status.statustype = client.fetch_single_status_type(statustype_url) @@ -55,8 +47,7 @@ def resolve_resultaat(case: Zaak, client: ZakenClient | None = None) -> None: """ Resolve `case.resultaat` (`str`) to a `Resultaat(ZGWModel)` object """ - client = client or build_zaken_client() - if client and case.resultaat: + if case.resultaat: case.resultaat = client.fetch_single_result(case.resultaat) @@ -64,7 +55,6 @@ def resolve_resultaat_type(case: Zaak, client: CatalogiClient | None = None) -> """ Resolve `case.resultaat.resultaattype` (`str`) to a `ResultaatType(ZGWModel)` object """ - client = client or build_catalogi_client() if client and case.resultaat: case.resultaat.resultaattype = client.fetch_single_resultaat_type( case.resultaat.resultaattype @@ -102,30 +92,27 @@ def add_status_type_config(case: Zaak) -> None: pass -def preprocess_data(cases: list[Zaak]) -> list[Zaak]: +def preprocess_data(cases: list[Zaak], group: ZGWApiGroupConfig) -> list[Zaak]: """ Resolve zaaktype and statustype, add status type config, filter for visibility Note: we need to iterate twice over `cases` because the `zaak_type` must be resolved to a `ZaakType` object before we can filter by visibility """ - zaken_client = build_zaken_client() - catalogi_client = build_catalogi_client() def preprocess_case(case: Zaak) -> None: - resolve_status(case, client=zaken_client) - resolve_status_type(case, client=catalogi_client) - resolve_resultaat(case, client=zaken_client) - resolve_resultaat_type(case, client=catalogi_client) + resolve_status(case, client=group.zaken_client) + resolve_status_type(case, client=group.catalogi_client) + resolve_resultaat(case, client=group.zaken_client) + resolve_resultaat_type(case, client=group.catalogi_client) add_zaak_type_config(case) add_status_type_config(case) - # TODO error handling if these are none? # use contextmanager to ensure the `requests.Session` is reused - with zaken_client, catalogi_client: + with group.catalogi_client, group.zaken_client: with parallel(max_workers=settings.CASE_LIST_NUM_THREADS) as executor: futures = [ - executor.submit(resolve_zaak_type, case, client=catalogi_client) + executor.submit(resolve_zaak_type, case, client=group.catalogi_client) for case in cases ] concurrent.futures.wait(futures) diff --git a/src/open_inwoner/openzaak/models.py b/src/open_inwoner/openzaak/models.py index ccdcfdb74c..d46385a0c6 100644 --- a/src/open_inwoner/openzaak/models.py +++ b/src/open_inwoner/openzaak/models.py @@ -69,6 +69,16 @@ class ZGWApiGroupConfig(models.Model): null=False, blank=False, ) + + def _build_client_from_attr(self, attr: str): + from .clients import build_zgw_client_from_service + + return build_zgw_client_from_service(getattr(self, attr)) + + @property + def zaken_client(self): + return self._build_client_from_attr("zrc_service") + drc_service = models.ForeignKey( "zgw_consumers.Service", verbose_name=_("Documenten API"), @@ -78,6 +88,11 @@ class ZGWApiGroupConfig(models.Model): null=False, blank=False, ) + + @property + def documenten_client(self): + return self._build_client_from_attr("drc_service") + ztc_service = models.ForeignKey( "zgw_consumers.Service", verbose_name=_("Catalogi API"), @@ -87,6 +102,11 @@ class ZGWApiGroupConfig(models.Model): null=False, blank=False, ) + + @property + def catalogi_client(self): + return self._build_client_from_attr("ztc_service") + form_service = models.OneToOneField( "zgw_consumers.Service", verbose_name=_("Form API"), @@ -97,6 +117,11 @@ class ZGWApiGroupConfig(models.Model): blank=True, ) + @property + def forms_client(self): + if self.form_service: + return self._build_client_from_attr("form_service") + class Meta: verbose_name = _("ZGW API set") verbose_name_plural = _("ZGW API sets") diff --git a/src/open_inwoner/openzaak/tests/test_cases.py b/src/open_inwoner/openzaak/tests/test_cases.py index d149e5cfdc..8ceac10d8d 100644 --- a/src/open_inwoner/openzaak/tests/test_cases.py +++ b/src/open_inwoner/openzaak/tests/test_cases.py @@ -1,4 +1,7 @@ import datetime +import hashlib +import random +import uuid from unittest.mock import patch from django.conf import settings @@ -36,7 +39,31 @@ ) from .helpers import generate_oas_component_cached from .mocks import ESuiteSubmissionData -from .shared import CATALOGI_ROOT, ZAKEN_ROOT +from .shared import ANOTHER_CATALOGI_ROOT, ANOTHER_ZAKEN_ROOT, CATALOGI_ROOT, ZAKEN_ROOT + + +class SeededUUIDGenerator: + def __init__(self, seed_value): + self.rng = random.Random(seed_value) + self.current_uuid = self._generate_initial_uuid() + + def _generate_initial_uuid(self): + random_bytes = [self.rng.randint(0, 255) for _ in range(16)] + return uuid.UUID(bytes=bytes(random_bytes), version=4) + + def get_uuid(self): + # Increment the UUID + int_value = int(self.current_uuid) + int_value += 1 + self.current_uuid = uuid.UUID(int=int_value, version=4) + return self.current_uuid + + +def _md5(value: str): + m = hashlib.md5() + m.update(value.encode("utf-8")) + return m.hexdigest() + # Avoid redirects through `KvKLoginMiddleware` PATCHED_MIDDLEWARE = [ @@ -119,84 +146,66 @@ def test_no_cases_are_retrieved_when_http_500(self, m): self.assertListEqual(response.context.get("cases"), []) -@requests_mock.Mocker() -@override_settings( - ROOT_URLCONF="open_inwoner.cms.tests.urls", - MIDDLEWARE=PATCHED_MIDDLEWARE, -) -class CaseListViewTests(AssertTimelineLogMixin, ClearCachesMixin, TransactionTestCase): - inner_url = reverse_lazy("cases:cases_content") - maxDiff = None - - def setUp(self): - super().setUp() - - self.user = UserFactory( - login_type=LoginTypeChoices.digid, bsn="900222086", email="johm@smith.nl" - ) - self.eherkenning_user = eHerkenningUserFactory.create( - kvk="12345678", - rsin="123456789", - login_type=LoginTypeChoices.eherkenning, - ) - - # openzaak config - self.config = OpenZaakConfig.get_solo() - self.config.zaak_max_confidentiality = ( - VertrouwelijkheidsAanduidingen.beperkt_openbaar - ) - self.config.save() +class CaseListMocks: + def __init__(self, *, zaken_root: str, catalogi_root: str, user, eherkenning_user): + self.zaken_root = zaken_root + self.catalogi_root = catalogi_root + self.user = user + self.eherkenning_user = eherkenning_user + uuid_generator = SeededUUIDGenerator(zaken_root + catalogi_root) - # services - ZGWApiGroupConfigFactory( - ztc_service__api_root=CATALOGI_ROOT, - zrc_service__api_root=ZAKEN_ROOT, - form_service=None, - ) + catalogus_url = f"{catalogi_root}catalogussen/{uuid_generator.get_uuid()}" self.zaaktype = generate_oas_component_cached( "ztc", "schemas/ZaakType", - url=f"{CATALOGI_ROOT}zaaktypen/53340e34-7581-4b04-884f", - omschrijving="Coffee zaaktype", - identificatie="ZAAK-2022-0000000001", - catalogus=f"{CATALOGI_ROOT}catalogussen/1b643db-81bb-d71bd5a2317a", + url=f"{catalogi_root}zaaktypen/{uuid_generator.get_uuid()}", + omschrijving="Applying for a cup of coffee", + identificatie=f"ZAAK-2022-{_md5(zaken_root)}", + catalogus=catalogus_url, vertrouwelijkheidaanduiding=VertrouwelijkheidsAanduidingen.openbaar, indicatieInternOfExtern="extern", ) self.zaak_type_intern = generate_oas_component_cached( "ztc", "schemas/ZaakType", - url=f"{CATALOGI_ROOT}zaaktypen/53340e34-75a1-4b04-1234", - omschrijving="Intern zaaktype", - catalogus=f"{CATALOGI_ROOT}catalogussen/1b643db-81bb-d71bd5a2317a", + url=f"{catalogi_root}zaaktypen/{uuid_generator.get_uuid()}", + omschrijving="Applying for an internal cup of coffee for employees", + catalogus=catalogus_url, vertrouwelijkheidaanduiding=VertrouwelijkheidsAanduidingen.openbaar, indicatieInternOfExtern="intern", ) + + initial_statustype_id = str(uuid_generator.get_uuid()) self.status_type_initial = generate_oas_component_cached( "ztc", "schemas/StatusType", - url=f"{CATALOGI_ROOT}statustypen/e3798107-ab27-4c3c-977d-777yu878km09", + uuid=initial_statustype_id, + url=f"{catalogi_root}statustypen/{initial_statustype_id}", zaaktype=self.zaaktype["url"], omschrijving="Initial request", statustekst="", volgnummer=1, isEindstatus=False, ) + statustype_finish_id = str(uuid_generator.get_uuid()) self.status_type_finish = generate_oas_component_cached( "ztc", "schemas/StatusType", - url=f"{CATALOGI_ROOT}statustypen/e3798107-ab27-4c3c-977d-744516671fe4", + uuid=statustype_finish_id, + url=f"{catalogi_root}statustypen/{statustype_finish_id}", zaaktype=self.zaaktype["url"], omschrijving="Finish", statustekst="Statustekst finish", volgnummer=2, isEindstatus=True, ) + resultaat_type_id = str(uuid_generator.get_uuid()) self.resultaat_type = generate_oas_component_cached( "ztc", "schemas/ResultaatType", - url=f"{CATALOGI_ROOT}resultaattypen/ab798107-ab27-4c3c-977d-777yu878km09", + uuid=resultaat_type_id, + url=f"{catalogi_root}resultaattypen/{resultaat_type_id}", zaaktype=self.zaaktype["url"], omschrijving="Eindresultaat", resultaattypeomschrijving="test1", @@ -221,17 +230,18 @@ def setUp(self): call_to_action_text="Click me", ) # open + zaak1_id = str(uuid_generator.get_uuid()) self.zaak1 = generate_oas_component_cached( "zrc", "schemas/Zaak", - url=f"{ZAKEN_ROOT}zaken/d8bbdeb7-770f-4ca9-b1ea-77b4730bf67d", - uuid="d8bbdeb7-770f-4ca9-b1ea-77b4730bf67d", + url=f"{zaken_root}zaken/{zaak1_id}", + uuid=zaak1_id, zaaktype=self.zaaktype["url"], - identificatie="ZAAK-2022-0000000001", + identificatie=f"ZAAK-2022-{_md5(zaak1_id)}", omschrijving="Coffee zaak 1", startdatum="2022-01-02", einddatum=None, - status=f"{ZAKEN_ROOT}statussen/3da89990-c7fc-476a-ad13-c9023450083c", + status=f"{zaken_root}statussen/3da89990-c7fc-476a-ad13-c9023450083c", vertrouwelijkheidaanduiding=VertrouwelijkheidsAanduidingen.openbaar, ) self.status1 = generate_oas_component_cached( @@ -246,14 +256,14 @@ def setUp(self): self.zaak2 = generate_oas_component_cached( "zrc", "schemas/Zaak", - url=f"{ZAKEN_ROOT}zaken/e4d469b9-6666-4bdd-bf42-b53445298102", + url=f"{zaken_root}zaken/e4d469b9-6666-4bdd-bf42-b53445298102", uuid="e4d469b9-6666-4bdd-bf42-b53445298102", zaaktype=self.zaaktype["url"], identificatie="0014ESUITE66392022", omschrijving="Coffee zaak 2", startdatum="2022-01-12", einddatum=None, - status=f"{ZAKEN_ROOT}statussen/3da81560-c7fc-476a-ad13-beu760sle929", + status=f"{zaken_root}statussen/3da81560-c7fc-476a-ad13-beu760sle929", vertrouwelijkheidaanduiding=VertrouwelijkheidsAanduidingen.openbaar, ) self.status2 = generate_oas_component_cached( @@ -269,15 +279,15 @@ def setUp(self): self.zaak_result = generate_oas_component_cached( "zrc", "schemas/Zaak", - url=f"{ZAKEN_ROOT}zaken/e4d469b9-6666-4bdd-bf42-b53445298123", + url=f"{zaken_root}zaken/e4d469b9-6666-4bdd-bf42-b53445298123", uuid="e4d469b9-6666-4bdd-bf42-b53445298123", zaaktype=self.zaaktype["url"], identificatie="0014ESUITE43212022", omschrijving="Result zaak", startdatum="2020-01-01", einddatum="2022-01-13", - status=f"{ZAKEN_ROOT}statussen/3da81560-c7fc-476a-ad13-beu760sle929", - resultaat=f"{ZAKEN_ROOT}resultaten/3da81560-c7fc-476a-ad13-beu760sle929", + status=f"{zaken_root}statussen/3da81560-c7fc-476a-ad13-beu760sle929", + resultaat=f"{zaken_root}resultaten/3da81560-c7fc-476a-ad13-beu760sle929", vertrouwelijkheidaanduiding=VertrouwelijkheidsAanduidingen.openbaar, ) self.result = generate_oas_component_cached( @@ -293,41 +303,41 @@ def setUp(self): self.zaak_eherkenning1 = generate_oas_component_cached( "zrc", "schemas/Zaak", - url=f"{ZAKEN_ROOT}zaken/bf558d78-280d-4723-b8e8-2b6179cd74e3", + url=f"{zaken_root}zaken/bf558d78-280d-4723-b8e8-2b6179cd74e3", uuid="bf558d78-280d-4723-b8e8-2b6179cd74e3", zaaktype=self.zaaktype["url"], identificatie="ZAAK-2022-0000000003", omschrijving="Coffee zaak 3", startdatum="2022-01-02", einddatum=None, - status=f"{ZAKEN_ROOT}statussen/3da89990-c7fc-476a-ad13-c9023450083c", + status=f"{zaken_root}statussen/3da89990-c7fc-476a-ad13-c9023450083c", vertrouwelijkheidaanduiding=VertrouwelijkheidsAanduidingen.openbaar, ) self.zaak_eherkenning2 = generate_oas_component_cached( "zrc", "schemas/Zaak", - url=f"{ZAKEN_ROOT}zaken/ff5026c8-5d1f-4bd2-a069-58d4bf75ec8c", + url=f"{zaken_root}zaken/ff5026c8-5d1f-4bd2-a069-58d4bf75ec8c", uuid="ff5026c8-5d1f-4bd2-a069-58d4bf75ec8c", zaaktype=self.zaaktype["url"], identificatie="ZAAK-2022-0000000004", omschrijving="Coffee zaak 4", startdatum="2022-02-02", einddatum=None, - status=f"{ZAKEN_ROOT}statussen/3da89990-c7fc-476a-ad13-c9023450083c", + status=f"{zaken_root}statussen/3da89990-c7fc-476a-ad13-c9023450083c", vertrouwelijkheidaanduiding=VertrouwelijkheidsAanduidingen.openbaar, ) # closed self.zaak3 = generate_oas_component_cached( "zrc", "schemas/Zaak", - url=f"{ZAKEN_ROOT}zaken/6f8de38f-85ea-42d3-978c-845a033335a7", + url=f"{zaken_root}zaken/6f8de38f-85ea-42d3-978c-845a033335a7", uuid="6f8de38f-85ea-42d3-978c-845a033335a7", zaaktype=self.zaaktype["url"], identificatie="ZAAK-2022-0001000003", omschrijving="Coffee zaak closed", startdatum="2021-07-26", einddatum="2022-01-16", - status=f"{ZAKEN_ROOT}statussen/98659876-bbb3-476a-ad13-n3nvcght758js", + status=f"{zaken_root}statussen/98659876-bbb3-476a-ad13-n3nvcght758js", vertrouwelijkheidaanduiding=VertrouwelijkheidsAanduidingen.openbaar, ) self.status3 = generate_oas_component_cached( @@ -340,17 +350,18 @@ def setUp(self): statustoelichting="", ) # not visible + zaak_intern_id = str(uuid_generator.get_uuid()) self.zaak_intern = generate_oas_component_cached( "zrc", "schemas/Zaak", - url=f"{ZAKEN_ROOT}zaken/d8bbdeb7-770f-4ca9-b1ea-77b4ee0bf67d", + url=f"{zaken_root}zaken/d8bbdeb7-770f-4ca9-b1ea-77b4ee0bf67d", uuid="d8bbdeb7-770f-4ca9-b1ea-77b4730bf67d", zaaktype=self.zaak_type_intern["url"], identificatie="ZAAK-2022-0000000009", omschrijving="Intern zaak", startdatum="2022-01-02", einddatum=None, - status=f"{ZAKEN_ROOT}statussen/3da89990-c7fc-476a-ad13-c90234500333", + status=f"{zaken_root}statussen/3da89990-c7fc-476a-ad13-c90234500333", vertrouwelijkheidaanduiding=VertrouwelijkheidsAanduidingen.openbaar, ) self.status_intern = generate_oas_component_cached( @@ -365,7 +376,7 @@ def setUp(self): self.submission = generate_oas_component_cached( "zrc", "schemas/Zaak", - url=f"{ZAKEN_ROOT}zaken/d8bbdeb7-770f-4ca9-b1ea-77b4ee0bf67d", + url=f"{zaken_root}zaken/d8bbdeb7-770f-4ca9-b1ea-77b4ee0bf67d", uuid="c8yudeb7-490f-2cw9-h8wa-44h9830bf67d", naam="mysub", datum_laatste_wijziging="2023-10-10", @@ -373,7 +384,7 @@ def setUp(self): def _setUpMocks(self, m): m.get( - furl(f"{ZAKEN_ROOT}zaken") + furl(f"{self.zaken_root}zaken") .add( { "rol__betrokkeneIdentificatie__natuurlijkPersoon__inpBsn": self.user.bsn, @@ -387,7 +398,7 @@ def _setUpMocks(self, m): ) for identifier in [self.eherkenning_user.kvk, self.eherkenning_user.rsin]: m.get( - furl(f"{ZAKEN_ROOT}zaken") + furl(f"{self.zaken_root}zaken") .add( { "rol__betrokkeneIdentificatie__nietNatuurlijkPersoon__innNnpId": identifier, @@ -400,7 +411,7 @@ def _setUpMocks(self, m): ), ) m.get( - furl(f"{ZAKEN_ROOT}zaken") + furl(f"{self.zaken_root}zaken") .add( { "rol__betrokkeneIdentificatie__nietNatuurlijkPersoon__innNnpId": identifier, @@ -426,103 +437,176 @@ def _setUpMocks(self, m): ]: m.get(resource["url"], json=resource) + +@requests_mock.Mocker() +@override_settings( + ROOT_URLCONF="open_inwoner.cms.tests.urls", + MIDDLEWARE=PATCHED_MIDDLEWARE, +) +class CaseListViewTests(AssertTimelineLogMixin, ClearCachesMixin, TransactionTestCase): + inner_url = reverse_lazy("cases:cases_content") + maxDiff = None + + def setUp(self): + super().setUp() + + self.user = UserFactory( + login_type=LoginTypeChoices.digid, bsn="900222086", email="johm@smith.nl" + ) + self.eherkenning_user = eHerkenningUserFactory.create( + kvk="12345678", + rsin="123456789", + login_type=LoginTypeChoices.eherkenning, + ) + + # openzaak config + self.config = OpenZaakConfig.get_solo() + self.config.zaak_max_confidentiality = ( + VertrouwelijkheidsAanduidingen.beperkt_openbaar + ) + self.config.save() + + # services + self.mocks = [] + self.roots = ( + (ZAKEN_ROOT, CATALOGI_ROOT), + (ANOTHER_ZAKEN_ROOT, ANOTHER_CATALOGI_ROOT), + ) + self.api_groups = [] + for zaken_root, catalogi_root in self.roots: + self.api_groups.append( + ZGWApiGroupConfigFactory( + zrc_service__api_root=zaken_root, + ztc_service__api_root=catalogi_root, + form_service=None, + ) + ) + self.mocks.append( + CaseListMocks( + zaken_root=zaken_root, + catalogi_root=catalogi_root, + user=self.user, + eherkenning_user=self.eherkenning_user, + ) + ) + def test_list_cases(self, m): - self._setUpMocks(m) + for mock in self.mocks: + mock._setUpMocks(m) # Added for https://taiga.maykinmedia.nl/project/open-inwoner/task/1904 # In eSuite it is possible to reuse a StatusType for multiple ZaakTypen, which # led to errors when retrieving the ZaakTypeStatusTypeConfig. This duplicate # config is added to verify that that issue was solved - ZaakTypeStatusTypeConfigFactory.create( - statustype_url=self.status_type_initial["url"], - status_indicator=StatusIndicators.warning, - status_indicator_text="U moet documenten toevoegen", - description="Lorem ipsum dolor sit amet", - call_to_action_url="https://example.com", - call_to_action_text="duplicate", - ) + for mock in self.mocks: + ZaakTypeStatusTypeConfigFactory.create( + statustype_url=mock.status_type_initial["url"], + status_indicator=StatusIndicators.warning, + status_indicator_text="U moet documenten toevoegen", + description="Lorem ipsum dolor sit amet", + call_to_action_url="https://example.com", + call_to_action_text="duplicate", + ) self.client.force_login(user=self.user) response = self.client.get(self.inner_url, HTTP_HX_REQUEST="true") - self.assertListEqual( - response.context["cases"], - [ - { - "uuid": self.zaak2["uuid"], - "start_date": datetime.date.fromisoformat(self.zaak2["startdatum"]), - "end_date": None, - "identification": self.zaak2["identificatie"], - "description": self.zaaktype["omschrijving"], - "current_status": self.status_type_initial["omschrijving"], - "zaaktype_config": self.zaaktype_config1, - "statustype_config": self.zt_statustype_config1, - "case_type": "Zaak", - }, - { - "uuid": self.zaak1["uuid"], - "start_date": datetime.date.fromisoformat(self.zaak1["startdatum"]), - "end_date": None, - "identification": self.zaak1["identificatie"], - "description": self.zaaktype["omschrijving"], - "current_status": self.status_type_initial["omschrijving"], - "zaaktype_config": self.zaaktype_config1, - "statustype_config": self.zt_statustype_config1, - "case_type": "Zaak", - }, - { - "uuid": self.zaak3["uuid"], - "start_date": datetime.date.fromisoformat(self.zaak3["startdatum"]), - "end_date": datetime.date.fromisoformat(self.zaak3["einddatum"]), - "identification": self.zaak3["identificatie"], - "description": self.zaaktype["omschrijving"], - "current_status": self.status_type_finish["statustekst"], - "zaaktype_config": self.zaaktype_config1, - "statustype_config": None, - "case_type": "Zaak", - }, - { - "uuid": self.zaak_result["uuid"], - "start_date": datetime.date.fromisoformat( - self.zaak_result["startdatum"] - ), - "end_date": datetime.date(2022, 1, 13), - "identification": self.zaak_result["identificatie"], - "description": self.zaaktype["omschrijving"], - # use result here - "current_status": self.resultaat_type["omschrijving"], - "zaaktype_config": self.zaaktype_config1, - "statustype_config": self.zt_statustype_config1, - "case_type": "Zaak", - }, - ], - ) + expected_cases = [] + for i, mock in enumerate(self.mocks): + expected_cases.extend( + [ + { + "uuid": mock.zaak2["uuid"], + "start_date": datetime.date.fromisoformat( + mock.zaak2["startdatum"] + ), + "end_date": None, + "identification": mock.zaak2["identificatie"], + "description": mock.zaaktype["omschrijving"], + "current_status": mock.status_type_initial["omschrijving"], + "zaaktype_config": mock.zaaktype_config1, + "statustype_config": mock.zt_statustype_config1, + "case_type": "Zaak", + "api_group": self.api_groups[i], + }, + { + "uuid": mock.zaak1["uuid"], + "start_date": datetime.date.fromisoformat( + mock.zaak1["startdatum"] + ), + "end_date": None, + "identification": mock.zaak1["identificatie"], + "description": mock.zaaktype["omschrijving"], + "current_status": mock.status_type_initial["omschrijving"], + "zaaktype_config": mock.zaaktype_config1, + "statustype_config": mock.zt_statustype_config1, + "case_type": "Zaak", + "api_group": self.api_groups[i], + }, + { + "uuid": mock.zaak3["uuid"], + "start_date": datetime.date.fromisoformat( + mock.zaak3["startdatum"] + ), + "end_date": datetime.date.fromisoformat( + mock.zaak3["einddatum"] + ), + "identification": mock.zaak3["identificatie"], + "description": mock.zaaktype["omschrijving"], + "current_status": mock.status_type_finish["statustekst"], + "zaaktype_config": mock.zaaktype_config1, + "statustype_config": None, + "case_type": "Zaak", + "api_group": self.api_groups[i], + }, + { + "uuid": mock.zaak_result["uuid"], + "start_date": datetime.date.fromisoformat( + mock.zaak_result["startdatum"] + ), + "end_date": datetime.date(2022, 1, 13), + "identification": mock.zaak_result["identificatie"], + "description": mock.zaaktype["omschrijving"], + # use result here + "current_status": mock.resultaat_type["omschrijving"], + "zaaktype_config": mock.zaaktype_config1, + "statustype_config": mock.zt_statustype_config1, + "case_type": "Zaak", + "api_group": self.api_groups[i], + }, + ] + ) + + self.assertListEqual(response.context["cases"], expected_cases) # don't show internal cases - self.assertNotContains(response, self.zaak_intern["omschrijving"]) - self.assertNotContains(response, self.zaak_intern["identificatie"]) + for mock in self.mocks: + self.assertNotContains(response, mock.zaak_intern["omschrijving"]) + self.assertNotContains(response, text=mock.zaak_intern["identificatie"]) # check zaken request query parameters - list_zaken_req = [ - req - for req in m.request_history - if req.hostname == "zaken.nl" and req.path == "/api/v1/zaken" - ][0] - self.assertEqual(len(list_zaken_req.qs), 2) - self.assertEqual( - list_zaken_req.qs, - { - "rol__betrokkeneidentificatie__natuurlijkpersoon__inpbsn": [ - self.user.bsn - ], - "maximalevertrouwelijkheidaanduiding": [ - VertrouwelijkheidsAanduidingen.beperkt_openbaar - ], - }, - ) + for zaken_root in ("zaken.nl", "andere-zaken.nl"): + list_zaken_req = [ + req + for req in m.request_history + if req.hostname == zaken_root and req.path == "/api/v1/zaken" + ][0] + self.assertEqual(len(list_zaken_req.qs), 2) + self.assertEqual( + list_zaken_req.qs, + { + "rol__betrokkeneidentificatie__natuurlijkpersoon__inpbsn": [ + self.user.bsn + ], + "maximalevertrouwelijkheidaanduiding": [ + VertrouwelijkheidsAanduidingen.beperkt_openbaar + ], + }, + ) @set_kvk_branch_number_in_session(None) def test_list_cases_for_eherkenning_user(self, m): - self._setUpMocks(m) + for mock in self.mocks: + mock._setUpMocks(m) for fetch_eherkenning_zaken_with_rsin in [True, False]: with self.subTest( @@ -538,64 +622,81 @@ def test_list_cases_for_eherkenning_user(self, m): self.client.force_login(user=self.eherkenning_user) response = self.client.get(self.inner_url, HTTP_HX_REQUEST="true") - self.assertListEqual( - response.context["cases"], - [ - { - "uuid": self.zaak_eherkenning2["uuid"], - "start_date": datetime.date.fromisoformat( - self.zaak_eherkenning2["startdatum"] - ), - "end_date": None, - "identification": self.zaak_eherkenning2["identificatie"], - "description": self.zaaktype["omschrijving"], - "current_status": self.status_type_initial["omschrijving"], - "zaaktype_config": self.zaaktype_config1, - "statustype_config": self.zt_statustype_config1, - "case_type": "Zaak", - }, - { - "uuid": self.zaak_eherkenning1["uuid"], - "start_date": datetime.date.fromisoformat( - self.zaak_eherkenning1["startdatum"] - ), - "end_date": None, - "identification": self.zaak_eherkenning1["identificatie"], - "description": self.zaaktype["omschrijving"], - "current_status": self.status_type_initial["omschrijving"], - "zaaktype_config": self.zaaktype_config1, - "statustype_config": self.zt_statustype_config1, - "case_type": "Zaak", - }, - ], - ) - # don't show internal cases - self.assertNotContains(response, self.zaak_intern["omschrijving"]) - self.assertNotContains(response, self.zaak_intern["identificatie"]) + expected_cases = [] + for i, mock in enumerate(self.mocks): + expected_cases.extend( + [ + { + "uuid": mock.zaak_eherkenning2["uuid"], + "start_date": datetime.date.fromisoformat( + mock.zaak_eherkenning2["startdatum"] + ), + "end_date": None, + "identification": mock.zaak_eherkenning2[ + "identificatie" + ], + "description": mock.zaaktype["omschrijving"], + "current_status": mock.status_type_initial[ + "omschrijving" + ], + "zaaktype_config": mock.zaaktype_config1, + "statustype_config": mock.zt_statustype_config1, + "case_type": "Zaak", + "api_group": self.api_groups[i], + }, + { + "uuid": mock.zaak_eherkenning1["uuid"], + "start_date": datetime.date.fromisoformat( + mock.zaak_eherkenning1["startdatum"] + ), + "end_date": None, + "identification": mock.zaak_eherkenning1[ + "identificatie" + ], + "description": mock.zaaktype["omschrijving"], + "current_status": mock.status_type_initial[ + "omschrijving" + ], + "zaaktype_config": mock.zaaktype_config1, + "statustype_config": mock.zt_statustype_config1, + "case_type": "Zaak", + "api_group": self.api_groups[i], + }, + ] + ) + + self.assertListEqual(response.context["cases"], expected_cases) + + for mock in self.mocks: + # don't show internal cases + self.assertNotContains(response, mock.zaak_intern["omschrijving"]) + self.assertNotContains(response, mock.zaak_intern["identificatie"]) # check zaken request query parameters - list_zaken_req = [ - req - for req in m.request_history - if req.hostname == "zaken.nl" and req.path == "/api/v1/zaken" - ][0] - identifier = ( - self.eherkenning_user.rsin - if fetch_eherkenning_zaken_with_rsin - else self.eherkenning_user.kvk - ) - self.assertEqual(len(list_zaken_req.qs), 2) - self.assertEqual( - list_zaken_req.qs, - { - "rol__betrokkeneidentificatie__nietnatuurlijkpersoon__innnnpid": [ - identifier - ], - "maximalevertrouwelijkheidaanduiding": [ - VertrouwelijkheidsAanduidingen.beperkt_openbaar - ], - }, - ) + for zaken_root in ("zaken.nl", "andere-zaken.nl"): + list_zaken_req = [ + req + for req in m.request_history + if req.hostname == zaken_root and req.path == "/api/v1/zaken" + ][0] + identifier = ( + self.eherkenning_user.rsin + if fetch_eherkenning_zaken_with_rsin + else self.eherkenning_user.kvk + ) + + self.assertEqual(len(list_zaken_req.qs), 2) + self.assertEqual( + list_zaken_req.qs, + { + "rol__betrokkeneidentificatie__nietnatuurlijkpersoon__innnnpid": [ + identifier + ], + "maximalevertrouwelijkheidaanduiding": [ + VertrouwelijkheidsAanduidingen.beperkt_openbaar + ], + }, + ) @set_kvk_branch_number_in_session("1234") def test_list_cases_for_eherkenning_user_with_vestigingsnummer(self, m): @@ -603,7 +704,9 @@ def test_list_cases_for_eherkenning_user_with_vestigingsnummer(self, m): If a KVK_BRANCH_NUMBER that is different from the KVK number is specified, additional filtering by vestiging should be applied when retrieving zaken """ - self._setUpMocks(m) + for mock in self.mocks: + mock._setUpMocks(m) + self.client.force_login(user=self.eherkenning_user) for fetch_eherkenning_zaken_with_rsin in [True, False]: @@ -619,58 +722,64 @@ def test_list_cases_for_eherkenning_user_with_vestigingsnummer(self, m): response = self.client.get(self.inner_url, HTTP_HX_REQUEST="true") + expected_cases = [ + { + "uuid": mock.zaak_eherkenning1["uuid"], + "start_date": datetime.date.fromisoformat( + mock.zaak_eherkenning1["startdatum"] + ), + "end_date": None, + "identification": mock.zaak_eherkenning1["identificatie"], + "description": mock.zaaktype["omschrijving"], + "current_status": mock.status_type_initial["omschrijving"], + "zaaktype_config": mock.zaaktype_config1, + "statustype_config": mock.zt_statustype_config1, + "case_type": "Zaak", + "api_group": self.api_groups[i], + } + for i, mock in enumerate(self.mocks) + ] self.assertListEqual( response.context["cases"], - [ - { - "uuid": self.zaak_eherkenning1["uuid"], - "start_date": datetime.date.fromisoformat( - self.zaak_eherkenning1["startdatum"] - ), - "end_date": None, - "identification": self.zaak_eherkenning1["identificatie"], - "description": self.zaaktype["omschrijving"], - "current_status": self.status_type_initial["omschrijving"], - "zaaktype_config": self.zaaktype_config1, - "statustype_config": self.zt_statustype_config1, - "case_type": "Zaak", - }, - ], + expected_cases, ) - # don't show internal cases - self.assertNotContains(response, self.zaak_intern["omschrijving"]) - self.assertNotContains(response, self.zaak_intern["identificatie"]) + for mock in self.mocks: + # don't show internal cases + self.assertNotContains(response, mock.zaak_intern["omschrijving"]) + self.assertNotContains(response, mock.zaak_intern["identificatie"]) # check zaken request query parameters - list_zaken_req = [ - req - for req in m.request_history - if req.hostname == "zaken.nl" and req.path == "/api/v1/zaken" - ][0] - identifier = ( - self.eherkenning_user.rsin - if fetch_eherkenning_zaken_with_rsin - else self.eherkenning_user.kvk - ) - - self.assertEqual(len(list_zaken_req.qs), 3) - self.assertEqual( - list_zaken_req.qs, - { - "rol__betrokkeneidentificatie__nietnatuurlijkpersoon__innnnpid": [ - identifier - ], - "maximalevertrouwelijkheidaanduiding": [ - VertrouwelijkheidsAanduidingen.beperkt_openbaar - ], - "rol__betrokkeneidentificatie__vestiging__vestigingsnummer": [ - "1234" - ], - }, - ) + for zaken_root in ("zaken.nl", "andere-zaken.nl"): + list_zaken_req = [ + req + for req in m.request_history + if req.hostname == zaken_root and req.path == "/api/v1/zaken" + ][0] + identifier = ( + self.eherkenning_user.rsin + if fetch_eherkenning_zaken_with_rsin + else self.eherkenning_user.kvk + ) + + self.assertEqual(len(list_zaken_req.qs), 3) + self.assertEqual( + list_zaken_req.qs, + { + "rol__betrokkeneidentificatie__nietnatuurlijkpersoon__innnnpid": [ + identifier + ], + "maximalevertrouwelijkheidaanduiding": [ + VertrouwelijkheidsAanduidingen.beperkt_openbaar + ], + "rol__betrokkeneidentificatie__vestiging__vestigingsnummer": [ + "1234" + ], + }, + ) def test_list_cases_for_eherkenning_user_missing_rsin(self, m): - self._setUpMocks(m) + for mock in self.mocks: + mock._setUpMocks(m) self.eherkenning_user.rsin = "" self.eherkenning_user.save() @@ -684,21 +793,25 @@ def test_list_cases_for_eherkenning_user_missing_rsin(self, m): response = self.client.get(self.inner_url, HTTP_HX_REQUEST="true") self.assertListEqual(response.context["cases"], []) - # don't show internal cases - self.assertNotContains(response, self.zaak_intern["omschrijving"]) - self.assertNotContains(response, self.zaak_intern["identificatie"]) - - # check zaken request query parameters - list_zaken_req = [ - req - for req in m.request_history - if req.hostname == "zaken.nl" and req.path == "/api/v1/zaken" - ] - self.assertEqual(len(list_zaken_req), 0) + for mock in self.mocks: + # don't show internal cases + self.assertNotContains(response, mock.zaak_intern["omschrijving"]) + self.assertNotContains(response, mock.zaak_intern["identificatie"]) + + for zaken_root in ("zaken.nl", "andere-zaken.nl"): + # check zaken request query parameters + list_zaken_req = [ + req + for req in m.request_history + if req.hostname == zaken_root and req.path == "/api/v1/zaken" + ] + self.assertEqual(len(list_zaken_req), 0) def test_format_zaak_identificatie(self, m): + for mock in self.mocks: + mock._setUpMocks(m) + config = OpenZaakConfig.get_solo() - self._setUpMocks(m) self.client.force_login(user=self.user) with self.subTest("formatting enabled"): @@ -707,13 +820,13 @@ def test_format_zaak_identificatie(self, m): response = self.client.get(self.inner_url, HTTP_HX_REQUEST="true") - e_suite_case = next( - case - for case in response.context["cases"] - if case["uuid"] == self.zaak2["uuid"] - ) - - self.assertEqual(e_suite_case["identification"], "6639-2022") + for mock in self.mocks: + for e_suite_case in ( + case + for case in response.context["cases"] + if case["uuid"] == mock.zaak2["uuid"] + ): + self.assertEqual(e_suite_case["identification"], "6639-2022") with self.subTest("formatting disabled"): config.reformat_esuite_zaak_identificatie = False @@ -721,13 +834,15 @@ def test_format_zaak_identificatie(self, m): response = self.client.get(self.inner_url, HTTP_HX_REQUEST="true") - e_suite_case = next( - case - for case in response.context["cases"] - if case["uuid"] == self.zaak2["uuid"] - ) - - self.assertEqual(e_suite_case["identification"], "0014ESUITE66392022") + for mock in self.mocks: + for e_suite_case in ( + case + for case in response.context["cases"] + if case["uuid"] == mock.zaak2["uuid"] + ): + self.assertEqual( + e_suite_case["identification"], "0014ESUITE66392022" + ) def test_reformat_esuite_zaak_identificatie(self, m): tests = [ @@ -744,7 +859,8 @@ def test_reformat_esuite_zaak_identificatie(self, m): self.assertEqual(actual, expected) def test_list_cases_logs_displayed_case_ids(self, m): - self._setUpMocks(m) + for mock in self.mocks: + mock._setUpMocks(m) self.client.force_login(user=self.user) self.client.get(self.inner_url, HTTP_HX_REQUEST="true") @@ -753,118 +869,157 @@ def test_list_cases_logs_displayed_case_ids(self, m): logs = list(TimelineLog.objects.all()) case_log = [ - l for l in logs if self.zaak1["identificatie"] in l.extra_data["message"] + l + for l in logs + for mock in self.mocks + if mock.zaak1["identificatie"] in l.extra_data["message"] ] - self.assertEqual(len(case_log), 1) - self.assertEqual(self.user, case_log[0].user) - self.assertEqual(self.user, case_log[0].content_object) + self.assertEqual(len(case_log), 2) + self.assertTrue(all(l.user == self.user for l in case_log)) + self.assertTrue(all(l.content_object == self.user for l in case_log)) case_log = [ - l for l in logs if self.zaak2["identificatie"] in l.extra_data["message"] + l + for l in logs + for mock in self.mocks + if mock.zaak2["identificatie"] in l.extra_data["message"] ] - self.assertEqual(len(case_log), 1) - self.assertEqual(self.user, case_log[0].user) - self.assertEqual(self.user, case_log[0].content_object) + self.assertEqual(len(case_log), 2) + self.assertTrue(all(l.user == self.user for l in case_log)) + self.assertTrue(all(l.content_object == self.user for l in case_log)) # no logs for internal, hence non-displayed cases for log in logs: - self.assertNotIn( - self.zaak_intern["identificatie"], log.extra_data["message"] - ) + for mock in self.mocks: + self.assertNotIn( + mock.zaak_intern["identificatie"], log.extra_data["message"] + ) - @patch.object(InnerCaseListView, "paginate_by", 1) + @patch.object(InnerCaseListView, "paginate_by", 4) def test_list_cases_paginated(self, m): """ - show only one case and url to the next page + show only cases from the first backend and url to the next page """ - self._setUpMocks(m) + for mock in self.mocks: + mock._setUpMocks(m) # 1. test first page self.client.force_login(user=self.user) response_1 = self.client.get(self.inner_url, HTTP_HX_REQUEST="true") - self.assertListEqual( - response_1.context.get("cases"), + expected_cases = [ [ { - "uuid": self.zaak2["uuid"], - "start_date": datetime.date.fromisoformat(self.zaak2["startdatum"]), + "uuid": mock.zaak2["uuid"], + "start_date": datetime.date.fromisoformat(mock.zaak2["startdatum"]), "end_date": None, - "identification": self.zaak2["identificatie"], - "description": self.zaaktype["omschrijving"], - "current_status": self.status_type_initial["omschrijving"], - "zaaktype_config": self.zaaktype_config1, - "statustype_config": self.zt_statustype_config1, + "identification": mock.zaak2["identificatie"], + "description": mock.zaaktype["omschrijving"], + "current_status": mock.status_type_initial["omschrijving"], + "zaaktype_config": mock.zaaktype_config1, + "statustype_config": mock.zt_statustype_config1, "case_type": "Zaak", + "api_group": self.api_groups[i], }, - ], - ) - self.assertNotContains(response_1, self.zaak1["identificatie"]) + { + "uuid": mock.zaak1["uuid"], + "start_date": datetime.date.fromisoformat(mock.zaak1["startdatum"]), + "end_date": None, + "identification": mock.zaak1["identificatie"], + "description": mock.zaaktype["omschrijving"], + "current_status": mock.status_type_initial["omschrijving"], + "zaaktype_config": mock.zaaktype_config1, + "statustype_config": mock.zt_statustype_config1, + "case_type": "Zaak", + "api_group": self.api_groups[i], + }, + { + "uuid": mock.zaak3["uuid"], + "start_date": datetime.date.fromisoformat(mock.zaak3["startdatum"]), + "end_date": datetime.date.fromisoformat(mock.zaak3["einddatum"]), + "identification": mock.zaak3["identificatie"], + "description": mock.zaaktype["omschrijving"], + "current_status": mock.status_type_finish["statustekst"], + "zaaktype_config": mock.zaaktype_config1, + "statustype_config": None, + "case_type": "Zaak", + "api_group": self.api_groups[i], + }, + { + "uuid": mock.zaak_result["uuid"], + "start_date": datetime.date.fromisoformat( + mock.zaak_result["startdatum"] + ), + "end_date": datetime.date(2022, 1, 13), + "identification": mock.zaak_result["identificatie"], + "description": mock.zaaktype["omschrijving"], + # use result here + "current_status": mock.resultaat_type["omschrijving"], + "zaaktype_config": mock.zaaktype_config1, + "statustype_config": mock.zt_statustype_config1, + "case_type": "Zaak", + "api_group": self.api_groups[i], + }, + ] + for i, mock in enumerate(self.mocks) + ] + + self.assertListEqual(response_1.context.get("cases"), expected_cases[0]) + self.assertNotContains(response_1, self.mocks[0].zaak2["url"]) self.assertContains(response_1, "?page=2") - # 2. test next page + # 2. test page 2, where the responses from the second backend begin next_page = f"{self.inner_url}?page=2" response_2 = self.client.get(next_page, HTTP_HX_REQUEST="true") - self.assertListEqual( - response_2.context.get("cases"), - [ - { - "uuid": self.zaak1["uuid"], - "start_date": datetime.date.fromisoformat(self.zaak1["startdatum"]), - "end_date": None, - "identification": self.zaak1["identificatie"], - "description": self.zaaktype["omschrijving"], - "current_status": self.status_type_initial["omschrijving"], - "zaaktype_config": self.zaaktype_config1, - "statustype_config": self.zt_statustype_config1, - "case_type": "Zaak", - }, - ], - ) - self.assertNotContains(response_2, self.zaak2["identificatie"]) + self.assertListEqual(response_2.context.get("cases"), expected_cases[1]) + self.assertNotContains(response_2, self.mocks[1].zaak2["url"]) self.assertContains(response_2, "?page=1") - @patch.object(InnerCaseListView, "paginate_by", 1) + @patch.object(InnerCaseListView, "paginate_by", 4) def test_list_cases_paginated_logs_displayed_case_ids(self, m): - self._setUpMocks(m) - self.client.force_login(user=self.user) - - with self.subTest("first page"): - response = self.client.get(self.inner_url, HTTP_HX_REQUEST="true") - self.assertEqual( - response.context.get("cases")[0]["uuid"], self.zaak2["uuid"] - ) + for mock in self.mocks: + mock._setUpMocks(m) - self.assertTimelineLog(f"Zaken bekeken: {self.zaak2['identificatie']}") + self.client.force_login(user=self.user) - with self.assertRaises(AssertionError): - self.assertTimelineLog( - self.zaak1["identificatie"], lookup=Lookups.icontains - ) - self.assertTimelineLog( - self.zaak3["identificatie"], lookup=Lookups.icontains + for page, mock in enumerate(self.mocks): + with self.subTest(f"page {page + 1}"): + url = self.inner_url + f"?page={page + 1}" + response = self.client.get(url, HTTP_HX_REQUEST="true") + + expected_uuids = [ + mock.zaak2["uuid"], + mock.zaak1["uuid"], + mock.zaak3["uuid"], + mock.zaak_result["uuid"], + ] + self.assertListEqual( + [c["uuid"] for c in response.context.get("cases")], expected_uuids ) - TimelineLog.objects.all().delete() - - with self.subTest("next page"): - next_page = f"{self.inner_url}?page=2" - response = self.client.get(next_page, HTTP_HX_REQUEST="true") - self.assertEqual( - response.context.get("cases")[0]["uuid"], self.zaak1["uuid"] - ) - - self.assertTimelineLog(f"Zaken bekeken: {self.zaak1['identificatie']}") - - with self.assertRaises(AssertionError): + expected_identifications = [ + mock.zaak2["identificatie"], + mock.zaak1["identificatie"], + mock.zaak3["identificatie"], + mock.zaak_result["identificatie"], + ] self.assertTimelineLog( - self.zaak2["identificatie"], lookup=Lookups.icontains - ) - self.assertTimelineLog( - self.zaak3["identificatie"], lookup=Lookups.icontains + f"Zaken bekeken: {', '.join(expected_identifications)}" ) + other_mock = self.mocks[0 if page == 1 else 1] + with self.assertRaises(AssertionError): + self.assertTimelineLog( + message=other_mock.zaak1["identificatie"], + lookup=Lookups.icontains, + ) + self.assertTimelineLog( + other_mock.zaak3["identificatie"], lookup=Lookups.icontains + ) + + TimelineLog.objects.all().delete() + @override_settings(ROOT_URLCONF="open_inwoner.cms.tests.urls") class CaseSubmissionTest(WebTest):