Skip to content

Commit 8710e0e

Browse files
authored
Merge pull request #823 from NHSDigital/11725-delete-note
Add link to delete appointment notes
2 parents 991ecd2 + 1810cb9 commit 8710e0e

File tree

8 files changed

+283
-111
lines changed

8 files changed

+283
-111
lines changed

manage_breast_screening/mammograms/forms/appointment_note_form.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,7 @@ def save(self):
2727
self.instance.content = self.cleaned_data["content"]
2828
self.instance.save()
2929
return self.instance
30+
31+
@property
32+
def instance_is_saved(self):
33+
return self.instance and not self.instance._state.adding

manage_breast_screening/mammograms/jinja2/mammograms/show/appointment_note.jinja

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,16 @@
7777
{{ button({
7878
"text": "Save note"
7979
}) }}
80+
{% if form.instance_is_saved %}
81+
<p>
82+
<a href="{{ url('mammograms:delete_appointment_note', kwargs={'pk': presented_appointment.pk}) }}" class="nhsuk-link app-link--warning">
83+
Delete appointment note
84+
</a>
85+
</p>
86+
{% endif %}
8087
</div>
8188
</form>
89+
8290
</div>
8391
</div>
8492
{% endblock %}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import pytest
2+
from django.urls import reverse
3+
from pytest_django.asserts import assertRedirects
4+
5+
from manage_breast_screening.participants.models import AppointmentNote
6+
from manage_breast_screening.participants.tests.factories import AppointmentFactory
7+
8+
9+
@pytest.mark.django_db
10+
class TestAppointmentNoteView:
11+
def test_delete_link_not_shown_when_note_does_not_exist(self, clinical_user_client):
12+
appointment = AppointmentFactory.create(
13+
clinic_slot__clinic__setting__provider=clinical_user_client.current_provider
14+
)
15+
response = clinical_user_client.http.get(
16+
reverse(
17+
"mammograms:appointment_note",
18+
kwargs={"pk": appointment.pk},
19+
)
20+
)
21+
assert response.status_code == 200
22+
assert "Delete appointment note" not in response.content.decode()
23+
24+
def test_delete_link_shown_when_note_exists(self, clinical_user_client):
25+
appointment = AppointmentFactory.create(
26+
clinic_slot__clinic__setting__provider=clinical_user_client.current_provider
27+
)
28+
AppointmentNote.objects.create(appointment=appointment, content="Existing note")
29+
response = clinical_user_client.http.get(
30+
reverse(
31+
"mammograms:appointment_note",
32+
kwargs={"pk": appointment.pk},
33+
)
34+
)
35+
assert response.status_code == 200
36+
assert "Delete appointment note" in response.content.decode()
37+
38+
@pytest.mark.parametrize(
39+
"client_fixture", ["clinical_user_client", "administrative_user_client"]
40+
)
41+
def test_users_can_save_note(self, request, client_fixture):
42+
client = request.getfixturevalue(client_fixture)
43+
appointment = AppointmentFactory.create(
44+
clinic_slot__clinic__setting__provider=client.current_provider
45+
)
46+
47+
note_content = "Participant prefers left arm blood pressure readings."
48+
response = client.http.post(
49+
reverse(
50+
"mammograms:appointment_note",
51+
kwargs={"pk": appointment.pk},
52+
),
53+
{"content": note_content},
54+
)
55+
56+
assertRedirects(
57+
response,
58+
reverse("mammograms:appointment_note", kwargs={"pk": appointment.pk}),
59+
)
60+
saved_note = AppointmentNote.objects.get(appointment=appointment)
61+
assert saved_note.content == note_content
62+
63+
@pytest.mark.parametrize(
64+
"client_fixture", ["clinical_user_client", "administrative_user_client"]
65+
)
66+
def test_users_can_update_note(self, request, client_fixture):
67+
client = request.getfixturevalue(client_fixture)
68+
appointment = AppointmentFactory.create(
69+
clinic_slot__clinic__setting__provider=client.current_provider
70+
)
71+
note = AppointmentNote.objects.create(
72+
appointment=appointment, content="Original note"
73+
)
74+
75+
updated_content = "Updated note content"
76+
response = client.http.post(
77+
reverse("mammograms:appointment_note", kwargs={"pk": appointment.pk}),
78+
{"content": updated_content},
79+
)
80+
81+
assertRedirects(
82+
response,
83+
reverse("mammograms:appointment_note", kwargs={"pk": appointment.pk}),
84+
)
85+
updated_note = AppointmentNote.objects.get(pk=note.pk)
86+
assert updated_note.content == updated_content
87+
assert AppointmentNote.objects.count() == 1
88+
89+
90+
@pytest.mark.django_db
91+
class TestDeleteAppointmentNoteView:
92+
def test_get_redirects_when_note_does_not_exist(self, clinical_user_client):
93+
appointment = AppointmentFactory.create(
94+
clinic_slot__clinic__setting__provider=clinical_user_client.current_provider
95+
)
96+
response = clinical_user_client.http.get(
97+
reverse(
98+
"mammograms:delete_appointment_note",
99+
kwargs={"pk": appointment.pk},
100+
)
101+
)
102+
assertRedirects(
103+
response,
104+
reverse("mammograms:appointment_note", kwargs={"pk": appointment.pk}),
105+
)
106+
107+
def test_post_redirects_when_note_does_not_exist(self, clinical_user_client):
108+
appointment = AppointmentFactory.create(
109+
clinic_slot__clinic__setting__provider=clinical_user_client.current_provider
110+
)
111+
response = clinical_user_client.http.post(
112+
reverse(
113+
"mammograms:delete_appointment_note",
114+
kwargs={"pk": appointment.pk},
115+
)
116+
)
117+
assertRedirects(
118+
response,
119+
reverse("mammograms:appointment_note", kwargs={"pk": appointment.pk}),
120+
)

