Browse Source

CLDC-1687 allow deactivation or reactivation of last year schemes and locations in crossover period (#1396)

* create method to test whether we are currently in the crossover period and associated tests

* update copy, use method for testing whether we are in the crossover period, remove focus from test file

* reuse existing method to determine whether we are in a collection period

* use the existing method and update validations

* fix test broken by changes

* update location in same way as scheme

* create method on FormHandler that finds the start date of the earliest collection period

* ensure that default deactivation and reactivation dates also reflect the changes

* create tests for the new validations

* lint correction

* minor copy change

* minor logic change

* amend naming error after rebase conflict
remove test that is no longer correct after change on another branch to functionality
update a test after a copy change
pull/1523/head
Arthur Campbell 2 years ago committed by GitHub
parent
commit
9bbc2c2e17
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      app/controllers/locations_controller.rb
  2. 2
      app/controllers/schemes_controller.rb
  3. 4
      app/models/form_handler.rb
  4. 12
      app/models/location_deactivation_period.rb
  5. 10
      app/models/scheme_deactivation_period.rb
  6. 6
      app/views/locations/toggle_active.html.erb
  7. 6
      app/views/schemes/toggle_active.html.erb
  8. 6
      config/locales/en.yml
  9. 4
      spec/features/schemes_spec.rb
  10. 83
      spec/models/location_deactivation_period_spec.rb
  11. 68
      spec/models/scheme_deactivation_period_spec.rb

2
app/controllers/locations_controller.rb

@ -269,7 +269,7 @@ private
if params[:location_deactivation_period].blank? if params[:location_deactivation_period].blank?
return return
elsif params[:location_deactivation_period]["#{key}_type".to_sym] == "default" elsif params[:location_deactivation_period]["#{key}_type".to_sym] == "default"
return FormHandler.instance.current_collection_start_date return FormHandler.instance.start_date_of_earliest_open_collection_period
elsif params[:location_deactivation_period][key.to_sym].present? elsif params[:location_deactivation_period][key.to_sym].present?
return params[:location_deactivation_period][key.to_sym] return params[:location_deactivation_period][key.to_sym]
end end

2
app/controllers/schemes_controller.rb

@ -296,7 +296,7 @@ private
if params[:scheme_deactivation_period].blank? if params[:scheme_deactivation_period].blank?
return return
elsif params[:scheme_deactivation_period]["#{key}_type".to_sym] == "default" elsif params[:scheme_deactivation_period]["#{key}_type".to_sym] == "default"
return FormHandler.instance.current_collection_start_date return FormHandler.instance.start_date_of_earliest_open_collection_period
elsif params[:scheme_deactivation_period][key.to_sym].present? elsif params[:scheme_deactivation_period][key.to_sym].present?
return params[:scheme_deactivation_period][key.to_sym] return params[:scheme_deactivation_period][key.to_sym]
end end

4
app/models/form_handler.rb

@ -77,6 +77,10 @@ class FormHandler
form_mappings[current_collection_start_year - year] form_mappings[current_collection_start_year - year]
end end
def start_date_of_earliest_open_collection_period
in_crossover_period? ? previous_collection_start_date : current_collection_start_date
end
def in_crossover_period?(now: Time.zone.now) def in_crossover_period?(now: Time.zone.now)
lettings_in_crossover_period?(now:) || sales_in_crossover_period?(now:) lettings_in_crossover_period?(now:) || sales_in_crossover_period?(now:)
end end

12
app/models/location_deactivation_period.rb

@ -1,4 +1,6 @@
class LocationDeactivationPeriodValidator < ActiveModel::Validator class LocationDeactivationPeriodValidator < ActiveModel::Validator
include CollectionTimeHelper
def validate(record) def validate(record)
location = record.location location = record.location
recent_deactivation = location.location_deactivation_periods.deactivations_without_reactivation.first recent_deactivation = location.location_deactivation_periods.deactivations_without_reactivation.first
@ -16,7 +18,7 @@ class LocationDeactivationPeriodValidator < ActiveModel::Validator
elsif record.reactivation_date_type == "other" elsif record.reactivation_date_type == "other"
record.errors.add(:reactivation_date, message: I18n.t("validations.location.toggle_date.invalid")) record.errors.add(:reactivation_date, message: I18n.t("validations.location.toggle_date.invalid"))
end end
elsif !record.reactivation_date.between?(location.available_from, Time.zone.local(2200, 1, 1)) elsif record.reactivation_date.before? location.available_from
record.errors.add(:reactivation_date, message: I18n.t("validations.location.toggle_date.out_of_range", date: location.available_from.to_formatted_s(:govuk_date))) record.errors.add(:reactivation_date, message: I18n.t("validations.location.toggle_date.out_of_range", date: location.available_from.to_formatted_s(:govuk_date)))
elsif record.reactivation_date < recent_deactivation.deactivation_date elsif record.reactivation_date < recent_deactivation.deactivation_date
record.errors.add(:reactivation_date, message: I18n.t("validations.location.reactivation.before_deactivation", date: recent_deactivation.deactivation_date.to_formatted_s(:govuk_date))) record.errors.add(:reactivation_date, message: I18n.t("validations.location.reactivation.before_deactivation", date: recent_deactivation.deactivation_date.to_formatted_s(:govuk_date)))
@ -32,10 +34,10 @@ class LocationDeactivationPeriodValidator < ActiveModel::Validator
end end
elsif location.location_deactivation_periods.any? { |period| period.reactivation_date.present? && record.deactivation_date.between?(period.deactivation_date, period.reactivation_date - 1.day) } elsif location.location_deactivation_periods.any? { |period| period.reactivation_date.present? && record.deactivation_date.between?(period.deactivation_date, period.reactivation_date - 1.day) }
record.errors.add(:deactivation_date, message: I18n.t("validations.location.deactivation.during_deactivated_period")) record.errors.add(:deactivation_date, message: I18n.t("validations.location.deactivation.during_deactivated_period"))
else elsif record.deactivation_date.before? FormHandler.instance.start_date_of_earliest_open_collection_period
unless record.deactivation_date.between?(location.available_from, Time.zone.local(2200, 1, 1)) record.errors.add(:deactivation_date, message: I18n.t("validations.location.toggle_date.out_of_range", date: FormHandler.instance.start_date_of_earliest_open_collection_period.to_formatted_s(:govuk_date)))
record.errors.add(:deactivation_date, message: I18n.t("validations.location.toggle_date.out_of_range", date: location.available_from.to_formatted_s(:govuk_date))) elsif record.deactivation_date.before? location.available_from
end record.errors.add(:deactivation_date, message: I18n.t("validations.location.toggle_date.before_creation", date: location.available_from.to_formatted_s(:govuk_date)))
end end
end end
end end

10
app/models/scheme_deactivation_period.rb

@ -1,4 +1,6 @@
class SchemeDeactivationPeriodValidator < ActiveModel::Validator class SchemeDeactivationPeriodValidator < ActiveModel::Validator
include CollectionTimeHelper
def validate(record) def validate(record)
scheme = record.scheme scheme = record.scheme
recent_deactivation = scheme.scheme_deactivation_periods.deactivations_without_reactivation.first recent_deactivation = scheme.scheme_deactivation_periods.deactivations_without_reactivation.first
@ -32,10 +34,10 @@ class SchemeDeactivationPeriodValidator < ActiveModel::Validator
end end
elsif scheme.scheme_deactivation_periods.any? { |period| period.reactivation_date.present? && record.deactivation_date.between?(period.deactivation_date, period.reactivation_date - 1.day) } elsif scheme.scheme_deactivation_periods.any? { |period| period.reactivation_date.present? && record.deactivation_date.between?(period.deactivation_date, period.reactivation_date - 1.day) }
record.errors.add(:deactivation_date, message: I18n.t("validations.scheme.deactivation.during_deactivated_period")) record.errors.add(:deactivation_date, message: I18n.t("validations.scheme.deactivation.during_deactivated_period"))
else elsif record.deactivation_date.before? FormHandler.instance.start_date_of_earliest_open_collection_period
unless record.deactivation_date.between?(scheme.available_from, Time.zone.local(2200, 1, 1)) record.errors.add(:deactivation_date, message: I18n.t("validations.scheme.toggle_date.out_of_range", date: FormHandler.instance.start_date_of_earliest_open_collection_period.to_formatted_s(:govuk_date)))
record.errors.add(:deactivation_date, message: I18n.t("validations.scheme.toggle_date.out_of_range", date: scheme.available_from.to_formatted_s(:govuk_date))) elsif record.deactivation_date.before? scheme.available_from
end record.errors.add(:deactivation_date, message: I18n.t("validations.scheme.toggle_date.before_creation", date: scheme.available_from.to_formatted_s(:govuk_date)))
end end
end end
end end

6
app/views/locations/toggle_active.html.erb

@ -11,16 +11,16 @@
<%= form_with model: @location_deactivation_period, url: toggle_location_form_path(action, @location), method: "patch", local: true do |f| %> <%= form_with model: @location_deactivation_period, url: toggle_location_form_path(action, @location), method: "patch", local: true do |f| %>
<div class="govuk-grid-row"> <div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds"> <div class="govuk-grid-column-two-thirds">
<% collection_start_date = FormHandler.instance.earliest_open_collection_start_date(now: @location.available_from) %> <% start_date = FormHandler.instance.earliest_open_collection_start_date(now: @location.available_from) %>
<%= f.govuk_error_summary %> <%= f.govuk_error_summary %>
<%= f.govuk_radio_buttons_fieldset date_type_question(action), <%= f.govuk_radio_buttons_fieldset date_type_question(action),
legend: { text: I18n.t("questions.location.toggle_active.apply_from") }, legend: { text: I18n.t("questions.location.toggle_active.apply_from") },
caption: { text: title }, caption: { text: title },
hint: { text: I18n.t("hints.location.toggle_active", date: collection_start_date.to_formatted_s(:govuk_date)) } do %> hint: { text: I18n.t("hints.location.toggle_active", date: start_date.to_formatted_s(:govuk_date)) } do %>
<%= govuk_warning_text text: I18n.t("warnings.location.#{action}.existing_logs") %> <%= govuk_warning_text text: I18n.t("warnings.location.#{action}.existing_logs") %>
<%= f.govuk_radio_button date_type_question(action), <%= f.govuk_radio_button date_type_question(action),
"default", "default",
label: { text: "From the start of the current collection period (#{collection_start_date.to_formatted_s(:govuk_date)})" } %> label: { text: "From the start of the open collection period (#{start_date.to_formatted_s(:govuk_date)})" } %>
<%= f.govuk_radio_button date_type_question(action), <%= f.govuk_radio_button date_type_question(action),
"other", "other",

6
app/views/schemes/toggle_active.html.erb

@ -11,16 +11,16 @@
<%= form_with model: @scheme_deactivation_period, url: toggle_scheme_form_path(action, @scheme), method: "patch", local: true do |f| %> <%= form_with model: @scheme_deactivation_period, url: toggle_scheme_form_path(action, @scheme), method: "patch", local: true do |f| %>
<div class="govuk-grid-row"> <div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds"> <div class="govuk-grid-column-two-thirds">
<% collection_start_date = FormHandler.instance.current_collection_start_date %> <% start_date = FormHandler.instance.start_date_of_earliest_open_collection_period %>
<%= f.govuk_error_summary %> <%= f.govuk_error_summary %>
<%= f.govuk_radio_buttons_fieldset date_type_question(action), <%= f.govuk_radio_buttons_fieldset date_type_question(action),
legend: { text: I18n.t("questions.scheme.toggle_active.apply_from") }, legend: { text: I18n.t("questions.scheme.toggle_active.apply_from") },
caption: { text: title }, caption: { text: title },
hint: { text: I18n.t("hints.scheme.toggle_active", date: collection_start_date.to_formatted_s(:govuk_date)) } do %> hint: { text: I18n.t("hints.scheme.toggle_active", date: start_date.to_formatted_s(:govuk_date)) } do %>
<%= govuk_warning_text text: I18n.t("warnings.scheme.#{action}.existing_logs") %> <%= govuk_warning_text text: I18n.t("warnings.scheme.#{action}.existing_logs") %>
<%= f.govuk_radio_button date_type_question(action), <%= f.govuk_radio_button date_type_question(action),
"default", "default",
label: { text: "From the start of the current collection period (#{collection_start_date.to_formatted_s(:govuk_date)})" } %> label: { text: "From the start of the open collection period (#{start_date.to_formatted_s(:govuk_date)})" } %>
<%= f.govuk_radio_button date_type_question(action), <%= f.govuk_radio_button date_type_question(action),
"other", "other",
label: { text: "For tenancies starting after a certain date" }, label: { text: "For tenancies starting after a certain date" },

6
config/locales/en.yml

@ -456,6 +456,7 @@ en:
toggle_date: toggle_date:
not_selected: "Select one of the options" not_selected: "Select one of the options"
invalid: "Enter a valid day, month and year" invalid: "Enter a valid day, month and year"
before_creation: "The scheme cannot be deactivated before %{date}, the start of the collection year when it was created"
out_of_range: "The date must be on or after the %{date}" out_of_range: "The date must be on or after the %{date}"
reactivation: reactivation:
before_deactivation: "This scheme was deactivated on %{date}. The reactivation date must be on or after deactivation date" before_deactivation: "This scheme was deactivated on %{date}. The reactivation date must be on or after deactivation date"
@ -474,6 +475,7 @@ en:
toggle_date: toggle_date:
not_selected: "Select one of the options" not_selected: "Select one of the options"
invalid: "Enter a valid day, month and year" invalid: "Enter a valid day, month and year"
before_creation: "The location cannot be deactivated before %{date}, the date when it was first available"
out_of_range: "The date must be on or after the %{date}" out_of_range: "The date must be on or after the %{date}"
reactivation: reactivation:
before_deactivation: "This location was deactivated on %{date}. The reactivation date must be on or after deactivation date" before_deactivation: "This location was deactivated on %{date}. The reactivation date must be on or after deactivation date"
@ -594,10 +596,10 @@ en:
postcode: "For example, SW1P 4DF." postcode: "For example, SW1P 4DF."
name: "This is how you refer to this location within your organisation" name: "This is how you refer to this location within your organisation"
units: "A unit is the space being let. For example, the property might be a block of flats and the unit would be the specific flat being let. A unit can also be a bedroom in a shared house or flat. Do not include spaces used for staff." units: "A unit is the space being let. For example, the property might be a block of flats and the unit would be the specific flat being let. A unit can also be a bedroom in a shared house or flat. Do not include spaces used for staff."
toggle_active: "If the date is before %{date}, select ‘From the start of the current collection period’ because the previous period has now closed." toggle_active: "If the date is before %{date}, select ‘From the start of the open collection period’ because the previous period has now closed."
startdate: "For example, 27 3 2021" startdate: "For example, 27 3 2021"
scheme: scheme:
toggle_active: "If the date is before %{date}, select ‘From the start of the current collection period’ because the previous period has now closed." toggle_active: "If the date is before %{date}, select ‘From the start of the open collection period’ because the previous period has now closed."
bulk_upload: bulk_upload:
needstype: "General needs housing includes both self-contained and shared housing without support or specific adaptations. Supported housing can include direct access hostels, group homes, residential care and nursing homes." needstype: "General needs housing includes both self-contained and shared housing without support or specific adaptations. Supported housing can include direct access hostels, group homes, residential care and nursing homes."
offered: "Do not include the offer that led to this letting. This is after the last tenancy ended. If the property is being offered for let for the first time, enter 0." offered: "Do not include the offer that led to this letting. This is after the last tenancy ended. If the property is being offered for let for the first time, enter 0."

4
spec/features/schemes_spec.rb

@ -742,7 +742,7 @@ RSpec.describe "Schemes scheme Features" do
expect(page).to have_current_path("/schemes/#{scheme.id}/locations") expect(page).to have_current_path("/schemes/#{scheme.id}/locations")
end end
context "when location is incative" do context "when location is inactive" do
context "and I click to view the location" do context "and I click to view the location" do
before do before do
click_link(deactivated_location.postcode) click_link(deactivated_location.postcode)
@ -766,7 +766,7 @@ RSpec.describe "Schemes scheme Features" do
expect(page).to have_current_path("/schemes/#{scheme.id}/locations/#{deactivated_location.id}/new-reactivation") expect(page).to have_current_path("/schemes/#{scheme.id}/locations/#{deactivated_location.id}/new-reactivation")
expect(page).to have_content("Reactivate #{deactivated_location.name}") expect(page).to have_content("Reactivate #{deactivated_location.name}")
expect(page).to have_content("You’ll be able to add logs with this location if their tenancy start date is on or after the date you enter.") expect(page).to have_content("You’ll be able to add logs with this location if their tenancy start date is on or after the date you enter.")
expect(page).to have_content("If the date is before 1 April 2022, select ‘From the start of the current collection period’ because the previous period has now closed.") expect(page).to have_content("If the date is before 1 April 2022, select ‘From the start of the open collection period’ because the previous period has now closed.")
end end
context "when I press the back button" do context "when I press the back button" do

83
spec/models/location_deactivation_period_spec.rb

@ -0,0 +1,83 @@
require "rails_helper"
RSpec.describe LocationDeactivationPeriod do
let(:validator) { LocationDeactivationPeriodValidator.new }
let(:location) { FactoryBot.create(:location, startdate: now - 2.years) }
let(:record) { FactoryBot.create(:location_deactivation_period, deactivation_date: now, location:) }
describe "#validate" do
around do |example|
Timecop.freeze(now) do
example.run
end
end
context "when not in a crossover period" do
let(:now) { Time.utc(2023, 3, 1) }
context "with a deactivation date before the current collection period" do
it "adds an error" do
record.deactivation_date = now - 1.year
location.location_deactivation_periods.clear
validator.validate(record)
expect(record.errors[:deactivation_date]).to include "The date must be on or after the 1 April 2022"
end
end
context "with a deactivation date in the current collection period" do
it "does not add an error" do
record.deactivation_date = now - 1.day
location.location_deactivation_periods.clear
validator.validate(record)
expect(record.errors).to be_empty
end
end
end
context "when in a crossover period" do
let(:now) { Time.utc(2023, 5, 1) }
context "with a deactivation date before the previous collection period" do
it "does not add an error" do
record.deactivation_date = now - 2.years
location.location_deactivation_periods.clear
validator.validate(record)
expect(record.errors[:deactivation_date]).to include "The date must be on or after the 1 April 2022"
end
end
context "with a deactivation date in the previous collection period" do
it "does not add an error" do
record.deactivation_date = now - 1.year
location.location_deactivation_periods.clear
validator.validate(record)
expect(record.errors).to be_empty
end
end
context "with a deactivation date in the current collection period" do
it "does not add an error" do
record.deactivation_date = now - 1.day
location.location_deactivation_periods.clear
validator.validate(record)
expect(record.errors).to be_empty
end
end
context "but the location was created in the current collection period" do
let(:location) { FactoryBot.create(:location, startdate:) }
let(:startdate) { now - 2.days }
context "with a deactivation date in the previous collection period" do
it "adds an error" do
record.deactivation_date = now - 1.year
location.location_deactivation_periods.clear
validator.validate(record)
start_date = startdate.to_formatted_s(:govuk_date)
expect(record.errors[:deactivation_date]).to include "The location cannot be deactivated before #{start_date}, the date when it was first available"
end
end
end
end
end
end

68
spec/models/scheme_deactivation_period_spec.rb

@ -0,0 +1,68 @@
require "rails_helper"
RSpec.describe SchemeDeactivationPeriod do
let(:validator) { SchemeDeactivationPeriodValidator.new }
let(:scheme) { FactoryBot.create(:scheme, created_at: now - 2.years) }
let(:record) { FactoryBot.create(:scheme_deactivation_period, deactivation_date: now, scheme:) }
describe "#validate" do
around do |example|
Timecop.freeze(now) do
example.run
end
end
context "when not in a crossover period" do
let(:now) { Time.utc(2023, 3, 1) }
context "with a deactivation date before the current collection period" do
it "adds an error" do
record.deactivation_date = now - 1.year
scheme.scheme_deactivation_periods.clear
validator.validate(record)
expect(record.errors[:deactivation_date]).to include("The date must be on or after the 1 April 2022")
end
end
context "with a deactivation date in the current collection period" do
it "does not add an error" do
record.deactivation_date = now - 1.day
scheme.scheme_deactivation_periods.clear
validator.validate(record)
expect(record.errors[:deactivation_date]).to be_empty
end
end
end
context "when in a crossover period" do
let(:now) { Time.utc(2023, 5, 1) }
context "with a deactivation date before the previous collection period" do
it "does not add an error" do
record.deactivation_date = now - 2.years
scheme.scheme_deactivation_periods.clear
validator.validate(record)
expect(record.errors[:deactivation_date]).to include("The date must be on or after the 1 April 2022")
end
end
context "with a deactivation date in the previous collection period" do
it "does not add an error" do
record.deactivation_date = now - 1.year
scheme.scheme_deactivation_periods.clear
validator.validate(record)
expect(record.errors[:deactivation_date]).to be_empty
end
end
context "with a deactivation date in the current collection period" do
it "does not add an error" do
record.deactivation_date = now - 1.day
scheme.scheme_deactivation_periods.clear
validator.validate(record)
expect(record.errors[:deactivation_date]).to be_empty
end
end
end
end
end
Loading…
Cancel
Save