Browse Source

Multiple scheme deactivations (#1004)

* Remove deactivation date from schemes and add scheme deactivation periods table

* Update affected logs when a scheme gets deactivated

* Update status method

* Display availability timeline

* Update flash notice message
pull/1008/head
kosiakkatrina 2 years ago committed by GitHub
parent
commit
752103404f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      app/controllers/schemes_controller.rb
  2. 11
      app/helpers/schemes_helper.rb
  3. 2
      app/models/lettings_log.rb
  4. 10
      app/models/scheme.rb
  5. 3
      app/models/scheme_deactivation_period.rb
  6. 10
      db/migrate/20221117103841_add_scheme_deactivations.rb
  7. 13
      db/migrate/20221117103855_remove_deactivation_date_from_schemes.rb
  8. 18
      db/schema.rb
  9. 5
      spec/factories/scheme_deactivation_period.rb
  10. 25
      spec/helpers/schemes_helper_spec.rb
  11. 68
      spec/models/scheme_spec.rb
  12. 42
      spec/requests/schemes_controller_spec.rb

8
app/controllers/schemes_controller.rb

@ -44,7 +44,7 @@ class SchemesController < ApplicationController
def deactivate def deactivate
@scheme.run_deactivation_validations! @scheme.run_deactivation_validations!
if @scheme.update!(deactivation_date:) if @scheme.scheme_deactivation_periods.create!(deactivation_date:) && update_affected_logs
flash[:notice] = deactivate_success_notice flash[:notice] = deactivate_success_notice
end end
redirect_to scheme_details_path(@scheme) redirect_to scheme_details_path(@scheme)
@ -299,7 +299,7 @@ private
when :deactivated when :deactivated
"#{@scheme.service_name} has been deactivated" "#{@scheme.service_name} has been deactivated"
when :deactivating_soon when :deactivating_soon
"#{@scheme.service_name} will deactivate on #{@scheme.deactivation_date.to_formatted_s(:govuk_date)}" "#{@scheme.service_name} will deactivate on #{deactivation_date.to_time.to_formatted_s(:govuk_date)}"
end end
end end
@ -319,4 +319,8 @@ private
Time.zone.local(year.to_i, month.to_i, day.to_i) if Date.valid_date?(year.to_i, month.to_i, day.to_i) Time.zone.local(year.to_i, month.to_i, day.to_i) if Date.valid_date?(year.to_i, month.to_i, day.to_i)
end end
def update_affected_logs
@scheme.lettings_logs.filter_by_before_startdate(deactivation_date.to_time).update!(location: nil, scheme: nil)
end
end end

11
app/helpers/schemes_helper.rb

@ -14,7 +14,7 @@ module SchemesHelper
{ name: "Secondary client group", value: scheme.secondary_client_group }, { name: "Secondary client group", value: scheme.secondary_client_group },
{ name: "Level of support given", value: scheme.support_type }, { name: "Level of support given", value: scheme.support_type },
{ name: "Intended length of stay", value: scheme.intended_stay }, { name: "Intended length of stay", value: scheme.intended_stay },
{ name: "Availability", value: "Available from #{scheme.available_from.to_formatted_s(:govuk_date)}" }, { name: "Availability", value: scheme_availability(scheme) },
] ]
if FeatureToggle.scheme_toggle_enabled? if FeatureToggle.scheme_toggle_enabled?
@ -26,4 +26,13 @@ module SchemesHelper
end end
base_attributes base_attributes
end end
def scheme_availability(scheme)
availability = "Active from #{scheme.available_from.to_formatted_s(:govuk_date)}"
scheme.scheme_deactivation_periods.each do |deactivation|
availability << " to #{(deactivation.deactivation_date - 1.day).to_formatted_s(:govuk_date)}\nDeactivated on #{deactivation.deactivation_date.to_formatted_s(:govuk_date)}"
availability << "\nActive from #{deactivation.reactivation_date.to_formatted_s(:govuk_date)}" if deactivation.reactivation_date.present?
end
availability
end
end end

2
app/models/lettings_log.rb

