Browse Source

Merge branch 'main' into CLDC-2199-uprn-soft-validation-bugs

pull/1538/head
natdeanlewissoftwire 2 years ago
parent
commit
88b190eea9
  1. 2
      Gemfile
  2. 8
      app/components/bulk_upload_error_row_component.rb
  3. 4
      app/components/bulk_upload_error_summary_table_component.rb
  4. 6
      app/controllers/form_controller.rb
  5. 2
      app/controllers/locations_controller.rb
  6. 8
      app/helpers/collection_time_helper.rb
  7. 6
      app/helpers/locations_helper.rb
  8. 2
      app/helpers/navigation_items_helper.rb
  9. 20
      app/helpers/question_view_helper.rb
  10. 2
      app/helpers/tasklist_helper.rb
  11. 3
      app/models/bulk_upload_error.rb
  12. 49
      app/models/form.rb
  13. 14
      app/models/form/lettings/pages/care_home_weekly.rb
  14. 12
      app/models/form/lettings/pages/max_rent_value_check.rb
  15. 10
      app/models/form/lettings/pages/min_rent_value_check.rb
  16. 12
      app/models/form/lettings/pages/net_income_value_check.rb
  17. 2
      app/models/form/lettings/pages/outstanding_amount.rb
  18. 6
      app/models/form/lettings/pages/rent_4_weekly.rb
  19. 6
      app/models/form/lettings/pages/rent_bi_weekly.rb
  20. 6
      app/models/form/lettings/pages/rent_monthly.rb
  21. 26
      app/models/form/lettings/pages/rent_weekly.rb
  22. 5
      app/models/form/lettings/pages/uprn.rb
  23. 16
      app/models/form/lettings/pages/uprn_known.rb
  24. 2
      app/models/form/lettings/questions/location_id.rb
  25. 9
      app/models/form/lettings/questions/period.rb
  26. 9
      app/models/form/lettings/questions/scheme_id.rb
  27. 1
      app/models/form/lettings/questions/tshortfall.rb
  28. 13
      app/models/form/lettings/questions/uprn.rb
  29. 2
      app/models/form/lettings/questions/uprn_known.rb
  30. 1
      app/models/form/lettings/subsections/property_information.rb
  31. 24
      app/models/form/question.rb
  32. 21
      app/models/form/sales/pages/buyer_live_in_value_check.rb
  33. 16
      app/models/form/sales/pages/discounted_sale_value_check.rb
  34. 15
      app/models/form/sales/pages/percentage_discount_value_check.rb
  35. 4
      app/models/form/sales/pages/shared_ownership_deposit_value_check.rb
  36. 1
      app/models/form/sales/pages/uprn.rb
  37. 12
      app/models/form/sales/pages/uprn_known.rb
  38. 24
      app/models/form/sales/questions/buyer_live_in_value_check.rb
  39. 23
      app/models/form/sales/questions/percentage_discount_value_check.rb
  40. 13
      app/models/form/sales/questions/uprn.rb
  41. 8
      app/models/form/sales/questions/uprn_known.rb
  42. 1
      app/models/form/sales/subsections/discounted_ownership_scheme.rb
  43. 2
      app/models/form/sales/subsections/household_characteristics.rb
  44. 2
      app/models/form/sales/subsections/property_information.rb
  45. 2
      app/models/form/sales/subsections/setup.rb
  46. 26
      app/models/lettings_log.rb
  47. 1
      app/models/location.rb
  48. 17
      app/models/log.rb
  49. 20
      app/models/sales_log.rb
  50. 12
      app/models/scheme.rb
  51. 8
      app/models/validations/financial_validations.rb
  52. 2
      app/models/validations/sales/sale_information_validations.rb
  53. 24
      app/models/validations/sales/soft_validations.rb
  54. 8
      app/models/validations/setup_validations.rb
  55. 1
      app/models/validations/shared_validations.rb
  56. 68
      app/services/bulk_upload/lettings/year2022/row_parser.rb
  57. 9
      app/services/bulk_upload/lettings/year2023/row_parser.rb
  58. 46
      app/services/bulk_upload/sales/year2022/row_parser.rb
  59. 9
      app/services/exports/lettings_log_export_service.rb
  60. 10
      app/services/feature_toggle.rb
  61. 2
      app/services/imports/lettings_logs_import_service.rb
  62. 6
      app/services/imports/sales_logs_import_service.rb
  63. 6
      app/views/bulk_upload_lettings_logs/forms/checking_file.html.erb
  64. 1
      app/views/bulk_upload_lettings_logs/forms/prepare_your_file.html.erb
  65. 2
      app/views/bulk_upload_lettings_results/show.html.erb
  66. 6
      app/views/bulk_upload_sales_logs/forms/checking_file.html.erb
  67. 1
      app/views/bulk_upload_sales_logs/forms/prepare_your_file.html.erb
  68. 16
      app/views/form/_select_question.html.erb
  69. 2
      app/views/form/page.html.erb
  70. 1
      app/views/locations/availability.erb
  71. 1
      app/views/locations/check_answers.html.erb
  72. 1
      app/views/locations/index.html.erb
  73. 1
      app/views/locations/local_authority.html.erb
  74. 1
      app/views/locations/mobility_standards.html.erb
  75. 1
      app/views/locations/name.html.erb
  76. 1
      app/views/locations/postcode.html.erb
  77. 1
      app/views/locations/show.html.erb
  78. 1
      app/views/locations/toggle_active.html.erb
  79. 1
      app/views/locations/type_of_unit.html.erb
  80. 1
      app/views/locations/units.html.erb
  81. 8
      app/views/logs/index.html.erb
  82. 48
      app/views/organisations/merge.html.erb
  83. 3
      app/views/organisations/show.html.erb
  84. 1
      app/views/schemes/confirm_secondary.html.erb
  85. 5
      app/views/schemes/details.html.erb
  86. 5
      app/views/schemes/edit_name.html.erb
  87. 5
      app/views/schemes/new.html.erb
  88. 5
      app/views/schemes/primary_client_group.html.erb
  89. 1
      app/views/schemes/secondary_client_group.html.erb
  90. 1
      app/views/schemes/show.html.erb
  91. 1
      app/views/schemes/support.html.erb
  92. 1
      app/views/schemes/toggle_active.html.erb
  93. 201
      config/forms/2022_2023.json
  94. 2
      config/initializers/filter_parameter_logging.rb
  95. 35
      config/locales/en.yml
  96. 1
      config/routes.rb
  97. 5
      db/migrate/20230405074138_add_percentage_discount_value_check.rb
  98. 5
      db/migrate/20230405140343_add_buyer_livin_value_check.rb
  99. 2
      db/schema.rb
  100. BIN
      public/files/bulk-upload-lettings-specification-2023-24.xlsx
  101. Some files were not shown because too many files have changed in this diff Show More

2
Gemfile

@ -70,6 +70,7 @@ group :development, :test do
gem "byebug", platforms: %i[mri mingw x64_mingw] gem "byebug", platforms: %i[mri mingw x64_mingw]
gem "dotenv-rails" gem "dotenv-rails"
gem "factory_bot_rails" gem "factory_bot_rails"
gem "faker"
gem "pry-byebug" gem "pry-byebug"
gem "parallel_tests" gem "parallel_tests"
@ -93,7 +94,6 @@ group :test do
gem "capybara", require: false gem "capybara", require: false
gem "capybara-lockstep" gem "capybara-lockstep"
gem "capybara-screenshot" gem "capybara-screenshot"
gem "faker"
gem "rspec-rails", require: false gem "rspec-rails", require: false
gem "selenium-webdriver", require: false gem "selenium-webdriver", require: false
gem "simplecov", require: false gem "simplecov", require: false

8
app/components/bulk_upload_error_row_component.rb

@ -2,7 +2,7 @@ class BulkUploadErrorRowComponent < ViewComponent::Base
attr_reader :bulk_upload_errors attr_reader :bulk_upload_errors
def initialize(bulk_upload_errors:) def initialize(bulk_upload_errors:)
@bulk_upload_errors = sorted_errors(bulk_upload_errors) @bulk_upload_errors = bulk_upload_errors
super super
end end
@ -62,10 +62,4 @@ class BulkUploadErrorRowComponent < ViewComponent::Base
def sales? def sales?
bulk_upload.log_type == "sales" bulk_upload.log_type == "sales"
end end
private
def sorted_errors(errors)
errors.sort_by { |e| e.cell.rjust(3, "0") }
end
end end

4
app/components/bulk_upload_error_summary_table_component.rb

@ -16,8 +16,8 @@ class BulkUploadErrorSummaryTableComponent < ViewComponent::Base
.bulk_upload_errors .bulk_upload_errors
.group(:col, :field, :error) .group(:col, :field, :error)
.having("count(*) >= ?", display_threshold) .having("count(*) >= ?", display_threshold)
.order_by_col
.count .count
.sort_by { |el| el[0][0].rjust(3, "0") }
end end
def errors? def errors?
@ -39,8 +39,8 @@ private
.bulk_upload_errors .bulk_upload_errors
.where(category: "setup") .where(category: "setup")
.group(:col, :field, :error) .group(:col, :field, :error)
.order_by_col
.count .count
.sort_by { |el| el[0][0].rjust(3, "0") }
end end
def display_threshold def display_threshold

6
app/controllers/form_controller.rb

@ -122,11 +122,9 @@ private
def successful_redirect_path def successful_redirect_path
if is_referrer_check_answers? if is_referrer_check_answers?
page_ids = form.subsection_for_page(@page).pages.map(&:id) next_page_id = form.next_page_id(@page, @log, current_user)
page_index = page_ids.index(@page.id)
next_page_id = form.next_page(@page, @log, current_user)
next_page = form.get_page(next_page_id) next_page = form.get_page(next_page_id)
previous_page = form.previous_page(page_ids, page_index, @log, current_user) previous_page = form.previous_page_id(@page, @log, current_user)
if next_page&.interruption_screen? || next_page_id == previous_page || CONFIRMATION_PAGE_IDS.include?(next_page_id) if next_page&.interruption_screen? || next_page_id == previous_page || CONFIRMATION_PAGE_IDS.include?(next_page_id)
return send("#{@log.class.name.underscore}_#{next_page_id}_path", @log, { referrer: "check_answers" }) return send("#{@log.class.name.underscore}_#{next_page_id}_path", @log, { referrer: "check_answers" })

2
app/controllers/locations_controller.rb

@ -134,7 +134,7 @@ class LocationsController < ApplicationController
def check_answers; end def check_answers; end
def confirm def confirm
flash[:notice] = "#{@location.postcode} #{@location.startdate.blank? || @location.startdate < Time.zone.now ? 'has been' : 'will be'} added to this scheme" flash[:notice] = helpers.location_creation_success_notice(@location)
redirect_to scheme_locations_path(@scheme) redirect_to scheme_locations_path(@scheme)
end end

8
app/helpers/collection_time_helper.rb

@ -1,15 +1,15 @@
module CollectionTimeHelper module CollectionTimeHelper
def collection_start_year(date) def collection_start_year_for_date(date)
window_end_date = Time.zone.local(date.year, 4, 1) window_end_date = Time.zone.local(date.year, 4, 1)
date < window_end_date ? date.year - 1 : date.year date < window_end_date ? date.year - 1 : date.year
end end
def current_collection_start_year def current_collection_start_year
collection_start_year(Time.zone.now) collection_start_year_for_date(Time.zone.now)
end end
def collection_start_date(date) def collection_start_date(date)
Time.zone.local(collection_start_year(date), 4, 1) Time.zone.local(collection_start_year_for_date(date), 4, 1)
end end
def date_mid_collection_year_formatted(date) def date_mid_collection_year_formatted(date)
@ -22,7 +22,7 @@ module CollectionTimeHelper
end end
def collection_end_date(date) def collection_end_date(date)
Time.zone.local(collection_start_year(date) + 1, 3, 31).end_of_day Time.zone.local(collection_start_year_for_date(date) + 1, 3, 31).end_of_day
end end
def current_collection_end_date def current_collection_end_date

6
app/helpers/locations_helper.rb

@ -78,6 +78,12 @@ module LocationsHelper
return govuk_button_link_to "Reactivate this location", scheme_location_new_reactivation_path(location.scheme, location) if location.deactivated? return govuk_button_link_to "Reactivate this location", scheme_location_new_reactivation_path(location.scheme, location) if location.deactivated?
end end
def location_creation_success_notice(location)
if location.confirmed
"#{location.postcode} #{location.startdate.blank? || location.startdate.before?(Time.zone.now) ? 'has been' : 'will be'} added to this scheme"
end
end
private private
ActivePeriod = Struct.new(:from, :to) ActivePeriod = Struct.new(:from, :to)

2
app/helpers/navigation_items_helper.rb

@ -101,7 +101,7 @@ private
end end
def subnav_details_path?(path) def subnav_details_path?(path)
path.include?("/organisations") && path.include?("/details") path.include?("/organisations") && (path.include?("/details") || path.include?("/merge"))
end end
def stock_owners_path?(path) def stock_owners_path?(path)

20
app/helpers/question_view_helper.rb

@ -13,6 +13,26 @@ module QuestionViewHelper
} }
end end
def answer_option_synonyms(resource)
return unless resource.instance_of?(Scheme)
resource.locations.map(&:postcode).join(",")
end
def answer_option_append(resource)
return unless resource.instance_of?(Scheme)
confirmed_locations_count = resource.locations.confirmed.size
unconfirmed_locations_count = resource.locations.unconfirmed.size
"#{confirmed_locations_count} completed #{'location'.pluralize(confirmed_locations_count)}, #{unconfirmed_locations_count} incomplete #{'location'.pluralize(unconfirmed_locations_count)}"
end
def answer_option_hint(resource)
return unless resource.instance_of?(Scheme)
[resource.primary_client_group, resource.secondary_client_group].compact.join(", ")
end
private private
def label_size(page_header, conditional, question) def label_size(page_header, conditional, question)

2
app/helpers/tasklist_helper.rb

@ -15,7 +15,7 @@ module TasklistHelper
if subsection.pages.first.routed_to?(log, current_user) if subsection.pages.first.routed_to?(log, current_user)
subsection.pages.first.id subsection.pages.first.id
else else
log.form.next_page(subsection.pages.first, log, current_user) log.form.next_page_id(subsection.pages.first, log, current_user)
end end
end end

