diff --git a/manage_breast_screening/mammograms/jinja2/mammograms/show/participant_details.jinja b/manage_breast_screening/mammograms/jinja2/mammograms/show/participant_details.jinja
index 754ac365f..e3b6eb59c 100644
--- a/manage_breast_screening/mammograms/jinja2/mammograms/show/participant_details.jinja
+++ b/manage_breast_screening/mammograms/jinja2/mammograms/show/participant_details.jinja
@@ -4,7 +4,7 @@
{% from 'nhsuk/components/back-link/macro.jinja' import backLink %}
{% from 'components/appointment-status/macro.jinja' import appointment_status %}
{% from 'components/appointment-header/macro.jinja' import appointment_header %}
-{% from 'components/participant-details/template.jinja' import participant_details %}
+{% from 'components/participant-details/participant_details.jinja' import participant_details %}
{% from 'components/participant-details/contact_details.jinja' import contact_details %}
{% from 'components/secondary-navigation/macro.jinja' import app_secondary_navigation %}
{% from 'mammograms/special_appointments/special_appointment_banner.jinja' import special_appointment_banner %}
diff --git a/manage_breast_screening/participants/jinja2/components/participant-details/template.jinja b/manage_breast_screening/participants/jinja2/components/participant-details/participant_details.jinja
similarity index 100%
rename from manage_breast_screening/participants/jinja2/components/participant-details/template.jinja
rename to manage_breast_screening/participants/jinja2/components/participant-details/participant_details.jinja
diff --git a/manage_breast_screening/participants/jinja2/components/participant-details/personal_details.jinja b/manage_breast_screening/participants/jinja2/components/participant-details/personal_details.jinja
deleted file mode 100644
index 9d178652a..000000000
--- a/manage_breast_screening/participants/jinja2/components/participant-details/personal_details.jinja
+++ /dev/null
@@ -1,55 +0,0 @@
-{% from "nhsuk/components/card/macro.jinja" import card %}
-{% from "nhsuk/components/summary-list/macro.jinja" import summaryList %}
-{% from "components/participant-details/summary_list_rows.jinja" import date_of_birth_and_age_html, ethnicity_html %}
-
-{% macro personal_details(presented_participant, return_url) %}
- {% call card({
- "heading": "Personal details"
- }) %}
- {{ summaryList({
- "rows": [
- {
- "key": {
- "text": "NHS Number"
- },
- "value": {
- "text": presented_participant.nhs_number
- }
- },
- {
- "key": {
- "text": "Full name"
- },
- "value": {
- "text": presented_participant.full_name
- }
- },
- {
- "key": {
- "text": "Gender"
- },
- "value": {
- "text": presented_participant.gender
- }
- },
- {
- "key": {
- "text": "Date of birth"
- },
- "value": {
- "html": date_of_birth_and_age_html(presented_participant) | safe
- }
- },
- {
- "key": {
- "text": "Ethnicity"
- },
- "value": {
- "html": ethnicity_html(presented_participant) | safe
- },
- "actions": presented_participant.ethnicity_actions(return_url)
- },
- ]
- }) }}
- {% endcall %}
-{% endmacro %}
diff --git a/manage_breast_screening/participants/jinja2/participants/show.jinja b/manage_breast_screening/participants/jinja2/participants/show.jinja
deleted file mode 100644
index 49a2d9492..000000000
--- a/manage_breast_screening/participants/jinja2/participants/show.jinja
+++ /dev/null
@@ -1,25 +0,0 @@
-{% extends 'layout-app.jinja' %}
-{% from 'nhsuk/components/back-link/macro.jinja' import backLink %}
-{% from 'nhsuk/components/card/macro.jinja' import card %}
-{% from 'nhsuk/components/tag/macro.jinja' import tag %}
-{% from 'nhsuk/components/summary-list/macro.jinja' import summaryList %}
-{% from 'components/participant-details/appointments.jinja' import appointments %}
-{% from 'components/participant-details/contact_details.jinja' import contact_details %}
-{% from 'components/participant-details/personal_details.jinja' import personal_details %}
-{% from 'components/participant-details/screening_details.jinja' import screening_details %}
-
-
-{% block page_content %}
-
-
-
- {{ heading }}
-
-
- {{ personal_details(presented_participant=presented_participant) }}
- {{ contact_details(presented_participant=presented_participant) }}
- {{ screening_details(presented_mammograms=presented_mammograms) }}
- {{ appointments(presented_appointments=presented_appointments) }}
-
-
-{% endblock page_content %}
diff --git a/manage_breast_screening/participants/models/appointment.py b/manage_breast_screening/participants/models/appointment.py
index e5b32bafa..10da86145 100644
--- a/manage_breast_screening/participants/models/appointment.py
+++ b/manage_breast_screening/participants/models/appointment.py
@@ -39,6 +39,9 @@ def checked_in(self):
def in_progress(self):
return self.in_status(AppointmentStatus.IN_PROGRESS)
+ def for_participant(self, participant_id):
+ return self.filter(screening_episode__participant_id=participant_id)
+
def complete(self):
return self.in_status(
AppointmentStatus.CANCELLED,
diff --git a/manage_breast_screening/participants/tests/jinja2/test_personal_details.py b/manage_breast_screening/participants/tests/jinja2/test_personal_details.py
deleted file mode 100644
index a27fa0986..000000000
--- a/manage_breast_screening/participants/tests/jinja2/test_personal_details.py
+++ /dev/null
@@ -1,64 +0,0 @@
-from textwrap import dedent
-
-import pytest
-from pytest_django.asserts import assertInHTML
-
-from manage_breast_screening.participants.presenters import ParticipantPresenter
-
-from ..factories import ParticipantFactory
-
-
-class TestPersonalDetails:
- @pytest.fixture
- def presenter(self):
- return ParticipantPresenter(
- ParticipantFactory.build(
- ethnic_background_id="english_welsh_scottish_ni_british"
- )
- )
-
- def test_personal_details(self, presenter, jinja_env):
- template = jinja_env.from_string(
- dedent(
- r"""
- {% from 'components/participant-details/personal_details.jinja' import personal_details %}
- {{ personal_details(presenter) }}
- """
- )
- )
-
- response = template.render({"presenter": presenter})
-
- assertInHTML(
- 'Personal details
',
- response,
- )
-
- assertInHTML('NHS Number', response)
- assertInHTML(
- f'{presenter.nhs_number}',
- response,
- )
-
- assertInHTML('Full name', response)
- assertInHTML(
- f'{presenter.full_name}',
- response,
- )
-
- assertInHTML('Gender', response)
- assertInHTML(
- f'{presenter.gender}', response
- )
-
- assertInHTML('Date of birth', response)
- assertInHTML(
- f'{presenter.date_of_birth}
({presenter.age})',
- response,
- )
-
- assertInHTML('Ethnicity', response)
- assertInHTML(
- 'White (English, Welsh, Scottish, Northern Irish or British)',
- response,
- )
diff --git a/manage_breast_screening/participants/tests/test_models.py b/manage_breast_screening/participants/tests/test_models.py
index f26f11181..8f1c6e04f 100644
--- a/manage_breast_screening/participants/tests/test_models.py
+++ b/manage_breast_screening/participants/tests/test_models.py
@@ -240,6 +240,21 @@ def test_order_by_starts_at(self):
[late, middle, early],
)
+ def test_for_participant(self):
+ a = AppointmentFactory.create()
+ b = AppointmentFactory.create(
+ screening_episode__participant=a.screening_episode.participant
+ )
+ AppointmentFactory.create()
+
+ assertQuerySetEqual(
+ models.Appointment.objects.for_participant(
+ a.screening_episode.participant_id
+ ),
+ [a, b],
+ ordered=False,
+ )
+
@pytest.mark.django_db
class TestEagerLoadCurrentStatus:
def test_eager_loads_most_recent_status_with_created_by(
diff --git a/manage_breast_screening/participants/tests/test_views.py b/manage_breast_screening/participants/tests/test_views.py
index e6d4e7fd1..685251ed3 100644
--- a/manage_breast_screening/participants/tests/test_views.py
+++ b/manage_breast_screening/participants/tests/test_views.py
@@ -1,5 +1,6 @@
import pytest
from django.urls import reverse
+from pytest_django.asserts import assertRedirects
from manage_breast_screening.participants.tests.factories import (
AppointmentFactory,
@@ -9,14 +10,33 @@
@pytest.mark.django_db
class TestShowParticipant:
- def test_renders_response(self, clinical_user_client):
+ def test_redirects_to_appointment_participant_details(self, clinical_user_client):
# Create an appointment with the current provider so the participant is accessible
participant = ParticipantFactory.create()
- AppointmentFactory.create(
+ appointment = AppointmentFactory.create(
screening_episode__participant=participant,
clinic_slot__clinic__setting__provider=clinical_user_client.current_provider,
)
response = clinical_user_client.http.get(
reverse("participants:show", kwargs={"pk": participant.pk}),
)
- assert response.status_code == 200
+
+ assertRedirects(
+ response,
+ reverse(
+ "mammograms:participant_details",
+ kwargs={"pk": appointment.pk},
+ ),
+ )
+
+ def test_redirects_to_home_if_no_appointment(self, clinical_user_client):
+ participant = ParticipantFactory.create()
+
+ response = clinical_user_client.http.get(
+ reverse("participants:show", kwargs={"pk": participant.pk}),
+ )
+
+ assertRedirects(
+ response,
+ reverse("clinics:index"),
+ )
diff --git a/manage_breast_screening/participants/views.py b/manage_breast_screening/participants/views.py
index 57cd8ce42..370718d04 100644
--- a/manage_breast_screening/participants/views.py
+++ b/manage_breast_screening/participants/views.py
@@ -5,12 +5,11 @@
from django.shortcuts import redirect, render
from django.urls import reverse
-from manage_breast_screening.mammograms.presenters import LastKnownMammogramPresenter
+from manage_breast_screening.participants.models.appointment import Appointment
from manage_breast_screening.participants.services import fetch_most_recent_provider
from .forms import EthnicityForm, ParticipantReportedMammogramForm
-from .models import Participant, ParticipantReportedMammogram
-from .presenters import ParticipantAppointmentsPresenter, ParticipantPresenter
+from .models import Participant
logger = getLogger(__name__)
@@ -35,41 +34,18 @@ def parse_return_url(request, default: str) -> str:
def show(request, pk):
provider = request.user.current_provider
try:
- participant = provider.participants.get(pk=pk)
- except Participant.DoesNotExist:
- raise Http404("Participant not found")
- presented_participant = ParticipantPresenter(participant)
-
- appointments = participant.appointments.order_by_starts_at(
- desc=True
- ).select_related("clinic_slot__clinic__setting")
-
- presented_appointments = ParticipantAppointmentsPresenter(
- past_appointments=list(appointments.past()),
- upcoming_appointments=list(appointments.upcoming()),
- )
-
- last_known_mammograms = ParticipantReportedMammogram.objects.filter(
- participant_id=pk
- ).order_by("-created_at")
-
- presented_mammograms = LastKnownMammogramPresenter(
- last_known_mammograms,
- participant_pk=pk,
- current_url=request.path,
- )
+ appointment_id = (
+ provider.appointments.select_related("clinic_slot")
+ .for_participant(pk)
+ .order_by_starts_at(desc=True)[0:1]
+ .values_list("id", flat=True)
+ .get()
+ )
+ except Appointment.DoesNotExist:
+ logger.exception(f"Appointment not found for participant {pk}")
+ return redirect(reverse("clinics:index"))
- return render(
- request,
- "participants/show.jinja",
- context={
- "presented_participant": presented_participant,
- "presented_appointments": presented_appointments,
- "presented_mammograms": presented_mammograms,
- "heading": participant.full_name,
- "page_title": "Participant",
- },
- )
+ return redirect("mammograms:participant_details", pk=appointment_id)
def edit_ethnicity(request, pk):
diff --git a/manage_breast_screening/tests/system/administrative/test_participant_record.py b/manage_breast_screening/tests/system/administrative/test_participant_record.py
index 92535586e..72936dc6a 100644
--- a/manage_breast_screening/tests/system/administrative/test_participant_record.py
+++ b/manage_breast_screening/tests/system/administrative/test_participant_record.py
@@ -27,7 +27,7 @@ def test_viewing_participant_record_from_an_appointment(self):
self.given_i_am_logged_in_as_an_administrative_user()
self.and_the_participant_has_an_upcoming_appointment()
self.and_i_am_viewing_the_upcoming_appointment()
- self.when_i_click_on_view_participant_record()
+ self.when_i_click_on_participant_details()
self.then_i_should_be_on_the_participant_record_page()
self.and_i_should_see_the_participant_record()
self.when_i_click_on_the_back_link()
@@ -36,25 +36,9 @@ def test_viewing_participant_record_from_an_appointment(self):
def test_accessibility(self):
self.given_i_am_logged_in_as_an_administrative_user()
self.and_the_participant_has_an_upcoming_appointment()
- self.and_i_am_on_the_participant_record_page()
+ self.and_i_am_on_the_participant_details_tab()
self.then_the_accessibility_baseline_is_met()
- def test_viewing_upcoming_appointments(self):
- self.given_i_am_logged_in_as_an_administrative_user()
- self.and_the_participant_has_an_upcoming_appointment()
- self.and_i_am_on_the_participant_record_page()
- self.then_i_should_see_the_upcoming_appointment()
- self.when_i_click_on_the_upcoming_appointment()
- self.then_i_should_be_on_the_upcoming_appointment_page()
-
- def test_viewing_past_appointments(self):
- self.given_i_am_logged_in_as_an_administrative_user()
- self.and_the_participant_has_past_appointments()
- self.and_i_am_on_the_participant_record_page()
- self.then_i_should_see_the_past_appointments()
- self.when_i_click_on_a_past_appointment()
- self.then_i_should_be_on_the_past_appointment_page()
-
def and_the_participant_has_an_upcoming_appointment(self):
clinic_slot = ClinicSlotFactory(
starts_at=datetime(2025, 1, 2, 11, tzinfo=tz.utc),
@@ -95,18 +79,16 @@ def and_i_am_viewing_the_upcoming_appointment(self):
)
)
- def and_i_am_on_the_participant_record_page(self):
+ def and_i_am_on_the_participant_details_tab(self):
self.page.goto(
self.live_server_url
+ reverse(
- "participants:show",
- kwargs={"pk": self.participant.pk},
+ "mammograms:participant_details",
+ kwargs={"pk": self.upcoming_appointment.pk},
)
)
- and_i_am_on_the_participant_record_page = and_i_am_on_the_participant_record_page
-
- def when_i_click_on_view_participant_record(self):
+ def when_i_click_on_participant_details(self):
self.page.get_by_role("link", name="Participant details").click()
def then_i_should_be_on_the_participant_record_page(self):