Browse Source

Merge branch 'CLDC-4173-new-building-height-question-sales' into CLDC-4178-add-gender-same-as-sex-question-for-sales

pull/3188/head
Nat Dean-Lewis 3 months ago
parent
commit
059da597af
  1. 0
      .erb_lint.yml
  2. 5
      .rubocop.yml
  3. 2
      .ruby-version
  4. 4
      Dockerfile
  5. 11
      Gemfile
  6. 111
      Gemfile.lock
  7. 2
      app/controllers/csv_downloads_controller.rb
  8. 2
      app/controllers/lettings_logs_controller.rb
  9. 2
      app/controllers/lettings_logs_filters_controller.rb
  10. 2
      app/controllers/merge_requests_controller.rb
  11. 2
      app/controllers/sales_logs_filters_controller.rb
  12. 2
      app/helpers/bulk_upload/lettings_log_to_csv.rb
  13. 2
      app/helpers/bulk_upload/sales_log_to_csv.rb
  14. 2
      app/helpers/data_sharing_agreement_helper.rb
  15. 2
      app/helpers/form_page_error_helper.rb
  16. 3
      app/helpers/locations_helper.rb
  17. 4
      app/helpers/merge_requests_helper.rb
  18. 4
      app/helpers/notifications_helper.rb
  19. 3
      app/helpers/question_view_helper.rb
  20. 3
      app/helpers/schemes_helper.rb
  21. 3
      app/mailers/devise_notify_mailer.rb
  22. 10
      app/models/derived_variables/lettings_log_variables.rb
  23. 2
      app/models/derived_variables/shared_logic.rb
  24. 24
      app/models/form/lettings/pages/tenancyother_value_check.rb
  25. 13
      app/models/form/lettings/questions/tenancyother_value_check.rb
  26. 1
      app/models/form/lettings/subsections/tenancy_information.rb
  27. 3
      app/models/form/sales/pages/deposit.rb
  28. 6
      app/models/form/sales/questions/deposit_amount.rb
  29. 3
      app/models/form/sales/questions/mortgage_amount.rb
  30. 3
      app/models/form/sales/questions/mortgageused.rb
  31. 3
      app/models/form/sales/questions/purchase_price.rb
  32. 2
      app/models/form/subsection.rb
  33. 6
      app/models/lettings_log.rb
  34. 2
      app/models/sales_log.rb
  35. 2
      app/models/validations/sales/sale_information_validations.rb
  36. 2
      app/models/validations/sales/soft_validations.rb
  37. 10
      app/models/validations/shared_validations.rb
  38. 10
      app/models/validations/soft_validations.rb
  39. 2
      app/policies/location_policy.rb
  40. 2
      app/policies/organisation_policy.rb
  41. 2
      app/policies/scheme_policy.rb
  42. 22
      app/services/bulk_upload/lettings/year2023/row_parser.rb
  43. 10
      app/services/bulk_upload/lettings/year2024/row_parser.rb
  44. 10
      app/services/bulk_upload/lettings/year2025/row_parser.rb
  45. 10
      app/services/bulk_upload/lettings/year2026/row_parser.rb
  46. 43
      app/services/bulk_upload/sales/year2023/row_parser.rb
  47. 40
      app/services/bulk_upload/sales/year2024/row_parser.rb
  48. 39
      app/services/bulk_upload/sales/year2025/row_parser.rb
  49. 39
      app/services/bulk_upload/sales/year2026/row_parser.rb
  50. 6
      app/services/csv/lettings_log_csv_service.rb
  51. 3
      app/services/csv/sales_log_csv_service.rb
  52. 2
      app/services/documentation_generator.rb
  53. 2
      app/services/exports/organisation_export_constants.rb
  54. 2
      app/services/filter_manager.rb
  55. 2
      app/views/form/_checkbox_question.html.erb
  56. 4
      app/views/form/_interruption_screen_question.html.erb
  57. 4
      app/views/form/_radio_question.html.erb
  58. 2
      app/views/rails_admin/main/_submit_buttons.html.erb
  59. 2
      app/views/rails_admin/main/dashboard.html.erb
  60. 2
      app/views/rails_admin/main/delete.html.erb
  61. 8
      config/initializers/multi_logger.rb
  62. 2
      config/initializers/sidekiq.rb
  63. 17
      config/locales/forms/2026/lettings/soft_validations.en.yml
  64. 4
      config/routes.rb
  65. 2
      db/migrate/20241206142943_create_active_storage_variant_records.active_storage.rb
  66. 5
      db/migrate/20260212091506_add_tenancyother_value_check_to_lettings_logs.rb
  67. 1
      db/schema.rb
  68. 4
      docs/setup.md
  69. 2
      lib/tasks/generate_lettings_documentation.rake
  70. 2
      lib/tasks/generate_sales_documentation.rake
  71. 4
      lib/tasks/handle_unpended_logs.rake
  72. 2
      lib/tasks/lint.rake
  73. 2
      lib/tasks/set_log_validation_collection_year.rake
  74. 2
      spec/components/bulk_upload_error_row_component_spec.rb
  75. 4
      spec/components/check_answers_summary_list_card_component_spec.rb
  76. 16
      spec/components/create_log_actions_component_spec.rb
  77. 28
      spec/components/data_protection_confirmation_banner_component_spec.rb
  78. 3
      spec/db/seeds_spec.rb
  79. 2
      spec/factories/data_protection_confirmation.rb
  80. 2
      spec/features/accessibility_spec.rb
  81. 4
      spec/features/bulk_upload_lettings_logs_spec.rb
  82. 4
      spec/features/bulk_upload_sales_logs_spec.rb
  83. 20
      spec/features/form/accessible_autocomplete_spec.rb
  84. 6
      spec/features/form/address_search_spec.rb
  85. 2
      spec/features/form/checkboxes_spec.rb
  86. 6
      spec/features/form/conditional_questions_spec.rb
  87. 28
      spec/features/form/page_routing_spec.rb
  88. 4
      spec/features/form/progressive_total_field_spec.rb
  89. 2
      spec/features/form/saving_data_spec.rb
  90. 2
      spec/features/form/validations_spec.rb
  91. 6
      spec/features/lettings_log_spec.rb
  92. 4
      spec/features/sales_log_spec.rb
  93. 4
      spec/features/schemes_spec.rb
  94. 10
      spec/features/user_spec.rb
  95. 6
      spec/fixtures/files/lettings_log_csv_export_codes_26.csv
  96. 6
      spec/fixtures/files/lettings_log_csv_export_labels_26.csv
  97. 2
      spec/helpers/collection_resources_helper_spec.rb
  98. 4
      spec/helpers/question_attribute_helper_spec.rb
  99. 2
      spec/helpers/tag_helper_spec.rb
  100. 8
      spec/helpers/tasklist_helper_spec.rb
  101. Some files were not shown because too many files have changed in this diff Show More

0
.erb-lint.yml → .erb_lint.yml

5
.rubocop.yml

@ -1,5 +1,7 @@
require:
- rubocop-performance
plugins:
- rubocop-rails
- rubocop-rspec
@ -28,3 +30,6 @@ Rails/UnknownEnv:
- development
- test
- review
RSpec/IndexedLet:
Enabled: false

2
.ruby-version

@ -1 +1 @@
3.1.6
3.4.4

4
Dockerfile

@ -1,4 +1,4 @@
FROM ruby:3.1.6-alpine3.20 as base
FROM ruby:3.4.4-alpine3.20 as base
WORKDIR /app
@ -10,7 +10,7 @@ RUN apk add --update --no-cache tzdata && \
# build-base: compilation tools for bundle
# yarn: node package manager
# postgresql-dev: postgres driver and libraries
RUN apk add --no-cache build-base=0.5-r3 busybox=1.36.1-r29 nodejs=20.15.1-r0 yarn=1.22.22-r0 bash=5.2.26-r0 libpq-dev
RUN apk add --no-cache build-base=0.5-r3 busybox=1.36.1-r29 nodejs=20.15.1-r0 yarn=1.22.22-r0 bash=5.2.26-r0 libpq-dev yaml-dev linux-headers
# Bundler version should be the same version as what the Gemfile.lock was bundled with
RUN gem install bundler:2.6.4 --no-document

11
Gemfile

@ -3,7 +3,7 @@
source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
ruby "3.1.6"
ruby "3.4.4"
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails', branch: 'main'
gem "rails", "~> 7.2.2"
@ -51,7 +51,7 @@ gem "paper_trail-globalid"
gem "pundit"
# Request rate limiting
gem "rack", ">= 2.2.6.3"
gem "rack", "~> 3.1.20"
gem "rack-attack"
gem "redis", "~> 4.8"
# Receive exceptions and configure alerts
@ -72,9 +72,12 @@ gem "sidekiq-cron"
gem "unread"
# Pinning versions to address vulnerabilities
gem "nokogiri", "~> 1.18.9"
gem "nokogiri", "~> 1.19.1"
gem "thor", "~> 1.4.0"
# Pinning until activesupport is updated to v8.1.2
gem "connection_pool", "~> 2.5"
group :development, :test do
# Check gems for known vulnerabilities
gem "bundler-audit"
@ -95,7 +98,7 @@ group :development do
# Can be configured to work on production as well see: https://github.com/MiniProfiler/rack-mini-profiler/blob/master/README.md
gem "erb_lint", require: false
gem "rack-mini-profiler", "~> 3.3.0"
gem "rubocop-govuk", "4.3.0", require: false
gem "rubocop-govuk", "5.2.0", require: false
gem "rubocop-performance", require: false
gem "rubocop-rails", require: false
end

111
Gemfile.lock

