When PX closes a suggestion that was actually implemented, ticking the checkbox sends a high-value 'Good news — your suggestion was implemented' SMS instead of the generic closed message. The flag is ignored for any status other than CLOSED. Acknowledge-on-submit SMS already existed; this completes the closed-loop value path. The checkbox appears in the status-change form in feedback_detail.html. Three tests cover: implemented flag on close, flag off on close, flag ignored when transitioning to a non-closed status.
92 lines
4.2 KiB
Python
92 lines
4.2 KiB
Python
"""Tests for the suggestion workflow realignment (optional implemented-notice SMS)."""
|
|
from unittest.mock import patch
|
|
from django.contrib.auth.models import Group
|
|
|
|
import pytest
|
|
from django.test import TestCase
|
|
from django.urls import reverse
|
|
|
|
from apps.accounts.models import User
|
|
from apps.organizations.models import Hospital
|
|
from apps.feedback.models import Feedback, FeedbackStatus, FeedbackType
|
|
|
|
|
|
def _ensure_group(name):
|
|
"""Get or create a role group (pytest runs with --nomigrations)."""
|
|
grp, _ = Group.objects.get_or_create(name=name)
|
|
return grp
|
|
|
|
|
|
@pytest.mark.django_db
|
|
class TestSuggestionImplementedNotice(TestCase):
|
|
"""Closing a suggestion with implemented_notice=True sends the high-value SMS.
|
|
|
|
Uses self.client because feedback_change_status calls messages.success/error
|
|
(needs MessageMiddleware) and redirects (302) — no template rendering.
|
|
"""
|
|
|
|
def setUp(self):
|
|
self.hospital = Hospital.objects.create(name="Test Hospital", code="TH09")
|
|
# Use PX Employee (not PX Admin) so HospitalSelectionMiddleware uses
|
|
# user.hospital directly instead of requiring session['selected_hospital_id'].
|
|
_ensure_group("PX Employee")
|
|
self.user = User.objects.create_user(
|
|
username="pxsug", email="pxsug@test", password="x", hospital=self.hospital
|
|
)
|
|
self.user.groups.add(Group.objects.get(name="PX Employee"))
|
|
self.client.force_login(self.user)
|
|
|
|
self.feedback = Feedback.objects.create(
|
|
hospital=self.hospital,
|
|
feedback_type=FeedbackType.SUGGESTION,
|
|
status=FeedbackStatus.REVIEWED,
|
|
contact_phone="+966500000000",
|
|
contact_name="Patient",
|
|
message="Add online check-in",
|
|
)
|
|
|
|
@patch("apps.feedback.views.NotificationService.send_sms")
|
|
def test_close_with_implemented_notice_sends_implemented_sms(self, mock_sms):
|
|
"""When implemented_notice=on and status=closed, SMS body mentions 'implemented'."""
|
|
response = self.client.post(
|
|
reverse("feedback:feedback_change_status", kwargs={"pk": self.feedback.pk}),
|
|
data={"status": "closed", "implemented_notice": "on"},
|
|
)
|
|
assert response.status_code == 302, f"expected redirect, got {response.status_code}"
|
|
self.feedback.refresh_from_db()
|
|
assert self.feedback.status == FeedbackStatus.CLOSED
|
|
assert mock_sms.called, "send_sms should have been called"
|
|
last_call_body = mock_sms.call_args[0][1]
|
|
assert "implemented" in last_call_body.lower(), \
|
|
f"Expected 'implemented' in SMS body, got: {last_call_body}"
|
|
|
|
@patch("apps.feedback.views.NotificationService.send_sms")
|
|
def test_close_without_implemented_notice_sends_generic_sms(self, mock_sms):
|
|
"""Without the flag, the generic closed message fires (no 'implemented')."""
|
|
response = self.client.post(
|
|
reverse("feedback:feedback_change_status", kwargs={"pk": self.feedback.pk}),
|
|
data={"status": "closed"},
|
|
)
|
|
assert response.status_code == 302
|
|
self.feedback.refresh_from_db()
|
|
assert self.feedback.status == FeedbackStatus.CLOSED
|
|
assert mock_sms.called
|
|
last_call_body = mock_sms.call_args[0][1]
|
|
assert "implemented" not in last_call_body.lower(), \
|
|
f"Did not expect 'implemented' in generic SMS, got: {last_call_body}"
|
|
|
|
@patch("apps.feedback.views.NotificationService.send_sms")
|
|
def test_implemented_notice_ignored_when_status_not_closed(self, mock_sms):
|
|
"""The flag has no effect when transitioning to a non-closed status (e.g. acknowledged)."""
|
|
response = self.client.post(
|
|
reverse("feedback:feedback_change_status", kwargs={"pk": self.feedback.pk}),
|
|
data={"status": "acknowledged", "implemented_notice": "on"},
|
|
)
|
|
assert response.status_code == 302
|
|
self.feedback.refresh_from_db()
|
|
assert self.feedback.status == FeedbackStatus.ACKNOWLEDGED
|
|
# SMS fires for acknowledged too (existing behavior), but must NOT say 'implemented'.
|
|
if mock_sms.called:
|
|
last_call_body = mock_sms.call_args[0][1]
|
|
assert "implemented" not in last_call_body.lower()
|