3
app/models/bulk_upload_error.rb

@ -1,3 +1,6 @@
class BulkUploadError < ApplicationRecord class BulkUploadError < ApplicationRecord
belongs_to :bulk_upload belongs_to :bulk_upload
scope :order_by_cell, -> { order(Arel.sql("LPAD(cell, 10, '0')")) }
scope :order_by_col, -> { order(Arel.sql("LPAD(col, 10, '0')")) }
end end

49
app/models/form.rb

@ -61,30 +61,54 @@ class Form
subsections.find { |s| s.pages.find { |p| p.id == page.id } } subsections.find { |s| s.pages.find { |p| p.id == page.id } }
end end
def next_page(page, log, current_user) def next_page_id(page, log, current_user)
return page.next_unresolved_page_id || :check_answers if log.unresolved return page.next_unresolved_page_id || :check_answers if log.unresolved
page_ids = subsection_for_page(page).pages.map(&:id) page_ids = subsection_for_page(page).pages.map(&:id)
page_index = page_ids.index(page.id) page_index = page_ids.index(page.id)
page_id = if page.interruption_screen? && log[page.questions[0].id] == 1 && page.routed_to?(log, current_user) page_id = if page.interruption_screen? && log[page.questions[0].id] == 1 && page.routed_to?(log, current_user)
previous_page(page_ids, page_index, log, current_user) previous_page_id(page, log, current_user)
else else
page_ids[page_index + 1] page_ids[page_index + 1]
end end
nxt_page = get_page(page_id) next_page = get_page(page_id)
return :check_answers if nxt_page.nil? return :check_answers if next_page.nil?
return nxt_page.id if nxt_page.routed_to?(log, current_user) return next_page.id if next_page.routed_to?(log, current_user)
next_page(nxt_page, log, current_user) next_page_id(next_page, log, current_user)
end end
def next_page_redirect_path(page, log, current_user) def next_page_redirect_path(page, log, current_user)
nxt_page = next_page(page, log, current_user) next_page_id = next_page_id(page, log, current_user)
if nxt_page == :check_answers if next_page_id == :check_answers
"#{type}_log_#{subsection_for_page(page).id}_check_answers_path" "#{type}_log_#{subsection_for_page(page).id}_check_answers_path"
else else
"#{type}_log_#{nxt_page}_path" "#{type}_log_#{next_page_id}_path"
end
end
def previous_page_id(page, log, current_user)
page_ids = subsection_for_page(page).pages.map(&:id)
page_index = page_ids.index(page.id)
return :tasklist if page_index.zero?
page_id = page_ids[page_index - 1]
previous_page = get_page(page_id)
return previous_page.id if previous_page.routed_to?(log, current_user)
previous_page_id(previous_page, log, current_user)
end
def previous_page_redirect_path(page, log, current_user, referrer)
previous_page_id = previous_page_id(page, log, current_user)
if referrer == "check_answers"
"#{type}_log_#{subsection_for_page(page).id}_check_answers_path"
elsif previous_page_id == :tasklist
"#{type}_log_path"
else
"#{type}_log_#{previous_page_id}_path"
end end
end end
@ -206,13 +230,6 @@ class Form
questions.select { |q| q.type == "numeric" } questions.select { |q| q.type == "numeric" }
end end
def previous_page(page_ids, page_index, log, current_user)
prev_page = get_page(page_ids[page_index - 1])
return prev_page.id if prev_page.routed_to?(log, current_user)
previous_page(page_ids, page_index - 1, log, current_user)
end
def send_chain(arr, log) def send_chain(arr, log)
Array(arr).inject(log) { |o, a| o.public_send(*a) } Array(arr).inject(log) { |o, a| o.public_send(*a) }
end end

14
app/models/form/lettings/pages/care_home_weekly.rb

@ -3,18 +3,8 @@ class Form::Lettings::Pages::CareHomeWeekly < ::Form::Page
super super
@id = "care_home_weekly" @id = "care_home_weekly"
@depends_on = [ @depends_on = [
{ "period" => 1, "needstype" => 2, "household_charge" => 0 }, { "rent_and_charges_paid_weekly?" => true, "is_supported_housing?" => true, "household_charge" => 0 },
{ "period" => 1, "needstype" => 2, "household_charge" => nil }, { "rent_and_charges_paid_weekly?" => true, "is_supported_housing?" => true, "household_charge" => nil },
{ "period" => 5, "needstype" => 2, "household_charge" => 0 },
{ "period" => 5, "needstype" => 2, "household_charge" => nil },
{ "period" => 6, "needstype" => 2, "household_charge" => 0 },
{ "period" => 6, "needstype" => 2, "household_charge" => nil },
{ "period" => 7, "needstype" => 2, "household_charge" => 0 },
{ "period" => 7, "needstype" => 2, "household_charge" => nil },
{ "period" => 8, "needstype" => 2, "household_charge" => 0 },
{ "period" => 8, "needstype" => 2, "household_charge" => nil },
{ "period" => 9, "needstype" => 2, "household_charge" => 0 },
{ "period" => 9, "needstype" => 2, "household_charge" => nil },
] ]
end end

12
app/models/form/lettings/pages/max_rent_value_check.rb

@ -4,14 +4,20 @@ class Form::Lettings::Pages::MaxRentValueCheck < ::Form::Page
@depends_on = [{ "rent_in_soft_max_range?" => true }] @depends_on = [{ "rent_in_soft_max_range?" => true }]
@title_text = { @title_text = {
"translation" => "soft_validations.rent.outside_range_title", "translation" => "soft_validations.rent.outside_range_title",
"arguments" => [{ "key" => "brent", "label" => true, "i18n_template" => "brent" }], "arguments" => [
{
"key" => "brent",
"label" => true,
"i18n_template" => "brent",
},
],
} }
@informative_text = { @informative_text = {
"translation" => "soft_validations.rent.max_hint_text", "translation" => "soft_validations.rent.max_hint_text",
"arguments" => [ "arguments" => [
{ {
"key" => "soft_max_for_period", "key" => "field_formatted_as_currency",
"label" => false, "arguments_for_key" => "soft_max_for_period",
"i18n_template" => "soft_max_for_period", "i18n_template" => "soft_max_for_period",
}, },
], ],

10
app/models/form/lettings/pages/min_rent_value_check.rb

@ -4,14 +4,18 @@ class Form::Lettings::Pages::MinRentValueCheck < ::Form::Page
@depends_on = [{ "rent_in_soft_min_range?" => true }] @depends_on = [{ "rent_in_soft_min_range?" => true }]
@title_text = { @title_text = {
"translation" => "soft_validations.rent.outside_range_title", "translation" => "soft_validations.rent.outside_range_title",
"arguments" => [{ "key" => "brent", "label" => true, "i18n_template" => "brent" }], "arguments" => [{
"key" => "brent",
"label" => true,
"i18n_template" => "brent",
}],
} }
@informative_text = { @informative_text = {
"translation" => "soft_validations.rent.min_hint_text", "translation" => "soft_validations.rent.min_hint_text",
"arguments" => [ "arguments" => [
{ {
"key" => "soft_min_for_period", "key" => "field_formatted_as_currency",
"label" => false, "arguments_for_key" => "soft_min_for_period",
"i18n_template" => "soft_min_for_period", "i18n_template" => "soft_min_for_period",
}, },
], ],

12
app/models/form/lettings/pages/net_income_value_check.rb

@ -7,8 +7,16 @@ class Form::Lettings::Pages::NetIncomeValueCheck < ::Form::Page
@informative_text = { @informative_text = {
"translation" => "soft_validations.net_income.hint_text", "translation" => "soft_validations.net_income.hint_text",
"arguments" => [ "arguments" => [
{ "key" => "ecstat1", "label" => true, "i18n_template" => "ecstat1" }, {
{ "key" => "earnings", "label" => true, "i18n_template" => "earnings" }, "key" => "field_formatted_as_currency",
"arguments_for_key" => "ecstat1",
"i18n_template" => "ecstat1",
},
{
"key" => "field_formatted_as_currency",
"arguments_for_key" => "earnings",
"i18n_template" => "earnings",
},
], ],
} }
end end

2
app/models/form/lettings/pages/outstanding_amount.rb

@ -2,7 +2,7 @@ class Form::Lettings::Pages::OutstandingAmount < ::Form::Page
def initialize(id, hsh, subsection) def initialize(id, hsh, subsection)
super super
@id = "outstanding_amount" @id = "outstanding_amount"
@depends_on = [{ "hb" => 1, "hbrentshortfall" => 1 }, { "hb" => 6, "hbrentshortfall" => 1 }] @depends_on = [{ "receives_housing_related_benefits?" => true, "has_housing_benefit_rent_shortfall?" => true }]
end end
def questions def questions

6
app/models/form/lettings/pages/rent_4_weekly.rb

@ -4,10 +4,8 @@ class Form::Lettings::Pages::Rent4Weekly < ::Form::Page
@id = "rent_4_weekly" @id = "rent_4_weekly"
@header = "Household rent and charges" @header = "Household rent and charges"
@depends_on = [ @depends_on = [
{ "household_charge" => 0, "period" => 3, "is_carehome" => 0 }, { "household_charge" => 0, "rent_and_charges_paid_every_4_weeks?" => true, "is_carehome?" => false },
{ "household_charge" => nil, "period" => 3, "is_carehome" => 0 }, { "household_charge" => nil, "rent_and_charges_paid_every_4_weeks?" => true, "is_carehome?" => false },
{ "household_charge" => 0, "period" => 3, "is_carehome" => nil },
{ "household_charge" => nil, "period" => 3, "is_carehome" => nil },
] ]
end end

6
app/models/form/lettings/pages/rent_bi_weekly.rb

@ -4,10 +4,8 @@ class Form::Lettings::Pages::RentBiWeekly < ::Form::Page
@id = "rent_bi_weekly" @id = "rent_bi_weekly"
@header = "Household rent and charges" @header = "Household rent and charges"
@depends_on = [ @depends_on = [
{ "household_charge" => 0, "period" => 2, "is_carehome" => 0 }, { "household_charge" => nil, "rent_and_charges_paid_every_2_weeks?" => true, "is_carehome?" => false },
{ "household_charge" => nil, "period" => 2, "is_carehome" => 0 }, { "household_charge" => 0, "rent_and_charges_paid_every_2_weeks?" => true, "is_carehome?" => false },
{ "household_charge" => 0, "period" => 2, "is_carehome" => nil },
{ "household_charge" => nil, "period" => 2, "is_carehome" => nil },
] ]
end end

6
app/models/form/lettings/pages/rent_monthly.rb

@ -4,10 +4,8 @@ class Form::Lettings::Pages::RentMonthly < ::Form::Page
@id = "rent_monthly" @id = "rent_monthly"
@header = "Household rent and charges" @header = "Household rent and charges"
@depends_on = [ @depends_on = [
{ "household_charge" => 0, "period" => 4, "is_carehome" => 0 }, { "household_charge" => nil, "rent_and_charges_paid_monthly?" => true, "is_carehome?" => false },
{ "household_charge" => nil, "period" => 4, "is_carehome" => 0 }, { "household_charge" => 0, "rent_and_charges_paid_monthly?" => true, "is_carehome?" => false },
{ "household_charge" => 0, "period" => 4, "is_carehome" => nil },
{ "household_charge" => nil, "period" => 4, "is_carehome" => nil },
] ]
end end

26
app/models/form/lettings/pages/rent_weekly.rb

@ -4,30 +4,8 @@ class Form::Lettings::Pages::RentWeekly < ::Form::Page
@id = "rent_weekly" @id = "rent_weekly"
@header = "Household rent and charges" @header = "Household rent and charges"
@depends_on = [ @depends_on = [
{ "period" => 1, "household_charge" => 0, "is_carehome" => 0 }, { "rent_and_charges_paid_weekly?" => true, "household_charge" => 0, "is_carehome?" => false },
{ "period" => 1, "household_charge" => nil, "is_carehome" => 0 }, { "rent_and_charges_paid_weekly?" => true, "household_charge" => nil, "is_carehome?" => false },
{ "period" => 5, "household_charge" => 0, "is_carehome" => 0 },
{ "period" => 5, "household_charge" => nil, "is_carehome" => 0 },
{ "period" => 6, "household_charge" => 0, "is_carehome" => 0 },
{ "period" => 6, "household_charge" => nil, "is_carehome" => 0 },
{ "period" => 7, "household_charge" => 0, "is_carehome" => 0 },
{ "period" => 7, "household_charge" => nil, "is_carehome" => 0 },
{ "period" => 8, "household_charge" => 0, "is_carehome" => 0 },
{ "period" => 8, "household_charge" => nil, "is_carehome" => 0 },
{ "period" => 9, "household_charge" => 0, "is_carehome" => 0 },
{ "period" => 9, "household_charge" => nil, "is_carehome" => 0 },
{ "period" => 1, "household_charge" => 0, "is_carehome" => nil },
{ "period" => 1, "household_charge" => nil, "is_carehome" => nil },
{ "period" => 5, "household_charge" => 0, "is_carehome" => nil },
{ "period" => 5, "household_charge" => nil, "is_carehome" => nil },
{ "period" => 6, "household_charge" => 0, "is_carehome" => nil },
{ "period" => 6, "household_charge" => nil, "is_carehome" => nil },
{ "period" => 7, "household_charge" => 0, "is_carehome" => nil },
{ "period" => 7, "household_charge" => nil, "is_carehome" => nil },
{ "period" => 8, "household_charge" => 0, "is_carehome" => nil },
{ "period" => 8, "household_charge" => nil, "is_carehome" => nil },
{ "period" => 9, "household_charge" => 0, "is_carehome" => nil },
{ "period" => 9, "household_charge" => nil, "is_carehome" => nil },
] ]
end end

5
app/models/form/lettings/pages/uprn.rb

@ -6,14 +6,13 @@ class Form::Lettings::Pages::Uprn < ::Form::Page
def questions def questions
@questions ||= [ @questions ||= [
Form::Lettings::Questions::UprnKnown.new(nil, nil, self),
Form::Lettings::Questions::Uprn.new(nil, nil, self), Form::Lettings::Questions::Uprn.new(nil, nil, self),
] ]
end end
def routed_to?(log, _current_user = nil) def routed_to?(log, _current_user = nil)
return false if log.is_supported_housing? !log.is_supported_housing?
log.uprn_known == 1
end end
def skip_text def skip_text

16
app/models/form/lettings/pages/uprn_known.rb

@ -1,16 +0,0 @@
class Form::Lettings::Pages::UprnKnown < ::Form::Page
def initialize(id, hsh, subsection)
super
@id = "uprn_known"
end
def questions
@questions ||= [
Form::Lettings::Questions::UprnKnown.new(nil, nil, self),
]
end
def routed_to?(log, _current_user = nil)
!log.is_supported_housing?
end
end

2
app/models/form/lettings/questions/location_id.rb

@ -27,7 +27,7 @@ class Form::Lettings::Questions::LocationId < ::Form::Question
def displayed_answer_options(lettings_log, _user = nil) def displayed_answer_options(lettings_log, _user = nil)
return {} unless lettings_log.scheme return {} unless lettings_log.scheme
scheme_location_ids = lettings_log.scheme.locations.pluck(:id) scheme_location_ids = lettings_log.scheme.locations.confirmed.pluck(:id)
answer_options.select { |k, _v| scheme_location_ids.include?(k.to_i) } answer_options.select { |k, _v| scheme_location_ids.include?(k.to_i) }
end end

9
app/models/form/lettings/questions/period.rb

@ -15,11 +15,12 @@ class Form::Lettings::Questions::Period < ::Form::Question
"2" => { "value" => "Every 2 weeks" }, "2" => { "value" => "Every 2 weeks" },
"3" => { "value" => "Every 4 weeks" }, "3" => { "value" => "Every 4 weeks" },
"4" => { "value" => "Every calendar month" }, "4" => { "value" => "Every calendar month" },
"5" => { "value" => "Weekly for 50 weeks" },
"6" => { "value" => "Weekly for 49 weeks" },
"7" => { "value" => "Weekly for 48 weeks" },
"8" => { "value" => "Weekly for 47 weeks" },
"9" => { "value" => "Weekly for 46 weeks" }, "9" => { "value" => "Weekly for 46 weeks" },
"8" => { "value" => "Weekly for 47 weeks" },
"7" => { "value" => "Weekly for 48 weeks" },
"6" => { "value" => "Weekly for 49 weeks" },
"5" => { "value" => "Weekly for 50 weeks" },
"1" => { "value" => "Weekly for 52 weeks" }, "1" => { "value" => "Weekly for 52 weeks" },
"10" => { "value" => "Weekly for 53 weeks" },
}.freeze }.freeze
end end

9
app/models/form/lettings/questions/scheme_id.rb

@ -9,6 +9,11 @@ class Form::Lettings::Questions::SchemeId < ::Form::Question
@guidance_position = GuidancePosition::BOTTOM @guidance_position = GuidancePosition::BOTTOM
@guidance_partial = "scheme_selection" @guidance_partial = "scheme_selection"
@question_number = 9 @question_number = 9
@inferred_answers = {
"location.name": {
"scheme_has_multiple_locations?": false,
},
}
end end
def answer_options def answer_options
@ -41,6 +46,10 @@ class Form::Lettings::Questions::SchemeId < ::Form::Question
!supported_housing_selected?(lettings_log) !supported_housing_selected?(lettings_log)
end end
def get_extra_check_answer_value(lettings_log)
lettings_log.form.get_question("postcode_full", nil).label_from_value(lettings_log.postcode_full) unless lettings_log.scheme_has_multiple_locations?
end
private private
def supported_housing_selected?(lettings_log) def supported_housing_selected?(lettings_log)

1
app/models/form/lettings/questions/tshortfall.rb

@ -20,6 +20,7 @@ class Form::Lettings::Questions::Tshortfall < ::Form::Question
{ "label" => " every week for 47 weeks", "depends_on" => { "period" => 8 } }, { "label" => " every week for 47 weeks", "depends_on" => { "period" => 8 } },
{ "label" => " every week for 46 weeks", "depends_on" => { "period" => 9 } }, { "label" => " every week for 46 weeks", "depends_on" => { "period" => 9 } },
{ "label" => " every week for 52 weeks", "depends_on" => { "period" => 1 } }, { "label" => " every week for 52 weeks", "depends_on" => { "period" => 1 } },
{ "label" => " every week for 53 weeks", "depends_on" => { "period" => 10 } },
] ]
@question_number = 100 @question_number = 100
end end

