Skip to content

Commit

Permalink
[#2055] Add option to use different template for action required noti…
Browse files Browse the repository at this point in the history
…fications
  • Loading branch information
pi-sigma committed Feb 1, 2024
1 parent 32a04b0 commit 2fd1225
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 8 deletions.
61 changes: 61 additions & 0 deletions src/open_inwoner/conf/parts/maileditor.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,67 @@
},
],
},
"case_status_notification_action_required": {
"name": _("Case status update notification (action required)"),
"description": _(
"This email is used to notify people about a new status being set on their case "
"that requires action on their part."
),
"subject_default": "Action required",
"body_default": """
<p>Beste</p>
<p>U ontvangt deze email, omdat de status van een van uw zaken is bijgewerkt.</p>
<table>
<tr>
<th>Zaakidentificatie</th>
<td>{{ identification }}</td>
</tr>
<tr>
<th>Zaaktype</th>
<td>{{ type_description }}</td>
</tr>
<tr>
<th>Startdatum</th>
<td>{{ start_date }}</td>
</tr>
</table>
<p><a href="{{ case_link }}">Ga naar uw zaak</a> </p>
<p>Met vriendelijke groet,
{{ site_name }} </p>
""",
"subject": [
{
"name": "site_name",
"description": _("Name of the site."),
},
],
"body": [
{
"name": "identification",
"description": _("The identification of the case"),
},
{
"name": "type_description",
"description": _("The description of the type of the case"),
},
{
"name": "start_date",
"description": _("The start date of the case"),
},
{
"name": "case_link",
"description": _("The link to the case details."),
},
{
"name": "site_name",
"description": _("Name of the site"),
},
],
},
"contactform_registration": {
"name": _("Contact form registration notification"),
"description": _("This email is used to register a contact form submission"),
Expand Down
1 change: 1 addition & 0 deletions src/open_inwoner/openzaak/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ class ZaakTypeStatusTypeConfigInline(admin.StackedInline):
"status_indicator",
"status_indicator_text",
"notify_status_change",
"action_required",
"document_upload_enabled",
"document_upload_description",
"description",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Generated by Django 3.2.23 on 2024-01-30 14:23

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("openzaak", "0042_case_notification_mail_template_split"),
]

