Skip to content

Commit adb4703

Browse files
authored
Merge pull request #760 from NHSDigital/DTOSS-11525-update-history-of-cysts
Medical history - update history of cysts
2 parents 2ae0b6e + c960cf7 commit adb4703

16 files changed

+369
-65
lines changed

manage_breast_screening/mammograms/forms/cyst_history_form.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,13 @@
22
from django.forms.widgets import Textarea
33

44
from manage_breast_screening.core.services.auditor import Auditor
5-
from manage_breast_screening.nhsuk_forms.fields import (
6-
CharField,
7-
ChoiceField,
8-
)
5+
from manage_breast_screening.nhsuk_forms.fields import CharField, ChoiceField
96
from manage_breast_screening.participants.models.cyst_history_item import (
107
CystHistoryItem,
118
)
129

1310

14-
class CystHistoryForm(Form):
11+
class CystHistoryBaseForm(Form):
1512
def __init__(self, *args, participant, **kwargs):
1613
super().__init__(*args, **kwargs)
1714

@@ -38,6 +35,8 @@ def model_values(self):
3835
additional_details=self.cleaned_data.get("additional_details", ""),
3936
)
4037

38+
39+
class CystHistoryForm(CystHistoryBaseForm):
4140
def create(self, appointment, request):
4241
auditor = Auditor.from_request(request)
4342
field_values = self.model_values()
@@ -50,3 +49,25 @@ def create(self, appointment, request):
5049
auditor.audit_create(cyst_history)
5150

5251
return cyst_history
52+
53+
54+
class CystHistoryUpdateForm(CystHistoryBaseForm):
55+
def __init__(self, instance, *args, **kwargs):
56+
self.instance = instance
57+
58+
kwargs["participant"] = instance.participant
59+
kwargs["initial"] = {
60+
"treatment": instance.treatment,
61+
"additional_details": instance.additional_details,
62+
}
63+
64+
super().__init__(*args, **kwargs)
65+
66+
def update(self, request):
67+
self.instance.treatment = self.cleaned_data["treatment"]
68+
self.instance.additional_details = self.cleaned_data["additional_details"]
69+
self.instance.save()
70+
71+
Auditor.from_request(request).audit_update(self.instance)
72+
73+
return self.instance

manage_breast_screening/mammograms/jinja2/mammograms/record_medical_information.jinja

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@
6969

7070
{% set cyst_history_html %}
7171
{% for presented_item in presenter.cyst_history %}
72+
<a style="float: right" class="nhsuk-link nhsuk-link--no-visited-state" href="{{ presented_item.change_link.href}}">
73+
{{ presented_item.change_link.text }}<span class="nhsuk-u-visually-hidden">{{ presented_item.change_link.visually_hidden_text }}</span>
74+
</a><br>
7275
{{ summaryList(presented_item.summary_list_params) }}
7376
{% endfor %}
7477
<a href="{{ presenter.add_cyst_history_link.href }}" class="nhsuk-link nhsuk-link--no-visited-state">{{ presenter.add_cyst_history_link.text }}</a><br>

manage_breast_screening/mammograms/presenters/cyst_history_item_presenter.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1+
from django.urls import reverse
2+
13
from manage_breast_screening.core.template_helpers import nl2br
24

35

46
class CystHistoryItemPresenter:
5-
def __init__(self, breast_cancer_history_item):
7+
def __init__(self, breast_cancer_history_item, counter=None):
68
self._item = breast_cancer_history_item
79

10+
# If there are more than one of these items, we add a counter to the
11+
# visually hidden text
12+
self.counter = counter
13+
814
self.treatment = self._item.get_treatment_display()
915
self.additional_details = nl2br(self._item.additional_details)
1016

@@ -23,3 +29,19 @@ def summary_list_params(self):
2329
},
2430
],
2531
}
32+
33+
@property
34+
def change_link(self):
35+
return {
36+
"href": reverse(
37+
"mammograms:change_cyst_history_item",
38+
kwargs={
39+
"pk": self._item.appointment_id,
40+
"history_item_pk": self._item.pk,
41+
},
42+
),
43+
"text": "Change",
44+
"visually_hidden_text": (
45+
f" cyst item {self.counter}" if self.counter else " cyst item"
46+
),
47+
}

manage_breast_screening/mammograms/presenters/medical_information_presenter.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,15 @@ def __init__(self, appointment):
6060
BenignLumpHistoryItemPresenter(item)
6161
for item in appointment.benign_lump_history_items.all()
6262
]
63-
self.cyst_history = [
64-
CystHistoryItemPresenter(item)
65-
for item in appointment.cyst_history_items.all()
66-
]
63+
64+
cyst_history_items = list(appointment.cyst_history_items.all())
65+
if len(cyst_history_items) == 1:
66+
self.cyst_history = [CystHistoryItemPresenter(cyst_history_items[0])]
67+
else:
68+
self.cyst_history = [
69+
CystHistoryItemPresenter(item, counter=counter)
70+
for counter, item in enumerate(cyst_history_items, 1)
71+
]
6772
self.existing_symptom_type_ids = {
6873
symptom.symptom_type_id for symptom in symptoms
6974
}