13
app/models/form/lettings/questions/uprn.rb

@ -5,9 +5,14 @@ class Form::Lettings::Questions::Uprn < ::Form::Question
@check_answer_label = "UPRN" @check_answer_label = "UPRN"
@header = "What is the property's UPRN" @header = "What is the property's UPRN"
@type = "text" @type = "text"
@hint_text = "The Unique Property Reference Number (UPRN) is a unique number system created by Ordnance Survey and used by housing providers and sectors UK-wide. For example 10010457355."
@width = 10 @width = 10
@question_number = 11 @question_number = 11
@inferred_check_answers_value = [
{
"condition" => { "uprn_known" => 0 },
"value" => "Not known",
},
]
end end
def unanswered_error_message def unanswered_error_message
@ -15,6 +20,8 @@ class Form::Lettings::Questions::Uprn < ::Form::Question
end end
def get_extra_check_answer_value(log) def get_extra_check_answer_value(log)
return unless log.uprn_known == 1
value = [ value = [
log.address_line1, log.address_line1,
log.address_line2, log.address_line2,
@ -28,8 +35,4 @@ class Form::Lettings::Questions::Uprn < ::Form::Question
"\n\n#{value.join("\n")}" "\n\n#{value.join("\n")}"
end end
def hidden_in_check_answers?(log, _current_user = nil)
log.uprn_known != 1
end
end end

2
app/models/form/lettings/questions/uprn_known.rb

@ -8,6 +8,8 @@ class Form::Lettings::Questions::UprnKnown < ::Form::Question
@answer_options = ANSWER_OPTIONS @answer_options = ANSWER_OPTIONS
@hint_text = "The Unique Property Reference Number (UPRN) is a unique number system created by Ordnance Survey and used by housing providers and sectors UK-wide. For example 10010457355.<br><br> @hint_text = "The Unique Property Reference Number (UPRN) is a unique number system created by Ordnance Survey and used by housing providers and sectors UK-wide. For example 10010457355.<br><br>
You can continue without the UPRN, but it means we will need you to enter the address of the property." You can continue without the UPRN, but it means we will need you to enter the address of the property."
@conditional_for = { "uprn" => [1] }
@hidden_in_check_answers = true
end end
ANSWER_OPTIONS = { ANSWER_OPTIONS = {

1
app/models/form/lettings/subsections/property_information.rb

@ -34,7 +34,6 @@ class Form::Lettings::Subsections::PropertyInformation < ::Form::Subsection
def uprn_questions def uprn_questions
if form.start_date.year >= 2023 if form.start_date.year >= 2023
[ [
Form::Lettings::Pages::UprnKnown.new(nil, nil, self),
Form::Lettings::Pages::Uprn.new(nil, nil, self), Form::Lettings::Pages::Uprn.new(nil, nil, self),
Form::Lettings::Pages::UprnConfirmation.new(nil, nil, self), Form::Lettings::Pages::UprnConfirmation.new(nil, nil, self),
Form::Lettings::Pages::Address.new(nil, nil, self), Form::Lettings::Pages::Address.new(nil, nil, self),

24
app/models/form/question.rb

@ -226,24 +226,6 @@ class Form::Question
label label
end end
def answer_option_synonyms(resource)
return unless resource.respond_to?(:synonyms)
resource.synonyms
end
def answer_option_append(resource)
return unless resource.respond_to?(:appended_text)
resource.appended_text
end
def answer_option_hint(resource)
return unless resource.respond_to?(:hint)
resource.hint
end
def answer_selected?(log, answer) def answer_selected?(log, answer)
return false unless type == "select" return false unless type == "select"
@ -317,7 +299,11 @@ private
end end
def enabled_inferred_answers(inferred_answers, log) def enabled_inferred_answers(inferred_answers, log)
inferred_answers.filter { |_key, value| value.all? { |condition_key, condition_value| log[condition_key] == condition_value } } inferred_answers.filter do |_attribute, condition|
condition.all? do |condition_key, condition_value|
log.public_send(condition_key) == condition_value
end
end
end end
def inferred_answer_value(log) def inferred_answer_value(log)

21
app/models/form/sales/pages/buyer_live_in_value_check.rb

@ -0,0 +1,21 @@
class Form::Sales::Pages::BuyerLiveInValueCheck < Form::Sales::Pages::Person
def initialize(id, hsh, subsection, person_index:)
super
@depends_on = [
{
"buyer#{person_index}_livein_wrong_for_ownership_type?" => true,
},
]
@title_text = {
"translation" => "soft_validations.buyer#{person_index}_livein_wrong_for_ownership_type.title_text",
"arguments" => [{ "key" => "ownership_scheme", "label" => false, "i18n_template" => "ownership_scheme" }],
}
@informative_text = {}
end
def questions
@questions ||= [
Form::Sales::Questions::BuyerLiveInValueCheck.new(nil, nil, self, person_index: @person_index),
]
end
end

16
app/models/form/sales/pages/discounted_sale_value_check.rb

@ -4,11 +4,23 @@ class Form::Sales::Pages::DiscountedSaleValueCheck < ::Form::Page
@depends_on = depends_on @depends_on = depends_on
@title_text = { @title_text = {
"translation" => "soft_validations.discounted_sale_value.title_text", "translation" => "soft_validations.discounted_sale_value.title_text",
"arguments" => [{ "key" => "value_with_discount", "label" => false, "i18n_template" => "value_with_discount" }], "arguments" => [
{
"key" => "field_formatted_as_currency",
"arguments_for_key" => "value_with_discount",
"i18n_template" => "value_with_discount",
},
],
} }
@informative_text = { @informative_text = {
"translation" => "soft_validations.discounted_sale_value.informative_text", "translation" => "soft_validations.discounted_sale_value.informative_text",
"arguments" => [{ "key" => "mortgage_deposit_and_grant_total", "label" => false, "i18n_template" => "mortgage_deposit_and_grant_total" }], "arguments" => [
{
"key" => "field_formatted_as_currency",
"arguments_for_key" => "mortgage_deposit_and_grant_total",
"i18n_template" => "mortgage_deposit_and_grant_total",
},
],
} }
@person_index = person_index @person_index = person_index
@depends_on = [ @depends_on = [

15
app/models/form/sales/pages/percentage_discount_value_check.rb

@ -0,0 +1,15 @@
class Form::Sales::Pages::PercentageDiscountValueCheck < ::Form::Page
def initialize(id, hsh, subsection)
super
@title_text = {
"translation" => "soft_validations.percentage_discount_value.title_text",
"arguments" => [{ "key" => "discount", "label" => true, "i18n_template" => "discount" }],
}
@informative_text = {}
@depends_on = [{ "percentage_discount_invalid?" => true }]
end
def questions
@questions ||= [Form::Sales::Questions::PercentageDiscountValueCheck.new(nil, nil, self)]
end
end

4
app/models/form/sales/pages/shared_ownership_deposit_value_check.rb

@ -11,8 +11,8 @@ class Form::Sales::Pages::SharedOwnershipDepositValueCheck < ::Form::Page
"translation" => "soft_validations.shared_ownership_deposit.title_text", "translation" => "soft_validations.shared_ownership_deposit.title_text",
"arguments" => [ "arguments" => [
{ {
"key" => "expected_shared_ownership_deposit_value", "key" => "field_formatted_as_currency",
"label" => false, "arguments_for_key" => "expected_shared_ownership_deposit_value",
"i18n_template" => "expected_shared_ownership_deposit_value", "i18n_template" => "expected_shared_ownership_deposit_value",
}, },
], ],

1
app/models/form/sales/pages/uprn.rb

@ -6,6 +6,7 @@ class Form::Sales::Pages::Uprn < ::Form::Page
def questions def questions
@questions ||= [ @questions ||= [
Form::Sales::Questions::UprnKnown.new(nil, nil, self),
Form::Sales::Questions::Uprn.new(nil, nil, self), Form::Sales::Questions::Uprn.new(nil, nil, self),
] ]
end end

12
app/models/form/sales/pages/uprn_known.rb

@ -1,12 +0,0 @@
class Form::Sales::Pages::UprnKnown < ::Form::Page
def initialize(id, hsh, subsection)
super
@id = "uprn_known"
end
def questions
@questions ||= [
Form::Sales::Questions::UprnKnown.new(nil, nil, self),
]
end
end

24
app/models/form/sales/questions/buyer_live_in_value_check.rb

@ -0,0 +1,24 @@
class Form::Sales::Questions::BuyerLiveInValueCheck < ::Form::Question
def initialize(id, hsh, page, person_index:)
super(id, hsh, page)
@id = "buyer_livein_value_check"
@check_answer_label = "Buyer live in confirmation"
@type = "interruption_screen"
@answer_options = {
"0" => { "value" => "Yes" },
"1" => { "value" => "No" },
}
@hidden_in_check_answers = {
"depends_on" => [
{
"buyer_livein_value_check" => 0,
},
{
"buyer_livein_value_check" => 1,
},
],
}
@check_answers_card_number = person_index
@header = "Are you sure this is correct?"
end
end

23
app/models/form/sales/questions/percentage_discount_value_check.rb

@ -0,0 +1,23 @@
class Form::Sales::Questions::PercentageDiscountValueCheck < ::Form::Question
def initialize(id, hsh, page)
super
@id = "percentage_discount_value_check"
@check_answer_label = "Percentage discount confirmation"
@header = "Are you sure this is correct?"
@type = "interruption_screen"
@answer_options = {
"0" => { "value" => "Yes" },
"1" => { "value" => "No" },
}
@hidden_in_check_answers = {
"depends_on" => [
{
"percentage_discount_value_check" => 0,
},
{
"percentage_discount_value_check" => 1,
},
],
}
end
end

13
app/models/form/sales/questions/uprn.rb

@ -5,9 +5,14 @@ class Form::Sales::Questions::Uprn < ::Form::Question
@check_answer_label = "UPRN" @check_answer_label = "UPRN"
@header = "What is the property's UPRN" @header = "What is the property's UPRN"
@type = "text" @type = "text"
@hint_text = "The Unique Property Reference Number (UPRN) is a unique number system created by Ordnance Survey and used by housing providers and sectors UK-wide. For example 10010457355."
@width = 10 @width = 10
@question_number = 14 @question_number = 14
@inferred_check_answers_value = [
{
"condition" => { "uprn_known" => 0 },
"value" => "Not known",
},
]
end end
def unanswered_error_message def unanswered_error_message
@ -15,6 +20,8 @@ class Form::Sales::Questions::Uprn < ::Form::Question
end end
def get_extra_check_answer_value(log) def get_extra_check_answer_value(log)
return unless log.uprn_known == 1
value = [ value = [
log.address_line1, log.address_line1,
log.address_line2, log.address_line2,
@ -28,8 +35,4 @@ class Form::Sales::Questions::Uprn < ::Form::Question
"\n\n#{value.join("\n")}" "\n\n#{value.join("\n")}"
end end
def hidden_in_check_answers?(log, _current_user = nil)
log.uprn_known != 1
end
end end

8
app/models/form/sales/questions/uprn_known.rb

@ -8,6 +8,14 @@ class Form::Sales::Questions::UprnKnown < ::Form::Question
@answer_options = ANSWER_OPTIONS @answer_options = ANSWER_OPTIONS
@hint_text = "The Unique Property Reference Number (UPRN) is a unique number system created by Ordnance Survey and used by housing providers and sectors UK-wide. For example 10010457355.<br><br> @hint_text = "The Unique Property Reference Number (UPRN) is a unique number system created by Ordnance Survey and used by housing providers and sectors UK-wide. For example 10010457355.<br><br>
You can continue without the UPRN, but it means we will need you to enter the address of the property." You can continue without the UPRN, but it means we will need you to enter the address of the property."
@conditional_for = { "uprn" => [1] }
@inferred_check_answers_value = [
{
"condition" => { "uprn_known" => 0 },
"value" => "Not known",
},
]
@hidden_in_check_answers = true
end end
ANSWER_OPTIONS = { ANSWER_OPTIONS = {

1
app/models/form/sales/subsections/discounted_ownership_scheme.rb

@ -11,6 +11,7 @@ class Form::Sales::Subsections::DiscountedOwnershipScheme < ::Form::Subsection
Form::Sales::Pages::LivingBeforePurchase.new("living_before_purchase_discounted_ownership", nil, self, ownershipsch: 2), Form::Sales::Pages::LivingBeforePurchase.new("living_before_purchase_discounted_ownership", nil, self, ownershipsch: 2),
Form::Sales::Pages::AboutPriceRtb.new(nil, nil, self), Form::Sales::Pages::AboutPriceRtb.new(nil, nil, self),
Form::Sales::Pages::ExtraBorrowingValueCheck.new("extra_borrowing_price_value_check", nil, self), Form::Sales::Pages::ExtraBorrowingValueCheck.new("extra_borrowing_price_value_check", nil, self),
Form::Sales::Pages::PercentageDiscountValueCheck.new("percentage_discount_value_check", nil, self),
Form::Sales::Pages::AboutPriceNotRtb.new(nil, nil, self), Form::Sales::Pages::AboutPriceNotRtb.new(nil, nil, self),
Form::Sales::Pages::GrantValueCheck.new(nil, nil, self), Form::Sales::Pages::GrantValueCheck.new(nil, nil, self),
Form::Sales::Pages::PurchasePriceOutrightOwnership.new("purchase_price_discounted_ownership", nil, self, ownershipsch: 2), Form::Sales::Pages::PurchasePriceOutrightOwnership.new("purchase_price_discounted_ownership", nil, self, ownershipsch: 2),

2
app/models/form/sales/subsections/household_characteristics.rb

@ -26,6 +26,7 @@ class Form::Sales::Subsections::HouseholdCharacteristics < ::Form::Subsection
Form::Sales::Pages::RetirementValueCheck.new("working_situation_1_retirement_value_check", nil, self, person_index: 1), Form::Sales::Pages::RetirementValueCheck.new("working_situation_1_retirement_value_check", nil, self, person_index: 1),
Form::Sales::Pages::Buyer1IncomeValueCheck.new("working_situation_buyer_1_income_value_check", nil, self), Form::Sales::Pages::Buyer1IncomeValueCheck.new("working_situation_buyer_1_income_value_check", nil, self),
Form::Sales::Pages::Buyer1LiveInProperty.new(nil, nil, self), Form::Sales::Pages::Buyer1LiveInProperty.new(nil, nil, self),
Form::Sales::Pages::BuyerLiveInValueCheck.new("buyer_1_live_in_property_value_check", nil, self, person_index: 1),
Form::Sales::Pages::Buyer2RelationshipToBuyer1.new(nil, nil, self), Form::Sales::Pages::Buyer2RelationshipToBuyer1.new(nil, nil, self),
Form::Sales::Pages::PersonStudentNotChildValueCheck.new("buyer_2_relationship_student_not_child_value_check", nil, self, person_index: 2), Form::Sales::Pages::PersonStudentNotChildValueCheck.new("buyer_2_relationship_student_not_child_value_check", nil, self, person_index: 2),
Form::Sales::Pages::Age2.new(nil, nil, self), Form::Sales::Pages::Age2.new(nil, nil, self),
@ -40,6 +41,7 @@ class Form::Sales::Subsections::HouseholdCharacteristics < ::Form::Subsection
Form::Sales::Pages::Buyer2IncomeValueCheck.new("working_situation_buyer_2_income_value_check", nil, self), Form::Sales::Pages::Buyer2IncomeValueCheck.new("working_situation_buyer_2_income_value_check", nil, self),
Form::Sales::Pages::PersonStudentNotChildValueCheck.new("buyer_2_working_situation_student_not_child_value_check", nil, self, person_index: 2), Form::Sales::Pages::PersonStudentNotChildValueCheck.new("buyer_2_working_situation_student_not_child_value_check", nil, self, person_index: 2),
Form::Sales::Pages::Buyer2LiveInProperty.new(nil, nil, self), Form::Sales::Pages::Buyer2LiveInProperty.new(nil, nil, self),
Form::Sales::Pages::BuyerLiveInValueCheck.new("buyer_2_live_in_property_value_check", nil, self, person_index: 2),
Form::Sales::Pages::NumberOfOthersInProperty.new("number_of_others_in_property", nil, self, joint_purchase: false), Form::Sales::Pages::NumberOfOthersInProperty.new("number_of_others_in_property", nil, self, joint_purchase: false),
Form::Sales::Pages::NumberOfOthersInProperty.new("number_of_others_in_property_joint_purchase", nil, self, joint_purchase: true), Form::Sales::Pages::NumberOfOthersInProperty.new("number_of_others_in_property_joint_purchase", nil, self, joint_purchase: true),
Form::Sales::Pages::PersonKnown.new("person_2_known", nil, self, person_index: 2), Form::Sales::Pages::PersonKnown.new("person_2_known", nil, self, person_index: 2),

2
app/models/form/sales/subsections/property_information.rb

@ -13,6 +13,7 @@ class Form::Sales::Subsections::PropertyInformation < ::Form::Subsection
Form::Sales::Pages::AboutPriceValueCheck.new("about_price_bedrooms_value_check", nil, self), Form::Sales::Pages::AboutPriceValueCheck.new("about_price_bedrooms_value_check", nil, self),
Form::Sales::Pages::PropertyUnitType.new(nil, nil, self), Form::Sales::Pages::PropertyUnitType.new(nil, nil, self),
Form::Sales::Pages::MonthlyChargesValueCheck.new("monthly_charges_property_type_value_check", nil, self), Form::Sales::Pages::MonthlyChargesValueCheck.new("monthly_charges_property_type_value_check", nil, self),
Form::Sales::Pages::PercentageDiscountValueCheck.new("percentage_discount_proptype_value_check", nil, self),
Form::Sales::Pages::PropertyBuildingType.new(nil, nil, self), Form::Sales::Pages::PropertyBuildingType.new(nil, nil, self),
postcode_and_la_questions, postcode_and_la_questions,
Form::Sales::Pages::AboutPriceValueCheck.new("about_price_la_value_check", nil, self), Form::Sales::Pages::AboutPriceValueCheck.new("about_price_la_value_check", nil, self),
@ -23,7 +24,6 @@ class Form::Sales::Subsections::PropertyInformation < ::Form::Subsection
def uprn_questions def uprn_questions
if form.start_date.year >= 2023 if form.start_date.year >= 2023
[ [
Form::Sales::Pages::UprnKnown.new(nil, nil, self),
Form::Sales::Pages::Uprn.new(nil, nil, self), Form::Sales::Pages::Uprn.new(nil, nil, self),
Form::Sales::Pages::UprnConfirmation.new(nil, nil, self), Form::Sales::Pages::UprnConfirmation.new(nil, nil, self),
Form::Sales::Pages::Address.new(nil, nil, self), Form::Sales::Pages::Address.new(nil, nil, self),

2
app/models/form/sales/subsections/setup.rb

@ -19,6 +19,8 @@ class Form::Sales::Subsections::Setup < ::Form::Subsection
Form::Sales::Pages::OldPersonsSharedOwnershipValueCheck.new("ownership_type_old_persons_shared_ownership_value_check", nil, self), Form::Sales::Pages::OldPersonsSharedOwnershipValueCheck.new("ownership_type_old_persons_shared_ownership_value_check", nil, self),
Form::Sales::Pages::MonthlyChargesValueCheck.new("monthly_charges_type_value_check", nil, self), Form::Sales::Pages::MonthlyChargesValueCheck.new("monthly_charges_type_value_check", nil, self),
Form::Sales::Pages::DiscountedSaleValueCheck.new("discounted_sale_type_value_check", nil, self), Form::Sales::Pages::DiscountedSaleValueCheck.new("discounted_sale_type_value_check", nil, self),
Form::Sales::Pages::BuyerLiveInValueCheck.new("buyer_1_live_in_property_type_value_check", nil, self, person_index: 1),
Form::Sales::Pages::BuyerLiveInValueCheck.new("buyer_2_live_in_property_type_value_check", nil, self, person_index: 2),
Form::Sales::Pages::BuyerCompany.new(nil, nil, self), Form::Sales::Pages::BuyerCompany.new(nil, nil, self),
Form::Sales::Pages::BuyerLive.new(nil, nil, self), Form::Sales::Pages::BuyerLive.new(nil, nil, self),
Form::Sales::Pages::JointPurchase.new(nil, nil, self), Form::Sales::Pages::JointPurchase.new(nil, nil, self),

26
app/models/lettings_log.rb

@ -58,7 +58,7 @@ class LettingsLog < Log
OPTIONAL_FIELDS = %w[rent_value_check first_time_property_let_as_social_housing tenancycode propcode chcharge].freeze OPTIONAL_FIELDS = %w[rent_value_check first_time_property_let_as_social_housing tenancycode propcode chcharge].freeze
RENT_TYPE_MAPPING_LABELS = { 1 => "Social Rent", 2 => "Affordable Rent", 3 => "Intermediate Rent" }.freeze RENT_TYPE_MAPPING_LABELS = { 1 => "Social Rent", 2 => "Affordable Rent", 3 => "Intermediate Rent" }.freeze
HAS_BENEFITS_OPTIONS = [1, 6, 8, 7].freeze HAS_BENEFITS_OPTIONS = [1, 6, 8, 7].freeze
NUM_OF_WEEKS_FROM_PERIOD = { 2 => 26, 3 => 13, 4 => 12, 5 => 50, 6 => 49, 7 => 48, 8 => 47, 9 => 46, 1 => 52 }.freeze NUM_OF_WEEKS_FROM_PERIOD = { 2 => 26, 3 => 13, 4 => 12, 5 => 50, 6 => 49, 7 => 48, 8 => 47, 9 => 46, 1 => 52, 10 => 53 }.freeze
SUFFIX_FROM_PERIOD = { 2 => "every 2 weeks", 3 => "every 4 weeks", 4 => "every month" }.freeze SUFFIX_FROM_PERIOD = { 2 => "every 2 weeks", 3 => "every 4 weeks", 4 => "every month" }.freeze
RETIREMENT_AGES = { "M" => 67, "F" => 60, "X" => 67 }.freeze RETIREMENT_AGES = { "M" => 67, "F" => 60, "X" => 67 }.freeze
@ -203,7 +203,7 @@ class LettingsLog < Log
needstype == 2 needstype == 2
end end
def has_hbrentshortfall? def has_housing_benefit_rent_shortfall?
# 1: Yes # 1: Yes
hbrentshortfall == 1 hbrentshortfall == 1
end end
@ -506,7 +506,27 @@ class LettingsLog < Log
end end
def care_home_charge_expected_not_provided? def care_home_charge_expected_not_provided?
is_carehome == 1 && chcharge.blank? is_carehome? && chcharge.blank?
end
def rent_and_charges_paid_weekly?
[1, 5, 6, 7, 8, 9, 10].include? period
end
def rent_and_charges_paid_every_4_weeks?
period == 3
end
def rent_and_charges_paid_every_2_weeks?
period == 2
end
def rent_and_charges_paid_monthly?
period == 4
end
def is_carehome?
is_carehome == 1
end end
private private

1
app/models/location.rb

@ -24,6 +24,7 @@ class Location < ApplicationRecord
scope :started, -> { where("startdate <= ?", Time.zone.today).or(where(startdate: nil)) } scope :started, -> { where("startdate <= ?", Time.zone.today).or(where(startdate: nil)) }
scope :active, -> { where(confirmed: true).and(started) } scope :active, -> { where(confirmed: true).and(started) }
scope :confirmed, -> { where(confirmed: true) } scope :confirmed, -> { where(confirmed: true) }
scope :unconfirmed, -> { where.not(confirmed: true) }
LOCAL_AUTHORITIES = LocalAuthority.all.map { |la| [la.name, la.code] }.to_h LOCAL_AUTHORITIES = LocalAuthority.all.map { |la| [la.name, la.code] }.to_h

17
app/models/log.rb

@ -1,4 +1,6 @@
class Log < ApplicationRecord class Log < ApplicationRecord
include CollectionTimeHelper
self.abstract_class = true self.abstract_class = true
belongs_to :owning_organisation, class_name: "Organisation", optional: true belongs_to :owning_organisation, class_name: "Organisation", optional: true
@ -50,6 +52,7 @@ class Log < ApplicationRecord
presenter = UprnDataPresenter.new(service.result) presenter = UprnDataPresenter.new(service.result)
self.uprn_known = 1
self.uprn_confirmed = nil self.uprn_confirmed = nil
self.address_line1 = presenter.address_line1 self.address_line1 = presenter.address_line1
self.address_line2 = presenter.address_line2 self.address_line2 = presenter.address_line2
@ -87,6 +90,8 @@ class Log < ApplicationRecord
end end
def collection_period_open? def collection_period_open?
return false if older_than_previous_collection_year?
form.end_date > Time.zone.today form.end_date > Time.zone.today
end end
@ -126,8 +131,20 @@ class Log < ApplicationRecord
end end
end end
def field_formatted_as_currency(field_name)
field_value = public_send(field_name)
format_as_currency(field_value)
end
private private
# Handle logs that are older than previous collection start date
def older_than_previous_collection_year?
return false unless startdate
startdate < previous_collection_start_date
end
def plural_gender_for_person(person_num) def plural_gender_for_person(person_num)
gender = public_send("sex#{person_num}".to_sym) gender = public_send("sex#{person_num}".to_sym)
return unless gender return unless gender

20
app/models/sales_log.rb

@ -43,7 +43,7 @@ class SalesLog < Log
} }
scope :filter_by_organisation, ->(org, _user = nil) { where(owning_organisation: org) } scope :filter_by_organisation, ->(org, _user = nil) { where(owning_organisation: org) }
OPTIONAL_FIELDS = %w[saledate_check purchid monthly_charges_value_check old_persons_shared_ownership_value_check othtype discounted_sale_value_check].freeze OPTIONAL_FIELDS = %w[saledate_check purchid monthly_charges_value_check old_persons_shared_ownership_value_check othtype discounted_sale_value_check buyer_livein_value_check].freeze
RETIREMENT_AGES = { "M" => 65, "F" => 60, "X" => 65 }.freeze RETIREMENT_AGES = { "M" => 65, "F" => 60, "X" => 65 }.freeze
def lettings? def lettings?
@ -216,7 +216,7 @@ class SalesLog < Log
def expected_shared_ownership_deposit_value def expected_shared_ownership_deposit_value
return unless value && equity return unless value && equity
format_as_currency(value * equity / 100) value * equity / 100
end end
def process_postcode(postcode, postcode_known_key, la_inferred_key, la_key) def process_postcode(postcode, postcode_known_key, la_inferred_key, la_key)
@ -323,11 +323,6 @@ class SalesLog < Log
format_as_currency(soft_min) format_as_currency(soft_min)
end end
def field_formatted_as_currency(field_name)
field_value = public_send(field_name)
format_as_currency(field_value)
end
def should_process_uprn_change? def should_process_uprn_change?
uprn_changed? && saledate && saledate.year >= 2023 uprn_changed? && saledate && saledate.year >= 2023
end end
@ -350,4 +345,15 @@ class SalesLog < Log
def beds_for_la_sale_range def beds_for_la_sale_range
beds.nil? ? nil : [beds, LaSaleRange::MAX_BEDS].min beds.nil? ? nil : [beds, LaSaleRange::MAX_BEDS].min
end end
def ownership_scheme
case ownershipsch
when 1
"shared ownership"
when 2
"discounted ownership"
when 3
"outright sale"
end
end
end end

12
app/models/scheme.rb

@ -161,18 +161,6 @@ class Scheme < ApplicationRecord
] ]
end end
def synonyms
locations.map(&:postcode).join(",")
end
def appended_text
"#{locations.count { |location| location.startdate.blank? || location.startdate <= Time.zone.today }} locations"
end
def hint
[primary_client_group, secondary_client_group].filter(&:present?).join(", ")
end
def care_acts_options_with_hints def care_acts_options_with_hints
hints = { "Yes – part registered as a care home": "A proportion of units are registered as being a care home." } hints = { "Yes – part registered as a care home": "A proportion of units are registered as being a care home." }

8
app/models/validations/financial_validations.rb

@ -4,7 +4,7 @@ module Validations::FinancialValidations
# Validations methods need to be called 'validate_<page_name>' to run on model save # Validations methods need to be called 'validate_<page_name>' to run on model save
# or 'validate_' to run on submit as well # or 'validate_' to run on submit as well
def validate_outstanding_rent_amount(record) def validate_outstanding_rent_amount(record)
if !record.has_hbrentshortfall? && record.tshortfall.present? if !record.has_housing_benefit_rent_shortfall? && record.tshortfall.present?
record.errors.add :tshortfall, :no_outstanding_charges, message: I18n.t("validations.financial.tshortfall.outstanding_amount_not_required") record.errors.add :tshortfall, :no_outstanding_charges, message: I18n.t("validations.financial.tshortfall.outstanding_amount_not_required")
end end
end end
@ -69,7 +69,7 @@ module Validations::FinancialValidations
end end
def validate_tshortfall(record) def validate_tshortfall(record)
if record.has_hbrentshortfall? && no_known_benefits?(record) if record.has_housing_benefit_rent_shortfall? && no_known_benefits?(record)
record.errors.add :tshortfall, I18n.t("validations.financial.hbrentshortfall.outstanding_no_benefits") record.errors.add :tshortfall, I18n.t("validations.financial.hbrentshortfall.outstanding_no_benefits")
end end
end end
@ -99,7 +99,7 @@ module Validations::FinancialValidations
end end
if record.tcharge.present? && weekly_value_in_range(record, "tcharge", 0, 9.99) if record.tcharge.present? && weekly_value_in_range(record, "tcharge", 0, 9.99)
record.errors.add :tcharge, I18n.t("validations.financial.tcharge.under_10") record.errors.add :tcharge, :under_10, message: I18n.t("validations.financial.tcharge.under_10")
end end
answered_questions = [record.tcharge, record.chcharge].concat(record.household_charge && record.household_charge == 1 ? [record.household_charge] : []) answered_questions = [record.tcharge, record.chcharge].concat(record.household_charge && record.household_charge == 1 ? [record.household_charge] : [])
@ -224,7 +224,7 @@ private
end end
if record.weekly_value(record["brent"]) > rent_range.hard_max if record.weekly_value(record["brent"]) > rent_range.hard_max
record.errors.add :brent, I18n.t("validations.financial.brent.above_hard_max") record.errors.add :brent, :over_hard_max, message: I18n.t("validations.financial.brent.above_hard_max")
record.errors.add :beds, I18n.t("validations.financial.brent.beds.above_hard_max") record.errors.add :beds, I18n.t("validations.financial.brent.beds.above_hard_max")
record.errors.add :la, I18n.t("validations.financial.brent.la.above_hard_max") record.errors.add :la, I18n.t("validations.financial.brent.la.above_hard_max")
record.errors.add :postcode_known, I18n.t("validations.financial.brent.postcode_known.above_hard_max") record.errors.add :postcode_known, I18n.t("validations.financial.brent.postcode_known.above_hard_max")

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

@ -48,7 +48,7 @@ module Validations::Sales::SaleInformationValidations
end end
def validate_discounted_ownership_value(record) def validate_discounted_ownership_value(record)
return unless record.saledate && collection_start_year(record.saledate) >= 2024 return unless record.saledate && collection_start_year_for_date(record.saledate) >= 2024
return unless record.value && record.deposit && record.ownershipsch return unless record.value && record.deposit && record.ownershipsch
return unless record.mortgage || record.mortgageused == 2 return unless record.mortgage || record.mortgageused == 2
return unless record.discount || record.grant || record.type == 29 return unless record.discount || record.grant || record.type == 29

24
app/models/validations/sales/soft_validations.rb

@ -123,6 +123,30 @@ module Validations::Sales::SoftValidations
mortgage_deposit_and_grant_total != value_with_discount && discounted_ownership_sale? mortgage_deposit_and_grant_total != value_with_discount && discounted_ownership_sale?
end end
def buyer1_livein_wrong_for_ownership_type?
return unless ownershipsch && buy1livein
(discounted_ownership_sale? || shared_ownership_scheme?) && buy1livein == 2
end
def buyer2_livein_wrong_for_ownership_type?
return unless ownershipsch && buy2livein
return unless joint_purchase?
(discounted_ownership_sale? || shared_ownership_scheme?) && buy2livein == 2
end
def percentage_discount_invalid?
return unless discount && proptype
case proptype
when 1, 2
discount > 50
when 3, 4, 9
discount > 35
end
end
private private
def sale_range def sale_range

8
app/models/validations/setup_validations.rb

@ -20,6 +20,14 @@ module Validations::SetupValidations
location_during_startdate_validation(record, :location_id) location_during_startdate_validation(record, :location_id)
end end
def validate_scheme_has_confirmed_locations_validation(record)
return unless record.scheme
unless record.scheme.locations.confirmed.any?
record.errors.add :scheme_id, I18n.t("validations.scheme.no_completed_locations")
end
end
def validate_scheme(record) def validate_scheme(record)
location_during_startdate_validation(record, :scheme_id) location_during_startdate_validation(record, :scheme_id)
scheme_during_startdate_validation(record, :scheme_id) scheme_during_startdate_validation(record, :scheme_id)

1
app/models/validations/shared_validations.rb

@ -7,6 +7,7 @@ module Validations::SharedValidations
main_field_label = main_label || main_field.to_s.humanize(capitalize: false) main_field_label = main_label || main_field.to_s.humanize(capitalize: false)
other_field_label = other_label || other_field.to_s.humanize(capitalize: false) other_field_label = other_label || other_field.to_s.humanize(capitalize: false)
if record[main_field] == value_other && record[other_field].blank? if record[main_field] == value_other && record[other_field].blank?
record.errors.add main_field.to_sym, I18n.t("validations.other_field_missing", main_field_label:, other_field_label:)
record.errors.add other_field.to_sym, I18n.t("validations.other_field_missing", main_field_label:, other_field_label:) record.errors.add other_field.to_sym, I18n.t("validations.other_field_missing", main_field_label:, other_field_label:)
end end

68
app/services/bulk_upload/lettings/year2022/row_parser.rb

@ -14,37 +14,37 @@ class BulkUpload::Lettings::Year2022::RowParser
field_9: "What is the tenancy type?", field_9: "What is the tenancy type?",
field_10: "If 'Other', what is the tenancy type?", field_10: "If 'Other', what is the tenancy type?",
field_11: "What is the length of the fixed-term tenancy to the nearest year?", field_11: "What is the length of the fixed-term tenancy to the nearest year?",
field_12: "Age of Person 1", field_12: "Age of person 1",
field_13: "Age of Person 2", field_13: "Age of person 2",
field_14: "Age of Person 3", field_14: "Age of person 3",
field_15: "Age of Person 4", field_15: "Age of person 4",
field_16: "Age of Person 5", field_16: "Age of person 5",
field_17: "Age of Person 6", field_17: "Age of person 6",
field_18: "Age of Person 7", field_18: "Age of person 7",
field_19: "Age of Person 8", field_19: "Age of person 8",
field_20: "Gender identity of Person 1", field_20: "Gender identity of person 1",
field_21: "Gender identity of Person 2", field_21: "Gender identity of person 2",
field_22: "Gender identity of Person 3", field_22: "Gender identity of person 3",
field_23: "Gender identity of Person 4", field_23: "Gender identity of person 4",
field_24: "Gender identity of Person 5", field_24: "Gender identity of person 5",
field_25: "Gender identity of Person 6", field_25: "Gender identity of person 6",
field_26: "Gender identity of Person 7", field_26: "Gender identity of person 7",
field_27: "Gender identity of Person 8", field_27: "Gender identity of person 8",
field_28: "Relationship to Person 1 for Person 2", field_28: "Relationship to person 1 for person 2",
field_29: "Relationship to Person 1 for Person 3", field_29: "Relationship to person 1 for person 3",
field_30: "Relationship to Person 1 for Person 4", field_30: "Relationship to person 1 for person 4",
field_31: "Relationship to Person 1 for Person 5", field_31: "Relationship to person 1 for person 5",
field_32: "Relationship to Person 1 for Person 6", field_32: "Relationship to person 1 for person 6",
field_33: "Relationship to Person 1 for Person 7", field_33: "Relationship to person 1 for person 7",
field_34: "Relationship to Person 1 for Person 8", field_34: "Relationship to person 1 for person 8",
field_35: "Working situation of Person 1", field_35: "Working situation of person 1",
field_36: "Working situation of Person 2", field_36: "Working situation of person 2",
field_37: "Working situation of Person 3", field_37: "Working situation of person 3",
field_38: "Working situation of Person 4", field_38: "Working situation of person 4",
field_39: "Working situation of Person 5", field_39: "Working situation of person 5",
field_40: "Working situation of Person 6", field_40: "Working situation of person 6",
field_41: "Working situation of Person 7", field_41: "Working situation of person 7",
field_42: "Working situation of Person 8", field_42: "Working situation of person 8",
field_43: "What is the lead tenant's ethnic group?", field_43: "What is the lead tenant's ethnic group?",
field_44: "What is the lead tenant's nationality?", field_44: "What is the lead tenant's nationality?",
field_45: "Does anybody in the household have links to the UK armed forces?", field_45: "Does anybody in the household have links to the UK armed forces?",
@ -340,10 +340,10 @@ class BulkUpload::Lettings::Year2022::RowParser
return true if blank_row? return true if blank_row?
super
log.valid? log.valid?
super
log.errors.each do |error| log.errors.each do |error|
fields = field_mapping_for_errors[error.attribute] || [] fields = field_mapping_for_errors[error.attribute] || []
@ -650,7 +650,7 @@ private
end end
def questions def questions
log.form.subsections.flat_map { |ss| ss.applicable_questions(log) } @questions ||= log.form.subsections.flat_map { |ss| ss.applicable_questions(log) }
end end
def validate_nulls def validate_nulls

9
app/services/bulk_upload/lettings/year2023/row_parser.rb

@ -292,6 +292,7 @@ class BulkUpload::Lettings::Year2023::RowParser
validates :field_72, format: { with: /\A\d{1,3}\z|\AR\z/, message: "Age of person 7 must be a number or the letter R" }, allow_blank: true validates :field_72, format: { with: /\A\d{1,3}\z|\AR\z/, message: "Age of person 7 must be a number or the letter R" }, allow_blank: true
validates :field_76, format: { with: /\A\d{1,3}\z|\AR\z/, message: "Age of person 8 must be a number or the letter R" }, allow_blank: true validates :field_76, format: { with: /\A\d{1,3}\z|\AR\z/, message: "Age of person 8 must be a number or the letter R" }, allow_blank: true
validates :field_6, presence: { message: I18n.t("validations.not_answered", question: "property renewal") }
validates :field_7, presence: { message: I18n.t("validations.not_answered", question: "tenancy start date (day)") } validates :field_7, presence: { message: I18n.t("validations.not_answered", question: "tenancy start date (day)") }
validates :field_8, presence: { message: I18n.t("validations.not_answered", question: "tenancy start date (month)") } validates :field_8, presence: { message: I18n.t("validations.not_answered", question: "tenancy start date (month)") }
validates :field_9, presence: { message: I18n.t("validations.not_answered", question: "tenancy start date (year)") } validates :field_9, presence: { message: I18n.t("validations.not_answered", question: "tenancy start date (year)") }
@ -342,10 +343,10 @@ class BulkUpload::Lettings::Year2023::RowParser
return true if blank_row? return true if blank_row?
super
log.valid? log.valid?
super
log.errors.each do |error| log.errors.each do |error|
fields = field_mapping_for_errors[error.attribute] || [] fields = field_mapping_for_errors[error.attribute] || []
@ -826,7 +827,7 @@ private
end end
def questions def questions
log.form.subsections.flat_map { |ss| ss.applicable_questions(log) } @questions ||= log.form.subsections.flat_map { |ss| ss.applicable_questions(log) }
end end
def attributes_for_log def attributes_for_log
@ -1050,8 +1051,6 @@ private
1 1
when 2 when 2
0 0
when nil
rsnvac == 14 ? 1 : 0
else else
field_6 field_6
end end

46
app/services/bulk_upload/sales/year2022/row_parser.rb

@ -9,29 +9,29 @@ class BulkUpload::Sales::Year2022::RowParser
field_4: "What is the year of the sale completion date? - YY", field_4: "What is the year of the sale completion date? - YY",
field_5: "This question has been removed", field_5: "This question has been removed",
field_6: "Was the buyer interviewed for any of the answers you will provide on this log?", field_6: "Was the buyer interviewed for any of the answers you will provide on this log?",
field_7: "Age of Buyer 1", field_7: "Age of buyer 1",
field_8: "Age of Person 2", field_8: "Age of person 2",
field_9: "Age of Person 3", field_9: "Age of person 3",
field_10: "Age of Person 4", field_10: "Age of person 4",
field_11: "Age of Person 5", field_11: "Age of person 5",
field_12: "Age of Person 6", field_12: "Age of person 6",
field_13: "Gender identity of Buyer 1", field_13: "Gender identity of buyer 1",
field_14: "Gender identity of Person 2", field_14: "Gender identity of person 2",
field_15: "Gender identity of Person 3", field_15: "Gender identity of person 3",
field_16: "Gender identity of Person 4", field_16: "Gender identity of person 4",
field_17: "Gender identity of Person 5", field_17: "Gender identity of person 5",
field_18: "Gender identity of Person 6", field_18: "Gender identity of person 6",
field_19: "Relationship to Buyer 1 for Person 2", field_19: "Relationship to buyer 1 for person 2",
field_20: "Relationship to Buyer 1 for Person 3", field_20: "Relationship to buyer 1 for person 3",
field_21: "Relationship to Buyer 1 for Person 4", field_21: "Relationship to buyer 1 for person 4",
field_22: "Relationship to Buyer 1 for Person 5", field_22: "Relationship to buyer 1 for person 5",
field_23: "Relationship to Buyer 1 for Person 6", field_23: "Relationship to buyer 1 for person 6",
field_24: "Working situation of Buyer 1", field_24: "Working situation of buyer 1",
field_25: "Working situation of Person 2", field_25: "Working situation of person 2",
field_26: "Working situation of Person 3", field_26: "Working situation of person 3",
field_27: "Working situation of Person 4", field_27: "Working situation of person 4",
field_28: "Working situation of Person 5", field_28: "Working situation of person 5",
field_29: "Working situation of Person 6", field_29: "Working situation of person 6",
field_30: "What is buyer 1's ethnic group?", field_30: "What is buyer 1's ethnic group?",
field_31: "What is buyer 1's nationality?", field_31: "What is buyer 1's nationality?",
field_32: "What is buyer 1's gross annual income?", field_32: "What is buyer 1's gross annual income?",

9
app/services/exports/lettings_log_export_service.rb

@ -12,19 +12,20 @@ module Exports
start_time = Time.zone.now start_time = Time.zone.now
logs_by_collection = retrieve_lettings_logs(start_time, full_update).group_by(&:collection_start_year) logs_by_collection = retrieve_lettings_logs(start_time, full_update).group_by(&:collection_start_year)
daily_run_number = get_daily_run_number daily_run_number = get_daily_run_number
archives_for_manifest = [] archives_for_manifest = {}
base_number = LogsExport.where(empty_export: false).maximum(:base_number) || 1 base_number = LogsExport.where(empty_export: false).maximum(:base_number) || 1
available_collection_years.each do |collection| available_collection_years.each do |collection|
lettings_logs = logs_by_collection.fetch(collection, LettingsLog.none) lettings_logs = logs_by_collection.fetch(collection, LettingsLog.none)
export = build_export_run(collection, start_time, base_number, full_update) export = build_export_run(collection, start_time, base_number, full_update)
archives = write_export_archive(export, lettings_logs) archives = write_export_archive(export, lettings_logs)
archives_for_manifest << archives if archives.any? archives_for_manifest.merge!(archives)
export.empty_export = archives.empty? export.empty_export = archives.empty?
export.save! export.save!
end end
write_master_manifest(daily_run_number, archives_for_manifest.flatten) write_master_manifest(daily_run_number, archives_for_manifest)
end end
private private
@ -129,7 +130,7 @@ module Exports
headers = ["zip-name", "date-time zipped folder generated", "zip-file-uri"] headers = ["zip-name", "date-time zipped folder generated", "zip-file-uri"]
csv_string = CSV.generate do |csv| csv_string = CSV.generate do |csv|
csv << headers csv << headers
archive_datetimes.each do |archive, datetime| archive_datetimes.each do |(archive, datetime)|
csv << [archive, datetime, "#{archive}.zip"] csv << [archive, datetime, "#{archive}.zip"]
end end
end end

10
config/initializers/feature_toggle.rb → app/services/feature_toggle.rb

@ -36,7 +36,11 @@ class FeatureToggle
true true
end end
def self.bulk_upload_logs? def self.bulk_upload_lettings_logs?
!Rails.env.production?
end
def self.bulk_upload_sales_logs?
!Rails.env.production? !Rails.env.production?
end end
@ -53,4 +57,8 @@ class FeatureToggle
def self.collection_2023_2024_year_enabled? def self.collection_2023_2024_year_enabled?
true true
end end
def self.merge_organisations_enabled?
!Rails.env.production?
end
end end

2
app/services/imports/lettings_logs_import_service.rb

@ -302,6 +302,8 @@ module Imports
%i[supcharg outside_the_range] => %w[brent scharge pscharge supcharg tcharge], %i[supcharg outside_the_range] => %w[brent scharge pscharge supcharg tcharge],
%i[scharge outside_the_range] => %w[brent scharge pscharge supcharg tcharge], %i[scharge outside_the_range] => %w[brent scharge pscharge supcharg tcharge],
%i[location_id not_active] => %w[location_id scheme_id], %i[location_id not_active] => %w[location_id scheme_id],
%i[tcharge under_10] => %w[brent scharge pscharge supcharg tcharge],
%i[brent over_hard_max] => %w[brent scharge pscharge supcharg tcharge],
} }
(2..8).each do |person| (2..8).each do |person|

6
app/services/imports/sales_logs_import_service.rb

@ -155,6 +155,8 @@ module Imports
attributes["monthly_charges_value_check"] = 0 attributes["monthly_charges_value_check"] = 0
attributes["student_not_child_value_check"] = 0 attributes["student_not_child_value_check"] = 0
attributes["discounted_sale_value_check"] = 0 attributes["discounted_sale_value_check"] = 0
attributes["buyer_livein_value_check"] = 0
attributes["percentage_discount_value_check"] = 0
# Sets the log creator # Sets the log creator
owner_id = meta_field_value(xml_doc, "owner-user-id").strip owner_id = meta_field_value(xml_doc, "owner-user-id").strip
@ -278,7 +280,9 @@ module Imports
hodate_check hodate_check
saledate_check saledate_check
student_not_child_value_check student_not_child_value_check
discounted_sale_value_check] discounted_sale_value_check
buyer_livein_value_check
percentage_discount_value_check]
end end
def check_status_completed(sales_log, previous_status) def check_status_completed(sales_log, previous_status)

6
app/views/bulk_upload_lettings_logs/forms/checking_file.html.erb

@ -10,14 +10,14 @@
<span class="govuk-caption-l">Upload lettings logs in bulk (<%= @form.year_combo %>)</span> <span class="govuk-caption-l">Upload lettings logs in bulk (<%= @form.year_combo %>)</span>
<h1 class="govuk-heading-l">We’re checking the file</h1> <h1 class="govuk-heading-l">We’re checking the file</h1>
<h2 class="govuk-heading-m">Once this is done, we’ll email you the outcome.</h2> <h2 class="govuk-heading-s">Once this is done, we’ll email you the outcome.</h2>
<p class="govuk-body"> <p class="govuk-body">
We’re checking for any missing data, issues or errors. Depending on the file size, this could take a few minutes. We’re checking for any missing data, issues or errors. Depending on file size, this could take a few minutes.
</p> </p>
<p class="govuk-body"> <p class="govuk-body">
If there are errors we will email you a link to view all the errors. If there are errors, we will email you to let you know how to fix them.
</p> </p>
<p class="govuk-body"> <p class="govuk-body">

1
app/views/bulk_upload_lettings_logs/forms/prepare_your_file.html.erb

@ -19,6 +19,7 @@
<h2 class="govuk-heading-s">Create your file</h2> <h2 class="govuk-heading-s">Create your file</h2>
<ul class="govuk-list govuk-list--bullet"> <ul class="govuk-list govuk-list--bullet">
<li>Fill in the template with CORE data from your housing management system according to the <%= govuk_link_to "Lettings #{@form.year_combo} Bulk Upload Specification", @form.specification_path %></li> <li>Fill in the template with CORE data from your housing management system according to the <%= govuk_link_to "Lettings #{@form.year_combo} Bulk Upload Specification", @form.specification_path %></li>
<li><strong>Username field:</strong> To assign a log to someone else, enter the email address they use to log into CORE</li>
<li>If you have to manually enter large volumes of data into the bulk upload template, we recommend creating logs directly in the service instead. <%= govuk_link_to "Find out more about exporting your data", bulk_upload_lettings_log_path(id: "guidance", form: { year: @form.year }) %></li> <li>If you have to manually enter large volumes of data into the bulk upload template, we recommend creating logs directly in the service instead. <%= govuk_link_to "Find out more about exporting your data", bulk_upload_lettings_log_path(id: "guidance", form: { year: @form.year }) %></li>
</ul> </ul>

2
app/views/bulk_upload_lettings_results/show.html.erb

@ -13,7 +13,7 @@
<div class="govuk-grid-row"> <div class="govuk-grid-row">
<div class="govuk-grid-column-full"> <div class="govuk-grid-column-full">
<% @bulk_upload.bulk_upload_errors.group_by(&:row).each do |_row, errors_for_row| %> <% @bulk_upload.bulk_upload_errors.order_by_cell.group_by(&:row).each do |_row, errors_for_row| %>
<%= render BulkUploadErrorRowComponent.new(bulk_upload_errors: errors_for_row) %> <%= render BulkUploadErrorRowComponent.new(bulk_upload_errors: errors_for_row) %>
<% end %> <% end %>
</div> </div>

6
app/views/bulk_upload_sales_logs/forms/checking_file.html.erb

@ -10,14 +10,14 @@
<span class="govuk-caption-l">Upload sales logs in bulk (<%= @form.year_combo %>)</span> <span class="govuk-caption-l">Upload sales logs in bulk (<%= @form.year_combo %>)</span>
<h1 class="govuk-heading-l">We’re checking the file</h1> <h1 class="govuk-heading-l">We’re checking the file</h1>
<h2 class="govuk-heading-m">Once this is done, we’ll email you the outcome.</h2> <h2 class="govuk-heading-s">Once this is done, we’ll email you the outcome.</h2>
<p class="govuk-body"> <p class="govuk-body">
We’re checking for any missing data, issues or errors. Depending on the file size, this could take a few minutes. We’re checking for any missing data, issues or errors. Depending on file size, this could take a few minutes.
</p> </p>
<p class="govuk-body"> <p class="govuk-body">
If there are errors we will email you a link to view all the errors. If there are errors, we will email you to let you know how to fix them.
</p> </p>
<p class="govuk-body"> <p class="govuk-body">

1
app/views/bulk_upload_sales_logs/forms/prepare_your_file.html.erb

@ -19,6 +19,7 @@
<h2 class="govuk-heading-s">Create your file</h2> <h2 class="govuk-heading-s">Create your file</h2>
<ul class="govuk-list govuk-list--bullet"> <ul class="govuk-list govuk-list--bullet">
<li>Fill in the template with CORE data from your housing management system according to the <%= govuk_link_to "Sales #{@form.year_combo} Bulk Upload Specification", @form.specification_path %></li> <li>Fill in the template with CORE data from your housing management system according to the <%= govuk_link_to "Sales #{@form.year_combo} Bulk Upload Specification", @form.specification_path %></li>
<li><strong>Username field:</strong> To assign a log to someone else, enter the email address they use to log into CORE</li>
<li>If you have to manually enter large volumes of data into the bulk upload template, we recommend creating logs directly in the service instead. <%= govuk_link_to "Find out more about exporting your data", bulk_upload_sales_log_path(id: "guidance", form: { year: @form.year }) %></li> <li>If you have to manually enter large volumes of data into the bulk upload template, we recommend creating logs directly in the service instead. <%= govuk_link_to "Find out more about exporting your data", bulk_upload_sales_log_path(id: "guidance", form: { year: @form.year }) %></li>
</ul> </ul>

16
app/views/form/_select_question.html.erb

@ -7,14 +7,14 @@
"data-controller": "accessible-autocomplete", "data-controller": "accessible-autocomplete",
caption: caption(caption_text, page_header, conditional), caption: caption(caption_text, page_header, conditional),
hint: { text: question.hint_text&.html_safe }) do %> hint: { text: question.hint_text&.html_safe }) do %>
<% answers.each do |answer| %> <% answers.each do |answer| %>
<option value="<%= answer.id %>" <option value="<%= answer.id %>"
data-synonyms="<%= question.answer_option_synonyms(answer.resource) %>" data-synonyms="<%= answer_option_synonyms(answer.resource) %>"
data-append="<%= question.answer_option_append(answer.resource) %>" data-append="<%= answer_option_append(answer.resource) %>"
data-hint="<%= question.answer_option_hint(answer.resource) %>" data-hint="<%= answer_option_hint(answer.resource) %>"
<%= question.answer_selected?(@log, answer) ? "selected" : "" %> <%= question.answer_selected?(@log, answer) ? "selected" : "" %>
<%= answer.id == "" ? "disabled" : "" %>><%= answer.name || answer.resource %></option> <%= answer.id == "" ? "disabled" : "" %>><%= answer.name || answer.resource %></option>
<% end %> <% end %>
<% end %> <% end %>
<%= render partial: "form/guidance/#{question.guidance_partial}" if question.bottom_guidance? %> <%= render partial: "form/guidance/#{question.guidance_partial}" if question.bottom_guidance? %>

2
app/views/form/page.html.erb

@ -1,7 +1,7 @@
<% content_for :title, @page.header.presence || @page.questions.first.header.html_safe %> <% content_for :title, @page.header.presence || @page.questions.first.header.html_safe %>
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link(href: "javascript:history.back()") %> <%= govuk_back_link(href: send(@log.form.previous_page_redirect_path(@page, @log, current_user, params[:referrer]), @log)) %>
<% end %> <% end %>
<div data-controller="govukfrontend"></div> <div data-controller="govukfrontend"></div>

1
app/views/locations/availability.erb

@ -2,7 +2,6 @@
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: "Back",
href: params[:referrer] == "check_answers" ? scheme_location_check_answers_path(@scheme, @location, route: params[:route]) : scheme_location_mobility_standards_path(@scheme, @location, route: params[:route]), href: params[:referrer] == "check_answers" ? scheme_location_check_answers_path(@scheme, @location, route: params[:route]) : scheme_location_mobility_standards_path(@scheme, @location, route: params[:route]),
) %> ) %>
<% end %> <% end %>

1
app/views/locations/check_answers.html.erb

@ -3,7 +3,6 @@
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: "Back",
href: case params[:route] href: case params[:route]
when "locations" when "locations"
scheme_locations_path(@scheme) scheme_locations_path(@scheme)

1
app/views/locations/index.html.erb

@ -4,7 +4,6 @@
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: "Back",
href: "/schemes/#{@scheme.id}", href: "/schemes/#{@scheme.id}",
) %> ) %>
<% end %> <% end %>

