Browse Source

CLDC-4325: Check tests will run on go live day (#3250)

* CLDC-4325: Set date to 2026

* CLDC-4325: Fix sale information % tests

I'm not sure why I turned off strict post 2026, it's wanted in the same scenarios as before as shown by the failing tests

* CLDC-4325: Fix check answers spec

* CLDC-4325: Fix old rake task tests

* CLDC-4325: Fix sales soft validations

* CLDC-4325: Fix collection resources controller spec

* CLDC-4325: Only add noms and org to CSV row if prp

in most cases this was done by default but some tests construct an invalid log

* CLDC-4325: Fix lettings household validations spec

* CLDC-4221: Add 2026 collection deadlines

* CLDC-4325: Fix remaining model specs

* CLDC-4325: Fix form controller spec

* CLDC-4325: Fix hhmemb spec

* CLDC-4325: Fix duplicate logs controller spec

also introduce a new helper for a dynamic way of setting year

* CLDC-4325: Fix sales BU validator spec

* CLDC-4325: Fix check answers summary component

* CLDC-4325: Remove 2024 rake

* CLDC-4325: Use or later in all touched tests

* CLDC-4325: Fix guidance helper spec

* CLDC-4325: Run all tests now and in 2026

* CLDC-4325: Turn off 2026 override

* CLDC-4325: Add a corresponding return to timecop missing one

* CLDC-4325: Fix sales log spec in 2025

need to use let rather than let! so the timecop can run first

* CLDC-4325: Fix lettings log derived spec in 2025

timecop required for the start dates to work

* CLDC-4325: Turn the 2026 override on again

* fixup! CLDC-4325: Fix check answers summary component

* CLDC-4325: Delete recalculate_reasonpref_dontknow rake

only needed for 2024 logs

* fixup! CLDC-4325: Fix lettings household validations spec

Co-authored-by: Oscar Richardson <116292912+oscar-richardson-softwire@users.noreply.github.com>

* fixup! CLDC-4325: Fix sales log spec in 2025

* fixup! CLDC-4325: Fix sales log spec in 2025

* CLDC-4325: Make start controller spec not year specific

* CLDC-4325: Run tests in current day

* CLDC-4325: Run tests on 31st march

* CLDC-4325: Run tests on 2nd april

* CLDC-4325: Properly run tests on current day

* fixup! CLDC-4325: Fix sales soft validations

* fixup! CLDC-4325: Make start controller spec not year specific

* CLDC-4325: Run tests on 31st march

* CLDC-4325: Run tests on 1st april

* CLDC-4325: Run tests on 2nd april

* CLDC-4325: Revert time travel

---------

Co-authored-by: Oscar Richardson <116292912+oscar-richardson-softwire@users.noreply.github.com>
pull/3278/head
Samuel Young 3 months ago committed by GitHub
parent
commit
6a655e7210
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 4
      app/helpers/bulk_upload/lettings_log_to_csv.rb
  2. 6
      app/helpers/collection_time_helper.rb
  3. 2
      app/models/validations/sales/sale_information_validations.rb
  4. 12
      lib/tasks/recalculate_invalid_reasonpref_dontknow.rake
  5. 207
      lib/tasks/update_manual_address_entry_selected_prexisting_logs.rake
  6. 8
      spec/components/check_answers_summary_list_card_component_spec.rb
  7. 6
      spec/features/form/check_answers_page_sales_logs_spec.rb
  8. 2
      spec/helpers/guidance_helper_spec.rb
  9. 77
      spec/lib/tasks/recalculate_invalid_reasonpref_dontknow_spec.rb
  10. 218
      spec/lib/tasks/update_manual_address_entry_selected_prexisting_logs_spec.rb
  11. 30
      spec/models/bulk_upload_spec.rb
  12. 11
      spec/models/form/lettings/questions/hhmemb_spec.rb
  13. 37
      spec/models/lettings_log_derived_fields_spec.rb
  14. 10
      spec/models/organisation_name_change_spec.rb
  15. 60
      spec/models/sales_log_spec.rb
  16. 15
      spec/models/validations/household_validations_spec.rb
  17. 61
      spec/models/validations/property_validations_spec.rb
  18. 152
      spec/models/validations/sales/sale_information_validations_spec.rb
  19. 21
      spec/models/validations/sales/soft_validations_spec.rb
  20. 18
      spec/requests/collection_resources_controller_spec.rb
  21. 471
      spec/requests/duplicate_logs_controller_spec.rb
  22. 2
      spec/requests/form_controller_spec.rb
  23. 76
      spec/requests/start_controller_spec.rb
  24. 7
      spec/services/bulk_upload/sales/validator_spec.rb

4
app/helpers/bulk_upload/lettings_log_to_csv.rb

@ -240,8 +240,8 @@ class BulkUpload::LettingsLogToCsv
accessible_register, # 130 accessible_register, # 130
log.owning_organisation.la? ? log.referral_register : nil, log.owning_organisation.la? ? log.referral_register : nil,
log.owning_organisation.prp? ? log.referral_register : nil, log.owning_organisation.prp? ? log.referral_register : nil,
log.referral_noms, log.owning_organisation.prp? ? log.referral_noms : nil,
log.referral_org, log.owning_organisation.prp? ? log.referral_org : nil,
net_income_known, net_income_known,
log.incfreq, log.incfreq,
log.earnings, log.earnings,

6
app/helpers/collection_time_helper.rb

@ -94,4 +94,10 @@ module CollectionTimeHelper
available_dates = (start_date..end_date).to_a - [date.to_date] available_dates = (start_date..end_date).to_a - [date.to_date]
available_dates.empty? ? nil : available_dates.sample available_dates.empty? ? nil : available_dates.sample
end end
# useful for writing future tests that will also test the current time if it can or a future year if needed.
# stops tests being frozen on a specific year.
def collection_start_date_for_year_or_later(year)
collection_start_date_for_year([current_collection_start_year, year].max)
end
end end

2
app/models/validations/sales/sale_information_validations.rb

@ -82,7 +82,7 @@ module Validations::Sales::SaleInformationValidations
tolerance = record.value_with_discount_tolerance tolerance = record.value_with_discount_tolerance
if over_tolerance?(record.mortgage_deposit_and_grant_total, record.value_with_discount, tolerance, strict: !record.discount.nil? || record.form.start_year_2026_or_later?) && record.discounted_ownership_sale? if over_tolerance?(record.mortgage_deposit_and_grant_total, record.value_with_discount, tolerance, strict: !record.discount.nil?) && record.discounted_ownership_sale?
deposit_and_grant_sentence = record.grant.present? ? ", cash deposit (#{record.field_formatted_as_currency('deposit')}), and grant (#{record.field_formatted_as_currency('grant')})" : " and cash deposit (#{record.field_formatted_as_currency('deposit')})" deposit_and_grant_sentence = record.grant.present? ? ", cash deposit (#{record.field_formatted_as_currency('deposit')}), and grant (#{record.field_formatted_as_currency('grant')})" : " and cash deposit (#{record.field_formatted_as_currency('deposit')})"
discount_sentence = record.discount.present? ? " (#{record.field_formatted_as_currency('value')}) subtracted by the sum of the full purchase price (#{record.field_formatted_as_currency('value')}) multiplied by the percentage discount (#{record.discount}%)" : "" discount_sentence = record.discount.present? ? " (#{record.field_formatted_as_currency('value')}) subtracted by the sum of the full purchase price (#{record.field_formatted_as_currency('value')}) multiplied by the percentage discount (#{record.discount}%)" : ""
%i[mortgageused mortgage value deposit discount grant].each do |field| %i[mortgageused mortgage value deposit discount grant].each do |field|

12
lib/tasks/recalculate_invalid_reasonpref_dontknow.rake

@ -1,12 +0,0 @@
desc "Bulk update logs with invalid rp_dontknow values"
task recalculate_invalid_rpdontknow: :environment do
validation_trigger_condition = "rp_dontknow = 1 AND (rp_homeless = 1 OR rp_insan_unsat = 1 OR rp_medwel = 1 OR rp_hardship = 1)"
LettingsLog.filter_by_year(2024).where(validation_trigger_condition).find_each do |log|
log.rp_dontknow = 0
unless log.save
Rails.logger.info "Could not save changes to lettings log #{log.id}"
end
end
end

207
lib/tasks/update_manual_address_entry_selected_prexisting_logs.rake

@ -1,207 +0,0 @@
namespace :bulk_update do
desc "Update logs with specific criteria and set manual_address_entry_selected to true"
task update_manual_address_entry_selected: :environment do
updated_lettings_logs_count = 0
lettings_postcode_fixed_count = 0
lettings_postcode_fixed_status_changed_count = 0
lettings_postcode_not_fixed_status_changed_count = 0
lettings_postcode_fixed_status_changed_ids = []
lettings_postcode_not_fixed_status_changed_ids = []
lettings_updated_without_issue = 0
updated_sales_logs_count = 0
sales_postcode_fixed_count = 0
sales_postcode_fixed_status_changed_count = 0
sales_postcode_not_fixed_status_changed_count = 0
sales_postcode_fixed_status_changed_ids = []
sales_postcode_not_fixed_status_changed_ids = []
sales_updated_without_issue = 0
lettings_logs = LettingsLog.filter_by_year(2024)
.where(status: %w[in_progress completed])
.where(needstype: 1, manual_address_entry_selected: false, uprn: nil)
.where("(address_line1 IS NOT NULL AND address_line1 != '') OR (address_line2 IS NOT NULL AND address_line2 != '') OR (town_or_city IS NOT NULL AND town_or_city != '') OR (county IS NOT NULL AND county != '') OR (postcode_full IS NOT NULL AND postcode_full != '')")
lettings_logs.find_each do |log|
status_pre_change = log.status
log.manual_address_entry_selected = true
if log.save
updated_lettings_logs_count += 1
Rails.logger.info "manual_address_entry_selected updated for lettings log #{log.id}"
else
Rails.logger.info "Could not save manual_address_entry_selected changes to lettings log #{log.id} : #{log.errors.full_messages.join(', ')}"
end
postcode_fixed = false
if log.postcode_full.nil? && log.address_line1 == log.address_line1_input
log.postcode_full = log.postcode_full_input
if log.save
lettings_postcode_fixed_count += 1
Rails.logger.info "postcode_full updated by address_line1_input for lettings log #{log.id}"
postcode_fixed = true
else
Rails.logger.info "Could not save postcode_full changes to lettings log #{log.id} : #{log.errors.full_messages.join(', ')}"
end
end
if log.postcode_full.nil? && log.creation_method == "bulk upload" && log.address_line1 == log.address_line1_as_entered
log.postcode_full = log.postcode_full_as_entered
if log.save
lettings_postcode_fixed_count += 1
Rails.logger.info "postcode_full updated by address_line1_as_entered for lettings log #{log.id}"
postcode_fixed = true
else
Rails.logger.info "Could not save postcode_full changes to lettings log #{log.id} : #{log.errors.full_messages.join(', ')}"
end
end
status_post_change = log.status
if status_pre_change != status_post_change
if postcode_fixed
lettings_postcode_fixed_status_changed_count += 1
lettings_postcode_fixed_status_changed_ids << log.id
else
lettings_postcode_not_fixed_status_changed_count += 1
lettings_postcode_not_fixed_status_changed_ids << log.id
end
else
lettings_updated_without_issue += 1
end
end
sales_logs = SalesLog.filter_by_year(2024)
.where(status: %w[in_progress completed])
.where(manual_address_entry_selected: false, uprn: nil)
.where("(address_line1 IS NOT NULL AND address_line1 != '') OR (address_line2 IS NOT NULL AND address_line2 != '') OR (town_or_city IS NOT NULL AND town_or_city != '') OR (county IS NOT NULL AND county != '') OR (postcode_full IS NOT NULL AND postcode_full != '')")
sales_logs.find_each do |log|
status_pre_change = log.status
log.manual_address_entry_selected = true
if log.save
updated_sales_logs_count += 1
Rails.logger.info "manual_address_entry_selected updated for sales log #{log.id}"
else
Rails.logger.info "Could not save manual_address_entry_selected changes to sales log #{log.id} : #{log.errors.full_messages.join(', ')}"
end
postcode_fixed = false
if log.postcode_full.nil? && log.address_line1 == log.address_line1_input
log.postcode_full = log.postcode_full_input
if log.save
sales_postcode_fixed_count += 1
Rails.logger.info "postcode_full updated by address_line1_input for sales log #{log.id}"
postcode_fixed = true
else
Rails.logger.info "Could not save postcode_full changes to sales log #{log.id} : #{log.errors.full_messages.join(', ')}"
end
end
if log.postcode_full.nil? && log.creation_method == "bulk upload" && log.address_line1 == log.address_line1_as_entered
log.postcode_full = log.postcode_full_as_entered
if log.save
sales_postcode_fixed_count += 1
Rails.logger.info "postcode_full updated by address_line1_as_entered for sales log #{log.id}"
postcode_fixed = true
else
Rails.logger.info "Could not save postcode_full changes to sales log #{log.id} : #{log.errors.full_messages.join(', ')}"
end
end
status_post_change = log.status
if status_pre_change != status_post_change
if postcode_fixed
sales_postcode_fixed_status_changed_count += 1
sales_postcode_fixed_status_changed_ids << log.id
else
sales_postcode_not_fixed_status_changed_count += 1
sales_postcode_not_fixed_status_changed_ids << log.id
end
else
sales_updated_without_issue += 1
end
end
puts "#{updated_lettings_logs_count} lettings logs were updated."
puts "#{lettings_updated_without_issue} lettings logs were updated without issue."
puts "#{lettings_postcode_fixed_count} lettings logs where postcode fix was applied."
puts "#{lettings_postcode_fixed_status_changed_count} lettings logs with postcode fix and status changed."
puts "#{lettings_postcode_not_fixed_status_changed_count} lettings logs without postcode fix and status changed."
puts "IDs of lettings logs with postcode fix and status changed: [#{lettings_postcode_fixed_status_changed_ids.join(', ')}]"
puts "IDs of lettings logs without postcode fix and status changed: [#{lettings_postcode_not_fixed_status_changed_ids.join(', ')}]"
lettings_postcode_fixed_org_counts = LettingsLog.where(id: lettings_postcode_fixed_status_changed_ids).group(:owning_organisation_id).count
lettings_postcode_fixed_org_counts.each do |org_id, count|
puts "Org #{org_id}: #{count} logs with postcode fix and status changed."
end
lettings_postcode_not_fixed_org_counts = LettingsLog.where(id: lettings_postcode_not_fixed_status_changed_ids).group(:owning_organisation_id).count
lettings_postcode_not_fixed_org_counts.each do |org_id, count|
puts "Org #{org_id}: #{count} logs without postcode fix and status changed."
end
puts "#{updated_sales_logs_count} sales logs were updated."
puts "#{sales_updated_without_issue} sales logs were updated without issue."
puts "#{sales_postcode_fixed_count} sales logs where postcode fix was applied."
puts "#{sales_postcode_fixed_status_changed_count} sales logs with postcode fix and status changed."
puts "#{sales_postcode_not_fixed_status_changed_count} sales logs without postcode fix and status changed."
puts "IDs of sales logs with postcode fix and status changed: [#{sales_postcode_fixed_status_changed_ids.join(', ')}]"
puts "IDs of sales logs without postcode fix and status changed: [#{sales_postcode_not_fixed_status_changed_ids.join(', ')}]"
sales_postcode_fixed_org_counts = SalesLog.where(id: sales_postcode_fixed_status_changed_ids).group(:owning_organisation_id).count
sales_postcode_fixed_org_counts.each do |org_id, count|
puts "Org #{org_id}: #{count} logs with postcode fix and status changed."
end
sales_postcode_not_fixed_org_counts = SalesLog.where(id: sales_postcode_not_fixed_status_changed_ids).group(:owning_organisation_id).count
sales_postcode_not_fixed_org_counts.each do |org_id, count|
puts "Org #{org_id}: #{count} logs without postcode fix and status changed."
end
end
desc "Find logs to fix and update postcode_full if conditions are met"
task update_postcode_full_preexisting_manual_entry_logs: :environment do
updated_count = 0
fixed_count = 0
not_updated_count = 0
not_updated_ids = []
updated_but_not_fixed_ids = []
logs_to_fix = LettingsLog.filter_by_year(2024).where(manual_address_entry_selected: true, uprn: nil, status: "in_progress", postcode_full: nil, updated_at: Time.zone.parse("2025-03-19 16:00:00")..Time.zone.parse("2025-03-19 17:00:00"))
logs_to_fix.find_each do |log|
previous_version = log.versions[-2]
previous_status = previous_version&.reify&.status
if log.address_line1 == log.address_line1_input
log.postcode_full = log.postcode_full_input
elsif log.creation_method == "bulk upload" && log.address_line1 == log.address_line1_as_entered
log.postcode_full = log.postcode_full_as_entered
end
if log.postcode_full.present?
if log.save
Rails.logger.info "Updated postcode_full for lettings log #{log.id}"
updated_count += 1
if log.status == previous_status
fixed_count += 1
else
updated_but_not_fixed_ids << log.id
end
else
Rails.logger.info "Could not save changes to lettings log #{log.id}: #{log.errors.full_messages.join(', ')}"
not_updated_count += 1
not_updated_ids << log.id
end
else
not_updated_count += 1
not_updated_ids << log.id
end
end
puts "#{updated_count} logs updated."
puts "#{fixed_count} logs fixed."
puts "#{not_updated_count} logs not updated."
puts "IDs of logs not updated: [#{not_updated_ids.join(', ')}]"
puts "IDs of logs updated but not fixed: [#{updated_but_not_fixed_ids.join(', ')}]"
end
end

8
spec/components/check_answers_summary_list_card_component_spec.rb

@ -6,7 +6,7 @@ RSpec.describe CheckAnswersSummaryListCardComponent, type: :component do
let(:rendered) { render_inline(component) } let(:rendered) { render_inline(component) }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:log) { create(:lettings_log, :completed, sex1: "F", age2: 99, retirement_value_check: 1) } let(:log) { create(:lettings_log, :completed) }
let(:subsection_id) { "household_characteristics" } let(:subsection_id) { "household_characteristics" }
let(:subsection) { log.form.get_subsection(subsection_id) } let(:subsection) { log.form.get_subsection(subsection_id) }
let(:questions) { subsection.applicable_questions(log) } let(:questions) { subsection.applicable_questions(log) }
@ -21,8 +21,8 @@ RSpec.describe CheckAnswersSummaryListCardComponent, type: :component do
end end
it "has the correct answer label for a question" do it "has the correct answer label for a question" do
sex1_question = questions.find { |q| q.id == "sex1" } question = questions.find { |q| q.id == "ecstat1" }
expect(component.get_answer_label(sex1_question)).to eq("Female") expect(component.get_answer_label(question)).to eq("Other")
end end
context "when log was created via a bulk upload and has an unanswered question" do context "when log was created via a bulk upload and has an unanswered question" do
@ -46,7 +46,7 @@ RSpec.describe CheckAnswersSummaryListCardComponent, type: :component do
let(:log) { create(:lettings_log, :in_progress) } let(:log) { create(:lettings_log, :in_progress) }
it "displays normal copy with muted colour" do it "displays normal copy with muted colour" do
expect(rendered).to have_link(log.form.get_question("sex1", log).check_answer_prompt, href: "/lettings-logs/#{log.id}/lead-tenant-gender-identity?referrer=check_answers_new_answer", class: "govuk-link govuk-link--no-visited-state") expect(rendered).to have_link(log.form.get_question("age1", log).check_answer_prompt, href: "/lettings-logs/#{log.id}/lead-tenant-age?referrer=check_answers_new_answer", class: "govuk-link govuk-link--no-visited-state")
end end
end end