manage_breast_screening/mammograms/tests/forms/test_cyst_history_form.py

Lines changed: 63 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,25 @@
77
from manage_breast_screening.participants.models.cyst_history_item import (
88
CystHistoryItem,
99
)
10-
from manage_breast_screening.participants.tests.factories import AppointmentFactory
10+
from manage_breast_screening.participants.tests.factories import (
11+
AppointmentFactory,
12+
CystHistoryItemFactory,
13+
)
14+
15+
from ...forms.cyst_history_form import CystHistoryForm, CystHistoryUpdateForm
16+
1117

12-
from ...forms.cyst_history_form import CystHistoryForm
18+
@pytest.fixture
19+
def dummy_request(clinical_user):
20+
request = RequestFactory().get("/test-form")
21+
request.user = clinical_user
22+
return request
1323

1424

1525
@pytest.mark.django_db
16-
class TestCystHistoryItemForm:
17-
def test_no_data(self, clinical_user):
26+
class TestCystHistoryForm:
27+
def test_no_data(self):
1828
appointment = AppointmentFactory()
19-
request = RequestFactory().get("/test-form")
20-
request.user = clinical_user
21-
2229
form = CystHistoryForm(QueryDict(), participant=appointment.participant)
2330

2431
assert not form.is_valid()
@@ -43,20 +50,64 @@ def test_no_data(self, clinical_user):
4350
},
4451
],
4552
)
46-
def test_success(self, clinical_user, data):
53+
def test_success(self, data, dummy_request):
4754
appointment = AppointmentFactory()
48-
request = RequestFactory().get("/test-form")
49-
request.user = clinical_user
50-
5155
form = CystHistoryForm(
5256
QueryDict(urlencode(data, doseq=True)),
5357
participant=appointment.participant,
5458
)
5559

5660
assert form.is_valid()
5761

58-
obj = form.create(appointment=appointment, request=request)
62+
obj = form.create(appointment=appointment, request=dummy_request)
5963

6064
assert obj.appointment == appointment
6165
assert obj.treatment == data.get("treatment")
6266
assert obj.additional_details == data.get("additional_details", "")
67+
68+
69+
@pytest.mark.django_db
70+
class TestCystHistoryUpdateForm:
71+
@pytest.fixture
72+
def instance(self):
73+
return CystHistoryItemFactory(
74+
treatment=CystHistoryItem.Treatment.DRAINAGE_OR_REMOVAL
75+
)
76+
77+
def test_no_data(self, instance):
78+
form = CystHistoryUpdateForm(instance, QueryDict())
79+
80+
assert not form.is_valid()
81+
assert form.errors == {"treatment": ["Select the treatment type"]}
82+
83+
@pytest.mark.parametrize(
84+
"data",
85+
[
86+
{
87+
"treatment": CystHistoryItem.Treatment.NO_TREATMENT,
88+
},
89+
{
90+
"treatment": CystHistoryItem.Treatment.DRAINAGE_OR_REMOVAL,
91+
},
92+
{
93+
"treatment": CystHistoryItem.Treatment.NO_TREATMENT,
94+
"additional_details": "Some additional details",
95+
},
96+
{
97+
"treatment": CystHistoryItem.Treatment.DRAINAGE_OR_REMOVAL,
98+
"additional_details": "Some additional details",
99+
},
100+
],
101+
)
102+
def test_success(self, instance, data, dummy_request):
103+
form = CystHistoryUpdateForm(
104+
instance,
105+
QueryDict(urlencode(data, doseq=True)),
106+
)
107+
108+
assert form.is_valid()
109+
110+
obj = form.update(request=dummy_request)
111+
assert obj.appointment == instance.appointment
112+
assert obj.treatment == data.get("treatment")
113+
assert obj.additional_details == data.get("additional_details", "")

manage_breast_screening/mammograms/tests/presenters/test_cyst_history_item_presenter.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@
44
from manage_breast_screening.participants.models.cyst_history_item import (
55
CystHistoryItem,
66
)
7-
from manage_breast_screening.participants.tests.factories import (
8-
CystHistoryItemFactory,
9-
)
7+
from manage_breast_screening.participants.tests.factories import CystHistoryItemFactory
108

119

1210
class TestCystHistoryItemPresenter:
@@ -37,3 +35,29 @@ def test_single(self):
3735
},
3836
],
3937
}
38+
39+
def test_change_link(self):
40+
item = CystHistoryItemFactory.build(
41+
treatment=CystHistoryItem.Treatment.NO_TREATMENT,
42+
additional_details="Some additional details",
43+
)
44+
45+
presenter = CystHistoryItemPresenter(item)
46+
assert presenter.change_link == {
47+
"href": f"/mammograms/{item.appointment_id}/record-medical-information/cyst-history/{item.pk}",
48+
"text": "Change",
49+
"visually_hidden_text": " cyst item",
50+
}
51+
52+
def test_change_link_with_counter(self):
53+
item = CystHistoryItemFactory.build(
54+
treatment=CystHistoryItem.Treatment.NO_TREATMENT,
55+
additional_details="Some additional details",
56+
)
57+
58+
presenter = CystHistoryItemPresenter(item, counter=2)
59+
assert presenter.change_link == {
60+
"href": f"/mammograms/{item.appointment_id}/record-medical-information/cyst-history/{item.pk}",
61+
"text": "Change",
62+
"visually_hidden_text": " cyst item 2",
63+
}