1
app/views/locations/local_authority.html.erb

@ -2,7 +2,6 @@
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: "Back",
href: case params[:referrer] href: case params[:referrer]
when "check_local_authority" when "check_local_authority"
scheme_location_check_answers_path(@scheme, @location, route: params[:route]) scheme_location_check_answers_path(@scheme, @location, route: params[:route])

1
app/views/locations/mobility_standards.html.erb

@ -2,7 +2,6 @@
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: "Back",
href: params[:referrer] == "check_answers" ? scheme_location_check_answers_path(@scheme, @location, route: params[:route]) : scheme_location_type_of_unit_path(@scheme, @location, route: params[:route]), href: params[:referrer] == "check_answers" ? scheme_location_check_answers_path(@scheme, @location, route: params[:route]) : scheme_location_type_of_unit_path(@scheme, @location, route: params[:route]),
) %> ) %>
<% end %> <% end %>

1
app/views/locations/name.html.erb

@ -2,7 +2,6 @@
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: "Back",
href: case params[:referrer] href: case params[:referrer]
when "check_answers" when "check_answers"
scheme_location_check_answers_path(@scheme, @location, route: params[:route]) scheme_location_check_answers_path(@scheme, @location, route: params[:route])

1
app/views/locations/postcode.html.erb

@ -2,7 +2,6 @@
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: "Back",
href: if params[:referrer] == "check_answers" href: if params[:referrer] == "check_answers"
scheme_location_check_answers_path(@scheme, @location, route: params[:route]) scheme_location_check_answers_path(@scheme, @location, route: params[:route])
else else