6
spec/features/form/check_answers_page_sales_logs_spec.rb

@ -3,6 +3,8 @@ require_relative "helpers"
RSpec.describe "Sales Log Check Answers Page" do RSpec.describe "Sales Log Check Answers Page" do
include Helpers include Helpers
include CollectionTimeHelper
let(:user) { FactoryBot.create(:user) } let(:user) { FactoryBot.create(:user) }
let(:subsection) { "household-characteristics" } let(:subsection) { "household-characteristics" }
let(:conditional_subsection) { "conditional-question" } let(:conditional_subsection) { "conditional-question" }
@ -13,7 +15,7 @@ RSpec.describe "Sales Log Check Answers Page" do
:completed, :completed,
assigned_to: user, assigned_to: user,
jointpur: 1, jointpur: 1,
hholdcount: 4, hholdcount: current_collection_start_year >= 2026 ? 6 : 4,
) )
end end
@ -23,7 +25,7 @@ RSpec.describe "Sales Log Check Answers Page" do
:completed, :completed,
assigned_to: user, assigned_to: user,
jointpur: 2, jointpur: 2,
hholdcount: 4, hholdcount: current_collection_start_year >= 2026 ? 6 : 4,
) )
end end

2
spec/helpers/guidance_helper_spec.rb

@ -14,7 +14,7 @@ RSpec.describe GuidanceHelper do
let(:log) { create(:sales_log, :shared_ownership_setup_complete, mortgageused: 1, staircase: 2) } let(:log) { create(:sales_log, :shared_ownership_setup_complete, mortgageused: 1, staircase: 2) }
it "returns a link to the question with correct question number in brackets" do it "returns a link to the question with correct question number in brackets" do
expect(question_link("mortgage", log, log.assigned_to)).to eq("(<a class=\"govuk-link\" href=\"/sales-logs/#{log.id}/mortgage-amount-shared-ownership\">Q83</a>)") expect(question_link("mortgage", log, log.assigned_to)).to match(/\(<a class="govuk-link" href="\/sales-logs\/#{log.id}\/mortgage-amount-shared-ownership">Q\d+<\/a>\)/)
end end
end end
end end

77
spec/lib/tasks/recalculate_invalid_reasonpref_dontknow_spec.rb

@ -1,77 +0,0 @@
require "rails_helper"
require "rake"
RSpec.describe "recalculate_invalid_reasonpref_dontknow" do
include CollectionTimeHelper
subject(:task) { Rake::Task["recalculate_invalid_rpdontknow"] }
before do
Rake.application.rake_require("tasks/recalculate_invalid_reasonpref_dontknow")
Rake::Task.define_task(:environment)
task.reenable
Timecop.freeze(previous_collection_end_date)
end
after do
Timecop.return
end
let(:invalid_logs) { create_list(:lettings_log, 5, :completed, :ignore_validation_errors, reasonpref: 1, rp_dontknow: 1, rp_homeless: 1, rp_insan_unsat: rand(2), rp_medwel: rand(2), rp_hardship: rand(2), updated_at: Time.zone.local(2024, 4, 2, 12, 0, 0), startdate: Time.zone.local(2024, rand(4..12), rand(1..30))) }
let(:pre_2024_invalid_logs) do
create_list(:lettings_log, 5, :completed, reasonpref: 1, rp_dontknow: 1, rp_homeless: 1, rp_insan_unsat: rand(2), rp_medwel: rand(2), rp_hardship: rand(2)).each do |log|
log.startdate = Time.zone.local(rand(2021..2023), 4, 1)
log.save!(validate: false)
end
end
let(:valid_logs) { create_list(:lettings_log, 3, :completed, :ignore_validation_errors, reasonpref: 1, rp_dontknow: 0, rp_homeless: 1, rp_insan_unsat: 1, rp_medwel: rand(2), rp_hardship: rand(2), updated_at: Time.zone.local(2024, 4, 2, 12, 0, 0), startdate: Time.zone.local(2024, rand(4..12), rand(1..30))) }
it "updates the logs from 2024/25 with invalid rp_dontknow values" do
invalid_logs.each do |log|
expect(log.reasonpref).to eq(1)
expect(log.rp_dontknow).to eq(1)
expect(log.rp_homeless).to eq(1)
end
task.invoke
invalid_logs.each do |log|
log.reload
expect(log.reasonpref).to eq(1)
expect(log.rp_dontknow).to eq(0)
expect(log.rp_homeless).to eq(1)
expect(log.updated_at).not_to eq(Time.zone.local(2024, 4, 2, 12, 0, 0))
end
end
it "does not update the logs pre 2024 with invalid rp_dontknow values" do
pre_2024_invalid_logs.each do |log|
expect(log.reasonpref).to eq(1)
expect(log.rp_dontknow).to eq(1)
expect(log.rp_homeless).to eq(1)
end
task.invoke
pre_2024_invalid_logs.each do |log|
log.reload
expect(log.reasonpref).to eq(1)
expect(log.rp_dontknow).to eq(1)
expect(log.rp_homeless).to eq(1)
end
end
it "does not update the logs with valid rp_dontknow values" do
valid_logs.each do |log|
expect(log.reasonpref).to eq(1)
expect(log.rp_dontknow).to eq(0)
expect(log.rp_homeless).to eq(1)
expect(log.rp_insan_unsat).to eq(1)
end
task.invoke
valid_logs.each do |log|
log.reload
expect(log.reasonpref).to eq(1)
expect(log.rp_dontknow).to eq(0)
expect(log.rp_homeless).to eq(1)
expect(log.rp_insan_unsat).to eq(1)
expect(log.updated_at).to eq(Time.zone.local(2024, 4, 2, 12, 0, 0))
end
end
end

218
spec/lib/tasks/update_manual_address_entry_selected_prexisting_logs_spec.rb