@ -45,7 +45,7 @@ class LettingsLog < Log
.or(filter_by_postcode(param)) .or(filter_by_postcode(param))
.or(filter_by_id(param)) .or(filter_by_id(param))
} }
scope :filter_by_before_startdate, ->(date) { left_joins(:location).where("lettings_logs.startdate >= ?", date) } scope :filter_by_before_startdate, ->(date) { where("lettings_logs.startdate >= ?", date) }
AUTOGENERATED_FIELDS = %w[id status created_at updated_at discarded_at].freeze AUTOGENERATED_FIELDS = %w[id status created_at updated_at discarded_at].freeze
OPTIONAL_FIELDS = %w[first_time_property_let_as_social_housing tenancycode propcode].freeze OPTIONAL_FIELDS = %w[first_time_property_let_as_social_housing tenancycode propcode].freeze

10
app/models/scheme.rb

@ -3,6 +3,7 @@ class Scheme < ApplicationRecord
belongs_to :managing_organisation, optional: true, class_name: "Organisation" belongs_to :managing_organisation, optional: true, class_name: "Organisation"
has_many :locations, dependent: :delete_all has_many :locations, dependent: :delete_all
has_many :lettings_logs, class_name: "LettingsLog", dependent: :delete_all has_many :lettings_logs, class_name: "LettingsLog", dependent: :delete_all
has_many :scheme_deactivation_periods, class_name: "SchemeDeactivationPeriod"
has_paper_trail has_paper_trail
@ -22,7 +23,7 @@ class Scheme < ApplicationRecord
auto_strip_attributes :service_name auto_strip_attributes :service_name
attr_accessor :deactivation_date_type, :run_deactivation_validations attr_accessor :deactivation_date_type, :deactivation_date, :run_deactivation_validations
SENSITIVE = { SENSITIVE = {
No: 0, No: 0,
@ -216,8 +217,9 @@ class Scheme < ApplicationRecord
end end
def status def status
return :active if deactivation_date.blank? recent_deactivation = scheme_deactivation_periods.deactivations_without_reactivation.first
return :deactivating_soon if Time.zone.now < deactivation_date return :active if recent_deactivation.blank?
return :deactivating_soon if Time.zone.now < recent_deactivation.deactivation_date
:deactivated :deactivated
end end
@ -245,7 +247,7 @@ class Scheme < ApplicationRecord
end end
else else
collection_start_date = FormHandler.instance.current_collection_start_date collection_start_date = FormHandler.instance.current_collection_start_date
unless deactivation_date.between?(collection_start_date, Date.new(2200, 1, 1)) unless deactivation_date.between?(collection_start_date, Time.zone.local(2200, 1, 1))
errors.add(:deactivation_date, message: I18n.t("validations.scheme.deactivation_date.out_of_range", date: collection_start_date.to_formatted_s(:govuk_date))) errors.add(:deactivation_date, message: I18n.t("validations.scheme.deactivation_date.out_of_range", date: collection_start_date.to_formatted_s(:govuk_date)))
end end
end end

3
app/models/scheme_deactivation_period.rb

@ -0,0 +1,3 @@
class SchemeDeactivationPeriod < ApplicationRecord
scope :deactivations_without_reactivation, -> { where(reactivation_date: nil) }
end

10
db/migrate/20221117103841_add_scheme_deactivations.rb

@ -0,0 +1,10 @@
class AddSchemeDeactivations < ActiveRecord::Migration[7.0]
def change
create_table :scheme_deactivation_periods do |t|
t.datetime :deactivation_date
t.datetime :reactivation_date
t.belongs_to :scheme
t.timestamps
end
end
end

13
db/migrate/20221117103855_remove_deactivation_date_from_schemes.rb

@ -0,0 +1,13 @@
class RemoveDeactivationDateFromSchemes < ActiveRecord::Migration[7.0]
def up
change_table :schemes, bulk: true do |t|
t.remove :deactivation_date
end
end
def down
change_table :schemes, bulk: true do |t|
t.column :deactivation_date, :datetime
end
end
end

18
db/schema.rb

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.0].define(version: 2022_11_15_113437) do ActiveRecord::Schema[7.0].define(version: 2022_11_17_103855) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -372,20 +372,29 @@ ActiveRecord::Schema[7.0].define(version: 2022_11_15_113437) do
t.integer "la_known" t.integer "la_known"
t.integer "income1" t.integer "income1"
t.integer "income1nk" t.integer "income1nk"
t.integer "details_known_2"
t.integer "details_known_3"
t.integer "details_known_4"
t.integer "age4" t.integer "age4"
t.integer "age4_known" t.integer "age4_known"
t.integer "age5" t.integer "age5"
t.integer "age5_known" t.integer "age5_known"
t.integer "age6" t.integer "age6"
t.integer "age6_known" t.integer "age6_known"
t.integer "details_known_2"
t.integer "details_known_3"
t.integer "details_known_4"
t.index ["created_by_id"], name: "index_sales_logs_on_created_by_id" t.index ["created_by_id"], name: "index_sales_logs_on_created_by_id"
t.index ["managing_organisation_id"], name: "index_sales_logs_on_managing_organisation_id" t.index ["managing_organisation_id"], name: "index_sales_logs_on_managing_organisation_id"
t.index ["owning_organisation_id"], name: "index_sales_logs_on_owning_organisation_id" t.index ["owning_organisation_id"], name: "index_sales_logs_on_owning_organisation_id"
end end
create_table "scheme_deactivation_periods", force: :cascade do |t|
t.datetime "deactivation_date"
t.datetime "reactivation_date"
t.bigint "scheme_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["scheme_id"], name: "index_scheme_deactivation_periods_on_scheme_id"
end
create_table "schemes", force: :cascade do |t| create_table "schemes", force: :cascade do |t|
t.string "service_name" t.string "service_name"
t.bigint "owning_organisation_id", null: false t.bigint "owning_organisation_id", null: false
@ -406,7 +415,6 @@ ActiveRecord::Schema[7.0].define(version: 2022_11_15_113437) do
t.string "old_visible_id" t.string "old_visible_id"
t.integer "total_units" t.integer "total_units"
t.boolean "confirmed" t.boolean "confirmed"
t.datetime "deactivation_date"
t.index ["managing_organisation_id"], name: "index_schemes_on_managing_organisation_id" t.index ["managing_organisation_id"], name: "index_schemes_on_managing_organisation_id"
t.index ["owning_organisation_id"], name: "index_schemes_on_owning_organisation_id" t.index ["owning_organisation_id"], name: "index_schemes_on_owning_organisation_id"
end end

5
spec/factories/scheme_deactivation_period.rb

@ -0,0 +1,5 @@
FactoryBot.define do
factory :scheme_deactivation_period do
reactivation_date { nil }
end
end

25
spec/helpers/schemes_helper_spec.rb

@ -18,10 +18,33 @@ RSpec.describe SchemesHelper do
{ name: "Secondary client group", value: scheme.secondary_client_group }, { name: "Secondary client group", value: scheme.secondary_client_group },
{ name: "Level of support given", value: scheme.support_type }, { name: "Level of support given", value: scheme.support_type },
{ name: "Intended length of stay", value: scheme.intended_stay }, { name: "Intended length of stay", value: scheme.intended_stay },
{ name: "Availability", value: "Available from 8 August 2022" }, { name: "Availability", value: "Active from 8 August 2022" },
{ name: "Status", value: :active }, { name: "Status", value: :active },
] ]
expect(display_scheme_attributes(scheme)).to eq(attributes) expect(display_scheme_attributes(scheme)).to eq(attributes)
end end
context "when viewing availability" do
context "with are no deactivations" do
it "displays created_at as availability date" do
availability_attribute = display_scheme_attributes(scheme).find { |x| x[:name] == "Availability" }[:value]
expect(availability_attribute).to eq("Active from #{scheme.created_at.to_formatted_s(:govuk_date)}")
end
end
context "with previous deactivations" do
before do
scheme.scheme_deactivation_periods << FactoryBot.create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 8, 10), reactivation_date: Time.zone.local(2022, 9, 1))
scheme.scheme_deactivation_periods << FactoryBot.create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 9, 15), reactivation_date: nil)
end
it "displays the timeline of availability" do
availability_attribute = display_scheme_attributes(scheme).find { |x| x[:name] == "Availability" }[:value]
expect(availability_attribute).to eq("Active from 8 August 2022 to 9 August 2022\nDeactivated on 10 August 2022\nActive from 1 September 2022 to 14 September 2022\nDeactivated on 15 September 2022")
end
end
end
end end
end end