@ -78,7 +78,7 @@ GEM
tzinfo (~> 2.0, >= 2.0.5)
addressable (2.8.6)
public_suffix (>= 2.0.2, < 6.0)
ast (2.4.2)
ast (2.4.3)
auto_strip_attributes (2.6.0)
activerecord (>= 4.0)
aws-eventstream (1.4.0)
@ -113,15 +113,15 @@ GEM
thread_safe (~> 0.3, >= 0.3.1)
base64 (0.3.0)
bcrypt (3.1.20)
benchmark (0.4.1)
better_html (2.0.2)
actionview (>= 6.0)
activesupport (>= 6.0)
benchmark (0.5.0)
better_html (2.2.0)
actionview (>= 7.0)
activesupport (>= 7.0)
ast (~> 2.0)
erubi (~> 1.4)
parser (>= 2.4)
smart_properties
bigdecimal (3.2.2)
bigdecimal (4.0.1)
bindex (0.8.1)
bootsnap (1.18.3)
msgpack (~> 1.2)
@ -151,7 +151,7 @@ GEM
coderay (1.1.3)
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
concurrent-ruby (1.3.5)
concurrent-ruby (1.3.6)
connection_pool (2.5.3)
crack (1.0.0)
bigdecimal
@ -184,12 +184,12 @@ GEM
drb (2.2.3)
dumb_delegator (1.0.0)
encryptor (3.0.0)
erb_lint (0.5.0)
erb_lint (0.9.0)
activesupport
better_html (>= 2.0.1)
parser (>= 2.7.1.4)
rainbow
rubocop
rubocop (>= 1)
smart_properties
erubi (1.13.1)
et-orbi (1.2.11)
@ -232,7 +232,7 @@ GEM
hashdiff (1.1.0)
html-attributes-utils (1.0.2)
activesupport (>= 6.1.4.4)
i18n (1.14.7)
i18n (1.14.8)
concurrent-ruby (~> 1.0)
ice_nine (0.11.2)
iniparse (1.5.0)
@ -261,13 +261,15 @@ GEM
activerecord
kaminari-core (= 1.2.2)
kaminari-core (1.2.2)
language_server-protocol (3.17.0.5)
launchy (2.5.2)
addressable (~> 2.8)
lint_roller (1.1.0)
listen (3.9.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
logger (1.7.0)
loofah (2.24.0)
loofah (2.25.0)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
mail (2.8.1)
@ -279,7 +281,9 @@ GEM
matrix (0.4.2)
method_source (1.1.0)
mini_mime (1.1.5)
minitest (5.25.5)
minitest (6.0.2)
drb (~> 2.0)
prism (~> 1.5)
msgpack (1.7.2)
multipart-post (2.4.1)
nested_form (0.3.2)
@ -295,13 +299,13 @@ GEM
net-smtp (0.5.1)
net-protocol
nio4r (2.7.4)
nokogiri (1.18.9-arm64-darwin)
nokogiri (1.19.1-arm64-darwin)
racc (~> 1.4)
nokogiri (1.18.9-x86_64-darwin)
nokogiri (1.19.1-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.18.9-x86_64-linux-gnu)
nokogiri (1.19.1-x86_64-linux-gnu)
racc (~> 1.4)
nokogiri (1.18.9-x86_64-linux-musl)
nokogiri (1.19.1-x86_64-linux-musl)
racc (~> 1.4)
notifications-ruby-client (6.0.0)
jwt (>= 1.5, < 3)
@ -317,10 +321,10 @@ GEM
paper_trail-globalid (0.2.0)
globalid
paper_trail (>= 3.0.0)
parallel (1.24.0)
parallel (1.27.0)
parallel_tests (4.5.1)
parallel
parser (3.3.0.5)
parser (3.3.10.2)
ast (~> 2.4.1)
racc
pg (1.5.5)
@ -328,6 +332,7 @@ GEM
pp (0.6.2)
prettyprint
prettyprint (0.2.0)
prism (1.9.0)
propshaft (0.8.0)
actionpack (>= 7.0.0)
activesupport (>= 7.0.0)
@ -349,7 +354,7 @@ GEM
activesupport (>= 3.0.0)
raabro (1.4.0)
racc (1.8.1)
rack (3.1.18)
rack (3.1.20)
rack-attack (6.7.0)
rack (>= 1.0, < 4)
rack-mini-profiler (3.3.1)
@ -375,7 +380,7 @@ GEM
activesupport (= 7.2.2.2)
bundler (>= 1.15.0)
railties (= 7.2.2.2)
rails-dom-testing (2.2.0)
rails-dom-testing (2.3.0)
activesupport (>= 5.0.0)
minitest
nokogiri (>= 1.6)
@ -409,7 +414,7 @@ GEM
redis (4.8.1)
redis-client (0.22.1)
connection_pool
regexp_parser (2.9.0)
regexp_parser (2.11.3)
reline (0.6.0)
io-console (~> 0.5)
request_store (1.7.0)
@ -439,34 +444,45 @@ GEM
rspec-mocks (~> 3.12)
rspec-support (~> 3.12)
rspec-support (3.13.1)
rubocop (1.25.0)
rubocop (1.82.1)
json (~> 2.3)
language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0)
parallel (~> 1.10)
parser (>= 3.1.0.0)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml
rubocop-ast (>= 1.15.1, < 2.0)
regexp_parser (>= 2.9.3, < 3.0)
rubocop-ast (>= 1.48.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 3.0)
rubocop-ast (1.15.1)
parser (>= 3.0.1.1)
rubocop-govuk (4.3.0)
rubocop (= 1.25.0)
rubocop-ast (= 1.15.1)
rubocop-rails (= 2.13.2)
rubocop-rake (= 0.6.0)
rubocop-rspec (= 2.7.0)
unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.49.0)
parser (>= 3.3.7.2)
prism (~> 1.7)
rubocop-capybara (2.22.1)
lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1)
rubocop-govuk (5.2.0)
rubocop (= 1.82.1)
rubocop-ast (= 1.49.0)
rubocop-capybara (= 2.22.1)
rubocop-rails (= 2.34.3)
rubocop-rake (= 0.7.1)
rubocop-rspec (= 3.9.0)
rubocop-performance (1.19.1)
rubocop (>= 1.7.0, < 2.0)
rubocop-ast (>= 0.4.0)
rubocop-rails (2.13.2)
rubocop-rails (2.34.3)
activesupport (>= 4.2.0)
lint_roller (~> 1.1)
rack (>= 1.1)
rubocop (>= 1.7.0, < 2.0)
rubocop-rake (0.6.0)
rubocop (~> 1.0)
rubocop-rspec (2.7.0)
rubocop (~> 1.19)
rubocop (>= 1.75.0, < 2.0)
rubocop-ast (>= 1.44.0, < 2.0)
rubocop-rake (0.7.1)
lint_roller (~> 1.1)
rubocop (>= 1.72.1)
rubocop-rspec (3.9.0)
lint_roller (~> 1.1)
rubocop (~> 1.81)
ruby-openai (7.0.1)
event_stream_parser (>= 0.3.0, < 2.0.0)
faraday (>= 1)
@ -514,7 +530,9 @@ GEM
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
uk_postcode (2.1.8)
unicode-display_width (2.5.0)
unicode-display_width (3.2.0)
unicode-emoji (~> 4.1)
unicode-emoji (4.2.0)
unread (0.14.0)
activerecord (>= 6.1)
uri (1.0.4)
@ -563,6 +581,7 @@ DEPENDENCIES
capybara
capybara-lockstep
capybara-screenshot
connection_pool (~> 2.5)
cssbundling-rails
devise
devise_two_factor_authentication
@ -579,7 +598,7 @@ DEPENDENCIES
json-schema
listen (~> 3.3)
method_source (~> 1.1)
nokogiri (~> 1.18.9)
nokogiri (~> 1.19.1)
notifications-ruby-client
overcommit (>= 0.37.0)
paper_trail (~> 15.2)
@ -591,7 +610,7 @@ DEPENDENCIES
pry-byebug
puma (~> 6.4)
pundit
rack (>= 2.2.6.3)
rack (~> 3.1.20)
rack-attack
rack-mini-profiler (~> 3.3.0)
rails (~> 7.2.2)
@ -600,7 +619,7 @@ DEPENDENCIES
redis (~> 4.8)
roo
rspec-rails
rubocop-govuk (= 4.3.0)
rubocop-govuk (= 5.2.0)
rubocop-performance
rubocop-rails
ruby-openai
@ -621,7 +640,7 @@ DEPENDENCIES
webmock
RUBY VERSION
ruby 3.1.6p260
ruby 3.4.4p0
BUNDLED WITH
2.6.4

2
app/controllers/csv_downloads_controller.rb

@ -5,7 +5,7 @@ class CsvDownloadsController < ApplicationController
@csv_download = CsvDownload.find(params[:id])
authorize @csv_download
return render "errors/download_link_expired" if @csv_download.expired?
render "errors/download_link_expired" if @csv_download.expired?
end
def download

2
app/controllers/lettings_logs_controller.rb

@ -190,7 +190,7 @@ private
end
def resolve_logs!
if @log&.unresolved && @log.location.present? && @log.scheme.present? && @log&.resolve!
if @log&.unresolved && @log.location.present? && @log.scheme.present? && @log.resolve!
unresolved_logs_count_for_user = current_user.lettings_logs.unresolved.assigned_to(current_user).count
flash.now[:notice] = helpers.flash_notice_for_resolved_logs(unresolved_logs_count_for_user)
end

2
app/controllers/lettings_logs_filters_controller.rb

@ -52,8 +52,6 @@ class LettingsLogsFiltersController < ApplicationController
end
end
private
def lettings_session_filters
params["years"] = [params["years"]] if params["years"].present?
lettings_filter_manager.session_filters

2
app/controllers/merge_requests_controller.rb

@ -105,7 +105,7 @@ private
answer_options = { "" => "Select an option" }
if current_user.support?
Organisation.all.each do |organisation|
Organisation.all.find_each do |organisation|
date = @merge_request.merge_date || Time.zone.today
answer_options[organisation.id] = organisation.name(date:)
end

2
app/controllers/sales_logs_filters_controller.rb

@ -53,8 +53,6 @@ class SalesLogsFiltersController < ApplicationController
end
end
private
def sales_session_filters
params["years"] = [params["years"]] if params["years"].present?
sales_filter_manager.session_filters

2
app/helpers/bulk_upload/lettings_log_to_csv.rb

@ -2,12 +2,10 @@ class BulkUpload::LettingsLogToCsv
attr_reader :log, :line_ending, :col_offset, :overrides
def initialize(log:, line_ending: "\n", col_offset: 1, overrides: {})
# rubocop:disable Rails/HelperInstanceVariable
@log = log
@line_ending = line_ending
@col_offset = col_offset
@overrides = overrides
# rubocop:enable Rails/HelperInstanceVariable
end
def row_prefix

2
app/helpers/bulk_upload/sales_log_to_csv.rb

@ -2,12 +2,10 @@ class BulkUpload::SalesLogToCsv
attr_reader :log, :line_ending, :col_offset, :overrides
def initialize(log:, line_ending: "\n", col_offset: 1, overrides: {})
# rubocop:disable Rails/HelperInstanceVariable
@log = log
@line_ending = line_ending
@col_offset = col_offset
@overrides = overrides
# rubocop:enable Rails/HelperInstanceVariable
end
def row_prefix

2
app/helpers/data_sharing_agreement_helper.rb

@ -67,7 +67,7 @@ module DataSharingAgreementHelper
"12.2. For #{@org_name}: Name: #{@dpo_name}, Postal Address: #{@org_address}, E-mail address: #{@dpo_email}, Telephone number: #{@org_phone}"
end
end
# rubocop:enable Rails/HelperInstanceVariable
# rubocop:enable Rails/HelperInstanceVariable
private

2
app/helpers/form_page_error_helper.rb

@ -5,7 +5,7 @@ module FormPageErrorHelper
end
def remove_duplicate_page_errors(lettings_log)
lettings_log.errors.group_by(&:message).each do |_, errors|
lettings_log.errors.group_by(&:message).each_value do |errors|
next if errors.size == 1
errors.shift

3
app/helpers/locations_helper.rb

@ -91,7 +91,8 @@ module LocationsHelper
def toggle_location_link(location)
return govuk_button_link_to "Deactivate this location", scheme_location_new_deactivation_path(location.scheme, location), warning: true if location.active? || location.deactivates_in_a_long_time?
return govuk_button_link_to "Reactivate this location", scheme_location_new_reactivation_path(location.scheme, location) if location.deactivated? && !location.deactivated_by_scheme?
govuk_button_link_to "Reactivate this location", scheme_location_new_reactivation_path(location.scheme, location) if location.deactivated? && !location.deactivated_by_scheme?
end
def delete_location_link(location)

4
app/helpers/merge_requests_helper.rb

@ -101,13 +101,13 @@ module MergeRequestsHelper
attribute = page if attribute.nil?
return nil unless value_exists?(merge_request, attribute)
unless merge_request.status == "request_merged" || merge_request.status == "processing"
unless %w[request_merged processing].include?(merge_request.status)
{ text: merge_request_action_text(merge_request, attribute), href: send("#{page}_merge_request_path", merge_request, referrer: "check_answers"), visually_hidden_text: page.humanize }
end
end
def merge_outcome_action(merge_request, page)
unless merge_request.status == "request_merged" || merge_request.status == "processing"
unless %w[request_merged processing].include?(merge_request.status)
{ text: "View", href: send("#{page}_merge_request_path", merge_request), visually_hidden_text: page.humanize }
end
end

4
app/helpers/notifications_helper.rb