@ -1,218 +0,0 @@
require "rails_helper"
require "rake"
RSpec.describe "update_manual_address_entry_selected_preexisting_logs_spec", type: :task do
include CollectionTimeHelper
before do
Rake.application.rake_require("tasks/update_manual_address_entry_selected_prexisting_logs")
Rake::Task.define_task(:environment)
task.reenable
Timecop.freeze(previous_collection_end_date)
end
after do
Timecop.return
end
describe "bulk_update:update_manual_address_entry_selected" do
let(:task) { Rake::Task["bulk_update:update_manual_address_entry_selected"] }
let(:lettings_log_uprn_entered) do
build(:lettings_log, :completed, startdate: Time.zone.local(2024, 6, 1), needstype: 1, manual_address_entry_selected: false)
end
let(:lettings_log_uprn_found) do
build(:lettings_log, :completed, startdate: Time.zone.local(2024, 9, 1), needstype: 1, manual_address_entry_selected: false, address_line1_input: "1 Test Street", postcode_full_input: "SW1 1AA")
end
let(:lettings_log_address_fields_not_entered) do
build(:lettings_log, :inprogress_without_address_fields, startdate: Time.zone.local(2024, 9, 1), needstype: 1)
end
let(:lettings_log_address_manually_entered) do
build(:lettings_log, :completed_without_uprn, startdate: Time.zone.local(2024, 12, 1), needstype: 1)
end
let(:sales_log_uprn_entered) do
build(:sales_log, :completed, saledate: Time.zone.local(2024, 12, 1), manual_address_entry_selected: false)
end
let(:sales_log_uprn_found) do
build(:sales_log, :completed, saledate: Time.zone.local(2024, 7, 1), manual_address_entry_selected: false, address_line1_input: "1 Test Street", postcode_full_input: "SW1 1AA")
end
let(:sales_log_address_fields_not_entered) do
build(:sales_log, :inprogress_without_address_fields, saledate: Time.zone.local(2024, 12, 30))
end
let(:sales_log_address_manually_entered) do
build(:sales_log, :completed_without_uprn, saledate: Time.zone.local(2024, 12, 30))
end
context "when running the task" do
context "when logs do not meet the criteria" do
before do
lettings_log_uprn_found.save!(validate: false)
lettings_log_uprn_entered.save!(validate: false)
lettings_log_address_fields_not_entered.save!(validate: false)
sales_log_uprn_found.save!(validate: false)
sales_log_uprn_entered.save!(validate: false)
sales_log_address_fields_not_entered.save!(validate: false)
end
it "does not update logs with a UPRN entered" do
task.invoke
lettings_log_uprn_entered.reload
sales_log_uprn_entered.reload
expect(lettings_log_uprn_entered.manual_address_entry_selected).to be false
expect(lettings_log_uprn_entered.uprn).to eq("10033558653")
expect(sales_log_uprn_entered.manual_address_entry_selected).to be false
expect(sales_log_uprn_entered.uprn).to eq("10033558653")
end
it "does not update logs with a UPRN found" do
task.invoke
lettings_log_uprn_found.reload
sales_log_uprn_found.reload
expect(lettings_log_uprn_found.manual_address_entry_selected).to be false
expect(lettings_log_uprn_found.uprn).to eq("10033558653")
expect(sales_log_uprn_found.manual_address_entry_selected).to be false
expect(sales_log_uprn_found.uprn).to eq("10033558653")
end
it "does not update logs with no UPRN or address fields entered" do
task.invoke
lettings_log_address_fields_not_entered.reload
sales_log_address_fields_not_entered.reload
expect(lettings_log_address_fields_not_entered.manual_address_entry_selected).to be false
expect(sales_log_address_fields_not_entered.manual_address_entry_selected).to be false
end
end
context "when logs do meet the criteria" do
before do
lettings_log_address_manually_entered.manual_address_entry_selected = false
lettings_log_address_manually_entered.save!(validate: false)
sales_log_address_manually_entered.manual_address_entry_selected = false
sales_log_address_manually_entered.save!(validate: false)
end
it "updates logs with an address manually entered" do
expect(lettings_log_address_manually_entered.manual_address_entry_selected).to be false
expect(lettings_log_address_manually_entered.address_line1).to eq("1 Test Street")
expect(lettings_log_address_manually_entered.address_line2).to eq("Testville")
expect(lettings_log_address_manually_entered.town_or_city).to eq("Testford")
expect(lettings_log_address_manually_entered.postcode_full).to eq("SW1 1AA")
expect(sales_log_address_manually_entered.manual_address_entry_selected).to be false
expect(sales_log_address_manually_entered.address_line1).to eq("1 Test Street")
expect(sales_log_address_manually_entered.address_line2).to eq("Testville")
expect(sales_log_address_manually_entered.town_or_city).to eq("Testford")
expect(sales_log_address_manually_entered.postcode_full).to eq("SW1 1AA")
task.invoke
lettings_log_address_manually_entered.reload
sales_log_address_manually_entered.reload
expect(lettings_log_address_manually_entered.manual_address_entry_selected).to be true
expect(lettings_log_address_manually_entered.address_line1).to eq("1 Test Street")
expect(lettings_log_address_manually_entered.address_line2).to eq("Testville")
expect(lettings_log_address_manually_entered.town_or_city).to eq("Testford")
expect(lettings_log_address_manually_entered.postcode_full).to eq("SW1 1AA")
expect(sales_log_address_manually_entered.manual_address_entry_selected).to be true
expect(sales_log_address_manually_entered.address_line1).to eq("1 Test Street")
expect(sales_log_address_manually_entered.address_line2).to eq("Testville")
expect(sales_log_address_manually_entered.town_or_city).to eq("Testford")
expect(sales_log_address_manually_entered.postcode_full).to eq("SW1 1AA")
end
end
end
end
describe "bulk_update:update_postcode_full_preexisting_manual_entry_logs" do
let(:task) { Rake::Task["bulk_update:update_postcode_full_preexisting_manual_entry_logs"] }
let(:lettings_log_to_fix) do
build(:lettings_log, :inprogress_without_address_fields, startdate: Time.zone.local(2024, 6, 1), updated_at: Time.zone.parse("2025-03-19 16:30:00"))
end
let(:bu_lettings_log_to_fix) do
build(:lettings_log, :inprogress_without_address_fields, startdate: Time.zone.local(2024, 6, 1), creation_method: "bulk upload", updated_at: Time.zone.parse("2025-03-19 16:30:00"))
end
let(:lettings_log_not_to_fix) do
build(:lettings_log, :inprogress_without_address_fields, startdate: Time.zone.local(2024, 6, 1), updated_at: Time.zone.parse("2025-03-19 15:30:00"))
end
before do
lettings_log_to_fix.manual_address_entry_selected = true
lettings_log_to_fix.address_line1 = "1 Test Street"
lettings_log_to_fix.address_line2 = "Testville"
lettings_log_to_fix.town_or_city = "Testford"
lettings_log_to_fix.postcode_full = nil
lettings_log_to_fix.address_line1_input = "1 Test Street"
lettings_log_to_fix.postcode_full_input = "SW1 2BB"
lettings_log_to_fix.save!(validate: false)
bu_lettings_log_to_fix.manual_address_entry_selected = true
bu_lettings_log_to_fix.address_line1 = "1 Test Street"
bu_lettings_log_to_fix.address_line2 = "Testville"
bu_lettings_log_to_fix.town_or_city = "Testford"
bu_lettings_log_to_fix.postcode_full = nil
bu_lettings_log_to_fix.address_line1_as_entered = "1 Test Street"
bu_lettings_log_to_fix.postcode_full_as_entered = "SW1 2BB"
bu_lettings_log_to_fix.save!(validate: false)
lettings_log_not_to_fix.postcode_full = nil
lettings_log_not_to_fix.save!(validate: false)
end
context "when running the task" do
it "updates logs that meet the criteria" do
expect(lettings_log_to_fix.postcode_full).to be_nil
expect(lettings_log_to_fix.address_line1).to eq("1 Test Street")
expect(lettings_log_to_fix.address_line2).to eq("Testville")
expect(lettings_log_to_fix.town_or_city).to eq("Testford")
expect(lettings_log_to_fix.address_line1_input).to eq("1 Test Street")
expect(lettings_log_to_fix.postcode_full_input).to eq("SW1 2BB")
expect(bu_lettings_log_to_fix.postcode_full).to be_nil
expect(bu_lettings_log_to_fix.address_line1_input).to be_nil
expect(bu_lettings_log_to_fix.address_line1).to eq("1 Test Street")
expect(bu_lettings_log_to_fix.address_line2).to eq("Testville")
expect(bu_lettings_log_to_fix.town_or_city).to eq("Testford")
expect(bu_lettings_log_to_fix.address_line1_as_entered).to eq("1 Test Street")
expect(bu_lettings_log_to_fix.postcode_full_as_entered).to eq("SW1 2BB")
task.invoke
lettings_log_to_fix.reload
bu_lettings_log_to_fix.reload
expect(lettings_log_to_fix.postcode_full).to eq(lettings_log_to_fix.postcode_full_input)
expect(lettings_log_to_fix.postcode_full).to eq("SW1 2BB")
expect(bu_lettings_log_to_fix.postcode_full).to eq(bu_lettings_log_to_fix.postcode_full_as_entered)
expect(bu_lettings_log_to_fix.postcode_full).to eq("SW1 2BB")
end
it "does not update logs that do not meet the criteria" do
task.invoke
lettings_log_not_to_fix.reload
expect(lettings_log_not_to_fix.postcode_full).to be_nil
end
end
end
end

30
spec/models/bulk_upload_spec.rb

@ -22,8 +22,12 @@ RSpec.describe BulkUpload, type: :model do
end end
describe "value check clearing" do describe "value check clearing" do
context "when 2025", metadata: { year: 25 } do
let(:startdate) { collection_start_date_for_year(2025) }
let(:saledate) { collection_start_date_for_year(2025) }
context "with a lettings log bulk upload" do context "with a lettings log bulk upload" do
let(:log) { build(:lettings_log, startdate: current_collection_start_date, bulk_upload:) } let(:log) { build(:lettings_log, startdate:, bulk_upload:) }
it "has the correct number of value checks to be set as confirmed" do it "has the correct number of value checks to be set as confirmed" do
expect(bulk_upload.fields_to_confirm(log)).to match_array %w[rent_value_check void_date_value_check major_repairs_date_value_check pregnancy_value_check retirement_value_check referral_value_check net_income_value_check scharge_value_check pscharge_value_check supcharg_value_check multiple_partners_value_check partner_under_16_value_check reasonother_value_check] expect(bulk_upload.fields_to_confirm(log)).to match_array %w[rent_value_check void_date_value_check major_repairs_date_value_check pregnancy_value_check retirement_value_check referral_value_check net_income_value_check scharge_value_check pscharge_value_check supcharg_value_check multiple_partners_value_check partner_under_16_value_check reasonother_value_check]
@ -31,7 +35,7 @@ RSpec.describe BulkUpload, type: :model do
end end
context "with a sales log bulk upload" do context "with a sales log bulk upload" do
let(:log) { build(:sales_log, saledate: current_collection_start_date, bulk_upload:) } let(:log) { build(:sales_log, saledate:, bulk_upload:) }
it "has the correct number of value checks to be set as confirmed" do it "has the correct number of value checks to be set as confirmed" do
expect(bulk_upload.fields_to_confirm(log)).to match_array %w[value_value_check monthly_charges_value_check percentage_discount_value_check income1_value_check income2_value_check combined_income_value_check retirement_value_check old_persons_shared_ownership_value_check buyer_livein_value_check wheel_value_check mortgage_value_check savings_value_check deposit_value_check staircase_bought_value_check stairowned_value_check hodate_check shared_ownership_deposit_value_check extrabor_value_check grant_value_check discounted_sale_value_check deposit_and_mortgage_value_check multiple_partners_value_check partner_under_16_value_check] expect(bulk_upload.fields_to_confirm(log)).to match_array %w[value_value_check monthly_charges_value_check percentage_discount_value_check income1_value_check income2_value_check combined_income_value_check retirement_value_check old_persons_shared_ownership_value_check buyer_livein_value_check wheel_value_check mortgage_value_check savings_value_check deposit_value_check staircase_bought_value_check stairowned_value_check hodate_check shared_ownership_deposit_value_check extrabor_value_check grant_value_check discounted_sale_value_check deposit_and_mortgage_value_check multiple_partners_value_check partner_under_16_value_check]
@ -39,6 +43,28 @@ RSpec.describe BulkUpload, type: :model do
end end
end end
context "when 2026 or later", metadata: { year: 26 } do
let(:startdate) { collection_start_date_for_year_or_later(2026) }
let(:saledate) { collection_start_date_for_year_or_later(2026) }
context "with a lettings log bulk upload" do
let(:log) { build(:lettings_log, startdate:, bulk_upload:) }
it "has the correct number of value checks to be set as confirmed" do
expect(bulk_upload.fields_to_confirm(log)).to match_array %w[rent_value_check void_date_value_check major_repairs_date_value_check pregnancy_value_check retirement_value_check net_income_value_check scharge_value_check pscharge_value_check supcharg_value_check reasonother_value_check tenancyother_value_check working_situation_illness_check]
end
end
context "with a sales log bulk upload" do
let(:log) { build(:sales_log, saledate:, bulk_upload:) }
it "has the correct number of value checks to be set as confirmed" do
expect(bulk_upload.fields_to_confirm(log)).to match_array %w[value_value_check monthly_charges_value_check percentage_discount_value_check income1_value_check income2_value_check combined_income_value_check retirement_value_check old_persons_shared_ownership_value_check buyer_livein_value_check wheel_value_check mortgage_value_check savings_value_check deposit_value_check staircase_bought_value_check stairowned_value_check hodate_check shared_ownership_deposit_value_check extrabor_value_check grant_value_check discounted_sale_value_check deposit_and_mortgage_value_check multiple_partners_value_check partner_under_16_value_check]
end
end
end
end
describe "year_combo" do describe "year_combo" do
[ [
{ year: 2023, expected_value: "2023 to 2024" }, { year: 2023, expected_value: "2023 to 2024" },

11
spec/models/form/lettings/questions/hhmemb_spec.rb

@ -8,8 +8,9 @@ RSpec.describe Form::Lettings::Questions::Hhmemb, type: :model do
let(:question_definition) { nil } let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) } let(:page) { instance_double(Form::Page) }
let(:subsection) { instance_double(Form::Subsection) } let(:subsection) { instance_double(Form::Subsection) }
let(:start_year_2026_or_later?) { false } let(:start_year_2026_or_later?) { true }
let(:form) { instance_double(Form, start_date: current_collection_start_date, start_year_2026_or_later?: start_year_2026_or_later?) } let(:start_date) { current_collection_start_date }
let(:form) { instance_double(Form, start_date:, start_year_2026_or_later?: start_year_2026_or_later?) }
before do before do
allow(page).to receive(:subsection).and_return(subsection) allow(page).to receive(:subsection).and_return(subsection)
@ -37,6 +38,9 @@ RSpec.describe Form::Lettings::Questions::Hhmemb, type: :model do
end end
context "when in 2025", { year: 25 } do context "when in 2025", { year: 25 } do
let(:start_year_2026_or_later?) { false }
let(:start_date) { collection_start_date_for_year(2025) }
it "does not have check answers card title" do it "does not have check answers card title" do
expect(question.check_answers_card_title).to be_nil expect(question.check_answers_card_title).to be_nil
end end
@ -48,13 +52,14 @@ RSpec.describe Form::Lettings::Questions::Hhmemb, type: :model do
context "when in 2026", { year: 26 } do context "when in 2026", { year: 26 } do
let(:start_year_2026_or_later?) { true } let(:start_year_2026_or_later?) { true }
let(:start_date) { collection_start_date_for_year(2026) }
it "has correct check answers card title" do it "has correct check answers card title" do
expect(question.check_answers_card_title).to eq("Household") expect(question.check_answers_card_title).to eq("Household")
end end
it "has the correct question number" do it "has the correct question number" do
expect(question.question_number).to eq(30) expect(question.question_number).to eq(29)
end end
end end
end end

