Skip to content

Commit b16682e

Browse files
Merge pull request #5853 from nhsuk/school-info
Update `school.name` in reporting API totals view
2 parents e9bfa65 + 33b59fc commit b16682e

4 files changed

Lines changed: 106 additions & 5 deletions

File tree

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# frozen_string_literal: true
2+
3+
class UpdateReportingAPITotalsToVersion4 < ActiveRecord::Migration[8.1]
4+
def change
5+
update_view :reporting_api_totals,
6+
version: 4,
7+
revert_to_version: 3,
8+
materialized: true
9+
end
10+
end

db/schema.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#
1111
# It's strongly recommended that you check this file into your version control system.
1212

13-
ActiveRecord::Schema[8.1].define(version: 2026_01_19_161311) do
13+
ActiveRecord::Schema[8.1].define(version: 2026_01_22_093544) do
1414
# These are extensions that must be enabled in order to support this database
1515
enable_extension "pg_catalog.plpgsql"
1616
enable_extension "pg_trgm"
@@ -1387,8 +1387,8 @@
13871387
END AS patient_school_urn,
13881388
CASE
13891389
WHEN (school.name IS NOT NULL) THEN school.name
1390-
WHEN (pat.home_educated = true) THEN 'Home educated'::text
1391-
ELSE 'Unknown'::text
1390+
WHEN (pat.home_educated = true) THEN 'Home-schooled'::text
1391+
ELSE 'Unknown school'::text
13921392
END AS patient_school_name,
13931393
(ar.patient_id IS NOT NULL) AS is_archived,
13941394
(EXISTS ( SELECT 1
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
SELECT
2+
-- Composite key for unique index (required for concurrent refresh)
3+
pps.patient_id || '-' ||
4+
pps.programme_type || '-' ||
5+
tl.team_id || '-' ||
6+
pl.location_id || '-' ||
7+
pps.academic_year AS id,
8+
9+
-- Identifiers (for counting and grouping)
10+
pps.patient_id, -- COUNT(DISTINCT patient_id) for totals
11+
pps.academic_year, -- Filter: ?academic_year=2024
12+
pps.programme_type, -- Filter: ?programme=hpv
13+
pps.status, -- Scope: .vaccinated (status IN 60,61)
14+
tl.team_id, -- Filter: by user's team_ids
15+
pl.location_id AS session_location_id, -- Year group eligibility subquery
16+
17+
-- Patient demographics (used for filtering and CSV grouping)
18+
CASE pat.gender_code
19+
WHEN 0 THEN 'not known'
20+
WHEN 1 THEN 'male'
21+
WHEN 2 THEN 'female'
22+
WHEN 9 THEN 'not specified'
23+
ELSE NULL
24+
END AS patient_gender, -- Filter: ?gender=female
25+
26+
pps.academic_year
27+
- pat.birth_academic_year - 5 AS patient_year_group, -- Filter: ?year_group=8,9
28+
COALESCE(la.mhclg_code, '') AS patient_local_authority_code, -- Filter: ?local_authority=E09000001
29+
COALESCE(la.mhclg_code, '') AS patient_school_local_authority_code, -- Filter: ?school_local_authority=E09000001
30+
31+
-- School info (for CSV grouping by school)
32+
CASE
33+
WHEN school.urn IS NOT NULL THEN school.urn
34+
WHEN pat.home_educated = true THEN '999999'
35+
ELSE '888888'
36+
END AS patient_school_urn,
37+
CASE
38+
WHEN school.name IS NOT NULL THEN school.name
39+
WHEN pat.home_educated = true THEN 'Home-schooled'
40+
ELSE 'Unknown school'
41+
END AS patient_school_name,
42+
43+
-- Status flags
44+
ar.patient_id IS NOT NULL AS is_archived, -- Scope: .not_archived
45+
46+
-- Parent declared "already vaccinated" (counts toward vaccinated total)
47+
EXISTS (
48+
SELECT 1 FROM consents con
49+
WHERE con.patient_id = pps.patient_id
50+
AND con.programme_type = pps.programme_type
51+
AND con.academic_year = pps.academic_year
52+
AND con.invalidated_at IS NULL
53+
AND con.withdrawn_at IS NULL
54+
AND con.response = 1 -- refused
55+
AND con.reason_for_refusal = 1 -- already_vaccinated
56+
) AS has_already_vaccinated_consent
57+
58+
-- Source: pre-computed patient status per programme/year
59+
FROM patient_programme_statuses pps
60+
61+
-- Patient record (for demographics and exclusion checks)
62+
JOIN patients pat
63+
ON pat.id = pps.patient_id
64+
65+
-- Where the patient is enrolled this year (links to team via location)
66+
JOIN patient_locations pl
67+
ON pl.patient_id = pps.patient_id
68+
AND pl.academic_year = pps.academic_year
69+
70+
-- Which team owns this location (for team_id filtering)
71+
JOIN team_locations tl
72+
ON tl.location_id = pl.location_id
73+
AND tl.academic_year = pps.academic_year
74+
75+
-- Check if patient is archived by this team (LEFT: most aren't)
76+
LEFT JOIN archive_reasons ar
77+
ON ar.patient_id = pps.patient_id
78+
AND ar.team_id = tl.team_id
79+
80+
-- Patient's school (LEFT: home-educated patients have no school)
81+
LEFT JOIN locations school
82+
ON school.id = pat.school_id
83+
84+
-- School's local authority (LEFT: school may not have LA set)
85+
LEFT JOIN local_authorities la
86+
ON la.gias_code = school.gias_local_authority_code
87+
88+
-- Exclude patients who shouldn't appear in any reports
89+
WHERE pat.invalidated_at IS NULL -- Merged/duplicate record
90+
AND pat.restricted_at IS NULL -- S31 restricted access
91+
AND pat.date_of_death IS NULL -- Deceased

spec/controllers/api/reporting/totals_controller_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,12 +242,12 @@
242242
expect(school_two_data["vaccinated"]).to eq(1)
243243
expect(school_two_data["not_vaccinated"]).to eq(0)
244244

245-
expect(home_educated_data["school_name"]).to eq("Home educated")
245+
expect(home_educated_data["school_name"]).to eq("Home-schooled")
246246
expect(home_educated_data["cohort"]).to eq(1)
247247
expect(home_educated_data["vaccinated"]).to eq(0)
248248
expect(home_educated_data["not_vaccinated"]).to eq(1)
249249

250-
expect(unknown_data["school_name"]).to eq("Unknown")
250+
expect(unknown_data["school_name"]).to eq("Unknown school")
251251
expect(unknown_data["cohort"]).to eq(1)
252252
expect(unknown_data["vaccinated"]).to eq(0)
253253
expect(unknown_data["not_vaccinated"]).to eq(1)

0 commit comments

Comments
 (0)