manage_breast_screening/mammograms/tests/views/test_appointment_views.py

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
from pytest_django.asserts import assertContains, assertRedirects
44

55
from manage_breast_screening.core.models import AuditLog
6-
from manage_breast_screening.participants.models import AppointmentNote
76
from manage_breast_screening.participants.tests.factories import AppointmentFactory
87

98

@@ -22,60 +21,6 @@ def test_renders_response(self, clinical_user_client):
2221
assert response.status_code == 200
2322

2423

25-
@pytest.mark.django_db
26-
class TestAppointmentNoteView:
27-
@pytest.mark.parametrize(
28-
"client_fixture", ["clinical_user_client", "administrative_user_client"]
29-
)
30-
def test_users_can_save_note(self, request, client_fixture):
31-
client = request.getfixturevalue(client_fixture)
32-
appointment = AppointmentFactory.create(
33-
clinic_slot__clinic__setting__provider=client.current_provider
34-
)
35-
36-
note_content = "Participant prefers left arm blood pressure readings."
37-
response = client.http.post(
38-
reverse(
39-
"mammograms:appointment_note",
40-
kwargs={"pk": appointment.pk},
41-
),
42-
{"content": note_content},
43-
)
44-
45-
assertRedirects(
46-
response,
47-
reverse("mammograms:appointment_note", kwargs={"pk": appointment.pk}),
48-
)
49-
saved_note = AppointmentNote.objects.get(appointment=appointment)
50-
assert saved_note.content == note_content
51-
52-
@pytest.mark.parametrize(
53-
"client_fixture", ["clinical_user_client", "administrative_user_client"]
54-
)
55-
def test_users_can_update_note(self, request, client_fixture):
56-
client = request.getfixturevalue(client_fixture)
57-
appointment = AppointmentFactory.create(
58-
clinic_slot__clinic__setting__provider=client.current_provider
59-
)
60-
note = AppointmentNote.objects.create(
61-
appointment=appointment, content="Original note"
62-
)
63-
64-
updated_content = "Updated note content"
65-
response = client.http.post(
66-
reverse("mammograms:appointment_note", kwargs={"pk": appointment.pk}),
67-
{"content": updated_content},
68-
)
69-
70-
assertRedirects(
71-
response,
72-
reverse("mammograms:appointment_note", kwargs={"pk": appointment.pk}),
73-
)
74-
updated_note = AppointmentNote.objects.get(pk=note.pk)
75-
assert updated_note.content == updated_content
76-
assert AppointmentNote.objects.count() == 1
77-
78-
7924
@pytest.mark.django_db
8025
class TestConfirmIdentity:
8126
def test_renders_response(self, clinical_user_client):

manage_breast_screening/mammograms/urls.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
from django.urls import path
22