1
app/views/locations/show.html.erb

@ -3,7 +3,6 @@
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: "Back",
href: scheme_locations_path(@scheme), href: scheme_locations_path(@scheme),
) %> ) %>
<% end %> <% end %>

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

@ -3,7 +3,6 @@
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: "Back",
href: scheme_location_path(@location.scheme, @location), href: scheme_location_path(@location.scheme, @location),
) %> ) %>
<% end %> <% end %>

1
app/views/locations/type_of_unit.html.erb

@ -2,7 +2,6 @@
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: "Back",
href: params[:referrer] == "check_answers" ? scheme_location_check_answers_path(@scheme, @location, route: params[:route]) : scheme_location_units_path(@scheme, @location, route: params[:route]), href: params[:referrer] == "check_answers" ? scheme_location_check_answers_path(@scheme, @location, route: params[:route]) : scheme_location_units_path(@scheme, @location, route: params[:route]),
) %> ) %>
<% end %> <% end %>

1
app/views/locations/units.html.erb

@ -2,7 +2,6 @@
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: "Back",
href: params[:referrer] == "check_answers" ? scheme_location_check_answers_path(@scheme, @location, route: params[:route]) : scheme_location_name_path(@scheme, @location, route: params[:route]), href: params[:referrer] == "check_answers" ? scheme_location_check_answers_path(@scheme, @location, route: params[:route]) : scheme_location_name_path(@scheme, @location, route: params[:route]),
) %> ) %>
<% end %> <% end %>

