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

✨ [#2002] Implement Zaken notifications for companies #937

Merged
merged 1 commit into from
Jan 9, 2024
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
53 changes: 46 additions & 7 deletions src/open_inwoner/openzaak/notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -419,16 +419,55 @@ def get_np_initiator_bsns_from_roles(roles: List[Rol]) -> List[str]:
return list(ret)


def get_nnp_initiator_nnp_id_from_roles(roles: List[Rol]) -> List[str]:
"""
iterate over Rollen and for all non-natural-person initiators return their nnpId
"""
ret = set()

for role in roles:
if role.omschrijving_generiek not in (
RolOmschrijving.initiator,
RolOmschrijving.medeinitiator,
):
continue
if role.betrokkene_type != RolTypes.niet_natuurlijk_persoon:
continue
if not role.betrokkene_identificatie:
continue
nnp_id = role.betrokkene_identificatie.get("inn_nnp_id")
if not nnp_id:
continue
ret.add(nnp_id)

return list(ret)


def get_emailable_initiator_users_from_roles(roles: List[Rol]) -> List[User]:
"""
iterate over Rollen and return User objects for all natural-person initiators we can notify
"""
users = []

bsn_list = get_np_initiator_bsns_from_roles(roles)
if not bsn_list:
return []
users = list(
User.objects.filter(
bsn__in=bsn_list, is_active=True, cases_notifications=True
).having_usable_email()
)
if bsn_list:
users += list(
User.objects.filter(
bsn__in=bsn_list, is_active=True, cases_notifications=True
).having_usable_email()
)

nnp_id_list = get_nnp_initiator_nnp_id_from_roles(roles)
if nnp_id_list:
config = OpenZaakConfig.get_solo()
if config.fetch_eherkenning_zaken_with_rsin:
id_filter = {"rsin__in": nnp_id_list}
else:
id_filter = {"kvk__in": nnp_id_list}
users += list(
User.objects.filter(
is_active=True, cases_notifications=True, **id_filter
).having_usable_email()
)

return users
62 changes: 61 additions & 1 deletion src/open_inwoner/openzaak/tests/test_notification_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
from zgw_consumers.constants import APITypes
from zgw_consumers.test import generate_oas_component, mock_service_oas_get

from open_inwoner.accounts.tests.factories import DigidUserFactory
from open_inwoner.accounts.tests.factories import (
DigidUserFactory,
eHerkenningUserFactory,
)
from open_inwoner.openzaak.tests.factories import (
NotificationFactory,
ServiceFactory,
Expand Down Expand Up @@ -54,6 +57,11 @@ def __init__(self):
bsn="100000001",
email="[email protected]",
)
self.eherkenning_user_initiator = eHerkenningUserFactory(
kvk="12345678",
rsin="000000000",
email="[email protected]",
)
self.zaak_type = generate_oas_component(
"ztc",
"schemas/ZaakType",
Expand Down Expand Up @@ -93,6 +101,15 @@ def __init__(self):
resultaat=f"{ZAKEN_ROOT}resultaten/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
vertrouwelijkheidaanduiding=VertrouwelijkheidsAanduidingen.openbaar,
)
self.zaak2 = generate_oas_component(
"zrc",
"schemas/Zaak",
url=f"{ZAKEN_ROOT}zaken/bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb",
zaaktype=self.zaak_type["url"],
status=f"{ZAKEN_ROOT}statussen/aaaaaaaa-aaaa-aaaa-aaaa-222222222222",
resultaat=f"{ZAKEN_ROOT}resultaten/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa",
vertrouwelijkheidaanduiding=VertrouwelijkheidsAanduidingen.openbaar,
)
self.status_initial = generate_oas_component(
"zrc",
"schemas/Status",
Expand Down Expand Up @@ -123,6 +140,13 @@ def __init__(self):
informatieobject=self.informatie_object["url"],
zaak=self.zaak["url"],
)
self.zaak_informatie_object2 = generate_oas_component(
"zrc",
"schemas/ZaakInformatieObject",
url=f"{ZAKEN_ROOT}zaakinformatieobjecten/aaaaaaaa-0002-aaaa-aaaa-aaaaaaaaaaaa",
informatieobject=self.informatie_object["url"],
zaak=self.zaak2["url"],
)

self.role_initiator = generate_oas_component(
"zrc",
Expand All @@ -134,8 +158,32 @@ def __init__(self):
"inpBsn": self.user_initiator.bsn,
},
)
self.eherkenning_role_initiator = generate_oas_component(
"zrc",
"schemas/Rol",
url=f"{ZAKEN_ROOT}rollen/aaaaaaaa-0002-aaaa-aaaa-aaaaaaaaaaaa",
omschrijvingGeneriek=RolOmschrijving.initiator,
betrokkeneType=RolTypes.niet_natuurlijk_persoon,
betrokkeneIdentificatie={
"innNnpId": self.eherkenning_user_initiator.kvk,
},
)
self.eherkenning_role_initiator2 = generate_oas_component(
"zrc",
"schemas/Rol",
url=f"{ZAKEN_ROOT}rollen/aaaaaaaa-0003-aaaa-aaaa-aaaaaaaaaaaa",
omschrijvingGeneriek=RolOmschrijving.initiator,
betrokkeneType=RolTypes.niet_natuurlijk_persoon,
betrokkeneIdentificatie={
"innNnpId": self.eherkenning_user_initiator.rsin,
},
)