@ -57,7 +57,7 @@ class NotificationRenderer < Redcarpet::Render::HTML
def initialize(options = {})
link_class = "govuk-link"
link_class += " govuk-link--inverse" if options[:invert_link_colour]
@bold = options[:bold_all_text] # rubocop:disable Rails/HelperInstanceVariable
@bold = options[:bold_all_text]
base_options = { escape_html: true, safe_links_only: true, link_attributes: { class: link_class } }
super base_options
end
@ -78,7 +78,7 @@ class NotificationRenderer < Redcarpet::Render::HTML
end
def paragraph(text)
return %(<p class="govuk-!-font-weight-bold">#{text}</p>) if @bold # rubocop:disable Rails/HelperInstanceVariable
return %(<p class="govuk-!-font-weight-bold">#{text}</p>) if @bold
%(<p class="govuk-body-m">#{text}</p>)
end

3
app/helpers/question_view_helper.rb

@ -44,7 +44,8 @@ module QuestionViewHelper
def select_option_name(value)
return value.service_name if value.respond_to?(:service_name)
return value["name"] if value.is_a?(Hash) && value["name"].present?
return value["postcode"] if value.is_a?(Location)
value["postcode"] if value.is_a?(Location)
end
private

3
app/helpers/schemes_helper.rb

@ -12,7 +12,8 @@ module SchemesHelper
def toggle_scheme_link(scheme)
return govuk_button_link_to "Deactivate this scheme", scheme_new_deactivation_path(scheme), warning: true if scheme.active? || scheme.deactivates_in_a_long_time?
return govuk_button_link_to "Reactivate this scheme", scheme_new_reactivation_path(scheme) if scheme.deactivated? || scheme.deactivating_soon?
govuk_button_link_to "Reactivate this scheme", scheme_new_reactivation_path(scheme) if scheme.deactivated? || scheme.deactivating_soon?
end
def delete_scheme_link(scheme)

3
app/mailers/devise_notify_mailer.rb

@ -92,8 +92,7 @@ class DeviseNotifyMailer < Devise::Mailer
def email_changed?(record)
(
record.confirmable_template == User::CONFIRMABLE_TEMPLATE_ID && (
record.unconfirmed_email.present? && record.unconfirmed_email != record.email)
record.confirmable_template == User::CONFIRMABLE_TEMPLATE_ID && record.unconfirmed_email.present? && record.unconfirmed_email != record.email
) || (
record.versions.last.changeset.key?("unconfirmed_email") &&
record.confirmed?

10
app/models/derived_variables/lettings_log_variables.rb

@ -254,7 +254,7 @@ private
def clear_inapplicable_derived_values!
reset_invalidated_derived_values!(dependencies)
if (startdate_changed? || renewal_changed?) && (renewal_was == 1 && startdate_was&.between?(Time.zone.local(2021, 4, 1), Time.zone.local(2022, 3, 31)))
if (startdate_changed? || renewal_changed?) && renewal_was == 1 && startdate_was&.between?(Time.zone.local(2021, 4, 1), Time.zone.local(2022, 3, 31))
self.underoccupation_benefitcap = nil
end
if renewal_changed? && renewal_was == 1
@ -270,7 +270,7 @@ private
self.wchair = nil
self.location_id = nil
end
if form.start_year_2024_or_later? && (unittype_gn_changed? && unittype_gn_was == 2)
if form.start_year_2024_or_later? && unittype_gn_changed? && unittype_gn_was == 2
self.beds = nil
end
end
@ -439,13 +439,15 @@ private
def get_lar
return 1 if rent_type == 2
return 2 if rent_type == 1
2 if rent_type == 1
end
def get_irproduct
return 1 if rent_type == 3
return 2 if rent_type == 4
return 3 if rent_type == 5
3 if rent_type == 5
end
def clear_gender_description_unless_gender_not_same_as_sex!

2
app/models/derived_variables/shared_logic.rb

@ -9,7 +9,7 @@ private
previously_in_derived_state = dependency[:conditions].all? { |attribute, value| send("#{attribute}_was") == value }
next unless previously_in_derived_state
dependency[:derived_values].each do |derived_attribute, _derived_value|
dependency[:derived_values].each_key do |derived_attribute|
Rails.logger.debug("Cleared derived #{derived_attribute} value")
send("#{derived_attribute}=", nil)
end

24
app/models/form/lettings/pages/tenancyother_value_check.rb

@ -0,0 +1,24 @@
class Form::Lettings::Pages::TenancyotherValueCheck < ::Form::Page
def initialize(id, hsh, subsection)
super
@id = "tenancyother_value_check"
@copy_key = "lettings.soft_validations.tenancyother_value_check"
@depends_on = [{ "tenancyother_might_be_introductory_or_starter_period?" => true }]
@title_text = {
"translation" => "forms.#{form.start_date.year}.#{@copy_key}.title_text",
"arguments" => [{ "key" => "tenancyother", "i18n_template" => "tenancyother" }],
}
@informative_text = {
"translation" => "forms.#{form.start_date.year}.#{@copy_key}.informative_text",
"arguments" => [],
}
end
def questions
@questions ||= [Form::Lettings::Questions::TenancyotherValueCheck.new(nil, nil, self)]
end
def interruption_screen_question_ids
%w[startertenancy tenancy tenancyother]
end
end

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

@ -0,0 +1,13 @@
class Form::Lettings::Questions::TenancyotherValueCheck < ::Form::Question
def initialize(id, hsh, page)
super
@id = "tenancyother_value_check"
@copy_key = "lettings.soft_validations.tenancyother_value_check"
@type = "interruption_screen"
@check_answers_card_number = 0
@answer_options = ANSWER_OPTIONS
@hidden_in_check_answers = { "depends_on" => [{ "tenancyother_value_check" => 0 }, { "tenancyother_value_check" => 1 }] }
end
ANSWER_OPTIONS = { "0" => { "value" => "Yes" }, "1" => { "value" => "No" } }.freeze
end

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

@ -12,6 +12,7 @@ class Form::Lettings::Subsections::TenancyInformation < ::Form::Subsection
Form::Lettings::Pages::StarterTenancy.new("starter_tenancy", nil, self),
Form::Lettings::Pages::TenancyType.new(nil, nil, self),
Form::Lettings::Pages::StarterTenancyType.new(nil, nil, self),
(Form::Lettings::Pages::TenancyotherValueCheck.new(nil, nil, self) if form.start_year_2026_or_later?),
Form::Lettings::Pages::TenancyLength.new(nil, nil, self),
Form::Lettings::Pages::TenancyLengthAffordableRent.new(nil, nil, self),
Form::Lettings::Pages::TenancyLengthIntermediateRent.new(nil, nil, self),

3
app/models/form/sales/pages/deposit.rb

@ -23,6 +23,7 @@ class Form::Sales::Pages::Deposit < ::Form::Page
def copy_key
return "sales.sale_information.deposit.shared_ownership" if @ownershipsch == 1
return "sales.sale_information.deposit.discounted_ownership" if @ownershipsch == 2
return "sales.sale_information.deposit.outright_sale" if @ownershipsch == 3
"sales.sale_information.deposit.outright_sale" if @ownershipsch == 3
end
end

6
app/models/form/sales/questions/deposit_amount.rb

@ -29,12 +29,14 @@ class Form::Sales::Questions::DepositAmount < ::Form::Question
def top_guidance_partial
return "financial_calculations_shared_ownership" if @ownershipsch == 1
return "financial_calculations_discounted_ownership" if @ownershipsch == 2
return "financial_calculations_outright_sale" if @ownershipsch == 3
"financial_calculations_outright_sale" if @ownershipsch == 3
end
def copy_key
return "sales.sale_information.deposit.shared_ownership" if @ownershipsch == 1
return "sales.sale_information.deposit.discounted_ownership" if @ownershipsch == 2
return "sales.sale_information.deposit.outright_sale" if @ownershipsch == 3
"sales.sale_information.deposit.outright_sale" if @ownershipsch == 3
end
end

3
app/models/form/sales/questions/mortgage_amount.rb

@ -26,6 +26,7 @@ class Form::Sales::Questions::MortgageAmount < ::Form::Question
def top_guidance_partial
return "financial_calculations_shared_ownership" if @ownershipsch == 1
return "financial_calculations_discounted_ownership" if @ownershipsch == 2
return "financial_calculations_outright_sale" if @ownershipsch == 3
"financial_calculations_outright_sale" if @ownershipsch == 3
end
end

3
app/models/form/sales/questions/mortgageused.rb

@ -41,6 +41,7 @@ class Form::Sales::Questions::Mortgageused < ::Form::Question
def top_guidance_partial
return "financial_calculations_shared_ownership" if @ownershipsch == 1
return "financial_calculations_discounted_ownership" if @ownershipsch == 2
return "financial_calculations_outright_sale" if @ownershipsch == 3
"financial_calculations_outright_sale" if @ownershipsch == 3
end
end

3
app/models/form/sales/questions/purchase_price.rb

@ -30,6 +30,7 @@ class Form::Sales::Questions::PurchasePrice < ::Form::Question
def top_guidance_partial
return "financial_calculations_discounted_ownership" if @ownership_sch == 2
return "financial_calculations_outright_sale" if @ownership_sch == 3
"financial_calculations_outright_sale" if @ownership_sch == 3
end
end

2
app/models/form/subsection.rb

@ -1,5 +1,5 @@
class Form::Subsection
attr_accessor :id, :label, :section, :pages, :depends_on, :form
attr_accessor :id, :label, :section, :pages, :depends_on
def initialize(id, hsh, section)
@id = id

6
app/models/lettings_log.rb

@ -482,7 +482,7 @@ class LettingsLog < Log
def is_london_rent?
# 2: London Affordable Rent
# 4: London Living Rent
rent_type == 2 || rent_type == 4
[2, 4].include?(rent_type)
end
def previous_tenancy_was_foster_care?
@ -714,7 +714,7 @@ class LettingsLog < Log
end
def affordable_or_social_rent?
renttype == 1 || renttype == 2
[1, 2].include?(renttype)
end
def no_or_unknown_other_housing_needs?
@ -931,7 +931,7 @@ private
num_of_weeks = NUM_OF_WEEKS_FROM_PERIOD[period]
return "" unless value && num_of_weeks
format_as_currency((value * 52 / num_of_weeks))
format_as_currency(value * 52 / num_of_weeks)
end
def fully_wheelchair_accessible?

2
app/models/sales_log.rb

@ -533,7 +533,7 @@ class SalesLog < Log
end
def is_not_staircasing?
staircase == 2 || staircase == 3
[2, 3].include?(staircase)
end
def stairowned_100?

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

@ -136,7 +136,7 @@ module Validations::Sales::SaleInformationValidations
def validate_grant_amount(record)
return unless record.saledate && record.form.start_year_2024_or_later?
return unless record.grant && (record.type == 8 || record.type == 21)
return unless record.grant && [8, 21].include?(record.type)
unless record.grant.between?(9_000, 16_000)
record.errors.add :grant, I18n.t("validations.sales.sale_information.grant.out_of_range")

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

@ -144,7 +144,7 @@ module Validations::Sales::SoftValidations
def grant_outside_common_range?
return unless grant && type && saledate
return if form.start_year_2024_or_later? && (type == 21 || type == 8)
return if form.start_year_2024_or_later? && [21, 8].include?(type)
!grant.between?(9_000, 16_000)
end

10
app/models/validations/shared_validations.rb

@ -56,11 +56,11 @@ module Validations::SharedValidations
next unless incorrect_accuracy
case question.step
when 0.01 then record.errors.add question.id.to_sym, I18n.t("validations.shared.numeric.nearest_hundredth", field:)
when 0.1 then record.errors.add question.id.to_sym, I18n.t("validations.shared.numeric.nearest_tenth", field:)
when 1 then record.errors.add question.id.to_sym, :not_integer, message: I18n.t("validations.shared.numeric.whole_number", field:)
when 10 then record.errors.add question.id.to_sym, I18n.t("validations.shared.numeric.nearest_ten", field:)
case question.step.to_d
when BigDecimal("0.01") then record.errors.add question.id.to_sym, I18n.t("validations.shared.numeric.nearest_hundredth", field:)
when BigDecimal("0.1") then record.errors.add question.id.to_sym, I18n.t("validations.shared.numeric.nearest_tenth", field:)
when BigDecimal("1") then record.errors.add question.id.to_sym, :not_integer, message: I18n.t("validations.shared.numeric.whole_number", field:)
when BigDecimal("10") then record.errors.add question.id.to_sym, I18n.t("validations.shared.numeric.nearest_ten", field:)
else
record.errors.add question.id.to_sym, I18n.t("validations.shared.numeric.nearest_step", field:, step: question.step)
end

10
app/models/validations/soft_validations.rb

@ -194,6 +194,16 @@ module Validations::SoftValidations
PHRASES_LIKELY_TO_INDICATE_EXISTING_REASON_CATEGORY_REGEX.match?(reasonother)
end
PHRASES_LIKELY_TO_INDICATE_INTRODUCTORY_OR_STARTER_PERIOD = %w[introductory intro starter].freeze
PHRASES_LIKELY_TO_INDICATE_INTRODUCTORY_OR_STARTER_PERIOD_REGEX = Regexp.union(
PHRASES_LIKELY_TO_INDICATE_INTRODUCTORY_OR_STARTER_PERIOD.map { |phrase| Regexp.new("\\b[^[:alpha]]*#{phrase}[^[:alpha:]]*\\b", Regexp::IGNORECASE) },
)
def tenancyother_might_be_introductory_or_starter_period?
PHRASES_LIKELY_TO_INDICATE_INTRODUCTORY_OR_STARTER_PERIOD_REGEX.match?(tenancyother)
end
def multiple_partners?
return unless hhmemb

2
app/policies/location_policy.rb

@ -32,7 +32,7 @@ class LocationPolicy
def delete?
return false unless user.support?
return false unless location.status == :incomplete || location.status == :deactivated
return false unless %i[incomplete deactivated].include?(location.status)
!has_any_logs_in_editable_collection_period
end

2
app/policies/organisation_policy.rb

@ -20,7 +20,7 @@ class OrganisationPolicy
def delete?
return false unless user.support?
return false unless organisation.status == :deactivated || organisation.status == :merged
return false unless %i[deactivated merged].include?(organisation.status)
!has_any_logs_in_editable_collection_period
end

2
app/policies/scheme_policy.rb

@ -71,7 +71,7 @@ class SchemePolicy
def delete?
return false unless user.support?
return false unless scheme.status == :incomplete || scheme.status == :deactivated
return false unless %i[incomplete deactivated].include?(scheme.status)
!has_any_logs_in_editable_collection_period
end

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

@ -536,7 +536,7 @@ private
end
def validate_valid_radio_option
log.attributes.each do |question_id, _v|
log.attributes.each_key do |question_id|
question = log.form.get_question(question_id, log)
next unless question&.type == "radio"
@ -1321,22 +1321,26 @@ private
def scheme_field
return :field_16 if log_uses_new_scheme_id?
return :field_15 if log_uses_old_scheme_id?
:field_15 if log_uses_old_scheme_id?
end
def scheme_id
return field_16.strip if log_uses_new_scheme_id?
return field_15 if log_uses_old_scheme_id?
field_15 if log_uses_old_scheme_id?
end
def location_field
return :field_17 if log_uses_new_scheme_id?
return :field_16 if log_uses_old_scheme_id?
:field_16 if log_uses_old_scheme_id?
end
def location_id
return field_17 if log_uses_new_scheme_id?
return field_16 if log_uses_old_scheme_id?
field_16 if log_uses_old_scheme_id?
end
def scheme_or_management_group
@ -1424,7 +1428,8 @@ private
].each do |hash|
define_method("age#{hash[:person]}_known?") do
return 1 if public_send(hash[:field]) == "R"
return 0 if send("person_#{hash[:person]}_present?")
0 if send("person_#{hash[:person]}_present?")
end
end
@ -1488,7 +1493,8 @@ private
def housingneeds_other
return 1 if field_86 == 1
return 0 if [field_83, field_84, field_85].include?(1)
0 if [field_83, field_84, field_85].include?(1)
end
def prevloc
@ -1555,7 +1561,7 @@ private
end
def earnings
field_122.round if field_122.present?
field_122.presence&.round
end
def tshortfall_known

10
app/services/bulk_upload/lettings/year2024/row_parser.rb

@ -562,7 +562,7 @@ class BulkUpload::Lettings::Year2024::RowParser
private
def validate_valid_radio_option
log.attributes.each do |question_id, _v|
log.attributes.each_key do |question_id|
question = log.form.get_question(question_id, log)
next unless question&.type == "radio"
@ -1455,7 +1455,8 @@ private
].each do |hash|
define_method("age#{hash[:person]}_known?") do
return 1 if public_send(hash[:field]) == "R"
return 0 if send("person_#{hash[:person]}_present?")
0 if send("person_#{hash[:person]}_present?")
end
end
@ -1519,7 +1520,8 @@ private
def housingneeds_other
return 1 if field_82 == 1
return 0 if [field_79, field_80, field_81].include?(1)
0 if [field_79, field_80, field_81].include?(1)
end
def prevloc
@ -1595,7 +1597,7 @@ private
end
def earnings
field_119.round if field_119.present?
field_119.presence&.round
end
def tshortfall_known

10
app/services/bulk_upload/lettings/year2025/row_parser.rb

@ -561,7 +561,7 @@ class BulkUpload::Lettings::Year2025::RowParser
private
def validate_valid_radio_option
log.attributes.each do |question_id, _v|
log.attributes.each_key do |question_id|
question = log.form.get_question(question_id, log)
next unless question&.type == "radio"
@ -1452,7 +1452,8 @@ private
].each do |hash|
define_method("age#{hash[:person]}_known?") do
return 1 if public_send(hash[:field]) == "R"
return 0 if send("person_#{hash[:person]}_present?")
0 if send("person_#{hash[:person]}_present?")
end
end
@ -1516,7 +1517,8 @@ private
def housingneeds_other
return 1 if field_82 == 1
return 0 if [field_79, field_80, field_81].include?(1)
0 if [field_79, field_80, field_81].include?(1)
end
def prevloc
@ -1592,7 +1594,7 @@ private
end
def earnings
field_119.round if field_119.present?
field_119.presence&.round
end
def tshortfall_known

10
app/services/bulk_upload/lettings/year2026/row_parser.rb

@ -606,7 +606,7 @@ class BulkUpload::Lettings::Year2026::RowParser
private
def validate_valid_radio_option
log.attributes.each do |question_id, _v|
log.attributes.each_key do |question_id|
question = log.form.get_question(question_id, log)
next unless question&.type == "radio"
@ -1573,7 +1573,8 @@ private
].each do |hash|
define_method("age#{hash[:person]}_known?") do
return 1 if public_send(hash[:field]) == "R"
return 0 if send("person_#{hash[:person]}_present?")
0 if send("person_#{hash[:person]}_present?")
end
end
@ -1637,7 +1638,8 @@ private
def housingneeds_other
return 1 if field_82 == 1
return 0 if [field_79, field_80, field_81].include?(1)
0 if [field_79, field_80, field_81].include?(1)
end
def prevloc
@ -1713,7 +1715,7 @@ private
end
def earnings
field_119.round if field_119.present?
field_119.presence&.round
end
def tshortfall_known