37
spec/models/lettings_log_derived_fields_spec.rb

@ -1068,9 +1068,20 @@ RSpec.describe LettingsLog, type: :model do
describe "variables dependent on whether a letting is a renewal" do describe "variables dependent on whether a letting is a renewal" do
let(:organisation) { create(:organisation) } let(:organisation) { create(:organisation) }
let(:user) { create(:user, organisation:) } let(:user) { create(:user, organisation:) }
let(:startdate) { Time.zone.today }
let(:persisted_renewal_lettings_log) { create(:lettings_log, :setup_completed, startdate:, renewal: 1, assigned_to: user) } let(:persisted_renewal_lettings_log) { create(:lettings_log, :setup_completed, startdate:, renewal: 1, assigned_to: user) }
before do
Timecop.travel(startdate)
Singleton.__init__(FormHandler)
end
after do
Timecop.return
end
context "when 2025", metadata: { year: 25 } do
let(:startdate) { collection_start_date_for_year(2025) }
it "derives waityear offered referral first_time_property_let_as_social_housing rsnvac when renewal" do it "derives waityear offered referral first_time_property_let_as_social_housing rsnvac when renewal" do
log.renewal = 1 log.renewal = 1
expect { log.set_derived_fields! } expect { log.set_derived_fields! }
@ -1089,6 +1100,30 @@ RSpec.describe LettingsLog, type: :model do
.and change(persisted_renewal_lettings_log, :first_time_property_let_as_social_housing).from(0).to(nil) .and change(persisted_renewal_lettings_log, :first_time_property_let_as_social_housing).from(0).to(nil)
.and change(persisted_renewal_lettings_log, :rsnvac).from(14).to(nil) .and change(persisted_renewal_lettings_log, :rsnvac).from(14).to(nil)
end end
end
context "when 2026 or later", metadata: { year: 26 } do
let(:startdate) { collection_start_date_for_year_or_later(2026) }
it "derives waityear offered referral first_time_property_let_as_social_housing rsnvac when renewal" do
log.renewal = 1
expect { log.set_derived_fields! }
.to change(log, :waityear).to(2)
.and change(log, :offered).to(0)
.and change(log, :referral_register).to(1)
.and change(log, :first_time_property_let_as_social_housing).to(0)
.and change(log, :rsnvac).to(14)
end
it "clears waityear offered referral first_time_property_let_as_social_housing rsnvac when not a renewal" do
expect { persisted_renewal_lettings_log.update!(renewal: 0) }
.to change(persisted_renewal_lettings_log, :waityear).from(2).to(nil)
.and change(persisted_renewal_lettings_log, :offered).from(0).to(nil)
.and change(persisted_renewal_lettings_log, :referral_register).from(1).to(nil)
.and change(persisted_renewal_lettings_log, :first_time_property_let_as_social_housing).from(0).to(nil)
.and change(persisted_renewal_lettings_log, :rsnvac).from(14).to(nil)
end
end
describe "deriving voiddate from startdate" do describe "deriving voiddate from startdate" do
let(:startdate) { Time.zone.now.beginning_of_day } let(:startdate) { Time.zone.now.beginning_of_day }

10
spec/models/organisation_name_change_spec.rb

@ -30,13 +30,13 @@ RSpec.describe OrganisationNameChange, type: :model do
it "is invalid if name is the same as the current name on the change date" do it "is invalid if name is the same as the current name on the change date" do
create(:organisation_name_change, organisation:, name: "New Name", startdate: 1.day.ago) create(:organisation_name_change, organisation:, name: "New Name", startdate: 1.day.ago)
name_change = build(:organisation_name_change, organisation:, name: "New Name", startdate: Time.zone.now) name_change = build(:organisation_name_change, organisation:, name: "New Name", startdate: Time.zone.today)
expect(name_change).not_to be_valid expect(name_change).not_to be_valid
expect(name_change.errors[:name]).to include(I18n.t("validations.organisation.name_changes.name.must_be_different")) expect(name_change.errors[:name]).to include(I18n.t("validations.organisation.name_changes.name.must_be_different"))
end end
it "is invalid if startdate is after the organisation's merge date" do it "is invalid if startdate is after the organisation's merge date" do
organisation.update!(merge_date: Time.zone.now) organisation.update!(merge_date: Time.zone.today)
name_change = build(:organisation_name_change, organisation:, immediate_change: false, startdate: Time.zone.tomorrow) name_change = build(:organisation_name_change, organisation:, immediate_change: false, startdate: Time.zone.tomorrow)
expect(name_change).not_to be_valid expect(name_change).not_to be_valid
expect(name_change.errors[:startdate]).to include(I18n.t("validations.organisation.name_changes.startdate.must_be_before_merge_date", merge_date: organisation.merge_date.to_formatted_s(:govuk_date))) expect(name_change.errors[:startdate]).to include(I18n.t("validations.organisation.name_changes.startdate.must_be_before_merge_date", merge_date: organisation.merge_date.to_formatted_s(:govuk_date)))
@ -54,12 +54,12 @@ RSpec.describe OrganisationNameChange, type: :model do
it "returns changes before a specific date" do it "returns changes before a specific date" do
name_change = create(:organisation_name_change, organisation:, startdate: 1.day.ago) name_change = create(:organisation_name_change, organisation:, startdate: 1.day.ago)
expect(described_class.before_date(Time.zone.now)).to include(name_change) expect(described_class.before_date(Time.zone.today)).to include(name_change)
end end
it "returns changes after a specific date" do it "returns changes after a specific date" do
name_change = create(:organisation_name_change, organisation:, startdate: 2.days.from_now) name_change = create(:organisation_name_change, organisation:, startdate: 2.days.from_now)
expect(described_class.after_date(Time.zone.now)).to include(name_change) expect(described_class.after_date(Time.zone.today)).to include(name_change)
end end
end end
@ -84,7 +84,7 @@ RSpec.describe OrganisationNameChange, type: :model do
describe "#includes_date?" do describe "#includes_date?" do
it "returns true if the date is within the change period" do it "returns true if the date is within the change period" do
name_change = create(:organisation_name_change, organisation:, startdate: 1.day.ago) name_change = create(:organisation_name_change, organisation:, startdate: 1.day.ago)
expect(name_change.includes_date?(Time.zone.now)).to be true expect(name_change.includes_date?(Time.zone.today)).to be true
end end
it "returns false if the date is outside the change period" do it "returns false if the date is outside the change period" do

60
spec/models/sales_log_spec.rb

@ -684,12 +684,13 @@ RSpec.describe SalesLog, type: :model do
end end
context "when deriving household variables" do context "when deriving household variables" do
let!(:sales_log) do let(:sales_log) do
create( create(
:sales_log, :sales_log,
:completed, :completed,
saledate:,
jointpur: 1, jointpur: 1,
hholdcount: 4, hholdcount:,
details_known_3: 1, details_known_3: 1,
details_known_4: 1, details_known_4: 1,
details_known_5: 1, details_known_5: 1,
@ -711,13 +712,26 @@ RSpec.describe SalesLog, type: :model do
) )
end end
it "correctly derives and saves hhmemb" do before do
Timecop.travel(saledate)
Singleton.__init__(FormHandler)
end
after do
Timecop.return
end
context "when 2025", metadata: { year: 25 } do
let(:saledate) { collection_start_date_for_year(2025) }
let(:hholdcount) { 4 }
it "correctly derives and saves hhmemb if it's a joint purchase" do
record_from_db = described_class.find(sales_log.id) record_from_db = described_class.find(sales_log.id)
expect(record_from_db["hhmemb"]).to eq(6) expect(record_from_db["hhmemb"]).to eq(6)
end end
it "correctly derives and saves hhmemb if it's a joint purchase" do it "correctly derives and saves hhmemb if it's not a joint purchase" do
sales_log.update!(jointpur: 2, jointmore: 2) sales_log.update!(jointpur: 2)
record_from_db = described_class.find(sales_log.id) record_from_db = described_class.find(sales_log.id)
expect(record_from_db["hhmemb"]).to eq(5) expect(record_from_db["hhmemb"]).to eq(5)
end end
@ -738,6 +752,38 @@ RSpec.describe SalesLog, type: :model do
end end
end end
context "when 2026 or later", metadata: { year: 26 } do
let(:saledate) { collection_start_date_for_year_or_later(2026) }
let(:hholdcount) { 6 }
it "correctly derives and saves hhmemb if it's a joint purchase" do
record_from_db = described_class.find(sales_log.id)
expect(record_from_db["hhmemb"]).to eq(6)
end
it "correctly derives and saves hhmemb if it's not a joint purchase" do
sales_log.update!(jointpur: 2)
record_from_db = described_class.find(sales_log.id)
expect(record_from_db["hhmemb"]).to eq(6)
end
it "correctly derives and saves totchild" do
record_from_db = described_class.find(sales_log.id)
expect(record_from_db["totchild"]).to eq(2)
end
it "correctly derives and saves totadult" do
record_from_db = described_class.find(sales_log.id)
expect(record_from_db["totadult"]).to eq(4)
end
it "correctly derives and saves hhtype" do
record_from_db = described_class.find(sales_log.id)
expect(record_from_db["hhtype"]).to eq(9)
end
end
end
context "when saving previous address" do context "when saving previous address" do
def check_previous_postcode_fields(postcode_field) def check_previous_postcode_fields(postcode_field)
record_from_db = described_class.find(address_sales_log.id) record_from_db = described_class.find(address_sales_log.id)
@ -806,10 +852,10 @@ RSpec.describe SalesLog, type: :model do
end end
describe "expected_shared_ownership_deposit_value" do describe "expected_shared_ownership_deposit_value" do
let!(:completed_sales_log) { create(:sales_log, :completed, ownershipsch: 1, type: 2, value: 1000, equity: 50, staircase: 1) } let(:completed_sales_log) { create(:sales_log, :completed, ownershipsch: 1, type: 2, value: 15_000, equity: 50, staircase: 1) }
it "is set to completed for a completed sales log" do it "is set to completed for a completed sales log" do
expect(completed_sales_log.expected_shared_ownership_deposit_value).to eq(500) expect(completed_sales_log.expected_shared_ownership_deposit_value).to eq(7500)
end end
end end

15
spec/models/validations/household_validations_spec.rb

