diff --git a/manage_breast_screening/mammograms/forms/mastectomy_or_lumpectomy_history_form.py b/manage_breast_screening/mammograms/forms/mastectomy_or_lumpectomy_history_form.py index fe5d312b1..9b52244d4 100644 --- a/manage_breast_screening/mammograms/forms/mastectomy_or_lumpectomy_history_form.py +++ b/manage_breast_screening/mammograms/forms/mastectomy_or_lumpectomy_history_form.py @@ -90,7 +90,21 @@ class MastectomyOrLumpectomyHistoryForm(FormWithConditionalFields): error_messages={"max_words": "Additional details must be 500 words or less"}, ) - def __init__(self, *args, participant, **kwargs): + def __init__(self, *args, **kwargs): + self.instance = kwargs.pop("instance", None) + + if self.instance: + kwargs["initial"] = { + "left_breast_procedure": self.instance.left_breast_procedure, + "right_breast_procedure": self.instance.right_breast_procedure, + "left_breast_other_surgery": self.instance.left_breast_other_surgery, + "right_breast_other_surgery": self.instance.right_breast_other_surgery, + "year_of_surgery": self.instance.year_of_surgery, + "surgery_reason": self.instance.surgery_reason, + "surgery_other_reason_details": self.instance.surgery_other_reason_details, + "additional_details": self.instance.additional_details, + } + super().__init__(*args, **kwargs) self.given_field_value( @@ -132,3 +146,26 @@ def create(self, appointment, request): auditor.audit_create(mastectomy_or_lumpectomy_history) return mastectomy_or_lumpectomy_history + + def update(self, request): + self.instance.left_breast_procedure = self.cleaned_data["left_breast_procedure"] + self.instance.right_breast_procedure = self.cleaned_data[ + "right_breast_procedure" + ] + self.instance.left_breast_other_surgery = self.cleaned_data[ + "left_breast_other_surgery" + ] + self.instance.right_breast_other_surgery = self.cleaned_data[ + "right_breast_other_surgery" + ] + self.instance.year_of_surgery = self.cleaned_data["year_of_surgery"] + self.instance.surgery_reason = self.cleaned_data["surgery_reason"] + self.instance.surgery_other_reason_details = self.cleaned_data[ + "surgery_other_reason_details" + ] + self.instance.additional_details = self.cleaned_data["additional_details"] + self.instance.save() + + Auditor.from_request(request).audit_update(self.instance) + + return self.instance diff --git a/manage_breast_screening/mammograms/jinja2/mammograms/record_medical_information.jinja b/manage_breast_screening/mammograms/jinja2/mammograms/record_medical_information.jinja index 62a50aaaf..6f516a47e 100644 --- a/manage_breast_screening/mammograms/jinja2/mammograms/record_medical_information.jinja +++ b/manage_breast_screening/mammograms/jinja2/mammograms/record_medical_information.jinja @@ -45,6 +45,9 @@ {% set mastectomy_or_lumpectomy_history_html %} {% for presented_item in presenter.mastectomy_or_lumpectomy_history %} + + {{ presented_item.change_link.text }}{{ presented_item.change_link.visually_hidden_text }} +
{{ summaryList(presented_item.summary_list_params) }} {% endfor %} {{ presenter.add_mastectomy_or_lumpectomy_history_link.text }}
diff --git a/manage_breast_screening/mammograms/presenters/mastectomy_or_lumpectomy_history_item_presenter.py b/manage_breast_screening/mammograms/presenters/mastectomy_or_lumpectomy_history_item_presenter.py index aac1954b4..87453cddd 100644 --- a/manage_breast_screening/mammograms/presenters/mastectomy_or_lumpectomy_history_item_presenter.py +++ b/manage_breast_screening/mammograms/presenters/mastectomy_or_lumpectomy_history_item_presenter.py @@ -1,3 +1,5 @@ +from django.urls import reverse + from manage_breast_screening.core.template_helpers import multiline_content, nl2br from manage_breast_screening.participants.models.mastectomy_or_lumpectomy_history_item import ( MastectomyOrLumpectomyHistoryItem, @@ -5,9 +7,13 @@ class MastectomyOrLumpectomyHistoryItemPresenter: - def __init__(self, mastectomy_or_lumpectomy_history_item): + def __init__(self, mastectomy_or_lumpectomy_history_item, counter=None): self._item = mastectomy_or_lumpectomy_history_item + # If there are more than one of these items, we add a counter to the + # visually hidden text + self.counter = counter + self.right_breast_procedure = self._item.get_right_breast_procedure_display() self.left_breast_procedure = self._item.get_left_breast_procedure_display() @@ -75,3 +81,21 @@ def summary_list_params(self): def _format_multiple_choices(self, choices, ChoiceClass): return ", ".join(ChoiceClass(choice).label for choice in choices) + + @property + def change_link(self): + return { + "href": reverse( + "mammograms:change_mastectomy_or_lumpectomy_history_item", + kwargs={ + "pk": self._item.appointment_id, + "history_item_pk": self._item.pk, + }, + ), + "text": "Change", + "visually_hidden_text": ( + f" mastectomy or lumpectomy item {self.counter}" + if self.counter + else " mastectomy or lumpectomy item" + ), + } diff --git a/manage_breast_screening/mammograms/presenters/medical_information_presenter.py b/manage_breast_screening/mammograms/presenters/medical_information_presenter.py index c1b34e913..0b0fb1182 100644 --- a/manage_breast_screening/mammograms/presenters/medical_information_presenter.py +++ b/manage_breast_screening/mammograms/presenters/medical_information_presenter.py @@ -41,25 +41,15 @@ def __init__(self, appointment): BreastCancerHistoryItemPresenter, ) - self.mastectomy_or_lumpectomy_history = [ - MastectomyOrLumpectomyHistoryItemPresenter(item) - for item in appointment.mastectomy_or_lumpectomy_history_items.all() - ] + self.mastectomy_or_lumpectomy_history = self._present_items( + appointment.mastectomy_or_lumpectomy_history_items.all(), + MastectomyOrLumpectomyHistoryItemPresenter, + ) - implanted_medical_device_history = list( - appointment.implanted_medical_device_history_items.all() + self.implanted_medical_device_history = self._present_items( + appointment.implanted_medical_device_history_items.all(), + ImplantedMedicalDeviceHistoryItemPresenter, ) - if len(implanted_medical_device_history) == 1: - self.implanted_medical_device_history = [ - ImplantedMedicalDeviceHistoryItemPresenter( - implanted_medical_device_history[0] - ) - ] - else: - self.implanted_medical_device_history = [ - ImplantedMedicalDeviceHistoryItemPresenter(item, counter=counter) - for counter, item in enumerate(implanted_medical_device_history, 1) - ] self.breast_augmentation_history = [ BreastAugmentationHistoryItemPresenter(item) diff --git a/manage_breast_screening/mammograms/tests/forms/test_mastectomy_or_lumpectomy_history_form.py b/manage_breast_screening/mammograms/tests/forms/test_mastectomy_or_lumpectomy_history_form.py index 55dd2aad1..8ddf7bace 100644 --- a/manage_breast_screening/mammograms/tests/forms/test_mastectomy_or_lumpectomy_history_form.py +++ b/manage_breast_screening/mammograms/tests/forms/test_mastectomy_or_lumpectomy_history_form.py @@ -9,23 +9,27 @@ from manage_breast_screening.participants.models.mastectomy_or_lumpectomy_history_item import ( MastectomyOrLumpectomyHistoryItem, ) -from manage_breast_screening.participants.tests.factories import AppointmentFactory +from manage_breast_screening.participants.tests.factories import ( + AppointmentFactory, + MastectomyOrLumpectomyHistoryItemFactory, +) from ...forms.mastectomy_or_lumpectomy_history_form import ( MastectomyOrLumpectomyHistoryForm, ) +@pytest.fixture +def dummy_request(clinical_user): + request = RequestFactory().get("/test-form") + request.user = clinical_user + return request + + @pytest.mark.django_db class TestMastectomyOrLumpectomyHistoryItemForm: - def test_missing_required_fields(self, clinical_user): - appointment = AppointmentFactory() - request = RequestFactory().get("/test-form") - request.user = clinical_user - - form = MastectomyOrLumpectomyHistoryForm( - QueryDict(), participant=appointment.participant - ) + def test_missing_required_fields(self): + form = MastectomyOrLumpectomyHistoryForm(QueryDict()) assert not form.is_valid() assert form.errors == { @@ -44,13 +48,7 @@ def test_missing_required_fields(self, clinical_user): "surgery_reason": ["Select the reason for surgery"], } - def test_right_breast_other_surgery_no_other_surgery_and_others( - self, clinical_user - ): - appointment = AppointmentFactory() - request = RequestFactory().get("/test-form") - request.user = clinical_user - + def test_right_breast_other_surgery_no_other_surgery_and_others(self): form = MastectomyOrLumpectomyHistoryForm( QueryDict( urlencode( @@ -70,7 +68,6 @@ def test_right_breast_other_surgery_no_other_surgery_and_others( doseq=True, ), ), - participant=appointment.participant, ) assert not form.is_valid() @@ -80,11 +77,7 @@ def test_right_breast_other_surgery_no_other_surgery_and_others( ], } - def test_left_breast_other_surgery_no_other_surgery_and_others(self, clinical_user): - appointment = AppointmentFactory() - request = RequestFactory().get("/test-form") - request.user = clinical_user - + def test_left_breast_other_surgery_no_other_surgery_and_others(self): form = MastectomyOrLumpectomyHistoryForm( QueryDict( urlencode( @@ -103,7 +96,6 @@ def test_left_breast_other_surgery_no_other_surgery_and_others(self, clinical_us doseq=True, ), ), - participant=appointment.participant, ) assert not form.is_valid() @@ -123,11 +115,7 @@ def test_left_breast_other_surgery_no_other_surgery_and_others(self, clinical_us 3000, ], ) - def test_year_of_surgery_outside_range(self, clinical_user, year_of_surgery): - appointment = AppointmentFactory() - request = RequestFactory().get("/test-form") - request.user = clinical_user - + def test_year_of_surgery_outside_range(self, year_of_surgery): form = MastectomyOrLumpectomyHistoryForm( QueryDict( urlencode( @@ -146,7 +134,6 @@ def test_year_of_surgery_outside_range(self, clinical_user, year_of_surgery): doseq=True, ), ), - participant=appointment.participant, ) assert not form.is_valid() @@ -156,11 +143,7 @@ def test_year_of_surgery_outside_range(self, clinical_user, year_of_surgery): ], } - def test_year_of_surgery_invalid(self, clinical_user): - appointment = AppointmentFactory() - request = RequestFactory().get("/test-form") - request.user = clinical_user - + def test_year_of_surgery_invalid(self): form = MastectomyOrLumpectomyHistoryForm( QueryDict( urlencode( @@ -179,7 +162,6 @@ def test_year_of_surgery_invalid(self, clinical_user): doseq=True, ), ), - participant=appointment.participant, ) assert not form.is_valid() @@ -187,11 +169,7 @@ def test_year_of_surgery_invalid(self, clinical_user): "year_of_surgery": ["Enter a whole number."], } - def test_other_reason_without_details(self, clinical_user): - appointment = AppointmentFactory() - request = RequestFactory().get("/test-form") - request.user = clinical_user - + def test_other_reason_without_details(self): form = MastectomyOrLumpectomyHistoryForm( QueryDict( urlencode( @@ -209,7 +187,6 @@ def test_other_reason_without_details(self, clinical_user): doseq=True, ), ), - participant=appointment.participant, ) assert not form.is_valid() @@ -217,10 +194,8 @@ def test_other_reason_without_details(self, clinical_user): "surgery_other_reason_details": ["Provide details of the surgery"], } - def test_other_reason_details_when_not_other_reason(self, clinical_user): + def test_other_reason_details_when_not_other_reason(self, dummy_request): appointment = AppointmentFactory() - request = RequestFactory().get("/test-form") - request.user = clinical_user form = MastectomyOrLumpectomyHistoryForm( QueryDict( @@ -240,12 +215,11 @@ def test_other_reason_details_when_not_other_reason(self, clinical_user): doseq=True, ), ), - participant=appointment.participant, ) assert form.is_valid() - obj = form.create(appointment=appointment, request=request) + obj = form.create(appointment=appointment, request=dummy_request) obj.refresh_from_db() assert obj.appointment == appointment @@ -315,20 +289,17 @@ def test_other_reason_details_when_not_other_reason(self, clinical_user): }, ], ) - def test_success(self, clinical_user, data): + def test_success(self, clinical_user, data, dummy_request): appointment = AppointmentFactory() - request = RequestFactory().get("/test-form") - request.user = clinical_user form = MastectomyOrLumpectomyHistoryForm( QueryDict(urlencode(data, doseq=True)), - participant=appointment.participant, ) assert form.is_valid() existing_log_count = AuditLog.objects.count() - obj = form.create(appointment=appointment, request=request) + obj = form.create(appointment=appointment, request=dummy_request) assert AuditLog.objects.count() == existing_log_count + 1 audit_log = AuditLog.objects.filter( object_id=obj.pk, operation=AuditLog.Operations.CREATE @@ -356,3 +327,84 @@ def create_year_outside_range_error_messsage(self, request_year): if request_year > max_year else (f"Year must be {min_year} or later") ) + + +@pytest.mark.django_db +class TestUpdateMastectomyOrLumpectomyHistoryForm: + @pytest.fixture + def instance(self): + return MastectomyOrLumpectomyHistoryItemFactory( + right_breast_procedure=MastectomyOrLumpectomyHistoryItem.Procedure.NO_PROCEDURE, + left_breast_procedure=MastectomyOrLumpectomyHistoryItem.Procedure.NO_PROCEDURE, + right_breast_other_surgery=[ + MastectomyOrLumpectomyHistoryItem.Surgery.NO_OTHER_SURGERY, + ], + left_breast_other_surgery=[ + MastectomyOrLumpectomyHistoryItem.Surgery.NO_OTHER_SURGERY, + ], + year_of_surgery=None, + surgery_reason=MastectomyOrLumpectomyHistoryItem.SurgeryReason.RISK_REDUCTION, + additional_details="", + ) + + def test_no_data(self, instance): + form = MastectomyOrLumpectomyHistoryForm(QueryDict(), instance=instance) + + assert not form.is_valid() + assert form.errors == { + "right_breast_procedure": [ + "Select which procedure they have had in the right breast", + ], + "left_breast_procedure": [ + "Select which procedure they have had in the left breast", + ], + "right_breast_other_surgery": [ + "Select any other surgery they have had in the right breast", + ], + "left_breast_other_surgery": [ + "Select any other surgery they have had in the left breast", + ], + "surgery_reason": ["Select the reason for surgery"], + } + + @pytest.mark.parametrize( + "data", + [ + { + "right_breast_procedure": MastectomyOrLumpectomyHistoryItem.Procedure.LUMPECTOMY, + "left_breast_procedure": MastectomyOrLumpectomyHistoryItem.Procedure.LUMPECTOMY, + "right_breast_other_surgery": [ + MastectomyOrLumpectomyHistoryItem.Surgery.RECONSTRUCTION + ], + "left_breast_other_surgery": [ + MastectomyOrLumpectomyHistoryItem.Surgery.RECONSTRUCTION + ], + "year_of_surgery": datetime.date.today().year, + "surgery_reason": MastectomyOrLumpectomyHistoryItem.SurgeryReason.OTHER_REASON, + "surgery_other_reason_details": "surgery other details", + "additional_details": "additional details", + }, + ], + ) + def test_success(self, instance, data, dummy_request): + form = MastectomyOrLumpectomyHistoryForm( + QueryDict(urlencode(data, doseq=True)), + instance=instance, + ) + + assert form.is_valid() + + obj = form.update(request=dummy_request) + + obj.refresh_from_db() + assert obj.appointment == instance.appointment + assert obj.right_breast_procedure == data.get("right_breast_procedure") + assert obj.left_breast_procedure == data.get("left_breast_procedure") + assert obj.right_breast_other_surgery == data.get("right_breast_other_surgery") + assert obj.left_breast_other_surgery == data.get("left_breast_other_surgery") + assert obj.year_of_surgery == data.get("year_of_surgery", None) + assert obj.surgery_reason == data.get("surgery_reason", "") + assert obj.surgery_other_reason_details == data.get( + "surgery_other_reason_details", "" + ) + assert obj.additional_details == data.get("additional_details", "") diff --git a/manage_breast_screening/mammograms/tests/presenters/test_mastectomy_or_lumpectomy_history_item_presenter.py b/manage_breast_screening/mammograms/tests/presenters/test_mastectomy_or_lumpectomy_history_item_presenter.py index 65783a21a..b330a561d 100644 --- a/manage_breast_screening/mammograms/tests/presenters/test_mastectomy_or_lumpectomy_history_item_presenter.py +++ b/manage_breast_screening/mammograms/tests/presenters/test_mastectomy_or_lumpectomy_history_item_presenter.py @@ -79,3 +79,27 @@ def test_single(self): }, ], } + + def test_change_link(self): + item = MastectomyOrLumpectomyHistoryItemFactory.build( + additional_details="Some additional details", + ) + + presenter = MastectomyOrLumpectomyHistoryItemPresenter(item) + assert presenter.change_link == { + "href": f"/mammograms/{item.appointment_id}/record-medical-information/mastectomy-or-lumpectomy-history/{item.pk}", + "text": "Change", + "visually_hidden_text": " mastectomy or lumpectomy item", + } + + def test_change_link_with_counter(self): + item = MastectomyOrLumpectomyHistoryItemFactory.build( + additional_details="Some additional details", + ) + + presenter = MastectomyOrLumpectomyHistoryItemPresenter(item, counter=2) + assert presenter.change_link == { + "href": f"/mammograms/{item.appointment_id}/record-medical-information/mastectomy-or-lumpectomy-history/{item.pk}", + "text": "Change", + "visually_hidden_text": " mastectomy or lumpectomy item 2", + } diff --git a/manage_breast_screening/mammograms/tests/presenters/test_medical_information_presenter.py b/manage_breast_screening/mammograms/tests/presenters/test_medical_information_presenter.py index df043e5bf..15575bf82 100644 --- a/manage_breast_screening/mammograms/tests/presenters/test_medical_information_presenter.py +++ b/manage_breast_screening/mammograms/tests/presenters/test_medical_information_presenter.py @@ -11,6 +11,7 @@ AppointmentFactory, CystHistoryItemFactory, ImplantedMedicalDeviceHistoryItemFactory, + MastectomyOrLumpectomyHistoryItemFactory, SymptomFactory, ) @@ -223,3 +224,31 @@ def test_mastectomy_or_lumpectomy_history_link(self): "href": f"/mammograms/{appointment.pk}/record-medical-information/mastectomy-or-lumpectomy-history/", "text": "Add mastectomy or lumpectomy history", } + + def test_mastectomy_or_lumpectomy_history_items_have_a_counter(self): + appointment = AppointmentFactory() + MastectomyOrLumpectomyHistoryItemFactory.create_batch( + 2, appointment=appointment + ) + + counters = [ + item.counter + for item in MedicalInformationPresenter( + appointment + ).mastectomy_or_lumpectomy_history + ] + + assert counters == [1, 2] + + def test_single_mastectomy_or_lumpectomy_history_item_has_no_counter(self): + appointment = AppointmentFactory() + MastectomyOrLumpectomyHistoryItemFactory.create(appointment=appointment) + + counters = [ + item.counter + for item in MedicalInformationPresenter( + appointment + ).mastectomy_or_lumpectomy_history + ] + + assert counters == [None] diff --git a/manage_breast_screening/mammograms/tests/views/test_mastectomy_or_lumpectomy_history_views.py b/manage_breast_screening/mammograms/tests/views/test_mastectomy_or_lumpectomy_history_views.py index 24ca28908..dc8940fba 100644 --- a/manage_breast_screening/mammograms/tests/views/test_mastectomy_or_lumpectomy_history_views.py +++ b/manage_breast_screening/mammograms/tests/views/test_mastectomy_or_lumpectomy_history_views.py @@ -8,6 +8,7 @@ ) from manage_breast_screening.participants.tests.factories import ( AppointmentFactory, + MastectomyOrLumpectomyHistoryItemFactory, ) @@ -89,3 +90,74 @@ def test_invalid_post_renders_response_with_errors(self, clinical_user_client): """, response.text, ) + + +@pytest.mark.django_db +class TestUpdateMastectomyOrLumpectomyHistoryView: + @pytest.fixture + def appointment(self, clinical_user_client): + return AppointmentFactory.create( + clinic_slot__clinic__setting__provider=clinical_user_client.current_provider + ) + + @pytest.fixture + def history_item(self, appointment): + return MastectomyOrLumpectomyHistoryItemFactory.create( + appointment=appointment, + right_breast_procedure=MastectomyOrLumpectomyHistoryItem.Procedure.NO_PROCEDURE, + left_breast_procedure=MastectomyOrLumpectomyHistoryItem.Procedure.NO_PROCEDURE, + right_breast_other_surgery=[ + MastectomyOrLumpectomyHistoryItem.Surgery.NO_OTHER_SURGERY, + ], + left_breast_other_surgery=[ + MastectomyOrLumpectomyHistoryItem.Surgery.NO_OTHER_SURGERY, + ], + year_of_surgery=None, + surgery_reason=MastectomyOrLumpectomyHistoryItem.SurgeryReason.RISK_REDUCTION, + additional_details="", + ) + + def test_renders_response(self, clinical_user_client, history_item): + response = clinical_user_client.http.get( + reverse( + "mammograms:change_mastectomy_or_lumpectomy_history_item", + kwargs={ + "pk": history_item.appointment.pk, + "history_item_pk": history_item.pk, + }, + ) + ) + assert response.status_code == 200 + + def test_valid_post_redirects_to_appointment( + self, clinical_user_client, appointment, history_item + ): + response = clinical_user_client.http.post( + reverse( + "mammograms:change_mastectomy_or_lumpectomy_history_item", + kwargs={"pk": appointment.pk, "history_item_pk": history_item.pk}, + ), + { + "right_breast_procedure": "NO_PROCEDURE", + "left_breast_procedure": "NO_PROCEDURE", + "right_breast_other_surgery": "NO_OTHER_SURGERY", + "left_breast_other_surgery": "NO_OTHER_SURGERY", + "surgery_reason": "RISK_REDUCTION", + }, + ) + assertRedirects( + response, + reverse( + "mammograms:record_medical_information", + kwargs={"pk": appointment.pk}, + ), + ) + assertMessages( + response, + [ + messages.Message( + level=messages.SUCCESS, + message="Details of mastectomy or lumpectomy updated", + ) + ], + ) diff --git a/manage_breast_screening/mammograms/urls.py b/manage_breast_screening/mammograms/urls.py index 2880e7961..0f847034d 100644 --- a/manage_breast_screening/mammograms/urls.py +++ b/manage_breast_screening/mammograms/urls.py @@ -170,4 +170,9 @@ mastectomy_or_lumpectomy_history_view.AddMastectomyOrLumpectomyHistoryView.as_view(), name="add_mastectomy_or_lumpectomy_history_item", ), + path( + "/record-medical-information/mastectomy-or-lumpectomy-history/", + mastectomy_or_lumpectomy_history_view.UpdateMastectomyOrLumpectomyHistoryView.as_view(), + name="change_mastectomy_or_lumpectomy_history_item", + ), ] diff --git a/manage_breast_screening/mammograms/views/mastectomy_or_lumpectomy_history_view.py b/manage_breast_screening/mammograms/views/mastectomy_or_lumpectomy_history_view.py index eef6180c7..9988a68ad 100644 --- a/manage_breast_screening/mammograms/views/mastectomy_or_lumpectomy_history_view.py +++ b/manage_breast_screening/mammograms/views/mastectomy_or_lumpectomy_history_view.py @@ -1,21 +1,28 @@ +import logging from functools import cached_property from django.contrib import messages +from django.http import Http404 +from django.shortcuts import redirect from django.urls import reverse from django.views.generic import FormView from manage_breast_screening.mammograms.presenters.medical_information_presenter import ( MedicalInformationPresenter, ) +from manage_breast_screening.participants.models.mastectomy_or_lumpectomy_history_item import ( + MastectomyOrLumpectomyHistoryItem, +) from ..forms.mastectomy_or_lumpectomy_history_form import ( MastectomyOrLumpectomyHistoryForm, ) from .mixins import InProgressAppointmentMixin +logger = logging.getLogger(__name__) -class AddMastectomyOrLumpectomyHistoryView(InProgressAppointmentMixin, FormView): - form_class = MastectomyOrLumpectomyHistoryForm + +class BaseMastectomyOrLumpectomyHistoryView(InProgressAppointmentMixin, FormView): template_name = "mammograms/medical_information/medical_history/forms/mastectomy_or_lumpectomy_history.jinja" def get_success_url(self): @@ -23,17 +30,6 @@ def get_success_url(self): "mammograms:record_medical_information", kwargs={"pk": self.appointment.pk} ) - def form_valid(self, form): - form.create(appointment=self.appointment, request=self.request) - - messages.add_message( - self.request, - messages.SUCCESS, - "Details of mastectomy or lumpectomy added", - ) - - return super().form_valid(form) - def get_back_link_params(self): return { "href": reverse( @@ -53,8 +49,6 @@ def get_context_data(self, **kwargs): "back_link_params": self.get_back_link_params(), "caption": participant.full_name, "participant_first_name": participant.first_name, - "heading": "Add details of mastectomy or lumpectomy", - "page_title": "Add details of mastectomy or lumpectomy", "presenter": MedicalInformationPresenter(self.appointment), }, ) @@ -65,7 +59,85 @@ def get_context_data(self, **kwargs): def participant(self): return self.appointment.participant + +class AddMastectomyOrLumpectomyHistoryView(BaseMastectomyOrLumpectomyHistoryView): + form_class = MastectomyOrLumpectomyHistoryForm + + def form_valid(self, form): + form.create(appointment=self.appointment, request=self.request) + + messages.add_message( + self.request, + messages.SUCCESS, + "Details of mastectomy or lumpectomy added", + ) + + return super().form_valid(form) + + def get_context_data(self, **kwargs): + context = super().get_context_data() + + context.update( + { + "heading": "Add details of mastectomy or lumpectomy", + "page_title": "Add details of mastectomy or lumpectomy", + }, + ) + + return context + + +class UpdateMastectomyOrLumpectomyHistoryView(BaseMastectomyOrLumpectomyHistoryView): + form_class = MastectomyOrLumpectomyHistoryForm + + def get_instance(self): + try: + return MastectomyOrLumpectomyHistoryItem.objects.get( + pk=self.kwargs["history_item_pk"], + appointment_id=self.kwargs["pk"], + ) + except MastectomyOrLumpectomyHistoryItem.DoesNotExist: + logger.exception("History item does not exist for kwargs=%s", self.kwargs) + return None + + def get(self, *args, **kwargs): + self.instance = self.get_instance() + if not self.instance: + # For a GET request, if the page shouldn't exist we can + # safely redirect to the hub page. + return redirect(self.get_success_url()) + return super().get(*args, **kwargs) + + def post(self, *args, **kwargs): + self.instance = self.get_instance() + if not self.instance: + raise Http404 + return super().post(*args, **kwargs) + def get_form_kwargs(self): kwargs = super().get_form_kwargs() - kwargs["participant"] = self.participant + kwargs["instance"] = self.instance return kwargs + + def form_valid(self, form): + form.update(request=self.request) + + messages.add_message( + self.request, + messages.SUCCESS, + "Details of mastectomy or lumpectomy updated", + ) + + return super().form_valid(form) + + def get_context_data(self, **kwargs): + context = super().get_context_data() + + context.update( + { + "heading": "Edit details of mastectomy or lumpectomy", + "page_title": "Details of the mastectomy or lumpectomy", + }, + ) + + return context diff --git a/manage_breast_screening/participants/models/mastectomy_or_lumpectomy_history_item.py b/manage_breast_screening/participants/models/mastectomy_or_lumpectomy_history_item.py index 91d0b3c9b..d02d57c8c 100644 --- a/manage_breast_screening/participants/models/mastectomy_or_lumpectomy_history_item.py +++ b/manage_breast_screening/participants/models/mastectomy_or_lumpectomy_history_item.py @@ -49,3 +49,7 @@ class SurgeryReason(models.TextChoices): surgery_reason = models.CharField(choices=SurgeryReason) surgery_other_reason_details = models.CharField(blank=True, null=False, default="") additional_details = models.TextField(blank=True, null=False, default="") + + @property + def participant(self): + return self.appointment.participant diff --git a/manage_breast_screening/tests/system/clinical/test_mastectomy_or_lumpectomy_history.py b/manage_breast_screening/tests/system/clinical/test_mastectomy_or_lumpectomy_history.py index ae25710ba..9b0216cc1 100644 --- a/manage_breast_screening/tests/system/clinical/test_mastectomy_or_lumpectomy_history.py +++ b/manage_breast_screening/tests/system/clinical/test_mastectomy_or_lumpectomy_history.py @@ -27,6 +27,14 @@ def test_adding_mastectomy_or_lumpectomy(self): self.and_the_mastectomy_or_lumpectomy_is_listed() self.and_the_message_says_mastectomy_or_lumpectomy_added() + self.when_i_click_change() + self.then_i_see_the_edit_mastectomy_or_lumpectomy_form() + self.when_i_update_additional_details() + self.and_i_click_save() + self.then_i_am_back_on_the_medical_information_page() + self.and_the_mastectomy_or_lumpectomy_is_updated() + self.and_the_message_says_mastectomy_or_lumpectomy_updated() + def test_accessibility(self): self.given_i_am_logged_in_as_a_clinical_user() self.and_there_is_an_appointment() @@ -157,3 +165,33 @@ def and_the_message_says_mastectomy_or_lumpectomy_added(self): expect(alert).to_contain_text("Success") expect(alert).to_contain_text("Details of mastectomy or lumpectomy added") + + def when_i_click_change(self): + self.page.get_by_text("Change mastectomy or lumpectomy item").click() + + def then_i_see_the_edit_mastectomy_or_lumpectomy_form(self): + expect( + self.page.get_by_text("Edit details of mastectomy or lumpectomy") + ).to_be_visible() + self.assert_page_title_contains("Details of the mastectomy or lumpectomy") + + def when_i_update_additional_details(self): + self.page.get_by_label("Additional details (optional)", exact=True).fill( + "updated additional details for test of mastectomy or lumpectomy details" + ) + + def and_the_mastectomy_or_lumpectomy_is_updated(self): + key = self.page.locator( + ".nhsuk-summary-list__key", + has=self.page.get_by_text("Mastectomy or lumpectomy history", exact=True), + ) + row = self.page.locator(".nhsuk-summary-list__row").filter(has=key) + expect(row).to_contain_text( + "updated additional details for test of mastectomy or lumpectomy details" + ) + + def and_the_message_says_mastectomy_or_lumpectomy_updated(self): + alert = self.page.get_by_role("alert") + + expect(alert).to_contain_text("Success") + expect(alert).to_contain_text("Details of mastectomy or lumpectomy updated")