43
app/services/bulk_upload/sales/year2023/row_parser.rb

@ -915,7 +915,7 @@ private
attributes["mortlen"] = mortlen
attributes["proplen"] = proplen if proplen&.positive?
attributes["proplen_asked"] = attributes["proplen"]&.present? ? 0 : 1
attributes["proplen_asked"] = attributes["proplen"].present? ? 0 : 1
attributes["jointmore"] = field_15
attributes["staircase"] = field_87
attributes["privacynotice"] = field_29
@ -992,7 +992,8 @@ private
].each do |hash|
define_method("age#{hash[:person]}_known?") do
return 1 if public_send(hash[:field]) == "R"
return 0 if send("person_#{hash[:person]}_present?")
0 if send("person_#{hash[:person]}_present?")
end
end
@ -1050,72 +1051,84 @@ private
def sale_type
return field_8 if shared_ownership?
return field_9 if discounted_ownership?
return field_10 if outright_sale?
field_10 if outright_sale?
end
def value
return field_103 if shared_ownership?
return field_116 if discounted_ownership?
return field_127 if outright_sale?
field_127 if outright_sale?
end
def mortgage
return field_106 if shared_ownership?
return field_120 if discounted_ownership?
return field_129 if outright_sale?
field_129 if outright_sale?
end
def extrabor
return field_110 if shared_ownership?
return field_124 if discounted_ownership?
return field_133 if outright_sale?
field_133 if outright_sale?
end
def deposit
return field_111 if shared_ownership?
return field_125 if discounted_ownership?
return field_134 if outright_sale?
field_134 if outright_sale?
end
def mscharge
return field_114 if shared_ownership?
return field_126 if discounted_ownership?
return field_135 if outright_sale?
field_135 if outright_sale?
end
def mortgagelender
return field_107 if shared_ownership?
return field_121 if discounted_ownership?
return field_130 if outright_sale?
field_130 if outright_sale?
end
def mortgagelenderother
return field_108 if shared_ownership?
return field_122 if discounted_ownership?
return field_131 if outright_sale?
field_131 if outright_sale?
end
def mortlen
return field_109 if shared_ownership?
return field_123 if discounted_ownership?
return field_132 if outright_sale?
field_132 if outright_sale?
end
def proplen
return field_86 if shared_ownership?
return field_115 if discounted_ownership?
field_115 if discounted_ownership?
end
def mortgageused
return field_105 if shared_ownership?
return field_119 if discounted_ownership?
return field_128 if outright_sale?
field_128 if outright_sale?
end
def mortgageused_field
return :field_105 if shared_ownership?
return :field_119 if discounted_ownership?
return :field_128 if outright_sale?
:field_128 if outright_sale?
end
def owning_organisation
@ -1263,7 +1276,7 @@ private
end
def validate_valid_radio_option
log.attributes.each do |question_id, _v|
log.attributes.each_key do |question_id|
question = log.form.get_question(question_id, log)
next if question_id == "type"

40
app/services/bulk_upload/sales/year2024/row_parser.rb

@ -938,7 +938,7 @@ private
attributes["mortlen"] = mortlen
attributes["proplen"] = proplen if proplen&.positive?
attributes["proplen_asked"] = attributes["proplen"]&.present? ? 0 : 1
attributes["proplen_asked"] = attributes["proplen"].present? ? 0 : 1
attributes["jointmore"] = field_16
attributes["staircase"] = field_86
attributes["privacynotice"] = field_18
@ -1026,7 +1026,8 @@ private
].each do |hash|
define_method("age#{hash[:person]}_known?") do
return 1 if public_send(hash[:field]) == "R"
return 0 if send("person_#{hash[:person]}_present?")
0 if send("person_#{hash[:person]}_present?")
end
end
@ -1084,64 +1085,75 @@ private
def sale_type
return field_9 if shared_ownership?
return field_10 if discounted_ownership?
return field_11 if outright_sale?
field_11 if outright_sale?
end
def value
return field_101 if shared_ownership?
return field_114 if discounted_ownership?
return field_125 if outright_sale?
field_125 if outright_sale?
end
def mortgage
return field_104 if shared_ownership?
return field_118 if discounted_ownership?
return field_127 if outright_sale?
field_127 if outright_sale?
end
def extrabor
return field_108 if shared_ownership?
return field_122 if discounted_ownership?
return field_129 if outright_sale?
field_129 if outright_sale?
end
def deposit
return field_109 if shared_ownership?
return field_123 if discounted_ownership?
return field_130 if outright_sale?
field_130 if outright_sale?
end
def mscharge
return field_112 if shared_ownership?
return field_124 if discounted_ownership?
return field_131 if outright_sale?
field_131 if outright_sale?
end
def mortgagelender
return field_105 if shared_ownership?
return field_119 if discounted_ownership?
field_119 if discounted_ownership?
end
def mortgagelenderother
return field_106 if shared_ownership?
return field_120 if discounted_ownership?
field_120 if discounted_ownership?
end
def mortlen
return field_107 if shared_ownership?
return field_121 if discounted_ownership?
return field_128 if outright_sale?
field_128 if outright_sale?
end
def proplen
return field_85 if shared_ownership?
return field_113 if discounted_ownership?
field_113 if discounted_ownership?
end
def mortgageused
return field_103 if shared_ownership?
return field_117 if discounted_ownership?
return field_126 if outright_sale?
field_126 if outright_sale?
end
def value_fields
@ -1393,7 +1405,7 @@ private
end
def validate_valid_radio_option
log.attributes.each do |question_id, _v|
log.attributes.each_key do |question_id|
question = log.form.get_question(question_id, log)
next if question_id == "type"

39
app/services/bulk_upload/sales/year2025/row_parser.rb

@ -906,7 +906,7 @@ private
attributes["mortlen"] = mortlen
attributes["proplen"] = proplen if proplen&.positive?
attributes["proplen_asked"] = attributes["proplen"]&.present? ? 0 : 1
attributes["proplen_asked"] = attributes["proplen"].present? ? 0 : 1
attributes["jointmore"] = field_13
attributes["staircase"] = field_10
attributes["privacynotice"] = field_15
@ -1008,7 +1008,8 @@ private
].each do |hash|
define_method("age#{hash[:person]}_known?") do
return 1 if public_send(hash[:field]) == "R"
return 0 if send("person_#{hash[:person]}_present?")
0 if send("person_#{hash[:person]}_present?")
end
end
@ -1076,58 +1077,68 @@ private
def sale_type
return field_9 if shared_ownership?
return field_11 if discounted_ownership?
field_11 if discounted_ownership?
end
def value
return field_86 if shared_ownership_initial_purchase?
return field_113 if discounted_ownership?
return field_107 if staircasing?
field_107 if staircasing?
end
def equity
return field_87 if shared_ownership_initial_purchase?
return field_108 if staircasing?
field_108 if staircasing?
end
def mortgage
return field_89 if shared_ownership?
return field_117 if discounted_ownership?
field_117 if discounted_ownership?
end
def extrabor
return field_119 if discounted_ownership?
field_119 if discounted_ownership?
end
def deposit
return field_91 if shared_ownership?
return field_120 if discounted_ownership?
field_120 if discounted_ownership?
end
def mrent
return field_93 if shared_ownership_initial_purchase?
return field_111 if staircasing?
field_111 if staircasing?
end
def mscharge
return field_94 if shared_ownership?
return field_121 if discounted_ownership?
field_121 if discounted_ownership?
end
def mortlen
return field_90 if shared_ownership?
return field_118 if discounted_ownership?
field_118 if discounted_ownership?
end
def proplen
return field_79 if shared_ownership?
return field_112 if discounted_ownership?
field_112 if discounted_ownership?
end
def mortgageused
return field_88 if shared_ownership_initial_purchase?
return field_116 if discounted_ownership?
return field_109 if staircasing?
field_109 if staircasing?
end
def value_fields
@ -1369,7 +1380,7 @@ private
end
def validate_valid_radio_option
log.attributes.each do |question_id, _v|
log.attributes.each_key do |question_id|
question = log.form.get_question(question_id, log)
next if question_id == "type"

