diff --git a/manage_breast_screening/assets/sass/main.scss b/manage_breast_screening/assets/sass/main.scss index f550a039b..5e7d09862 100644 --- a/manage_breast_screening/assets/sass/main.scss +++ b/manage_breast_screening/assets/sass/main.scss @@ -9,6 +9,8 @@ @forward "components/secondary-navigation"; @forward "components/special-appointment-banner"; +$color_app-dark-blue: #00386e; + h1 { @extend %nhsuk-heading-l; } @@ -80,3 +82,45 @@ a[href="#"] { } } } + +.app-status-bar { + background-color: $color_app-dark-blue; + color: $color_nhsuk-white; + padding: nhsuk-spacing(2) 0; + border-bottom: 1px solid nhsuk-colour("grey-4"); +} + +.app-status-bar a { + color: $color_nhsuk-white; +} +.app-status-bar a:hover, +.app-status-bar a:active { + color: $color_nhsuk-white; +} +.app-status-bar a:focus { + color: $color_nhsuk-black; +} + +.app-status-bar__row { + display: flex; + flex-wrap: wrap; + gap: nhsuk-spacing(4); + align-items: center; +} + +.app-status-bar__row + .app-status-bar__row { + margin-top: nhsuk-spacing(2); + padding-top: nhsuk-spacing(2); + border-top: 1px solid rgba($color_nhsuk-white, 0.2); +} + +.app-status-bar__item { + display: flex; + gap: nhsuk-spacing(2); + align-items: center; +} + +.app-status-bar__key { + @include nhsuk-typography-weight-bold(true); + opacity: 0.9; +} diff --git a/manage_breast_screening/core/jinja2/components/appointment-status-bar.jinja b/manage_breast_screening/core/jinja2/components/appointment-status-bar.jinja new file mode 100644 index 000000000..da3205e03 --- /dev/null +++ b/manage_breast_screening/core/jinja2/components/appointment-status-bar.jinja @@ -0,0 +1,34 @@ +{% from 'nhsuk/components/tag/macro.jinja' import tag %} + +{% macro appointment_status_bar(user, presented_status_bar) %} + {% if presented_status_bar and presented_status_bar.show_status_bar_for(user) %} +
+ {% endif %} +{% endmacro %} diff --git a/manage_breast_screening/core/jinja2/layout-app.jinja b/manage_breast_screening/core/jinja2/layout-app.jinja index 754d99f0e..314aa031f 100644 --- a/manage_breast_screening/core/jinja2/layout-app.jinja +++ b/manage_breast_screening/core/jinja2/layout-app.jinja @@ -1,5 +1,6 @@ {% from 'nhsuk/components/header/macro.jinja' import header %} {% from "notification-banner/macro.jinja" import notificationBanner %} +{% from 'components/appointment-status-bar.jinja' import appointment_status_bar %} {% set assetPath = STATIC_URL ~ "/assets" %} {% extends "nhsuk/template.jinja" %} @@ -33,6 +34,10 @@ ] } }) }} + + {{ + appointment_status_bar(request.user, presented_appointment.status_bar) + }} {% endblock %} {% block content %} @@ -71,4 +76,4 @@ {% block bodyEnd %} -{% endblock %}} +{% endblock %} diff --git a/manage_breast_screening/core/utils/string_formatting.py b/manage_breast_screening/core/utils/string_formatting.py index 3d4266bb6..fefb0ffe6 100644 --- a/manage_breast_screening/core/utils/string_formatting.py +++ b/manage_breast_screening/core/utils/string_formatting.py @@ -40,9 +40,9 @@ def format_age(value: int) -> str: Format an age in years as a string >>> format_age(64) - '64 years old' + '64 years' """ - return f"{value} years old" + return f"{value} years" def format_phone_number(value: str) -> str: diff --git a/manage_breast_screening/mammograms/presenters/appointment_presenters.py b/manage_breast_screening/mammograms/presenters/appointment_presenters.py index 22817cc97..36f4d7149 100644 --- a/manage_breast_screening/mammograms/presenters/appointment_presenters.py +++ b/manage_breast_screening/mammograms/presenters/appointment_presenters.py @@ -120,6 +120,32 @@ def note(self): except AppointmentNote.DoesNotExist: return None + @cached_property + def status_bar(self): + return StatusBarPresenter(self) + + +class StatusBarPresenter: + def __init__(self, appointment): + self.appointment = appointment + self.clinic_slot = appointment.clinic_slot + self.participant = appointment.participant + + def show_status_bar_for(self, user): + # The appointment status bar should only display if the current user is the one that has the appointment 'in progress' + current_status = self.appointment._appointment.current_status + return ( + current_status.state == AppointmentStatus.IN_PROGRESS + and user.nhs_uid == current_status.created_by.nhs_uid + ) + + @property + def tag_properties(self): + return { + "classes": "nhsuk-tag--yellow nhsuk-u-margin-left-1", + "text": "Special appointment", + } + class ClinicSlotPresenter: def __init__(self, clinic_slot): @@ -143,6 +169,15 @@ def slot_time_and_clinic_date(self): return f"{format_time(clinic_slot.starts_at)} ({clinic_slot.duration_in_minutes} minutes) - {format_date(clinic.starts_at)} ({format_relative_date(clinic.starts_at)})" + @cached_property + def clinic_date_and_slot_time(self): + clinic_slot = self._clinic_slot + clinic = self._clinic + + return ( + f"{format_date(clinic.starts_at)} at {format_time(clinic_slot.starts_at)}" + ) + @cached_property def starts_at(self): return format_time(self._clinic_slot.starts_at) diff --git a/manage_breast_screening/mammograms/tests/presenters/test_appointment_presenters.py b/manage_breast_screening/mammograms/tests/presenters/test_appointment_presenters.py index 5893051bf..43b9d21b2 100644 --- a/manage_breast_screening/mammograms/tests/presenters/test_appointment_presenters.py +++ b/manage_breast_screening/mammograms/tests/presenters/test_appointment_presenters.py @@ -200,6 +200,68 @@ def test_status_attribution( assert presenter.status_attribution == expected_result +class TestStatusBarPresenter: + @pytest.fixture + def mock_appointment(self): + mock = MagicMock(spec=Appointment) + mock.screening_episode.participant.nhs_number = "99900900829" + mock.screening_episode.participant.pk = uuid4() + return mock + + @pytest.fixture + def mock_user(self): + return MagicMock(spec=User) + + def test_show_status_bar_when_in_progress_and_user_is_owner( + self, mock_appointment, mock_user + ): + mock_appointment.current_status.state = AppointmentStatus.IN_PROGRESS + mock_user.nhs_uid = "user-123" + mock_appointment.current_status.created_by.nhs_uid = "user-123" + presenter = AppointmentPresenter(mock_appointment) + assert presenter.status_bar.show_status_bar_for(mock_user) + + def test_show_status_bar_when_user_is_not_owner(self, mock_appointment, mock_user): + mock_appointment.current_status.state = AppointmentStatus.IN_PROGRESS + mock_user.nhs_uid = "user-123" + mock_appointment.current_status.created_by.nhs_uid = "user-456" + presenter = AppointmentPresenter(mock_appointment) + assert not presenter.status_bar.show_status_bar_for(mock_user) + + @pytest.mark.parametrize( + "current_state", + [ + AppointmentStatus.CONFIRMED, + AppointmentStatus.CHECKED_IN, + AppointmentStatus.DID_NOT_ATTEND, + AppointmentStatus.SCREENED, + AppointmentStatus.PARTIALLY_SCREENED, + AppointmentStatus.ATTENDED_NOT_SCREENED, + ], + ) + def test_dont_show_status_bar_when_not_in_progress( + self, mock_appointment, mock_user, current_state + ): + mock_appointment.current_status.state = current_state + mock_user.nhs_uid = "user-123" + mock_appointment.current_status.created_by.nhs_uid = "user-123" + presenter = AppointmentPresenter(mock_appointment) + assert not presenter.status_bar.show_status_bar_for(mock_user) + + def test_tag_properties(self, mock_appointment): + presenter = AppointmentPresenter(mock_appointment) + assert presenter.status_bar.tag_properties == { + "classes": "nhsuk-tag--yellow nhsuk-u-margin-left-1", + "text": "Special appointment", + } + + def test_attributes(self, mock_appointment): + presenter = AppointmentPresenter(mock_appointment) + assert presenter.status_bar.appointment == presenter + assert presenter.status_bar.clinic_slot == presenter.clinic_slot + assert presenter.status_bar.participant == presenter.participant + + class TestClinicSlotPresenter: @pytest.fixture def clinic_slot_mock(self): @@ -229,6 +291,17 @@ def test_slot_time_and_clinic_date(self, clinic_slot_mock): == "9:30am (30 minutes) - 2 January 2025 (4 months, 17 days ago)" ) + @time_machine.travel(datetime(2025, 5, 19, tzinfo=tz.utc)) + def test_clinic_date_and_slot_time(self, clinic_slot_mock): + clinic_slot_mock.starts_at = datetime(2025, 1, 2, 9, 30) + clinic_slot_mock.duration_in_minutes = 30 + clinic_slot_mock.clinic.starts_at = date(2025, 1, 2) + + assert ( + ClinicSlotPresenter(clinic_slot_mock).clinic_date_and_slot_time + == "2 January 2025 at 9:30am" + ) + class TestSpecialAppointmentPresenter: def test_change_url(self): diff --git a/manage_breast_screening/mammograms/views/appointment_views.py b/manage_breast_screening/mammograms/views/appointment_views.py index 5e428261c..a132d78eb 100644 --- a/manage_breast_screening/mammograms/views/appointment_views.py +++ b/manage_breast_screening/mammograms/views/appointment_views.py @@ -168,16 +168,22 @@ class ConfirmIdentity(InProgressAppointmentMixin, TemplateView): template_name = "mammograms/confirm_identity.jinja" def get_context_data(self, pk, **kwargs): + context = super().get_context_data() + participant = self.appointment.participant - return { - "heading": "Confirm identity", - "page_title": "Confirm identity", - "presented_participant": ParticipantPresenter(participant), - "appointment_cannot_proceed_href": reverse( - "mammograms:appointment_cannot_go_ahead", kwargs={"pk": pk} - ), - } + context.update( + { + "heading": "Confirm identity", + "page_title": "Confirm identity", + "presented_participant": ParticipantPresenter(participant), + "appointment_cannot_proceed_href": reverse( + "mammograms:appointment_cannot_go_ahead", kwargs={"pk": pk} + ), + }, + ) + + return context def post(self, request, pk): return redirect("mammograms:ask_for_medical_information", pk=pk) diff --git a/manage_breast_screening/mammograms/views/mixins.py b/manage_breast_screening/mammograms/views/mixins.py index 2cf387a6c..879725bf6 100644 --- a/manage_breast_screening/mammograms/views/mixins.py +++ b/manage_breast_screening/mammograms/views/mixins.py @@ -5,6 +5,9 @@ from rules.contrib.views import PermissionRequiredMixin from manage_breast_screening.auth.models import Permission +from manage_breast_screening.mammograms.presenters.appointment_presenters import ( + AppointmentPresenter, +) from manage_breast_screening.participants.models import Appointment @@ -33,6 +36,17 @@ def appointment(self): def participant(self): return self.appointment.participant + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + + context.update( + { + "presented_appointment": AppointmentPresenter(self.appointment), + }, + ) + + return context + class InProgressAppointmentMixin(PermissionRequiredMixin, AppointmentMixin): """ diff --git a/manage_breast_screening/participants/tests/factories.py b/manage_breast_screening/participants/tests/factories.py index 72faff128..3978e9306 100644 --- a/manage_breast_screening/participants/tests/factories.py +++ b/manage_breast_screening/participants/tests/factories.py @@ -160,6 +160,14 @@ def current_status(obj, create, extracted, **kwargs): AppointmentStatusFactory.create(state=extracted, appointment=obj) ) + # Allow passing an explicit status and created_by user + # e.g. `current_status_params={'state': AppointmentStatus.IN_PROGRESS, 'created_by': self.current_user}` + @post_generation + def current_status_params(obj, create, extracted, **kwargs): + if not create or not extracted: + return + obj.statuses.add(AppointmentStatusFactory.create(appointment=obj, **extracted)) + class AppointmentNoteFactory(DjangoModelFactory): class Meta: diff --git a/manage_breast_screening/participants/tests/test_presenters.py b/manage_breast_screening/participants/tests/test_presenters.py index 1bc7b0aa5..f3b1420d4 100644 --- a/manage_breast_screening/participants/tests/test_presenters.py +++ b/manage_breast_screening/participants/tests/test_presenters.py @@ -54,7 +54,7 @@ def test_presented_values(self, participant): assert result.phone == "07700 900000" assert result.nhs_number == "999 009 00829" assert result.date_of_birth == "1 January 1955" - assert result.age == "70 years old" + assert result.age == "70 years" assert result.risk_level == "" assert result.url == f"/participants/{participant.pk}/" diff --git a/manage_breast_screening/tests/system/clinical/test_benign_lump_history.py b/manage_breast_screening/tests/system/clinical/test_benign_lump_history.py index bfbb26c91..9bfcb3600 100644 --- a/manage_breast_screening/tests/system/clinical/test_benign_lump_history.py +++ b/manage_breast_screening/tests/system/clinical/test_benign_lump_history.py @@ -1,6 +1,8 @@ from django.urls import reverse from playwright.sync_api import expect +from manage_breast_screening.core.utils.string_formatting import format_nhs_number +from manage_breast_screening.participants.models import AppointmentStatus from manage_breast_screening.participants.models.medical_history.benign_lump_history_item import ( BenignLumpHistoryItem, ) @@ -21,6 +23,7 @@ def test_adding_a_benign_lump_history_item(self): self.and_i_am_on_the_record_medical_information_page() self.when_i_click_on_benign_lumps() self.then_i_see_the_add_benign_lump_history_form() + self.and_i_see_the_appointment_status_bar() self.when_i_try_to_save_without_entering_benign_lump_details() self.then_i_see_validation_errors_for_missing_benign_lump_details() @@ -63,6 +66,10 @@ def and_there_is_an_appointment(self): self.appointment = AppointmentFactory( screening_episode=self.screening_episode, clinic_slot__clinic__setting__provider=self.current_provider, + current_status_params={ + "state": AppointmentStatus.IN_PROGRESS, + "created_by": self.current_user, + }, ) def and_i_am_on_the_record_medical_information_page(self): @@ -74,6 +81,13 @@ def and_i_am_on_the_record_medical_information_page(self): ) ) + def and_i_see_the_appointment_status_bar(self): + status_bar = self.page.locator("div.app-status-bar") + expect(status_bar).to_contain_text( + format_nhs_number(self.participant.nhs_number) + ) + expect(status_bar).to_contain_text(self.participant.full_name) + def when_i_click_on_benign_lumps(self): self.page.get_by_role("button").filter(has_text="Benign lumps").click() diff --git a/manage_breast_screening/tests/system/clinical/test_breast_augmentation_history.py b/manage_breast_screening/tests/system/clinical/test_breast_augmentation_history.py index e2824ac35..ed512036d 100644 --- a/manage_breast_screening/tests/system/clinical/test_breast_augmentation_history.py +++ b/manage_breast_screening/tests/system/clinical/test_breast_augmentation_history.py @@ -1,6 +1,8 @@ from django.urls import reverse from playwright.sync_api import expect +from manage_breast_screening.core.utils.string_formatting import format_nhs_number +from manage_breast_screening.participants.models import AppointmentStatus from manage_breast_screening.participants.tests.factories import ( AppointmentFactory, ParticipantFactory, @@ -15,8 +17,10 @@ def test_adding_breast_augmentation(self): self.given_i_am_logged_in_as_a_clinical_user() self.and_there_is_an_appointment() self.and_i_am_on_the_record_medical_information_page() + self.and_i_see_the_appointment_status_bar() self.when_i_click_on_breast_implants_or_augmentation() self.then_i_see_the_add_breast_augmentation_form() + self.and_i_see_the_appointment_status_bar() self.when_i_click_save_without_entering_details() self.then_i_see_validation_errors_for_missing_breast_augmentation_details() @@ -51,6 +55,10 @@ def and_there_is_an_appointment(self): self.appointment = AppointmentFactory( screening_episode=self.screening_episode, clinic_slot__clinic__setting__provider=self.current_provider, + current_status_params={ + "state": AppointmentStatus.IN_PROGRESS, + "created_by": self.current_user, + }, ) def and_i_am_on_the_record_medical_information_page(self): @@ -75,6 +83,13 @@ def then_i_see_the_add_breast_augmentation_form(self): "Add details of breast implants or augmentation" ) + def and_i_see_the_appointment_status_bar(self): + status_bar = self.page.locator("div.app-status-bar") + expect(status_bar).to_contain_text( + format_nhs_number(self.participant.nhs_number) + ) + expect(status_bar).to_contain_text(self.participant.full_name) + def then_i_see_validation_errors_for_missing_breast_augmentation_details(self): self.expect_validation_error( error_text="Select procedures for the right breast", diff --git a/manage_breast_screening/tests/system/clinical/test_breast_cancer_history.py b/manage_breast_screening/tests/system/clinical/test_breast_cancer_history.py index 8d6774c64..bfd0ebd88 100644 --- a/manage_breast_screening/tests/system/clinical/test_breast_cancer_history.py +++ b/manage_breast_screening/tests/system/clinical/test_breast_cancer_history.py @@ -1,6 +1,8 @@ from django.urls import reverse from playwright.sync_api import expect +from manage_breast_screening.core.utils.string_formatting import format_nhs_number +from manage_breast_screening.participants.models import AppointmentStatus from manage_breast_screening.participants.tests.factories import ( AppointmentFactory, ParticipantFactory, @@ -15,8 +17,10 @@ def test_adding_and_editing_breast_cancer_history(self): self.given_i_am_logged_in_as_a_clinical_user() self.and_there_is_an_appointment() self.and_i_am_on_the_record_medical_information_page() + self.and_i_see_the_appointment_status_bar() self.when_i_click_on_breast_cancer() self.then_i_see_the_add_breast_cancer_history_form() + self.and_i_see_the_appointment_status_bar() self.when_i_select_right_breast() self.and_i_select_lumpectomy_in_right_breast() @@ -67,6 +71,10 @@ def and_there_is_an_appointment(self): self.appointment = AppointmentFactory( screening_episode=self.screening_episode, clinic_slot__clinic__setting__provider=self.current_provider, + current_status_params={ + "state": AppointmentStatus.IN_PROGRESS, + "created_by": self.current_user, + }, ) def and_i_am_on_the_record_medical_information_page(self): @@ -85,6 +93,13 @@ def then_i_see_the_add_breast_cancer_history_form(self): expect(self.page.get_by_text("Add details of breast cancer")).to_be_visible() self.assert_page_title_contains("Add details of breast cancer") + def and_i_see_the_appointment_status_bar(self): + status_bar = self.page.locator("div.app-status-bar") + expect(status_bar).to_contain_text( + format_nhs_number(self.participant.nhs_number) + ) + expect(status_bar).to_contain_text(self.participant.full_name) + def then_i_see_the_edit_breast_cancer_history_form(self): expect(self.page.get_by_text("Edit details of breast cancer")).to_be_visible() self.assert_page_title_contains("Edit details of breast cancer") diff --git a/manage_breast_screening/tests/system/clinical/test_cyst_history.py b/manage_breast_screening/tests/system/clinical/test_cyst_history.py index bf5caaabe..8bb0c10e3 100644 --- a/manage_breast_screening/tests/system/clinical/test_cyst_history.py +++ b/manage_breast_screening/tests/system/clinical/test_cyst_history.py @@ -1,6 +1,8 @@ from django.urls import reverse from playwright.sync_api import expect +from manage_breast_screening.core.utils.string_formatting import format_nhs_number +from manage_breast_screening.participants.models import AppointmentStatus from manage_breast_screening.participants.tests.factories import ( AppointmentFactory, ParticipantFactory, @@ -15,8 +17,10 @@ def test_adding_and_changing_cyst(self): self.given_i_am_logged_in_as_a_clinical_user() self.and_there_is_an_appointment() self.and_i_am_on_the_record_medical_information_page() + self.and_i_see_the_appointment_status_bar() self.when_i_click_on_cysts() self.then_i_see_the_add_cyst_form() + self.and_i_see_the_appointment_status_bar() self.when_i_select_no_treatment() self.and_i_click_save() @@ -45,6 +49,10 @@ def and_there_is_an_appointment(self): self.appointment = AppointmentFactory( screening_episode=self.screening_episode, clinic_slot__clinic__setting__provider=self.current_provider, + current_status_params={ + "state": AppointmentStatus.IN_PROGRESS, + "created_by": self.current_user, + }, ) def and_i_am_on_the_record_medical_information_page(self): @@ -63,6 +71,13 @@ def then_i_see_the_add_cyst_form(self): expect(self.page.get_by_text("Add details of cysts")).to_be_visible() self.assert_page_title_contains("Details of the cysts") + def and_i_see_the_appointment_status_bar(self): + status_bar = self.page.locator("div.app-status-bar") + expect(status_bar).to_contain_text( + format_nhs_number(self.participant.nhs_number) + ) + expect(status_bar).to_contain_text(self.participant.full_name) + def when_i_select_no_treatment(self): self.page.get_by_label("No treatment", exact=True).click() diff --git a/manage_breast_screening/tests/system/clinical/test_implanted_medical_device_history.py b/manage_breast_screening/tests/system/clinical/test_implanted_medical_device_history.py index 302a8a39f..1ab65dada 100644 --- a/manage_breast_screening/tests/system/clinical/test_implanted_medical_device_history.py +++ b/manage_breast_screening/tests/system/clinical/test_implanted_medical_device_history.py @@ -1,6 +1,8 @@ from django.urls import reverse from playwright.sync_api import expect +from manage_breast_screening.core.utils.string_formatting import format_nhs_number +from manage_breast_screening.participants.models import AppointmentStatus from manage_breast_screening.participants.tests.factories import ( AppointmentFactory, ParticipantFactory, @@ -15,8 +17,10 @@ def test_adding_and_changing_device(self): self.given_i_am_logged_in_as_a_clinical_user() self.and_there_is_an_appointment() self.and_i_am_on_the_record_medical_information_page() + self.and_i_see_the_appointment_status_bar() self.when_i_click_on_implanted_medical_device() self.then_i_see_the_add_a_implanted_medical_device_form() + self.and_i_see_the_appointment_status_bar() self.when_i_click_save_device_without_entering_details() self.then_i_see_validation_errors_for_missing_implanted_medical_device_details() @@ -51,6 +55,10 @@ def and_there_is_an_appointment(self): self.appointment = AppointmentFactory( screening_episode=self.screening_episode, clinic_slot__clinic__setting__provider=self.current_provider, + current_status_params={ + "state": AppointmentStatus.IN_PROGRESS, + "created_by": self.current_user, + }, ) def and_i_am_on_the_record_medical_information_page(self): @@ -73,6 +81,13 @@ def then_i_see_the_add_a_implanted_medical_device_form(self): ).to_be_visible() self.assert_page_title_contains("Details of the implanted medical device") + def and_i_see_the_appointment_status_bar(self): + status_bar = self.page.locator("div.app-status-bar") + expect(status_bar).to_contain_text( + format_nhs_number(self.participant.nhs_number) + ) + expect(status_bar).to_contain_text(self.participant.full_name) + def then_i_see_validation_errors_for_missing_implanted_medical_device_details(self): self.expect_validation_error( error_text="Select the device type", 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 6ca3d6b83..aadc6ee3d 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 @@ -1,6 +1,8 @@ from django.urls import reverse from playwright.sync_api import expect +from manage_breast_screening.core.utils.string_formatting import format_nhs_number +from manage_breast_screening.participants.models import AppointmentStatus from manage_breast_screening.participants.tests.factories import ( AppointmentFactory, ParticipantFactory, @@ -15,8 +17,10 @@ def test_adding_mastectomy_or_lumpectomy(self): self.given_i_am_logged_in_as_a_clinical_user() self.and_there_is_an_appointment() self.and_i_am_on_the_record_medical_information_page() + self.and_i_see_the_appointment_status_bar() self.when_i_click_on_mastectomy_or_lumpectomy() self.then_i_see_the_add_mastectomy_or_lumpectomy_form() + self.and_i_see_the_appointment_status_bar() self.when_i_click_save() self.then_i_see_validation_errors_for_missing_mastectomy_or_lumpectomy_details() @@ -48,6 +52,10 @@ def and_there_is_an_appointment(self): self.appointment = AppointmentFactory( screening_episode=self.screening_episode, clinic_slot__clinic__setting__provider=self.current_provider, + current_status_params={ + "state": AppointmentStatus.IN_PROGRESS, + "created_by": self.current_user, + }, ) def and_i_am_on_the_record_medical_information_page(self): @@ -81,6 +89,13 @@ def then_i_see_the_add_mastectomy_or_lumpectomy_form(self): kwargs={"pk": self.appointment.pk}, ) + def and_i_see_the_appointment_status_bar(self): + status_bar = self.page.locator("div.app-status-bar") + expect(status_bar).to_contain_text( + format_nhs_number(self.participant.nhs_number) + ) + expect(status_bar).to_contain_text(self.participant.full_name) + def then_i_see_validation_errors_for_missing_mastectomy_or_lumpectomy_details(self): self.expect_validation_error( error_text="Select which procedure they have had in the right breast", diff --git a/manage_breast_screening/tests/system/clinical/test_other_procedure_history.py b/manage_breast_screening/tests/system/clinical/test_other_procedure_history.py index 866b35258..7a6bfc075 100644 --- a/manage_breast_screening/tests/system/clinical/test_other_procedure_history.py +++ b/manage_breast_screening/tests/system/clinical/test_other_procedure_history.py @@ -1,6 +1,8 @@ from django.urls import reverse from playwright.sync_api import expect +from manage_breast_screening.core.utils.string_formatting import format_nhs_number +from manage_breast_screening.participants.models import AppointmentStatus from manage_breast_screening.participants.tests.factories import ( AppointmentFactory, ParticipantFactory, @@ -15,8 +17,10 @@ def test_adding_and_changing_other_procedure(self): self.given_i_am_logged_in_as_a_clinical_user() self.and_there_is_an_appointment() self.and_i_am_on_the_record_medical_information_page() + self.and_i_see_the_appointment_status_bar() self.when_i_click_on_other_procedures() self.then_i_see_the_add_other_procedure_form() + self.and_i_see_the_appointment_status_bar() self.when_i_click_save() self.then_i_see_validation_error_for_missing_procedure() @@ -56,6 +60,10 @@ def and_there_is_an_appointment(self): self.appointment = AppointmentFactory( screening_episode=self.screening_episode, clinic_slot__clinic__setting__provider=self.current_provider, + current_status_params={ + "state": AppointmentStatus.IN_PROGRESS, + "created_by": self.current_user, + }, ) def and_i_am_on_the_record_medical_information_page(self): @@ -74,6 +82,13 @@ def then_i_see_the_add_other_procedure_form(self): expect(self.page.get_by_text("Add details of other procedures")).to_be_visible() self.assert_page_title_contains("Details of the other procedure") + def and_i_see_the_appointment_status_bar(self): + status_bar = self.page.locator("div.app-status-bar") + expect(status_bar).to_contain_text( + format_nhs_number(self.participant.nhs_number) + ) + expect(status_bar).to_contain_text(self.participant.full_name) + def then_i_see_validation_error_for_missing_procedure(self): self.expect_validation_error( error_text="Select the procedure", diff --git a/manage_breast_screening/tests/system/clinical/test_recording_a_mammogram.py b/manage_breast_screening/tests/system/clinical/test_recording_a_mammogram.py index d11399605..e3e32a820 100644 --- a/manage_breast_screening/tests/system/clinical/test_recording_a_mammogram.py +++ b/manage_breast_screening/tests/system/clinical/test_recording_a_mammogram.py @@ -3,6 +3,7 @@ from django.urls import reverse from playwright.sync_api import expect +from manage_breast_screening.core.utils.string_formatting import format_nhs_number from manage_breast_screening.participants.tests.factories import ( AppointmentFactory, ParticipantFactory, @@ -36,6 +37,7 @@ def test_recording_a_mammogram_without_capturing_medical_information(self): self.when_i_click_start_this_appointment() self.then_i_should_be_on_the_confirm_identity_page() + self.and_i_see_the_appointment_status_bar() self.and_i_should_see_the_participant_details() self.when_i_click_confirm_identity() @@ -55,6 +57,7 @@ def test_capturing_medical_information(self): self.when_i_click_start_this_appointment() self.then_i_should_be_on_the_confirm_identity_page() + self.and_i_see_the_appointment_status_bar() self.when_i_click_confirm_identity() self.then_i_should_be_on_the_medical_information_page() @@ -77,6 +80,7 @@ def test_filling_out_forms_incorrectly(self): self.when_i_click_start_this_appointment() self.then_i_should_be_on_the_confirm_identity_page() + self.and_i_see_the_appointment_status_bar() self.when_i_click_confirm_identity() self.then_i_should_be_on_the_medical_information_page() @@ -157,6 +161,13 @@ def then_i_should_be_on_the_confirm_identity_page(self): expect(self.page).to_have_url(re.compile(path)) self.assert_page_title_contains("Confirm identity") + def and_i_see_the_appointment_status_bar(self): + status_bar = self.page.locator("div.app-status-bar") + expect(status_bar).to_contain_text( + format_nhs_number(self.participant.nhs_number) + ) + expect(status_bar).to_contain_text(self.participant.full_name) + def then_i_should_be_on_the_medical_information_page(self): path = reverse( "mammograms:ask_for_medical_information", diff --git a/manage_breast_screening/tests/system/clinical/test_recording_symptoms.py b/manage_breast_screening/tests/system/clinical/test_recording_symptoms.py index 70ee06c81..86294bdf4 100644 --- a/manage_breast_screening/tests/system/clinical/test_recording_symptoms.py +++ b/manage_breast_screening/tests/system/clinical/test_recording_symptoms.py @@ -2,6 +2,8 @@ from django.urls import reverse from playwright.sync_api import expect +from manage_breast_screening.core.utils.string_formatting import format_nhs_number +from manage_breast_screening.participants.models import AppointmentStatus from manage_breast_screening.participants.models.symptom import ( RelativeDateChoices, SymptomType, @@ -28,8 +30,10 @@ def test_adding_a_symptom(self): self.given_i_am_logged_in_as_a_clinical_user() self.and_there_is_an_appointment() self.and_i_am_on_the_record_medical_information_page() + self.and_i_see_the_appointment_status_bar() self.when_i_click_on_lump() self.then_i_see_the_add_a_lump_form() + self.and_i_see_the_appointment_status_bar() self.when_i_select_right_breast() self.and_i_enter_the_area() @@ -96,6 +100,10 @@ def and_there_is_an_appointment(self): self.appointment = AppointmentFactory( screening_episode=self.screening_episode, clinic_slot__clinic__setting__provider=self.current_provider, + current_status_params={ + "state": AppointmentStatus.IN_PROGRESS, + "created_by": self.current_user, + }, ) def and_there_is_an_appointment_with_a_symptom_added_in_the_last_three_months(self): @@ -129,6 +137,13 @@ def then_i_see_the_add_a_lump_form(self): expect(self.page.get_by_text("Details of the lump")).to_be_visible() self.assert_page_title_contains("Details of the lump") + def and_i_see_the_appointment_status_bar(self): + status_bar = self.page.locator("div.app-status-bar") + expect(status_bar).to_contain_text( + format_nhs_number(self.participant.nhs_number) + ) + expect(status_bar).to_contain_text(self.participant.full_name) + def when_i_select_right_breast(self): self.page.get_by_label("Right breast", exact=True).click()