Skip to content

Commit

Permalink
Add programme to vaccines
Browse files Browse the repository at this point in the history
This adds a programme column to vaccines, to change the relationship
between programmes and vaccines to be one to many rather than many to
many.
  • Loading branch information
thomasleese committed Sep 27, 2024
1 parent 98178d6 commit d88a2dc
Show file tree
Hide file tree
Showing 17 changed files with 156 additions and 74 deletions.
2 changes: 0 additions & 2 deletions app/models/batch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ class Batch < ApplicationRecord

has_and_belongs_to_many :immunisation_imports

has_many :programmes, through: :vaccine

validates :name, presence: true
validates :expiry, presence: true
end
23 changes: 1 addition & 22 deletions app/models/programme.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ class Programme < ApplicationRecord
audited

has_and_belongs_to_many :sessions
has_and_belongs_to_many :vaccines

has_many :consent_forms
has_many :consents
Expand All @@ -28,6 +27,7 @@ class Programme < ApplicationRecord
has_many :team_programmes
has_many :triages
has_many :vaccination_records
has_many :vaccines

has_many :batches, through: :vaccines
has_many :patient_sessions, through: :sessions
Expand All @@ -36,34 +36,13 @@ class Programme < ApplicationRecord

enum :type, { flu: "flu", hpv: "hpv" }, validate: true

validate :vaccines_match_type

def name
human_enum_name(:type)
end

def vaccine_ids
@vaccine_ids ||= vaccines.map(&:id)
end

def vaccine_ids=(ids)
self.vaccines = Vaccine.where(id: ids)
end

YEAR_GROUPS_BY_TYPE = { "flu" => (0..11).to_a, "hpv" => (8..11).to_a }.freeze

def year_groups
YEAR_GROUPS_BY_TYPE.fetch(type)
end

private

def vaccines_match_type
errors.add(:vaccines, :blank) if vaccines.empty?

vaccine_types = vaccines.map(&:type).uniq
unless vaccine_types.empty? || vaccine_types == [type]
errors.add(:vaccines, :match_type)
end
end
end
8 changes: 8 additions & 0 deletions app/models/vaccine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,28 @@
# type :string not null
# created_at :datetime not null
# updated_at :datetime not null
# programme_id :bigint not null
#
# Indexes
#
# index_vaccines_on_gtin (gtin) UNIQUE
# index_vaccines_on_manufacturer_and_brand (manufacturer,brand) UNIQUE
# index_vaccines_on_nivs_name (nivs_name) UNIQUE
# index_vaccines_on_programme_id (programme_id)
# index_vaccines_on_snomed_product_code (snomed_product_code) UNIQUE
# index_vaccines_on_snomed_product_term (snomed_product_term) UNIQUE
#
# Foreign Keys
#
# fk_rails_... (programme_id => programmes.id)
#
class Vaccine < ApplicationRecord
self.inheritance_column = nil

audited

belongs_to :programme

has_and_belongs_to_many :programmes
has_many :health_questions, dependent: :destroy
has_many :batches, -> { order(:name) }
Expand Down
6 changes: 5 additions & 1 deletion app/policies/batch_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ def initialize(user, scope)
end

def resolve
@scope.joins(:programmes).where(programmes: @user.programmes)
@scope.joins(vaccine: :programme).where(
vaccine: {
programme: @user.programmes
}
)
end
end
end
2 changes: 1 addition & 1 deletion app/policies/vaccine_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ def initialize(user, scope)
end

def resolve
@scope.joins(:programmes).where(programmes: @user.programmes)
@scope.joins(:programme).where(programme: @user.programmes)
end
end
end
19 changes: 19 additions & 0 deletions db/migrate/20240927134753_add_programme_to_vaccines.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

class AddProgrammeToVaccines < ActiveRecord::Migration[7.2]
def up
add_reference :vaccines, :programme, foreign_key: true

Vaccine.all.find_each do |vaccine|
vaccine.update!(
programme: Programme.find_or_create_by!(type: vaccine.type)
)
end