39
app/services/bulk_upload/sales/year2026/row_parser.rb

@ -990,7 +990,7 @@ private
attributes["mortlen"] = mortlen
attributes["proplen"] = proplen if proplen&.positive?
attributes["proplen_asked"] = attributes["proplen"]&.present? ? 0 : 1
attributes["proplen_asked"] = attributes["proplen"].present? ? 0 : 1
attributes["jointmore"] = field_13
attributes["staircase"] = field_10
attributes["privacynotice"] = field_15
@ -1092,7 +1092,8 @@ private
].each do |hash|
define_method("age#{hash[:person]}_known?") do
return 1 if public_send(hash[:field]) == "R"
return 0 if send("person_#{hash[:person]}_present?")
0 if send("person_#{hash[:person]}_present?")
end
end
@ -1160,58 +1161,68 @@ private
def sale_type
return field_9 if shared_ownership?
return field_11 if discounted_ownership?
field_11 if discounted_ownership?
end
def value
return field_86 if shared_ownership_initial_purchase?
return field_113 if discounted_ownership?
return field_107 if staircasing?
field_107 if staircasing?
end
def equity
return field_87 if shared_ownership_initial_purchase?
return field_108 if staircasing?
field_108 if staircasing?
end
def mortgage
return field_89 if shared_ownership?
return field_117 if discounted_ownership?
field_117 if discounted_ownership?
end
def extrabor
return field_119 if discounted_ownership?
field_119 if discounted_ownership?
end
def deposit
return field_91 if shared_ownership?
return field_120 if discounted_ownership?
field_120 if discounted_ownership?
end
def mrent
return field_93 if shared_ownership_initial_purchase?
return field_111 if staircasing?
field_111 if staircasing?
end
def mscharge
return field_94 if shared_ownership?
return field_121 if discounted_ownership?
field_121 if discounted_ownership?
end
def mortlen
return field_90 if shared_ownership?
return field_118 if discounted_ownership?
field_118 if discounted_ownership?
end
def proplen
return field_79 if shared_ownership?
return field_112 if discounted_ownership?
field_112 if discounted_ownership?
end
def mortgageused
return field_88 if shared_ownership_initial_purchase?
return field_116 if discounted_ownership?
return field_109 if staircasing?
field_109 if staircasing?
end
def value_fields
@ -1454,7 +1465,7 @@ private
end
def validate_valid_radio_option
log.attributes.each do |question_id, _v|
log.attributes.each_key do |question_id|
question = log.form.get_question(question_id, log)
next if question_id == "type"

6
app/services/csv/lettings_log_csv_service.rb

@ -398,12 +398,14 @@ module Csv
def label_if_boolean_value(value)
return "Yes" if value == true
return "No" if value == false
"No" if value == false
end
def conventional_yes_no_label(value)
return "Yes" if value == 1
return "No" if value&.zero?
"No" if value&.zero?
end
end
end

3
app/services/csv/sales_log_csv_service.rb

@ -409,7 +409,8 @@ module Csv
def label_if_boolean_value(value)
return "Yes" if value == true
return "No" if value == false
"No" if value == false
end
end
end

2
app/services/documentation_generator.rb

@ -93,7 +93,7 @@ class DocumentationGenerator
interruption_screen_pages = form.pages.select { |page| page.questions.first.type == "interruption_screen" }
interruption_screen_pages_grouped_by_question = interruption_screen_pages.group_by { |page| page.questions.first.id }
interruption_screen_pages_grouped_by_question.each do |_question_id, pages|
interruption_screen_pages_grouped_by_question.each_value do |pages|
pages.map do |page|
save_soft_validation(form, page, validation_descriptions, log_type)
end

2
app/services/exports/organisation_export_constants.rb

@ -23,6 +23,6 @@ module Exports::OrganisationExportConstants
"dpo_email",
"profit_status",
"group",
"status"
"status",
]
end

2
app/services/filter_manager.rb

@ -121,7 +121,7 @@ class FilterManager
new_filters = new_filters.except("user") if params["assigned_to"] == "all"
new_filters["user"] = current_user.id.to_s if params["assigned_to"] == "you"
new_filters = new_filters.except("user_text_search") if params["assigned_to"] == "all" || params["assigned_to"] == "you"
new_filters = new_filters.except("user_text_search") if %w[all you].include?(params["assigned_to"])
new_filters = new_filters.except("owning_organisation_text_search") if params["owning_organisation_select"] == "all"
new_filters = new_filters.except("managing_organisation_text_search") if params["managing_organisation_select"] == "all"
end

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

@ -16,7 +16,7 @@
hint: { text: option["hint"] },
checked: @log[key] == 1,
exclusive: after_divider,
link_errors: index.zero? ? true : nil,
link_errors: index.zero? || nil,
**stimulus_html_attributes(question) %>
<% end %>
<% end %>

4
app/views/form/_interruption_screen_question.html.erb

@ -18,7 +18,7 @@
<div class="govuk-button-group">
<%= f.govuk_submit "Confirm and continue" %>
<%= govuk_link_to(
(@page.skip_text || "Skip for now"),
(@page.skip_href(@log) || send(@log.form.next_page_redirect_path(@page, @log, current_user, ignore_answered: true), @log)),
@page.skip_text || "Skip for now",
@page.skip_href(@log) || send(@log.form.next_page_redirect_path(@page, @log, current_user, ignore_answered: true), @log),
) %>
</div>

4
app/views/form/_radio_question.html.erb