self.case_roles = [self.role_initiator]
self.eherkenning_case_roles = [
self.eherkenning_role_initiator,
self.eherkenning_role_initiator2,
]
self.status_history = [self.status_initial, self.status_final]

self.status_notification = NotificationFactory(
Expand All @@ -150,6 +198,12 @@ def __init__(self):
resource_url=self.zaak_informatie_object["url"],
hoofd_object=self.zaak["url"],
)
self.zio_notification2 = NotificationFactory(
resource="zaakinformatieobject",
actie="create",
resource_url=self.zaak_informatie_object2["url"],
hoofd_object=self.zaak2["url"],
)

def setUpOASMocks(self, m):
mock_service_oas_get(m, ZAKEN_ROOT, "zrc")
Expand All @@ -171,6 +225,10 @@ def install_mocks(self, m, *, res404: Optional[List[str]] = None) -> "MockAPIDat
f"{ZAKEN_ROOT}rollen?zaak={self.zaak['url']}",
json=paginated_response(self.case_roles),
)
m.get(
f"{ZAKEN_ROOT}rollen?zaak={self.zaak2['url']}",
json=paginated_response(self.eherkenning_case_roles),
)

if "status_history" in res404:
m.get(f"{ZAKEN_ROOT}statussen?zaak={self.zaak['url']}", status_code=404)
Expand All @@ -182,6 +240,7 @@ def install_mocks(self, m, *, res404: Optional[List[str]] = None) -> "MockAPIDat

for resource_attr in [
"zaak",
"zaak2",
"zaak_type",
"status_initial",
"status_final",
Expand All @@ -190,6 +249,7 @@ def install_mocks(self, m, *, res404: Optional[List[str]] = None) -> "MockAPIDat
"status_type_final",
"informatie_object",
"zaak_informatie_object",
"zaak_informatie_object2",
]:
resource = getattr(self, resource_attr)
if resource_attr in res404:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,48 @@ def test_zio_handle_zaken_notification(self, m, mock_handle: Mock):
level=logging.INFO,
)

def test_zio_handle_zaken_notification_niet_natuurlijk_persoon_initiator(
self, m, mock_handle: Mock
):
"""
happy-flow from valid data calls the (mocked) handle_zaakinformatieobject() for
niet natuurlijk persoon initiator
"""
data = MockAPIData().install_mocks(m)

ZaakTypeInformatieObjectTypeConfigFactory.from_case_type_info_object_dicts(
data.zaak_type, data.informatie_object, document_notification_enabled=True
)

config = OpenZaakConfig.get_solo()
for fetch_eherkenning_zaken_with_rsin in [True, False]:
with self.subTest(
fetch_eherkenning_zaken_with_rsin=fetch_eherkenning_zaken_with_rsin
):
mock_handle.reset_mock()
self.clearTimelineLogs()

config.fetch_eherkenning_zaken_with_rsin = (
fetch_eherkenning_zaken_with_rsin
)
config.save()

handle_zaken_notification(data.zio_notification2)

mock_handle.assert_called_once()

# check call arguments
args = mock_handle.call_args.args
self.assertEqual(args[0], data.eherkenning_user_initiator)
self.assertEqual(args[1].url, data.zaak2["url"])
self.assertEqual(args[2].url, data.zaak_informatie_object2["url"])

self.assertTimelineLog(
"accepted zaakinformatieobject notification: attempt informing users ",
lookup=Lookups.startswith,
level=logging.INFO,
)

# start of generic checks

def test_zio_bails_when_bad_notification_channel(self, m, mock_handle: Mock):
Expand Down
Loading