Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prepopulate unscheduled sessions #1942

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions app/components/app_session_table_component.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,7 @@
<span class="nhsuk-table-responsive__heading">Location</span>

<span>
<% if session.new_record? %>
<%= govuk_link_to helpers.session_location(session), new_session_path(session, location_id: session.location.id) %>
<% else %>
<%= govuk_link_to helpers.session_location(session), session_path(session) %>
<% end %>
<%= govuk_link_to helpers.session_location(session), session_path(session) %>

<% if (location = session.location)&.has_address? %>
<br />
Expand Down
13 changes: 1 addition & 12 deletions app/controllers/programmes_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,10 @@ def show
end

def sessions
academic_year = Date.current.academic_year
sessions_for_programme = policy_scope(Session).has_programme(@programme)

@scheduled_sessions = sessions_for_programme.scheduled

@unscheduled_sessions =
sessions_for_programme.unscheduled +
policy_scope(Location)
.school
.for_year_groups(@programme.year_groups)
.has_no_session
.map do |location|
Session.new(team: current_user.team, location:, academic_year:)
end

@unscheduled_sessions = sessions_for_programme.unscheduled
@completed_sessions = sessions_for_programme.completed
end

Expand Down
27 changes: 2 additions & 25 deletions app/controllers/sessions_controller.rb
Original file line number Diff line number Diff line change
@@ -1,24 +1,7 @@
# frozen_string_literal: true

class SessionsController < ApplicationController
before_action :set_session,
except: %i[new index scheduled unscheduled completed]

skip_after_action :verify_policy_scoped, only: :new

def new
location =
team.schools.for_year_groups(team.year_groups).find(params[:location_id])

session =
ActiveRecord::Base.transaction do
Session.find_or_create_by!(team:, location:, academic_year:).tap(
&:create_patient_sessions!
)
end

redirect_to session_path(session)
end
before_action :set_session, only: %i[show edit make_in_progress]

def index
@sessions = policy_scope(Session).today
Expand All @@ -33,13 +16,7 @@ def scheduled
end

def unscheduled
@sessions =
policy_scope(Session).unscheduled +
team
.schools
.for_year_groups(team.year_groups)
.has_no_session
.map { |location| Session.new(team:, location:, academic_year:) }
@sessions = policy_scope(Session).unscheduled

render layout: "full"
end
Expand Down
42 changes: 42 additions & 0 deletions app/lib/unscheduled_sessions_factory.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# frozen_string_literal: true

class UnscheduledSessionsFactory
def initialize(academic_year: nil)
@academic_year = academic_year || Date.current.academic_year
end

def call
Team
.includes(:locations, :programmes, :sessions)
.find_each do |team|
sessions = team.sessions.select { _1.academic_year == academic_year }

team.locations.find_each do |location|
next if sessions.any? { _1.location_id == location.id }

programmes =
team.programmes.select do
_1.year_groups.intersect?(location.year_groups)
end

next if programmes.empty?

Session.create!(academic_year:, location:, programmes:, team:).tap(
&:create_patient_sessions!
)
end

location_ids = team.locations.map(&:id)

sessions
.select(&:unscheduled?)
.reject { _1.location_id.in?(location_ids) }
.reject { _1.patients.exists? }
.each(&:destroy!)
end
end

private

attr_reader :academic_year
end
1 change: 1 addition & 0 deletions app/models/immunisation_import_row.rb
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ def session

@session ||=
Session
.create_with(programmes: [@programme])
.find_or_create_by!(
team:,
location:,
Expand Down
12 changes: 0 additions & 12 deletions app/models/location.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,6 @@ class Location < ApplicationRecord
where("year_groups && ARRAY[?]::integer[]", year_groups)
end

scope :has_no_session,
-> do
where.not(
Session
.where(academic_year: Date.current.academic_year)
.where("location_id = locations.id")
.where("team_id = locations.team_id")
.arel
.exists
)
end

validates :name, presence: true
validates :url, url: true, allow_nil: true

Expand Down
11 changes: 1 addition & 10 deletions app/models/session.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,7 @@ class Session < ApplicationRecord
)
end

after_initialize :set_programmes

validates :programmes, presence: true
validate :programmes_part_of_team

def today?
Expand Down Expand Up @@ -195,14 +194,6 @@ def open_for_consent?

private

def set_programmes
return unless new_record?
return if location.nil?

self.programmes =
team.programmes.select { _1.year_groups.intersect?(location.year_groups) }
end

def programmes_part_of_team
return if programmes.empty?

Expand Down
2 changes: 1 addition & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@
end
end

resources :sessions, only: %i[new edit index show] do
resources :sessions, only: %i[edit index show] do
collection do
get "completed"
get "scheduled"
Expand Down
2 changes: 2 additions & 0 deletions db/seeds.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ def create_session(user, team)
created_by: user
)
end

UnscheduledSessionsFactory.new.call
end

def create_patients(team)
Expand Down
2 changes: 2 additions & 0 deletions lib/tasks/add_new_location.rake
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,6 @@ task :add_new_location,
Location.create!(name:, address:, town:, county:, urn:, postcode:, team_id:)