8
app/views/logs/index.html.erb

@ -55,8 +55,12 @@
<%= govuk_button_to "Create a new sales log", sales_logs_path, class: "govuk-!-margin-right-6" %> <%= govuk_button_to "Create a new sales log", sales_logs_path, class: "govuk-!-margin-right-6" %>
<% end %> <% end %>
<% if FeatureToggle.bulk_upload_logs? %> <% if FeatureToggle.bulk_upload_lettings_logs? && log_type_for_controller(controller) == "lettings" %>
<%= govuk_button_link_to "Upload #{log_type_for_controller(controller)} logs in bulk", bulk_upload_path_for_controller(controller, id: "start"), secondary: true %> <%= govuk_button_link_to "Upload lettings logs in bulk", bulk_upload_path_for_controller(controller, id: "start"), secondary: true %>
<% end %>
<% if FeatureToggle.bulk_upload_sales_logs? && log_type_for_controller(controller) == "sales" %>
<%= govuk_button_link_to "Upload sales logs in bulk", bulk_upload_path_for_controller(controller, id: "start"), secondary: true %>
<% end %> <% end %>
</div> </div>
<% end %> <% end %>

48
app/views/organisations/merge.html.erb

@ -0,0 +1,48 @@
<% content_for :before_content do %>
<% title = "Tell us if your organisation is merging" %>
<% content_for :title, title %>
<%= govuk_back_link href: organisation_path %>
<% end %>
<h2 class="govuk-heading-l">Tell us if your organisation is merging</h2>
<div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds-from-desktop">
<p class="govuk-body">
Use this service to tell us if your organisation is merging with one or more other organisations. You can also use it to tell us about past merges that have not yet been reported to CORE.
</p>
<h2 class="govuk-heading-m">Before you start</h2>
<p class="govuk-body">Regardless of the merge type, you’ll be asked for:</p>
<ul class="govuk-list govuk-list--bullet">
<li>the organisations merging in CORE</li>
<li>the merge type: for example one organisation absorbing the rest, or them all creating a new organisation</li>
<li>to confirm or update the telephone number</li>
<li>the merge date</li>
<li>if user email addresses will change with this merge</li>
</ul>
<h2 class="govuk-heading-m">If email addresses are changing</h2>
<%= govuk_inset_text(text: "Update all user email addresses on CORE as soon as they change, so that everyone can still access their CORE account. ") %>
<p class="govuk-body">
Users must have access to their old email address, so they can confirm their new one.
</p>
<h2 class="govuk-heading-m">If merging into a new organisation</h2>
<p class="govuk-body">You'll also be asked for the new organisation’s:</p>
<ul class="govuk-list govuk-list--bullet">
<li>name</li>
<li>address</li>
<li>telephone number</li>
<li>housing provider type</li>
<li>Regulator of Social Housing registration number</li>
<li>held stock details</li>
</ul>
<%= govuk_warning_text text: "You will not be able to submit your request without the above information. Do not start the form until you have obtained all of the information. " %>
<%= govuk_start_button(
text: "Start now",
href: "#",
) %>
</div>
</div>

