diff --git a/app/controllers/sessions/edit_controller.rb b/app/controllers/sessions/edit_controller.rb index 7be58350f6..9a612a22b2 100644 --- a/app/controllers/sessions/edit_controller.rb +++ b/app/controllers/sessions/edit_controller.rb @@ -21,7 +21,7 @@ def show def update case current_step when :confirm - @session.draft = false + @session.active = true @session.patient_sessions.update_all(active: true) if @session.send_consent_at.today? @@ -109,16 +109,14 @@ def set_patients @session .location .patients - .where( - "NOT EXISTS (:sessions)", - sessions: - Session - .select(1) - .joins(:patient_sessions) - .where( - "patient_sessions.patient_id = patients.id AND draft = false AND campaign_id = :campaign_id", - campaign_id: @session.campaign_id - ) + .where.not( + Session + .joins(:patient_sessions) + .active + .where(campaign: @session.campaign) + .where("patient_sessions.patient_id = patients.id") + .arel + .exists ) .sort_by(&:last_name) end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 17d70b3de7..285fcaa931 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -8,7 +8,7 @@ def create campaign = current_user.team.campaigns.first - @session = Session.create!(draft: true, campaign:) + @session = Session.create!(active: false, campaign:) redirect_to session_edit_path(@session, :location) end diff --git a/app/models/campaign.rb b/app/models/campaign.rb index ede63bbb68..fc135beb80 100644 --- a/app/models/campaign.rb +++ b/app/models/campaign.rb @@ -24,6 +24,7 @@ # fk_rails_... (team_id => teams.id) # class Campaign < ApplicationRecord + include Draftable include WizardStepConcern self.inheritance_column = nil @@ -44,8 +45,6 @@ class Campaign < ApplicationRecord enum :type, { flu: "flu", hpv: "hpv" }, validate: { allow_nil: true } - scope :active, -> { where(active: true) } - normalizes :name, with: ->(name) { name&.strip } on_wizard_step :details do diff --git a/app/models/concerns/draftable.rb b/app/models/concerns/draftable.rb new file mode 100644 index 0000000000..55a12d9e71 --- /dev/null +++ b/app/models/concerns/draftable.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +module Draftable + extend ActiveSupport::Concern + + included do + scope :active, -> { where(active: true) } + scope :draft, -> { where(active: false) } + end + + def draft? + !active + end +end diff --git a/app/models/immunisation_import.rb b/app/models/immunisation_import.rb index 5dbe96b4d4..bbaba2c501 100644 --- a/app/models/immunisation_import.rb +++ b/app/models/immunisation_import.rb @@ -107,7 +107,7 @@ def record! end if (session = vaccination_record.session).draft? - session.update!(draft: false) + session.update!(active: true) end vaccination_record.update!(recorded_at:) diff --git a/app/models/immunisation_import_row.rb b/app/models/immunisation_import_row.rb index a48c9de8f7..18719154b7 100644 --- a/app/models/immunisation_import_row.rb +++ b/app/models/immunisation_import_row.rb @@ -113,7 +113,7 @@ def session .sessions .active .or(Session.where(imported_from:)) - .create_with(imported_from:, draft: true) + .create_with(imported_from:, active: false) .find_or_create_by!( date: session_date, location:, diff --git a/app/models/patient_session.rb b/app/models/patient_session.rb index 7a576d26f8..23e73457e6 100644 --- a/app/models/patient_session.rb +++ b/app/models/patient_session.rb @@ -24,6 +24,8 @@ # class PatientSession < ApplicationRecord + include Draftable + audited has_associated_audits @@ -50,12 +52,6 @@ class PatientSession < ApplicationRecord through: :patient, class_name: "Consent" - scope :active, -> { where(active: true) } - - def draft? - !active - end - def vaccination_record # HACK: in future, it will be possible to have multiple vaccination records for a patient session vaccination_records.recorded.last diff --git a/app/models/session.rb b/app/models/session.rb index 7ccea3145b..876678dbb7 100644 --- a/app/models/session.rb +++ b/app/models/session.rb @@ -5,9 +5,9 @@ # Table name: sessions # # id :bigint not null, primary key +# active :boolean default(FALSE), not null # close_consent_at :date # date :date -# draft :boolean default(FALSE) # send_consent_at :date # send_reminders_at :date # time_of_day :integer @@ -27,7 +27,9 @@ # fk_rails_... (imported_from_id => immunisation_imports.id) # class Session < ApplicationRecord + include Draftable include WizardStepConcern + audited DEFAULT_DAYS_FOR_REMINDER = 2 @@ -46,8 +48,6 @@ class Session < ApplicationRecord enum :time_of_day, %w[morning afternoon all_day] - scope :active, -> { where(draft: false) } - scope :draft, -> { where(draft: true) } scope :past, -> { where(date: ..Time.zone.yesterday) } scope :in_progress, -> { where(date: Time.zone.today) } scope :future, -> { where(date: Time.zone.tomorrow..) } @@ -55,11 +55,7 @@ class Session < ApplicationRecord after_initialize :set_timeline_attributes after_validation :set_timeline_timestamps - validates :time_of_day, - inclusion: { - in: time_of_days.keys - }, - unless: -> { draft? } + validates :time_of_day, inclusion: { in: time_of_days.keys }, unless: :draft? on_wizard_step :location, exact: true do validates :location_id, presence: true @@ -98,10 +94,6 @@ class Session < ApplicationRecord if: -> { close_consent_on == "custom" } end - def active? - !draft - end - def health_questions campaign.vaccines.first.health_questions end diff --git a/db/migrate/20240905113128_rename_session_draft_to_active.rb b/db/migrate/20240905113128_rename_session_draft_to_active.rb new file mode 100644 index 0000000000..6554356bb4 --- /dev/null +++ b/db/migrate/20240905113128_rename_session_draft_to_active.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class RenameSessionDraftToActive < ActiveRecord::Migration[7.2] + def up + change_table :sessions, bulk: true do |t| + t.rename :draft, :active + t.change_null :active, false + end + + Session.update_all("active = NOT active") + end + + def down + Session.update_all("active = NOT active") + + change_table :sessions, bulk: true do |t| + t.rename :active, :draft + t.change_null :draft, true + end + end +end diff --git a/db/schema.rb b/db/schema.rb index b0bf6f8d83..bcd744b251 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -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_05_090740) do +ActiveRecord::Schema[7.2].define(version: 2024_09_05_113128) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -360,7 +360,7 @@ t.datetime "created_at", null: false t.datetime "updated_at", null: false t.bigint "campaign_id" - t.boolean "draft", default: false + t.boolean "active", default: false, null: false t.date "send_consent_at" t.date "send_reminders_at" t.date "close_consent_at" diff --git a/erd.pdf b/erd.pdf index 2703b017d5..5cf99e3404 100644 Binary files a/erd.pdf and b/erd.pdf differ diff --git a/spec/components/app_session_details_component_spec.rb b/spec/components/app_session_details_component_spec.rb index e35171f94f..63547a55c0 100644 --- a/spec/components/app_session_details_component_spec.rb +++ b/spec/components/app_session_details_component_spec.rb @@ -51,7 +51,6 @@ context "for a session with the minimum amount of information" do let(:session) do Session.new( - draft: false, location: create(:location, :school), campaign: create(:campaign, :hpv), date:, diff --git a/spec/factories/patient_sessions.rb b/spec/factories/patient_sessions.rb index 38bd45e47d..39303fcce6 100644 --- a/spec/factories/patient_sessions.rb +++ b/spec/factories/patient_sessions.rb @@ -33,7 +33,7 @@ patient { association :patient, session:, **patient_attributes } created_by { association :user } - active { session.active? } + active { session.active } trait :active do active { true } diff --git a/spec/factories/sessions.rb b/spec/factories/sessions.rb index d57ad94ee0..3142a13a93 100644 --- a/spec/factories/sessions.rb +++ b/spec/factories/sessions.rb @@ -5,9 +5,9 @@ # Table name: sessions # # id :bigint not null, primary key +# active :boolean default(FALSE), not null # close_consent_at :date # date :date -# draft :boolean default(FALSE) # send_consent_at :date # send_reminders_at :date # time_of_day :integer @@ -40,6 +40,16 @@ time_of_day { %w[morning afternoon all_day].sample } + active { campaign.active } + + trait :active do + active { true } + end + + trait :draft do + active { false } + end + trait :in_progress do date { Time.zone.now } end diff --git a/spec/jobs/consent_reminders_job_spec.rb b/spec/jobs/consent_reminders_job_spec.rb index 76323de38b..b9667ecaf5 100644 --- a/spec/jobs/consent_reminders_job_spec.rb +++ b/spec/jobs/consent_reminders_job_spec.rb @@ -8,10 +8,9 @@ context "with draft and active sessions" do it "enqueues ConsentRemindersSessionBatchJob for each active sessions" do - active_session = - create(:session, draft: false, send_reminders_at: Time.zone.today) + active_session = create(:session, send_reminders_at: Time.zone.today) _draft_session = - create(:session, draft: true, campaign: active_session.campaign) + create(:session, :draft, campaign: active_session.campaign) described_class.perform_now expect(ConsentRemindersSessionBatchJob).to have_been_enqueued.once @@ -23,12 +22,10 @@ context "with sessions set to send consent today and in the future" do it "enqueues ConsentRemindersSessionBatchJob for the session set to send consent today" do - active_session = - create(:session, draft: false, send_reminders_at: Time.zone.today) + active_session = create(:session, send_reminders_at: Time.zone.today) _later_session = create( :session, - draft: false, send_reminders_at: 2.days.from_now, campaign: active_session.campaign ) diff --git a/spec/jobs/consent_requests_job_spec.rb b/spec/jobs/consent_requests_job_spec.rb index 9082502d6e..1b94ea105b 100644 --- a/spec/jobs/consent_requests_job_spec.rb +++ b/spec/jobs/consent_requests_job_spec.rb @@ -6,18 +6,13 @@ ActiveJob::Base.queue_adapter.enqueued_jobs.clear end - let(:campaign) { create(:campaign) } + let(:campaign) { create(:campaign, :active) } context "with draft and active sessions" do it "enqueues ConsentRequestsSessionBatchJob for each active sessions" do active_session = - create( - :session, - draft: false, - send_consent_at: Time.zone.today, - campaign: - ) - _draft_session = create(:session, draft: true, campaign:) + create(:session, send_consent_at: Time.zone.today, campaign:) + _draft_session = create(:session, :draft, campaign:) described_class.perform_now expect(ConsentRequestsSessionBatchJob).to have_been_enqueued.once @@ -30,19 +25,9 @@ context "with sessions set to send consent today and in the future" do it "enqueues ConsentRequestsSessionBatchJob for the session set to send consent today" do active_session = - create( - :session, - draft: false, - send_consent_at: Time.zone.today, - campaign: - ) + create(:session, send_consent_at: Time.zone.today, campaign:) _later_session = - create( - :session, - draft: false, - send_consent_at: 2.days.from_now, - campaign: - ) + create(:session, send_consent_at: 2.days.from_now, campaign:) described_class.perform_now expect(ConsentRequestsSessionBatchJob).to have_been_enqueued.once diff --git a/spec/jobs/session_reminders_job_spec.rb b/spec/jobs/session_reminders_job_spec.rb index df094369f1..85dd4a18b2 100644 --- a/spec/jobs/session_reminders_job_spec.rb +++ b/spec/jobs/session_reminders_job_spec.rb @@ -6,7 +6,7 @@ ActiveJob::Base.queue_adapter.enqueued_jobs.clear end - let(:campaign) { create(:campaign) } + let(:campaign) { create(:campaign, :active) } it "enqueues SessionRemdindersJob for each session happening tomorrow" do tomorrow_session = create(:session, date: Date.tomorrow, campaign:) @@ -22,10 +22,8 @@ context "with draft and active sessions" do it "enqueues ConsentRemindersSessionBatchJob for each active sessions" do - active_session = - create(:session, draft: false, date: Date.tomorrow, campaign:) - _draft_session = - create(:session, draft: true, date: Date.tomorrow, campaign:) + active_session = create(:session, date: Date.tomorrow, campaign:) + _draft_session = create(:session, :draft, date: Date.tomorrow, campaign:) described_class.perform_now expect(SessionRemindersBatchJob).to have_been_enqueued.once diff --git a/spec/models/session_spec.rb b/spec/models/session_spec.rb index 16f7e966c6..e81b34c6e6 100644 --- a/spec/models/session_spec.rb +++ b/spec/models/session_spec.rb @@ -5,9 +5,9 @@ # Table name: sessions # # id :bigint not null, primary key +# active :boolean default(FALSE), not null # close_consent_at :date # date :date -# draft :boolean default(FALSE) # send_consent_at :date # send_reminders_at :date # time_of_day :integer @@ -27,7 +27,7 @@ # fk_rails_... (imported_from_id => immunisation_imports.id) # -describe Session do +describe Session, type: :model do describe "validations" do context "when wizard_step is location" do subject { build(:session, wizard_step:, campaign:) } @@ -40,6 +40,18 @@ end end + describe "scopes" do + describe "#active" do + subject(:scope) { described_class.active } + + let!(:active_session) { create(:session) } + let!(:draft_session) { create(:session, :draft) } + + it { should include(active_session) } + it { should_not include(draft_session) } + end + end + describe "#in_progress?" do subject { session.in_progress? } @@ -61,15 +73,4 @@ it { should be_falsey } end end - - describe ".active scope" do - subject { described_class.active } - - let(:campaign) { create(:campaign) } - let!(:active_session) { create(:session, campaign:) } - let!(:draft_session) { create(:session, campaign:, draft: true) } - - it { should include active_session } - it { should_not include draft_session } - end end diff --git a/spec/policies/session_policy_spec.rb b/spec/policies/session_policy_spec.rb index 6c1bdfe4b3..53be712fc5 100644 --- a/spec/policies/session_policy_spec.rb +++ b/spec/policies/session_policy_spec.rb @@ -26,8 +26,8 @@ let(:team) { create :team } let(:user) { create :user, teams: [team] } let(:location) { create(:location, :school) } - let(:campaign) { create :campaign, team: } - let(:draft_session) { create :session, draft: true, location:, campaign: } + let(:campaign) { create :campaign, :active, team: } + let(:draft_session) { create :session, :draft, location:, campaign: } let(:session) { create :session, location:, campaign: } it { should include draft_session } @@ -35,16 +35,14 @@ context "location and campaign are nil" do let(:draft_session) do - create :session, draft: true, location: nil, campaign: nil + create :session, :draft, location: nil, campaign: nil end it { should include draft_session } end context "campaign is set but not location" do - let(:draft_session) do - create :session, draft: true, location: nil, campaign: - end + let(:draft_session) { create :session, :draft, location: nil, campaign: } it { should include draft_session } end