operations = [
migrations.AddField(
model_name="zaaktypestatustypeconfig",
name="action_required",
field=models.BooleanField(
default=False,
help_text="Whether the status change notification should indicate that an action is required",
verbose_name="Action required",
),
),
]
7 changes: 7 additions & 0 deletions src/open_inwoner/openzaak/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,13 @@ class ZaakTypeStatusTypeConfig(models.Model):
"Whether the user should be notfied if a case is set to this type of status"
),
)
action_required = models.BooleanField(
verbose_name=_("Action required"),
default=False,
help_text=_(
"Whether the status change notification should indicate that an action is required"
),
)
document_upload_enabled = models.BooleanField(
default=True,
verbose_name=_("Document uploads"),
Expand Down
20 changes: 17 additions & 3 deletions src/open_inwoner/openzaak/notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -418,17 +418,24 @@ def check_user_status_notitifactions(
user: User,
case: Zaak,
status: Status,
status_type_config: ZaakTypeStatusTypeConfig,
) -> bool:
"""
Check if user has an email and status notifications enabled
Check if user has an email and status notifications are enabled
The user cannot opt out of action-required-notifications
"""
if status_type_config.action_required:
return True

if not user.cases_notifications or not user.get_contact_email():
log_system_action(
f"ignored user-disabled notification delivery for user '{user}' status "
f"{status.url} case {case.url}",
log_level=logging.INFO,
)
return False

return True


Expand Down Expand Up @@ -461,7 +468,7 @@ def handle_status_notification(
status.statustype = status_type

for user in inform_users:
if not check_user_status_notitifactions(user, case, status):
if not check_user_status_notitifactions(user, case, status, status_type_config):
return

# all checks have passed
Expand All @@ -477,6 +484,7 @@ def handle_status_update(
user: User,
case: Zaak,
status: Status,
status_type_config: ZaakTypeStatusTypeConfig,
):
# hook into userfeed
hooks.case_status_notification_received(user, case, status)
Expand Down Expand Up @@ -505,7 +513,13 @@ def handle_status_update(
)
return

send_case_update_email(user, case, "case_status_notification")
# choose template
if status_type_config.action_required:
template_name = "case_status_notification_action_required"
else:
template_name = "case_status_notification"

send_case_update_email(user, case, template_name)
note.mark_sent()

log_system_action(
Expand Down
90 changes: 85 additions & 5 deletions src/open_inwoner/openzaak/tests/test_notification_zaak_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,38 @@ def test_user_status_notifications_disabled(self, m, mock_handle: Mock):

mock_handle.assert_not_called()

def test_action_required_notifications_cannot_be_disabled(
self, m, mock_handle: Mock
):
oz_config = OpenZaakConfig.get_solo()
oz_config.skip_notification_statustype_informeren = True
oz_config.save()

data = MockAPIData()
data.zaak_type["catalogus"] = None
data.install_mocks(m)

user = data.user_initiator
user.cases_notifications = False # opt-out
user.save()

ztc = ZaakTypeConfigFactory.create(
catalogus=None,
identificatie=data.zaak_type["identificatie"],
notify_status_changes=True,
)
ZaakTypeStatusTypeConfigFactory.create(
zaaktype_config=ztc,
omschrijving=data.status_type_final["omschrijving"],
statustype_url=data.status_type_final["url"],
notify_status_change=True,
action_required=True, # these cannot be disabled by the user
)

handle_zaken_notification(data.status_notification)

mock_handle.assert_called_once()

def test_user_bad_email(self, m, mock_handle: Mock):
oz_config = OpenZaakConfig.get_solo()
oz_config.skip_notification_statustype_informeren = True
Expand Down Expand Up @@ -540,8 +572,21 @@ def test_handle_status_update(self, mock_send: Mock, mock_feed_hook: Mock):
status = factory(Status, data.status_final)
status.statustype = factory(StatusType, data.status_type_final)

ztc = ZaakTypeConfigFactory.create(
catalogus=None,
identificatie=data.zaak_type["identificatie"],
# set this to notify
notify_status_changes=True,
)
status_type_config = ZaakTypeStatusTypeConfigFactory.create(
zaaktype_config=ztc,
omschrijving=data.status_type_final["omschrijving"],
statustype_url=data.status_type_final["url"],
notify_status_change=True,
)

# first call
handle_status_update(user, case, status)
handle_status_update(user, case, status, status_type_config)

mock_send.assert_called_once()

Expand All @@ -566,7 +611,7 @@ def test_handle_status_update(self, mock_send: Mock, mock_feed_hook: Mock):
)

# second call with same case/status
handle_status_update(user, case, status)
handle_status_update(user, case, status, status_type_config)

# no duplicate mail for this user/case/status
mock_send.assert_not_called()
Expand All @@ -578,7 +623,7 @@ def test_handle_status_update(self, mock_send: Mock, mock_feed_hook: Mock):
)
# other user is fine
other_user = UserFactory.create()
handle_status_update(other_user, case, status)
handle_status_update(other_user, case, status, status_type_config)

mock_send.assert_called_once()

Expand All @@ -594,7 +639,7 @@ def test_handle_status_update(self, mock_send: Mock, mock_feed_hook: Mock):
status.statustype = factory(
StatusType, copy_with_new_uuid(data.status_type_final)
)
handle_status_update(user, case, status)
handle_status_update(user, case, status, status_type_config)

# not sent because we already send to this user within the frequency
mock_send.assert_not_called()
Expand All @@ -611,7 +656,42 @@ def test_handle_status_update(self, mock_send: Mock, mock_feed_hook: Mock):
status.statustype = factory(
StatusType, copy_with_new_uuid(data.status_type_final)
)
handle_status_update(user, case, status)
handle_status_update(user, case, status, status_type_config)

# this one succeeds
mock_send.assert_called_once()

@patch("open_inwoner.userfeed.hooks.case_status_notification_received")
@patch("open_inwoner.openzaak.notifications.send_case_update_email")
def test_action_required_template(self, mock_send: Mock, mock_feed_hook: Mock):
data = MockAPIData()
user = data.user_initiator

case = factory(Zaak, data.zaak)
case.zaaktype = factory(ZaakType, data.zaak_type)

status = factory(Status, data.status_final)
status.statustype = factory(StatusType, data.status_type_final)

ztc = ZaakTypeConfigFactory.create(
catalogus=None,
identificatie=data.zaak_type["identificatie"],
# set this to notify
notify_status_changes=True,
)
status_type_config = ZaakTypeStatusTypeConfigFactory.create(
zaaktype_config=ztc,
omschrijving=data.status_type_final["omschrijving"],
statustype_url=data.status_type_final["url"],
notify_status_change=True,
action_required=True,
)

handle_status_update(user, case, status, status_type_config)

mock_send.assert_called_once()
# check call arguments
args = mock_send.call_args.args
self.assertEqual(args[0], user)
self.assertEqual(args[1].url, case.url)
self.assertEqual(args[2], "case_status_notification_action_required")

0 comments on commit 2fd1225

Please sign in to comment.