3-
from .views import appointment_views, special_appointment_views, symptom_views
3+
from .views import (
4+
appointment_note_views,
5+
appointment_views,
6+
special_appointment_views,
7+
symptom_views,
8+
)
49
from .views.medical_history import (
510
benign_lump_history_item_views,
611
breast_augmentation_history_item_views,
@@ -36,9 +41,14 @@
3641
),
3742
path(
3843
"<uuid:pk>/note/",
39-
appointment_views.AppointmentNoteView.as_view(),
44+
appointment_note_views.AppointmentNoteView.as_view(),
4045
name="appointment_note",
4146
),
47+
path(
48+
"<uuid:pk>/note/delete/",
49+
appointment_note_views.DeleteAppointmentNoteView.as_view(),
50+
name="delete_appointment_note",
51+
),
4252
path(
4353
"<uuid:pk>/confirm-identity/",
4454
appointment_views.ConfirmIdentity.as_view(),
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import logging
2+
3+
from django.contrib import messages
4+
from django.shortcuts import redirect
5+
from django.urls import reverse
6+
from django.views.generic import FormView
7+
8+
from manage_breast_screening.core.services.auditor import Auditor
9+
from manage_breast_screening.core.views.generic import DeleteWithAuditView
10+
from manage_breast_screening.participants.models import AppointmentNote
11+
12+
from ..forms import AppointmentNoteForm
13+
from ..presenters import AppointmentPresenter, present_secondary_nav
14+
from .mixins import AppointmentMixin
15+
16+
logger = logging.getLogger(__name__)
17+
18+
19+
class AppointmentNoteView(AppointmentMixin, FormView):
20+
template_name = "mammograms/show/appointment_note.jinja"
21+
form_class = AppointmentNoteForm
22+
23+
def get_context_data(self, **kwargs):
24+
context = super().get_context_data(**kwargs)
25+
appointment = self.appointment
26+
appointment_presenter = AppointmentPresenter(
27+
appointment, tab_description="Note"
28+
)
29+
30+
context.update(
31+
{
32+
"heading": appointment_presenter.participant.full_name,
33+
"caption": appointment_presenter.caption,
34+
"page_title": appointment_presenter.page_title,
35+
"presented_appointment": appointment_presenter,
36+
"secondary_nav_items": present_secondary_nav(
37+
appointment.pk, current_tab="note"
38+
),
39+
}
40+
)
41+
return context
42+
43+
def get_form_kwargs(self):
44+
kwargs = super().get_form_kwargs()
45+
try:
46+
kwargs["instance"] = self.appointment.note
47+
except AppointmentNote.DoesNotExist:
48+
kwargs["instance"] = AppointmentNote(appointment=self.appointment)
49+
return kwargs
50+
51+
def form_valid(self, form):
52+
is_new_note = form.instance._state.adding
53+
note = form.save()
54+
auditor = Auditor.from_request(self.request)
55+
if is_new_note:
56+
auditor.audit_create(note)
57+
else:
58+
auditor.audit_update(note)
59+
messages.add_message(
60+
self.request,
61+
messages.SUCCESS,
62+
"Appointment note saved",
63+
)
64+
return redirect("mammograms:appointment_note", pk=self.appointment.pk)
65+
66+
67+
class DeleteAppointmentNoteView(DeleteWithAuditView):
68+
def get_thing_name(self, object):
69+
return "appointment note"
70+
71+
def get_success_message_content(self, object):
72+
return "Appointment note deleted"
73+
74+
def get_object(self):
75+
provider = self.request.user.current_provider
76+
appointment = provider.appointments.get(pk=self.kwargs["pk"])
77+
return appointment.note
78+
79+
def get_success_url(self):
80+
return reverse("mammograms:appointment_note", kwargs={"pk": self.kwargs["pk"]})
81+
82+
def get(self, request, *args, **kwargs):
83+
try:
84+
return super().get(request, *args, **kwargs)
85+
except AppointmentNote.DoesNotExist:
86+
return redirect(self.get_success_url())
87+
88+
def post(self, request, *args, **kwargs):
89+
try:
90+
return super().post(request, *args, **kwargs)
91+
except AppointmentNote.DoesNotExist:
92+
return redirect(self.get_success_url())

0 commit comments

Comments
 (0)