change_column_null :vaccines, :programme_id, false
end

def down
remove_reference :vaccines, :programme
end
end
5 changes: 4 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[7.2].define(version: 2024_09_27_124718) do
ActiveRecord::Schema[7.2].define(version: 2024_09_27_134753) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"

Expand Down Expand Up @@ -599,9 +599,11 @@
t.string "snomed_product_term", null: false
t.text "nivs_name", null: false
t.boolean "discontinued", default: false, null: false
t.bigint "programme_id", null: false
t.index ["gtin"], name: "index_vaccines_on_gtin", unique: true
t.index ["manufacturer", "brand"], name: "index_vaccines_on_manufacturer_and_brand", unique: true
t.index ["nivs_name"], name: "index_vaccines_on_nivs_name", unique: true
t.index ["programme_id"], name: "index_vaccines_on_programme_id"
t.index ["snomed_product_code"], name: "index_vaccines_on_snomed_product_code", unique: true
t.index ["snomed_product_term"], name: "index_vaccines_on_snomed_product_term", unique: true
end
Expand Down Expand Up @@ -668,4 +670,5 @@
add_foreign_key "vaccination_records", "programmes"
add_foreign_key "vaccination_records", "users", column: "performed_by_user_id"
add_foreign_key "vaccination_records", "vaccines"
add_foreign_key "vaccines", "programmes"
end
Binary file modified erd.pdf
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@

let(:administered_at) { Time.zone.local(2024, 9, 6, 12) }
let(:location) { create(:location, :school, name: "Hogwarts") }
let(:programme) { create(:programme, type: vaccine&.type || :hpv) }
let(:programme) { create(:programme, :hpv) }
let(:session) { create(:session, programme:, location:) }
let(:patient_session) { create(:patient_session, session:) }
let(:vaccine) { create(:vaccine, :gardasil_9) }
let(:vaccine) { programme.vaccines.first }
let(:batch) do
create(:batch, name: "ABC", expiry: Date.new(2020, 1, 1), vaccine:)
end
Expand Down
113 changes: 93 additions & 20 deletions spec/factories/programmes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,24 @@
transient { batch_count { 1 } }

type { %w[flu hpv].sample }
vaccines { [association(:vaccine, type:, batch_count:)] }
vaccines do
[association(:vaccine, type:, batch_count:, programme: instance)]
end

trait :hpv do
type { "hpv" }
vaccines { [association(:vaccine, :gardasil_9, batch_count:)] }
vaccines do
[association(:vaccine, :gardasil_9, batch_count:, programme: instance)]
end
end

