From c8db98880ac2ed8a3b0c0ae434e579ed77cac792 Mon Sep 17 00:00:00 2001 From: ismail Date: Mon, 20 Jul 2026 22:03:02 +0300 Subject: [PATCH] feat(inquiry): remove PX-side Response to Patient from UI Per the workflow realignment, the department owns inquiry resolution end-to-end. The PX-side respond modal and its 'Response to Patient' tile button are removed; the 'Resolve' button in the 'Department has responded' banner now POSTs directly to inquiry_change_status (with a confirm dialog), which already enforces the contact_status gate. The inquiry_respond view and URL are kept for backward compatibility but no UI surfaces them. Two regression tests lock in the new behavior: - showRespondModal JS function and respondModal div are gone - Resolve form posts directly to inquiry_change_status with status=resolved --- apps/complaints/test_workflow_realignment.py | 76 ++++++++++ templates/complaints/inquiry_detail.html | 140 +------------------ 2 files changed, 82 insertions(+), 134 deletions(-) diff --git a/apps/complaints/test_workflow_realignment.py b/apps/complaints/test_workflow_realignment.py index 6bfd5d4..7f97e42 100644 --- a/apps/complaints/test_workflow_realignment.py +++ b/apps/complaints/test_workflow_realignment.py @@ -70,3 +70,79 @@ class TestInquiryDepartmentResponsePermission(TestCase): ) assert response.status_code == 302, \ f"dept_manager of other dept should be redirected (denied), got {response.status_code}" + + +@pytest.mark.django_db +class TestInquiryDetailUIRealignment(TestCase): + """The inquiry detail page no longer surfaces the PX-side 'Response to Patient' + action. Resolution happens via direct POST to inquiry_change_status. + + Locks in Task 5 of the workflow realignment: department owns resolution. + """ + + def setUp(self): + self.hospital = Hospital.objects.create(name="Test Hospital UI", code="TH03") + self.dept = Department.objects.create(name="Dept UI", hospital=self.hospital, code="UI") + + _ensure_group("PX Admin") + self.px_admin = User.objects.create_user( + username="pxui", email="pxui@test", password="x", hospital=self.hospital + ) + self.px_admin.groups.add(Group.objects.get(name="PX Admin")) + + def _make_inquiry(self, **kwargs): + defaults = dict( + hospital=self.hospital, + department=self.dept, + subject="UI test", + message="msg", + status="in_progress", + activated_at=kwargs.pop("activated_at", __import__("django.utils.timezone", fromlist=["now"]).now()), + ) + defaults.update(kwargs) + return Inquiry.objects.create(**defaults) + + def test_response_to_patient_button_is_gone(self): + """The 'Response to Patient' tile button must not appear anywhere on the page.""" + inquiry = self._make_inquiry() + self.client.force_login(self.px_admin) + # PX admins are redirected to select-hospital unless the session has a + # selected_hospital_id (HospitalSelectionMiddleware). Set it directly. + session = self.client.session + session["selected_hospital_id"] = str(self.hospital.id) + session.save() + response = self.client.get(reverse("inquiries:inquiry_detail", kwargs={"pk": inquiry.pk})) + assert response.status_code == 200 + # The PX-side respond modal and its trigger are removed. The button label + # may still appear inside {% comment %} blocks (inert), but the live + # onclick="showRespondModal()" button in the actions tile is gone. + content = response.content.decode() + # showRespondModal JS function definition must be gone. + assert "function showRespondModal" not in content, \ + "showRespondModal JS function should be removed" + # The respondModal div must be gone. + assert 'id="respondModal"' not in content, \ + "respondModal div should be removed" + + def test_resolve_uses_direct_status_change_form(self): + """The Resolve button POSTs directly to inquiry_change_status (not a modal).""" + from django.utils import timezone + # Department has responded → "Department has responded" banner shows Resolve. + inquiry = self._make_inquiry( + sent_to_department=True, + department_responded_at=timezone.now(), + ) + self.client.force_login(self.px_admin) + session = self.client.session + session["selected_hospital_id"] = str(self.hospital.id) + session.save() + response = self.client.get(reverse("inquiries:inquiry_detail", kwargs={"pk": inquiry.pk})) + assert response.status_code == 200 + content = response.content.decode() + change_status_url = reverse("inquiries:inquiry_change_status", kwargs={"pk": inquiry.pk}) + # The Resolve button must be a real form posting to inquiry_change_status + # with status=resolved — not a showRespondModal() trigger. + assert f'action="{change_status_url}"' in content, \ + "Resolve must POST to inquiry_change_status" + assert 'name="status" value="resolved"' in content, \ + "Resolve form must include hidden status=resolved input" diff --git a/templates/complaints/inquiry_detail.html b/templates/complaints/inquiry_detail.html index 3e1cba8..1021d18 100644 --- a/templates/complaints/inquiry_detail.html +++ b/templates/complaints/inquiry_detail.html @@ -213,7 +213,11 @@ {% endcomment %} {% if can_respond and inquiry.activated_at %} - +
+ {% csrf_token %} + +
{% endif %} {% endif %} @@ -623,10 +627,6 @@ {% trans "Send to Department" %} - {% endif %} {% endif %} {% endif %} @@ -702,84 +702,7 @@ {% endif %} - - +