@ -6,7 +6,7 @@ RSpec.describe Validations::HouseholdValidations do
subject(:household_validator) { validator_class.new } subject(:household_validator) { validator_class.new }
let(:validator_class) { Class.new { include Validations::HouseholdValidations } } let(:validator_class) { Class.new { include Validations::HouseholdValidations } }
let(:startdate) { Time.zone.now } let(:startdate) { current_collection_start_date }
let(:record) { FactoryBot.build(:lettings_log, :setup_completed, startdate:, assigned_to: create(:user)) } let(:record) { FactoryBot.build(:lettings_log, :setup_completed, startdate:, assigned_to: create(:user)) }
describe "reasonable preference validations" do describe "reasonable preference validations" do
@ -117,6 +117,10 @@ RSpec.describe Validations::HouseholdValidations do
end end
end end
context "when 2025", metadata: { year: 25 } do
# post 2025 we don't ask referral and referral_type anymore
let(:startdate) { collection_start_date_for_year(2025) }
context "when referral is not internal transfer" do context "when referral is not internal transfer" do
it "can be permanently decanted from another property owned by this landlord" do it "can be permanently decanted from another property owned by this landlord" do
record.reason = 1 record.reason = 1
@ -166,6 +170,7 @@ RSpec.describe Validations::HouseholdValidations do
end end
end end
end end
end
describe "armed forces validations" do describe "armed forces validations" do
context "when the tenant or partner was and is not a member of the armed forces" do context "when the tenant or partner was and is not a member of the armed forces" do
@ -445,6 +450,9 @@ RSpec.describe Validations::HouseholdValidations do
end end
describe "referral validations" do describe "referral validations" do
context "when start year is 2025", metadata: { year: 25 } do
let(:startdate) { collection_start_date_for_year(2025) }
context "when homelessness is assessed" do context "when homelessness is assessed" do
it "can be internal transfer" do it "can be internal transfer" do
record.homeless = 11 record.homeless = 11
@ -490,9 +498,10 @@ RSpec.describe Validations::HouseholdValidations do
expect(record.errors["homeless"]).to be_empty expect(record.errors["homeless"]).to be_empty
end end
end end
end
context "when start year is 2026" do context "when start year is 2026 or later", metadata: { year: 26 } do
let(:startdate) { collection_start_date_for_year(2026) } let(:startdate) { collection_start_date_for_year_or_later(2026) }
[ [
{ {

61
spec/models/validations/property_validations_spec.rb

@ -1,6 +1,8 @@
require "rails_helper" require "rails_helper"
RSpec.describe Validations::PropertyValidations do RSpec.describe Validations::PropertyValidations do
include CollectionTimeHelper
subject(:property_validator) { property_validator_class.new } subject(:property_validator) { property_validator_class.new }
let(:property_validator_class) { Class.new { include Validations::PropertyValidations } } let(:property_validator_class) { Class.new { include Validations::PropertyValidations } }
@ -316,9 +318,12 @@ RSpec.describe Validations::PropertyValidations do
end end
end end
context "when 2025", metadata: { year: 25 } do
let(:startdate) { collection_start_date_for_year(2025) }
context "and the local authority is active for supported housing log" do context "and the local authority is active for supported housing log" do
let(:location) { create(:location, location_code: la_ecode_active) } let(:location) { create(:location, location_code: la_ecode_active) }
let(:log) { build(:lettings_log, :completed, needstype: 2, location:) } let(:log) { build(:lettings_log, :completed, startdate:, needstype: 2, location:) }
it "does not add an error" do it "does not add an error" do
property_validator.validate_la_is_active(log) property_validator.validate_la_is_active(log)
@ -334,7 +339,7 @@ RSpec.describe Validations::PropertyValidations do
context "and the local authority is inactive for supported housing log" do context "and the local authority is inactive for supported housing log" do
let(:location) { create(:location, location_code: la_ecode_inactive) } let(:location) { create(:location, location_code: la_ecode_inactive) }
let(:log) { build(:lettings_log, :completed, needstype: 2, location:) } let(:log) { build(:lettings_log, :completed, startdate:, needstype: 2, location:) }
context "and the inactive local authority is not linked to an active one" do context "and the inactive local authority is not linked to an active one" do
it "adds an error" do it "adds an error" do
@ -365,6 +370,58 @@ RSpec.describe Validations::PropertyValidations do
end end
end end
context "when 2026 or later", metadata: { year: 26 } do
let(:startdate) { collection_start_date_for_year_or_later(2026) }
context "and the local authority is active for supported housing log" do
let(:log) { build(:lettings_log, :completed, startdate:, la: la_ecode_active, needstype: 2) }
it "does not add an error" do
property_validator.validate_la_is_active(log)
expect(log.errors["scheme_id"]).to be_empty
expect(log.errors["location_id"]).to be_empty
expect(log.errors["startdate"]).to be_empty
expect(log.errors["la"]).to be_empty
expect(log.errors["postcode_full"]).to be_empty
expect(log.errors["uprn"]).to be_empty
expect(log.errors["uprn_selection"]).to be_empty
end
end
context "and the local authority is inactive for supported housing log" do
let(:log) { build(:lettings_log, :completed, startdate:, la: la_ecode_inactive, needstype: 2) }
context "and the inactive local authority is not linked to an active one" do
it "adds an error" do
property_validator.validate_la_is_active(log)
expect(log.errors["scheme_id"]).to include(I18n.t("validations.lettings.property.scheme_id.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["location_id"]).to include(I18n.t("validations.lettings.property.location_id.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["startdate"]).to include(I18n.t("validations.lettings.property.startdate.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["la"]).to include(I18n.t("validations.lettings.property.la.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["postcode_full"]).to include(I18n.t("validations.lettings.property.postcode_full.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["uprn"]).to include(I18n.t("validations.lettings.property.uprn.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["uprn_selection"]).to include(I18n.t("validations.lettings.property.uprn_selection.la_not_valid_for_date", la: local_authority_inactive.name))
end
end
context "and the inactive local authority is linked to an active one" do
# the link code was only ever used if the LA was drawn from the location
it "adds an error" do
LocalAuthorityLink.create!(local_authority: local_authority_inactive, linked_local_authority: local_authority_active)
property_validator.validate_la_is_active(log)
expect(log.errors["scheme_id"]).to include(I18n.t("validations.lettings.property.scheme_id.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["location_id"]).to include(I18n.t("validations.lettings.property.location_id.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["startdate"]).to include(I18n.t("validations.lettings.property.startdate.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["la"]).to include(I18n.t("validations.lettings.property.la.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["postcode_full"]).to include(I18n.t("validations.lettings.property.postcode_full.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["uprn"]).to include(I18n.t("validations.lettings.property.uprn.la_not_valid_for_date", la: local_authority_inactive.name))
expect(log.errors["uprn_selection"]).to include(I18n.t("validations.lettings.property.uprn_selection.la_not_valid_for_date", la: local_authority_inactive.name))
end
end
end
end
end
context "with a log before 2025" do context "with a log before 2025" do
before do before do
allow(log.form).to receive(:start_year_2025_or_later?).and_return false allow(log.form).to receive(:start_year_2025_or_later?).and_return false

152
spec/models/validations/sales/sale_information_validations_spec.rb

@ -6,6 +6,7 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
subject(:sale_information_validator) { validator_class.new } subject(:sale_information_validator) { validator_class.new }
let(:validator_class) { Class.new { include Validations::Sales::SaleInformationValidations } } let(:validator_class) { Class.new { include Validations::Sales::SaleInformationValidations } }
let(:saledate) { current_collection_start_date }
describe "#validate_practical_completion_date" do describe "#validate_practical_completion_date" do
context "when hodate blank" do context "when hodate blank" do
@ -59,8 +60,10 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
end end
context "when hodate 3 or more years before saledate" do context "when hodate 3 or more years before saledate" do
let(:record) { build(:sales_log, hodate: saledate - 3.years, saledate:) }
context "and form year is 2024 or earlier" do context "and form year is 2024 or earlier" do
let(:record) { build(:sales_log, hodate: previous_collection_start_date - 3.years, saledate: previous_collection_start_date) } let(:saledate) { collection_start_date_for_year(2024) }
it "does add an error" do it "does add an error" do
sale_information_validator.validate_practical_completion_date(record) sale_information_validator.validate_practical_completion_date(record)
@ -71,7 +74,7 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
end end
context "and form year is 2025 or later" do context "and form year is 2025 or later" do
let(:record) { build(:sales_log, hodate: current_collection_start_date - 3.years, saledate: current_collection_start_date) } let(:saledate) { collection_start_date_for_year_or_later(2025) }
it "does not add an error" do it "does not add an error" do
sale_information_validator.validate_practical_completion_date(record) sale_information_validator.validate_practical_completion_date(record)
@ -376,10 +379,8 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
end end
describe "#validate_discounted_ownership_value" do describe "#validate_discounted_ownership_value" do
let(:record) { FactoryBot.build(:sales_log, :saledate_today, mortgage: 10_000, deposit: 5_000, value: 30_000, ownershipsch: 2, type: 8) }
context "when grant is routed to" do context "when grant is routed to" do
let(:record) { FactoryBot.build(:sales_log, :saledate_today, deposit: nil, ownershipsch: 2, type: 8) } let(:record) { FactoryBot.build(:sales_log, saledate:, deposit: nil, ownershipsch: 2, type: 8) }
context "and not provided" do context "and not provided" do
before do before do
@ -453,7 +454,7 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
end end
context "when discount is routed to" do context "when discount is routed to" do
let(:record) { FactoryBot.build(:sales_log, :saledate_today, grant: nil, ownershipsch: 2, type: 9) } let(:record) { FactoryBot.build(:sales_log, saledate:, grant: nil, ownershipsch: 2, type: 9) }
context "and not provided" do context "and not provided" do
it "returns false" do it "returns false" do
@ -475,6 +476,9 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
end end
context "and is provided" do context "and is provided" do
context "and is 2025" do
let(:saledate) { collection_start_date_for_year(2025) }
it "does not add errors if mortgage and deposit total equals market value - discount" do it "does not add errors if mortgage and deposit total equals market value - discount" do
record.value = 30_000 record.value = 30_000
record.mortgage = 10_000 record.mortgage = 10_000
@ -542,6 +546,90 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
expect(record.errors["discount"]).to be_empty expect(record.errors["discount"]).to be_empty
expect(record.errors["grant"]).to be_empty expect(record.errors["grant"]).to be_empty
end end
it "does not add errors if mortgageused is don't know" do
record.mortgageused = 3
record.value = 30_000
record.deposit = 5_000
record.discount = 50
expect(record.errors["mortgageused"]).to be_empty
expect(record.errors["mortgage"]).to be_empty
expect(record.errors["value"]).to be_empty
expect(record.errors["deposit"]).to be_empty
expect(record.errors["ownershipsch"]).to be_empty
expect(record.errors["discount"]).to be_empty
expect(record.errors["grant"]).to be_empty
end
end
context "and is 2026" do
let(:saledate) { collection_start_date_for_year(2026) }
it "does not add errors if mortgage and deposit total equals market value - discount" do
record.value = 30_000
record.mortgage = 10_000
record.deposit = 5_000
record.discount = 50
sale_information_validator.validate_discounted_ownership_value(record)
expect(record.errors["mortgageused"]).to be_empty
expect(record.errors["mortgage"]).to be_empty
expect(record.errors["value"]).to be_empty
expect(record.errors["deposit"]).to be_empty
expect(record.errors["ownershipsch"]).to be_empty
expect(record.errors["discount"]).to be_empty
expect(record.errors["grant"]).to be_empty
end
it "does not add errors if mortgage and deposit total is within a 0.1% tolerance" do
record.value = 30_000
record.mortgage = 10_000
record.deposit = 5_000
record.discount = 50.1
sale_information_validator.validate_discounted_ownership_value(record)
expect(record.errors["mortgageused"]).to be_empty
expect(record.errors["mortgage"]).to be_empty
expect(record.errors["value"]).to be_empty
expect(record.errors["deposit"]).to be_empty
expect(record.errors["ownershipsch"]).to be_empty
expect(record.errors["discount"]).to be_empty
expect(record.errors["grant"]).to be_empty
end
it "adds errors if mortgage and deposit total is not within a 0.1% tolerance" do
record.value = 123_000
record.mortgage = 66_113
record.deposit = 0
record.discount = 50.2
sale_information_validator.validate_discounted_ownership_value(record)
expect(record.errors["mortgageused"]).to include("The mortgage (£66,113.00) and cash deposit (£0.00) added together is £66,113.00.</br></br>The full purchase price (£123,000.00) subtracted by the sum of the full purchase price (£123,000.00) multiplied by the percentage discount (50.2%) is £61,254.00.</br></br>These two amounts should be the same.")
expect(record.errors["mortgage"]).to include("The mortgage (£66,113.00) and cash deposit (£0.00) added together is £66,113.00.</br></br>The full purchase price (£123,000.00) subtracted by the sum of the full purchase price (£123,000.00) multiplied by the percentage discount (50.2%) is £61,254.00.</br></br>These two amounts should be the same.")
expect(record.errors["value"]).to include("The mortgage (£66,113.00) and cash deposit (£0.00) added together is £66,113.00.</br></br>The full purchase price (£123,000.00) subtracted by the sum of the full purchase price (£123,000.00) multiplied by the percentage discount (50.2%) is £61,254.00.</br></br>These two amounts should be the same.")
expect(record.errors["deposit"]).to include("The mortgage (£66,113.00) and cash deposit (£0.00) added together is £66,113.00.</br></br>The full purchase price (£123,000.00) subtracted by the sum of the full purchase price (£123,000.00) multiplied by the percentage discount (50.2%) is £61,254.00.</br></br>These two amounts should be the same.")
expect(record.errors["ownershipsch"]).to include("The mortgage (£66,113.00) and cash deposit (£0.00) added together is £66,113.00.</br></br>The full purchase price (£123,000.00) subtracted by the sum of the full purchase price (£123,000.00) multiplied by the percentage discount (50.2%) is £61,254.00.</br></br>These two amounts should be the same.")
expect(record.errors["discount"]).to include("The mortgage (£66,113.00) and cash deposit (£0.00) added together is £66,113.00.</br></br>The full purchase price (£123,000.00) subtracted by the sum of the full purchase price (£123,000.00) multiplied by the percentage discount (50.2%) is £61,254.00.</br></br>These two amounts should be the same.")
expect(record.errors["grant"]).to include("The mortgage (£66,113.00) and cash deposit (£0.00) added together is £66,113.00.</br></br>The full purchase price (£123,000.00) subtracted by the sum of the full purchase price (£123,000.00) multiplied by the percentage discount (50.2%) is £61,254.00.</br></br>These two amounts should be the same.")
end
it "does not add errors if mortgageused is don't know" do
record.mortgageused = 3
record.value = 30_000
record.deposit = 5_000
record.discount = 50
expect(record.errors["mortgageused"]).to be_empty
expect(record.errors["mortgage"]).to be_empty
expect(record.errors["value"]).to be_empty
expect(record.errors["deposit"]).to be_empty
expect(record.errors["ownershipsch"]).to be_empty
expect(record.errors["discount"]).to be_empty
expect(record.errors["grant"]).to be_empty
end
end
end end
end end
@ -663,58 +751,6 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
expect(record.errors["grant"]).to be_empty expect(record.errors["grant"]).to be_empty
end end
end end
context "with year 2026", :aggregate_failures do
let(:saledate) { Time.zone.local(2026, 4, 1) }
context "when mortgage and deposit is exact" do
let(:record) { FactoryBot.build(:sales_log, saledate:, mortgage: 85_000, deposit: 5_000, value: 100_000, discount: 10, ownershipsch: 2, type: 9) }
it "does not add an error" do
sale_information_validator.validate_discounted_ownership_value(record)
expect(record.errors["mortgage"]).to be_empty
expect(record.errors["value"]).to be_empty
expect(record.errors["deposit"]).to be_empty
expect(record.errors["discount"]).to be_empty
end
end
context "when mortgage and deposit is within 0.1% discount tolerance" do
let(:record) { FactoryBot.build(:sales_log, saledate:, mortgage: 85_000, deposit: 5_000, value: 100_000, discount: 10.1, ownershipsch: 2, type: 9) }
it "does not add an error" do
sale_information_validator.validate_discounted_ownership_value(record)
expect(record.errors["mortgage"]).to be_empty
expect(record.errors["value"]).to be_empty
expect(record.errors["deposit"]).to be_empty
expect(record.errors["discount"]).to be_empty
end
end
context "when mortgage and deposit is outside 0.1% discount tolerance" do
let(:record) { FactoryBot.build(:sales_log, saledate:, mortgage: 85_000, deposit: 5_000, value: 100_000, discount: 10.2, ownershipsch: 2, type: 9) }
it "adds an error" do
sale_information_validator.validate_discounted_ownership_value(record)
expect(record.errors["mortgage"]).not_to be_empty
expect(record.errors["value"]).not_to be_empty
expect(record.errors["deposit"]).not_to be_empty
expect(record.errors["discount"]).not_to be_empty
end
end
end
context "when mortgageused is don't know" do
let(:record) { FactoryBot.build(:sales_log, :saledate_today, mortgageused: 3, deposit: 10_000, value: 100_000, discount: 10, ownershipsch: 2, type: 9) }
it "does not add an error" do
sale_information_validator.validate_discounted_ownership_value(record)
expect(record.errors["mortgage"]).to be_empty
expect(record.errors["value"]).to be_empty
expect(record.errors["deposit"]).to be_empty
expect(record.errors["discount"]).to be_empty
end
end
end end
describe "#validate_outright_sale_value_matches_mortgage_plus_deposit" do describe "#validate_outright_sale_value_matches_mortgage_plus_deposit" do

21
spec/models/validations/sales/soft_validations_spec.rb

@ -3,7 +3,8 @@ require "rails_helper"
RSpec.describe Validations::Sales::SoftValidations do RSpec.describe Validations::Sales::SoftValidations do
include CollectionTimeHelper include CollectionTimeHelper
let(:record) { build(:sales_log) } let(:saledate) { current_collection_start_date }
let(:record) { build(:sales_log, saledate:) }
describe "income validations" do describe "income validations" do
context "when validating soft range based on ecstat" do context "when validating soft range based on ecstat" do
@ -396,6 +397,9 @@ RSpec.describe Validations::Sales::SoftValidations do
expect(record).not_to be_mortgage_plus_deposit_less_than_discounted_value expect(record).not_to be_mortgage_plus_deposit_less_than_discounted_value
end end
context "and 2025", metadata: { year: 25 } do
let(:saledate) { collection_start_date_for_year(2025) }
it "returns true if the deposit and mortgage add up to less than the discounted value" do it "returns true if the deposit and mortgage add up to less than the discounted value" do
record.value = 500_000 record.value = 500_000
record.discount = 10 record.discount = 10
@ -405,8 +409,21 @@ RSpec.describe Validations::Sales::SoftValidations do
end end
end end
context "and 2026 or later", metadata: { year: 26 } do
let(:saledate) { collection_start_date_for_year_or_later(2026) }
it "returns false if the deposit and mortgage add up to less than the discounted value" do
record.value = 500_000
record.discount = 10
record.mortgage = 200_000
record.deposit = 200_000
expect(record).not_to be_mortgage_plus_deposit_less_than_discounted_value
end
end
end
context "when validating extra borrowing" do context "when validating extra borrowing" do
let(:record) { build(:sales_log, saledate: previous_collection_start_date) } let(:saledate) { collection_start_date_for_year_or_later(2024) }
it "returns false for logs from 2024 onwards" do it "returns false for logs from 2024 onwards" do
record.extrabor = 2 record.extrabor = 2

18
spec/requests/collection_resources_controller_spec.rb

@ -49,12 +49,16 @@ RSpec.describe CollectionResourcesController, type: :request do
let(:user) { create(:user, :support) } let(:user) { create(:user, :support) }
before do before do
allow(Time.zone).to receive(:today).and_return(Time.zone.local(2025, 1, 8)) Timecop.travel(Time.zone.local(current_collection_start_year, 1, 8))
allow(user).to receive(:need_two_factor_authentication?).and_return(false) allow(user).to receive(:need_two_factor_authentication?).and_return(false)
allow(storage_service).to receive(:file_exists?).and_return(true) allow(storage_service).to receive(:file_exists?).and_return(true)
sign_in user sign_in user
end end
after do
Timecop.return
end
it "displays collection resources" do it "displays collection resources" do
get collection_resources_path get collection_resources_path
@ -122,7 +126,7 @@ RSpec.describe CollectionResourcesController, type: :request do
context "when the collection year has not started yet" do context "when the collection year has not started yet" do
before do before do
Timecop.freeze(Time.zone.local(2025, 3, 1)) Timecop.travel(Time.zone.local(current_collection_start_year, 3, 1))
get collection_resources_path get collection_resources_path
end end
@ -131,8 +135,8 @@ RSpec.describe CollectionResourcesController, type: :request do
end end
it "displays next year banner" do it "displays next year banner" do
expect(page).to have_content("The 2025 to 2026 collection resources are not yet available to users.") expect(page).to have_content("The #{next_collection_start_year} to #{next_collection_end_year} collection resources are not yet available to users.")
expect(page).to have_link("Release the 2025 to 2026 collection resources to users", href: confirm_mandatory_collection_resources_release_path(year: 2025)) expect(page).to have_link("Release the #{next_collection_start_year} to #{next_collection_end_year} collection resources to users", href: confirm_mandatory_collection_resources_release_path(year: next_collection_start_year))
end end
end end
@ -176,7 +180,7 @@ RSpec.describe CollectionResourcesController, type: :request do
context "when the collection year has not started yet" do context "when the collection year has not started yet" do
before do before do
Timecop.freeze(Time.zone.local(2025, 3, 1)) Timecop.travel(Time.zone.local(current_collection_start_year, 3, 1))
get collection_resources_path get collection_resources_path
end end
@ -185,8 +189,8 @@ RSpec.describe CollectionResourcesController, type: :request do
end end
it "displays next year banner" do it "displays next year banner" do
expect(page).to have_content("The 2025 to 2026 collection resources are not yet available to users.") expect(page).to have_content("The #{next_collection_start_year} to #{next_collection_end_year} collection resources are not yet available to users.")
expect(page).to have_content("Once you have uploaded all the required 2025 to 2026 collection resources, you will be able to release them to users.") expect(page).to have_content("Once you have uploaded all the required #{next_collection_start_year} to #{next_collection_end_year} collection resources, you will be able to release them to users.")
end end
end end
end end

471
spec/requests/duplicate_logs_controller_spec.rb

@ -1,11 +1,22 @@
require "rails_helper" require "rails_helper"
RSpec.describe DuplicateLogsController, type: :request do RSpec.describe DuplicateLogsController, type: :request do
include CollectionTimeHelper
let(:page) { Capybara::Node::Simple.new(response.body) } let(:page) { Capybara::Node::Simple.new(response.body) }
let(:user) { create(:user, :data_coordinator) } let(:user) { create(:user, :data_coordinator) }
let(:lettings_log) { create(:lettings_log, :duplicate, assigned_to: user) } let(:lettings_log) { create(:lettings_log, :duplicate, assigned_to: user) }
let(:sales_log) { create(:sales_log, :duplicate, staircase: 2, assigned_to: user) } let(:sales_log) { create(:sales_log, :duplicate, staircase: 2, assigned_to: user) }
context "when 2025", metadata: { year: 25 } do
before do
Timecop.travel(collection_start_date_for_year(2025))
end
after do
Timecop.return
end
describe "GET show" do describe "GET show" do
context "when user is not signed in" do context "when user is not signed in" do
it "redirects to sign in page" do it "redirects to sign in page" do
@ -454,6 +465,466 @@ RSpec.describe DuplicateLogsController, type: :request do
end end
end end
end end
end
context "when 2026 or later", metadata: { year: 26 } do
before do
Timecop.travel(collection_start_date_for_year_or_later(2026))
end
after do
Timecop.return
end
describe "GET show" do
context "when user is not signed in" do
it "redirects to sign in page" do
get "/lettings-logs/#{lettings_log.id}/duplicate-logs"
expect(response).to redirect_to("/account/sign-in")
end
end
context "when the user is from different organisation" do
let(:other_user) { create(:user) }
before do
allow(other_user).to receive(:need_two_factor_authentication?).and_return(false)
sign_in other_user
end
it "renders page not found" do
get "/lettings-logs/#{lettings_log.id}/duplicate-logs"
expect(response).to have_http_status(:not_found)
end
end
context "when user is signed in" do
context "when user is support" do
let(:support_user_org) { create(:organisation) }
let(:user) { create(:user, :support, organisation: support_user_org) }
before do
allow(user).to receive(:need_two_factor_authentication?).and_return(false)
sign_in user
end
context "when viewing lettings logs duplicates" do
context "when there are multiple duplicate logs" do
let(:duplicate_logs) { create_list(:lettings_log, 2, :completed) }
before do
allow(LettingsLog).to receive(:duplicate_logs).and_return(duplicate_logs)
get "/lettings-logs/#{lettings_log.id}/duplicate-logs?original_log_id=#{lettings_log.id}&organisation_id=#{lettings_log.owning_organisation_id}"
end
it "displays links to all the duplicate logs" do
expect(page).to have_link("Log #{lettings_log.id}", href: "/lettings-logs/#{lettings_log.id}")
expect(page).to have_link("Log #{duplicate_logs.first.id}", href: "/lettings-logs/#{duplicate_logs.first.id}")
expect(page).to have_link("Log #{duplicate_logs.second.id}", href: "/lettings-logs/#{duplicate_logs.second.id}")
end
it "displays check your answers for each log with correct questions" do
expect(page).to have_content("- Tenancy start date", count: 3)
expect(page).to have_content("- Tenant code", count: 3)
expect(page).to have_content("- Lead tenant’s age", count: 3)
expect(page).to have_content("- Lead tenant’s sex registered at birth", count: 3)
expect(page).to have_content("- Lead tenant’s working situation", count: 3)
expect(page).to have_content("Household rent and charges", count: 3)
expect(page).to have_link("Change", count: 27)
expect(page).to have_link("Change", href: "/lettings-logs/#{lettings_log.id}/tenant-code?first_remaining_duplicate_id=#{duplicate_logs[0].id}&organisation_id=#{lettings_log.owning_organisation_id}&original_log_id=#{lettings_log.id}&referrer=duplicate_logs")
expect(page).to have_link("Change", href: "/lettings-logs/#{duplicate_logs[0].id}/tenant-code?first_remaining_duplicate_id=#{lettings_log.id}&organisation_id=#{lettings_log.owning_organisation_id}&original_log_id=#{lettings_log.id}&referrer=duplicate_logs")
expect(page).to have_link("Change", href: "/lettings-logs/#{duplicate_logs[1].id}/tenant-code?first_remaining_duplicate_id=#{lettings_log.id}&organisation_id=#{lettings_log.owning_organisation_id}&original_log_id=#{lettings_log.id}&referrer=duplicate_logs")
end
it "displays check your answers for each log with correct questions where UPRN is given" do
lettings_log.update!(uprn: "123", uprn_known: 1, uprn_confirmed: 1, manual_address_entry_selected: false)
duplicate_logs[0].update!(uprn: "123", uprn_known: 1, uprn_confirmed: 1, manual_address_entry_selected: false)
get "/lettings-logs/#{lettings_log.id}/duplicate-logs?original_log_id=#{lettings_log.id}"
expect(page).to have_content("- Tenancy start date", count: 3)
expect(page).to have_content("- Tenant code", count: 3)
expect(page).to have_content("- Address", count: 3)
expect(page).to have_content("- Lead tenant’s age", count: 3)
expect(page).to have_content("- Lead tenant’s sex registered at birth", count: 3)
expect(page).to have_content("- Lead tenant’s working situation", count: 3)
expect(page).to have_content("Household rent and charges", count: 3)
expect(page).to have_link("Change", count: 25)
expect(page).to have_link("Change", href: "/lettings-logs/#{lettings_log.id}/tenant-code?first_remaining_duplicate_id=#{duplicate_logs[0].id}&original_log_id=#{lettings_log.id}&referrer=duplicate_logs")
expect(page).to have_link("Change", href: "/lettings-logs/#{duplicate_logs[0].id}/tenant-code?first_remaining_duplicate_id=#{lettings_log.id}&original_log_id=#{lettings_log.id}&referrer=duplicate_logs")
expect(page).to have_link("Change", href: "/lettings-logs/#{duplicate_logs[1].id}/tenant-code?first_remaining_duplicate_id=#{lettings_log.id}&original_log_id=#{lettings_log.id}&referrer=duplicate_logs")
end
it "displays buttons to delete" do
expect(page).to have_link("Keep this log and delete duplicates", count: 3)
expect(page).to have_link("Keep this log and delete duplicates", href: "/lettings-logs/#{lettings_log.id}/delete-duplicates?organisation_id=#{lettings_log.owning_organisation_id}&original_log_id=#{lettings_log.id}")
expect(page).to have_link("Keep this log and delete duplicates", href: "/lettings-logs/#{duplicate_logs.first.id}/delete-duplicates?organisation_id=#{lettings_log.owning_organisation_id}&original_log_id=#{lettings_log.id}")
expect(page).to have_link("Keep this log and delete duplicates", href: "/lettings-logs/#{duplicate_logs.second.id}/delete-duplicates?organisation_id=#{lettings_log.owning_organisation_id}&original_log_id=#{lettings_log.id}")
end
end
context "when there are no more duplicate logs" do
context "when accessed from the duplicate logs banner flow" do
before do
allow(LettingsLog).to receive(:duplicate_logs).and_return(LettingsLog.none)
get "/lettings-logs/#{lettings_log.id}/duplicate-logs?original_log_id=#{lettings_log.id}&organisation_id=#{lettings_log.owning_organisation_id}&referrer=duplicate_logs_banner"
end
it "displays check your answers for each log with correct questions" do
expect(page).to have_content("- Tenancy start date", count: 1)
expect(page).to have_content("- Tenant code", count: 1)
expect(page).to have_content("- Lead tenant’s age", count: 1)
expect(page).to have_content("- Lead tenant’s sex registered at birth", count: 1)
expect(page).to have_content("- Lead tenant’s working situation", count: 1)
expect(page).to have_content("Household rent and charges", count: 1)
expect(page).to have_link("Change", count: 9)
expect(page).to have_link("Change", href: "/lettings-logs/#{lettings_log.id}/tenant-code?original_log_id=#{lettings_log.id}&referrer=interruption_screen")
end
it "displays button to review other duplicates" do
expect(page).to have_link("Review other duplicates", href: "/organisations/#{lettings_log.owning_organisation_id}/duplicates?referrer=duplicate_logs_banner")
end
it "displays no duplicates banner" do
expect(page).to have_content("This log had the same answers but it is no longer a duplicate. Make sure the answers are correct.")
end
end
context "when accessed from the single log submission flow" do
before do
allow(LettingsLog).to receive(:duplicate_logs).and_return(LettingsLog.none)
get "/lettings-logs/#{lettings_log.id}/duplicate-logs?original_log_id=#{lettings_log.id}&organisation_id=#{lettings_log.owning_organisation_id}"
end
it "displays check your answers for each log with correct questions" do
expect(page).to have_content("- Tenancy start date", count: 1)
expect(page).to have_content("- Tenant code", count: 1)
expect(page).to have_content("- Lead tenant’s age", count: 1)
expect(page).to have_content("- Lead tenant’s sex registered at birth", count: 1)
expect(page).to have_content("- Lead tenant’s working situation", count: 1)
expect(page).to have_content("Household rent and charges", count: 1)
expect(page).to have_link("Change", count: 9)
expect(page).to have_link("Change", href: "/lettings-logs/#{lettings_log.id}/tenant-code?original_log_id=#{lettings_log.id}&referrer=interruption_screen")
end
it "displays button to return to log" do
expect(page).to have_link("Back to Log #{lettings_log.id}", href: "/lettings-logs/#{lettings_log.id}")
end
it "displays no duplicates banner" do
expect(page).to have_content("This log had the same answers but it is no longer a duplicate. Make sure the answers are correct.")
end
end
end
end
context "when viewing sales logs duplicates" do
context "when there are multiple duplicate logs" do
let(:duplicate_logs) { create_list(:sales_log, 2, :completed) }
before do
allow(SalesLog).to receive(:duplicate_logs).and_return(duplicate_logs)
get "/sales-logs/#{sales_log.id}/duplicate-logs?original_log_id=#{sales_log.id}&organisation_id=#{sales_log.owning_organisation_id}"
end
it "displays links to all the duplicate logs" do
expect(page).to have_link("Log #{sales_log.id}", href: "/sales-logs/#{sales_log.id}")
expect(page).to have_link("Log #{duplicate_logs.first.id}", href: "/sales-logs/#{duplicate_logs.first.id}")
expect(page).to have_link("Log #{duplicate_logs.second.id}", href: "/sales-logs/#{duplicate_logs.second.id}")
end
it "displays check your answers for each log with correct questions" do
expect(page).to have_content("- Owning organisation", count: 3)
expect(page).to have_content("- Sale completion date", count: 3)
expect(page).to have_content("- Purchaser code", count: 3)
expect(page).to have_content("- Buyer 1’s age", count: 3)
expect(page).to have_content("- Buyer 1’s sex registered at birth", count: 3)
expect(page).to have_content("- Buyer 1’s working situation", count: 3)
expect(page).to have_content("- Postcode", count: 3)
expect(page).to have_content("- Address line 1", count: 3)
expect(page).to have_link("Change", count: 24)
expect(page).to have_link("Change", href: "/sales-logs/#{sales_log.id}/purchaser-code?first_remaining_duplicate_id=#{duplicate_logs[0].id}&organisation_id=#{sales_log.owning_organisation_id}&original_log_id=#{sales_log.id}&referrer=duplicate_logs")
expect(page).to have_link("Change", href: "/sales-logs/#{duplicate_logs[0].id}/purchaser-code?first_remaining_duplicate_id=#{sales_log.id}&organisation_id=#{sales_log.owning_organisation_id}&original_log_id=#{sales_log.id}&referrer=duplicate_logs")
expect(page).to have_link("Change", href: "/sales-logs/#{duplicate_logs[1].id}/purchaser-code?first_remaining_duplicate_id=#{sales_log.id}&organisation_id=#{sales_log.owning_organisation_id}&original_log_id=#{sales_log.id}&referrer=duplicate_logs")
end
it "displays check your answers for each log with correct questions when UPRN is given" do
sales_log.update!(uprn: "123", uprn_known: 1, manual_address_entry_selected: false)
duplicate_logs[0].update!(uprn: "123", uprn_known: 1, manual_address_entry_selected: false)
duplicate_logs[1].update!(uprn: "123", uprn_known: 1, manual_address_entry_selected: false)
get "/sales-logs/#{sales_log.id}/duplicate-logs?original_log_id=#{sales_log.id}"
expect(page).to have_content("- Sale completion date", count: 3)
expect(page).to have_content("- Purchaser code", count: 3)
expect(page).to have_content("- Buyer 1’s age", count: 3)
expect(page).to have_content("- Buyer 1’s sex registered at birth", count: 3)
expect(page).to have_content("- Buyer 1’s working situation", count: 3)
expect(page).to have_content("- Address", count: 3)
expect(page).to have_link("Change", count: 21)
expect(page).to have_link("Change", href: "/sales-logs/#{sales_log.id}/purchaser-code?first_remaining_duplicate_id=#{duplicate_logs[0].id}&original_log_id=#{sales_log.id}&referrer=duplicate_logs")
expect(page).to have_link("Change", href: "/sales-logs/#{duplicate_logs[0].id}/purchaser-code?first_remaining_duplicate_id=#{sales_log.id}&original_log_id=#{sales_log.id}&referrer=duplicate_logs")
expect(page).to have_link("Change", href: "/sales-logs/#{duplicate_logs[1].id}/purchaser-code?first_remaining_duplicate_id=#{sales_log.id}&original_log_id=#{sales_log.id}&referrer=duplicate_logs")
end
it "displays buttons to delete" do
expect(page).to have_link("Keep this log and delete duplicates", count: 3)
expect(page).to have_link("Keep this log and delete duplicates", href: "/sales-logs/#{sales_log.id}/delete-duplicates?organisation_id=#{sales_log.owning_organisation_id}&original_log_id=#{sales_log.id}")
expect(page).to have_link("Keep this log and delete duplicates", href: "/sales-logs/#{duplicate_logs.first.id}/delete-duplicates?organisation_id=#{sales_log.owning_organisation_id}&original_log_id=#{sales_log.id}")
expect(page).to have_link("Keep this log and delete duplicates", href: "/sales-logs/#{duplicate_logs.second.id}/delete-duplicates?organisation_id=#{sales_log.owning_organisation_id}&original_log_id=#{sales_log.id}")
end
end
context "when there are no more duplicate logs" do
context "when accessed from the duplicate logs banner flow" do
before do
allow(SalesLog).to receive(:duplicate_logs).and_return(SalesLog.none)
get "/sales-logs/#{sales_log.id}/duplicate-logs?original_log_id=#{sales_log.id}&referrer=duplicate_logs_banner&organisation_id=#{sales_log.owning_organisation_id}"
end
it "displays check your answers for each log with correct questions" do
expect(page).to have_content("- Sale completion date", count: 1)
expect(page).to have_content("- Purchaser code", count: 1)
expect(page).to have_content("- Buyer 1’s age", count: 1)
expect(page).to have_content("- Buyer 1’s sex registered at birth", count: 1)
expect(page).to have_content("- Buyer 1’s working situation", count: 1)
expect(page).to have_content("- Postcode", count: 1)
expect(page).to have_content("- Address line 1", count: 1)
expect(page).to have_link("Change", count: 8)
expect(page).to have_link("Change", href: "/sales-logs/#{sales_log.id}/purchaser-code?original_log_id=#{sales_log.id}&referrer=interruption_screen")
end
it "displays button to review other duplicates" do
expect(page).to have_link("Review other duplicates", href: "/organisations/#{sales_log.owning_organisation_id}/duplicates?referrer=duplicate_logs_banner")
end
it "displays no duplicates banner" do
expect(page).to have_content("This log had the same answers but it is no longer a duplicate. Make sure the answers are correct.")
end
end
context "when accessed from the single log submission flow" do
before do
allow(SalesLog).to receive(:duplicate_logs).and_return(SalesLog.none)
get "/sales-logs/#{sales_log.id}/duplicate-logs?original_log_id=#{sales_log.id}&organisation_id=#{sales_log.owning_organisation_id}"
end
it "displays check your answers for each log with correct questions" do
expect(page).to have_content("- Sale completion date", count: 1)
expect(page).to have_content("- Purchaser code", count: 1)
expect(page).to have_content("- Buyer 1’s age", count: 1)
expect(page).to have_content("- Buyer 1’s sex registered at birth", count: 1)
expect(page).to have_content("- Buyer 1’s working situation", count: 1)
expect(page).to have_content("- Postcode", count: 1)
expect(page).to have_content("- Address line 1", count: 1)
expect(page).to have_link("Change", count: 8)
expect(page).to have_link("Change", href: "/sales-logs/#{sales_log.id}/purchaser-code?original_log_id=#{sales_log.id}&referrer=interruption_screen")
end
it "displays button to return to log" do
expect(page).to have_link("Back to Log #{sales_log.id}", href: "/sales-logs/#{sales_log.id}")
end
it "displays no duplicates banner" do
expect(page).to have_content("This log had the same answers but it is no longer a duplicate. Make sure the answers are correct.")
end
end
end
end
end
context "when user is a data provider" do
before do
allow(user).to receive(:need_two_factor_authentication?).and_return(false)
sign_in user
end
context "when viewing lettings logs duplicates" do
context "when there are multiple duplicate logs" do
let(:duplicate_logs) { create_list(:lettings_log, 2, :completed) }
before do
allow(LettingsLog).to receive(:duplicate_logs).and_return(duplicate_logs)
get "/lettings-logs/#{lettings_log.id}/duplicate-logs?original_log_id=#{lettings_log.id}"
end
it "displays links to all the duplicate logs" do
expect(page).to have_link("Log #{lettings_log.id}", href: "/lettings-logs/#{lettings_log.id}")
expect(page).to have_link("Log #{duplicate_logs.first.id}", href: "/lettings-logs/#{duplicate_logs.first.id}")
expect(page).to have_link("Log #{duplicate_logs.second.id}", href: "/lettings-logs/#{duplicate_logs.second.id}")
end
it "displays check your answers for each log with correct questions" do
expect(page).to have_content("- Tenancy start date", count: 3)
expect(page).to have_content("- Tenant code", count: 3)
expect(page).to have_content("- Lead tenant’s age", count: 3)
expect(page).to have_content("- Lead tenant’s sex registered at birth", count: 3)
expect(page).to have_content("- Lead tenant’s working situation", count: 3)
expect(page).to have_content("Household rent and charges", count: 3)
expect(page).to have_link("Change", count: 24)
expect(page).to have_link("Change", href: "/lettings-logs/#{lettings_log.id}/tenant-code?first_remaining_duplicate_id=#{duplicate_logs[0].id}&original_log_id=#{lettings_log.id}&referrer=duplicate_logs")
expect(page).to have_link("Change", href: "/lettings-logs/#{duplicate_logs[0].id}/tenant-code?first_remaining_duplicate_id=#{lettings_log.id}&original_log_id=#{lettings_log.id}&referrer=duplicate_logs")
expect(page).to have_link("Change", href: "/lettings-logs/#{duplicate_logs[1].id}/tenant-code?first_remaining_duplicate_id=#{lettings_log.id}&original_log_id=#{lettings_log.id}&referrer=duplicate_logs")
end
it "displays buttons to delete" do
expect(page).to have_link("Keep this log and delete duplicates", count: 3)
expect(page).to have_link("Keep this log and delete duplicates", href: "/lettings-logs/#{lettings_log.id}/delete-duplicates?original_log_id=#{lettings_log.id}")
expect(page).to have_link("Keep this log and delete duplicates", href: "/lettings-logs/#{duplicate_logs.first.id}/delete-duplicates?original_log_id=#{lettings_log.id}")
expect(page).to have_link("Keep this log and delete duplicates", href: "/lettings-logs/#{duplicate_logs.second.id}/delete-duplicates?original_log_id=#{lettings_log.id}")
end
end
context "when there are no more duplicate logs" do
context "when accessed from the duplicate logs banner flow" do
before do
allow(LettingsLog).to receive(:duplicate_logs).and_return(LettingsLog.none)
get "/lettings-logs/#{lettings_log.id}/duplicate-logs?original_log_id=#{lettings_log.id}&referrer=duplicate_logs_banner"
end
it "displays check your answers for each log with correct questions" do
expect(page).to have_content("- Tenancy start date", count: 1)
expect(page).to have_content("- Tenant code", count: 1)
expect(page).to have_content("- Lead tenant’s age", count: 1)
expect(page).to have_content("- Lead tenant’s sex registered at birth", count: 1)
expect(page).to have_content("- Lead tenant’s working situation", count: 1)
expect(page).to have_content("Household rent and charges", count: 1)
expect(page).to have_link("Change", count: 8)
expect(page).to have_link("Change", href: "/lettings-logs/#{lettings_log.id}/tenant-code?original_log_id=#{lettings_log.id}&referrer=interruption_screen")
end
it "displays button to review other duplicates" do
expect(page).to have_link("Review other duplicates", href: "/duplicate-logs?referrer=duplicate_logs_banner")
end
it "displays no duplicates banner" do
expect(page).to have_content("This log had the same answers but it is no longer a duplicate. Make sure the answers are correct.")
end
end
context "when accessed from the single log submission flow" do
before do
allow(LettingsLog).to receive(:duplicate_logs).and_return(LettingsLog.none)
get "/lettings-logs/#{lettings_log.id}/duplicate-logs?original_log_id=#{lettings_log.id}"
end
it "displays check your answers for each log with correct questions" do
expect(page).to have_content("- Tenancy start date", count: 1)
expect(page).to have_content("- Tenant code", count: 1)
expect(page).to have_content("- Lead tenant’s age", count: 1)
expect(page).to have_content("- Lead tenant’s sex registered at birth", count: 1)
expect(page).to have_content("- Lead tenant’s working situation", count: 1)
expect(page).to have_content("Household rent and charges", count: 1)
expect(page).to have_link("Change", count: 8)
expect(page).to have_link("Change", href: "/lettings-logs/#{lettings_log.id}/tenant-code?original_log_id=#{lettings_log.id}&referrer=interruption_screen")
end
it "displays button to return to log" do
expect(page).to have_link("Back to Log #{lettings_log.id}", href: "/lettings-logs/#{lettings_log.id}")
end
it "displays no duplicates banner" do
expect(page).to have_content("This log had the same answers but it is no longer a duplicate. Make sure the answers are correct.")
end
end
end
end
context "when viewing sales logs duplicates" do
context "when there are multiple duplicate logs" do
let(:duplicate_logs) { create_list(:sales_log, 2, :completed) }
before do
allow(SalesLog).to receive(:duplicate_logs).and_return(duplicate_logs)
get "/sales-logs/#{sales_log.id}/duplicate-logs?original_log_id=#{sales_log.id}"
end
it "displays links to all the duplicate logs" do
expect(page).to have_link("Log #{sales_log.id}", href: "/sales-logs/#{sales_log.id}")
expect(page).to have_link("Log #{duplicate_logs.first.id}", href: "/sales-logs/#{duplicate_logs.first.id}")
expect(page).to have_link("Log #{duplicate_logs.second.id}", href: "/sales-logs/#{duplicate_logs.second.id}")
end
it "displays check your answers for each log with correct questions" do
expect(page).to have_content("- Sale completion date", count: 3)
expect(page).to have_content("- Purchaser code", count: 3)
expect(page).to have_content("- Buyer 1’s age", count: 3)
expect(page).to have_content("- Buyer 1’s sex registered at birth", count: 3)
expect(page).to have_content("- Buyer 1’s working situation", count: 3)
expect(page).to have_content("- Postcode", count: 3)
expect(page).to have_content("- Address line 1", count: 3)
expect(page).to have_link("Change", count: 21)
expect(page).to have_link("Change", href: "/sales-logs/#{sales_log.id}/purchaser-code?first_remaining_duplicate_id=#{duplicate_logs[0].id}&original_log_id=#{sales_log.id}&referrer=duplicate_logs")
expect(page).to have_link("Change", href: "/sales-logs/#{duplicate_logs[0].id}/purchaser-code?first_remaining_duplicate_id=#{sales_log.id}&original_log_id=#{sales_log.id}&referrer=duplicate_logs")
expect(page).to have_link("Change", href: "/sales-logs/#{duplicate_logs[1].id}/purchaser-code?first_remaining_duplicate_id=#{sales_log.id}&original_log_id=#{sales_log.id}&referrer=duplicate_logs")
end
it "displays buttons to delete" do
expect(page).to have_link("Keep this log and delete duplicates", count: 3)
expect(page).to have_link("Keep this log and delete duplicates", href: "/sales-logs/#{sales_log.id}/delete-duplicates?original_log_id=#{sales_log.id}")
expect(page).to have_link("Keep this log and delete duplicates", href: "/sales-logs/#{duplicate_logs.first.id}/delete-duplicates?original_log_id=#{sales_log.id}")
expect(page).to have_link("Keep this log and delete duplicates", href: "/sales-logs/#{duplicate_logs.second.id}/delete-duplicates?original_log_id=#{sales_log.id}")
end
end
context "when there are no more duplicate logs" do
context "when accessed from the duplicate logs banner flow" do
before do
allow(SalesLog).to receive(:duplicate_logs).and_return(SalesLog.none)
get "/sales-logs/#{sales_log.id}/duplicate-logs?original_log_id=#{sales_log.id}&referrer=duplicate_logs_banner"
end
it "displays check your answers for each log with correct questions" do
expect(page).to have_content("- Sale completion date", count: 1)
expect(page).to have_content("- Purchaser code", count: 1)
expect(page).to have_content("- Buyer 1’s age", count: 1)
expect(page).to have_content("- Buyer 1’s sex registered at birth", count: 1)
expect(page).to have_content("- Buyer 1’s working situation", count: 1)
expect(page).to have_content("- Postcode", count: 1)
expect(page).to have_content("- Address line 1", count: 1)
expect(page).to have_link("Change", count: 7)
expect(page).to have_link("Change", href: "/sales-logs/#{sales_log.id}/purchaser-code?original_log_id=#{sales_log.id}&referrer=interruption_screen")
end
it "displays button to review other duplicates" do
expect(page).to have_link("Review other duplicates", href: "/duplicate-logs?referrer=duplicate_logs_banner")
end
it "displays no duplicates banner" do
expect(page).to have_content("This log had the same answers but it is no longer a duplicate. Make sure the answers are correct.")
end
end
context "when accessed from the single log submission flow" do
before do
allow(SalesLog).to receive(:duplicate_logs).and_return(SalesLog.none)
get "/sales-logs/#{sales_log.id}/duplicate-logs?original_log_id=#{sales_log.id}"
end
it "displays check your answers for each log with correct questions" do
expect(page).to have_content("- Sale completion date", count: 1)
expect(page).to have_content("- Purchaser code", count: 1)
expect(page).to have_content("- Buyer 1’s age", count: 1)
expect(page).to have_content("- Buyer 1’s sex registered at birth", count: 1)
expect(page).to have_content("- Buyer 1’s working situation", count: 1)
expect(page).to have_content("- Postcode", count: 1)
expect(page).to have_content("- Address line 1", count: 1)
expect(page).to have_link("Change", count: 7)
expect(page).to have_link("Change", href: "/sales-logs/#{sales_log.id}/purchaser-code?original_log_id=#{sales_log.id}&referrer=interruption_screen")
end
it "displays button to return to log" do
expect(page).to have_link("Back to Log #{sales_log.id}", href: "/sales-logs/#{sales_log.id}")
end
it "displays no duplicates banner" do
expect(page).to have_content("This log had the same answers but it is no longer a duplicate. Make sure the answers are correct.")
end
end
end
end
end
end
end
end
describe "GET lettings delete-duplicates" do describe "GET lettings delete-duplicates" do
let(:id) { lettings_log.id } let(:id) { lettings_log.id }

2
spec/requests/form_controller_spec.rb

@ -1194,7 +1194,7 @@ RSpec.describe FormController, type: :request do
it "displays a success banner" do it "displays a success banner" do
follow_redirect! follow_redirect!
expect(response.body).to include("You have successfully updated Q31: lead tenant’s age") expect(response.body).to match(/You have successfully updated Q\d+: lead tenant’s age/)
end end
end end

76
spec/requests/start_controller_spec.rb

@ -1,6 +1,8 @@
require "rails_helper" require "rails_helper"
RSpec.describe StartController, type: :request do RSpec.describe StartController, type: :request do
include CollectionTimeHelper
let(:user) { create(:user) } let(:user) { create(:user) }
let(:page) { Capybara::Node::Simple.new(response.body) } let(:page) { Capybara::Node::Simple.new(response.body) }
let(:notify_client) { instance_double(Notifications::Client) } let(:notify_client) { instance_double(Notifications::Client) }
@ -322,41 +324,67 @@ RSpec.describe StartController, type: :request do
end end
end end
context "and 2024 collection window is open for editing" do context "and previous collection window is open for editing" do
before do before do
create(:collection_resource, :additional, year: 2024, log_type: "sales", display_name: "sales additional resource (2024 to 2025)") create(:collection_resource, :additional, year: previous_collection_start_year, log_type: "sales", display_name: "sales additional resource (#{previous_collection_start_year} to #{previous_collection_end_year})")
allow(Time).to receive(:now).and_return(Time.zone.local(2025, 4, 1)) Timecop.freeze(current_collection_start_date)
end
after do
Timecop.return
end end
it "displays correct resources for 2024/25 and 2025/26 collection years" do it "displays correct resources for previous and current collection years" do
current_collection_start_year_short = current_collection_start_year - 2000
current_collection_end_year_short = current_collection_end_year - 2000
previous_collection_start_year_short = previous_collection_start_year - 2000
previous_collection_end_year_short = previous_collection_end_year - 2000
current_collection_range_slash = "#{current_collection_start_year_short}/#{current_collection_end_year_short}"
previous_collection_range_slash = "#{previous_collection_start_year_short}/#{previous_collection_end_year_short}"
current_collection_range_to = "#{current_collection_start_year} to #{current_collection_end_year}"
previous_collection_range_to = "#{previous_collection_start_year} to #{previous_collection_end_year}"
get root_path get root_path
expect(page).to have_content("Lettings 25/26") expect(page).to have_content("Lettings #{current_collection_range_slash}")
expect(page).to have_content("Lettings 24/25") expect(page).to have_content("Lettings #{previous_collection_range_slash}")
expect(page).to have_content("Lettings 2025 to 2026") expect(page).to have_content("Lettings #{current_collection_range_to}")
expect(page).to have_content("Lettings 2024 to 2025") expect(page).to have_content("Lettings #{previous_collection_range_to}")
expect(page).to have_content("Sales 25/26") expect(page).to have_content("Sales #{current_collection_range_slash}")
expect(page).to have_content("Sales 24/25") expect(page).to have_content("Sales #{previous_collection_range_slash}")
expect(page).to have_content("Sales 2025 to 2026") expect(page).to have_content("Sales #{current_collection_range_to}")
expect(page).to have_content("Sales 2024 to 2025") expect(page).to have_content("Sales #{previous_collection_range_to}")
expect(page).to have_content("Download the sales additional resource (2024 to 2025)") expect(page).to have_content("Download the sales additional resource (#{previous_collection_range_to})")
end end
end end
context "and 2024 collection window is closed for editing" do context "and previous collection window is closed for editing" do
before do before do
allow(Time).to receive(:now).and_return(Time.zone.local(2025, 12, 1)) Timecop.freeze(current_collection_start_date + 6.months)
end end
it "displays correct resources" do after do
Timecop.return
end
it "displays correct resources for current collection year only" do
current_collection_start_year_short = current_collection_start_year - 2000
current_collection_end_year_short = current_collection_end_year - 2000
previous_collection_start_year_short = previous_collection_start_year - 2000
previous_collection_end_year_short = previous_collection_end_year - 2000
current_collection_range_slash = "#{current_collection_start_year_short}/#{current_collection_end_year_short}"
previous_collection_range_slash = "#{previous_collection_start_year_short}/#{previous_collection_end_year_short}"
current_collection_range_to = "#{current_collection_start_year} to #{current_collection_end_year}"
previous_collection_range_to = "#{previous_collection_start_year} to #{previous_collection_end_year}"
get root_path get root_path
expect(page).to have_content("Lettings 25/26") expect(page).to have_content("Lettings #{current_collection_range_slash}")
expect(page).not_to have_content("Lettings 24/25") expect(page).not_to have_content("Lettings #{previous_collection_range_slash}")
expect(page).to have_content("Lettings 2025 to 2026") expect(page).to have_content("Lettings #{current_collection_range_to}")
expect(page).not_to have_content("Lettings 2024 to 2025") expect(page).not_to have_content("Lettings #{previous_collection_range_to}")
expect(page).to have_content("Sales 25/26") expect(page).to have_content("Sales #{current_collection_range_slash}")
expect(page).not_to have_content("Sales 24/25") expect(page).not_to have_content("Sales #{previous_collection_range_slash}")
expect(page).to have_content("Sales 2025 to 2026") expect(page).to have_content("Sales #{current_collection_range_to}")
expect(page).not_to have_content("Sales 2024 to 2025") expect(page).not_to have_content("Sales #{previous_collection_range_to}")
end end
end end

7
spec/services/bulk_upload/sales/validator_spec.rb

@ -37,10 +37,15 @@ RSpec.describe BulkUpload::Sales::Validator do
context "when file has too many columns" do context "when file has too many columns" do
before do before do
file.write((%w[a] * (Object.const_get("BulkUpload::Sales::Year#{year}::CsvParser::MAX_COLUMNS") + 1)).join(",")) Timecop.travel(collection_start_date_for_year_or_later(2025))
file.write((%w[a] * (Object.const_get("BulkUpload::Sales::Year#{year}::CsvParser::FIELDS") + 1)).join(","))
file.rewind file.rewind
end end
after do
Timecop.return
end
it "is not valid" do it "is not valid" do
expect(validator).not_to be_valid expect(validator).not_to be_valid
end end

Loading…
Cancel
Save