3
app/views/organisations/show.html.erb

@ -35,6 +35,9 @@
<% end %> <% end %>
<% end %> <% end %>
<% if FeatureToggle.merge_organisations_enabled? %>
<p>Is your organisation merging with another? <%= govuk_link_to "Let us know using this form", merge_organisation_path %></p>
<% end %>
</div> </div>
<div class="govuk-grid-column-one-third-from-desktop"> <div class="govuk-grid-column-one-third-from-desktop">

1
app/views/schemes/confirm_secondary.html.erb

@ -2,7 +2,6 @@
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: "Back",
href: request.query_parameters["check_answers"] ? "/schemes/#{@scheme.id}/check-answers" : "/schemes/#{@scheme.id}/primary-client-group", href: request.query_parameters["check_answers"] ? "/schemes/#{@scheme.id}/check-answers" : "/schemes/#{@scheme.id}/primary-client-group",
) %> ) %>
<% end %> <% end %>

5
app/views/schemes/details.html.erb

@ -1,10 +1,7 @@
<% content_for :title, "Create a new supported housing scheme" %> <% content_for :title, "Create a new supported housing scheme" %>
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(href: :back) %>
text: "Back",
href: :back,
) %>
<% end %> <% end %>
<%= form_for(@scheme, method: :patch) do |f| %> <%= form_for(@scheme, method: :patch) do |f| %>

5
app/views/schemes/edit_name.html.erb

@ -1,10 +1,7 @@
<% content_for :title, "Scheme details" %> <% content_for :title, "Scheme details" %>
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(href: :back) %>
text: "Back",
href: :back,
) %>
<% end %> <% end %>
<%= form_for(@scheme, method: :patch) do |f| %> <%= form_for(@scheme, method: :patch) do |f| %>

5
app/views/schemes/new.html.erb

@ -6,10 +6,7 @@
<% content_for :title, "Create a new supported housing scheme" %> <% content_for :title, "Create a new supported housing scheme" %>
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(href: "javascript:history.back()") %>
text: "Back",
href: "javascript:history.go(-1);",
) %>
<% end %> <% end %>
<h1 class="govuk-heading-l"> <h1 class="govuk-heading-l">

5
app/views/schemes/primary_client_group.html.erb

@ -7,10 +7,7 @@
<% end %> <% end %>
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(href: back_button_path) %>
text: "Back",
href: back_button_path,
) %>
<% end %> <% end %>
<%= form_for(@scheme, method: :patch) do |f| %> <%= form_for(@scheme, method: :patch) do |f| %>

1
app/views/schemes/secondary_client_group.html.erb

@ -2,7 +2,6 @@
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: "Back",
href: request.query_parameters["check_answers"] ? "/schemes/#{@scheme.id}/check-answers" : "/schemes/#{@scheme.id}/confirm-secondary-client-group", href: request.query_parameters["check_answers"] ? "/schemes/#{@scheme.id}/check-answers" : "/schemes/#{@scheme.id}/confirm-secondary-client-group",
) %> ) %>
<% end %> <% end %>

1
app/views/schemes/show.html.erb

@ -3,7 +3,6 @@
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: "Back",
href: "/schemes", href: "/schemes",
) %> ) %>
<% end %> <% end %>

1
app/views/schemes/support.html.erb

@ -2,7 +2,6 @@
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: "Back",
href: request.query_parameters["check_answers"] ? "/schemes/#{@scheme.id}/check-answers" : "/schemes/#{@scheme.id}/secondary-client-group", href: request.query_parameters["check_answers"] ? "/schemes/#{@scheme.id}/check-answers" : "/schemes/#{@scheme.id}/secondary-client-group",
) %> ) %>
<% end %> <% end %>

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

@ -3,7 +3,6 @@
<% content_for :before_content do %> <% content_for :before_content do %>
<%= govuk_back_link( <%= govuk_back_link(
text: "Back",
href: scheme_details_path(@scheme), href: scheme_details_path(@scheme),
) %> ) %>
<% end %> <% end %>

201
config/forms/2022_2023.json