68
spec/models/scheme_spec.rb

@ -99,32 +99,56 @@ RSpec.describe Scheme, type: :model do
Timecop.freeze(2022, 6, 7) Timecop.freeze(2022, 6, 7)
end end
it "returns active if the scheme is not deactivated" do context "when there have not been any previous deactivations" do
scheme.deactivation_date = nil it "returns active if the scheme is not deactivated" do
scheme.deactivation_date_type = nil expect(scheme.status).to eq(:active)
scheme.save! end
expect(scheme.status).to eq(:active)
end
it "returns deactivating soon if deactivation_date is in the future" do it "returns deactivating soon if deactivation_date is in the future" do
scheme.deactivation_date = Time.zone.local(2022, 8, 8) scheme.scheme_deactivation_periods << FactoryBot.create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 8, 8))
scheme.deactivation_date_type = "other" scheme.save!
scheme.save! expect(scheme.status).to eq(:deactivating_soon)
expect(scheme.status).to eq(:deactivating_soon) end
end
it "returns deactivated if deactivation_date is in the past" do it "returns deactivated if deactivation_date is in the past" do
scheme.deactivation_date = Time.zone.local(2022, 4, 8) scheme.scheme_deactivation_periods << FactoryBot.create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 6))
scheme.deactivation_date_type = "other" scheme.save!
scheme.save! expect(scheme.status).to eq(:deactivated)
expect(scheme.status).to eq(:deactivated) end
it "returns deactivated if deactivation_date is today" do
scheme.scheme_deactivation_periods << FactoryBot.create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 7))
scheme.save!
expect(scheme.status).to eq(:deactivated)
end
end end
it "returns deactivated if deactivation_date is today" do context "when there have been previous deactivations" do
scheme.deactivation_date = Time.zone.local(2022, 6, 7) before do
scheme.deactivation_date_type = "other" scheme.scheme_deactivation_periods << FactoryBot.create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 4), reactivation_date: Time.zone.local(2022, 6, 5))
scheme.save! end
expect(scheme.status).to eq(:deactivated)
it "returns active if the scheme has no relevant deactivation records" do
expect(scheme.status).to eq(:active)
end
it "returns deactivating soon if deactivation_date is in the future" do
scheme.scheme_deactivation_periods << FactoryBot.create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 8, 8))
scheme.save!
expect(scheme.status).to eq(:deactivating_soon)
end
it "returns deactivated if deactivation_date is in the past" do
scheme.scheme_deactivation_periods << FactoryBot.create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 6))
scheme.save!
expect(scheme.status).to eq(:deactivated)
end
it "returns deactivated if deactivation_date is today" do
scheme.scheme_deactivation_periods << FactoryBot.create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 7))
scheme.save!
expect(scheme.status).to eq(:deactivated)
end
end end
end end