manage_breast_screening/mammograms/tests/presenters/test_medical_information_presenter.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
)
1010
from manage_breast_screening.participants.tests.factories import (
1111
AppointmentFactory,
12+
CystHistoryItemFactory,
1213
SymptomFactory,
1314
)
1415

@@ -124,6 +125,28 @@ def test_add_breast_cancer_history_link(self):
124125
"text": "Add breast cancer history",
125126
}
126127

128+
def test_cyst_history_items_have_a_counter(self):
129+
appointment = AppointmentFactory()
130+
CystHistoryItemFactory.create_batch(2, appointment=appointment)
131+
132+
counters = [
133+
item.counter
134+
for item in MedicalInformationPresenter(appointment).cyst_history
135+
]
136+
137+
assert counters == [1, 2]
138+
139+
def test_single_cyst_history_item_has_no_counter(self):
140+
appointment = AppointmentFactory()
141+
CystHistoryItemFactory.create(appointment=appointment)
142+
143+
counters = [
144+
item.counter
145+
for item in MedicalInformationPresenter(appointment).cyst_history
146+
]
147+
148+
assert counters == [None]
149+
127150
def test_implanted_medical_device_history_link(self):
128151
appointment = AppointmentFactory()
129152

manage_breast_screening/mammograms/tests/views/test_cyst_history_views.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
)
99
from manage_breast_screening.participants.tests.factories import (
1010
AppointmentFactory,
11+
CystHistoryItemFactory,
1112
)
1213

1314

@@ -75,3 +76,59 @@ def test_invalid_post_renders_response_with_errors(self, clinical_user_client):
7576
""",
7677
response.text,
7778
)
79+
80+
81+
@pytest.mark.django_db
82+
class TestChangeCystHistoryView:
83+
@pytest.fixture
84+
def appointment(self, clinical_user_client):
85+
return AppointmentFactory.create(
86+
clinic_slot__clinic__setting__provider=clinical_user_client.current_provider
87+
)
88+
89+
@pytest.fixture
90+
def history_item(self, appointment):
91+
return CystHistoryItemFactory.create(
92+
appointment=appointment, treatment=CystHistoryItem.Treatment.NO_TREATMENT
93+
)
94+
95+
def test_renders_response(self, clinical_user_client, history_item):
96+
response = clinical_user_client.http.get(
97+
reverse(
98+
"mammograms:change_cyst_history_item",
99+
kwargs={
100+
"pk": history_item.appointment.pk,
101+
"history_item_pk": history_item.pk,
102+
},
103+
)
104+
)
105+
assert response.status_code == 200
106+
107+
def test_valid_post_redirects_to_appointment(
108+
self, clinical_user_client, appointment, history_item
109+
):
110+
response = clinical_user_client.http.post(
111+
reverse(
112+
"mammograms:change_cyst_history_item",
113+
kwargs={"pk": appointment.pk, "history_item_pk": history_item.pk},
114+
),
115+
{
116+
"treatment": CystHistoryItem.Treatment.DRAINAGE_OR_REMOVAL,
117+
},
118+
)
119+
assertRedirects(
120+
response,
121+
reverse(
122+
"mammograms:record_medical_information",
123+
kwargs={"pk": appointment.pk},
124+
),
125+
)
126+
assertMessages(
127+
response,
128+
[
129+
messages.Message(
130+
level=messages.SUCCESS,
131+
message="Details of cysts updated",
132+
)
133+
],
134+
)

manage_breast_screening/mammograms/urls.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,11 @@
140140
cyst_history_view.AddCystHistoryView.as_view(),
141141
name="add_cyst_history_item",
142142
),
143+
path(
144+
"<uuid:pk>/record-medical-information/cyst-history/<uuid:history_item_pk>",
145+
cyst_history_view.ChangeCystHistoryView.as_view(),
146+
name="change_cyst_history_item",
147+
),
143148
path(
144149
"<uuid:pk>/record-medical-information/breast-augmentation-history/",
145150
breast_augmentation_history_view.AddBreastAugmentationHistoryView.as_view(),

manage_breast_screening/mammograms/views/breast_augmentation_history_view.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22
from django.urls import reverse
33
from django.views.generic import FormView
44

5-
from ..forms.breast_augmentation_history_form import (
6-
BreastAugmentationHistoryForm,
7-
)
5+
from ..forms.breast_augmentation_history_form import BreastAugmentationHistoryForm
86
from .mixins import InProgressAppointmentMixin
97

108

0 commit comments

Comments
 (0)