trait :hpv_all_vaccines do
hpv
vaccines do
[
association(:vaccine, :cervarix, batch_count:),
association(:vaccine, :gardasil, batch_count:),
association(:vaccine, :gardasil_9, batch_count:)
association(:vaccine, :cervarix, batch_count:, programme: instance),
association(:vaccine, :gardasil, batch_count:, programme: instance),
association(:vaccine, :gardasil_9, batch_count:, programme: instance)
]
end
end
Expand All @@ -45,12 +49,37 @@
type { "flu" }
vaccines do
[
association(:vaccine, :adjuvanted_quadrivalent, batch_count:),
association(:vaccine, :cell_quadrivalent, batch_count:),
association(:vaccine, :fluenz_tetra, batch_count:),
association(:vaccine, :quadrivalent_influenza, batch_count:),
association(:vaccine, :quadrivalent_influvac_tetra, batch_count:),
association(:vaccine, :supemtek, batch_count:)
association(
:vaccine,
:adjuvanted_quadrivalent,
batch_count:,
programme: instance
),
association(
:vaccine,
:cell_quadrivalent,
batch_count:,
programme: instance
),
association(
:vaccine,
:fluenz_tetra,
batch_count:,
programme: instance
),
association(
:vaccine,
:quadrivalent_influenza,
batch_count:,
programme: instance
),
association(
:vaccine,
:quadrivalent_influvac_tetra,
batch_count:,
programme: instance
),
association(:vaccine, :supemtek, batch_count:, programme: instance)
]
end
end
Expand All @@ -59,21 +88,65 @@
flu
vaccines do
[
association(:vaccine, :adjuvanted_quadrivalent, batch_count:),
association(:vaccine, :cell_quadrivalent, batch_count:),
association(:vaccine, :fluad_tetra, batch_count:),
association(:vaccine, :flucelvax_tetra, batch_count:),
association(:vaccine, :fluenz_tetra, batch_count:),
association(:vaccine, :quadrivalent_influenza, batch_count:),
association(:vaccine, :quadrivalent_influvac_tetra, batch_count:),
association(:vaccine, :supemtek, batch_count:)
association(
:vaccine,
:adjuvanted_quadrivalent,
batch_count:,
programme: instance
),
association(
:vaccine,
:cell_quadrivalent,
batch_count:,
programme: instance
),
association(
:vaccine,
:fluad_tetra,
batch_count:,
programme: instance
),
association(
:vaccine,
:flucelvax_tetra,
batch_count:,
programme: instance
),
association(
:vaccine,
:fluenz_tetra,
batch_count:,
programme: instance
),
association(
:vaccine,
:quadrivalent_influenza,
batch_count:,
programme: instance
),
association(
:vaccine,
:quadrivalent_influvac_tetra,
batch_count:,
programme: instance
),
association(:vaccine, :supemtek, batch_count:, programme: instance)
]
end
end

trait :flu_nasal_only do
flu
vaccines { [association(:vaccine, :fluenz_tetra, batch_count:)] }
vaccines do
[
association(
:vaccine,
:fluenz_tetra,
batch_count:,
programme: instance
)
]
end
end
end
end
8 changes: 8 additions & 0 deletions spec/factories/vaccines.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,28 @@
# type :string not null
# created_at :datetime not null
# updated_at :datetime not null
# programme_id :bigint not null
#
# Indexes
#
# index_vaccines_on_gtin (gtin) UNIQUE
# index_vaccines_on_manufacturer_and_brand (manufacturer,brand) UNIQUE
# index_vaccines_on_nivs_name (nivs_name) UNIQUE
# index_vaccines_on_programme_id (programme_id)
# index_vaccines_on_snomed_product_code (snomed_product_code) UNIQUE
# index_vaccines_on_snomed_product_term (snomed_product_term) UNIQUE
#
# Foreign Keys
#
# fk_rails_... (programme_id => programmes.id)
#
FactoryBot.define do
factory :vaccine do
transient { batch_count { 1 } }

type { %w[flu hpv].sample }
programme { Programme.find_or_create_by!(type:) }

brand { Faker::Commerce.product_name }
manufacturer { Faker::Company.name }
sequence(:nivs_name) { |n| "#{brand.parameterize}-#{n}" }
Expand Down
5 changes: 2 additions & 3 deletions spec/features/manage_vaccines_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@
end

def given_my_team_is_running_an_hpv_vaccination_programme
@programme = create(:programme, :hpv_no_batches)
@team = create(:team, :with_one_nurse, programmes: [@programme])
@vaccine = @programme.vaccines.first
programme = create(:programme, :hpv_no_batches)
@team = create(:team, :with_one_nurse, programmes: [programme])
end

def when_i_manage_vaccines
Expand Down
3 changes: 1 addition & 2 deletions spec/features/user_authorisation_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@
end

def given_an_hpv_programme_is_underway_with_two_teams
vaccine = create(:vaccine, :hpv)
programme = create(:programme, :hpv, vaccines: [vaccine])
programme = create(:programme, :hpv)

@team = create(:team, :with_one_nurse, programmes: [programme])
@other_team = create(:team, :with_one_nurse, programmes: [programme])
Expand Down
Loading

0 comments on commit d88a2dc

Please sign in to comment.