diff --git a/.rspec_parallel b/.rspec_parallel new file mode 100644 index 000000000..aaff198a3 --- /dev/null +++ b/.rspec_parallel @@ -0,0 +1,2 @@ +--format progress +--format ParallelTests::RSpec::RuntimeLogger --out tmp/parallel_runtime_rspec.log diff --git a/Gemfile b/Gemfile index e6dac1995..02bcdf3b7 100644 --- a/Gemfile +++ b/Gemfile @@ -68,6 +68,8 @@ group :development, :test do gem "byebug", platforms: %i[mri mingw x64_mingw] gem "dotenv-rails" gem "pry-byebug" + + gem "parallel_tests" end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index 2a9fb454f..b509fb950 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -247,6 +247,8 @@ GEM globalid paper_trail (>= 3.0.0) parallel (1.22.1) + parallel_tests (4.0.0) + parallel parser (3.1.2.1) ast (~> 2.4.1) pg (1.4.3) @@ -430,6 +432,7 @@ PLATFORMS x86_64-darwin-19 x86_64-darwin-20 x86_64-darwin-21 + x86_64-darwin-22 x86_64-linux DEPENDENCIES @@ -456,6 +459,7 @@ DEPENDENCIES overcommit (>= 0.37.0) paper_trail paper_trail-globalid + parallel_tests pg (~> 1.1) possessive postcodes_io diff --git a/app/controllers/locations_controller.rb b/app/controllers/locations_controller.rb index f4e48c665..7d89a1bfa 100644 --- a/app/controllers/locations_controller.rb +++ b/app/controllers/locations_controller.rb @@ -108,7 +108,11 @@ class LocationsController < ApplicationController redirect_to(scheme_check_answers_path(@scheme, anchor: "locations")) end when "edit-name" - redirect_to(scheme_check_answers_path(@scheme, anchor: "locations")) + if @scheme.locations.count == @scheme.locations.active.count + redirect_to(scheme_location_path(@scheme, @location)) + else + redirect_to(scheme_check_answers_path(@scheme, anchor: "locations")) + end when "edit-local-authority" if params[:add_another_location] == "Yes" redirect_to(new_scheme_location_path(@location.scheme)) diff --git a/app/helpers/check_answers_helper.rb b/app/helpers/check_answers_helper.rb index 1583b3791..1d4a1a9aa 100644 --- a/app/helpers/check_answers_helper.rb +++ b/app/helpers/check_answers_helper.rb @@ -18,7 +18,7 @@ module CheckAnswersHelper def get_location_change_link_href_postcode(scheme, location) if location.confirmed? - scheme_location_edit_name_path(scheme_id: scheme.id, location_id: location.id) + scheme_location_path(scheme_id: scheme.id, id: location.id) else edit_scheme_location_path(scheme_id: scheme.id, id: location.id) end diff --git a/app/models/form/common/questions/created_by_id.rb b/app/models/form/common/questions/created_by_id.rb index b0558e5e2..b8409d99c 100644 --- a/app/models/form/common/questions/created_by_id.rb +++ b/app/models/form/common/questions/created_by_id.rb @@ -19,7 +19,7 @@ class Form::Common::Questions::CreatedById < ::Form::Question end end - def displayed_answer_options(log) + def displayed_answer_options(log, _user = nil) return answer_options unless log.owning_organisation user_ids = log.owning_organisation.users.pluck(:id) + [""] diff --git a/app/models/form/common/questions/owning_organisation_id.rb b/app/models/form/common/questions/owning_organisation_id.rb index 84eefbf21..9adb0bf64 100644 --- a/app/models/form/common/questions/owning_organisation_id.rb +++ b/app/models/form/common/questions/owning_organisation_id.rb @@ -19,7 +19,7 @@ class Form::Common::Questions::OwningOrganisationId < ::Form::Question end end - def displayed_answer_options(_log) + def displayed_answer_options(_log, _user = nil) answer_options end diff --git a/app/models/form/lettings/pages/created_by.rb b/app/models/form/lettings/pages/created_by.rb new file mode 100644 index 000000000..42289befa --- /dev/null +++ b/app/models/form/lettings/pages/created_by.rb @@ -0,0 +1,19 @@ +class Form::Lettings::Pages::CreatedBy < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "created_by" + @header = "" + @description = "" + @subsection = subsection + end + + def questions + @questions ||= [ + Form::Lettings::Questions::CreatedById.new(nil, nil, self), + ] + end + + def routed_to?(_log, current_user) + !!current_user&.support? + end +end diff --git a/app/models/form/lettings/pages/housing_provider.rb b/app/models/form/lettings/pages/housing_provider.rb new file mode 100644 index 000000000..a1c3a6687 --- /dev/null +++ b/app/models/form/lettings/pages/housing_provider.rb @@ -0,0 +1,30 @@ +class Form::Lettings::Pages::HousingProvider < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "housing_provider" + @header = "" + @description = "" + @subsection = subsection + end + + def questions + @questions ||= [ + Form::Lettings::Questions::HousingProvider.new(nil, nil, self), + ] + end + + def routed_to?(log, current_user) + return false unless current_user + return true if current_user.support? + return true unless current_user.organisation.holds_own_stock? + + housing_providers = current_user.organisation.housing_providers + + return false if housing_providers.count.zero? + return true if housing_providers.count > 1 + + log.update!(owning_organisation: housing_providers.first) + + false + end +end diff --git a/app/models/form/lettings/pages/managing_organisation.rb b/app/models/form/lettings/pages/managing_organisation.rb new file mode 100644 index 000000000..67e8ae586 --- /dev/null +++ b/app/models/form/lettings/pages/managing_organisation.rb @@ -0,0 +1,30 @@ +class Form::Lettings::Pages::ManagingOrganisation < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "managing_organisation" + @header = "" + @description = "" + @subsection = subsection + end + + def questions + @questions ||= [ + Form::Lettings::Questions::ManagingOrganisation.new(nil, nil, self), + ] + end + + def routed_to?(log, current_user) + return false unless current_user + return true if current_user.support? + return true unless current_user.organisation.holds_own_stock? + + managing_agents = current_user.organisation.managing_agents + + return false if managing_agents.count.zero? + return true if managing_agents.count > 1 + + log.update!(managing_organisation: managing_agents.first) + + false + end +end diff --git a/app/models/form/lettings/questions/created_by_id.rb b/app/models/form/lettings/questions/created_by_id.rb new file mode 100644 index 000000000..cf7323940 --- /dev/null +++ b/app/models/form/lettings/questions/created_by_id.rb @@ -0,0 +1,48 @@ +class Form::Lettings::Questions::CreatedById < ::Form::Question + def initialize(id, hsh, page) + super + @id = "created_by_id" + @check_answer_label = "Log owner" + @header = "Which user are you creating this log for?" + @hint_text = "" + @type = "select" + @page = page + end + + def answer_options + answer_opts = { "" => "Select an option" } + return answer_opts unless ActiveRecord::Base.connected? + + User.select(:id, :name, :email).each_with_object(answer_opts) do |user, hsh| + hsh[user.id] = "#{user.name} (#{user.email})" + hsh + end + end + + def displayed_answer_options(log, _user = nil) + return answer_options unless log.owning_organisation + + user_ids = log.owning_organisation.users.pluck(:id) + [""] + answer_options.select { |k, _v| user_ids.include?(k) } + end + + def label_from_value(value) + return unless value + + answer_options[value] + end + + def hidden_in_check_answers?(_log, current_user) + !current_user.support? + end + + def derived? + true + end + +private + + def selected_answer_option_is_derived?(_log) + true + end +end diff --git a/app/models/form/lettings/questions/housing_provider.rb b/app/models/form/lettings/questions/housing_provider.rb new file mode 100644 index 000000000..f0b69f9f7 --- /dev/null +++ b/app/models/form/lettings/questions/housing_provider.rb @@ -0,0 +1,68 @@ +class Form::Lettings::Questions::HousingProvider < ::Form::Question + attr_accessor :current_user, :log + + def initialize(id, hsh, page) + super + @id = "owning_organisation_id" + @check_answer_label = "Housing provider" + @header = "Which organisation owns this property?" + @type = "select" + @page = page + end + + def answer_options + answer_opts = { "" => "Select an option" } + return answer_opts unless ActiveRecord::Base.connected? + return answer_opts unless current_user + + if !current_user.support? && current_user.organisation.holds_own_stock? + answer_opts[current_user.organisation.id] = "#{current_user.organisation.name} (Your organisation)" + end + + answer_opts.merge(housing_providers_answer_options) + end + + def displayed_answer_options(log, user = nil) + @current_user = user + @log = log + + answer_options + end + + def label_from_value(value) + return unless value + + answer_options[value] + end + + def derived? + true + end + + def hidden_in_check_answers?(_log, user = nil) + @current_user = user + + return false unless @current_user + return false if @current_user.support? + + housing_providers_answer_options.count < 2 + end + + def enabled + true + end + +private + + def selected_answer_option_is_derived?(_log) + true + end + + def housing_providers_answer_options + @housing_providers_answer_options ||= if current_user.support? + Organisation + else + current_user.organisation.housing_providers + end.pluck(:id, :name).to_h + end +end diff --git a/app/models/form/lettings/questions/managing_organisation.rb b/app/models/form/lettings/questions/managing_organisation.rb new file mode 100644 index 000000000..ff6da010a --- /dev/null +++ b/app/models/form/lettings/questions/managing_organisation.rb @@ -0,0 +1,74 @@ +class Form::Lettings::Questions::ManagingOrganisation < ::Form::Question + attr_accessor :current_user, :log + + def initialize(id, hsh, page) + super + @id = "managing_organisation_id" + @check_answer_label = "Managing agent" + @header = "Which organisation manages this letting?" + @type = "select" + @answer_options = answer_options + @page = page + end + + def answer_options + opts = { "" => "Select an option" } + return opts unless ActiveRecord::Base.connected? + return opts unless current_user + return opts unless log + + if current_user.support? + if log.owning_organisation.holds_own_stock? + opts[log.owning_organisation.id] = "#{log.owning_organisation.name} (Owning organisation)" + end + elsif current_user.organisation.holds_own_stock? + opts[current_user.organisation.id] = "#{current_user.organisation.name} (Your organisation)" + end + + opts.merge(managing_organisations_answer_options) + end + + def displayed_answer_options(log, user) + @current_user = user + @log = log + + answer_options + end + + def label_from_value(value) + return unless value + + answer_options[value] + end + + def derived? + true + end + + def hidden_in_check_answers?(_log, user = nil) + @current_user = user + + return false unless @current_user + return false if @current_user.support? + + managing_organisations_answer_options.count < 2 + end + + def enabled + true + end + +private + + def selected_answer_option_is_derived?(_log) + true + end + + def managing_organisations_answer_options + @managing_organisations_answer_options ||= if current_user.support? + log.owning_organisation + else + current_user.organisation + end.managing_agents.pluck(:id, :name).to_h + end +end diff --git a/app/models/form/lettings/questions/scheme_id.rb b/app/models/form/lettings/questions/scheme_id.rb index 7d7966c00..d576a3f72 100644 --- a/app/models/form/lettings/questions/scheme_id.rb +++ b/app/models/form/lettings/questions/scheme_id.rb @@ -20,7 +20,7 @@ class Form::Lettings::Questions::SchemeId < ::Form::Question end end - def displayed_answer_options(lettings_log) + def displayed_answer_options(lettings_log, _user = nil) organisation = lettings_log.owning_organisation || lettings_log.created_by&.organisation schemes = organisation ? Scheme.select(:id).where(owning_organisation_id: organisation.id, confirmed: true) : Scheme.select(:id).where(confirmed: true) filtered_scheme_ids = schemes.joins(:locations).merge(Location.where("startdate <= ? or startdate IS NULL", Time.zone.today)).map(&:id) diff --git a/app/models/form/lettings/subsections/setup.rb b/app/models/form/lettings/subsections/setup.rb index 79d346599..e871406be 100644 --- a/app/models/form/lettings/subsections/setup.rb +++ b/app/models/form/lettings/subsections/setup.rb @@ -8,8 +8,10 @@ class Form::Lettings::Subsections::Setup < ::Form::Subsection def pages @pages ||= [ - Form::Common::Pages::Organisation.new(nil, nil, self), - Form::Common::Pages::CreatedBy.new(nil, nil, self), + organisation_page, + housing_provider_page, + managing_organisation_page, + created_by_page, Form::Lettings::Pages::NeedsType.new(nil, nil, self), Form::Lettings::Pages::Scheme.new(nil, nil, self), Form::Lettings::Pages::Location.new(nil, nil, self), @@ -18,11 +20,7 @@ class Form::Lettings::Subsections::Setup < ::Form::Subsection Form::Lettings::Pages::RentType.new(nil, nil, self), Form::Lettings::Pages::TenantCode.new(nil, nil, self), Form::Lettings::Pages::PropertyReference.new(nil, nil, self), - ] - end - - def applicable_questions(lettings_log) - questions.select { |q| support_only_questions.include?(q.id) } + super + ].compact end def enabled?(_lettings_log) @@ -31,7 +29,29 @@ class Form::Lettings::Subsections::Setup < ::Form::Subsection private - def support_only_questions - %w[owning_organisation_id created_by_id].freeze + def organisation_page + return if FeatureToggle.managing_for_other_user_enabled? + + Form::Common::Pages::Organisation.new(nil, nil, self) + end + + def housing_provider_page + return unless FeatureToggle.managing_for_other_user_enabled? + + Form::Lettings::Pages::HousingProvider.new(nil, nil, self) + end + + def managing_organisation_page + return unless FeatureToggle.managing_for_other_user_enabled? + + Form::Lettings::Pages::ManagingOrganisation.new(nil, nil, self) + end + + def created_by_page + if FeatureToggle.managing_for_other_user_enabled? + Form::Lettings::Pages::CreatedBy.new(nil, nil, self) + else + Form::Common::Pages::CreatedBy.new(nil, nil, self) + end end end diff --git a/app/models/form/question.rb b/app/models/form/question.rb index 7f3717d4a..13b1c62c9 100644 --- a/app/models/form/question.rb +++ b/app/models/form/question.rb @@ -107,7 +107,7 @@ class Form::Question false end - def displayed_answer_options(log) + def displayed_answer_options(log, _current_user = nil) answer_options.select do |_key, val| !val.is_a?(Hash) || !val["depends_on"] || form.depends_on_met(val["depends_on"], log) end diff --git a/app/models/form/sales/subsections/household_characteristics.rb b/app/models/form/sales/subsections/household_characteristics.rb index fb2b7dc6e..5a8eeef83 100644 --- a/app/models/form/sales/subsections/household_characteristics.rb +++ b/app/models/form/sales/subsections/household_characteristics.rb @@ -4,7 +4,7 @@ class Form::Sales::Subsections::HouseholdCharacteristics < ::Form::Subsection @id = "household_characteristics" @label = "Household characteristics" @section = section - @depends_on = [{ "setup" => "completed" }] + @depends_on = [{ "setup_completed?" => true }] end def pages diff --git a/app/models/form/sales/subsections/household_needs.rb b/app/models/form/sales/subsections/household_needs.rb index bf7a5df3a..a85cadcf3 100644 --- a/app/models/form/sales/subsections/household_needs.rb +++ b/app/models/form/sales/subsections/household_needs.rb @@ -4,7 +4,7 @@ class Form::Sales::Subsections::HouseholdNeeds < ::Form::Subsection @id = "household_needs" @label = "Household needs" @section = section - @depends_on = [{ "setup" => "completed" }] + @depends_on = [{ "setup_completed?" => true }] end def pages diff --git a/app/models/form/sales/subsections/income_benefits_and_outgoings.rb b/app/models/form/sales/subsections/income_benefits_and_outgoings.rb index 2c9d779b4..6ec5c6488 100644 --- a/app/models/form/sales/subsections/income_benefits_and_outgoings.rb +++ b/app/models/form/sales/subsections/income_benefits_and_outgoings.rb @@ -4,7 +4,7 @@ class Form::Sales::Subsections::IncomeBenefitsAndOutgoings < ::Form::Subsection @id = "income_benefits_and_outgoings" @label = "Income, benefits and outgoings" @section = section - @depends_on = [{ "setup" => "completed" }] + @depends_on = [{ "setup_completed?" => true }] end def pages diff --git a/app/models/form/sales/subsections/property_information.rb b/app/models/form/sales/subsections/property_information.rb index 5ebe7b581..2a29e27c2 100644 --- a/app/models/form/sales/subsections/property_information.rb +++ b/app/models/form/sales/subsections/property_information.rb @@ -4,7 +4,7 @@ class Form::Sales::Subsections::PropertyInformation < ::Form::Subsection @id = "property_information" @label = "Property information" @section = section - @depends_on = [{ "setup" => "completed" }] + @depends_on = [{ "setup_completed?" => true }] end def pages diff --git a/app/models/form/subsection.rb b/app/models/form/subsection.rb index d3ab0ddd2..07e7fe65c 100644 --- a/app/models/form/subsection.rb +++ b/app/models/form/subsection.rb @@ -20,11 +20,7 @@ class Form::Subsection def enabled?(log) return true unless depends_on - depends_on.any? do |conditions_set| - conditions_set.all? do |subsection_id, dependent_status| - form.get_subsection(subsection_id).status(log) == dependent_status.to_sym - end - end + form.depends_on_met(depends_on, log) end def status(log) diff --git a/app/models/lettings_log.rb b/app/models/lettings_log.rb index f09fd1ebd..bc011fdfd 100644 --- a/app/models/lettings_log.rb +++ b/app/models/lettings_log.rb @@ -507,6 +507,10 @@ class LettingsLog < Log form.get_question("rent_type", self)&.label_from_value(rent_type) end + def non_location_setup_questions_completed? + [needstype, renewal, rent_type, startdate, owning_organisation_id, created_by_id].all?(&:present?) + end + private PIO = PostcodeService.new diff --git a/app/models/log.rb b/app/models/log.rb index 54770515f..abde757e5 100644 --- a/app/models/log.rb +++ b/app/models/log.rb @@ -40,6 +40,10 @@ class Log < ApplicationRecord ethnic_group == 17 end + def managing_organisation_provider_type + managing_organisation&.provider_type + end + private def update_status! diff --git a/app/models/organisation_relationship.rb b/app/models/organisation_relationship.rb index acda8d2c4..d1f073737 100644 --- a/app/models/organisation_relationship.rb +++ b/app/models/organisation_relationship.rb @@ -2,6 +2,9 @@ class OrganisationRelationship < ApplicationRecord belongs_to :child_organisation, class_name: "Organisation" belongs_to :parent_organisation, class_name: "Organisation" + scope :owning, -> { where(relationship_type: OWNING) } + scope :managing, -> { where(relationship_type: MANAGING) } + OWNING = "owning".freeze MANAGING = "managing".freeze RELATIONSHIP_TYPE = { diff --git a/app/models/sales_log.rb b/app/models/sales_log.rb index e1458caa9..7c352aa78 100644 --- a/app/models/sales_log.rb +++ b/app/models/sales_log.rb @@ -47,4 +47,8 @@ class SalesLog < Log def completed? status == "completed" end + + def setup_completed? + form.setup_sections.all? { |sections| sections.subsections.all? { |subsection| subsection.status(self) == :completed } } + end end diff --git a/app/services/imports/user_import_service.rb b/app/services/imports/user_import_service.rb index f5a730479..9ab8f6886 100644 --- a/app/services/imports/user_import_service.rb +++ b/app/services/imports/user_import_service.rb @@ -45,7 +45,7 @@ module Imports end def user_field_value(xml_document, field) - field_value(xml_document, "user", field) + field_value(xml_document, "user", field, { "user" => "dclg:user" }) end def role(field_value) diff --git a/app/views/form/_radio_question.html.erb b/app/views/form/_radio_question.html.erb index ed5e71a0b..bac6fec8f 100644 --- a/app/views/form/_radio_question.html.erb +++ b/app/views/form/_radio_question.html.erb @@ -5,7 +5,7 @@ legend: legend(question, page_header, conditional), hint: { text: question.hint_text&.html_safe } do %> - <% question.displayed_answer_options(@log).map do |key, options| %> + <% question.displayed_answer_options(@log, current_user).map do |key, options| %> <% if key.starts_with?("divider") %> <%= f.govuk_radio_divider %> <% else %> diff --git a/app/views/form/_select_question.html.erb b/app/views/form/_select_question.html.erb index 63f50fb94..c1ee8c3e0 100644 --- a/app/views/form/_select_question.html.erb +++ b/app/views/form/_select_question.html.erb @@ -1,7 +1,7 @@ <%= render partial: "form/guidance/#{question.guidance_partial}" if question.top_guidance? %> <% selected = @log.public_send(question.id) || "" %> -<% answers = question.displayed_answer_options(@log).map { |key, value| OpenStruct.new(id: key, name: value.respond_to?(:service_name) ? value.service_name : nil, resource: value) } %> +<% answers = question.displayed_answer_options(@log, current_user).map { |key, value| OpenStruct.new(id: key, name: value.respond_to?(:service_name) ? value.service_name : nil, resource: value) } %> <%= f.govuk_select(question.id.to_sym, label: legend(question, page_header, conditional), "data-controller": "accessible-autocomplete", diff --git a/config/database.yml b/config/database.yml index 74e6632ef..c09e3600a 100644 --- a/config/database.yml +++ b/config/database.yml @@ -66,7 +66,7 @@ staging: # Do not set this db to the same as development or production. test: <<: *default - database: data_collector_test + database: data_collector_test<%= ENV['TEST_ENV_NUMBER'] %> # As with config/credentials.yml, you never want to store sensitive information, # like your database password, in your source code. If your source code is diff --git a/config/environments/test.rb b/config/environments/test.rb index a3a798981..2af4affe7 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -1,4 +1,5 @@ require "active_support/core_ext/integer/time" +require "faker" # The test environment is used exclusively to run your application's # test suite. You never need to work with it otherwise. Remember that diff --git a/config/forms/2021_2022.json b/config/forms/2021_2022.json index a180bcc67..19d8c291d 100644 --- a/config/forms/2021_2022.json +++ b/config/forms/2021_2022.json @@ -10,7 +10,7 @@ "label": "Property information", "depends_on": [ { - "setup": "completed" + "non_location_setup_questions_completed?": true } ], "pages": { @@ -952,7 +952,7 @@ "label": "Tenancy information", "depends_on": [ { - "setup": "completed" + "non_location_setup_questions_completed?": true } ], "pages": { @@ -1133,7 +1133,7 @@ "label": "Household characteristics", "depends_on": [ { - "setup": "completed" + "non_location_setup_questions_completed?": true } ], "pages": { @@ -5671,7 +5671,7 @@ "label": "Household needs", "depends_on": [ { - "setup": "completed" + "non_location_setup_questions_completed?": true } ], "pages": { @@ -6060,7 +6060,7 @@ "label": "Household situation", "depends_on": [ { - "setup": "completed" + "non_location_setup_questions_completed?": true } ], "pages": { @@ -7302,7 +7302,7 @@ "label": "Income, benefits and outgoings", "depends_on": [ { - "setup": "completed" + "non_location_setup_questions_completed?": true } ], "pages": { diff --git a/config/forms/2022_2023.json b/config/forms/2022_2023.json index 76595bdc5..2c6d0763f 100644 --- a/config/forms/2022_2023.json +++ b/config/forms/2022_2023.json @@ -10,7 +10,7 @@ "label": "Property information", "depends_on": [ { - "setup": "completed" + "non_location_setup_questions_completed?": true } ], "pages": { @@ -952,7 +952,7 @@ "label": "Tenancy information", "depends_on": [ { - "setup": "completed" + "non_location_setup_questions_completed?": true } ], "pages": { @@ -1168,7 +1168,7 @@ "label": "Household characteristics", "depends_on": [ { - "setup": "completed" + "non_location_setup_questions_completed?": true } ], "pages": { @@ -5670,7 +5670,7 @@ "label": "Household needs", "depends_on": [ { - "setup": "completed" + "non_location_setup_questions_completed?": true } ], "pages": { @@ -6062,7 +6062,7 @@ "label": "Household situation", "depends_on": [ { - "setup": "completed" + "non_location_setup_questions_completed?": true } ], "pages": { @@ -7070,7 +7070,7 @@ }, "depends_on": [ { - "managing_organisation.provider_type": "LA", + "managing_organisation_provider_type": "LA", "needstype": 1, "renewal": 0 } @@ -7127,7 +7127,7 @@ }, "depends_on": [ { - "managing_organisation.provider_type": "PRP", + "managing_organisation_provider_type": "PRP", "needstype": 1, "renewal": 0 } @@ -7184,7 +7184,7 @@ }, "depends_on": [ { - "managing_organisation.provider_type": "LA", + "managing_organisation_provider_type": "LA", "needstype": 2, "renewal": 0 } @@ -7244,7 +7244,7 @@ }, "depends_on": [ { - "managing_organisation.provider_type": "PRP", + "managing_organisation_provider_type": "PRP", "needstype": 2, "renewal": 0 } @@ -7261,7 +7261,7 @@ "label": "Income, benefits and outgoings", "depends_on": [ { - "setup": "completed" + "non_location_setup_questions_completed?": true } ], "pages": { diff --git a/config/initializers/feature_toggle.rb b/config/initializers/feature_toggle.rb index 983fb527b..7cd75ddd3 100644 --- a/config/initializers/feature_toggle.rb +++ b/config/initializers/feature_toggle.rb @@ -18,4 +18,8 @@ class FeatureToggle def self.location_toggle_enabled? !Rails.env.production? end + + def self.managing_for_other_user_enabled? + !Rails.env.production? + end end diff --git a/db/schema.rb b/db/schema.rb index 1ff8f157c..0f2ad0025 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -364,15 +364,15 @@ ActiveRecord::Schema[7.0].define(version: 2022_11_11_102656) do t.integer "la_known" t.integer "income1" t.integer "income1nk" - t.integer "details_known_2" - t.integer "details_known_3" - t.integer "details_known_4" t.integer "age4" t.integer "age4_known" t.integer "age5" t.integer "age5_known" t.integer "age6" t.integer "age6_known" + t.integer "details_known_2" + t.integer "details_known_3" + t.integer "details_known_4" t.index ["created_by_id"], name: "index_sales_logs_on_created_by_id" t.index ["managing_organisation_id"], name: "index_sales_logs_on_managing_organisation_id" t.index ["owning_organisation_id"], name: "index_sales_logs_on_owning_organisation_id" @@ -398,7 +398,6 @@ ActiveRecord::Schema[7.0].define(version: 2022_11_11_102656) do t.string "old_visible_id" t.integer "total_units" t.boolean "confirmed" - t.datetime "deactivation_date" t.index ["managing_organisation_id"], name: "index_schemes_on_managing_organisation_id" t.index ["owning_organisation_id"], name: "index_schemes_on_owning_organisation_id" end diff --git a/db/seeds.rb b/db/seeds.rb index e357e6efe..9d78fd8cb 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -8,8 +8,8 @@ # rubocop:disable Rails/Output unless Rails.env.test? - housing_provider = Organisation.find_or_create_by!( - name: "Housing Provider", + housing_provider1 = Organisation.find_or_create_by!( + name: "Housing Provider 1", address_line1: "2 Marsham Street", address_line2: "London", postcode: "SW1P 4DF", @@ -18,8 +18,28 @@ unless Rails.env.test? managing_agents_label: "None", provider_type: "LA", ) - managing_agent = Organisation.find_or_create_by!( - name: "Managing Agent", + housing_provider2 = Organisation.find_or_create_by!( + name: "Housing Provider 2", + address_line1: "2 Marsham Street", + address_line2: "London", + postcode: "SW1P 4DF", + holds_own_stock: true, + other_stock_owners: "None", + managing_agents_label: "None", + provider_type: "LA", + ) + managing_agent1 = Organisation.find_or_create_by!( + name: "Managing Agent 1", + address_line1: "2 Marsham Street", + address_line2: "London", + postcode: "SW1P 4DF", + holds_own_stock: true, + other_stock_owners: "None", + managing_agents_label: "None", + provider_type: "LA", + ) + managing_agent2 = Organisation.find_or_create_by!( + name: "Managing Agent 2", address_line1: "2 Marsham Street", address_line2: "London", postcode: "SW1P 4DF", @@ -49,11 +69,21 @@ unless Rails.env.test? OrganisationRelationship.create!( child_organisation: org, - parent_organisation: housing_provider, + parent_organisation: housing_provider1, + relationship_type: OrganisationRelationship::OWNING, + ) + OrganisationRelationship.create!( + child_organisation: org, + parent_organisation: housing_provider2, relationship_type: OrganisationRelationship::OWNING, ) OrganisationRelationship.create!( - child_organisation: managing_agent, + child_organisation: managing_agent1, + parent_organisation: org, + relationship_type: OrganisationRelationship::MANAGING, + ) + OrganisationRelationship.create!( + child_organisation: managing_agent2, parent_organisation: org, relationship_type: OrganisationRelationship::MANAGING, ) diff --git a/docs/form/builder.md b/docs/form/builder.md index cd703b5f5..97d1e67a9 100644 --- a/docs/form/builder.md +++ b/docs/form/builder.md @@ -9,7 +9,7 @@ nav_order: 1 The setup this log section is treated slightly differently from the rest of the form. It is more accurately viewed as providing metadata about the form than as being part of the form itself. It also needs to know far more about the application specific context than other parts of the form such as who the current user is, what organisation they’re part of and what role they have etc. -As a result it’s not modelled as part of the config but rather as code. It still uses the same [Form Runner](runner) components though. +As a result it’s not modelled as part of the config but rather as code. It still uses the same [Form Runner](/form/runner) components though. ## Features the Form Config supports diff --git a/docs/testing.md b/docs/testing.md index a453c69ca..57e40f747 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -15,3 +15,19 @@ nav_order: 4 - Feature specs are generally written sparingly as they’re also the slowest, where possible a request spec is preferred as this still tests a large surface area (route, controller, model, view) without the performance impact. They are not suitable for tests that need to run JavaScript or test that a specific set of interaction events that trigger a specific set of requests (with high confidence). - Test data is created with [FactoryBot](https://github.com/thoughtbot/factory_bot) where ever possible + +## Parallel testing + +- The RSpec test suite can be ran in parallel in local development for quicker turnaround times + +- Setup with the following: + +```sh +bundle exec rake parallel:setup +``` + +- Run with: + +```sh +RAILS_ENV=test bundle exec rake parallel:spec +``` diff --git a/spec/features/lettings_log_spec.rb b/spec/features/lettings_log_spec.rb index 1bd72b5cf..294ef51cd 100644 --- a/spec/features/lettings_log_spec.rb +++ b/spec/features/lettings_log_spec.rb @@ -3,10 +3,10 @@ require "rails_helper" RSpec.describe "Lettings Log Features" do context "when searching for specific logs" do context "when I am signed in and there are logs in the database" do - let(:user) { FactoryBot.create(:user, last_sign_in_at: Time.zone.now) } - let!(:log_to_search) { FactoryBot.create(:lettings_log, owning_organisation: user.organisation) } - let!(:same_organisation_log) { FactoryBot.create(:lettings_log, owning_organisation: user.organisation) } - let!(:another_organisation_log) { FactoryBot.create(:lettings_log) } + let(:user) { create(:user, last_sign_in_at: Time.zone.now) } + let!(:log_to_search) { create(:lettings_log, owning_organisation: user.organisation) } + let!(:same_organisation_log) { create(:lettings_log, owning_organisation: user.organisation) } + let!(:another_organisation_log) { create(:lettings_log) } before do visit("/lettings-logs") @@ -58,7 +58,7 @@ RSpec.describe "Lettings Log Features" do end context "when the signed is user is a Support user" do - let(:support_user) { FactoryBot.create(:user, :support, last_sign_in_at: Time.zone.now) } + let(:support_user) { create(:user, :support, last_sign_in_at: Time.zone.now) } let(:devise_notify_mailer) { DeviseNotifyMailer.new } let(:notify_client) { instance_double(Notifications::Client) } let(:mfa_template_id) { User::MFA_TEMPLATE_ID } @@ -77,26 +77,29 @@ RSpec.describe "Lettings Log Features" do click_button("Submit") end - context "when completing the setup lettings log section" do + context "when completing the setup lettings log section", :aggregate_failure do it "includes the organisation and created by questions" do visit("/lettings-logs") click_button("Create a new lettings log") click_link("Set up this lettings log") select(support_user.organisation.name, from: "lettings-log-owning-organisation-id-field") click_button("Save and continue") + select("#{support_user.organisation.name} (Owning organisation)", from: "lettings-log-managing-organisation-id-field") + click_button("Save and continue") select(support_user.name, from: "lettings-log-created-by-id-field") click_button("Save and continue") log_id = page.current_path.scan(/\d/).join visit("lettings-logs/#{log_id}/setup/check-answers") - expect(page).to have_content("Owning organisation #{support_user.organisation.name}") - expect(page).to have_content("User #{support_user.name}") - expect(page).to have_content("You have answered 2 of 8 questions") + expect(page).to have_content("Housing provider #{support_user.organisation.name}") + expect(page).to have_content("Managing agent #{support_user.organisation.name}") + expect(page).to have_content("Log owner #{support_user.name}") + expect(page).to have_content("You have answered 3 of 9 questions") end end end context "when the signed is user is not a Support user" do - let(:support_user) { FactoryBot.create(:user) } + let(:support_user) { create(:user) } let(:devise_notify_mailer) { DeviseNotifyMailer.new } let(:notify_client) { instance_double(Notifications::Client) } diff --git a/spec/features/schemes_spec.rb b/spec/features/schemes_spec.rb index 9aab9baf2..1500a728c 100644 --- a/spec/features/schemes_spec.rb +++ b/spec/features/schemes_spec.rb @@ -801,9 +801,9 @@ RSpec.describe "Schemes scheme Features" do it "returns to locations check your answers page and shows the new name" do fill_in "location-name-field", with: "NewName" click_button "Save and continue" - expect(page).to have_content location.id + expect(page).to have_content location.postcode expect(page).to have_content "NewName" - expect(page.current_url.split("/").last).to eq("check-answers#locations") + expect(page).to have_current_path("/schemes/#{scheme.id}/locations/#{location.id}") end context "when I press the back button" do diff --git a/spec/fixtures/forms/2021_2022.json b/spec/fixtures/forms/2021_2022.json index ac02a62a2..8e73f645b 100644 --- a/spec/fixtures/forms/2021_2022.json +++ b/spec/fixtures/forms/2021_2022.json @@ -1099,9 +1099,10 @@ "label": "Declaration", "depends_on": [ { - "household_characteristics": "completed", - "household_needs": "completed", - "property_information": "completed" + "armedforces": 1 + }, + { + "armedforces": 3 } ], "pages": { diff --git a/spec/fixtures/forms/2022_2023.json b/spec/fixtures/forms/2022_2023.json index a704a9229..5f5671b6f 100644 --- a/spec/fixtures/forms/2022_2023.json +++ b/spec/fixtures/forms/2022_2023.json @@ -47,7 +47,7 @@ }, "depends_on": [ { - "setup": "completed" + "non_location_setup_questions_completed?": true } ] } diff --git a/spec/fixtures/imports/user/80d9b73aa1c88b6e5c36ee49be9050b923b4a1bb.xml b/spec/fixtures/imports/user/80d9b73aa1c88b6e5c36ee49be9050b923b4a1bb.xml new file mode 100644 index 000000000..8fd86a5b1 --- /dev/null +++ b/spec/fixtures/imports/user/80d9b73aa1c88b6e5c36ee49be9050b923b4a1bb.xml @@ -0,0 +1,19 @@ + + 80d9b73aa1c88b6e5c36ee49be9050b923b4a1bb + Jane Doe + 7c5bd5fb549c09a2c55d7cb90d7ba84927e64618 + 1158 1158 + true + Data Provider + + false + false + false + None + jane.doe@gov.uk + REDACTED + Jane Doe + 01111 000000 + false + 2021-09-28Z + \ No newline at end of file diff --git a/spec/models/form/lettings/pages/created_by_spec.rb b/spec/models/form/lettings/pages/created_by_spec.rb new file mode 100644 index 000000000..c4fd460cb --- /dev/null +++ b/spec/models/form/lettings/pages/created_by_spec.rb @@ -0,0 +1,55 @@ +require "rails_helper" + +RSpec.describe Form::Lettings::Pages::CreatedBy, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection) } + + let(:page_id) { nil } + let(:page_definition) { nil } + let(:subsection) { instance_double(Form::Subsection) } + let(:form) { instance_double(Form) } + let(:lettings_log) { instance_double(LettingsLog) } + + describe "#routed_to?" do + context "when nil" do + it "is not shown" do + expect(page.routed_to?(nil, nil)).to eq(false) + end + end + + context "when support" do + it "is shown" do + expect(page.routed_to?(nil, create(:user, :support))).to eq(true) + end + end + + context "when not support" do + it "is not shown" do + expect(page.routed_to?(nil, create(:user, :data_coordinator))).to eq(false) + end + end + end + + it "has correct subsection" do + expect(page.subsection).to eq(subsection) + end + + it "has correct questions" do + expect(page.questions.map(&:id)).to eq(%w[created_by_id]) + end + + it "has the correct id" do + expect(page.id).to eq("created_by") + end + + it "has the correct header" do + expect(page.header).to eq("") + end + + it "has the correct description" do + expect(page.description).to eq("") + end + + it "has the correct depends_on" do + expect(page.depends_on).to be nil + end +end diff --git a/spec/models/form/lettings/pages/housing_provider_spec.rb b/spec/models/form/lettings/pages/housing_provider_spec.rb new file mode 100644 index 000000000..97420506e --- /dev/null +++ b/spec/models/form/lettings/pages/housing_provider_spec.rb @@ -0,0 +1,128 @@ +require "rails_helper" + +RSpec.describe Form::Lettings::Pages::HousingProvider, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection) } + + let(:page_id) { nil } + let(:page_definition) { nil } + let(:subsection) { instance_double(Form::Subsection) } + let(:form) { instance_double(Form) } + + it "has correct subsection" do + expect(page.subsection).to eq(subsection) + end + + it "has correct questions" do + expect(page.questions.map(&:id)).to eq(%w[owning_organisation_id]) + end + + it "has the correct id" do + expect(page.id).to eq("housing_provider") + end + + it "has the correct header" do + expect(page.header).to eq("") + end + + it "has the correct description" do + expect(page.description).to eq("") + end + + it "has the correct depends_on" do + expect(page.depends_on).to be nil + end + + describe "#routed_to?" do + let(:log) { create(:lettings_log, owning_organisation_id: nil) } + + context "when user nil" do + it "is not shown" do + expect(page.routed_to?(log, nil)).to eq(false) + end + + it "does not update owning_organisation_id" do + expect { page.routed_to?(log, nil) }.not_to change(log.reload, :owning_organisation).from(nil) + end + end + + context "when support" do + let(:user) { create(:user, :support) } + + it "is shown" do + expect(page.routed_to?(log, user)).to eq(true) + end + + it "does not update owning_organisation_id" do + expect { page.routed_to?(log, user) }.not_to change(log.reload, :owning_organisation).from(nil) + end + end + + context "when not support" do + context "when does not hold own stock" do + let(:user) do + create(:user, :data_coordinator, organisation: create(:organisation, holds_own_stock: false)) + end + + it "is shown" do + expect(page.routed_to?(log, user)).to eq(true) + end + + it "does not update owning_organisation_id" do + expect { page.routed_to?(log, user) }.not_to change(log.reload, :owning_organisation).from(nil) + end + end + + context "when holds own stock" do + let(:user) do + create(:user, :data_coordinator, organisation: create(:organisation, holds_own_stock: true)) + end + + context "with 0 housing_providers" do + it "is not shown" do + expect(page.routed_to?(log, user)).to eq(false) + end + + it "does not update owning_organisation_id" do + expect { page.routed_to?(log, user) }.not_to change(log.reload, :owning_organisation).from(nil) + end + end + + context "with >1 housing_providers" do + before do + create(:organisation_relationship, :owning, child_organisation: user.organisation) + create(:organisation_relationship, :owning, child_organisation: user.organisation) + end + + it "is shown" do + expect(page.routed_to?(log, user)).to eq(true) + end + + it "does not update owning_organisation_id" do + expect { page.routed_to?(log, user) }.not_to change(log.reload, :owning_organisation).from(nil) + end + end + + context "with 1 housing_providers" do + let(:housing_provider) { create(:organisation) } + + before do + create( + :organisation_relationship, + :owning, + child_organisation: user.organisation, + parent_organisation: housing_provider, + ) + end + + it "is not shown" do + expect(page.routed_to?(log, user)).to eq(false) + end + + it "updates owning_organisation_id" do + expect { page.routed_to?(log, user) }.to change(log.reload, :owning_organisation).from(nil).to(housing_provider) + end + end + end + end + end +end diff --git a/spec/models/form/lettings/pages/managing_organisation_spec.rb b/spec/models/form/lettings/pages/managing_organisation_spec.rb new file mode 100644 index 000000000..fcb93d565 --- /dev/null +++ b/spec/models/form/lettings/pages/managing_organisation_spec.rb @@ -0,0 +1,130 @@ +require "rails_helper" + +RSpec.describe Form::Lettings::Pages::ManagingOrganisation, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection) } + + let(:page_id) { nil } + let(:page_definition) { nil } + let(:subsection) { instance_double(Form::Subsection) } + let(:form) { instance_double(Form) } + + it "has correct subsection" do + expect(page.subsection).to eq(subsection) + end + + it "has correct questions" do + expect(page.questions.map(&:id)).to eq(%w[managing_organisation_id]) + end + + it "has the correct id" do + expect(page.id).to eq("managing_organisation") + end + + it "has the correct header" do + expect(page.header).to eq("") + end + + it "has the correct description" do + expect(page.description).to eq("") + end + + it "has the correct depends_on" do + expect(page.depends_on).to be nil + end + + describe "#routed_to?" do + let(:log) { create(:lettings_log) } + let(:organisation) { create(:organisation) } + + context "when user nil" do + it "is not shown" do + expect(page.routed_to?(log, nil)).to eq(false) + end + + it "does not update managing_organisation_id" do + expect { page.routed_to?(log, nil) }.not_to change(log.reload, :managing_organisation) + end + end + + context "when support" do + let(:organisation) { create(:organisation) } + let(:user) { create(:user, :support, organisation:) } + + it "is shown" do + expect(page.routed_to?(log, user)).to eq(true) + end + + it "does not update managing_organisation_id" do + expect { page.routed_to?(log, user) }.not_to change(log.reload, :managing_organisation) + end + end + + context "when not support" do + context "when does not hold own stock" do + let(:user) do + create(:user, :data_coordinator, organisation: create(:organisation, holds_own_stock: false)) + end + + it "is shown" do + expect(page.routed_to?(log, user)).to eq(true) + end + + it "does not update managing_organisation_id" do + expect { page.routed_to?(log, user) }.not_to change(log.reload, :managing_organisation) + end + end + + context "when holds own stock" do + let(:user) do + create(:user, :data_coordinator, organisation: create(:organisation, holds_own_stock: true)) + end + + context "with 0 managing_agents" do + it "is not shown" do + expect(page.routed_to?(log, user)).to eq(false) + end + + it "does not update managing_organisation_id" do + expect { page.routed_to?(log, user) }.not_to change(log.reload, :managing_organisation) + end + end + + context "with >1 managing_agents" do + before do + create(:organisation_relationship, :managing, parent_organisation: user.organisation) + create(:organisation_relationship, :managing, parent_organisation: user.organisation) + end + + it "is shown" do + expect(page.routed_to?(log, user)).to eq(true) + end + + it "does not update managing_organisation_id" do + expect { page.routed_to?(log, user) }.not_to change(log.reload, :managing_organisation) + end + end + + context "with 1 managing_agents" do + let(:managing_agent) { create(:organisation) } + + before do + create( + :organisation_relationship, + :managing, + child_organisation: managing_agent, + parent_organisation: user.organisation, + ) + end + + it "is not shown" do + expect(page.routed_to?(log, user)).to eq(false) + end + + it "updates managing_organisation_id" do + expect { page.routed_to?(log, user) }.to change(log.reload, :managing_organisation).to(managing_agent) + end + end + end + end + end +end diff --git a/spec/models/form/lettings/questions/created_by_id_spec.rb b/spec/models/form/lettings/questions/created_by_id_spec.rb new file mode 100644 index 000000000..152a24265 --- /dev/null +++ b/spec/models/form/lettings/questions/created_by_id_spec.rb @@ -0,0 +1,82 @@ +require "rails_helper" + +RSpec.describe Form::Lettings::Questions::CreatedById, type: :model do + subject(:question) { described_class.new(question_id, question_definition, page) } + + let(:question_id) { nil } + let(:question_definition) { nil } + let(:page) { instance_double(Form::Page) } + let(:subsection) { instance_double(Form::Subsection) } + let(:form) { instance_double(Form) } + let(:user_1) { FactoryBot.create(:user, name: "first user") } + let(:user_2) { FactoryBot.create(:user, name: "second user") } + let!(:expected_answer_options) do + { + "" => "Select an option", + user_1.id => "#{user_1.name} (#{user_1.email})", + user_2.id => "#{user_2.name} (#{user_2.email})", + } + end + + it "has correct page" do + expect(question.page).to eq(page) + end + + it "has the correct id" do + expect(question.id).to eq("created_by_id") + end + + it "has the correct header" do + expect(question.header).to eq("Which user are you creating this log for?") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to eq("Log owner") + end + + it "has the correct type" do + expect(question.type).to eq("select") + end + + it "has the correct hint_text" do + expect(question.hint_text).to eq("") + end + + it "has the correct answer options" do + expect(question.answer_options).to eq(expected_answer_options) + end + + it "is marked as derived" do + expect(question.derived?).to be true + end + + context "when the current user is support" do + let(:support_user) { FactoryBot.build(:user, :support) } + + it "is shown in check answers" do + expect(question.hidden_in_check_answers?(nil, support_user)).to be false + end + end + + context "when the current user is not support" do + let(:user) { FactoryBot.build(:user) } + + it "is not shown in check answers" do + expect(question.hidden_in_check_answers?(nil, user)).to be true + end + end + + context "when the owning organisation is already set" do + let(:lettings_log) { FactoryBot.create(:lettings_log, owning_organisation: user_2.organisation) } + let(:expected_answer_options) do + { + "" => "Select an option", + user_2.id => "#{user_2.name} (#{user_2.email})", + } + end + + it "only displays users that belong to that organisation" do + expect(question.displayed_answer_options(lettings_log)).to eq(expected_answer_options) + end + end +end diff --git a/spec/models/form/lettings/questions/housing_provider_spec.rb b/spec/models/form/lettings/questions/housing_provider_spec.rb new file mode 100644 index 000000000..073c59e37 --- /dev/null +++ b/spec/models/form/lettings/questions/housing_provider_spec.rb @@ -0,0 +1,117 @@ +require "rails_helper" + +RSpec.describe Form::Lettings::Questions::HousingProvider, type: :model do + subject(:question) { described_class.new(question_id, question_definition, page) } + + let(:question_id) { nil } + let(:question_definition) { nil } + let(:page) { instance_double(Form::Page) } + let(:subsection) { instance_double(Form::Subsection) } + let(:form) { instance_double(Form) } + + it "has correct page" do + expect(question.page).to eq(page) + end + + it "has the correct id" do + expect(question.id).to eq("owning_organisation_id") + end + + it "has the correct header" do + expect(question.header).to eq("Which organisation owns this property?") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to eq("Housing provider") + end + + it "has the correct type" do + expect(question.type).to eq("select") + end + + it "has the correct hint_text" do + expect(question.hint_text).to be_nil + end + + describe "answer options" do + let(:options) { { "" => "Select an option" } } + + context "when current_user nil" do + it "shows default options" do + expect(question.answer_options).to eq(options) + end + end + + context "when user not support and owns own stock" do + let(:user) { create(:user, :data_coordinator, organisation: create(:organisation, holds_own_stock: true)) } + let(:options) do + { + "" => "Select an option", + user.organisation.id => "#{user.organisation.name} (Your organisation)", + } + end + + before do + question.current_user = user + end + + it "shows housing providers with own org at the top" do + expect(question.answer_options).to eq(options) + end + end + + context "when user support" do + before do + question.current_user = create(:user, :support) + end + + let(:expected_opts) do + Organisation.all.each_with_object(options) do |organisation, hsh| + hsh[organisation.id] = organisation.name + hsh + end + end + + it "shows all orgs" do + expect(question.answer_options).to eq(expected_opts) + end + end + end + + it "is marked as derived" do + expect(question.derived?).to be true + end + + describe "#hidden_in_check_answers?" do + context "when housing providers < 2" do + context "when not support user" do + let(:user) { create(:user) } + + it "is hidden in check answers" do + expect(question.hidden_in_check_answers?(nil, user)).to be true + end + end + + context "when support" do + let(:user) { create(:user, :support) } + + it "is not hiddes in check answers" do + expect(question.hidden_in_check_answers?(nil, user)).to be false + end + end + end + + context "when housing providers >= 2" do + let(:user) { create(:user) } + + before do + create(:organisation_relationship, :owning, child_organisation: user.organisation) + create(:organisation_relationship, :owning, child_organisation: user.organisation) + end + + it "is not hidden in check answers" do + expect(question.hidden_in_check_answers?(nil, user)).to be false + end + end + end +end diff --git a/spec/models/form/lettings/questions/managing_organisation_spec.rb b/spec/models/form/lettings/questions/managing_organisation_spec.rb new file mode 100644 index 000000000..f80099d67 --- /dev/null +++ b/spec/models/form/lettings/questions/managing_organisation_spec.rb @@ -0,0 +1,155 @@ +require "rails_helper" + +RSpec.describe Form::Lettings::Questions::ManagingOrganisation, type: :model do + subject(:question) { described_class.new(question_id, question_definition, page) } + + let(:question_id) { nil } + let(:question_definition) { nil } + let(:page) { instance_double(Form::Page) } + let(:subsection) { instance_double(Form::Subsection) } + let(:form) { instance_double(Form) } + + it "has correct page" do + expect(question.page).to eq(page) + end + + it "has the correct id" do + expect(question.id).to eq("managing_organisation_id") + end + + it "has the correct header" do + expect(question.header).to eq("Which organisation manages this letting?") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to eq("Managing agent") + end + + it "has the correct type" do + expect(question.type).to eq("select") + end + + it "has the correct hint_text" do + expect(question.hint_text).to be_nil + end + + describe "#displayed_answer_options" do + let(:options) { { "" => "Select an option" } } + + context "when current_user nil" do + let(:log) { create(:lettings_log) } + + it "shows default options" do + expect(question.displayed_answer_options(log, nil)).to eq(options) + end + end + + context "when log nil" do + let(:user) { create(:user) } + + it "shows default options" do + expect(question.displayed_answer_options(nil, user)).to eq(options) + end + end + + context "when user not support and owns own stock" do + let(:user) { create(:user, :data_coordinator, organisation: create(:organisation, holds_own_stock: true)) } + + let(:log) { create(:lettings_log) } + let!(:org_rel1) { create(:organisation_relationship, :managing, parent_organisation: user.organisation) } + let!(:org_rel2) { create(:organisation_relationship, :managing, parent_organisation: user.organisation) } + + let(:options) do + { + "" => "Select an option", + user.organisation.id => "#{user.organisation.name} (Your organisation)", + org_rel1.child_organisation.id => org_rel1.child_organisation.name, + org_rel2.child_organisation.id => org_rel2.child_organisation.name, + } + end + + it "shows managing agents with own org at the top" do + expect(question.displayed_answer_options(log, user)).to eq(options) + end + end + + context "when support user and org does not own own stock" do + let(:user) { create(:user, :support) } + let(:log_owning_org) { create(:organisation, holds_own_stock: false) } + let(:log) { create(:lettings_log, owning_organisation: log_owning_org) } + let!(:org_rel1) { create(:organisation_relationship, :managing, parent_organisation: log_owning_org) } + let!(:org_rel2) { create(:organisation_relationship, :managing, parent_organisation: log_owning_org) } + + let(:options) do + { + "" => "Select an option", + org_rel1.child_organisation.id => org_rel1.child_organisation.name, + org_rel2.child_organisation.id => org_rel2.child_organisation.name, + } + end + + it "shows owning org managing agents with hint" do + expect(question.displayed_answer_options(log, user)).to eq(options) + end + end + + context "when support user and org does own stock" do + let(:user) { create(:user, :support) } + let(:log_owning_org) { create(:organisation, holds_own_stock: true) } + let(:log) { create(:lettings_log, owning_organisation: log_owning_org) } + let!(:org_rel1) { create(:organisation_relationship, :managing, parent_organisation: log_owning_org) } + let!(:org_rel2) { create(:organisation_relationship, :managing, parent_organisation: log_owning_org) } + + let(:options) do + { + "" => "Select an option", + log_owning_org.id => "#{log_owning_org.name} (Owning organisation)", + org_rel1.child_organisation.id => org_rel1.child_organisation.name, + org_rel2.child_organisation.id => org_rel2.child_organisation.name, + } + end + + it "shows owning org managing agents + " do + expect(question.displayed_answer_options(log, user)).to eq(options) + end + end + end + + it "is marked as derived" do + expect(question.derived?).to be true + end + + describe "#hidden_in_check_answers?" do + context "when housing providers < 2" do + context "when not support user" do + let(:user) { create(:user) } + + it "is hidden in check answers" do + expect(question.hidden_in_check_answers?(nil, user)).to be true + end + end + + context "when support" do + let(:user) { create(:user, :support) } + + it "is not hiddes in check answers" do + expect(question.hidden_in_check_answers?(nil, user)).to be false + end + end + end + + context "when managing agents >= 2" do + let(:user) { create(:user) } + + before do + create(:organisation_relationship, :managing, parent_organisation: user.organisation) + create(:organisation_relationship, :managing, parent_organisation: user.organisation) + end + + it "is not hidden in check answers" do + expect(question.hidden_in_check_answers?(nil, user)).to be false + end + end + end +end diff --git a/spec/models/form/lettings/subsections/setup_spec.rb b/spec/models/form/lettings/subsections/setup_spec.rb index 3e2fba32f..6188cc1e0 100644 --- a/spec/models/form/lettings/subsections/setup_spec.rb +++ b/spec/models/form/lettings/subsections/setup_spec.rb @@ -13,16 +13,19 @@ RSpec.describe Form::Lettings::Subsections::Setup, type: :model do it "has correct pages" do expect(setup.pages.map(&:id)).to eq( - %w[organisation - created_by - needs_type - scheme - location - renewal - tenancy_start_date - rent_type - tenant_code - property_reference], + %w[ + housing_provider + managing_organisation + created_by + needs_type + scheme + location + renewal + tenancy_start_date + rent_type + tenant_code + property_reference + ], ) end @@ -33,4 +36,47 @@ RSpec.describe Form::Lettings::Subsections::Setup, type: :model do it "has the correct label" do expect(setup.label).to eq("Set up this lettings log") end + + context "when not production" do + it "has correct pages" do + expect(setup.pages.map(&:id)).to eq( + %w[ + housing_provider + managing_organisation + created_by + needs_type + scheme + location + renewal + tenancy_start_date + rent_type + tenant_code + property_reference + ], + ) + end + end + + context "when production" do + before do + allow(Rails.env).to receive(:production?).and_return(true) + end + + it "has the correct pages" do + expect(setup.pages.map(&:id)).to eq( + %w[ + organisation + created_by + needs_type + scheme + location + renewal + tenancy_start_date + rent_type + tenant_code + property_reference + ], + ) + end + end end diff --git a/spec/models/form/sales/subsections/household_characteristics_spec.rb b/spec/models/form/sales/subsections/household_characteristics_spec.rb index dbe8a24a3..7aec7d56a 100644 --- a/spec/models/form/sales/subsections/household_characteristics_spec.rb +++ b/spec/models/form/sales/subsections/household_characteristics_spec.rb @@ -53,6 +53,6 @@ RSpec.describe Form::Sales::Subsections::HouseholdCharacteristics, type: :model end it "has correct depends on" do - expect(household_characteristics.depends_on).to eq([{ "setup" => "completed" }]) + expect(household_characteristics.depends_on).to eq([{ "setup_completed?" => true }]) end end diff --git a/spec/models/form/sales/subsections/income_benefits_and_outgoings_spec.rb b/spec/models/form/sales/subsections/income_benefits_and_outgoings_spec.rb index add0a6952..01028b0a8 100644 --- a/spec/models/form/sales/subsections/income_benefits_and_outgoings_spec.rb +++ b/spec/models/form/sales/subsections/income_benefits_and_outgoings_spec.rb @@ -28,6 +28,6 @@ RSpec.describe Form::Sales::Subsections::IncomeBenefitsAndOutgoings, type: :mode end it "has correct depends on" do - expect(subsection.depends_on).to eq([{ "setup" => "completed" }]) + expect(subsection.depends_on).to eq([{ "setup_completed?" => true }]) end end diff --git a/spec/models/form_handler_spec.rb b/spec/models/form_handler_spec.rb index c6a47c107..e4056c6c1 100644 --- a/spec/models/form_handler_spec.rb +++ b/spec/models/form_handler_spec.rb @@ -27,13 +27,13 @@ RSpec.describe FormHandler do it "is able to load a current lettings form" do form = form_handler.get_form("current_lettings") expect(form).to be_a(Form) - expect(form.pages.count).to eq(45) + expect(form.pages.count).to eq(46) end it "is able to load a next lettings form" do form = form_handler.get_form("next_lettings") expect(form).to be_a(Form) - expect(form.pages.count).to eq(12) + expect(form.pages.count).to eq(13) end end @@ -49,13 +49,13 @@ RSpec.describe FormHandler do it "is able to load a current lettings form" do form = form_handler.get_form("current_lettings") expect(form).to be_a(Form) - expect(form.pages.count).to eq(12) + expect(form.pages.count).to eq(13) end it "is able to load a previous lettings form" do form = form_handler.get_form("previous_lettings") expect(form).to be_a(Form) - expect(form.pages.count).to eq(45) + expect(form.pages.count).to eq(46) end it "is able to load a current sales form" do diff --git a/spec/models/validations/financial_validations_spec.rb b/spec/models/validations/financial_validations_spec.rb index 0b88fdd76..409ed86c2 100644 --- a/spec/models/validations/financial_validations_spec.rb +++ b/spec/models/validations/financial_validations_spec.rb @@ -832,6 +832,11 @@ RSpec.describe Validations::FinancialValidations do financial_validator.validate_rent_amount(record) expect(record.errors["brent"]) .to include(match I18n.t("validations.financial.brent.below_hard_min")) + + %w[beds la postcode_known scheme_id location_id rent_type needstype period].each do |field| + expect(record.errors[field]) + .to include(match I18n.t("validations.financial.brent.#{field}.below_hard_min")) + end end it "validates hard max for general needs" do @@ -846,22 +851,11 @@ RSpec.describe Validations::FinancialValidations do financial_validator.validate_rent_amount(record) expect(record.errors["brent"]) .to include(match I18n.t("validations.financial.brent.above_hard_max")) - expect(record.errors["beds"]) - .to include(match I18n.t("validations.financial.brent.beds.above_hard_max")) - expect(record.errors["la"]) - .to include(match I18n.t("validations.financial.brent.la.above_hard_max")) - expect(record.errors["postcode_known"]) - .to include(match I18n.t("validations.financial.brent.postcode_known.above_hard_max")) - expect(record.errors["scheme_id"]) - .to include(match I18n.t("validations.financial.brent.scheme_id.above_hard_max")) - expect(record.errors["location_id"]) - .to include(match I18n.t("validations.financial.brent.location_id.above_hard_max")) - expect(record.errors["rent_type"]) - .to include(match I18n.t("validations.financial.brent.rent_type.above_hard_max")) - expect(record.errors["needstype"]) - .to include(match I18n.t("validations.financial.brent.needstype.above_hard_max")) - expect(record.errors["period"]) - .to include(match I18n.t("validations.financial.brent.period.above_hard_max")) + + %w[beds la postcode_known scheme_id location_id rent_type needstype period].each do |field| + expect(record.errors[field]) + .to include(match I18n.t("validations.financial.brent.#{field}.above_hard_max")) + end end it "validates hard max for supported housing" do @@ -875,22 +869,11 @@ RSpec.describe Validations::FinancialValidations do financial_validator.validate_rent_amount(record) expect(record.errors["brent"]) .to include(match I18n.t("validations.financial.brent.above_hard_max")) - expect(record.errors["beds"]) - .to include(match I18n.t("validations.financial.brent.beds.above_hard_max")) - expect(record.errors["la"]) - .to include(match I18n.t("validations.financial.brent.la.above_hard_max")) - expect(record.errors["postcode_known"]) - .to include(match I18n.t("validations.financial.brent.postcode_known.above_hard_max")) - expect(record.errors["scheme_id"]) - .to include(match I18n.t("validations.financial.brent.scheme_id.above_hard_max")) - expect(record.errors["location_id"]) - .to include(match I18n.t("validations.financial.brent.location_id.above_hard_max")) - expect(record.errors["rent_type"]) - .to include(match I18n.t("validations.financial.brent.rent_type.above_hard_max")) - expect(record.errors["needstype"]) - .to include(match I18n.t("validations.financial.brent.needstype.above_hard_max")) - expect(record.errors["period"]) - .to include(match I18n.t("validations.financial.brent.period.above_hard_max")) + + %w[beds la postcode_known scheme_id location_id rent_type needstype period].each do |field| + expect(record.errors[field]) + .to include(match I18n.t("validations.financial.brent.#{field}.above_hard_max")) + end end it "validates hard max for correct collection year" do @@ -904,14 +887,11 @@ RSpec.describe Validations::FinancialValidations do financial_validator.validate_rent_amount(record) expect(record.errors["brent"]) .to include(match I18n.t("validations.financial.brent.above_hard_max")) - expect(record.errors["beds"]) - .to include(match I18n.t("validations.financial.brent.beds.above_hard_max")) - expect(record.errors["la"]) - .to include(match I18n.t("validations.financial.brent.la.above_hard_max")) - expect(record.errors["rent_type"]) - .to include(match I18n.t("validations.financial.brent.rent_type.above_hard_max")) - expect(record.errors["needstype"]) - .to include(match I18n.t("validations.financial.brent.needstype.above_hard_max")) + + %w[beds la postcode_known scheme_id location_id rent_type needstype period].each do |field| + expect(record.errors[field]) + .to include(match I18n.t("validations.financial.brent.#{field}.above_hard_max")) + end end it "does not error if some of the fields are missing" do diff --git a/spec/requests/form_controller_spec.rb b/spec/requests/form_controller_spec.rb index ade87cfde..1bb73f399 100644 --- a/spec/requests/form_controller_spec.rb +++ b/spec/requests/form_controller_spec.rb @@ -2,18 +2,18 @@ require "rails_helper" RSpec.describe FormController, type: :request do let(:page) { Capybara::Node::Simple.new(response.body) } - let(:user) { FactoryBot.create(:user) } + let(:user) { create(:user) } let(:organisation) { user.organisation } - let(:other_organisation) { FactoryBot.create(:organisation) } + let(:other_organisation) { create(:organisation) } let!(:unauthorized_lettings_log) do - FactoryBot.create( + create( :lettings_log, owning_organisation: other_organisation, managing_organisation: other_organisation, ) end let(:setup_complete_lettings_log) do - FactoryBot.create( + create( :lettings_log, :about_completed, status: 1, @@ -23,7 +23,7 @@ RSpec.describe FormController, type: :request do ) end let(:completed_lettings_log) do - FactoryBot.create( + create( :lettings_log, :completed, owning_organisation: organisation, @@ -39,7 +39,7 @@ RSpec.describe FormController, type: :request do context "when a user is not signed in" do let!(:lettings_log) do - FactoryBot.create( + create( :lettings_log, owning_organisation: organisation, managing_organisation: organisation, @@ -68,7 +68,7 @@ RSpec.describe FormController, type: :request do context "when a user is signed in" do let!(:lettings_log) do - FactoryBot.create( + create( :lettings_log, owning_organisation: organisation, managing_organisation: organisation, @@ -83,8 +83,8 @@ RSpec.describe FormController, type: :request do describe "GET" do context "with form pages" do context "when forms exist for multiple years" do - let(:lettings_log_year_1) { FactoryBot.create(:lettings_log, startdate: Time.zone.local(2021, 5, 1), owning_organisation: organisation, created_by: user) } - let(:lettings_log_year_2) { FactoryBot.create(:lettings_log, :about_completed, startdate: Time.zone.local(2022, 5, 1), owning_organisation: organisation, created_by: user) } + let(:lettings_log_year_1) { create(:lettings_log, startdate: Time.zone.local(2021, 5, 1), owning_organisation: organisation, created_by: user) } + let(:lettings_log_year_2) { create(:lettings_log, :about_completed, startdate: Time.zone.local(2022, 5, 1), owning_organisation: organisation, created_by: user) } it "displays the correct question details for each lettings log based on form year" do get "/lettings-logs/#{lettings_log_year_1.id}/tenant-code-test", headers: headers, params: {} @@ -110,11 +110,11 @@ RSpec.describe FormController, type: :request do context "when viewing the setup section schemes page" do context "when the user is support" do - let(:user) { FactoryBot.create(:user, :support) } + let(:user) { create(:user, :support) } context "when organisation and user have not been selected yet" do let(:lettings_log) do - FactoryBot.create( + create( :lettings_log, owning_organisation: nil, managing_organisation: nil, @@ -124,7 +124,7 @@ RSpec.describe FormController, type: :request do end before do - locations = FactoryBot.create_list(:location, 5) + locations = create_list(:location, 5) locations.each { |location| location.scheme.update!(arrangement_type: "The same organisation that owns the housing stock", managing_organisation_id: location.scheme.owning_organisation_id) } end @@ -147,7 +147,7 @@ RSpec.describe FormController, type: :request do context "when no other sections are enabled" do let(:lettings_log_2022) do - FactoryBot.create( + create( :lettings_log, startdate: Time.zone.local(2022, 12, 1), owning_organisation: organisation, @@ -194,17 +194,17 @@ RSpec.describe FormController, type: :request do context "when viewing a user dependent page" do context "when the dependency is met" do - let(:user) { FactoryBot.create(:user, :support) } + let(:user) { create(:user, :support) } it "routes to the page" do - get "/lettings-logs/#{lettings_log.id}/organisation" + get "/lettings-logs/#{lettings_log.id}/created-by" expect(response).to have_http_status(:ok) end end context "when the dependency is not met" do it "redirects to the tasklist page" do - get "/lettings-logs/#{lettings_log.id}/organisation" + get "/lettings-logs/#{lettings_log.id}/created-by" expect(response).to redirect_to("/lettings-logs/#{lettings_log.id}") end end @@ -213,10 +213,10 @@ RSpec.describe FormController, type: :request do describe "Submit Form" do context "with a form page" do - let(:user) { FactoryBot.create(:user) } + let(:user) { create(:user) } let(:organisation) { user.organisation } let(:lettings_log) do - FactoryBot.create( + create( :lettings_log, owning_organisation: organisation, managing_organisation: organisation, @@ -527,9 +527,9 @@ RSpec.describe FormController, type: :request do context "with lettings logs that are not owned or managed by your organisation" do let(:answer) { 25 } - let(:other_organisation) { FactoryBot.create(:organisation) } + let(:other_organisation) { create(:organisation) } let(:unauthorized_lettings_log) do - FactoryBot.create( + create( :lettings_log, owning_organisation: other_organisation, managing_organisation: other_organisation, diff --git a/spec/requests/locations_controller_spec.rb b/spec/requests/locations_controller_spec.rb index 2b6b1fd83..2aca9bd93 100644 --- a/spec/requests/locations_controller_spec.rb +++ b/spec/requests/locations_controller_spec.rb @@ -597,7 +597,7 @@ RSpec.describe LocationsController, type: :request do it "updates existing location for scheme with valid params and redirects to correct page" do follow_redirect! expect(response).to have_http_status(:ok) - expect(page).to have_content("Locations") + expect(page).to have_content("Test") end it "updates existing location for scheme with valid params" do @@ -736,7 +736,7 @@ RSpec.describe LocationsController, type: :request do it "updates existing location for scheme with valid params and redirects to correct page" do follow_redirect! expect(response).to have_http_status(:ok) - expect(page).to have_content("Locations") + expect(page).to have_content("Test") end it "updates existing location for scheme with valid params" do diff --git a/spec/services/imports/user_import_service_spec.rb b/spec/services/imports/user_import_service_spec.rb index b8a831dbc..ea3388169 100644 --- a/spec/services/imports/user_import_service_spec.rb +++ b/spec/services/imports/user_import_service_spec.rb @@ -107,6 +107,19 @@ RSpec.describe Imports::UserImportService do end end + context "when the user does not have namespace bindings" do + let(:old_user_id) { "80d9b73aa1c88b6e5c36ee49be9050b923b4a1bb" } + + it "imports them succesfully" do + FactoryBot.create(:organisation, old_org_id:) + import_service.create_users("user_directory") + + user = LegacyUser.find_by(old_user_id:)&.user + expect(user.name).to eq("Jane Doe") + expect(user.email).to eq("jane.doe@gov.uk") + end + end + context "when a user has already been imported with that email" do let!(:org) { FactoryBot.create(:organisation, old_org_id:) } let!(:user) { FactoryBot.create(:user, :data_provider, organisation: org, email: "john.doe@gov.uk") }