diff --git a/manage_breast_screening/mammograms/forms/appointment_note_form.py b/manage_breast_screening/mammograms/forms/appointment_note_form.py
index a63da9018..fe7e7733f 100644
--- a/manage_breast_screening/mammograms/forms/appointment_note_form.py
+++ b/manage_breast_screening/mammograms/forms/appointment_note_form.py
@@ -27,3 +27,7 @@ def save(self):
self.instance.content = self.cleaned_data["content"]
self.instance.save()
return self.instance
+
+ @property
+ def instance_is_saved(self):
+ return self.instance and not self.instance._state.adding
diff --git a/manage_breast_screening/mammograms/jinja2/mammograms/show/appointment_note.jinja b/manage_breast_screening/mammograms/jinja2/mammograms/show/appointment_note.jinja
index 6e90d1475..5c027ad32 100644
--- a/manage_breast_screening/mammograms/jinja2/mammograms/show/appointment_note.jinja
+++ b/manage_breast_screening/mammograms/jinja2/mammograms/show/appointment_note.jinja
@@ -77,8 +77,16 @@
{{ button({
"text": "Save note"
}) }}
+ {% if form.instance_is_saved %}
+
+
+ Delete appointment note
+
+
+ {% endif %}
+
{% endblock %}
diff --git a/manage_breast_screening/mammograms/tests/views/test_appointment_note_views.py b/manage_breast_screening/mammograms/tests/views/test_appointment_note_views.py
new file mode 100644
index 000000000..275d2bf54
--- /dev/null
+++ b/manage_breast_screening/mammograms/tests/views/test_appointment_note_views.py
@@ -0,0 +1,120 @@
+import pytest
+from django.urls import reverse
+from pytest_django.asserts import assertRedirects
+
+from manage_breast_screening.participants.models import AppointmentNote
+from manage_breast_screening.participants.tests.factories import AppointmentFactory
+
+
+@pytest.mark.django_db
+class TestAppointmentNoteView:
+ def test_delete_link_not_shown_when_note_does_not_exist(self, clinical_user_client):
+ appointment = AppointmentFactory.create(
+ clinic_slot__clinic__setting__provider=clinical_user_client.current_provider
+ )
+ response = clinical_user_client.http.get(
+ reverse(
+ "mammograms:appointment_note",
+ kwargs={"pk": appointment.pk},
+ )
+ )
+ assert response.status_code == 200
+ assert "Delete appointment note" not in response.content.decode()
+
+ def test_delete_link_shown_when_note_exists(self, clinical_user_client):
+ appointment = AppointmentFactory.create(
+ clinic_slot__clinic__setting__provider=clinical_user_client.current_provider
+ )
+ AppointmentNote.objects.create(appointment=appointment, content="Existing note")
+ response = clinical_user_client.http.get(
+ reverse(
+ "mammograms:appointment_note",
+ kwargs={"pk": appointment.pk},
+ )
+ )
+ assert response.status_code == 200
+ assert "Delete appointment note" in response.content.decode()
+
+ @pytest.mark.parametrize(
+ "client_fixture", ["clinical_user_client", "administrative_user_client"]
+ )
+ def test_users_can_save_note(self, request, client_fixture):
+ client = request.getfixturevalue(client_fixture)
+ appointment = AppointmentFactory.create(
+ clinic_slot__clinic__setting__provider=client.current_provider
+ )
+
+ note_content = "Participant prefers left arm blood pressure readings."
+ response = client.http.post(
+ reverse(
+ "mammograms:appointment_note",
+ kwargs={"pk": appointment.pk},
+ ),
+ {"content": note_content},
+ )
+
+ assertRedirects(
+ response,
+ reverse("mammograms:appointment_note", kwargs={"pk": appointment.pk}),
+ )
+ saved_note = AppointmentNote.objects.get(appointment=appointment)
+ assert saved_note.content == note_content
+
+ @pytest.mark.parametrize(
+ "client_fixture", ["clinical_user_client", "administrative_user_client"]
+ )
+ def test_users_can_update_note(self, request, client_fixture):
+ client = request.getfixturevalue(client_fixture)
+ appointment = AppointmentFactory.create(
+ clinic_slot__clinic__setting__provider=client.current_provider
+ )
+ note = AppointmentNote.objects.create(
+ appointment=appointment, content="Original note"
+ )
+
+ updated_content = "Updated note content"
+ response = client.http.post(
+ reverse("mammograms:appointment_note", kwargs={"pk": appointment.pk}),
+ {"content": updated_content},
+ )
+
+ assertRedirects(
+ response,
+ reverse("mammograms:appointment_note", kwargs={"pk": appointment.pk}),
+ )
+ updated_note = AppointmentNote.objects.get(pk=note.pk)
+ assert updated_note.content == updated_content
+ assert AppointmentNote.objects.count() == 1
+
+
+@pytest.mark.django_db
+class TestDeleteAppointmentNoteView:
+ def test_get_redirects_when_note_does_not_exist(self, clinical_user_client):
+ appointment = AppointmentFactory.create(
+ clinic_slot__clinic__setting__provider=clinical_user_client.current_provider
+ )
+ response = clinical_user_client.http.get(
+ reverse(
+ "mammograms:delete_appointment_note",
+ kwargs={"pk": appointment.pk},
+ )
+ )
+ assertRedirects(
+ response,
+ reverse("mammograms:appointment_note", kwargs={"pk": appointment.pk}),
+ )
+
+ def test_post_redirects_when_note_does_not_exist(self, clinical_user_client):
+ appointment = AppointmentFactory.create(
+ clinic_slot__clinic__setting__provider=clinical_user_client.current_provider
+ )
+ response = clinical_user_client.http.post(
+ reverse(
+ "mammograms:delete_appointment_note",
+ kwargs={"pk": appointment.pk},
+ )
+ )
+ assertRedirects(
+ response,
+ reverse("mammograms:appointment_note", kwargs={"pk": appointment.pk}),
+ )
diff --git a/manage_breast_screening/mammograms/tests/views/test_appointment_views.py b/manage_breast_screening/mammograms/tests/views/test_appointment_views.py
index 903705593..a3532b6ac 100644
--- a/manage_breast_screening/mammograms/tests/views/test_appointment_views.py
+++ b/manage_breast_screening/mammograms/tests/views/test_appointment_views.py
@@ -3,7 +3,6 @@
from pytest_django.asserts import assertContains, assertRedirects
from manage_breast_screening.core.models import AuditLog
-from manage_breast_screening.participants.models import AppointmentNote
from manage_breast_screening.participants.tests.factories import AppointmentFactory
@@ -22,60 +21,6 @@ def test_renders_response(self, clinical_user_client):
assert response.status_code == 200
-@pytest.mark.django_db
-class TestAppointmentNoteView:
- @pytest.mark.parametrize(
- "client_fixture", ["clinical_user_client", "administrative_user_client"]
- )
- def test_users_can_save_note(self, request, client_fixture):
- client = request.getfixturevalue(client_fixture)
- appointment = AppointmentFactory.create(
- clinic_slot__clinic__setting__provider=client.current_provider
- )
-
- note_content = "Participant prefers left arm blood pressure readings."
- response = client.http.post(
- reverse(
- "mammograms:appointment_note",
- kwargs={"pk": appointment.pk},
- ),
- {"content": note_content},
- )
-
- assertRedirects(
- response,
- reverse("mammograms:appointment_note", kwargs={"pk": appointment.pk}),
- )
- saved_note = AppointmentNote.objects.get(appointment=appointment)
- assert saved_note.content == note_content
-
- @pytest.mark.parametrize(
- "client_fixture", ["clinical_user_client", "administrative_user_client"]
- )
- def test_users_can_update_note(self, request, client_fixture):
- client = request.getfixturevalue(client_fixture)
- appointment = AppointmentFactory.create(
- clinic_slot__clinic__setting__provider=client.current_provider
- )
- note = AppointmentNote.objects.create(
- appointment=appointment, content="Original note"
- )
-
- updated_content = "Updated note content"
- response = client.http.post(
- reverse("mammograms:appointment_note", kwargs={"pk": appointment.pk}),
- {"content": updated_content},
- )
-
- assertRedirects(
- response,
- reverse("mammograms:appointment_note", kwargs={"pk": appointment.pk}),
- )
- updated_note = AppointmentNote.objects.get(pk=note.pk)
- assert updated_note.content == updated_content
- assert AppointmentNote.objects.count() == 1
-
-
@pytest.mark.django_db
class TestConfirmIdentity:
def test_renders_response(self, clinical_user_client):
diff --git a/manage_breast_screening/mammograms/urls.py b/manage_breast_screening/mammograms/urls.py
index cfee41fea..4a7178ee7 100644
--- a/manage_breast_screening/mammograms/urls.py
+++ b/manage_breast_screening/mammograms/urls.py
@@ -1,6 +1,11 @@
from django.urls import path
-from .views import appointment_views, special_appointment_views, symptom_views
+from .views import (
+ appointment_note_views,
+ appointment_views,
+ special_appointment_views,
+ symptom_views,
+)
from .views.medical_history import (
benign_lump_history_item_views,
breast_augmentation_history_item_views,
@@ -36,9 +41,14 @@
),
path(
"/note/",
- appointment_views.AppointmentNoteView.as_view(),
+ appointment_note_views.AppointmentNoteView.as_view(),
name="appointment_note",
),
+ path(
+ "/note/delete/",
+ appointment_note_views.DeleteAppointmentNoteView.as_view(),
+ name="delete_appointment_note",
+ ),
path(
"/confirm-identity/",
appointment_views.ConfirmIdentity.as_view(),
diff --git a/manage_breast_screening/mammograms/views/appointment_note_views.py b/manage_breast_screening/mammograms/views/appointment_note_views.py
new file mode 100644
index 000000000..6a51bee48
--- /dev/null
+++ b/manage_breast_screening/mammograms/views/appointment_note_views.py
@@ -0,0 +1,92 @@
+import logging
+
+from django.contrib import messages
+from django.shortcuts import redirect
+from django.urls import reverse
+from django.views.generic import FormView
+
+from manage_breast_screening.core.services.auditor import Auditor
+from manage_breast_screening.core.views.generic import DeleteWithAuditView
+from manage_breast_screening.participants.models import AppointmentNote
+
+from ..forms import AppointmentNoteForm
+from ..presenters import AppointmentPresenter, present_secondary_nav
+from .mixins import AppointmentMixin
+
+logger = logging.getLogger(__name__)
+
+
+class AppointmentNoteView(AppointmentMixin, FormView):
+ template_name = "mammograms/show/appointment_note.jinja"
+ form_class = AppointmentNoteForm
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ appointment = self.appointment
+ appointment_presenter = AppointmentPresenter(
+ appointment, tab_description="Note"
+ )
+
+ context.update(
+ {
+ "heading": appointment_presenter.participant.full_name,
+ "caption": appointment_presenter.caption,
+ "page_title": appointment_presenter.page_title,
+ "presented_appointment": appointment_presenter,
+ "secondary_nav_items": present_secondary_nav(
+ appointment.pk, current_tab="note"
+ ),
+ }
+ )
+ return context
+
+ def get_form_kwargs(self):
+ kwargs = super().get_form_kwargs()
+ try:
+ kwargs["instance"] = self.appointment.note
+ except AppointmentNote.DoesNotExist:
+ kwargs["instance"] = AppointmentNote(appointment=self.appointment)
+ return kwargs
+
+ def form_valid(self, form):
+ is_new_note = form.instance._state.adding
+ note = form.save()
+ auditor = Auditor.from_request(self.request)
+ if is_new_note:
+ auditor.audit_create(note)
+ else:
+ auditor.audit_update(note)
+ messages.add_message(
+ self.request,
+ messages.SUCCESS,
+ "Appointment note saved",
+ )
+ return redirect("mammograms:appointment_note", pk=self.appointment.pk)
+
+
+class DeleteAppointmentNoteView(DeleteWithAuditView):
+ def get_thing_name(self, object):
+ return "appointment note"
+
+ def get_success_message_content(self, object):
+ return "Appointment note deleted"
+
+ def get_object(self):
+ provider = self.request.user.current_provider
+ appointment = provider.appointments.get(pk=self.kwargs["pk"])
+ return appointment.note
+
+ def get_success_url(self):
+ return reverse("mammograms:appointment_note", kwargs={"pk": self.kwargs["pk"]})
+
+ def get(self, request, *args, **kwargs):
+ try:
+ return super().get(request, *args, **kwargs)
+ except AppointmentNote.DoesNotExist:
+ return redirect(self.get_success_url())
+
+ def post(self, request, *args, **kwargs):
+ try:
+ return super().post(request, *args, **kwargs)
+ except AppointmentNote.DoesNotExist:
+ return redirect(self.get_success_url())
diff --git a/manage_breast_screening/mammograms/views/appointment_views.py b/manage_breast_screening/mammograms/views/appointment_views.py
index 5e428261c..2a56f663e 100644
--- a/manage_breast_screening/mammograms/views/appointment_views.py
+++ b/manage_breast_screening/mammograms/views/appointment_views.py
@@ -1,6 +1,5 @@
import logging
-from django.contrib import messages
from django.http import Http404
from django.shortcuts import redirect, render
from django.urls import reverse, reverse_lazy
@@ -14,14 +13,12 @@
)
from manage_breast_screening.participants.models import (
Appointment,
- AppointmentNote,
ParticipantReportedMammogram,
)
from manage_breast_screening.participants.presenters import ParticipantPresenter
from ..forms import (
AppointmentCannotGoAheadForm,
- AppointmentNoteForm,
AskForMedicalInformationForm,
RecordMedicalInformationForm,
)
@@ -116,54 +113,6 @@ def get(self, request, *args, **kwargs):
)
-class AppointmentNoteView(AppointmentMixin, FormView):
- template_name = "mammograms/show/appointment_note.jinja"
- form_class = AppointmentNoteForm
-
- def get_context_data(self, **kwargs):
- context = super().get_context_data(**kwargs)
- appointment = self.appointment
- appointment_presenter = AppointmentPresenter(
- appointment, tab_description="Note"
- )
-
- context.update(
- {
- "heading": appointment_presenter.participant.full_name,
- "caption": appointment_presenter.caption,
- "page_title": appointment_presenter.page_title,
- "presented_appointment": appointment_presenter,
- "secondary_nav_items": present_secondary_nav(
- appointment.pk, current_tab="note"
- ),
- }
- )
- return context
-
- def get_form_kwargs(self):
- kwargs = super().get_form_kwargs()
- try:
- kwargs["instance"] = self.appointment.note
- except AppointmentNote.DoesNotExist:
- kwargs["instance"] = AppointmentNote(appointment=self.appointment)
- return kwargs
-
- def form_valid(self, form):
- is_new_note = form.instance._state.adding
- note = form.save()
- auditor = Auditor.from_request(self.request)
- if is_new_note:
- auditor.audit_create(note)
- else:
- auditor.audit_update(note)
- messages.add_message(
- self.request,
- messages.SUCCESS,
- "Appointment note saved",
- )
- return redirect("mammograms:appointment_note", pk=self.appointment.pk)
-
-
class ConfirmIdentity(InProgressAppointmentMixin, TemplateView):
template_name = "mammograms/confirm_identity.jinja"
diff --git a/manage_breast_screening/tests/system/clinical/test_appointment_note.py b/manage_breast_screening/tests/system/clinical/test_appointment_note.py
index 11f8e8a22..706db510d 100644
--- a/manage_breast_screening/tests/system/clinical/test_appointment_note.py
+++ b/manage_breast_screening/tests/system/clinical/test_appointment_note.py
@@ -21,15 +21,24 @@ def test_clinical_user_adds_and_updates_an_appointment_note(self):
self.when_i_enter_a_note()
self.and_i_save_the_note()
self.then_i_see_a_message_confirming_the_save()
- self.then_the_note_field_contains(self.initial_note_text)
+ self.and_the_note_field_contains(self.initial_note_text)
self.and_the_appointment_details_tab_shows_the_note(self.initial_note_text)
self.when_i_update_the_note()
self.and_i_save_the_note()
self.then_i_see_a_message_confirming_the_save()
- self.then_the_note_field_contains(self.updated_note_text)
+ self.and_the_note_field_contains(self.updated_note_text)
self.and_the_appointment_details_tab_shows_the_note(self.updated_note_text)
+ self.when_i_click_the_note_change_link()
+ self.and_i_click_delete_note()
+ self.and_i_click_cancel()
+ self.then_the_note_is_not_deleted()
+
+ self.when_i_click_delete_note()
+ self.and_i_confirm_deletion()
+ self.then_the_note_is_deleted()
+
def and_there_is_an_appointment_for_my_provider(self):
self.appointment = AppointmentFactory(
clinic_slot__clinic__setting__provider=self.current_provider
@@ -67,7 +76,7 @@ def and_i_save_the_note(self):
def when_i_save_the_note(self):
self.and_i_save_the_note()
- def then_the_note_field_contains(self, text):
+ def and_the_note_field_contains(self, text):
expect(self.page.get_by_label("Note")).to_have_value(text)
def then_i_see_a_message_confirming_the_save(self):
@@ -86,3 +95,38 @@ def and_the_appointment_details_tab_shows_the_note(self, text):
)
expect(note_container).to_be_visible()
expect(note_container).to_contain_text(text)
+
+ def when_i_click_the_note_change_link(self):
+ note_container = self.page.locator(
+ ".nhsuk-warning-callout", has_text="Appointment note"
+ )
+ expect(note_container).to_be_visible()
+ change_link = note_container.get_by_role("link", name="Change")
+ change_link.click()
+
+ def and_i_click_delete_note(self):
+ delete_link = self.page.get_by_role("link", name="Delete appointment note")
+ expect(delete_link).to_be_visible()
+ delete_link.click()
+
+ def when_i_click_delete_note(self):
+ self.and_i_click_delete_note()
+
+ def and_i_click_cancel(self):
+ cancel_link = self.page.get_by_role("link", name="Cancel")
+ expect(cancel_link).to_be_visible()
+ cancel_link.click()
+
+ def then_the_note_is_not_deleted(self):
+ expect(self.page.get_by_label("Note")).to_have_value(self.updated_note_text)
+
+ def and_i_confirm_deletion(self):
+ delete_button = self.page.get_by_role("button", name="Delete appointment note")
+ expect(delete_button).to_be_visible()
+ delete_button.click()
+
+ def then_the_note_is_deleted(self):
+ banner = self.page.locator(".nhsuk-notification-banner--success")
+ expect(banner).to_be_visible()
+ expect(banner).to_contain_text("Appointment note deleted")
+ expect(self.page.get_by_label("Note")).to_have_value("")