42
spec/requests/schemes_controller_spec.rb

@ -246,19 +246,18 @@ RSpec.describe SchemesController, type: :request do
context "when looking at scheme details" do context "when looking at scheme details" do
let(:user) { FactoryBot.create(:user, :data_coordinator) } let(:user) { FactoryBot.create(:user, :data_coordinator) }
let!(:scheme) { FactoryBot.create(:scheme, owning_organisation: user.organisation) } let!(:scheme) { FactoryBot.create(:scheme, owning_organisation: user.organisation) }
let(:add_deactivations) { scheme.scheme_deactivation_periods << scheme_deactivation_period }
before do before do
Timecop.freeze(Time.utc(2022, 10, 10)) Timecop.freeze(Time.utc(2022, 10, 10))
sign_in user sign_in user
scheme.deactivation_date = deactivation_date add_deactivations
scheme.deactivation_date_type = deactivation_date_type
scheme.save! scheme.save!
get "/schemes/#{scheme.id}" get "/schemes/#{scheme.id}"
end end
context "with active scheme" do context "with active scheme" do
let(:deactivation_date) { nil } let(:add_deactivations) {}
let(:deactivation_date_type) { nil }
it "renders deactivate this scheme" do it "renders deactivate this scheme" do
expect(response).to have_http_status(:ok) expect(response).to have_http_status(:ok)
@ -267,8 +266,7 @@ RSpec.describe SchemesController, type: :request do
end end
context "with deactivated scheme" do context "with deactivated scheme" do
let(:deactivation_date) { Time.utc(2022, 10, 9) } let(:scheme_deactivation_period) { FactoryBot.create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 10, 9)) }
let(:deactivation_date_type) { "other" }
it "renders reactivate this scheme" do it "renders reactivate this scheme" do
expect(response).to have_http_status(:ok) expect(response).to have_http_status(:ok)
@ -277,8 +275,7 @@ RSpec.describe SchemesController, type: :request do
end end
context "with scheme that's deactivating soon" do context "with scheme that's deactivating soon" do
let(:deactivation_date) { Time.utc(2022, 10, 12) } let(:scheme_deactivation_period) { FactoryBot.create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 10, 12)) }
let(:deactivation_date_type) { "other" }
it "renders reactivate this scheme" do it "renders reactivate this scheme" do
expect(response).to have_http_status(:ok) expect(response).to have_http_status(:ok)
@ -1768,8 +1765,10 @@ RSpec.describe SchemesController, type: :request do
context "when signed in as a data coordinator" do context "when signed in as a data coordinator" do
let(:user) { FactoryBot.create(:user, :data_coordinator) } let(:user) { FactoryBot.create(:user, :data_coordinator) }
let!(:scheme) { FactoryBot.create(:scheme, owning_organisation: user.organisation) } let!(:scheme) { FactoryBot.create(:scheme, owning_organisation: user.organisation) }
let(:startdate) { Time.utc(2021, 1, 2) } let!(:location) { FactoryBot.create(:location, scheme:) }
let(:deactivation_date) { Time.utc(2022, 10, 10) } let(:deactivation_date) { Time.utc(2022, 10, 10) }
let!(:lettings_log) { FactoryBot.create(:lettings_log, :sh, location:, scheme:, startdate:, owning_organisation: user.organisation) }
let(:startdate) { Time.utc(2022, 10, 11) }
before do before do
Timecop.freeze(Time.utc(2022, 10, 10)) Timecop.freeze(Time.utc(2022, 10, 10))
@ -1812,7 +1811,30 @@ RSpec.describe SchemesController, type: :request do
expect(response).to have_http_status(:ok) expect(response).to have_http_status(:ok)
expect(page).to have_css(".govuk-notification-banner.govuk-notification-banner--success") expect(page).to have_css(".govuk-notification-banner.govuk-notification-banner--success")
scheme.reload scheme.reload
expect(scheme.deactivation_date).to eq(deactivation_date) expect(scheme.scheme_deactivation_periods.count).to eq(1)
expect(scheme.scheme_deactivation_periods.first.deactivation_date).to eq(deactivation_date)
end
context "and a log startdate is after scheme deactivation date" do
it "clears the scheme and scheme answers" do
expect(lettings_log.scheme).to eq(scheme)
expect(lettings_log.scheme).to eq(scheme)
lettings_log.reload
expect(lettings_log.scheme).to eq(nil)
expect(lettings_log.scheme).to eq(nil)
end
end
context "and a log startdate is before scheme deactivation date" do
let(:startdate) { Time.utc(2022, 10, 9) }
it "does not update the log" do
expect(lettings_log.scheme).to eq(scheme)
expect(lettings_log.scheme).to eq(scheme)
lettings_log.reload
expect(lettings_log.scheme).to eq(scheme)
expect(lettings_log.scheme).to eq(scheme)
end
end end
end end

Loading…
Cancel
Save