@ -28,14 +28,14 @@
key,
label: { text: options["value"] },
hint: { text: options["hint"] },
link_errors: index.zero? ? true : nil,
link_errors: index.zero? || nil,
**stimulus_html_attributes(question) %>
<% else %>
<%= f.govuk_radio_button question.id.to_sym,
key,
label: { text: options["value"] },
hint: { text: options["hint"] },
link_errors: index.zero? ? true : nil,
link_errors: index.zero? || nil,
**stimulus_html_attributes(question) do %>
<%= render partial: "#{conditional_question.type}_question", locals: {
question: conditional_question,

2
app/views/rails_admin/main/_submit_buttons.html.erb

@ -1,6 +1,6 @@
<div class="form-actions row justify-content-end my-3">
<div class="col-sm-10">
<input name="return_to" type="<%= :hidden %>" value="<%= (params[:return_to].presence || request.referer) %>">
<input name="return_to" type="<%= :hidden %>" value="<%= params[:return_to].presence || request.referer %>">
<button class="govuk-button" data-disable-with="<%= t("admin.form.save") %>" name="_save" type="submit"<%= " disabled" unless @action.enabled? %>>
<i class="fas fa-check"></i>
<%= t("admin.form.save") %>

2
app/views/rails_admin/main/dashboard.html.erb

@ -40,7 +40,7 @@
-1
end %>
<div class="<%= active ? "active progress-bar-striped " : "" %>progress" style="margin-bottom:0px">
<div class="bg-<%= get_indicator(percent) %> progress-bar animate-width-to" data-animate-length="<%= ([1.0, percent].max.to_i * 20) %>" data-animate-width-to="<%= [2.0, percent].max.to_i %>%" style="width:2%">
<div class="bg-<%= get_indicator(percent) %> progress-bar animate-width-to" data-animate-length="<%= [1.0, percent].max.to_i * 20 %>" data-animate-width-to="<%= [2.0, percent].max.to_i %>%" style="width:2%">
<%= @count[abstract_model.model.name] %>
</div>
</div>

2
app/views/rails_admin/main/delete.html.erb

@ -7,7 +7,7 @@
<%= render partial: "delete_notice", object: @object %>
</ul>
<%= form_for(@object, url: delete_path(model_name: @abstract_model.to_param, id: @object.id), html: { method: "delete" }) do %>
<input name="return_to" type="<%= :hidden %>" value="<%= (params[:return_to].presence || request.referer) %>">
<input name="return_to" type="<%= :hidden %>" value="<%= params[:return_to].presence || request.referer %>">
<div class="form-actions">
<button class="govuk-button govuk-button--warning" data-disable-with="<%= t("admin.form.confirmation") %>" type="submit">
<i class="fas fa-check"></i>

8
config/initializers/multi_logger.rb

@ -4,13 +4,9 @@ class MultiLogger
@file_logger = file_logger
end
def info(data)
@rails_logger.info(data)
end
delegate :info, to: :@rails_logger
def warn(data)
@rails_logger.warn(data)
end
delegate :warn, to: :@rails_logger
def error(data)
@rails_logger.error(data)

2
config/initializers/sidekiq.rb

@ -32,7 +32,7 @@ Redis.silence_deprecations = true
Sidekiq.configure_server do |config|
config.on(:startup) do
Sidekiq::Cron::Job.all.each(&:destroy)
Sidekiq::Cron::Job.all.find_each(&:destroy)
unless FeatureToggle.service_moved? || FeatureToggle.service_unavailable?
Sidekiq::Cron::Job.load_from_hash YAML.load_file("config/sidekiq_cron_schedule.yml")
end

17
config/locales/forms/2026/lettings/soft_validations.en.yml

@ -57,6 +57,23 @@ en:
title_text: "You told us that the tenant’s main reason for leaving their last settled home was %{reasonother}."
informative_text: "The reason you have entered looks very similar to one of the existing response categories. Please check the categories and select the appropriate one. If the existing categories are not suitable, please confirm here to move onto the next question."
tenancyother_value_check:
page_header: ""
check_answer_label: "Tenancy other confirmation"
check_answer_prompt: "Confirm tenancy type"
hint_text: ""
question_text: ""
title_text: "You told us that the type of tenancy was %{tenancyother}."
informative_text: "We already know whether the tenancy is introductory or has a starter period from your previous answer. Your answer to the type of main tenancy question should be the type of tenancy that the tenant will roll onto after any introductory or starter period. Choose from the categories or write a description if no category is suitable."
referral_value_check:
page_header: ""
check_answer_label: "Referral confirmation"
check_answer_prompt: "Confirm referral type"
hint_text: ""
question_text: "Are you sure?"
title_text: "Are you sure?"
informative_text: "This is a general needs log, and this referral type is for supported housing."
net_income_value_check:
page_header: ""
check_answer_label: "Net income confirmation"

4
config/routes.rb

@ -301,7 +301,7 @@ Rails.application.routes.draw do
get "review", to: "form#review"
end
FormHandler.instance.lettings_forms.each do |_key, form|
FormHandler.instance.lettings_forms.each_value do |form|
form.pages.map do |page|
get page.id.to_s.dasherize, to: "form#show_page"
post page.id.to_s.dasherize, to: "form#submit_form"
@ -377,7 +377,7 @@ Rails.application.routes.draw do
get "review", to: "form#review"
end
FormHandler.instance.sales_forms.each do |_key, form|
FormHandler.instance.sales_forms.each_value do |form|
form.pages.map do |page|
get page.id.to_s.dasherize, to: "form#show_page"
post page.id.to_s.dasherize, to: "form#submit_form"

2
db/migrate/20241206142943_create_active_storage_variant_records.active_storage.rb

@ -4,7 +4,7 @@ class CreateActiveStorageVariantRecords < ActiveRecord::Migration[6.0]
return unless table_exists?(:active_storage_blobs)
# Use Active Record's configured type for primary key
create_table :active_storage_variant_records, id: primary_key_type, if_not_exists: true do |t| # rubocop:disable Rails/CreateTableWithTimestamps
create_table :active_storage_variant_records, id: primary_key_type, if_not_exists: true do |t|
t.belongs_to :blob, null: false, index: false, type: blobs_primary_key_type
t.string :variation_digest, null: false

5
db/migrate/20260212091506_add_tenancyother_value_check_to_lettings_logs.rb

@ -0,0 +1,5 @@
class AddTenancyotherValueCheckToLettingsLogs < ActiveRecord::Migration[7.0]
def change
add_column :lettings_logs, :tenancyother_value_check, :integer
end
end

1
db/schema.rb

@ -403,6 +403,7 @@ ActiveRecord::Schema[7.2].define(version: 2026_02_20_141000) do
t.integer "referral_register"
t.integer "referral_noms"
t.integer "referral_org"
t.integer "tenancyother_value_check"
t.index ["assigned_to_id"], name: "index_lettings_logs_on_assigned_to_id"
t.index ["bulk_upload_id"], name: "index_lettings_logs_on_bulk_upload_id"
t.index ["created_by_id"], name: "index_lettings_logs_on_created_by_id"

4
docs/setup.md

@ -70,8 +70,8 @@ We recommend using [nvm](https://github.com/nvm-sh/nvm) to manage NodeJS version
4. Install Ruby and Bundler
```bash
rbenv install 3.1.6
rbenv global 3.1.6
rbenv install 3.4.4
rbenv global 3.4.4
source ~/.bashrc
gem install bundler
```

2
lib/tasks/generate_lettings_documentation.rake

@ -50,7 +50,7 @@ namespace :generate_lettings_documentation do
all_validation_methods = row_parser_class.private_instance_methods.select { |method| method.starts_with?("validate_") }
all_helper_methods = row_parser_class.private_instance_methods(false) + row_parser_class.instance_methods(false) - all_validation_methods
all_helper_methods = row_parser_class.private_instance_methods(false) + row_parser_class.instance_methods(false) - all_validation_methods
field_mapping_for_errors = row_parser_class.new.send("field_mapping_for_errors")
DocumentationGenerator.new.describe_bu_validations(client, form, row_parser_class, all_validation_methods, all_helper_methods, field_mapping_for_errors, "lettings")

2
lib/tasks/generate_sales_documentation.rake

@ -47,7 +47,7 @@ namespace :generate_sales_documentation do
row_parser_class = "BulkUpload::Sales::Year#{form_year}::RowParser".constantize
client = OpenAI::Client.new(access_token: ENV["OPENAI_API_KEY"])
all_validation_methods = row_parser_class.private_instance_methods.select { |method| method.starts_with?("validate_") }
all_helper_methods = row_parser_class.private_instance_methods(false) + row_parser_class.instance_methods(false) - all_validation_methods
all_helper_methods = row_parser_class.private_instance_methods(false) + row_parser_class.instance_methods(false) - all_validation_methods
field_mapping_for_errors = row_parser_class.new.send("field_mapping_for_errors")
DocumentationGenerator.new.describe_bu_validations(client, form, row_parser_class, all_validation_methods, all_helper_methods, field_mapping_for_errors, "sales")

4
lib/tasks/handle_unpended_logs.rake

@ -62,13 +62,13 @@ task :handle_unpended_logs, %i[perform_updates] => :environment do |_task, args|
visible_duplicates = duplicates.where(status: %w[in_progress completed])
deleted_duplicates = duplicates.where(status: %w[deleted])
if visible_duplicates.length.zero? && deleted_duplicates.any? { |dup| dup.discarded_at > result["created_at"] }
if visible_duplicates.empty? && deleted_duplicates.any? { |dup| dup.discarded_at > result["created_at"] }
seen.add(id)
csv << [id, log.collection_start_year, log.status, log.owning_organisation_name, log.assigned_to_id, log.assigned_to.email, "Leave", "Log has no visible duplicates and at least one duplicate has been deleted since being affected"]
next
end
if visible_duplicates.length.zero?
if visible_duplicates.empty?
seen.add(id)
csv << [id, log.collection_start_year, log.status, log.owning_organisation_name, log.assigned_to_id, log.assigned_to.email, "Leave", "Log has no visible duplicates"]
next

2
lib/tasks/lint.rake

@ -5,7 +5,7 @@ end
desc "Run ERB Lint"
task erblint: :environment do
sh "bundle exec erblint --lint-all"
sh "bundle exec erb_lint --lint-all"
end
desc "Run Standard"

2
lib/tasks/set_log_validation_collection_year.rake

@ -1,6 +1,6 @@
desc "Sets value for collection_year log validations depending on the from value"
task set_log_validation_collection_year: :environment do
LogValidation.all.each do |log_validation|
LogValidation.all.find_each do |log_validation|
log_validation.update(collection_year: "#{log_validation.from.year}/#{log_validation.from.year + 1}")
end
end

2
spec/components/bulk_upload_error_row_component_spec.rb

@ -46,7 +46,7 @@ RSpec.describe BulkUploadErrorRowComponent, type: :component do
end
context "when the bulk upload is for 2024" do
context "with a lettings bulk upload" do
context "with a lettings bulk upload" do
let(:bulk_upload) { build(:bulk_upload, :lettings, year: 2024) }
let(:field) { :field_130 }

4
spec/components/check_answers_summary_list_card_component_spec.rb

@ -17,7 +17,7 @@ RSpec.describe CheckAnswersSummaryListCardComponent, type: :component do
end
it "applicable questions doesn't return questions that are hidden in check answers" do
expect(component.applicable_questions.map(&:id).include?("retirement_value_check")).to eq(false)
expect(component.applicable_questions.map(&:id).include?("retirement_value_check")).to be(false)
end
it "has the correct answer label for a question" do
@ -45,7 +45,7 @@ RSpec.describe CheckAnswersSummaryListCardComponent, type: :component do
context "when log was not created via a bulk upload and has an unanswered question" do
let(:log) { create(:lettings_log, :in_progress) }
it "displays normal copy with muted colour " do
it "displays normal copy with muted colour" do
expect(rendered).to have_link(log.form.get_question("sex1", log).check_answer_prompt, href: "/lettings-logs/#{log.id}/lead-tenant-gender-identity?referrer=check_answers_new_answer", class: "govuk-link govuk-link--no-visited-state")
end
end

16
spec/components/create_log_actions_component_spec.rb

@ -14,7 +14,7 @@ RSpec.describe CreateLogActionsComponent, type: :component do
let(:bulk_upload) { true }
it "does not render actions" do
expect(component.display_actions?).to eq(false)
expect(component.display_actions?).to be(false)
end
end
@ -25,7 +25,7 @@ RSpec.describe CreateLogActionsComponent, type: :component do
let(:user) { create(:user, :support) }
it "renders actions" do
expect(component.display_actions?).to eq(true)
expect(component.display_actions?).to be(true)
end
it "returns create button copy" do
@ -60,7 +60,7 @@ RSpec.describe CreateLogActionsComponent, type: :component do
let(:log_type) { "sales" }
it "renders actions" do
expect(component.display_actions?).to eq(true)
expect(component.display_actions?).to be(true)
end
it "returns create button copy" do
@ -97,7 +97,7 @@ RSpec.describe CreateLogActionsComponent, type: :component do
let(:user) { create(:user) }
it "renders actions" do
expect(component.display_actions?).to eq(true)
expect(component.display_actions?).to be(true)
end
it "returns create button copy" do
@ -122,7 +122,7 @@ RSpec.describe CreateLogActionsComponent, type: :component do
let(:log_type) { "sales" }
it "renders actions" do
expect(component.display_actions?).to eq(true)
expect(component.display_actions?).to be(true)
end
it "returns create button copy" do
@ -147,7 +147,7 @@ RSpec.describe CreateLogActionsComponent, type: :component do
end
it "renders actions" do
expect(component.display_actions?).to eq(true)
expect(component.display_actions?).to be(true)
end
end
@ -159,7 +159,7 @@ RSpec.describe CreateLogActionsComponent, type: :component do
end
it "renders actions" do
expect(component.display_actions?).to eq(false)
expect(component.display_actions?).to be(false)
end
end
@ -170,7 +170,7 @@ RSpec.describe CreateLogActionsComponent, type: :component do
end
it "does not render actions" do
expect(component.display_actions?).to eq(false)
expect(component.display_actions?).to be(false)
end
end
end

28
spec/components/data_protection_confirmation_banner_component_spec.rb

@ -13,7 +13,7 @@ RSpec.describe DataProtectionConfirmationBannerComponent, type: :component do
let(:organisation) { nil }
it "does not display banner" do
expect(component.display_banner?).to eq(false)
expect(component.display_banner?).to be(false)
expect(render.content).to be_empty
end
end
@ -24,7 +24,7 @@ RSpec.describe DataProtectionConfirmationBannerComponent, type: :component do
end
it "displays the banner" do
expect(component.display_banner?).to eq(true)
expect(component.display_banner?).to be(true)
expect(render).to have_link(
"Contact helpdesk to assign a data protection officer",
href: "https://mhclgdigital.atlassian.net/servicedesk/customer/portal/6/group/11",
@ -41,7 +41,7 @@ RSpec.describe DataProtectionConfirmationBannerComponent, type: :component do
let!(:dpo) { create(:user, :data_protection_officer, organisation:, with_dsa: false) }
it "displays the banner and shows DPOs" do
expect(component.display_banner?).to eq(true)
expect(component.display_banner?).to be(true)
expect(render.css("a")).to be_empty
expect(render).to have_selector("p", text: "Your data protection officer must accept the Data Sharing Agreement on CORE before you can create any logs.")
expect(render).to have_selector("p", text: "You can ask: #{dpo.name}")
@ -53,7 +53,7 @@ RSpec.describe DataProtectionConfirmationBannerComponent, type: :component do
let(:user) { create(:user, :data_protection_officer, organisation:, with_dsa: false) }
it "displays the banner and asks to sign" do
expect(component.display_banner?).to eq(true)
expect(component.display_banner?).to be(true)
expect(render).to have_link(
"Read the Data Sharing Agreement",
href: "/organisations/#{organisation.id}/data-sharing-agreement",
@ -71,7 +71,7 @@ RSpec.describe DataProtectionConfirmationBannerComponent, type: :component do
end
it "displays the banner and asks to sign" do
expect(component.display_banner?).to eq(true)
expect(component.display_banner?).to be(true)
expect(render).to have_link(
"Read the Data Sharing Agreement",
href: "/organisations/#{organisation.id}/data-sharing-agreement",
@ -83,7 +83,7 @@ RSpec.describe DataProtectionConfirmationBannerComponent, type: :component do
context "when org has a signed data sharing agremeent" do
it "does not display banner" do
expect(component.display_banner?).to eq(false)
expect(component.display_banner?).to be(false)
expect(render.content).to be_empty
end
@ -99,7 +99,7 @@ RSpec.describe DataProtectionConfirmationBannerComponent, type: :component do
end
it "does not display banner" do
expect(component.display_banner?).to eq(false)
expect(component.display_banner?).to be(false)
expect(render.content).to be_empty
end
end
@ -111,7 +111,7 @@ RSpec.describe DataProtectionConfirmationBannerComponent, type: :component do
end
it "displays the banner and asks to create stock owners" do
expect(component.display_banner?).to eq(true)
expect(component.display_banner?).to be(true)
expect(render).to have_link(
"View or add stock owners",
href: "/organisations/#{organisation.id}/stock-owners",
@ -128,7 +128,7 @@ RSpec.describe DataProtectionConfirmationBannerComponent, type: :component do
end
it "displays the banner" do
expect(component.display_banner?).to eq(true)
expect(component.display_banner?).to be(true)
expect(render).to have_link(
"Contact helpdesk to assign a data protection officer",
href: "https://mhclgdigital.atlassian.net/servicedesk/customer/portal/6/group/11",
@ -145,7 +145,7 @@ RSpec.describe DataProtectionConfirmationBannerComponent, type: :component do
let!(:dpo) { create(:user, :data_protection_officer, organisation:, with_dsa: false) }
it "displays the banner and shows DPOs" do
expect(component.display_banner?).to eq(true)
expect(component.display_banner?).to be(true)
expect(render.css("a")).to be_empty
expect(render).to have_selector("p", text: "Your data protection officer must accept the Data Sharing Agreement on CORE before you can create any logs.")
expect(render).to have_selector("p", text: "You can ask: #{dpo.name}")
@ -158,7 +158,7 @@ RSpec.describe DataProtectionConfirmationBannerComponent, type: :component do
end
it "displays the banner and shows DPOs" do
expect(component.display_banner?).to eq(true)
expect(component.display_banner?).to be(true)
expect(render.css("a")).to be_empty
expect(render).to have_selector("p", text: "Your data protection officer must accept the Data Sharing Agreement on CORE before you can create any logs.")
expect(render).to have_selector("p", text: "You can ask: #{dpo.name}")
@ -171,7 +171,7 @@ RSpec.describe DataProtectionConfirmationBannerComponent, type: :component do
let(:user) { create(:user, :data_protection_officer, organisation:, with_dsa: false) }
it "displays the banner and asks to sign" do
expect(component.display_banner?).to eq(true)
expect(component.display_banner?).to be(true)
expect(render).to have_link(
"Read the Data Sharing Agreement",
href: "/organisations/#{organisation.id}/data-sharing-agreement",
@ -186,7 +186,7 @@ RSpec.describe DataProtectionConfirmationBannerComponent, type: :component do
end
it "displays the banner and asks to sign" do
expect(component.display_banner?).to eq(true)
expect(component.display_banner?).to be(true)
expect(render).to have_link(
"Read the Data Sharing Agreement",
href: "/organisations/#{organisation.id}/data-sharing-agreement",
@ -199,7 +199,7 @@ RSpec.describe DataProtectionConfirmationBannerComponent, type: :component do
context "when org has a signed data sharing agremeent" do
it "does not display banner" do
expect(component.display_banner?).to eq(false)
expect(component.display_banner?).to be(false)
expect(render.content).to be_empty
end
end

3
spec/db/seeds_spec.rb

@ -17,8 +17,7 @@ RSpec.describe "seeding process", type: task do
Rake.application.rake_require("tasks/rent_ranges")
Rake::Task.define_task(:environment)
allow(Rails.env).to receive(:test?).and_return(false)
allow(Rails.env).to receive(:review?).and_return(true)
allow(Rails.env).to receive_messages(test?: false, review?: true)
end
# Doing this in one test should save ~2 minutes

2
spec/factories/data_protection_confirmation.rb

@ -1,7 +1,7 @@
FactoryBot.define do
factory :data_protection_confirmation do
organisation { association :organisation, data_protection_confirmation: instance }
data_protection_officer { association :user, :data_protection_officer, organisation: (instance.organisation || organisation) }
data_protection_officer { association :user, :data_protection_officer, organisation: instance.organisation || organisation }
organisation_name { organisation.name }
organisation_address { organisation.address_row }

2
spec/features/accessibility_spec.rb

@ -1,6 +1,6 @@
require "rails_helper"
RSpec.describe "Accessibility", js: true do
RSpec.describe "Accessibility", :js do
let(:user) { create(:user, :support) }
let!(:other_user) { create(:user, name: "new user", organisation: user.organisation, email: "new_user@example.com", confirmation_token: "abc") }
let(:storage_service) { instance_double(Storage::S3Service, get_file_metadata: nil) }

4
spec/features/bulk_upload_lettings_logs_spec.rb

@ -9,7 +9,7 @@ RSpec.describe "Bulk upload lettings log" do
let(:stub_file_upload) do
vcap_services = { "aws-s3-bucket" => {} }
mock_storage_service = instance_double("S3Service")
mock_storage_service = instance_double(Storage::S3Service)
allow(ENV).to receive(:[])
allow(ENV).to receive(:[]).with("VCAP_SERVICES").and_return(vcap_services.to_json)
@ -76,7 +76,7 @@ RSpec.describe "Bulk upload lettings log" do
end
it "shows file to large error" do
stub_const("Forms::BulkUploadForm::UploadYourFile::MAX_FILE_SIZE", 1.bytes)
stub_const("Forms::BulkUploadForm::UploadYourFile::MAX_FILE_SIZE", 1.byte)
visit("/lettings-logs")
click_link("Upload lettings logs in bulk")

4
spec/features/bulk_upload_sales_logs_spec.rb

@ -8,7 +8,7 @@ RSpec.describe "Bulk upload sales log" do
let(:stub_file_upload) do
vcap_services = { "aws-s3-bucket" => {} }
mock_storage_service = instance_double("S3Service")
mock_storage_service = instance_double(Storage::S3Service)
allow(ENV).to receive(:[])
allow(ENV).to receive(:[]).with("VCAP_SERVICES").and_return(vcap_services.to_json)
@ -71,7 +71,7 @@ RSpec.describe "Bulk upload sales log" do
end
it "shows file to large error" do
stub_const("Forms::BulkUploadForm::UploadYourFile::MAX_FILE_SIZE", 1.bytes)
stub_const("Forms::BulkUploadForm::UploadYourFile::MAX_FILE_SIZE", 1.byte)
visit("/sales-logs")
click_link("Upload sales logs in bulk")

20
spec/features/form/accessible_autocomplete_spec.rb

@ -25,38 +25,38 @@ RSpec.describe "Accessible Autocomplete" do
visit("/lettings-logs/#{lettings_log.id}/previous-local-authority")
end
it "allows type ahead filtering", js: true do
it "allows type ahead filtering", :js do
find("#lettings-log-prevloc-field").click.native.send_keys("T", "h", "a", "n", :down, :enter)
expect(find("#lettings-log-prevloc-field").value).to eq("Thanet")
end
it "ignores punctuation", js: true do
it "ignores punctuation", :js do
find("#lettings-log-prevloc-field").click.native.send_keys("T", "h", "a", "'", "n", :down, :enter)
expect(find("#lettings-log-prevloc-field").value).to eq("Thanet")
end
it "ignores stop words", js: true do
it "ignores stop words", :js do
find("#lettings-log-prevloc-field").click.native.send_keys("t", "h", "e", " ", "W", "e", "s", "t", "m", :down, :enter)
expect(find("#lettings-log-prevloc-field").value).to eq("Westmorland and Furness")
end
it "does not perform an exact match", js: true do
it "does not perform an exact match", :js do
find("#lettings-log-prevloc-field").click.native.send_keys("K", "i", "n", "g", "s", "t", "o", "n", " ", "T", "h", "a", "m", "e", "s", :down, :enter)
expect(find("#lettings-log-prevloc-field").value).to eq("Kingston upon Thames")
end
it "maintains enhancement state across back navigation", js: true do
it "maintains enhancement state across back navigation", :js do
find("#lettings-log-prevloc-field").click.native.send_keys("T", "h", "a", "n", :down, :enter)
click_button("Save and continue")
page.go_back
expect(page).to have_selector("input", class: "autocomplete__input", count: 1)
end
it "displays the placeholder text", js: true do
it "displays the placeholder text", :js do
expect(find("#lettings-log-prevloc-field")["placeholder"]).to eq("Start typing to search")
end
context "and multiple schemes with same names", js: true do
context "and multiple schemes with same names", :js do
let(:lettings_log) { FactoryBot.create(:lettings_log, :sh, assigned_to: user) }
let!(:schemes) { FactoryBot.create_list(:scheme, 2, owning_organisation_id: user.organisation_id, service_name: "Scheme", primary_client_group: "O", secondary_client_group: "O") }
@ -98,18 +98,18 @@ RSpec.describe "Accessible Autocomplete" do
visit("/lettings-logs/#{lettings_log.id}/scheme")
end
it "can match on synonyms", js: true do
it "can match on synonyms", :js do
find("#lettings-log-scheme-id-field").click.native.send_keys("w", "6", :down, :enter)
expect(find("#lettings-log-scheme-id-field").value).to include(scheme.service_name)
end
it "displays appended text next to the options", js: true do
it "displays appended text next to the options", :js do
find("#lettings-log-scheme-id-field").click.native.send_keys("w", "6", :down, :enter)
expect(find(".autocomplete__option", visible: :hidden, text: scheme.service_name)).to be_present
expect(find("span", visible: :hidden, text: "2 completed locations, 1 incomplete location")).to be_present
end
it "displays hint text under the options", js: true do
it "displays hint text under the options", :js do
find("#lettings-log-scheme-id-field").click.native.send_keys("w", "6", :down, :enter)
expect(find(".autocomplete__option__hint", visible: :hidden, text: /Young people at risk, Young people leaving care/)).to be_present
end

6
spec/features/form/address_search_spec.rb

@ -22,17 +22,17 @@ RSpec.describe "Address Search" do
visit("/sales-logs/#{sales_log.id}/address-search")
end
it "allows searching by a UPRN", js: true do
it "allows searching by a UPRN", :js do
find("#sales-log-uprn-field").click.native.send_keys("1", "0", "0", "3", "3", "5", "4", "4", "6", "1", "4", :down)
expect(find("#sales-log-uprn-field").value).to eq("10033544614")
end
it "allows searching by address", js: true do
it "allows searching by address", :js do
find("#sales-log-uprn-field").click.native.send_keys("S", "W", "1", "5", :down, :enter)
expect(find("#sales-log-uprn-field").value).to eq("SW15")
end
it "displays the placeholder text", js: true do
it "displays the placeholder text", :js do
expect(find("#sales-log-uprn-field")["placeholder"]).to eq("Start typing to search")
end

2
spec/features/form/checkboxes_spec.rb

@ -29,7 +29,7 @@ RSpec.describe "Checkboxes" do
sign_in user
end
context "when exclusive checkbox is selected", js: true do
context "when exclusive checkbox is selected", :js do
it "deselects all other checkboxes" do
visit("/lettings-logs/#{id}/accessibility-requirements")
page.check("lettings-log-accessibility-requirements-housingneeds-a-field", allow_label_click: true)

6
spec/features/form/conditional_questions_spec.rb

@ -47,7 +47,7 @@ RSpec.describe "Form Conditional Questions" do
expect(page).not_to have_selector("#armed_forces_injured_div")
end
it "shows conditional questions if the required answer is selected and hides it again when a different answer option is selected", js: true do
it "shows conditional questions if the required answer is selected and hides it again when a different answer option is selected", :js do
visit("/lettings-logs/#{id}/armed-forces")
# Something about our styling makes the selenium webdriver think the actual radio buttons are not visible so we allow label click here
choose("lettings-log-armedforces-1-field", allow_label_click: true)
@ -59,7 +59,7 @@ RSpec.describe "Form Conditional Questions" do
end
end
context "when a conditional question has a saved answer", js: true do
context "when a conditional question has a saved answer", :js do
before do
allow(sales_log.form).to receive(:new_logs_end_date).and_return(Time.zone.today + 1.day)
allow(lettings_log.form).to receive(:new_logs_end_date).and_return(Time.zone.today + 1.day)
@ -96,7 +96,7 @@ RSpec.describe "Form Conditional Questions" do
FormHandler.instance.use_real_forms!
end
it "shows conditional questions if the required answer is selected and hides it again when a different answer option is selected", js: true do
it "shows conditional questions if the required answer is selected and hides it again when a different answer option is selected", :js do
visit("/lettings-logs/#{id}/lead-tenant-age")
choose("lettings-log-age1-known-0-field", allow_label_click: true)
fill_in("lettings-log-age1-field", with: "200")

28
spec/features/form/page_routing_spec.rb

@ -29,7 +29,7 @@ RSpec.describe "Form Page Routing" do
Singleton.__init__(FormHandler)
end
it "can route the user to a different page based on their answer on the current page", js: true do
it "can route the user to a different page based on their answer on the current page", :js do
visit("/lettings-logs/#{id}/conditional-question")
# using a question name that is already in the db to avoid
# having to add a new column to the db for this test
@ -43,7 +43,7 @@ RSpec.describe "Form Page Routing" do
expect(page).to have_current_path("/lettings-logs/#{id}/conditional-question-no-page")
end
it "can route based on multiple conditions", js: true do
it "can route based on multiple conditions", :js do
visit("/lettings-logs/#{id}/person-1-gender")
choose("lettings-log-sex1-f-field", allow_label_click: true)
click_button("Save and continue")
@ -57,7 +57,7 @@ RSpec.describe "Form Page Routing" do
expect(page).to have_current_path("/lettings-logs/#{id}/conditional-question/check-answers")
end
context "when the answers are inferred", js: true do
context "when the answers are inferred", :js do
it "shows question if the answer could not be inferred" do
visit("/lettings-logs/#{id}/property-postcode")
fill_in("lettings-log-postcode-full-field", with: "PO5 3TE")
@ -119,7 +119,7 @@ RSpec.describe "Form Page Routing" do
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{id}/tenancy-start-date")
expect(find_field("lettings_log[startdate]").value).to eq(nil)
expect(find_field("lettings_log[startdate]").value).to be_nil
end
it "does not show see all related answers link if only 1 field has an error" do
@ -170,21 +170,21 @@ RSpec.describe "Form Page Routing" do
it "returns true if there is no depends_on" do
depends_on = nil
expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to eq(true)
expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to be(true)
end
it "returns true if the depends_on is met" do
depends_on = [{ "armedforces" => 1 }]
lettings_log.armedforces = 1
expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to eq(true)
expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to be(true)
end
it "returns false if the depends_on is not met" do
depends_on = [{ "armedforces" => 1 }]
lettings_log.armedforces = 0
expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to eq(false)
expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to be(false)
end
it "returns true if a complex depends_on is met" do
@ -192,7 +192,7 @@ RSpec.describe "Form Page Routing" do
lettings_log.is_la_inferred = false
lettings_log.needstype = 1
expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to eq(true)
expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to be(true)
end
it "returns false if any part of a complex depends_on is not met" do
@ -200,7 +200,7 @@ RSpec.describe "Form Page Routing" do
lettings_log.is_la_inferred = false
lettings_log.needstype = 2
expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to eq(false)
expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to be(false)
end
it "returns true if the first of multiple depends_ons are met" do
@ -208,7 +208,7 @@ RSpec.describe "Form Page Routing" do
lettings_log.is_la_inferred = false
lettings_log.needstype = 2
expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to eq(true)
expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to be(true)
end
it "returns true if the last of multiple depends_ons are met" do
@ -216,7 +216,7 @@ RSpec.describe "Form Page Routing" do
lettings_log.is_la_inferred = true
lettings_log.needstype = 1
expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to eq(true)
expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to be(true)
end
context "with operator-based depends_ons" do
@ -234,7 +234,7 @@ RSpec.describe "Form Page Routing" do
lettings_log.details_known_2 = 0
lettings_log.age2 = 16
expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to eq(true)
expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to be(true)
end
it "returns false if an operator-based depends_on is not met" do
@ -251,7 +251,7 @@ RSpec.describe "Form Page Routing" do
lettings_log.details_known_2 = 0
lettings_log.age2 = 15
expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to eq(false)
expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to be(false)
end
it "returns true if an operator-based depends_on is met on an inequality threshold" do
@ -268,7 +268,7 @@ RSpec.describe "Form Page Routing" do
lettings_log.details_known_2 = 0
lettings_log.age2 = 15
expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to eq(true)
expect(lettings_log.form.depends_on_met(depends_on, lettings_log)).to be(true)
end
end
end

4
spec/features/form/progressive_total_field_spec.rb

@ -31,7 +31,7 @@ RSpec.describe "Accessible Autocomplete" do
expect(page).to have_selector("#tcharge_div", visible: :all)
end
it "does show when js is enabled and calculates the total", js: true do
it "does show when js is enabled and calculates the total", :js do
visit("/lettings-logs/#{lettings_log.id}/rent")
expect(page).to have_selector("#tcharge_div")
fill_in("lettings-log-brent-field", with: 5)
@ -40,7 +40,7 @@ RSpec.describe "Accessible Autocomplete" do
expect(find("#lettings-log-tcharge-field").value).to eq("8.00")
end
it "total displays despite error message", js: true do
it "total displays despite error message", :js do
visit("/lettings-logs/#{lettings_log.id}/rent")
choose("lettings-log-period-1-field", allow_label_click: true)
fill_in("lettings-log-brent-field", with: 500)

2
spec/features/form/saving_data_spec.rb

@ -62,7 +62,7 @@ RSpec.describe "Form Saving Data" do
end
end
it "updates total value of the rent", js: true do
it "updates total value of the rent", :js do
visit("/lettings-logs/#{id}/rent")
fill_in("lettings-log-brent-field", with: 3.02)

2
spec/features/form/validations_spec.rb

@ -60,7 +60,7 @@ RSpec.describe "validations" do
end
end
describe "date validation", js: true do
describe "date validation", :js do
def fill_in_date(lettings_log_id, question, day, month, year, path)
visit("/lettings-logs/#{lettings_log_id}/#{path}")
fill_in("lettings_log[#{question}]", with: [day, month, year].join("/"))

6
spec/features/lettings_log_spec.rb

@ -398,7 +398,7 @@ RSpec.describe "Lettings Log Features" do
rows = page.find_all "tbody tr"
expect(rows.count).to be 2
id_to_delete, id_to_keep = rows.map { |row| row.first("td").text.to_i }
expect([id_to_delete, id_to_keep]).to match_array [lettings_log_1.id, lettings_log_2.id]
expect([id_to_delete, id_to_keep]).to contain_exactly(lettings_log_1.id, lettings_log_2.id)
check "forms-delete-logs-form-selected-ids-#{id_to_delete}-field"
uncheck "forms-delete-logs-form-selected-ids-#{id_to_keep}-field"
click_button "Continue"
@ -413,13 +413,13 @@ RSpec.describe "Lettings Log Features" do
expect(page.find("article.app-log-summary h2").text).to eq "Log #{id_to_keep}"
deleted_log = LettingsLog.find(id_to_delete)
expect(deleted_log.status).to eq "deleted"
expect(deleted_log.discarded_at).not_to be nil
expect(deleted_log.discarded_at).not_to be_nil
end
context "when visiting the bulk uploads page" do
let(:bulk_upload_errors) { create_list(:bulk_upload_error, 2, category: nil) }
let(:bulk_upload) { create(:bulk_upload, :lettings, user: support_user, bulk_upload_errors:, total_logs_count: 10) }
let(:mock_storage_service) { instance_double("S3Service") }
let(:mock_storage_service) { instance_double(Storage::S3Service) }
before do
allow(Storage::S3Service).to receive(:new).and_return(mock_storage_service)

4
spec/features/sales_log_spec.rb

@ -91,7 +91,7 @@ RSpec.describe "Sales Log Features" do
expect(page.find("article.app-log-summary h2").text).to eq "Log #{id_to_keep}"
deleted_log = SalesLog.find(id_to_delete)
expect(deleted_log.status).to eq "deleted"
expect(deleted_log.discarded_at).not_to be nil
expect(deleted_log.discarded_at).not_to be_nil
end
end
end
@ -322,7 +322,7 @@ RSpec.describe "Sales Log Features" do
context "when visiting the bulk uploads page" do
let(:bulk_upload_errors) { create_list(:bulk_upload_error, 2, category: nil) }
let(:bulk_upload) { create(:bulk_upload, :sales, user:, bulk_upload_errors:, total_logs_count: 10) }
let(:mock_storage_service) { instance_double("S3Service") }
let(:mock_storage_service) { instance_double(Storage::S3Service) }
before do
allow(Storage::S3Service).to receive(:new).and_return(mock_storage_service)

4
spec/features/schemes_spec.rb

@ -297,7 +297,7 @@ RSpec.describe "Schemes scheme Features" do
it "displays all schemes after I clear the search results" do
click_link("Clear search")
Location.all.each do |location|
Location.all.find_each do |location|
expect(page).to have_content(location.name)
end
end
@ -953,7 +953,7 @@ RSpec.describe "Schemes scheme Features" do
it "displays all schemes after I clear the search results" do
click_link("Clear search")
Location.all.each do |location|
Location.all.find_each do |location|
expect(page).to have_content(location.name)
end
end

10
spec/features/user_spec.rb

@ -37,7 +37,7 @@ RSpec.describe "User Features" do
expect(page).to have_current_path("/lettings-logs")
end
it "can log out again", js: true do
it "can log out again", :js do
visit("/lettings-logs")
fill_in("user[email]", with: user.email)
fill_in("user[password]", with: "pAssword1")
@ -157,8 +157,7 @@ RSpec.describe "User Features" do
end
it "does not show 'Sign in' link when both the service_moved? and service_unavailable? feature toggles are on" do
allow(FeatureToggle).to receive(:service_moved?).and_return(true)
allow(FeatureToggle).to receive(:service_unavailable?).and_return(true)
allow(FeatureToggle).to receive_messages(service_moved?: true, service_unavailable?: true)
visit("/lettings-logs")
expect(page).not_to have_link("Sign in")
end
@ -363,8 +362,7 @@ RSpec.describe "User Features" do
end
it "does not show 'Your account' or 'Sign out' links when both the service_moved? and service_unavailable? feature toggles are on" do
allow(FeatureToggle).to receive(:service_moved?).and_return(true)
allow(FeatureToggle).to receive(:service_unavailable?).and_return(true)
allow(FeatureToggle).to receive_messages(service_moved?: true, service_unavailable?: true)
visit("/lettings-logs")
expect(page).not_to have_link("Your account")
expect(page).not_to have_link("Sign out")
@ -796,7 +794,7 @@ RSpec.describe "User Features" do
end
context "when viewing logs" do
context "when filtering by owning organisation and then switching back to all organisations", js: true do
context "when filtering by owning organisation and then switching back to all organisations", :js do
let!(:organisation) { create(:organisation) }
let(:parent_organisation) { create(:organisation, name: "Filtered Org") }

6
spec/fixtures/files/lettings_log_csv_export_codes_26.csv vendored

File diff suppressed because one or more lines are too long

6
spec/fixtures/files/lettings_log_csv_export_labels_26.csv vendored

File diff suppressed because one or more lines are too long

2
spec/helpers/collection_resources_helper_spec.rb

@ -62,7 +62,7 @@ RSpec.describe CollectionResourcesHelper do
let(:current_date) { Time.zone.local(2025, 2, 1) }
it "returns current and next years" do
expect(editable_collection_resource_years).to match_array([2024, 2025])
expect(editable_collection_resource_years).to contain_exactly(2024, 2025)
end
end

4
spec/helpers/question_attribute_helper_spec.rb

@ -11,12 +11,12 @@ RSpec.describe QuestionAttributeHelper do
end
describe "html attributes" do
it "returns empty hash if fields-to-add or result-field are empty " do
it "returns empty hash if fields-to-add or result-field are empty" do
question = form.get_page("weekly_net_income").questions.find { |q| q.id == "earnings" }
expect(stimulus_html_attributes(question)).to eq({})
end
it "returns html attributes if fields-to-add or result-field are not empty " do
it "returns html attributes if fields-to-add or result-field are not empty" do
brent = questions.find { |q| q.id == "brent" }
expect(stimulus_html_attributes(brent)).to eq({
"data-controller": "numeric-question",

2
spec/helpers/tag_helper_spec.rb

@ -11,7 +11,7 @@ RSpec.describe TagHelper do
it "returns tag with correct status text and colour and custom class" do
expect(status_tag("not_started", "app-tag--small")).to eq("<strong class=\"govuk-tag govuk-tag--light-blue app-tag--small\">Not started</strong>")
expect(status_tag("cannot_start_yet", "app-tag--small")).to eq(nil)
expect(status_tag("cannot_start_yet", "app-tag--small")).to be_nil
expect(status_tag("in_progress", "app-tag--small")).to eq("<strong class=\"govuk-tag govuk-tag--blue app-tag--small\">In progress</strong>")
expect(status_tag("completed", "app-tag--small")).to eq("<strong class=\"govuk-tag govuk-tag--green app-tag--small\">Completed</strong>")
expect(status_tag("active", "app-tag--small")).to eq("<strong class=\"govuk-tag govuk-tag--green app-tag--small\">Active</strong>")

8
spec/helpers/tasklist_helper_spec.rb

@ -17,8 +17,8 @@ RSpec.describe TasklistHelper do
end
describe "get sections count" do
let(:completed_subsection) { instance_double("Subsection", status: :completed, displayed_in_tasklist?: true, applicable_questions: [{ id: "question" }]) }
let(:incomplete_subsection) { instance_double("Subsection", status: :not_started, displayed_in_tasklist?: true, applicable_questions: []) }
let(:completed_subsection) { instance_double(Form::Subsection, status: :completed, displayed_in_tasklist?: true, applicable_questions: [{ id: "question" }]) }
let(:incomplete_subsection) { instance_double(Form::Subsection, status: :not_started, displayed_in_tasklist?: true, applicable_questions: []) }
context "with an empty lettings log" do
before do
@ -79,8 +79,8 @@ RSpec.describe TasklistHelper do
describe "with sales" do
let(:empty_sales_log) { build(:sales_log, owning_organisation: nil) }
let(:completed_sales_log) { build(:sales_log, :completed) }
let(:completed_subsection) { instance_double("Subsection", status: :completed, displayed_in_tasklist?: true, applicable_questions: [{ id: "question" }]) }
let(:incomplete_subsection) { instance_double("Subsection", status: :not_started, displayed_in_tasklist?: true, applicable_questions: []) }
let(:completed_subsection) { instance_double(Form::Subsection, status: :completed, displayed_in_tasklist?: true, applicable_questions: [{ id: "question" }]) }
let(:incomplete_subsection) { instance_double(Form::Subsection, status: :not_started, displayed_in_tasklist?: true, applicable_questions: []) }
describe "get sections count" do
context "with an empty sales log" do

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

Loading…
Cancel
Save