Skip to content

Commit e97d319

Browse files
authored
Merge pull request #785 from NHSDigital/DTOSS-11532-delete-breast-cancer-history
Medical information - delete breast cancer history
2 parents ae93a64 + 92c849c commit e97d319

File tree

15 files changed

+258
-69
lines changed

15 files changed

+258
-69
lines changed

manage_breast_screening/core/jinja2/layout-confirmation.jinja

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
{% extends "layout-app.jinja" %}
22
{% from 'nhsuk/components/button/macro.jinja' import button %}
3+
{% from 'nhsuk/components/inset-text/macro.jinja' import insetText %}
4+
35

46
{% block header %}
57
{{ header({
@@ -21,6 +23,13 @@
2123
</h1>
2224

2325
{% block details %}
26+
{% set insetTextHtml %}
27+
<p>This action is final and cannot be undone.</p>
28+
{% endset %}
29+
30+
{{ insetText({
31+
"html": insetTextHtml
32+
}) }}
2433
{% endblock %}
2534

2635
<form method="post" action="{{ confirm_action.href | default(request.path) }}">

manage_breast_screening/core/views/__init__.py

Whitespace-only changes.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
from django.contrib import messages
2+
from django.shortcuts import redirect
3+
from django.views.generic import DeleteView
4+
5+
from ..services.auditor import Auditor
6+
7+
8+
class DeleteWithAuditView(DeleteView):
9+
"""
10+
A generic delete view with a confirmation page, success message,
11+
and some default context variables.
12+
13+
The object is hard deleted but the record is audited first.
14+
"""
15+
16+
template_name = "layout-confirmation.jinja"
17+
18+
def get_thing_name(self, object):
19+
return object._meta.verbose_name
20+
21+
def get_success_message_content(self, object):
22+
return f"Deleted {self.get_thing_name(object)}"
23+
24+
def get_cancel_url(self):
25+
return self.get_success_url()
26+
27+
def get_context_data(self, **kwargs):
28+
context = super().get_context_data(**kwargs)
29+
thing_name = self.get_thing_name(self.object)
30+
context.update(
31+
{
32+
"page_title": f"Are you sure you want to delete this {thing_name}?",
33+
"heading": f"Are you sure you want to delete this {thing_name}?",
34+
"confirm_action": {
35+
"text": f"Delete {thing_name}",
36+
"href": self.request.get_full_path(),
37+
},
38+
"cancel_action": {"href": self.get_cancel_url()},
39+
}
40+
)
41+
return context
42+
43+
def post(self, request, *args, **kwargs):
44+
object = self.get_object()
45+
auditor = Auditor.from_request(request)
46+
auditor.audit_delete(object)
47+
object.delete()
48+
49+
messages.add_message(
50+
self.request,
51+
messages.SUCCESS,
52+
self.get_success_message_content(object),
53+
)
54+
55+
return redirect(self.get_success_url())

manage_breast_screening/mammograms/forms/symptom_forms.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ def create(self, appointment, request):
218218
auditor = Auditor.from_request(request)
219219
field_values = self.model_values()
220220

221-
symptom = appointment.symptom_set.create(
221+
symptom = appointment.symptoms.create(
222222
appointment=appointment,
223223
symptom_type_id=self.symptom_type,
224224
reported_at=date.today(),

manage_breast_screening/mammograms/jinja2/mammograms/medical_information/medical_history/forms/breast_cancer_history_item_form.jinja

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,12 @@
6262
}) }}
6363
</div>
6464

65+
{% if delete_link %}
66+
<p class="nhsuk-u-margin-top-4">
67+
<a href="{{ delete_link.href }}" class="{{ delete_link.class }}">
68+
{{ delete_link.text }}
69+
</a>
70+
</p>
71+
{% endif %}
72+
6573
{% endblock %}

manage_breast_screening/mammograms/presenters/medical_information_presenter.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
class MedicalInformationPresenter:
3333
def __init__(self, appointment):
3434
self.appointment = AppointmentPresenter(appointment)
35-
symptoms = appointment.symptom_set.select_related("symptom_type").order_by(
35+
symptoms = appointment.symptoms.select_related("symptom_type").order_by(
3636
"symptom_type__name", "reported_at"
3737
)
3838
self.symptoms = [SymptomPresenter(symptom) for symptom in symptoms]

manage_breast_screening/mammograms/tests/views/test_breast_cancer_history_views.py

Lines changed: 72 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,27 @@
33
from django.urls import reverse
44
from pytest_django.asserts import assertInHTML, assertMessages, assertRedirects
55

6+
from manage_breast_screening.participants.models.breast_cancer_history_item import (
7+
BreastCancerHistoryItem,
8+
)
69
from manage_breast_screening.participants.tests.factories import (
710
AppointmentFactory,
811
BreastCancerHistoryItemFactory,
912
)
1013

1114

15+
@pytest.fixture
16+
def appointment(clinical_user_client):
17+
return AppointmentFactory.create(
18+
clinic_slot__clinic__setting__provider=clinical_user_client.current_provider
19+
)
20+
21+
22+
@pytest.fixture
23+
def history_item(appointment):
24+
return BreastCancerHistoryItemFactory.create(appointment=appointment)
25+
26+
1227
@pytest.mark.django_db
1328
class TestBreastCancerHistoryView:
1429
def test_renders_response(self, clinical_user_client):
@@ -97,16 +112,6 @@ def test_invalid_post_renders_response_with_errors(self, clinical_user_client):
97112

98113
@pytest.mark.django_db
99114
class TestBreastCancerHistoryUpdateView:
100-
@pytest.fixture
101-
def appointment(self, clinical_user_client):
102-
return AppointmentFactory.create(
103-
clinic_slot__clinic__setting__provider=clinical_user_client.current_provider
104-
)
105-
106-
@pytest.fixture
107-
def history_item(self, appointment):
108-
return BreastCancerHistoryItemFactory.create(appointment=appointment)
109-
110115
def test_renders_response(self, clinical_user_client, history_item):
111116
response = clinical_user_client.http.get(
112117
reverse(
@@ -160,3 +165,60 @@ def test_valid_post_redirects_to_appointment(
160165
)
161166
],
162167
)
168+
169+
170+
@pytest.mark.django_db
171+
class TestDeleteSymptomView:
172+
def test_get_renders_response(self, clinical_user_client, history_item):
173+
response = clinical_user_client.http.get(
174+
reverse(
175+
"mammograms:delete_breast_cancer_history_item",
176+
kwargs={
177+
"pk": history_item.appointment.pk,
178+
"history_item_pk": history_item.pk,
179+
},
180+
)
181+
)
182+
assert response.status_code == 200
183+
184+
def test_post_redirects_to_record_medical_information(
185+
self, clinical_user_client, history_item
186+
):
187+
response = clinical_user_client.http.post(
188+
reverse(
189+
"mammograms:delete_breast_cancer_history_item",
190+
kwargs={
191+
"pk": history_item.appointment.pk,
192+
"history_item_pk": history_item.pk,
193+
},
194+
)
195+
)
196+
assertRedirects(
197+
response,
198+
reverse(
199+
"mammograms:record_medical_information",
200+
kwargs={"pk": history_item.appointment.pk},
201+
),
202+
)
203+
assertMessages(
204+
response,
205+
[
206+
messages.Message(
207+
level=messages.SUCCESS,
208+
message="Deleted breast cancer",
209+
)
210+
],
211+
)
212+
213+
def test_the_symptom_is_deleted(self, clinical_user_client, history_item):
214+
clinical_user_client.http.post(
215+
reverse(
216+
"mammograms:delete_breast_cancer_history_item",
217+
kwargs={
218+
"pk": history_item.appointment.pk,
219+
"history_item_pk": history_item.pk,
220+
},
221+
)
222+
)
223+
224+
assert not BreastCancerHistoryItem.objects.filter(pk=history_item.pk).exists()

manage_breast_screening/mammograms/urls.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@
135135
breast_cancer_history_views.ChangeBreastCancerHistoryView.as_view(),
136136
name="change_breast_cancer_history_item",
137137
),
138+
path(
139+
"<uuid:pk>/record-medical-information/breast-cancer-history/<uuid:history_item_pk>/delete",
140+
breast_cancer_history_views.DeleteBreastCancerHistoryView.as_view(),
141+
name="delete_breast_cancer_history_item",
142+
),
138143
path(
139144
"<uuid:pk>/record-medical-information/implanted-medical-device-history/",
140145
implanted_medical_device_history_view.AddImplantedMedicalDeviceHistoryView.as_view(),

manage_breast_screening/mammograms/views/breast_cancer_history_views.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from django.urls import reverse
88
from django.views.generic import FormView
99

10+
from manage_breast_screening.core.views.generic import DeleteWithAuditView
1011
from manage_breast_screening.mammograms.forms.breast_cancer_history_form import (
1112
BreastCancerHistoryForm,
1213
BreastCancerHistoryUpdateForm,
@@ -84,7 +85,7 @@ class ChangeBreastCancerHistoryView(BaseBreastCancerHistoryView):
8485

8586
def get_instance(self):
8687
try:
87-
return BreastCancerHistoryItem.objects.get(
88+
return self.appointment.breast_cancer_history_items.get(
8889
pk=self.kwargs["history_item_pk"],
8990
appointment_id=self.kwargs["pk"],
9091
)
@@ -134,7 +135,39 @@ def get_context_data(self, **kwargs):
134135
{
135136
"heading": "Edit details of breast cancer",
136137
"page_title": "Edit details of breast cancer",
138+
"delete_link": {
139+
"text": "Delete this item",
140+
"class": "nhsuk-link app-link--warning",
141+
"href": reverse(
142+
"mammograms:delete_breast_cancer_history_item",
143+
kwargs={
144+
"pk": self.kwargs["pk"],
145+
"history_item_pk": self.kwargs["history_item_pk"],
146+
},
147+
),
148+
},
137149
},
138150
)
139151

140152
return context
153+
154+
155+
class DeleteBreastCancerHistoryView(DeleteWithAuditView):
156+
def get_thing_name(self, object):
157+
return "item"
158+
159+
def get_success_message_content(self, object):
160+
return "Deleted breast cancer"
161+
162+
def get_object(self):
163+
provider = self.request.user.current_provider
164+
appointment = provider.appointments.get(pk=self.kwargs["pk"])
165+
return appointment.breast_cancer_history_items.get(
166+
pk=self.kwargs["history_item_pk"]
167+
)
168+
169+
def get_success_url(self) -> str:
170+
return reverse(
171+
"mammograms:record_medical_information",
172+
kwargs={"pk": self.kwargs["pk"]},
173+
)

manage_breast_screening/mammograms/views/symptom_views.py

Lines changed: 21 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
from django.contrib import messages
22
from django.http import Http404
3-
from django.shortcuts import redirect, render
43
from django.urls import reverse
5-
from django.views import View
64
from django.views.generic import FormView
75

8-
from manage_breast_screening.core.services.auditor import Auditor
6+
from manage_breast_screening.core.views.generic import DeleteWithAuditView
97
from manage_breast_screening.mammograms.presenters.symptom_presenter import (
108
SymptomPresenter,
119
)
@@ -85,7 +83,7 @@ def get_form_kwargs(self):
8583
kwargs = super().get_form_kwargs()
8684

8785
try:
88-
instance = Symptom.objects.get(
86+
instance = self.appointment.symptoms.get(
8987
pk=self.kwargs["symptom_pk"],
9088
appointment_id=self.kwargs["pk"],
9189
**self.extra_filters(),
@@ -248,59 +246,29 @@ def get_context_data(self, **kwargs):
248246
return context
249247

250248

251-
class DeleteSymptomView(View):
252-
def get(self, request, *args, **kwargs):
253-
try:
254-
symptom = Symptom.objects.get(pk=kwargs["symptom_pk"])
255-
except Symptom.DoesNotExist:
256-
raise Http404("Symptom not found")
249+
class DeleteSymptomView(DeleteWithAuditView):
250+
template_name = "mammograms/medical_information/symptoms/confirm_delete_lump.jinja"
257251

258-
context = {
259-
"page_title": "Are you sure you want to delete this symptom?",
260-
"heading": "Are you sure you want to delete this symptom?",
261-
"confirm_action": {
262-
"text": "Delete symptom",
263-
"href": reverse(
264-
"mammograms:delete_symptom",
265-
kwargs={
266-
"pk": kwargs["pk"],
267-
"symptom_pk": kwargs["symptom_pk"],
268-
},
269-
),
270-
},
271-
"cancel_action": {
272-
"href": reverse(
273-
"mammograms:record_medical_information",
274-
kwargs={"pk": kwargs["pk"]},
275-
)
276-
},
277-
"summary_list_row": SymptomPresenter(symptom).build_summary_list_row(
278-
include_actions=False
279-
),
280-
}
281-
282-
return render(
283-
request,
284-
"mammograms/medical_information/symptoms/confirm_delete_lump.jinja",
285-
context=context,
252+
def get_success_url(self):
253+
return reverse(
254+
"mammograms:record_medical_information",
255+
kwargs={"pk": self.kwargs["pk"]},
286256
)
287257

288-
def post(self, request, *args, **kwargs):
289-
try:
290-
symptom = Symptom.objects.get(pk=kwargs["symptom_pk"])
291-
except Symptom.DoesNotExist:
292-
raise Http404("Symptom not found")
293-
auditor = Auditor.from_request(request)
294-
295-
presenter = SymptomPresenter(symptom)
258+
def get_object(self):
259+
provider = self.request.user.current_provider
260+
appointment = provider.appointments.get(pk=self.kwargs["pk"])
261+
return appointment.symptoms.get(pk=self.kwargs["symptom_pk"])
296262

297-
auditor.audit_delete(symptom)
298-
symptom.delete()
263+
def get_context_data(self, **kwargs):
264+
symptom = self.object
299265

300-
messages.add_message(
301-
self.request,
302-
messages.SUCCESS,
303-
presenter.delete_message_html,
266+
context = super().get_context_data(**kwargs)
267+
context["summary_list_row"] = SymptomPresenter(symptom).build_summary_list_row(
268+
include_actions=False
304269
)
270+
return context
305271

306-
return redirect("mammograms:record_medical_information", pk=kwargs["pk"])
272+
def get_success_message_content(self, symptom):
273+
presenter = SymptomPresenter(symptom)
274+
return presenter.delete_message_html

0 commit comments

Comments
 (0)