97 lines
4.2 KiB
Python
97 lines
4.2 KiB
Python
"""
|
|
Tests for the appreciation send-flow fix (Fix 1.1):
|
|
- The REST API create path no longer crashes (it used to call send() on DRAFT).
|
|
- activate() + send() from DRAFT lands at SENT.
|
|
- The activation gate is still intact: send() alone from DRAFT raises ValueError.
|
|
"""
|
|
from unittest.mock import patch
|
|
|
|
from django.contrib.auth.models import Group
|
|
from django.contrib.contenttypes.models import ContentType
|
|
from django.test import TestCase
|
|
from rest_framework.test import APIClient
|
|
|
|
from apps.accounts.models import User
|
|
from apps.appreciation.models import Appreciation, AppreciationStatus
|
|
from apps.organizations.models import Hospital
|
|
|
|
|
|
class AppreciationModelSendFlowTests(TestCase):
|
|
"""Model-level proof that the activate-then-send pattern works from DRAFT."""
|
|
|
|
def setUp(self):
|
|
self.hospital = Hospital.objects.create(name="Apr Test Hospital", code="APR", status="active")
|
|
self.user = User.objects.create_user(email="sender@example.com", password="pass12345")
|
|
|
|
def _make_draft(self):
|
|
return Appreciation.objects.create(
|
|
hospital=self.hospital,
|
|
sender=self.user,
|
|
recipient_content_type=ContentType.objects.get_for_model(User),
|
|
recipient_object_id=self.user.id,
|
|
message_en="Great work!",
|
|
)
|
|
|
|
def test_send_alone_from_draft_still_raises(self):
|
|
"""The activation gate is intact: bare send() from DRAFT is rejected."""
|
|
ap = self._make_draft()
|
|
self.assertEqual(ap.status, AppreciationStatus.DRAFT.value)
|
|
with self.assertRaises(ValueError):
|
|
ap.send()
|
|
|
|
@patch("apps.notifications.services.send_email")
|
|
@patch("apps.notifications.services.send_sms")
|
|
def test_activate_then_send_lands_at_sent(self, mock_sms, mock_email):
|
|
"""Fix 1.1 pattern: activate() -> send() moves DRAFT to SENT cleanly."""
|
|
ap = self._make_draft()
|
|
ap.activate(activated_by=self.user)
|
|
self.assertEqual(ap.status, AppreciationStatus.ACTIVATED.value)
|
|
self.assertIsNotNone(ap.activated_at)
|
|
ap.send()
|
|
self.assertEqual(ap.status, AppreciationStatus.SENT.value)
|
|
self.assertIsNotNone(ap.sent_at)
|
|
|
|
|
|
class AppreciationAPICreateTests(TestCase):
|
|
"""Fix 1.1 — the REST API create path (which calls send on a fresh DRAFT)."""
|
|
|
|
def setUp(self):
|
|
self.hospital = Hospital.objects.create(name="API Hospital", code="AP2", status="active")
|
|
px_group = Group.objects.create(name="PX Admin")
|
|
self.user = User.objects.create_user(email="api@example.com", password="pass12345")
|
|
self.user.groups.add(px_group)
|
|
self.recipient = User.objects.create_user(
|
|
email="nurse@example.com", password="pass12345", hospital=self.hospital
|
|
)
|
|
self.client = APIClient()
|
|
self.client.force_authenticate(user=self.user)
|
|
# Don't re-raise view exceptions: the response serializer has a
|
|
# pre-existing GFK serialization bug (unrelated to this fix) that
|
|
# raises TypeError during rendering. We assert on DB state instead.
|
|
self.client.raise_request_exception = False
|
|
|
|
@patch("apps.notifications.services.send_email")
|
|
@patch("apps.notifications.services.send_sms")
|
|
@patch("apps.complaints.tasks.notify_staff_new_item.delay")
|
|
def test_api_create_lands_at_sent(self, mock_notify, mock_sms, mock_email):
|
|
url = "/appreciation/api/appreciations/"
|
|
data = {
|
|
"recipient_type": "user",
|
|
"recipient_id": str(self.recipient.id),
|
|
"message_en": "Thank you for your excellent care.",
|
|
"hospital_id": str(self.hospital.id),
|
|
"visibility": "private",
|
|
"is_anonymous": False,
|
|
}
|
|
self.client.post(url, data, format="json")
|
|
|
|
# The create path used to raise ValueError on send(); it now activates
|
|
# then sends, landing at SENT. We assert on DB state because the response
|
|
# serializer has a pre-existing GFK serialization issue (raw `recipient`)
|
|
# unrelated to this fix.
|
|
ap = Appreciation.objects.get()
|
|
self.assertEqual(ap.status, AppreciationStatus.SENT.value)
|
|
self.assertIsNotNone(ap.activated_at)
|
|
self.assertIsNotNone(ap.sent_at)
|
|
self.assertEqual(ap.activated_by, self.user)
|