@ -7492,23 +7492,26 @@
"4": { "4": {
"value": "Every calendar month" "value": "Every calendar month"
}, },
"5": { "9": {
"value": "Weekly for 50 weeks" "value": "Weekly for 46 weeks"
}, },
"6": { "8": {
"value": "Weekly for 49 weeks" "value": "Weekly for 47 weeks"
}, },
"7": { "7": {
"value": "Weekly for 48 weeks" "value": "Weekly for 48 weeks"
}, },
"8": { "6": {
"value": "Weekly for 47 weeks" "value": "Weekly for 49 weeks"
}, },
"9": { "5": {
"value": "Weekly for 46 weeks" "value": "Weekly for 50 weeks"
}, },
"1": { "1": {
"value": "Weekly for 52 weeks" "value": "Weekly for 52 weeks"
},
"10": {
"value": "Weekly for 53 weeks"
} }
} }
} }
@ -7558,63 +7561,13 @@
}, },
"depends_on": [ "depends_on": [
{ {
"period": 1, "rent_and_charges_paid_weekly?": true,
"needstype": 2, "is_supported_housing?": true,
"household_charge": 0 "household_charge": 0
}, },
{ {
"period": 1, "rent_and_charges_paid_weekly?": true,
"needstype": 2, "is_supported_housing?": true,
"household_charge": null
},
{
"period": 5,
"needstype": 2,
"household_charge": 0
},
{
"period": 5,
"needstype": 2,
"household_charge": null
},
{
"period": 6,
"needstype": 2,
"household_charge": 0
},
{
"period": 6,
"needstype": 2,
"household_charge": null
},
{
"period": 7,
"needstype": 2,
"household_charge": 0
},
{
"period": 7,
"needstype": 2,
"household_charge": null
},
{
"period": 8,
"needstype": 2,
"household_charge": 0
},
{
"period": 8,
"needstype": 2,
"household_charge": null
},
{
"period": 9,
"needstype": 2,
"household_charge": 0
},
{
"period": 9,
"needstype": 2,
"household_charge": null "household_charge": null
} }
] ]
@ -7898,124 +7851,14 @@
}, },
"depends_on": [ "depends_on": [
{ {
"period": 1, "rent_and_charges_paid_weekly?": true,
"household_charge": 0,
"is_carehome": 0
},
{
"period": 1,
"household_charge": null,
"is_carehome": 0
},
{
"period": 5,
"household_charge": 0,
"is_carehome": 0
},
{
"period": 5,
"household_charge": null,
"is_carehome": 0
},
{
"period": 6,
"household_charge": 0,
"is_carehome": 0
},
{
"period": 6,
"household_charge": null,
"is_carehome": 0
},
{
"period": 7,
"household_charge": 0,
"is_carehome": 0
},
{
"period": 7,
"household_charge": null,
"is_carehome": 0
},
{
"period": 8,
"household_charge": 0, "household_charge": 0,
"is_carehome": 0 "is_carehome?": false
}, },
{ {
"period": 8, "rent_and_charges_paid_weekly?": true,
"household_charge": null, "household_charge": null,
"is_carehome": 0 "is_carehome?": false
},
{
"period": 9,
"household_charge": 0,
"is_carehome": 0
},
{
"period": 9,
"household_charge": null,
"is_carehome": 0
},
{
"period": 1,
"household_charge": 0,
"is_carehome": null
},
{
"period": 1,
"household_charge": null,
"is_carehome": null
},
{
"period": 5,
"household_charge": 0,
"is_carehome": null
},
{
"period": 5,
"household_charge": null,
"is_carehome": null
},
{
"period": 6,
"household_charge": 0,
"is_carehome": null
},
{
"period": 6,
"household_charge": null,
"is_carehome": null
},
{
"period": 7,
"household_charge": 0,
"is_carehome": null
},
{
"period": 7,
"household_charge": null,
"is_carehome": null
},
{
"period": 8,
"household_charge": 0,
"is_carehome": null
},
{
"period": 8,
"household_charge": null,
"is_carehome": null
},
{
"period": 9,
"household_charge": 0,
"is_carehome": null
},
{
"period": 9,
"household_charge": null,
"is_carehome": null
} }
] ]
}, },
@ -8602,6 +8445,12 @@
"depends_on": { "depends_on": {
"period": 1 "period": 1
} }
},
{
"label": " every week for 53 weeks",
"depends_on": {
"period": 10
}
} }
] ]
} }

2
config/initializers/filter_parameter_logging.rb

@ -2,5 +2,5 @@
# Configure sensitive parameters which will be filtered from the log file. # Configure sensitive parameters which will be filtered from the log file.
Rails.application.config.filter_parameters += %i[ Rails.application.config.filter_parameters += %i[
passw secret token crypt salt certificate otp ssn passw secret token crypt salt certificate otp ssn reset_password_token
] ]

35
config/locales/en.yml

@ -190,11 +190,11 @@ en:
reactivating_soon: "The scheme %{name} is not available until %{date}. Select another scheme or edit the tenancy start date" reactivating_soon: "The scheme %{name} is not available until %{date}. Select another scheme or edit the tenancy start date"
activating_soon: "%{name} is not available until %{date}. Enter a tenancy start date after %{date}" activating_soon: "%{name} is not available until %{date}. Enter a tenancy start date after %{date}"
owning_organisation: owning_organisation:
invalid: "Please select owning organisation or managing organisation that you belong to" invalid: "Please select the owning organisation or managing organisation that you belong to"
managing_organisation: managing_organisation:
invalid: "Please select owning organisation or managing organisation that you belong to" invalid: "Please select the owning organisation or managing organisation that you belong to"
created_by: created_by:
invalid: "Please select owning organisation or managing organisation that you belong to" invalid: "Please select the owning organisation or managing organisation that you belong to"
lettype: lettype:
general_needs_mismatch: Lettings type must be a general needs type because you selected general needs when uploading the file general_needs_mismatch: Lettings type must be a general needs type because you selected general needs when uploading the file
supported_housing_mismatch: Lettings type must be a supported housing type because you selected supported housing when uploading the file supported_housing_mismatch: Lettings type must be a supported housing type because you selected supported housing when uploading the file
@ -253,10 +253,10 @@ en:
freq_missing: "Select how often the household receives income" freq_missing: "Select how often the household receives income"
earnings_missing: "Enter how much income the household has in total" earnings_missing: "Enter how much income the household has in total"
income: income:
over_hard_max_for_london: "Income must not exceed £90,000.00 for properties within London local authorities" over_hard_max_for_london: "Income must be £90,000 or lower for properties within a London local authority"
over_hard_max_for_outside_london: "Income must not exceed £80,000.00 for properties outside London local authorities" over_hard_max_for_outside_london: "Income must be £80,000 or lower for properties outside London local authority"
combined_over_hard_max_for_london: "Combined income must not exceed £90,000.00 for properties within London local authorities" combined_over_hard_max_for_london: "Combined income must be £90,000 or lower for properties within a London local authority"
combined_over_hard_max_for_outside_london: "Combined income must not exceed £80,000.00 for properties outside London local authorities" combined_over_hard_max_for_outside_london: "Combined income must be £80,000 or lower for properties outside London local authorities"
child_has_income: "Child's income must be £0" child_has_income: "Child's income must be £0"
negative_currency: "Enter an amount above 0" negative_currency: "Enter an amount above 0"
rent: rent:
@ -283,7 +283,7 @@ en:
general_needs: "Enter a value for the support charge between £0 and £60 per week if the landlord is a local authority and it is a general needs letting" general_needs: "Enter a value for the support charge between £0 and £60 per week if the landlord is a local authority and it is a general needs letting"
supported_housing: "Enter a value for the support charge between £0 and £120 per week if the landlord is a local authority and it is a supported housing letting" supported_housing: "Enter a value for the support charge between £0 and £120 per week if the landlord is a local authority and it is a supported housing letting"
ecstat: ecstat:
over_hard_max: "Net income of £%{hard_max} per week is too high for given the tenant’s working situation" over_hard_max: "Net income of %{hard_max} per week is too high given the tenant’s working situation"
brent: brent:
below_hard_min: "Rent is below the absolute minimum expected for a property of this type. Please check the rent, rent period, local authority and (if general needs) number of bedrooms" below_hard_min: "Rent is below the absolute minimum expected for a property of this type. Please check the rent, rent period, local authority and (if general needs) number of bedrooms"
above_hard_max: "Rent is higher than the absolute maximum expected for a property of this type. Please check the rent, rent period, local authority and (if general needs) number of bedrooms" above_hard_max: "Rent is higher than the absolute maximum expected for a property of this type. Please check the rent, rent period, local authority and (if general needs) number of bedrooms"
@ -314,7 +314,7 @@ en:
charges: charges:
complete_1_of_3: "Answer either the ‘household rent and charges’ question or ‘is this accommodation a care home‘, or select ‘no’ for ‘does the household pay rent or charges for the accommodation?’" complete_1_of_3: "Answer either the ‘household rent and charges’ question or ‘is this accommodation a care home‘, or select ‘no’ for ‘does the household pay rent or charges for the accommodation?’"
tcharge: tcharge:
under_10: "Enter a total charge that is at least £10 per week" under_10: "Enter a total charge that is at least £10.00 per week"
rent_period: rent_period:
invalid_for_org: "%{org_name} does not charge rent %{rent_period}" invalid_for_org: "%{org_name} does not charge rent %{rent_period}"
carehome: carehome:
@ -466,6 +466,7 @@ en:
during_deactivated_period: "The scheme is already deactivated during this date, please enter a different date" during_deactivated_period: "The scheme is already deactivated during this date, please enter a different date"
owning_organisation: owning_organisation:
does_not_own_stock: "Enter an organisation that owns housing stock" does_not_own_stock: "Enter an organisation that owns housing stock"
no_completed_locations: "This scheme cannot be chosen as it has no completed locations"
location: location:
postcode_blank: "Enter a postcode" postcode_blank: "Enter a postcode"
@ -516,8 +517,8 @@ en:
under_soft_min_for_economic_status: "You said income was %{income}, which is below this working situation's minimum (%{minimum})" under_soft_min_for_economic_status: "You said income was %{income}, which is below this working situation's minimum (%{minimum})"
rent: rent:
outside_range_title: "You told us the rent is %{brent}" outside_range_title: "You told us the rent is %{brent}"
min_hint_text: "The minimum rent expected for this type of property in this local authority is £%{soft_min_for_period}." min_hint_text: "The minimum rent expected for this type of property in this local authority is %{soft_min_for_period}."
max_hint_text: "The maximum rent expected for this type of property in this local authority is £%{soft_max_for_period}." max_hint_text: "The maximum rent expected for this type of property in this local authority is %{soft_max_for_period}."
purchase_price: purchase_price:
title_text: "You told us the purchase price is %{value}" title_text: "You told us the purchase price is %{value}"
hint_text: "The %{min_or_max} purchase price expected for this type of property in this local authority is %{soft_min_or_soft_max}" hint_text: "The %{min_or_max} purchase price expected for this type of property in this local authority is %{soft_min_or_soft_max}"
@ -539,7 +540,7 @@ en:
void_date: void_date:
title_text: "You told us the time between the start of the tenancy and the void date is more than 2 years" title_text: "You told us the time between the start of the tenancy and the void date is more than 2 years"
shared_ownership_deposit: shared_ownership_deposit:
title_text: "Mortgage, deposit and cash discount total should equal £%{expected_shared_ownership_deposit_value}" title_text: "Mortgage, deposit and cash discount total should equal %{expected_shared_ownership_deposit_value}"
old_persons_shared_ownership: "At least one buyer should be aged over 64 for Older persons’ shared ownership scheme" old_persons_shared_ownership: "At least one buyer should be aged over 64 for Older persons’ shared ownership scheme"
staircase_bought_seems_high: "You said %{percentage}% was bought in this staircasing transaction, which seems high. Are you sure?" staircase_bought_seems_high: "You said %{percentage}% was bought in this staircasing transaction, which seems high. Are you sure?"
monthly_charges_over_soft_max: monthly_charges_over_soft_max:
@ -547,10 +548,16 @@ en:
student_not_child: student_not_child:
title_text: "You told us this person is a student aged beween 16 and 19" title_text: "You told us this person is a student aged beween 16 and 19"
discounted_sale_value: discounted_sale_value:
title_text: "Mortgage, deposit, and grant total must equal £%{value_with_discount}" title_text: "Mortgage, deposit, and grant total must equal %{value_with_discount}"
informative_text: "Your given mortgage, deposit and grant total is £%{mortgage_deposit_and_grant_total}" informative_text: "Your given mortgage, deposit and grant total is %{mortgage_deposit_and_grant_total}"
care_home_charges: care_home_charges:
title_text: "Care home charges should be provided if this is a care home accommodation" title_text: "Care home charges should be provided if this is a care home accommodation"
buyer1_livein_wrong_for_ownership_type:
title_text: "You told us that buyer 1 will not live in the property. For %{ownership_scheme} types, the buyer usually lives in the property."
buyer2_livein_wrong_for_ownership_type:
title_text: "You told us that buyer 2 will not live in the property. For %{ownership_scheme} types, the buyer usually lives in the property."
percentage_discount_value:
title_text: "You told us that the percentage discount was %{discount}. This seems high for this type of property."
devise: devise:
two_factor_authentication: two_factor_authentication:

1
config/routes.rb

@ -119,6 +119,7 @@ Rails.application.routes.draw do
get "managing-agents/remove", to: "organisation_relationships#remove_managing_agent" get "managing-agents/remove", to: "organisation_relationships#remove_managing_agent"
post "managing-agents", to: "organisation_relationships#create_managing_agent" post "managing-agents", to: "organisation_relationships#create_managing_agent"
delete "managing-agents", to: "organisation_relationships#delete_managing_agent" delete "managing-agents", to: "organisation_relationships#delete_managing_agent"
get "merge", to: "organisations#merge"
end end
end end

5
db/migrate/20230405074138_add_percentage_discount_value_check.rb

@ -0,0 +1,5 @@
class AddPercentageDiscountValueCheck < ActiveRecord::Migration[7.0]
def change
add_column :sales_logs, :percentage_discount_value_check, :integer
end
end

5
db/migrate/20230405140343_add_buyer_livin_value_check.rb

@ -0,0 +1,5 @@
class AddBuyerLivinValueCheck < ActiveRecord::Migration[7.0]
def change
add_column :sales_logs, :buyer_livein_value_check, :integer
end
end

2
db/schema.rb

@ -573,6 +573,8 @@ ActiveRecord::Schema[7.0].define(version: 2023_04_12_143245) do
t.integer "nationalbuy2" t.integer "nationalbuy2"
t.integer "discounted_sale_value_check" t.integer "discounted_sale_value_check"
t.integer "student_not_child_value_check" t.integer "student_not_child_value_check"
t.integer "buyer_livein_value_check"
t.integer "percentage_discount_value_check"
t.index ["bulk_upload_id"], name: "index_sales_logs_on_bulk_upload_id" t.index ["bulk_upload_id"], name: "index_sales_logs_on_bulk_upload_id"
t.index ["created_by_id"], name: "index_sales_logs_on_created_by_id" t.index ["created_by_id"], name: "index_sales_logs_on_created_by_id"
t.index ["old_id"], name: "index_sales_logs_on_old_id", unique: true t.index ["old_id"], name: "index_sales_logs_on_old_id", unique: true

BIN
public/files/bulk-upload-lettings-specification-2023-24.xlsx

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save