puts "Location #{name} (id: #{location.id}) added to team #{Team.find(team_id).name}."

UnscheduledSessionsFactory.new.call
end
2 changes: 2 additions & 0 deletions lib/tasks/schools.rake
Original file line number Diff line number Diff line change
Expand Up @@ -166,5 +166,7 @@ namespace :schools do
end

location.update!(team:)

UnscheduledSessionsFactory.new.call
end
end
7 changes: 7 additions & 0 deletions spec/features/e2e_journey_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ def given_an_hpv_programme_is_underway
@programme = create(:programme, :hpv)
@team = create(:team, :with_one_nurse, programmes: [@programme])
@school = create(:location, :secondary, team: @team, name: "Pilot School")
create(
:session,
:unscheduled,
location: @school,
team: @team,
programme: @programme
)
end

def and_i_am_a_nurse_signed_into_the_service
Expand Down
5 changes: 3 additions & 2 deletions spec/features/import_class_lists_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,10 @@

def given_an_hpv_programme_is_underway
@team = create(:team, :with_one_nurse)
create(:location, :secondary, name: "Waterloo Road", team: @team)
location = create(:location, :secondary, name: "Waterloo Road", team: @team)
@user = @team.users.first
create(:programme, :hpv, teams: [@team])
programme = create(:programme, :hpv, teams: [@team])
create(:session, :unscheduled, team: @team, location:, programme:)
end

def when_i_visit_a_session_page_for_the_hpv_programme
Expand Down
7 changes: 7 additions & 0 deletions spec/features/manage_sessions_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ def given_my_team_is_running_an_hpv_vaccination_programme
school: @location,
team: @team
)
create(
:session,
:unscheduled,
location: @location,
team: @team,
programme: @programme
)
end

def when_i_go_to_todays_sessions_as_a_nurse
Expand Down
80 changes: 80 additions & 0 deletions spec/lib/unscheduled_sessions_factory_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# frozen_string_literal: true

describe UnscheduledSessionsFactory do
describe "#call" do
subject(:call) { described_class.new.call }

let(:programme) { create(:programme, :hpv) }
let(:team) { create(:team, programmes: [programme]) }

context "with a school that's eligible for the programme" do
let!(:location) { create(:location, :secondary, team:) }

it "creates missing unscheduled sessions" do
expect { call }.to change(team.sessions, :count).by(1)

session = team.sessions.first
expect(session.location).to eq(location)
expect(session.programmes).to eq([programme])
end
end

context "with a school that's not eligible for the programme" do
before { create(:location, :primary, team:) }

it "doesn't create any sessions" do
expect { call }.not_to change(Session, :count)
end
end

context "when a session already exists" do
before do
location = create(:location, :secondary, team:)
create(:session, team:, location:, programme:)
end

it "doesn't create any sessions" do
expect { call }.not_to change(Session, :count)
end
end

context "when a session exists for a different academic year" do
before do
location = create(:location, :secondary, team:)
create(
:session,
team:,
location:,
programme:,
date: Date.new(2013, 1, 1)
)
end

it "creates the missing unscheduled session" do
expect { call }.to change(team.sessions, :count).by(1)
end
end

context "with an unscheduled session for a location no longer managed by the team" do
let(:location) { create(:location, :secondary) }
let!(:session) do
create(:session, :unscheduled, team:, location:, programme:)
end

it "destroys the session" do
expect { call }.to change(Session, :count).by(-1)
expect { session.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
end

context "with a scheduled session for a location no longer managed by the team" do
let(:location) { create(:location, :secondary) }

before { create(:session, :scheduled, team:, location:, programme:) }

it "doesn't destroy the session" do
expect { call }.not_to change(Session, :count)
end
end
end
end
18 changes: 0 additions & 18 deletions spec/models/location_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,24 +43,6 @@
it { should include(matching) }
it { should_not include(mismatch) }
end

describe "#has_no_session" do
subject(:scope) { described_class.has_no_session }

let(:location_with_session) { create(:session).location }
let(:location_without_session) { create(:location, :school) }
let(:location_with_session_in_different_year) do
create(
:session,
academic_year: 2023,
date: Date.new(2023, 9, 1)
).location
end

it { should include(location_without_session) }
it { should_not include(location_with_session) }
it { should include(location_with_session_in_different_year) }
end
end

describe "validations" do
Expand Down
13 changes: 0 additions & 13 deletions spec/models/session_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,19 +76,6 @@
end
end

it "sets default programmes when creating a new session" do
hpv_programme = create(:programme, :hpv)
flu_programme = create(:programme, :flu)

team = create(:team, programmes: [hpv_programme, flu_programme])
location = create(:location, :primary)

session = described_class.new(team:, location:)

expect(session.programmes).to include(flu_programme)
expect(session.programmes).not_to include(hpv_programme)
end

describe "#today?" do
subject(:today?) { session.today? }

Expand Down
Loading