Browse Source

CLDC-1917 Add Startdate Validation (#1378)

* feat: add validation with feature flag, typo fix and update tests

* feat: flip feature toggle

* feat: update feature toggle name

* feat: fix form handler inequality

* refactor: linting

* refactor: use between in form handler

* feat: remove feature toggle

* feat: add dynamic date to lettings log factory

* feat: fix log_summary_component_spec.rb tests

* feat: update lettings_log.rb and start fixing lettings_log_spec.rb

* feat: fix more tests

* feat: fix more tests

* feat: fix lettings log import service

* refactor: linting

* feat: fix checkboxes_spec.rb

* feat: fix interruption_screen_helper_spec.rb

* feat: fix check_answers_helper_spec.rb

* feat: fix page_routing_spec.rb

* feat: fix lettings_logs_field_import_service_spec.rb

* feat: fix lettings_log_spec.rb

* feat: fix question_spec.rb

* feat: fix lettings_logs_controller_spec.rb

* feat: fix check_answers_page_lettings_logs_spec.rb

* feat: fix tenancy_validations_spec.rb

* feat: fix validations_spec.rb

* feat: fix accessible_autocomplete_spec.rb

* feat: fix form_navigation_spec.rb

* feat: fix soft_validations_spec.rb

* feat: fix lettings_log_export_service_spec.rb

* feat: fix saving_data_spec.rb

* feat: fix page_spec.rb

* feat: fix form_controller_spec.rb

* refactor: linting

* feat: fix subsection_spec.rb

* feat: fix lettings_log_spec.rb

* feat: fix financial_validations_spec.rb

* feat: fix tasklist_page_spec.rb

* feat: fix conditional_questions_spec.rb

* feat: fix form_page_error_helper_spec.rb and log_summary_component_spec.rb

* feat: fix lettings_log_csv_service_spec.rb

* feat: fix tasklist_helper_spec.rb

* refactor: linting

* refactor: linting

* feat: fix lettings_log_spec.rb

* refactor: linting

* refactor: replace financial year with collection yaer

* feat: respond to PR comments pt. 1

* feat: respond to PR comments pt. 2
revert-1378-CLDC-1917-startdate-validation
natdeanlewissoftwire 2 years ago committed by GitHub
parent
commit
f758d598c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      app/models/form_handler.rb
  2. 26
      app/models/validations/date_validations.rb
  3. 12
      app/models/validations/sales/setup_validations.rb
  4. 40
      app/models/validations/setup_validations.rb
  5. 4
      config/initializers/feature_toggle.rb
  6. 14
      config/locales/en.yml
  7. 2
      db/schema.rb
  8. 6
      spec/components/log_summary_component_spec.rb
  9. 13
      spec/factories/lettings_log.rb
  10. 13
      spec/features/form/accessible_autocomplete_spec.rb
  11. 11
      spec/features/form/check_answers_page_lettings_logs_spec.rb
  12. 9
      spec/features/form/checkboxes_spec.rb
  13. 10
      spec/features/form/conditional_questions_spec.rb
  14. 9
      spec/features/form/form_navigation_spec.rb
  15. 159
      spec/features/form/page_routing_spec.rb
  16. 9
      spec/features/form/progressive_total_field_spec.rb
  17. 9
      spec/features/form/saving_data_spec.rb
  18. 16
      spec/features/form/tasklist_page_spec.rb
  19. 11
      spec/features/form/validations_spec.rb
  20. 2
      spec/fixtures/exports/general_needs_log.csv
  21. 4
      spec/fixtures/exports/general_needs_log.xml
  22. 4
      spec/fixtures/exports/supported_housing_logs.xml
  23. 9
      spec/helpers/check_answers_helper_spec.rb
  24. 9
      spec/helpers/form_page_error_helper_spec.rb
  25. 9
      spec/helpers/interruption_screen_helper_spec.rb
  26. 86
      spec/helpers/tasklist_helper_spec.rb
  27. 6
      spec/jobs/email_csv_job_spec.rb
  28. 9
      spec/models/form/page_spec.rb
  29. 11
      spec/models/form/question_spec.rb
  30. 9
      spec/models/form/subsection_spec.rb
  31. 9
      spec/models/form_spec.rb
  32. 181
      spec/models/lettings_log_spec.rb
  33. 24
      spec/models/validations/date_validations_spec.rb
  34. 2
      spec/models/validations/financial_validations_spec.rb
  35. 20
      spec/models/validations/sales/setup_validations_spec.rb
  36. 102
      spec/models/validations/setup_validations_spec.rb
  37. 16
      spec/models/validations/soft_validations_spec.rb
  38. 20
      spec/models/validations/tenancy_validations_spec.rb
  39. 16
      spec/requests/form_controller_spec.rb
  40. 44
      spec/requests/lettings_logs_controller_spec.rb
  41. 9
      spec/requests/sales_logs_controller_spec.rb
  42. 2
      spec/services/csv/lettings_log_csv_service_spec.rb
  43. 8
      spec/services/exports/lettings_log_export_service_spec.rb
  44. 11
      spec/services/imports/lettings_logs_field_import_service_spec.rb
  45. 733
      spec/services/imports/lettings_logs_import_service_spec.rb
  46. 9
      spec/views/form/page_view_spec.rb

4
app/models/form_handler.rb

@ -79,12 +79,12 @@ class FormHandler
def lettings_in_crossover_period?(now: Time.zone.now)
forms = lettings_forms.values
forms.count { |form| form.start_date < now && now < form.end_date } > 1
forms.count { |form| now.between?(form.start_date, form.end_date) } > 1
end
def sales_in_crossover_period?(now: Time.zone.now)
forms = sales_forms.values
forms.count { |form| form.start_date < now && now < form.end_date } > 1
forms.count { |form| now.between?(form.start_date, form.end_date) } > 1
end
def use_fake_forms!

26
app/models/validations/date_validations.rb

@ -33,16 +33,6 @@ module Validations::DateValidations
def validate_startdate(record)
return unless record.startdate && date_valid?("startdate", record)
created_at = record.created_at || Time.zone.now
if created_at > first_collection_end_date && record.startdate < second_collection_start_date
record.errors.add :startdate, I18n.t("validations.date.outside_collection_window")
end
if (record.startdate < first_collection_start_date || record.startdate > second_collection_end_date) && FeatureToggle.startdate_collection_window_validation_enabled?
record.errors.add :startdate, I18n.t("validations.date.outside_collection_window")
end
if FeatureToggle.startdate_two_week_validation_enabled? && record.startdate > Time.zone.today + 14
record.errors.add :startdate, I18n.t("validations.setup.startdate.later_than_14_days_after")
end
@ -68,22 +58,6 @@ module Validations::DateValidations
private
def first_collection_start_date
@first_collection_start_date ||= FormHandler.instance.lettings_forms["previous_lettings"].start_date
end
def first_collection_end_date
@first_collection_end_date ||= FormHandler.instance.lettings_forms["previous_lettings"].end_date
end
def second_collection_start_date
@second_collection_start_date ||= FormHandler.instance.lettings_forms["current_lettings"].start_date
end
def second_collection_end_date
@second_collection_end_date ||= FormHandler.instance.lettings_forms["current_lettings"].end_date
end
def is_rsnvac_first_let?(record)
[15, 16, 17].include?(record["rsnvac"])
end

12
app/models/validations/sales/setup_validations.rb

@ -3,10 +3,10 @@ module Validations::Sales::SetupValidations
include CollectionTimeHelper
def validate_saledate(record)
return unless record.saledate && date_valid?("saledate", record)
return unless record.saledate && date_valid?("saledate", record) && FeatureToggle.saledate_collection_window_validation_enabled?
unless record.saledate.between?(active_collection_start_date, current_collection_end_date) || !FeatureToggle.saledate_collection_window_validation_enabled?
record.errors.add :saledate, validation_error_message
unless record.saledate.between?(active_collection_start_date, current_collection_end_date)
record.errors.add :saledate, saledate_validation_error_message
end
end
@ -20,12 +20,12 @@ private
end
end
def validation_error_message
def saledate_validation_error_message
current_end_year_long = current_collection_end_date.strftime("#{current_collection_end_date.day.ordinalize} %B %Y")
if FormHandler.instance.sales_in_crossover_period?
I18n.t(
"validations.setup.saledate.previous_and_current_financial_year",
"validations.setup.saledate.previous_and_current_collection_year",
previous_start_year_short: previous_collection_start_date.strftime("%y"),
previous_end_year_short: previous_collection_end_date.strftime("%y"),
previous_start_year_long: previous_collection_start_date.strftime("#{previous_collection_start_date.day.ordinalize} %B %Y"),
@ -34,7 +34,7 @@ private
)
else
I18n.t(
"validations.setup.saledate.current_financial_year",
"validations.setup.saledate.current_collection_year",
current_start_year_short: current_collection_start_date.strftime("%y"),
current_end_year_short: current_collection_end_date.strftime("%y"),
current_start_year_long: current_collection_start_date.strftime("#{current_collection_start_date.day.ordinalize} %B %Y"),

40
app/models/validations/setup_validations.rb

@ -1,5 +1,14 @@
module Validations::SetupValidations
include Validations::SharedValidations
include CollectionTimeHelper
def validate_startdate_setup(record)
return unless record.startdate && date_valid?("startdate", record) && FeatureToggle.startdate_collection_window_validation_enabled?
unless record.startdate.between?(active_collection_start_date, current_collection_end_date)
record.errors.add :startdate, startdate_validation_error_message
end
end
def validate_irproduct_other(record)
if intermediate_product_rent_type?(record) && record.irproduct_other.blank?
@ -27,6 +36,37 @@ module Validations::SetupValidations
private
def active_collection_start_date
if FormHandler.instance.lettings_in_crossover_period?
previous_collection_start_date
else
current_collection_start_date
end
end
def startdate_validation_error_message
current_end_year_long = current_collection_end_date.strftime("#{current_collection_end_date.day.ordinalize} %B %Y")
if FormHandler.instance.lettings_in_crossover_period?
I18n.t(
"validations.setup.startdate.previous_and_current_collection_year",
previous_start_year_short: previous_collection_start_date.strftime("%y"),
previous_end_year_short: previous_collection_end_date.strftime("%y"),
previous_start_year_long: previous_collection_start_date.strftime("#{previous_collection_start_date.day.ordinalize} %B %Y"),
current_end_year_short: current_collection_end_date.strftime("%y"),
current_end_year_long:,
)
else
I18n.t(
"validations.setup.startdate.current_collection_year",
current_start_year_short: current_collection_start_date.strftime("%y"),
current_end_year_short: current_collection_end_date.strftime("%y"),
current_start_year_long: current_collection_start_date.strftime("#{current_collection_start_date.day.ordinalize} %B %Y"),
current_end_year_long:,
)
end
end
def intermediate_product_rent_type?(record)
record.rent_type == 5
end

4
config/initializers/feature_toggle.rb

@ -4,11 +4,11 @@ class FeatureToggle
Rails.env.production? || Rails.env.test? || Rails.env.staging?
end
def self.startdate_two_week_validation_enabled?
def self.startdate_collection_window_validation_enabled?
Rails.env.production? || Rails.env.test? || Rails.env.staging?
end
def self.startdate_collection_window_validation_enabled?
def self.startdate_two_week_validation_enabled?
Rails.env.production? || Rails.env.test? || Rails.env.staging?
end

14
config/locales/en.yml

@ -141,7 +141,7 @@ en:
above_min: "%{field} must be at least %{min}"
date:
invalid_date: "Enter a date in the correct format, for example 31 1 2022"
outside_collection_window: Enter a date within the 22/23 financial year, which is between 1st April 2022 and 31st March 2023
outside_collection_window: Enter a date within the 22/23 collection year, which is between 1st April 2022 and 31st March 2023
postcode: "Enter a postcode in the correct format, for example AA1 1AA"
location_admin_district: "Select a local authority"
email:
@ -155,14 +155,18 @@ en:
intermediate_rent_product_name:
blank: "Enter name of other intermediate rent product"
saledate:
current_financial_year:
Enter a date within the %{current_start_year_short}/%{current_end_year_short} financial year, which is between %{current_start_year_long} and %{current_end_year_long}
previous_and_current_financial_year:
"Enter a date within the %{previous_start_year_short}/%{previous_end_year_short} or %{previous_end_year_short}/%{current_end_year_short} financial years, which is between %{previous_start_year_long} and %{current_end_year_long}"
current_collection_year:
Enter a date within the %{current_start_year_short}/%{current_end_year_short} collection year, which is between %{current_start_year_long} and %{current_end_year_long}
previous_and_current_collection_year:
"Enter a date within the %{previous_start_year_short}/%{previous_end_year_short} or %{previous_end_year_short}/%{current_end_year_short} collection years, which is between %{previous_start_year_long} and %{current_end_year_long}"
type:
percentage_bought_must_be_at_least_threshold: "The minimum increase in equity while staircasing is %{threshold}% for this shared ownership type"
startdate:
current_collection_year:
Enter a date within the %{current_start_year_short}/%{current_end_year_short} collection year, which is between %{current_start_year_long} and %{current_end_year_long}
previous_and_current_collection_year:
"Enter a date within the %{previous_start_year_short}/%{previous_end_year_short} or %{previous_end_year_short}/%{current_end_year_short} collection years, which is between %{previous_start_year_long} and %{current_end_year_long}"
later_than_14_days_after: "The tenancy start date must not be later than 14 days from today’s date"
before_scheme_end_date: "The tenancy start date must be before the end date for this supported housing scheme"
after_void_date: "Enter a tenancy start date that is after the void date"

2
db/schema.rb

@ -557,9 +557,9 @@ ActiveRecord::Schema[7.0].define(version: 2023_03_09_145740) do
t.integer "ethnicbuy2"
t.integer "proplen_asked"
t.string "old_id"
t.integer "pregblank"
t.integer "buy2living"
t.integer "prevtenbuy2"
t.integer "pregblank"
t.integer "nationalbuy2"
t.string "uprn"
t.integer "uprn_known"

6
spec/components/log_summary_component_spec.rb

@ -5,7 +5,7 @@ RSpec.describe LogSummaryComponent, type: :component do
let(:coordinator_user) { FactoryBot.create(:user) }
let(:propcode) { "P3647" }
let(:tenancycode) { "T62863" }
let(:lettings_log) { FactoryBot.create(:lettings_log, needstype: 1, startdate: Time.utc(2022, 1, 1), tenancycode:, propcode:) }
let(:lettings_log) { FactoryBot.create(:lettings_log, needstype: 1, tenancycode:, propcode:, startdate: Time.zone.today) }
let(:sales_log) { FactoryBot.create(:sales_log) }
context "when rendering lettings log for a support user" do
@ -16,8 +16,8 @@ RSpec.describe LogSummaryComponent, type: :component do
expect(result).to have_text(lettings_log.tenancycode)
expect(result).to have_text(lettings_log.propcode)
expect(result).to have_text("General needs")
expect(result).to have_text("Tenancy starts 1 January 2022")
expect(result).to have_text("Created 8 February 2022")
expect(result).to have_text("Tenancy starts #{Time.zone.today.strftime('%e %B %Y')}")
expect(result).to have_text("Created #{Time.zone.today.strftime('%e %B %Y')}")
expect(result).to have_text("by Danny Rojas")
expect(result).to have_content("Owned by\n DLUHC")
expect(result).to have_content("Managed by\n DLUHC")

13
spec/factories/lettings_log.rb

@ -7,7 +7,6 @@ FactoryBot.define do
renewal { 0 }
needstype { 1 }
rent_type { 1 }
startdate { Time.zone.local(2022, 5, 1) }
end
trait :in_progress do
status { 1 }
@ -18,7 +17,7 @@ FactoryBot.define do
age2 { 19 }
renewal { 1 }
rent_type { 1 }
startdate { Time.zone.local(2021, 5, 1) }
startdate { Time.zone.today }
end
trait :soft_validations_triggered do
status { 1 }
@ -36,6 +35,7 @@ FactoryBot.define do
hhmemb { 1 }
end
trait :completed do
startdate { Time.zone.today }
status { 2 }
tenancycode { Faker::Name.initials(number: 10) }
age1_known { 0 }
@ -66,7 +66,7 @@ FactoryBot.define do
rsnvac { 6 }
unittype_gn { 7 }
beds { 3 }
voiddate { "03/11/2019" }
voiddate { 2.days.ago }
offered { 2 }
wchair { 1 }
earnings { 68 }
@ -132,9 +132,8 @@ FactoryBot.define do
hbrentshortfall { 1 }
tshortfall { 12 }
property_relet { 0 }
mrcdate { Time.zone.local(2020, 5, 5, 10, 36, 49) }
mrcdate { 1.day.ago }
incref { 0 }
startdate { Time.zone.today }
armedforces { 1 }
builtype { 1 }
unitletas { 2 }
@ -155,7 +154,7 @@ FactoryBot.define do
sheltered { 0 }
household_charge { 0 }
end
created_at { Time.utc(2022, 2, 8, 16, 52, 15) }
updated_at { Time.utc(2022, 2, 8, 16, 52, 15) }
created_at { Time.zone.today }
updated_at { Time.zone.today }
end
end

13
spec/features/form/accessible_autocomplete_spec.rb

@ -2,6 +2,15 @@ require "rails_helper"
require_relative "helpers"
RSpec.describe "Accessible Autocomplete" do
around do |example|
Timecop.freeze(Time.zone.local(2022, 1, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
include Helpers
let(:user) { FactoryBot.create(:user) }
let(:lettings_log) do
@ -64,8 +73,8 @@ RSpec.describe "Accessible Autocomplete" do
let(:scheme) { FactoryBot.create(:scheme, owning_organisation_id: lettings_log.created_by.organisation_id, primary_client_group: "Q", secondary_client_group: "P") }
before do
FactoryBot.create(:location, scheme:, postcode: "W6 0ST")
FactoryBot.create(:location, scheme:, postcode: "SE6 1LB")
FactoryBot.create(:location, scheme:, postcode: "W6 0ST", startdate: Time.zone.local(2022, 1, 1))
FactoryBot.create(:location, scheme:, postcode: "SE6 1LB", startdate: Time.zone.local(2022, 1, 1))
lettings_log.update!(needstype: 2)
visit("/lettings-logs/#{lettings_log.id}/scheme")
end

11
spec/features/form/check_answers_page_lettings_logs_spec.rb

@ -2,6 +2,15 @@ require "rails_helper"
require_relative "helpers"
RSpec.describe "Lettings Log Check Answers Page" do
around do |example|
Timecop.freeze(Time.zone.local(2021, 5, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
include Helpers
let(:user) { FactoryBot.create(:user) }
let(:subsection) { "household-characteristics" }
@ -152,7 +161,7 @@ RSpec.describe "Lettings Log Check Answers Page" do
context "when viewing setup section answers" do
before do
FactoryBot.create(:location, scheme:)
FactoryBot.create(:location, scheme:, startdate: Time.zone.local(2021, 1, 1))
end
it "displays inferred postcode with the location id" do

9
spec/features/form/checkboxes_spec.rb

@ -14,6 +14,15 @@ RSpec.describe "Checkboxes" do
end
let(:id) { lettings_log.id }
around do |example|
Timecop.freeze(Time.zone.local(2022, 1, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
before do
allow(lettings_log.form).to receive(:end_date).and_return(Time.zone.today + 1.day)
RequestHelper.stub_http_requests

10
spec/features/form/conditional_questions_spec.rb

@ -2,6 +2,15 @@ require "rails_helper"
require_relative "helpers"
RSpec.describe "Form Conditional Questions" do
around do |example|
Timecop.freeze(Time.zone.local(2022, 1, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
include Helpers
let(:user) { FactoryBot.create(:user) }
let(:lettings_log) do
@ -16,6 +25,7 @@ RSpec.describe "Form Conditional Questions" do
:sales_log,
:completed,
created_by: user,
saledate: Time.zone.local(2022, 1, 1),
)
end
let(:id) { lettings_log.id }

9
spec/features/form/form_navigation_spec.rb

@ -2,6 +2,15 @@ require "rails_helper"
require_relative "helpers"
RSpec.describe "Form Navigation" do
around do |example|
Timecop.travel(Time.zone.local(2022, 1, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
include Helpers
let(:user) { FactoryBot.create(:user) }
let(:lettings_log) do

159
spec/features/form/page_routing_spec.rb

@ -20,95 +20,106 @@ RSpec.describe "Form Page Routing" do
sign_in user
end
it "can route the user to a different page based on their answer on the current page", js: true do
visit("/lettings-logs/#{id}/conditional-question")
# using a question name that is already in the db to avoid
# having to add a new column to the db for this test
choose("lettings-log-preg-occ-1-field", allow_label_click: true)
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{id}/conditional-question-yes-page")
click_link(text: "Back")
expect(page).to have_current_path("/lettings-logs/#{id}/conditional-question")
choose("lettings-log-preg-occ-2-field", allow_label_click: true)
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{id}/conditional-question-no-page")
end
it "can route based on multiple conditions", js: true do
visit("/lettings-logs/#{id}/person-1-gender")
choose("lettings-log-sex1-f-field", allow_label_click: true)
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{id}/person-1-working-situation")
visit("/lettings-logs/#{id}/conditional-question")
choose("lettings-log-preg-occ-2-field", allow_label_click: true)
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{id}/conditional-question-no-page")
choose("lettings-log-cbl-0-field", allow_label_click: true)
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{id}/conditional-question/check-answers")
end
context "with 21/22 logs" do
around do |example|
Timecop.freeze(Time.zone.local(2022, 1, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
context "when the answers are inferred", js: true do
it "shows question if the answer could not be inferred" do
visit("/lettings-logs/#{id}/property-postcode")
fill_in("lettings-log-postcode-full-field", with: "PO5 3TE")
it "can route the user to a different page based on their answer on the current page", js: true do
visit("/lettings-logs/#{id}/conditional-question")
# using a question name that is already in the db to avoid
# having to add a new column to the db for this test
choose("lettings-log-preg-occ-1-field", allow_label_click: true)
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{id}/conditional-question-yes-page")
click_link(text: "Back")
expect(page).to have_current_path("/lettings-logs/#{id}/conditional-question")
choose("lettings-log-preg-occ-2-field", allow_label_click: true)
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{id}/do-you-know-the-local-authority")
expect(page).to have_current_path("/lettings-logs/#{id}/conditional-question-no-page")
end
it "shows question if the answer could not be inferred from an empty input" do
visit("/lettings-logs/#{id}/property-postcode")
it "can route based on multiple conditions", js: true do
visit("/lettings-logs/#{id}/person-1-gender")
choose("lettings-log-sex1-f-field", allow_label_click: true)
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{id}/do-you-know-the-local-authority")
expect(page).to have_current_path("/lettings-logs/#{id}/person-1-working-situation")
visit("/lettings-logs/#{id}/conditional-question")
choose("lettings-log-preg-occ-2-field", allow_label_click: true)
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{id}/conditional-question-no-page")
choose("lettings-log-cbl-0-field", allow_label_click: true)
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{id}/conditional-question/check-answers")
end
it "does not show question if the answer could be inferred" do
stub_request(:get, /api.postcodes.io/)
.to_return(status: 200, body: "{\"status\":200,\"result\":{\"admin_district\":\"Manchester\", \"codes\":{\"admin_district\": \"E08000003\"}}}", headers: {})
context "when the answers are inferred", js: true do
it "shows question if the answer could not be inferred" do
visit("/lettings-logs/#{id}/property-postcode")
fill_in("lettings-log-postcode-full-field", with: "PO5 3TE")
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{id}/do-you-know-the-local-authority")
end
visit("/lettings-logs/#{id}/property-postcode")
fill_in("lettings-log-postcode-full-field", with: "P0 5ST")
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{id}/property-wheelchair-accessible")
end
end
it "shows question if the answer could not be inferred from an empty input" do
visit("/lettings-logs/#{id}/property-postcode")
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{id}/do-you-know-the-local-authority")
end
context "when answer is invalid" do
it "shows error with invalid value in the field" do
visit("/lettings-logs/#{id}/property-postcode")
fill_in("lettings-log-postcode-full-field", with: "fake_postcode")
click_button("Save and continue")
it "does not show question if the answer could be inferred" do
stub_request(:get, /api.postcodes.io/)
.to_return(status: 200, body: "{\"status\":200,\"result\":{\"admin_district\":\"Manchester\", \"codes\":{\"admin_district\": \"E08000003\"}}}", headers: {})
expect(page).to have_current_path("/lettings-logs/#{id}/property-postcode")
expect(find("#lettings-log-postcode-full-field-error").value).to eq("fake_postcode")
visit("/lettings-logs/#{id}/property-postcode")
fill_in("lettings-log-postcode-full-field", with: "P0 5ST")
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{id}/property-wheelchair-accessible")
end
end
it "does not reset the displayed date" do
lettings_log.update!(startdate: "2021/10/13")
visit("/lettings-logs/#{id}/tenancy-start-date")
fill_in("lettings_log[startdate(1i)]", with: "202")
fill_in("lettings_log[startdate(2i)]", with: "32")
fill_in("lettings_log[startdate(3i)]", with: "0")
click_button("Save and continue")
context "when answer is invalid" do
it "shows error with invalid value in the field" do
visit("/lettings-logs/#{id}/property-postcode")
fill_in("lettings-log-postcode-full-field", with: "fake_postcode")
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{id}/tenancy-start-date")
expect(find_field("lettings_log[startdate(3i)]").value).to eq("13")
expect(find_field("lettings_log[startdate(2i)]").value).to eq("10")
expect(find_field("lettings_log[startdate(1i)]").value).to eq("2021")
end
expect(page).to have_current_path("/lettings-logs/#{id}/property-postcode")
expect(find("#lettings-log-postcode-full-field-error").value).to eq("fake_postcode")
end
it "does not reset the displayed date if it's empty" do
lettings_log.update!(startdate: nil)
visit("/lettings-logs/#{id}/tenancy-start-date")
fill_in("lettings_log[startdate(1i)]", with: "202")
fill_in("lettings_log[startdate(2i)]", with: "32")
fill_in("lettings_log[startdate(3i)]", with: "0")
click_button("Save and continue")
it "does not reset the displayed date" do
lettings_log.update!(startdate: "2021/10/13")
visit("/lettings-logs/#{id}/tenancy-start-date")
fill_in("lettings_log[startdate(1i)]", with: "202")
fill_in("lettings_log[startdate(2i)]", with: "32")
fill_in("lettings_log[startdate(3i)]", with: "0")
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{id}/tenancy-start-date")
expect(find_field("lettings_log[startdate(3i)]").value).to eq("13")
expect(find_field("lettings_log[startdate(2i)]").value).to eq("10")
expect(find_field("lettings_log[startdate(1i)]").value).to eq("2021")
end
expect(page).to have_current_path("/lettings-logs/#{id}/tenancy-start-date")
expect(find_field("lettings_log[startdate(3i)]").value).to eq(nil)
expect(find_field("lettings_log[startdate(2i)]").value).to eq(nil)
expect(find_field("lettings_log[startdate(1i)]").value).to eq(nil)
it "does not reset the displayed date if it's empty" do
lettings_log.update!(startdate: nil)
visit("/lettings-logs/#{id}/tenancy-start-date")
fill_in("lettings_log[startdate(1i)]", with: "202")
fill_in("lettings_log[startdate(2i)]", with: "32")
fill_in("lettings_log[startdate(3i)]", with: "0")
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{id}/tenancy-start-date")
expect(find_field("lettings_log[startdate(3i)]").value).to eq(nil)
expect(find_field("lettings_log[startdate(2i)]").value).to eq(nil)
expect(find_field("lettings_log[startdate(1i)]").value).to eq(nil)
end
end
end

9
spec/features/form/progressive_total_field_spec.rb

@ -12,6 +12,15 @@ RSpec.describe "Accessible Autocomplete" do
)
end
around do |example|
Timecop.freeze(Time.zone.local(2022, 1, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
before do
allow(lettings_log.form).to receive(:end_date).and_return(Time.zone.today + 1.day)
sign_in user

9
spec/features/form/saving_data_spec.rb

@ -2,6 +2,15 @@ require "rails_helper"
require_relative "helpers"
RSpec.describe "Form Saving Data" do
around do |example|
Timecop.freeze(Time.zone.local(2022, 1, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
include Helpers
let(:user) { FactoryBot.create(:user) }
let(:lettings_log) do

16
spec/features/form/tasklist_page_spec.rb

@ -36,18 +36,32 @@ RSpec.describe "Task List" do
:about_completed,
owning_organisation: user.organisation,
managing_organisation: user.organisation,
startdate: Time.zone.local(2021, 5, 1),
created_by: user,
)
end
let(:id) { lettings_log.id }
let(:status) { lettings_log.status }
around do |example|
Timecop.freeze(Time.zone.local(2022, 1, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
before do
Timecop.freeze(Time.zone.local(2021, 5, 1))
setup_completed_log.update!(startdate: Time.zone.local(2021, 5, 1))
allow(lettings_log.form).to receive(:end_date).and_return(Time.zone.today + 1.day)
sign_in user
end
after do
Timecop.unfreeze
end
it "shows if the section has not been started" do
visit("/lettings-logs/#{empty_lettings_log.id}")
expect(page).to have_content("This log has not been started.")

11
spec/features/form/validations_spec.rb

@ -2,6 +2,15 @@ require "rails_helper"
require_relative "helpers"
RSpec.describe "validations" do
around do |example|
Timecop.freeze(Time.zone.local(2022, 1, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
let(:fake_2021_2022_form) { Form.new("spec/fixtures/forms/2021_2022.json") }
let(:user) { FactoryBot.create(:user) }
let(:lettings_log) do
@ -26,6 +35,8 @@ RSpec.describe "validations" do
status: 1,
declaration: nil,
startdate: Time.zone.local(2021, 5, 1),
voiddate: Time.zone.local(2021, 5, 1),
mrcdate: Time.zone.local(2021, 5, 1),
)
end
let(:id) { lettings_log.id }

2
spec/fixtures/exports/general_needs_log.csv vendored

@ -1,2 +1,2 @@
status,tenancycode,age1,sex1,ethnic,national,prevten,ecstat1,hhmemb,age2,sex2,ecstat2,age3,sex3,ecstat3,age4,sex4,ecstat4,age5,sex5,ecstat5,age6,sex6,ecstat6,age7,sex7,ecstat7,age8,sex8,ecstat8,homeless,underoccupation_benefitcap,leftreg,reservist,illness,preg_occ,startertenancy,tenancylength,tenancy,ppostcode_full,rsnvac,unittype_gn,beds,offered,wchair,earnings,incfreq,benefits,period,layear,waityear,postcode_full,reasonpref,cbl,chr,cap,reasonother,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,illness_type_1,illness_type_2,illness_type_3,illness_type_4,illness_type_8,illness_type_5,illness_type_6,illness_type_7,illness_type_9,illness_type_10,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,tenancyother,irproduct_other,reason,propcode,la,prevloc,hb,hbrentshortfall,mrcdate,incref,startdate,armedforces,unitletas,builtype,voiddate,renttype,needstype,lettype,totchild,totelder,totadult,nocharge,referral,brent,scharge,pscharge,supcharg,tcharge,tshortfall,chcharge,ppcodenk,has_benefits,renewal,wrent,wscharge,wpschrge,wsupchrg,wtcharge,wtshortfall,refused,housingneeds,wchchrg,newprop,relat2,relat3,relat4,relat5,relat6,relat7,relat8,lar,irproduct,joint,sheltered,hhtype,new_old,vacdays,formid,owningorgid,owningorgname,hcnum,maningorgid,maningorgname,manhcnum,createddate,uploaddate
2,BZ737,35,F,2,4,6,0,2,32,M,6,,,,,,,,,,,,,,,,,,,1,4,1,1,1,2,1,5,1,SE2 6RT,6,7,3,2,1,68,1,1,2,2,1,NW1 5TY,1,2,1,2,,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,,,4,123,E09000003,E07000105,6,1,2020-05-05T10:36:49+01:00,0,2022-02-02T10:36:49+00:00,1,2,1,2019-11-03T00:00:00+00:00,2,1,7,0,0,2,0,2,200.0,50.0,40.0,35.0,325.0,12.0,,1,1,0,100.0,25.0,20.0,17.5,162.5,6.0,0,1,,2,P,,,,,,,,,,,4,2,638,{id},{owning_org_id},DLUHC,1234,{managing_org_id},DLUHC,1234,2022-02-08T16:52:15+00:00,2022-02-08T16:52:15+00:00
2,BZ737,35,F,2,4,6,0,2,32,M,6,,,,,,,,,,,,,,,,,,,1,4,1,1,1,2,1,5,1,SE2 6RT,6,7,3,2,1,68,1,1,2,2,1,NW1 5TY,1,2,1,2,,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,,,4,123,E09000003,E07000105,6,1,2020-05-05T10:36:49+01:00,0,2022-02-02T10:36:49+00:00,1,2,1,2019-11-03T00:00:00+00:00,2,1,7,0,0,2,0,2,200.0,50.0,40.0,35.0,325.0,12.0,,1,1,0,100.0,25.0,20.0,17.5,162.5,6.0,0,1,,2,P,,,,,,,,,,,4,2,638,{id},{owning_org_id},DLUHC,1234,{managing_org_id},DLUHC,1234,2022-05-01T00:00:00+01:00,2022-05-01T00:00:00+01:00

1 status tenancycode age1 sex1 ethnic national prevten ecstat1 hhmemb age2 sex2 ecstat2 age3 sex3 ecstat3 age4 sex4 ecstat4 age5 sex5 ecstat5 age6 sex6 ecstat6 age7 sex7 ecstat7 age8 sex8 ecstat8 homeless underoccupation_benefitcap leftreg reservist illness preg_occ startertenancy tenancylength tenancy ppostcode_full rsnvac unittype_gn beds offered wchair earnings incfreq benefits period layear waityear postcode_full reasonpref cbl chr cap reasonother housingneeds_a housingneeds_b housingneeds_c housingneeds_f housingneeds_g housingneeds_h illness_type_1 illness_type_2 illness_type_3 illness_type_4 illness_type_8 illness_type_5 illness_type_6 illness_type_7 illness_type_9 illness_type_10 rp_homeless rp_insan_unsat rp_medwel rp_hardship rp_dontknow tenancyother irproduct_other reason propcode la prevloc hb hbrentshortfall mrcdate incref startdate armedforces unitletas builtype voiddate renttype needstype lettype totchild totelder totadult nocharge referral brent scharge pscharge supcharg tcharge tshortfall chcharge ppcodenk has_benefits renewal wrent wscharge wpschrge wsupchrg wtcharge wtshortfall refused housingneeds wchchrg newprop relat2 relat3 relat4 relat5 relat6 relat7 relat8 lar irproduct joint sheltered hhtype new_old vacdays formid owningorgid owningorgname hcnum maningorgid maningorgname manhcnum createddate uploaddate
2 2 BZ737 35 F 2 4 6 0 2 32 M 6 1 4 1 1 1 2 1 5 1 SE2 6RT 6 7 3 2 1 68 1 1 2 2 1 NW1 5TY 1 2 1 2 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 4 123 E09000003 E07000105 6 1 2020-05-05T10:36:49+01:00 0 2022-02-02T10:36:49+00:00 1 2 1 2019-11-03T00:00:00+00:00 2 1 7 0 0 2 0 2 200.0 50.0 40.0 35.0 325.0 12.0 1 1 0 100.0 25.0 20.0 17.5 162.5 6.0 0 1 2 P 4 2 638 {id} {owning_org_id} DLUHC 1234 {managing_org_id} DLUHC 1234 2022-02-08T16:52:15+00:00 2022-05-01T00:00:00+01:00 2022-02-08T16:52:15+00:00 2022-05-01T00:00:00+01:00

4
spec/fixtures/exports/general_needs_log.xml vendored

@ -142,8 +142,8 @@
<maningorgid>{managing_org_id}</maningorgid>
<maningorgname>DLUHC</maningorgname>
<manhcnum>1234</manhcnum>
<createddate>2022-02-08T16:52:15+00:00</createddate>
<uploaddate>2022-02-08T16:52:15+00:00</uploaddate>
<createddate>2022-05-01T00:00:00+01:00</createddate>
<uploaddate>2022-05-01T00:00:00+01:00</uploaddate>
<providertype>1</providertype>
</form>
</forms>

4
spec/fixtures/exports/supported_housing_logs.xml vendored

@ -141,8 +141,8 @@
<maningorgid>{managing_org_id}</maningorgid>
<maningorgname>DLUHC</maningorgname>
<manhcnum>1234</manhcnum>
<createddate>2022-02-08T16:52:15+00:00</createddate>
<uploaddate>2022-02-08T16:52:15+00:00</uploaddate>
<createddate>2022-05-01T00:00:00+01:00</createddate>
<uploaddate>2022-05-01T00:00:00+01:00</uploaddate>
<unittype_sh>7</unittype_sh>
<confidential>1</confidential>
<cligrp1>G</cligrp1>

9
spec/helpers/check_answers_helper_spec.rb

@ -6,6 +6,15 @@ RSpec.describe CheckAnswersHelper do
let(:lettings_log) { FactoryBot.build(:lettings_log, :in_progress) }
let(:current_user) { FactoryBot.build(:user) }
around do |example|
Timecop.freeze(Time.zone.local(2022, 1, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
describe "display_answered_questions_summary" do
context "when a section hasn't been completed yet" do
it "returns that you have unanswered questions" do

9
spec/helpers/form_page_error_helper_spec.rb

@ -3,6 +3,15 @@ require "rails_helper"
RSpec.describe FormPageErrorHelper do
describe "#remove_other_page_errors" do
context "when non base other questions are removed" do
around do |example|
Timecop.freeze(Time.zone.local(2022, 1, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
let!(:lettings_log) { FactoryBot.create(:lettings_log, :in_progress) }
let!(:form) { lettings_log.form }

9
spec/helpers/interruption_screen_helper_spec.rb

@ -17,6 +17,15 @@ RSpec.describe InterruptionScreenHelper do
)
end
around do |example|
Timecop.freeze(Time.zone.local(2022, 1, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
describe "display_informative_text" do
context "when 2 out of 2 arguments are given" do
it "returns correct informative text" do

86
spec/helpers/tasklist_helper_spec.rb

@ -1,7 +1,7 @@
require "rails_helper"
RSpec.describe TasklistHelper do
let(:now) { Time.utc(2022, 6, 1) }
let(:now) { Time.utc(2022, 1, 1) }
around do |example|
Timecop.freeze(now) do
@ -13,7 +13,7 @@ RSpec.describe TasklistHelper do
describe "with lettings" do
let(:empty_lettings_log) { create(:lettings_log) }
let(:lettings_log) { build(:lettings_log, :in_progress, needstype: 1) }
let(:lettings_log) { build(:lettings_log, :in_progress, needstype: 1, startdate: now) }
describe "get next incomplete section" do
it "returns the first subsection name if it is not completed" do
@ -27,8 +27,14 @@ RSpec.describe TasklistHelper do
end
describe "get sections count" do
let(:fake_2021_2022_form) { Form.new("spec/fixtures/forms/2021_2022.json") }
before do
allow(FormHandler.instance).to receive(:get_form).and_return(fake_2021_2022_form)
end
it "returns the total of sections if no status is given" do
expect(get_subsections_count(empty_lettings_log)).to eq(1)
expect(get_subsections_count(empty_lettings_log)).to eq(8)
end
it "returns 0 sections for completed sections if no sections are completed" do
@ -36,7 +42,7 @@ RSpec.describe TasklistHelper do
end
it "returns the number of not started sections" do
expect(get_subsections_count(empty_lettings_log, :not_started)).to eq(1)
expect(get_subsections_count(empty_lettings_log, :not_started)).to eq(8)
end
it "returns the number of sections in progress" do
@ -48,41 +54,6 @@ RSpec.describe TasklistHelper do
end
end
describe "review_log_text" do
context "when collection_period_open? == true" do
context "with 2023 deadline" do
let(:now) { Time.utc(2022, 6, 1) }
let(:lettings_log) { create(:lettings_log, :completed) }
it "returns relevant text" do
expect(review_log_text(lettings_log)).to eq(
"You can #{govuk_link_to 'review and make changes to this log', review_lettings_log_path(lettings_log)} until 1 July 2023.".html_safe,
)
end
end
context "with 2024 deadline" do
let(:now) { Time.utc(2023, 6, 20) }
let(:lettings_log) { create(:lettings_log, :completed, national: 18, waityear: 2) }
it "returns relevant text" do
expect(review_log_text(lettings_log)).to eq(
"You can #{govuk_link_to 'review and make changes to this log', review_lettings_log_path(lettings_log)} until 9 July 2024.".html_safe,
)
end
end
end
context "when collection_period_open? == false" do
let(:now) { Time.utc(2023, 7, 8) }
let(:lettings_log) { create(:lettings_log, :completed, startdate: Time.utc(2023, 2, 8)) }
it "returns relevant text" do
expect(review_log_text(lettings_log)).to eq("This log is from the 2022/2023 collection window, which is now closed.")
end
end
end
describe "subsection link" do
let(:lettings_log) { create(:lettings_log, :completed) }
let(:subsection) { lettings_log.form.get_subsection("household_characteristics") }
@ -130,5 +101,42 @@ RSpec.describe TasklistHelper do
end
end
end
context "with lettings log" do
context "when collection_period_open? == true" do
context "with 2023 deadline" do
let(:now) { Time.utc(2022, 6, 1) }
let(:lettings_log) { create(:lettings_log, :completed) }
it "returns relevant text" do
expect(review_log_text(lettings_log)).to eq(
"You can #{govuk_link_to 'review and make changes to this log', review_lettings_log_path(lettings_log)} until 1 July 2023.".html_safe,
)
end
end
context "with 2024 deadline" do
let(:now) { Time.utc(2023, 6, 20) }
let(:lettings_log) { create(:lettings_log, :completed, national: 18, waityear: 2) }
it "returns relevant text" do
expect(review_log_text(lettings_log)).to eq(
"You can #{govuk_link_to 'review and make changes to this log', review_lettings_log_path(lettings_log)} until 9 July 2024.".html_safe,
)
end
end
end
context "when collection_period_open? == false" do
let(:now) { Time.utc(2022, 6, 1) }
let!(:sales_log) { create(:lettings_log, :completed) }
it "returns relevant text" do
Timecop.freeze(now + 1.year) do
expect(review_log_text(sales_log)).to eq("This log is from the 2021/2022 collection window, which is now closed.")
end
end
end
end
end
end

6
spec/jobs/email_csv_job_spec.rb

@ -31,7 +31,9 @@ describe EmailCsvJob do
FactoryBot.create(:lettings_log,
:completed,
created_by: user,
startdate: Time.zone.local(2021, 5, 1))
startdate: Time.zone.local(2022, 5, 1),
voiddate: Time.zone.local(2022, 5, 1),
mrcdate: Time.zone.local(2022, 5, 1))
allow(Storage::S3Service).to receive(:new).and_return(storage_service)
allow(storage_service).to receive(:write_file)
@ -104,7 +106,7 @@ describe EmailCsvJob do
it "writes answer labels rather than values" do
expect_csv do |csv|
expect(csv.second[16]).to eq("Full-time – 30 hours or more")
expect(csv.second[19]).to eq("Full-time – 30 hours or more")
end
job.perform(user)

9
spec/models/form/page_spec.rb

@ -3,6 +3,15 @@ require "rails_helper"
RSpec.describe Form::Page, type: :model do
subject(:page) { described_class.new(page_id, page_definition, subsection) }
around do |example|
Timecop.freeze(Time.zone.local(2022, 1, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
let(:user) { FactoryBot.create(:user) }
let(:lettings_log) { FactoryBot.build(:lettings_log) }
let(:form) { lettings_log.form }

11
spec/models/form/question_spec.rb

@ -3,6 +3,15 @@ require "rails_helper"
RSpec.describe Form::Question, type: :model do
subject(:question) { described_class.new(question_id, question_definition, page) }
around do |example|
Timecop.freeze(Time.zone.local(2022, 1, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
let(:lettings_log) { FactoryBot.build(:lettings_log) }
let(:form) { lettings_log.form }
let(:section_id) { "rent_and_charges" }
@ -367,7 +376,7 @@ RSpec.describe Form::Question, type: :model do
end
context "when Sales form" do
let(:sales_log) { FactoryBot.create(:sales_log, :completed, ethnic_group: 17) }
let(:sales_log) { FactoryBot.create(:sales_log, :completed, ethnic_group: 17, saledate: Time.zone.local(2022, 1, 1)) }
let(:question) { sales_log.form.get_question("ethnic_group", sales_log) }
it "returns the inferred label value" do

9
spec/models/form/subsection_spec.rb

@ -4,6 +4,15 @@ require_relative "../../request_helper"
RSpec.describe Form::Subsection, type: :model do
subject(:subsection) { described_class.new(subsection_id, subsection_definition, section) }
around do |example|
Timecop.freeze(Time.zone.local(2022, 1, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
let(:lettings_log) { FactoryBot.build(:lettings_log) }
let(:form) { lettings_log.form }
let(:section_id) { "household" }

9
spec/models/form_spec.rb

@ -1,6 +1,15 @@
require "rails_helper"
RSpec.describe Form, type: :model do
around do |example|
Timecop.freeze(Time.zone.local(2022, 1, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
let(:user) { FactoryBot.build(:user) }
let(:lettings_log) { FactoryBot.build(:lettings_log, :in_progress) }
let(:form) { lettings_log.form }

181
spec/models/lettings_log_spec.rb

@ -6,6 +6,16 @@ RSpec.describe LettingsLog do
let(:created_by_user) { create(:user) }
let(:owning_organisation) { created_by_user.organisation }
let(:fake_2021_2022_form) { Form.new("spec/fixtures/forms/2021_2022.json") }
let(:fake_2022_2023_form) { Form.new("spec/fixtures/forms/2022_2023.json") }
around do |example|
Timecop.freeze(Time.utc(2022, 1, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
before do
allow(FormHandler.instance).to receive(:current_lettings_form).and_return(fake_2021_2022_form)
@ -33,7 +43,15 @@ RSpec.describe LettingsLog do
let(:lettings_log_2) { build(:lettings_log, startdate: Time.zone.local(2022, 1, 1), created_by: created_by_user) }
let(:lettings_log_year_2) { build(:lettings_log, startdate: Time.zone.local(2023, 5, 1), created_by: created_by_user) }
it "has returns the correct form based on the start date" do
before do
Timecop.freeze(2023, 1, 1)
end
after do
Timecop.unfreeze
end
it "returns the correct form based on the start date" do
expect(lettings_log.form_name).to be_nil
expect(lettings_log.form).to be_a(Form)
expect(lettings_log_2.form_name).to eq("previous_lettings")
@ -1477,10 +1495,15 @@ RSpec.describe LettingsLog do
context "when deriving renttype and unitletas" do
before do
Timecop.freeze(Time.zone.local(2022, 1, 1))
allow(FeatureToggle).to receive(:startdate_two_week_validation_enabled?).and_return(false)
lettings_log.update!(rent_type:, irproduct_other: "other")
end
after do
Timecop.unfreeze
end
context "when the rent_type is Social Rent (0)" do
let(:rent_type) { 0 }
@ -1497,6 +1520,23 @@ RSpec.describe LettingsLog do
end
context "and it is a 23/24 form" do
before do
Timecop.freeze(Time.zone.local(2023, 5, 1))
end
after do
Timecop.unfreeze
end
around do |example|
Timecop.freeze(Time.zone.local(2023, 5, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
it "derives and saves unitletas as Social rent(1)" do
lettings_log.update!(startdate: Time.zone.local(2023, 5, 1))
record_from_db = ActiveRecord::Base.connection.execute("select unitletas from lettings_logs where id=#{lettings_log.id}").to_a[0]
@ -1522,6 +1562,23 @@ RSpec.describe LettingsLog do
end
context "and it is a 23/24 form" do
before do
Timecop.freeze(Time.zone.local(2023, 5, 1))
end
after do
Timecop.unfreeze
end
around do |example|
Timecop.freeze(Time.zone.local(2023, 5, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
it "derives and saves unitletas as Affordable Rent basis(2)" do
lettings_log.update!(startdate: Time.zone.local(2023, 5, 1))
record_from_db = ActiveRecord::Base.connection.execute("select unitletas from lettings_logs where id=#{lettings_log.id}").to_a[0]
@ -1547,6 +1604,23 @@ RSpec.describe LettingsLog do
end
context "and it is a 23/24 form" do
before do
Timecop.freeze(Time.zone.local(2023, 5, 1))
end
after do
Timecop.unfreeze
end
around do |example|
Timecop.freeze(Time.zone.local(2023, 5, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
it "derives and saves unitletas as London Affordable Rent basis(5)" do
lettings_log.update!(startdate: Time.zone.local(2023, 5, 1))
record_from_db = ActiveRecord::Base.connection.execute("select unitletas from lettings_logs where id=#{lettings_log.id}").to_a[0]
@ -1572,6 +1646,23 @@ RSpec.describe LettingsLog do
end
context "and it is a 23/24 form" do
before do
Timecop.freeze(Time.zone.local(2023, 5, 1))
end
after do
Timecop.unfreeze
end
around do |example|
Timecop.freeze(Time.zone.local(2023, 5, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
it "derives and saves unitletas as Rent to Buy basis(6)" do
lettings_log.update!(startdate: Time.zone.local(2023, 5, 1))
record_from_db = ActiveRecord::Base.connection.execute("select unitletas from lettings_logs where id=#{lettings_log.id}").to_a[0]
@ -1597,6 +1688,23 @@ RSpec.describe LettingsLog do
end
context "and it is a 23/24 form" do
before do
Timecop.freeze(Time.zone.local(2023, 5, 1))
end
after do
Timecop.unfreeze
end
around do |example|
Timecop.freeze(Time.zone.local(2023, 5, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
it "derives and saves unitletas as London Living Rent basis(7)" do
lettings_log.update!(startdate: Time.zone.local(2023, 5, 1))
record_from_db = ActiveRecord::Base.connection.execute("select unitletas from lettings_logs where id=#{lettings_log.id}").to_a[0]
@ -1622,6 +1730,23 @@ RSpec.describe LettingsLog do
end
context "and it is a 23/24 form" do
before do
Timecop.freeze(Time.zone.local(2023, 5, 1))
end
after do
Timecop.unfreeze
end
around do |example|
Timecop.freeze(Time.zone.local(2023, 5, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
it "derives and saves unitletas as Other intermediate rent basis(8)" do
lettings_log.update!(startdate: Time.zone.local(2023, 5, 1))
record_from_db = ActiveRecord::Base.connection.execute("select unitletas from lettings_logs where id=#{lettings_log.id}").to_a[0]
@ -1863,7 +1988,11 @@ RSpec.describe LettingsLog do
let(:scheme) { create(:scheme) }
let!(:location) { create(:location, scheme:) }
before { lettings_log.update!(startdate: Time.zone.local(2022, 4, 2), scheme:) }
before do
Timecop.freeze(Time.zone.local(2022, 4, 2))
lettings_log.update!(startdate: Time.zone.local(2022, 4, 2), scheme:)
Timecop.unfreeze
end
it "derives the scheme location" do
record_from_db = ActiveRecord::Base.connection.execute("select location_id from lettings_logs where id=#{lettings_log.id}").to_a[0]
@ -1950,9 +2079,16 @@ RSpec.describe LettingsLog do
end
context "and renewal" do
before do
Timecop.freeze(Time.zone.local(2022, 4, 2))
end
after do
Timecop.unfreeze
end
let(:scheme) { create(:scheme) }
let(:location) { create(:location, scheme:) }
let!(:supported_housing_lettings_log) do
described_class.create!({
managing_organisation: owning_organisation,
@ -1962,12 +2098,12 @@ RSpec.describe LettingsLog do
scheme_id: scheme.id,
location_id: location.id,
renewal: 1,
startdate: Time.zone.now,
startdate: Time.zone.local(2022, 4, 2),
created_at: Time.utc(2022, 2, 8, 16, 52, 15),
})
end
it "correcly infers and saves the renewal date" do
it "correctly infers and saves the renewal date" do
record_from_db = ActiveRecord::Base.connection.execute("SELECT voiddate from lettings_logs where id=#{supported_housing_lettings_log.id}").to_a[0]
expect(record_from_db["voiddate"].to_i).to eq(supported_housing_lettings_log.startdate.to_i)
end
@ -2333,6 +2469,15 @@ RSpec.describe LettingsLog do
end
context "and the new location triggers the rent range validation" do
around do |example|
Timecop.freeze(Time.zone.local(2022, 4, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
it "clears rent values" do
lettings_log.update!(location:, scheme:)
lettings_log.reload
@ -2467,8 +2612,8 @@ RSpec.describe LettingsLog do
end
describe "scopes" do
let!(:lettings_log_1) { create(:lettings_log, :in_progress, startdate: Time.utc(2021, 5, 3), created_by: created_by_user) }
let!(:lettings_log_2) { create(:lettings_log, :completed, startdate: Time.utc(2021, 5, 3), created_by: created_by_user) }
let!(:lettings_log_1) { create(:lettings_log, :in_progress, startdate: Time.utc(2021, 5, 3), mrcdate: Time.utc(2021, 5, 3), voiddate: Time.utc(2021, 5, 3), created_by: created_by_user) }
let!(:lettings_log_2) { create(:lettings_log, :completed, startdate: Time.utc(2021, 5, 3), mrcdate: Time.utc(2021, 5, 3), voiddate: Time.utc(2021, 5, 3), created_by: created_by_user) }
before do
Timecop.freeze(Time.utc(2022, 6, 3))
@ -2755,7 +2900,7 @@ RSpec.describe LettingsLog do
context "with values represented as human readable labels" do
before do
Timecop.freeze(Time.utc(2022, 6, 5))
lettings_log = FactoryBot.create(:lettings_log, needstype: 2, scheme:, location:, owning_organisation: scheme.owning_organisation, created_by: user, rent_type: 2, startdate: Time.zone.local(2021, 10, 2))
lettings_log = FactoryBot.create(:lettings_log, needstype: 2, scheme:, location:, owning_organisation: scheme.owning_organisation, created_by: user, rent_type: 2, startdate: Time.zone.local(2021, 10, 2), created_at: Time.zone.local(2022, 2, 8, 16, 52, 15), updated_at: Time.zone.local(2022, 2, 8, 16, 52, 15))
expected_content.sub!(/\{id\}/, lettings_log["id"].to_s)
expected_content.sub!(/\{scheme_code\}/, "S#{scheme['id']}")
expected_content.sub!(/\{scheme_service_name\}/, scheme["service_name"].to_s)
@ -2770,6 +2915,15 @@ RSpec.describe LettingsLog do
expected_content.sub!(/\{location_id\}/, location["id"].to_s)
end
around do |example|
Timecop.freeze(Time.zone.local(2022, 6, 5)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
context "with a support user" do
let(:csv_export_file) { File.open("spec/fixtures/files/lettings_logs_download.csv", "r:UTF-8") }
@ -2790,7 +2944,7 @@ RSpec.describe LettingsLog do
context "with values represented as codes" do
before do
Timecop.freeze(Time.utc(2022, 6, 5))
lettings_log = FactoryBot.create(:lettings_log, needstype: 2, scheme:, location:, owning_organisation: scheme.owning_organisation, created_by: user, rent_type: 2, startdate: Time.zone.local(2021, 10, 2))
lettings_log = FactoryBot.create(:lettings_log, needstype: 2, scheme:, location:, owning_organisation: scheme.owning_organisation, created_by: user, rent_type: 2, startdate: Time.zone.local(2021, 10, 2), created_at: Time.zone.local(2022, 2, 8, 16, 52, 15), updated_at: Time.zone.local(2022, 2, 8, 16, 52, 15))
expected_content.sub!(/\{id\}/, lettings_log["id"].to_s)
expected_content.sub!(/\{scheme_code\}/, "S#{scheme.id}")
expected_content.sub!(/\{scheme_service_name\}/, scheme.service_name.to_s)
@ -2807,6 +2961,15 @@ RSpec.describe LettingsLog do
let(:csv_export_file) { File.open("spec/fixtures/files/lettings_logs_download_codes_only.csv", "r:UTF-8") }
around do |example|
Timecop.freeze(Time.zone.local(2022, 6, 5)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
it "generates a correct csv from a lettings log" do
expect(described_class.to_csv(codes_only_export: true)).to eq(expected_content)
end

24
spec/models/validations/date_validations_spec.rb

@ -9,18 +9,6 @@ RSpec.describe Validations::DateValidations do
let(:scheme_no_end_date) { FactoryBot.create(:scheme, end_date: nil) }
describe "tenancy start date" do
it "cannot be before the first collection window start date" do
record.startdate = Time.zone.local(2020, 1, 1)
date_validator.validate_startdate(record)
expect(record.errors["startdate"]).to include(match I18n.t("validations.date.outside_collection_window"))
end
it "cannot be after the second collection window end date" do
record.startdate = Time.zone.local(2023, 7, 1, 6)
date_validator.validate_startdate(record)
expect(record.errors["startdate"]).to include(match I18n.t("validations.date.outside_collection_window"))
end
it "must be a valid date" do
record.startdate = Time.zone.local(0, 7, 1)
date_validator.validate_startdate(record)
@ -98,7 +86,7 @@ RSpec.describe Validations::DateValidations do
record.location = location
date_validator.validate_startdate(record)
expect(record.errors["startdate"])
.to include(match I18n.t("validations.setup.startdate.location.deactivated", postcode: location.postcode, date: "4 June 2022"))
.to include(match I18n.t("validations.setup.startdate.location.deactivated", postcode: location.postcode, date: "4 June 2022"))
end
it "produces no error when tenancy start date is during an active location period" do
@ -123,7 +111,7 @@ RSpec.describe Validations::DateValidations do
record.location = location
date_validator.validate_startdate(record)
expect(record.errors["startdate"])
.to include(match I18n.t("validations.setup.startdate.location.reactivating_soon", postcode: location.postcode, date: "4 August 2022"))
.to include(match I18n.t("validations.setup.startdate.location.reactivating_soon", postcode: location.postcode, date: "4 August 2022"))
end
it "produces no error when tenancy start date is during an active location period" do
@ -150,7 +138,7 @@ RSpec.describe Validations::DateValidations do
record.location = location
date_validator.validate_startdate(record)
expect(record.errors["startdate"])
.to include(match I18n.t("validations.setup.startdate.location.reactivating_soon", postcode: location.postcode, date: "4 September 2022"))
.to include(match I18n.t("validations.setup.startdate.location.reactivating_soon", postcode: location.postcode, date: "4 September 2022"))
end
it "produces no error when tenancy start date is during an active location period" do
@ -177,7 +165,7 @@ RSpec.describe Validations::DateValidations do
record.location = location
date_validator.validate_startdate(record)
expect(record.errors["startdate"])
.to include(match I18n.t("validations.setup.startdate.location.activating_soon", postcode: location.postcode, date: "15 September 2022"))
.to include(match I18n.t("validations.setup.startdate.location.activating_soon", postcode: location.postcode, date: "15 September 2022"))
end
end
@ -194,7 +182,7 @@ RSpec.describe Validations::DateValidations do
record.scheme = scheme
date_validator.validate_startdate(record)
expect(record.errors["startdate"])
.to include(match I18n.t("validations.setup.startdate.scheme.reactivating_soon", name: scheme.service_name, date: "4 August 2022"))
.to include(match I18n.t("validations.setup.startdate.scheme.reactivating_soon", name: scheme.service_name, date: "4 August 2022"))
end
it "produces no error when tenancy start date is during an active scheme period" do
@ -220,7 +208,7 @@ RSpec.describe Validations::DateValidations do
record.scheme = scheme
date_validator.validate_startdate(record)
expect(record.errors["startdate"])
.to include(match I18n.t("validations.setup.startdate.scheme.reactivating_soon", name: scheme.service_name, date: "4 September 2022"))
.to include(match I18n.t("validations.setup.startdate.scheme.reactivating_soon", name: scheme.service_name, date: "4 September 2022"))
end
it "produces no error when tenancy start date is during an active scheme period" do

2
spec/models/validations/financial_validations_spec.rb

@ -86,7 +86,7 @@ RSpec.describe Validations::FinancialValidations do
end
context "when outstanding rent or charges is yes" do
let(:record) { FactoryBot.create(:lettings_log, :about_completed) }
let(:record) { FactoryBot.create(:lettings_log, :about_completed, startdate: Time.zone.now) }
it "expects that a shortfall is provided" do
record.hbrentshortfall = 1

20
spec/models/validations/sales/setup_validations_spec.rb

@ -17,7 +17,7 @@ RSpec.describe Validations::Sales::SetupValidations do
end
end
context "when saledate is in the 22/23 financial year" do
context "when saledate is in the 22/23 collection year" do
let(:record) { build(:sales_log, saledate: Time.zone.local(2023, 1, 1)) }
it "does not add an error" do
@ -27,23 +27,23 @@ RSpec.describe Validations::Sales::SetupValidations do
end
end
context "when saledate is before the 22/23 financial year" do
context "when saledate is before the 22/23 collection year" do
let(:record) { build(:sales_log, saledate: Time.zone.local(2020, 1, 1)) }
it "adds error" do
setup_validator.validate_saledate(record)
expect(record.errors[:saledate]).to include("Enter a date within the 22/23 financial year, which is between 1st April 2022 and 31st March 2023")
expect(record.errors[:saledate]).to include("Enter a date within the 22/23 collection year, which is between 1st April 2022 and 31st March 2023")
end
end
context "when saledate is after the 22/23 financial year" do
context "when saledate is after the 22/23 collection year" do
let(:record) { build(:sales_log, saledate: Time.zone.local(2025, 4, 1)) }
it "adds error" do
setup_validator.validate_saledate(record)
expect(record.errors[:saledate]).to include("Enter a date within the 22/23 financial year, which is between 1st April 2022 and 31st March 2023")
expect(record.errors[:saledate]).to include("Enter a date within the 22/23 collection year, which is between 1st April 2022 and 31st March 2023")
end
end
end
@ -67,7 +67,7 @@ RSpec.describe Validations::Sales::SetupValidations do
end
end
context "when saledate is in the 22/23 financial year" do
context "when saledate is in the 22/23 collection year" do
let(:record) { build(:sales_log, saledate: Time.zone.local(2024, 1, 1)) }
it "does not add an error" do
@ -77,23 +77,23 @@ RSpec.describe Validations::Sales::SetupValidations do
end
end
context "when saledate is before the 22/23 financial year" do
context "when saledate is before the 22/23 collection year" do
let(:record) { build(:sales_log, saledate: Time.zone.local(2020, 5, 1)) }
it "adds error" do
setup_validator.validate_saledate(record)
expect(record.errors[:saledate]).to include("Enter a date within the 23/24 or 24/25 financial years, which is between 1st April 2023 and 31st March 2025")
expect(record.errors[:saledate]).to include("Enter a date within the 23/24 or 24/25 collection years, which is between 1st April 2023 and 31st March 2025")
end
end
context "when saledate is after the 22/23 financial year" do
context "when saledate is after the 22/23 collection year" do
let(:record) { build(:sales_log, saledate: Time.zone.local(2025, 4, 1)) }
it "adds error" do
setup_validator.validate_saledate(record)
expect(record.errors[:saledate]).to include("Enter a date within the 23/24 or 24/25 financial years, which is between 1st April 2023 and 31st March 2025")
expect(record.errors[:saledate]).to include("Enter a date within the 23/24 or 24/25 collection years, which is between 1st April 2023 and 31st March 2025")
end
end
end

102
spec/models/validations/setup_validations_spec.rb

@ -6,13 +6,95 @@ RSpec.describe Validations::SetupValidations do
let(:setup_validator_class) { Class.new { include Validations::SetupValidations } }
let(:record) { FactoryBot.create(:lettings_log) }
describe "tenancy start date" do
context "when in 22/23 collection" do
context "when in the crossover period" do
before do
allow(Time).to receive(:now).and_return(Time.zone.local(2022, 4, 1))
record.created_at = Time.zone.local(2022, 4, 1)
end
it "cannot be before the first collection window start date" do
record.startdate = Time.zone.local(2021, 1, 1)
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to include(match "Enter a date within the 21/22 or 22/23 collection years, which is between 1st April 2021 and 31st March 2023")
end
it "cannot be after the second collection window end date" do
record.startdate = Time.zone.local(2023, 7, 1, 6)
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to include(match "Enter a date within the 21/22 or 22/23 collection years, which is between 1st April 2021 and 31st March 2023")
end
end
context "when after the crossover period" do
before do
allow(Time).to receive(:now).and_return(Time.zone.local(2023, 1, 1))
record.created_at = Time.zone.local(2023, 1, 1)
end
it "cannot be before the first collection window start date" do
record.startdate = Time.zone.local(2022, 1, 1)
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to include(match "Enter a date within the 22/23 collection year, which is between 1st April 2022 and 31st March 2023")
end
it "cannot be after the second collection window end date" do
record.startdate = Time.zone.local(2023, 7, 1, 6)
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to include(match "Enter a date within the 22/23 collection year, which is between 1st April 2022 and 31st March 2023")
end
end
end
context "when in 23/24 collection" do
context "when in the crossover period" do
before do
allow(Time).to receive(:now).and_return(Time.zone.local(2023, 4, 1))
record.created_at = Time.zone.local(2023, 4, 1)
end
it "cannot be before the first collection window start date" do
record.startdate = Time.zone.local(2022, 1, 1)
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to include(match "Enter a date within the 22/23 or 23/24 collection years, which is between 1st April 2022 and 31st March 2024")
end
it "cannot be after the second collection window end date" do
record.startdate = Time.zone.local(2024, 7, 1, 6)
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to include(match "Enter a date within the 22/23 or 23/24 collection years, which is between 1st April 2022 and 31st March 2024")
end
end
context "when after the crossover period" do
before do
allow(Time).to receive(:now).and_return(Time.zone.local(2024, 1, 1))
record.created_at = Time.zone.local(2024, 1, 1)
end
it "cannot be before the first collection window start date" do
record.startdate = Time.zone.local(2023, 1, 1)
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to include(match "Enter a date within the 23/24 collection year, which is between 1st April 2023 and 31st March 2024")
end
it "cannot be after the second collection window end date" do
record.startdate = Time.zone.local(2024, 7, 1, 6)
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to include(match "Enter a date within the 23/24 collection year, which is between 1st April 2023 and 31st March 2024")
end
end
end
end
describe "#validate_irproduct" do
it "adds an error when the intermediate rent product name is not provided but the rent type was given as other intermediate rent product" do
record.rent_type = 5
record.irproduct_other = nil
setup_validator.validate_irproduct_other(record)
expect(record.errors["irproduct_other"])
.to include(match I18n.t("validations.setup.intermediate_rent_product_name.blank"))
.to include(match I18n.t("validations.setup.intermediate_rent_product_name.blank"))
end
it "adds an error when the intermediate rent product name is blank but the rent type was given as other intermediate rent product" do
@ -20,7 +102,7 @@ RSpec.describe Validations::SetupValidations do
record.irproduct_other = ""
setup_validator.validate_irproduct_other(record)
expect(record.errors["irproduct_other"])
.to include(match I18n.t("validations.setup.intermediate_rent_product_name.blank"))
.to include(match I18n.t("validations.setup.intermediate_rent_product_name.blank"))
end
it "Does not add an error when the intermediate rent product name is provided and the rent type was given as other intermediate rent product" do
@ -46,7 +128,7 @@ RSpec.describe Validations::SetupValidations do
record.location = location
setup_validator.validate_scheme(record)
expect(record.errors["scheme_id"])
.to include(match I18n.t("validations.setup.startdate.location.deactivated", postcode: location.postcode, date: "4 June 2022"))
.to include(match I18n.t("validations.setup.startdate.location.deactivated", postcode: location.postcode, date: "4 June 2022"))
end
it "produces no error when tenancy start date is during an active location period" do
@ -71,7 +153,7 @@ RSpec.describe Validations::SetupValidations do
record.location = location
setup_validator.validate_scheme(record)
expect(record.errors["scheme_id"])
.to include(match I18n.t("validations.setup.startdate.location.reactivating_soon", postcode: location.postcode, date: "4 August 2022"))
.to include(match I18n.t("validations.setup.startdate.location.reactivating_soon", postcode: location.postcode, date: "4 August 2022"))
end
it "produces no error when tenancy start date is during an active location period" do
@ -98,7 +180,7 @@ RSpec.describe Validations::SetupValidations do
record.location = location
setup_validator.validate_scheme(record)
expect(record.errors["scheme_id"])
.to include(match I18n.t("validations.setup.startdate.location.activating_soon", postcode: location.postcode, date: "15 September 2022"))
.to include(match I18n.t("validations.setup.startdate.location.activating_soon", postcode: location.postcode, date: "15 September 2022"))
end
end
@ -115,7 +197,7 @@ RSpec.describe Validations::SetupValidations do
record.scheme = scheme
setup_validator.validate_scheme(record)
expect(record.errors["scheme_id"])
.to include(match I18n.t("validations.setup.startdate.scheme.reactivating_soon", name: scheme.service_name, date: "4 August 2022"))
.to include(match I18n.t("validations.setup.startdate.scheme.reactivating_soon", name: scheme.service_name, date: "4 August 2022"))
end
it "produces no error when tenancy start date is during an active scheme period" do
@ -141,7 +223,7 @@ RSpec.describe Validations::SetupValidations do
record.scheme = scheme
setup_validator.validate_scheme(record)
expect(record.errors["scheme_id"])
.to include(match I18n.t("validations.setup.startdate.scheme.reactivating_soon", name: scheme.service_name, date: "4 September 2022"))
.to include(match I18n.t("validations.setup.startdate.scheme.reactivating_soon", name: scheme.service_name, date: "4 September 2022"))
end
it "produces no error when tenancy start date is during an active scheme period" do
@ -168,7 +250,7 @@ RSpec.describe Validations::SetupValidations do
record.location = location
setup_validator.validate_location(record)
expect(record.errors["location_id"])
.to include(match I18n.t("validations.setup.startdate.location.deactivated", postcode: location.postcode, date: "4 June 2022"))
.to include(match I18n.t("validations.setup.startdate.location.deactivated", postcode: location.postcode, date: "4 June 2022"))
end
it "produces no error when tenancy start date is during an active location period" do
@ -193,7 +275,7 @@ RSpec.describe Validations::SetupValidations do
record.location = location
setup_validator.validate_location(record)
expect(record.errors["location_id"])
.to include(match I18n.t("validations.setup.startdate.location.reactivating_soon", postcode: location.postcode, date: "4 August 2022"))
.to include(match I18n.t("validations.setup.startdate.location.reactivating_soon", postcode: location.postcode, date: "4 August 2022"))
end
it "produces no error when tenancy start date is during an active location period" do
@ -220,7 +302,7 @@ RSpec.describe Validations::SetupValidations do
record.location = location
setup_validator.validate_location(record)
expect(record.errors["location_id"])
.to include(match I18n.t("validations.setup.startdate.location.activating_soon", postcode: location.postcode, date: "15 September 2022"))
.to include(match I18n.t("validations.setup.startdate.location.activating_soon", postcode: location.postcode, date: "15 September 2022"))
end
end
end

16
spec/models/validations/soft_validations_spec.rb

@ -207,6 +207,14 @@ RSpec.describe Validations::SoftValidations do
end
describe "major repairs date soft validations" do
before do
Timecop.freeze(Time.zone.local(2022, 2, 1))
end
after do
Timecop.unfreeze
end
context "when the major repairs date is within 10 years of the tenancy start date" do
it "shows the interruption screen" do
record.update!(startdate: Time.zone.local(2022, 2, 1), mrcdate: Time.zone.local(2013, 2, 1))
@ -223,6 +231,14 @@ RSpec.describe Validations::SoftValidations do
end
describe "void date soft validations" do
before do
Timecop.freeze(Time.zone.local(2022, 2, 1))
end
after do
Timecop.unfreeze
end
context "when the void date is within 10 years of the tenancy start date" do
it "shows the interruption screen" do
record.update!(startdate: Time.zone.local(2022, 2, 1), voiddate: Time.zone.local(2013, 2, 1))

20
spec/models/validations/tenancy_validations_spec.rb

@ -3,6 +3,10 @@ require "rails_helper"
RSpec.describe Validations::TenancyValidations do
subject(:tenancy_validator) { validator_class.new }
before do
Timecop.freeze(Time.zone.local(2021, 5, 1))
end
let(:validator_class) { Class.new { include Validations::TenancyValidations } }
let(:record) { FactoryBot.create(:lettings_log, startdate: Time.zone.local(2021, 5, 1), needstype: 1, rent_type: 1) }
@ -117,6 +121,14 @@ RSpec.describe Validations::TenancyValidations do
end
context "when the collection start year is 2022 or later" do
before do
Timecop.freeze(2022, 5, 1)
end
after do
Timecop.unfreeze
end
let(:record) { FactoryBot.create(:lettings_log, startdate: Time.zone.local(2022, 5, 1), needstype: 1, rent_type: 1) }
context "when type of tenancy is Secure - fixed term" do
@ -260,6 +272,14 @@ RSpec.describe Validations::TenancyValidations do
describe "joint tenancy validation" do
context "when the data inputter has said that there is only one member in the household" do
before do
Timecop.freeze(2022, 5, 1)
end
after do
Timecop.unfreeze
end
let(:record) { FactoryBot.create(:lettings_log, startdate: Time.zone.local(2022, 5, 1)) }
let(:expected_error) { I18n.t("validations.tenancy.not_joint") }
let(:hhmemb_expected_error) { I18n.t("validations.tenancy.joint_more_than_one_member") }

16
spec/requests/form_controller_spec.rb

@ -17,7 +17,6 @@ RSpec.describe FormController, type: :request do
:lettings_log,
:about_completed,
status: 1,
startdate: Time.zone.local(2021, 10, 10),
created_by: user,
)
end
@ -26,7 +25,6 @@ RSpec.describe FormController, type: :request do
:lettings_log,
:completed,
created_by: user,
startdate: Time.zone.local(2021, 5, 1),
)
end
let(:headers) { { "Accept" => "text/html" } }
@ -204,10 +202,13 @@ RSpec.describe FormController, type: :request do
describe "GET" do
context "with form pages" do
context "when forms exist for multiple years" do
let(:lettings_log_year_1) { create(:lettings_log, startdate: Time.zone.local(2021, 5, 1), owning_organisation: organisation, created_by: user) }
let(:lettings_log_year_1) { create(:lettings_log, owning_organisation: organisation, created_by: user) }
let(:lettings_log_year_2) { create(:lettings_log, :about_completed, startdate: Time.zone.local(2022, 5, 1), owning_organisation: organisation, created_by: user) }
before do
Timecop.freeze(Time.zone.local(2021, 5, 1))
lettings_log_year_1.update!(startdate: Time.zone.local(2021, 5, 1))
Timecop.unfreeze
allow(lettings_log_year_1.form).to receive(:end_date).and_return(Time.zone.today + 1.day)
end
@ -663,6 +664,15 @@ RSpec.describe FormController, type: :request do
end
let(:referrer) { "/lettings-logs/#{completed_lettings_log.id}/net-income-value-check?referrer=check_answers" }
around do |example|
Timecop.freeze(Time.zone.local(2022, 1, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
before do
completed_lettings_log.update!(ecstat1: 1, earnings: 130, hhmemb: 1) # we're not routing to that page, so it gets cleared?
allow(completed_lettings_log).to receive(:net_income_soft_validation_triggered?).and_return(true)

44
spec/requests/lettings_logs_controller_spec.rb

@ -333,6 +333,13 @@ RSpec.describe LettingsLogsController, type: :request do
end
context "with year filter" do
around do |example|
Timecop.freeze(2022, 3, 1) do
example.run
end
Timecop.unfreeze
end
let!(:lettings_log_2021) do
FactoryBot.create(:lettings_log, :in_progress,
created_by: user,
@ -364,6 +371,8 @@ RSpec.describe LettingsLogsController, type: :request do
context "with year and status filter" do
before do
Timecop.freeze(Time.zone.local(2022, 3, 1))
lettings_log_2021.update!(startdate: Time.zone.local(2022, 3, 1))
Timecop.freeze(Time.zone.local(2022, 12, 1))
end
@ -374,7 +383,6 @@ RSpec.describe LettingsLogsController, type: :request do
let!(:lettings_log_2021) do
FactoryBot.create(:lettings_log, :in_progress,
owning_organisation: organisation,
startdate: Time.zone.local(2022, 3, 1),
managing_organisation: organisation,
created_by: user)
end
@ -383,6 +391,7 @@ RSpec.describe LettingsLogsController, type: :request do
owning_organisation: organisation,
mrcdate: Time.zone.local(2022, 2, 1),
startdate: Time.zone.local(2022, 12, 1),
voiddate: Time.zone.local(2022, 2, 1),
tenancy: 6,
managing_organisation: organisation,
created_by: user)
@ -846,6 +855,10 @@ RSpec.describe LettingsLogsController, type: :request do
before do
sign_in user
get "/lettings-logs/#{lettings_log.id}", headers:, params: {}
Timecop.freeze(2021, 4, 1)
completed_lettings_log.update!(startdate: Time.zone.local(2021, 4, 1), voiddate: Time.zone.local(2021, 4, 1), mrcdate: Time.zone.local(2021, 4, 1))
completed_lettings_log.reload
Timecop.unfreeze
end
it "shows the tasklist for lettings logs you have access to" do
@ -871,9 +884,6 @@ RSpec.describe LettingsLogsController, type: :request do
end
it "displays a closed collection window message for previous collection year logs" do
completed_lettings_log.update!(startdate: Time.zone.local(2021, 4, 1))
completed_lettings_log.reload
get "/lettings-logs/#{completed_lettings_log.id}", headers:, params: {}
expect(completed_lettings_log.form.end_date).to eq(Time.zone.local(2022, 7, 1))
expect(completed_lettings_log.status).to eq("completed")
@ -940,19 +950,22 @@ RSpec.describe LettingsLogsController, type: :request do
end
context "when accessing the check answers page" do
before do
Timecop.freeze(2021, 4, 1)
completed_lettings_log.update!(startdate: Time.zone.local(2021, 4, 1), voiddate: Time.zone.local(2021, 4, 1), mrcdate: Time.zone.local(2021, 4, 1))
Timecop.unfreeze
stub_request(:get, /api.postcodes.io/)
.to_return(status: 200, body: "{\"status\":200,\"result\":{\"admin_district\":\"Manchester\", \"codes\":{\"admin_district\": \"E08000003\"}}}", headers: {})
sign_in user
end
let(:postcode_lettings_log) do
FactoryBot.create(:lettings_log,
created_by: user,
postcode_known: "No")
end
let(:id) { postcode_lettings_log.id }
let(:completed_lettings_log) { FactoryBot.create(:lettings_log, :completed, owning_organisation: user.organisation, managing_organisation: user.organisation, created_by: user, startdate: Time.zone.local(2021, 4, 1)) }
before do
stub_request(:get, /api.postcodes.io/)
.to_return(status: 200, body: "{\"status\":200,\"result\":{\"admin_district\":\"Manchester\", \"codes\":{\"admin_district\": \"E08000003\"}}}", headers: {})
sign_in user
end
let(:completed_lettings_log) { FactoryBot.create(:lettings_log, :completed, owning_organisation: user.organisation, managing_organisation: user.organisation, created_by: user) }
it "shows the inferred la" do
lettings_log = FactoryBot.create(:lettings_log,
@ -1154,6 +1167,15 @@ RSpec.describe LettingsLogsController, type: :request do
end
context "with an invalid lettings log params" do
around do |example|
Timecop.freeze(Time.zone.local(2022, 1, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
let(:params) { { age1: 200 } }
it "returns 422" do

9
spec/requests/sales_logs_controller_spec.rb

@ -231,11 +231,10 @@ RSpec.describe SalesLogsController, type: :request do
end
context "with year and status filter" do
before do
Timecop.freeze(Time.zone.local(2022, 12, 1))
end
after do
around do |example|
Timecop.freeze(2022, 12, 1) do
example.run
end
Timecop.unfreeze
end

2
spec/services/csv/lettings_log_csv_service_spec.rb

@ -6,7 +6,7 @@ RSpec.describe Csv::LettingsLogCsvService do
let(:real_2021_2022_form) { Form.new("config/forms/2021_2022.json") }
before do
LettingsLog.create!(startdate: "2021-10-10", created_at: Time.utc(2022, 2, 8, 16, 52, 15))
LettingsLog.create!(startdate: Time.zone.today, created_at: Time.utc(2022, 2, 8, 16, 52, 15))
allow(FormHandler.instance).to receive(:get_form).and_return(real_2021_2022_form)
end

8
spec/services/exports/lettings_log_export_service_spec.rb

@ -59,7 +59,7 @@ RSpec.describe Exports::LettingsLogExportService do
end
context "and one lettings log is available for export" do
let!(:lettings_log) { FactoryBot.create(:lettings_log, :completed, propcode: "123", ppostcode_full: "SE2 6RT", postcode_full: "NW1 5TY", tenancycode: "BZ737", startdate: Time.utc(2022, 2, 2, 10, 36, 49), tenancylength: 5, underoccupation_benefitcap: 4) }
let!(:lettings_log) { FactoryBot.create(:lettings_log, :completed, propcode: "123", ppostcode_full: "SE2 6RT", postcode_full: "NW1 5TY", tenancycode: "BZ737", startdate: Time.zone.local(2022, 2, 2, 10, 36, 49), voiddate: Time.zone.local(2019, 11, 3), mrcdate: Time.zone.local(2020, 5, 5, 10, 36, 49), tenancylength: 5, underoccupation_benefitcap: 4) }
it "generates a ZIP export file with the expected filename" do
expect(storage_service).to receive(:write_file).with(expected_zip_filename, any_args)
@ -161,7 +161,7 @@ RSpec.describe Exports::LettingsLogExportService do
context "when this is a second export (partial)" do
before do
start_time = Time.zone.local(2022, 4, 1)
start_time = Time.zone.local(2022, 6, 1)
LogsExport.new(started_at: start_time).save!
end
@ -237,7 +237,7 @@ RSpec.describe Exports::LettingsLogExportService do
let(:csv_export_file) { File.open("spec/fixtures/exports/general_needs_log.csv", "r:UTF-8") }
let(:expected_csv_filename) { "export_2022_05_01.csv" }
let(:lettings_log) { FactoryBot.create(:lettings_log, :completed, propcode: "123", ppostcode_full: "SE2 6RT", postcode_full: "NW1 5TY", tenancycode: "BZ737", startdate: Time.utc(2022, 2, 2, 10, 36, 49), tenancylength: 5, underoccupation_benefitcap: 4) }
let(:lettings_log) { FactoryBot.create(:lettings_log, :completed, propcode: "123", ppostcode_full: "SE2 6RT", postcode_full: "NW1 5TY", tenancycode: "BZ737", startdate: Time.zone.local(2022, 2, 2, 10, 36, 49), voiddate: Time.zone.local(2019, 11, 3), mrcdate: Time.zone.local(2020, 5, 5, 10, 36, 49), tenancylength: 5, underoccupation_benefitcap: 4) }
it "generates an CSV export file with the expected content" do
expected_content = replace_entity_ids(lettings_log, csv_export_file.read)
@ -256,7 +256,7 @@ RSpec.describe Exports::LettingsLogExportService do
let(:scheme) { FactoryBot.create(:scheme, :export, owning_organisation: organisation) }
let(:location) { FactoryBot.create(:location, :export, scheme:, startdate: Time.zone.local(2021, 4, 1)) }
let(:lettings_log) { FactoryBot.create(:lettings_log, :completed, :export, :sh, scheme:, location:, created_by: user, owning_organisation: organisation, startdate: Time.utc(2022, 2, 2, 10, 36, 49), underoccupation_benefitcap: 4, sheltered: 1) }
let(:lettings_log) { FactoryBot.create(:lettings_log, :completed, :export, :sh, scheme:, location:, created_by: user, owning_organisation: organisation, startdate: Time.zone.local(2022, 2, 2, 10, 36, 49), voiddate: Time.zone.local(2019, 11, 3), mrcdate: Time.zone.local(2020, 5, 5, 10, 36, 49), underoccupation_benefitcap: 4, sheltered: 1) }
before do
FactoryBot.create(:location, scheme:, startdate: Time.zone.local(2021, 4, 1), units: nil)

11
spec/services/imports/lettings_logs_field_import_service_spec.rb

@ -16,6 +16,15 @@ RSpec.describe Imports::LettingsLogsFieldImportService do
let(:old_user_id) { "c3061a2e6ea0b702e6f6210d5c52d2a92612d2aa" }
let(:organisation) { FactoryBot.create(:organisation, old_visible_id: "1", provider_type: "PRP") }
around do |example|
Timecop.freeze(Time.zone.local(2022, 1, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
def open_file(directory, filename)
File.open("#{directory}/#{filename}.xml")
end
@ -27,7 +36,7 @@ RSpec.describe Imports::LettingsLogsFieldImportService do
FactoryBot.create(:user, old_user_id:, organisation:)
# Stub the form handler to use the real form
allow(FormHandler.instance).to receive(:get_form).with("previous_lettings").and_return(real_2021_2022_form)
allow(FormHandler.instance).to receive(:get_form).with("current_lettings").and_return(real_2021_2022_form)
WebMock.stub_request(:get, /api.postcodes.io\/postcodes\/LS166FT/)
.to_return(status: 200, body: '{"status":200,"result":{"codes":{"admin_district":"E08000035"}}}', headers: {})

733
spec/services/imports/lettings_logs_import_service_spec.rb

@ -1,348 +1,333 @@
require "rails_helper"
RSpec.describe Imports::LettingsLogsImportService do
subject(:lettings_log_service) { described_class.new(storage_service, logger) }
context "with 21/22 logs" do
subject(:lettings_log_service) { described_class.new(storage_service, logger) }
let(:storage_service) { instance_double(Storage::S3Service) }
let(:logger) { instance_double(ActiveSupport::Logger) }
let(:real_2021_2022_form) { Form.new("config/forms/2021_2022.json") }
let(:real_2022_2023_form) { Form.new("config/forms/2022_2023.json") }
let(:fixture_directory) { "spec/fixtures/imports/logs" }
let(:organisation) { FactoryBot.create(:organisation, old_visible_id: "1", provider_type: "PRP") }
let(:managing_organisation) { FactoryBot.create(:organisation, old_visible_id: "2", provider_type: "PRP") }
let(:scheme1) { FactoryBot.create(:scheme, old_visible_id: "0123", owning_organisation: organisation) }
let(:scheme2) { FactoryBot.create(:scheme, old_visible_id: "456", owning_organisation: organisation) }
def open_file(directory, filename)
File.open("#{directory}/#{filename}.xml")
end
before do
WebMock.stub_request(:get, /api.postcodes.io\/postcodes\/LS166FT/)
.to_return(status: 200, body: '{"status":200,"result":{"admin_district":"Westminster","codes":{"admin_district":"E08000035"}}}', headers: {})
allow(Organisation).to receive(:find_by).and_return(nil)
allow(Organisation).to receive(:find_by).with(old_visible_id: organisation.old_visible_id).and_return(organisation)
allow(Organisation).to receive(:find_by).with(old_visible_id: managing_organisation.old_visible_id).and_return(managing_organisation)
# Created by users
FactoryBot.create(:user, old_user_id: "c3061a2e6ea0b702e6f6210d5c52d2a92612d2aa", organisation:)
FactoryBot.create(:user, old_user_id: "e29c492473446dca4d50224f2bb7cf965a261d6f", organisation:)
# Location setup
FactoryBot.create(:location, old_visible_id: "10", postcode: "LS166FT", scheme_id: scheme1.id, mobility_type: "W", startdate: Time.zone.local(2021, 4, 1))
FactoryBot.create(:location, scheme_id: scheme1.id, startdate: Time.zone.local(2021, 4, 1))
FactoryBot.create(:location, old_visible_id: "10", postcode: "LS166FT", scheme_id: scheme2.id, mobility_type: "W", startdate: Time.zone.local(2021, 4, 1))
# Stub the form handler to use the real form
allow(FormHandler.instance).to receive(:get_form).with("previous_lettings").and_return(real_2021_2022_form)
allow(FormHandler.instance).to receive(:get_form).with("current_lettings").and_return(real_2022_2023_form)
end
around do |example|
Timecop.freeze(Time.zone.local(2022, 1, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
context "when importing lettings logs" do
let(:remote_folder) { "lettings_logs" }
let(:lettings_log_id) { "0ead17cb-1668-442d-898c-0d52879ff592" }
let(:lettings_log_id2) { "166fc004-392e-47a8-acb8-1c018734882b" }
let(:lettings_log_id3) { "00d2343e-d5fa-4c89-8400-ec3854b0f2b4" }
let(:lettings_log_id4) { "0b4a68df-30cc-474a-93c0-a56ce8fdad3b" }
let(:sales_log) { "shared_ownership_sales_log" }
let(:storage_service) { instance_double(Storage::S3Service) }
let(:logger) { instance_double(ActiveSupport::Logger) }
before do
# Stub the S3 file listing and download
allow(storage_service).to receive(:list_files)
.and_return(%W[#{remote_folder}/#{lettings_log_id}.xml #{remote_folder}/#{lettings_log_id2}.xml #{remote_folder}/#{lettings_log_id3}.xml #{remote_folder}/#{lettings_log_id4}.xml #{remote_folder}/#{sales_log}.xml])
allow(storage_service).to receive(:get_file_io)
.with("#{remote_folder}/#{lettings_log_id}.xml")
.and_return(open_file(fixture_directory, lettings_log_id), open_file(fixture_directory, lettings_log_id))
allow(storage_service).to receive(:get_file_io)
.with("#{remote_folder}/#{lettings_log_id2}.xml")
.and_return(open_file(fixture_directory, lettings_log_id2), open_file(fixture_directory, lettings_log_id2))
allow(storage_service).to receive(:get_file_io)
.with("#{remote_folder}/#{lettings_log_id3}.xml")
.and_return(open_file(fixture_directory, lettings_log_id3), open_file(fixture_directory, lettings_log_id3))
allow(storage_service).to receive(:get_file_io)
.with("#{remote_folder}/#{lettings_log_id4}.xml")
.and_return(open_file(fixture_directory, lettings_log_id4), open_file(fixture_directory, lettings_log_id4))
allow(storage_service).to receive(:get_file_io)
.with("#{remote_folder}/#{sales_log}.xml")
.and_return(open_file(fixture_directory, sales_log), open_file(fixture_directory, sales_log))
end
let(:real_2021_2022_form) { Form.new("config/forms/2021_2022.json") }
let(:real_2022_2023_form) { Form.new("config/forms/2022_2023.json") }
let(:fixture_directory) { "spec/fixtures/imports/logs" }
it "successfully create all lettings logs" do
expect(logger).not_to receive(:error)
expect(logger).not_to receive(:warn)
expect(logger).not_to receive(:info)
expect { lettings_log_service.create_logs(remote_folder) }
.to change(LettingsLog, :count).by(4)
end
let(:organisation) { FactoryBot.create(:organisation, old_visible_id: "1", provider_type: "PRP") }
let(:managing_organisation) { FactoryBot.create(:organisation, old_visible_id: "2", provider_type: "PRP") }
let(:scheme1) { FactoryBot.create(:scheme, old_visible_id: "0123", owning_organisation: organisation) }
let(:scheme2) { FactoryBot.create(:scheme, old_visible_id: "456", owning_organisation: organisation) }
it "only updates existing lettings logs" do
expect(logger).not_to receive(:error)
expect(logger).not_to receive(:warn)
expect(logger).to receive(:info).with(/Updating lettings log/).exactly(4).times
expect { 2.times { lettings_log_service.create_logs(remote_folder) } }
.to change(LettingsLog, :count).by(4)
def open_file(directory, filename)
File.open("#{directory}/#{filename}.xml")
end
it "creates organisation relationship once" do
expect(logger).not_to receive(:error)
expect(logger).not_to receive(:warn)
expect { lettings_log_service.create_logs(remote_folder) }
.to change(OrganisationRelationship, :count).by(1)
before do
WebMock.stub_request(:get, /api.postcodes.io\/postcodes\/LS166FT/)
.to_return(status: 200, body: '{"status":200,"result":{"admin_district":"Westminster","codes":{"admin_district":"E08000035"}}}', headers: {})
allow(Organisation).to receive(:find_by).and_return(nil)
allow(Organisation).to receive(:find_by).with(old_visible_id: organisation.old_visible_id).and_return(organisation)
allow(Organisation).to receive(:find_by).with(old_visible_id: managing_organisation.old_visible_id).and_return(managing_organisation)
# Created by users
FactoryBot.create(:user, old_user_id: "c3061a2e6ea0b702e6f6210d5c52d2a92612d2aa", organisation:)
FactoryBot.create(:user, old_user_id: "e29c492473446dca4d50224f2bb7cf965a261d6f", organisation:)
# Location setup
FactoryBot.create(:location, old_visible_id: "10", postcode: "LS166FT", scheme_id: scheme1.id, mobility_type: "W", startdate: Time.zone.local(2021, 4, 1))
FactoryBot.create(:location, scheme_id: scheme1.id, startdate: Time.zone.local(2021, 4, 1))
FactoryBot.create(:location, old_visible_id: "10", postcode: "LS166FT", scheme_id: scheme2.id, mobility_type: "W", startdate: Time.zone.local(2021, 4, 1))
# Stub the form handler to use the real form
allow(FormHandler.instance).to receive(:get_form).with("current_lettings").and_return(real_2021_2022_form)
allow(FormHandler.instance).to receive(:get_form).with("previous_lettings").and_return(real_2021_2022_form)
allow(FormHandler.instance).to receive(:get_form).with("next_lettings").and_return(real_2022_2023_form)
end
context "when there are status discrepancies" do
let(:lettings_log_id5) { "893ufj2s-lq77-42m4-rty6-ej09gh585uy1" }
let(:lettings_log_id6) { "5ybz29dj-l33t-k1l0-hj86-n4k4ma77xkcd" }
let(:lettings_log_file) { open_file(fixture_directory, lettings_log_id5) }
let(:lettings_log_xml) { Nokogiri::XML(lettings_log_file) }
context "when importing lettings logs" do
let(:remote_folder) { "lettings_logs" }
let(:lettings_log_id) { "0ead17cb-1668-442d-898c-0d52879ff592" }
let(:lettings_log_id2) { "166fc004-392e-47a8-acb8-1c018734882b" }
let(:lettings_log_id3) { "0b4a68df-30cc-474a-93c0-a56ce8fdad3b" }
let(:sales_log) { "shared_ownership_sales_log" }
before do
# Stub the S3 file listing and download
allow(storage_service).to receive(:list_files)
.and_return(%W[#{remote_folder}/#{lettings_log_id}.xml #{remote_folder}/#{lettings_log_id2}.xml #{remote_folder}/#{lettings_log_id3}.xml #{remote_folder}/#{sales_log}.xml])
allow(storage_service).to receive(:get_file_io)
.with("#{remote_folder}/#{lettings_log_id5}.xml")
.and_return(open_file(fixture_directory, lettings_log_id5), open_file(fixture_directory, lettings_log_id5))
.with("#{remote_folder}/#{lettings_log_id}.xml")
.and_return(open_file(fixture_directory, lettings_log_id), open_file(fixture_directory, lettings_log_id))
allow(storage_service).to receive(:get_file_io)
.with("#{remote_folder}/#{lettings_log_id6}.xml")
.and_return(open_file(fixture_directory, lettings_log_id6), open_file(fixture_directory, lettings_log_id6))
.with("#{remote_folder}/#{lettings_log_id2}.xml")
.and_return(open_file(fixture_directory, lettings_log_id2), open_file(fixture_directory, lettings_log_id2))
allow(storage_service).to receive(:get_file_io)
.with("#{remote_folder}/#{lettings_log_id3}.xml")
.and_return(open_file(fixture_directory, lettings_log_id3), open_file(fixture_directory, lettings_log_id3))
allow(storage_service).to receive(:get_file_io)
.with("#{remote_folder}/#{sales_log}.xml")
.and_return(open_file(fixture_directory, sales_log), open_file(fixture_directory, sales_log))
end
it "the logger logs a warning with the lettings log's old id/filename" do
expect(logger).to receive(:warn).with(/is not completed/).once
expect(logger).to receive(:warn).with(/lettings log with old id:#{lettings_log_id5} is incomplete but status should be complete/).once
lettings_log_service.send(:create_log, lettings_log_xml)
it "successfully create all lettings logs" do
expect(logger).not_to receive(:error)
expect(logger).not_to receive(:warn)
expect(logger).not_to receive(:info)
expect { lettings_log_service.create_logs(remote_folder) }
.to change(LettingsLog, :count).by(3)
end
it "on completion the ids of all logs with status discrepancies are logged in a warning" do
allow(storage_service).to receive(:list_files)
.and_return(%W[#{remote_folder}/#{lettings_log_id5}.xml #{remote_folder}/#{lettings_log_id6}.xml])
expect(logger).to receive(:warn).with(/is not completed/).twice
expect(logger).to receive(:warn).with(/is incomplete but status should be complete/).twice
expect(logger).to receive(:warn).with(/The following lettings logs had status discrepancies: \[893ufj2s-lq77-42m4-rty6-ej09gh585uy1, 5ybz29dj-l33t-k1l0-hj86-n4k4ma77xkcd\]/)
lettings_log_service.create_logs(remote_folder)
it "only updates existing lettings logs" do
expect(logger).not_to receive(:error)
expect(logger).not_to receive(:warn)
expect(logger).to receive(:info).with(/Updating lettings log/).exactly(3).times
expect { 2.times { lettings_log_service.create_logs(remote_folder) } }
.to change(LettingsLog, :count).by(3)
end
end
end
context "when importing a specific log" do
let(:lettings_log_id) { "0ead17cb-1668-442d-898c-0d52879ff592" }
let(:lettings_log_file) { open_file(fixture_directory, lettings_log_id) }
let(:lettings_log_xml) { Nokogiri::XML(lettings_log_file) }
it "creates organisation relationship once" do
expect(logger).not_to receive(:error)
expect(logger).not_to receive(:warn)
expect { lettings_log_service.create_logs(remote_folder) }
.to change(OrganisationRelationship, :count).by(1)
end
context "and the void date is after the start date" do
before { lettings_log_xml.at_xpath("//xmlns:VYEAR").content = 2023 }
context "when there are status discrepancies" do
let(:lettings_log_id5) { "893ufj2s-lq77-42m4-rty6-ej09gh585uy1" }
let(:lettings_log_id6) { "5ybz29dj-l33t-k1l0-hj86-n4k4ma77xkcd" }
let(:lettings_log_file) { open_file(fixture_directory, lettings_log_id5) }
let(:lettings_log_xml) { Nokogiri::XML(lettings_log_file) }
it "does not import the voiddate" do
expect(logger).to receive(:warn).with(/is not completed/)
expect(logger).to receive(:warn).with(/lettings log with old id:#{lettings_log_id} is incomplete but status should be complete/)
before do
allow(storage_service).to receive(:get_file_io)
.with("#{remote_folder}/#{lettings_log_id5}.xml")
.and_return(open_file(fixture_directory, lettings_log_id5), open_file(fixture_directory, lettings_log_id5))
allow(storage_service).to receive(:get_file_io)
.with("#{remote_folder}/#{lettings_log_id6}.xml")
.and_return(open_file(fixture_directory, lettings_log_id6), open_file(fixture_directory, lettings_log_id6))
end
lettings_log_service.send(:create_log, lettings_log_xml)
it "the logger logs a warning with the lettings log's old id/filename" do
expect(logger).to receive(:warn).with(/is not completed/).once
expect(logger).to receive(:warn).with(/lettings log with old id:#{lettings_log_id5} is incomplete but status should be complete/).once
lettings_log = LettingsLog.where(old_id: lettings_log_id).first
expect(lettings_log&.voiddate).to be_nil
end
end
lettings_log_service.send(:create_log, lettings_log_xml)
end
context "and the organisation legacy ID does not exist" do
before { lettings_log_xml.at_xpath("//xmlns:OWNINGORGID").content = 99_999 }
it "on completion the ids of all logs with status discrepancies are logged in a warning" do
allow(storage_service).to receive(:list_files)
.and_return(%W[#{remote_folder}/#{lettings_log_id5}.xml #{remote_folder}/#{lettings_log_id6}.xml])
expect(logger).to receive(:warn).with(/is not completed/).twice
expect(logger).to receive(:warn).with(/is incomplete but status should be complete/).twice
expect(logger).to receive(:warn).with(/The following lettings logs had status discrepancies: \[893ufj2s-lq77-42m4-rty6-ej09gh585uy1, 5ybz29dj-l33t-k1l0-hj86-n4k4ma77xkcd\]/)
it "raises an exception" do
expect { lettings_log_service.send(:create_log, lettings_log_xml) }
.to raise_error(RuntimeError, "Organisation not found with legacy ID 99999")
lettings_log_service.create_logs(remote_folder)
end
end
end
context "and a person is under 16" do
before { lettings_log_xml.at_xpath("//xmlns:P2Age").content = 14 }
context "when importing a specific log" do
let(:lettings_log_id) { "0ead17cb-1668-442d-898c-0d52879ff592" }
let(:lettings_log_file) { open_file(fixture_directory, lettings_log_id) }
let(:lettings_log_xml) { Nokogiri::XML(lettings_log_file) }
context "and the void date is after the start date" do
before { lettings_log_xml.at_xpath("//xmlns:VYEAR").content = 2023 }
context "when the economic status is set to refuse" do
before { lettings_log_xml.at_xpath("//xmlns:P2Eco").content = "10) Refused" }
it "does not import the voiddate" do
expect(logger).to receive(:warn).with(/is not completed/)
expect(logger).to receive(:warn).with(/lettings log with old id:#{lettings_log_id} is incomplete but status should be complete/)
it "sets the economic status to child under 16" do
# The update is done when calculating derived variables
expect(logger).to receive(:warn).with(/Differences found when saving log/)
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.where(old_id: lettings_log_id).first
expect(lettings_log&.ecstat2).to be(9)
expect(lettings_log&.voiddate).to be_nil
end
end
context "when the relationship to lead tenant is set to refuse" do
before { lettings_log_xml.at_xpath("//xmlns:P2Rel").content = "Refused" }
it "sets the relationship to lead tenant to child" do
lettings_log_service.send(:create_log, lettings_log_xml)
context "and the organisation legacy ID does not exist" do
before { lettings_log_xml.at_xpath("//xmlns:OWNINGORGID").content = 99_999 }
lettings_log = LettingsLog.where(old_id: lettings_log_id).first
expect(lettings_log&.relat2).to eq("C")
it "raises an exception" do
expect { lettings_log_service.send(:create_log, lettings_log_xml) }
.to raise_error(RuntimeError, "Organisation not found with legacy ID 99999")
end
end
end
context "and this is an internal transfer that is in-progress with invalid answers" do
before do
lettings_log_xml.at_xpath("//meta:status").content = "submitted-invalid"
lettings_log_xml.at_xpath("//xmlns:P2Age").content = 999
end
context "and a person is under 16" do
before { lettings_log_xml.at_xpath("//xmlns:P2Age").content = 14 }
it "intercepts the relevant validation error" do
expect(logger).to receive(:warn).with(/Removing field age2 from log triggering validation: Answer cannot be over 16/)
expect(logger).to receive(:warn).with(/Removing field age2 from log triggering validation: Person 2’s age must be between/)
expect(logger).to receive(:warn).with(/Removing field ecstat2 from log triggering validation: Answer cannot be ‘child under 16’/)
expect { lettings_log_service.send(:create_log, lettings_log_xml) }
.not_to raise_error
end
context "when the economic status is set to refuse" do
before { lettings_log_xml.at_xpath("//xmlns:P2Eco").content = "10) Refused" }
it "clears out the invalid answers" do
allow(logger).to receive(:warn)
it "sets the economic status to child under 16" do
# The update is done when calculating derived variables
expect(logger).to receive(:warn).with(/Differences found when saving log/)
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
lettings_log = LettingsLog.where(old_id: lettings_log_id).first
expect(lettings_log&.ecstat2).to be(9)
end
end
expect(lettings_log).not_to be_nil
expect(lettings_log.age2).to be_nil
expect(lettings_log.ecstat2).to be_nil
end
end
context "when the relationship to lead tenant is set to refuse" do
before { lettings_log_xml.at_xpath("//xmlns:P2Rel").content = "Refused" }
context "and it has zero earnings" do
before do
lettings_log_xml.at_xpath("//meta:status").content = "submitted"
lettings_log_xml.at_xpath("//xmlns:Q8Money").content = 0
end
it "sets the relationship to lead tenant to child" do
lettings_log_service.send(:create_log, lettings_log_xml)
it "intercepts the relevant validation error" do
expect(logger).to receive(:warn).with(/Where the income is 0, set earnings and income to blank and set incref to refused/)
expect { lettings_log_service.send(:create_log, lettings_log_xml) }
.not_to raise_error
lettings_log = LettingsLog.where(old_id: lettings_log_id).first
expect(lettings_log&.relat2).to eq("C")
end
end
end
it "clears out the invalid answers" do
allow(logger).to receive(:warn)
context "and this is an internal transfer that is in-progress with invalid answers" do
before do
lettings_log_xml.at_xpath("//meta:status").content = "submitted-invalid"
lettings_log_xml.at_xpath("//xmlns:P2Age").content = 999
end
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
it "intercepts the relevant validation error" do
expect(logger).to receive(:warn).with(/Removing field age2 from log triggering validation: Answer cannot be over 16/)
expect(logger).to receive(:warn).with(/Removing field age2 from log triggering validation: Person 2’s age must be between/)
expect(logger).to receive(:warn).with(/Removing field ecstat2 from log triggering validation: Answer cannot be ‘child under 16’/)
expect { lettings_log_service.send(:create_log, lettings_log_xml) }
.not_to raise_error
end
expect(lettings_log).not_to be_nil
expect(lettings_log.earnings).to be_nil
expect(lettings_log.incref).to eq(1)
expect(lettings_log.net_income_known).to eq(2)
end
end
it "clears out the invalid answers" do
allow(logger).to receive(:warn)
context "and an invalid tenancy length for tenancy type" do
before do
lettings_log_xml.at_xpath("//meta:status").content = "submitted"
lettings_log_xml.at_xpath("//xmlns:_2cYears").content = "1"
lettings_log_xml.at_xpath("//xmlns:Q2b").content = "4"
end
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
it "intercepts the relevant validation error" do
expect(logger).to receive(:warn).with(/Removing tenancylength as invalid/)
expect { lettings_log_service.send(:create_log, lettings_log_xml) }
.not_to raise_error
expect(lettings_log).not_to be_nil
expect(lettings_log.age2).to be_nil
expect(lettings_log.ecstat2).to be_nil
end
end
it "clears out the invalid answers" do
allow(logger).to receive(:warn)
context "and it has zero earnings" do
before do
lettings_log_xml.at_xpath("//meta:status").content = "submitted"
lettings_log_xml.at_xpath("//xmlns:Q8Money").content = 0
end
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
it "intercepts the relevant validation error" do
expect(logger).to receive(:warn).with(/Where the income is 0, set earnings and income to blank and set incref to refused/)
expect { lettings_log_service.send(:create_log, lettings_log_xml) }
.not_to raise_error
end
expect(lettings_log).not_to be_nil
expect(lettings_log.tenancylength).to be_nil
expect(lettings_log.tenancy).to be_nil
end
end
it "clears out the invalid answers" do
allow(logger).to receive(:warn)
context "and an lead tenant must be under 20 if childrens home or foster care" do
before do
lettings_log_xml.at_xpath("//meta:status").content = "submitted"
lettings_log_xml.at_xpath("//xmlns:Q11").content = "13"
lettings_log_xml.at_xpath("//xmlns:P1Age").content = "22"
end
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
it "intercepts the relevant validation error" do
expect(logger).to receive(:warn).with(/Removing age1 and prevten as incompatible/)
expect { lettings_log_service.send(:create_log, lettings_log_xml) }
.not_to raise_error
expect(lettings_log).not_to be_nil
expect(lettings_log.earnings).to be_nil
expect(lettings_log.incref).to eq(1)
expect(lettings_log.net_income_known).to eq(2)
end
end
it "clears out the invalid answers" do
allow(logger).to receive(:warn)
context "and an invalid tenancy length for tenancy type" do
before do
lettings_log_xml.at_xpath("//meta:status").content = "submitted"
lettings_log_xml.at_xpath("//xmlns:_2cYears").content = "1"
lettings_log_xml.at_xpath("//xmlns:Q2b").content = "4"
end
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
it "intercepts the relevant validation error" do
expect(logger).to receive(:warn).with(/Removing tenancylength as invalid/)
expect { lettings_log_service.send(:create_log, lettings_log_xml) }
.not_to raise_error
end
expect(lettings_log).not_to be_nil
expect(lettings_log.age1).to be_nil
expect(lettings_log.prevten).to be_nil
end
end
it "clears out the invalid answers" do
allow(logger).to receive(:warn)
context "and is a carehome but missing carehome charge" do
let(:lettings_log_id) { "0b4a68df-30cc-474a-93c0-a56ce8fdad3b" }
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
before do
lettings_log_xml.at_xpath("//meta:status").content = "submitted"
lettings_log_xml.at_xpath("//xmlns:_1cmangroupcode").content = scheme2.old_visible_id
scheme2.update!(registered_under_care_act: 2)
lettings_log_xml.at_xpath("//xmlns:Q18b").content = ""
expect(lettings_log).not_to be_nil
expect(lettings_log.tenancylength).to be_nil
expect(lettings_log.tenancy).to be_nil
end
end
it "intercepts the relevant validation error" do
allow(logger).to receive(:warn)
context "and an lead tenant must be under 20 if childrens home or foster care" do
before do
lettings_log_xml.at_xpath("//meta:status").content = "submitted"
lettings_log_xml.at_xpath("//xmlns:Q11").content = "13"
lettings_log_xml.at_xpath("//xmlns:P1Age").content = "22"
end
expect { lettings_log_service.send(:create_log, lettings_log_xml) }
.not_to raise_error
end
it "intercepts the relevant validation error" do
expect(logger).to receive(:warn).with(/Removing age1 and prevten as incompatible/)
expect { lettings_log_service.send(:create_log, lettings_log_xml) }
.not_to raise_error
end
it "clears out the invalid answers" do
allow(logger).to receive(:warn)
it "clears out the invalid answers" do
allow(logger).to receive(:warn)
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
expect(lettings_log).not_to be_nil
expect(lettings_log.is_carehome).to be_truthy
expect(lettings_log.chcharge).to be_nil
expect(lettings_log).not_to be_nil
expect(lettings_log.age1).to be_nil
expect(lettings_log.prevten).to be_nil
end
end
end
context "and this is an internal transfer from a non social housing" do
before do
lettings_log_xml.at_xpath("//xmlns:Q11").content = "9 Residential care home"
lettings_log_xml.at_xpath("//xmlns:Q16").content = "1 Internal Transfer"
end
context "and is a carehome but missing carehome charge" do
let(:lettings_log_id) { "0b4a68df-30cc-474a-93c0-a56ce8fdad3b" }
it "intercepts the relevant validation error" do
expect(logger).to receive(:warn).with(/Removing internal transfer referral since previous tenancy is a non social housing/)
expect { lettings_log_service.send(:create_log, lettings_log_xml) }
.not_to raise_error
end
before do
lettings_log_xml.at_xpath("//meta:status").content = "submitted"
lettings_log_xml.at_xpath("//xmlns:_1cmangroupcode").content = scheme2.old_visible_id
scheme2.update!(registered_under_care_act: 2)
lettings_log_xml.at_xpath("//xmlns:Q18b").content = ""
end
it "clears out the referral answer" do
allow(logger).to receive(:warn)
it "intercepts the relevant validation error" do
allow(logger).to receive(:warn)
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
expect { lettings_log_service.send(:create_log, lettings_log_xml) }
.not_to raise_error
end
it "clears out the invalid answers" do
allow(logger).to receive(:warn)
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
expect(lettings_log).not_to be_nil
expect(lettings_log.referral).to be_nil
expect(lettings_log).not_to be_nil
expect(lettings_log.is_carehome).to be_truthy
expect(lettings_log.chcharge).to be_nil
end
end
context "and this is an internal transfer from a previous fixed term tenancy" do
context "and this is an internal transfer from a non social housing" do
before do
lettings_log_xml.at_xpath("//xmlns:Q11").content = "30 Fixed term Local Authority General Needs tenancy"
lettings_log_xml.at_xpath("//xmlns:Q11").content = "9 Residential care home"
lettings_log_xml.at_xpath("//xmlns:Q16").content = "1 Internal Transfer"
end
it "intercepts the relevant validation error" do
expect(logger).to receive(:warn).with(/Removing internal transfer referral since previous tenancy is fixed terms or lifetime/)
expect(logger).to receive(:warn).with(/Removing internal transfer referral since previous tenancy is a non social housing/)
expect { lettings_log_service.send(:create_log, lettings_log_xml) }
.not_to raise_error
end
@ -356,86 +341,202 @@ RSpec.describe Imports::LettingsLogsImportService do
expect(lettings_log).not_to be_nil
expect(lettings_log.referral).to be_nil
end
context "and this is an internal transfer from a previous fixed term tenancy" do
before do
lettings_log_xml.at_xpath("//xmlns:Q11").content = "30 Fixed term Local Authority General Needs tenancy"
lettings_log_xml.at_xpath("//xmlns:Q16").content = "1 Internal Transfer"
end
it "intercepts the relevant validation error" do
expect(logger).to receive(:warn).with(/Removing internal transfer referral since previous tenancy is fixed terms or lifetime/)
expect { lettings_log_service.send(:create_log, lettings_log_xml) }
.not_to raise_error
end
it "clears out the referral answer" do
allow(logger).to receive(:warn)
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
expect(lettings_log).not_to be_nil
expect(lettings_log.referral).to be_nil
end
end
end
end
context "and the net income soft validation is triggered (net_income_value_check)" do
before do
lettings_log_xml.at_xpath("//xmlns:Q8a").content = "1 Weekly"
lettings_log_xml.at_xpath("//xmlns:Q8Money").content = 890.00
context "and the net income soft validation is triggered (net_income_value_check)" do
before do
lettings_log_xml.at_xpath("//xmlns:Q8a").content = "1 Weekly"
lettings_log_xml.at_xpath("//xmlns:Q8Money").content = 890.00
end
it "completes the log" do
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
expect(lettings_log.status).to eq("completed")
end
end
it "completes the log" do
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
expect(lettings_log.status).to eq("completed")
context "and the rent soft validation is triggered (rent_value_check)" do
before do
lettings_log_xml.at_xpath("//xmlns:Q18ai").content = 200.00
lettings_log_xml.at_xpath("//xmlns:Q18av").content = 232.02
lettings_log_xml.at_xpath("//xmlns:Q17").content = "1 Weekly for 52 weeks"
LaRentRange.create!(
start_year: 2021,
la: "E08000035",
beds: 2,
lettype: 1,
soft_max: 900,
hard_max: 1500,
soft_min: 500,
hard_min: 100,
)
end
it "completes the log" do
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
expect(lettings_log.status).to eq("completed")
end
end
end
context "and the rent soft validation is triggered (rent_value_check)" do
before do
lettings_log_xml.at_xpath("//xmlns:Q18ai").content = 200.00
lettings_log_xml.at_xpath("//xmlns:Q18av").content = 232.02
lettings_log_xml.at_xpath("//xmlns:Q17").content = "1 Weekly for 52 weeks"
LaRentRange.create!(
start_year: 2021,
la: "E08000035",
beds: 2,
lettype: 1,
soft_max: 900,
hard_max: 1500,
soft_min: 500,
hard_min: 100,
)
context "and the retirement soft validation is triggered (retirement_value_check)" do
before do
lettings_log_xml.at_xpath("//xmlns:P1Age").content = 68
lettings_log_xml.at_xpath("//xmlns:P1Eco").content = "6) Not Seeking Work"
end
it "completes the log" do
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
expect(lettings_log.status).to eq("completed")
end
end
it "completes the log" do
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
expect(lettings_log.status).to eq("completed")
context "and this is a supported housing log with multiple locations under a scheme" do
let(:lettings_log_id) { "0b4a68df-30cc-474a-93c0-a56ce8fdad3b" }
it "sets the scheme and location values" do
expect(logger).not_to receive(:warn)
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
expect(lettings_log.scheme_id).not_to be_nil
expect(lettings_log.location_id).not_to be_nil
expect(lettings_log.status).to eq("completed")
end
end
end
context "and the retirement soft validation is triggered (retirement_value_check)" do
before do
lettings_log_xml.at_xpath("//xmlns:P1Age").content = 68
lettings_log_xml.at_xpath("//xmlns:P1Eco").content = "6) Not Seeking Work"
context "and this is a supported housing log with a single location under a scheme" do
let(:lettings_log_id) { "0b4a68df-30cc-474a-93c0-a56ce8fdad3b" }
before { lettings_log_xml.at_xpath("//xmlns:_1cmangroupcode").content = scheme2.old_visible_id }
it "sets the scheme and location values" do
expect(logger).not_to receive(:warn)
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
expect(lettings_log.scheme_id).not_to be_nil
expect(lettings_log.location_id).not_to be_nil
expect(lettings_log.status).to eq("completed")
end
end
end
end
it "completes the log" do
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
expect(lettings_log.status).to eq("completed")
context "with 22/23 logs" do
subject(:lettings_log_service) { described_class.new(storage_service, logger) }
around do |example|
Timecop.freeze(Time.zone.local(2023, 1, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
context "and this is a supported housing log with multiple locations under a scheme" do
let(:lettings_log_id) { "0b4a68df-30cc-474a-93c0-a56ce8fdad3b" }
let(:storage_service) { instance_double(Storage::S3Service) }
let(:logger) { instance_double(ActiveSupport::Logger) }
it "sets the scheme and location values" do
expect(logger).not_to receive(:warn)
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
let(:real_2021_2022_form) { Form.new("config/forms/2021_2022.json") }
let(:real_2022_2023_form) { Form.new("config/forms/2022_2023.json") }
let(:fixture_directory) { "spec/fixtures/imports/logs" }
expect(lettings_log.scheme_id).not_to be_nil
expect(lettings_log.location_id).not_to be_nil
expect(lettings_log.status).to eq("completed")
end
let(:organisation) { FactoryBot.create(:organisation, old_visible_id: "1", provider_type: "PRP") }
let(:managing_organisation) { FactoryBot.create(:organisation, old_visible_id: "2", provider_type: "PRP") }
let(:scheme1) { FactoryBot.create(:scheme, old_visible_id: "0123", owning_organisation: organisation) }
let(:scheme2) { FactoryBot.create(:scheme, old_visible_id: "456", owning_organisation: organisation) }
def open_file(directory, filename)
File.open("#{directory}/#{filename}.xml")
end
context "and this is a supported housing log with a single location under a scheme" do
let(:lettings_log_id) { "0b4a68df-30cc-474a-93c0-a56ce8fdad3b" }
before do
WebMock.stub_request(:get, /api.postcodes.io\/postcodes\/LS166FT/)
.to_return(status: 200, body: '{"status":200,"result":{"admin_district":"Westminster","codes":{"admin_district":"E08000035"}}}', headers: {})
allow(Organisation).to receive(:find_by).and_return(nil)
allow(Organisation).to receive(:find_by).with(old_visible_id: organisation.old_visible_id).and_return(organisation)
allow(Organisation).to receive(:find_by).with(old_visible_id: managing_organisation.old_visible_id).and_return(managing_organisation)
# Created by users
FactoryBot.create(:user, old_user_id: "c3061a2e6ea0b702e6f6210d5c52d2a92612d2aa", organisation:)
FactoryBot.create(:user, old_user_id: "e29c492473446dca4d50224f2bb7cf965a261d6f", organisation:)
# Location setup
FactoryBot.create(:location, old_visible_id: "10", postcode: "LS166FT", scheme_id: scheme1.id, mobility_type: "W", startdate: Time.zone.local(2021, 4, 1))
FactoryBot.create(:location, scheme_id: scheme1.id, startdate: Time.zone.local(2021, 4, 1))
FactoryBot.create(:location, old_visible_id: "10", postcode: "LS166FT", scheme_id: scheme2.id, mobility_type: "W", startdate: Time.zone.local(2021, 4, 1))
# Stub the form handler to use the real form
allow(FormHandler.instance).to receive(:get_form).with("current_lettings").and_return(real_2022_2023_form)
allow(FormHandler.instance).to receive(:get_form).with("previous_lettings").and_return(real_2021_2022_form)
allow(FormHandler.instance).to receive(:get_form).with("next_lettings").and_return(real_2022_2023_form)
end
before { lettings_log_xml.at_xpath("//xmlns:_1cmangroupcode").content = scheme2.old_visible_id }
context "when importing lettings logs" do
let(:remote_folder) { "lettings_logs" }
let(:lettings_log_id) { "00d2343e-d5fa-4c89-8400-ec3854b0f2b4" }
let(:sales_log) { "shared_ownership_sales_log" }
it "sets the scheme and location values" do
before do
# Stub the S3 file listing and download
allow(storage_service).to receive(:list_files)
.and_return(%W[#{remote_folder}/#{lettings_log_id}.xml #{remote_folder}/#{sales_log}.xml])
allow(storage_service).to receive(:get_file_io)
.with("#{remote_folder}/#{lettings_log_id}.xml")
.and_return(open_file(fixture_directory, lettings_log_id), open_file(fixture_directory, lettings_log_id))
allow(storage_service).to receive(:get_file_io)
.with("#{remote_folder}/#{sales_log}.xml")
.and_return(open_file(fixture_directory, sales_log), open_file(fixture_directory, sales_log))
end
it "successfully create all lettings logs" do
expect(logger).not_to receive(:error)
expect(logger).not_to receive(:warn)
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
expect(logger).not_to receive(:info)
expect { lettings_log_service.create_logs(remote_folder) }
.to change(LettingsLog, :count).by(1)
end
expect(lettings_log.scheme_id).not_to be_nil
expect(lettings_log.location_id).not_to be_nil
expect(lettings_log.status).to eq("completed")
it "only updates existing lettings logs" do
expect(logger).not_to receive(:error)
expect(logger).not_to receive(:warn)
expect(logger).to receive(:info).with(/Updating lettings log/).once
expect { 2.times { lettings_log_service.create_logs(remote_folder) } }
.to change(LettingsLog, :count).by(1)
end
it "creates organisation relationship once" do
expect(logger).not_to receive(:error)
expect(logger).not_to receive(:warn)
expect { lettings_log_service.create_logs(remote_folder) }
.to change(OrganisationRelationship, :count).by(1)
end
end
end

9
spec/views/form/page_view_spec.rb

@ -17,6 +17,15 @@ RSpec.describe "form/page" do
end
end
around do |example|
Timecop.freeze(Time.zone.local(2022, 1, 1)) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
before do
assign(:log, lettings_log)
assign(:page, page)

Loading…
Cancel
Save