Browse Source

Merge branch 'main' into CLDC-2604-add-org-select-to-sales-if-merged

# Conflicts:
#	app/models/form/sales/pages/organisation.rb
#	app/models/form/sales/questions/owning_organisation_id.rb
pull/1830/head
natdeanlewissoftwire 3 years ago
parent
commit
0e4af53ca6
  1. 11
      app/controllers/duplicate_logs_controller.rb
  2. 52
      app/controllers/form_controller.rb
  3. 13
      app/helpers/duplicate_logs_helper.rb
  4. 18
      app/models/form/sales/pages/organisation.rb
  5. 35
      app/models/form/sales/questions/owning_organisation_id.rb
  6. 2
      app/models/lettings_log.rb
  7. 1
      app/models/organisation.rb
  8. 2
      app/models/sales_log.rb
  9. 128
      app/models/validations/setup_validations.rb
  10. 27
      app/views/duplicate_logs/_duplicate_log_check_answers.erb
  11. 4
      app/views/duplicate_logs/show.html.erb
  12. 2
      app/views/logs/delete_duplicates.html.erb
  13. 17
      config/locales/en.yml
  14. 23
      spec/features/lettings_log_spec.rb
  15. 23
      spec/features/sales_log_spec.rb
  16. 32
      spec/models/form/sales/pages/organisation_spec.rb
  17. 132
      spec/models/form/sales/questions/owning_organisation_id_spec.rb
  18. 31
      spec/models/lettings_log_spec.rb
  19. 29
      spec/models/sales_log_spec.rb
  20. 256
      spec/models/validations/setup_validations_spec.rb
  21. 173
      spec/requests/duplicate_logs_controller_spec.rb
  22. 82
      spec/requests/form_controller_spec.rb
  23. 8
      spec/requests/sales_logs_controller_spec.rb

11
app/controllers/duplicate_logs_controller.rb

@ -2,7 +2,7 @@ class DuplicateLogsController < ApplicationController
before_action :authenticate_user! before_action :authenticate_user!
before_action :find_resource_by_named_id before_action :find_resource_by_named_id
before_action :find_duplicate_logs before_action :find_duplicate_logs
before_action :find_original_log_id before_action :find_original_log
def show def show
if @log if @log
@ -61,8 +61,13 @@ private
end end
end end
def find_original_log_id def find_original_log
query_params = URI.parse(request.url).query query_params = URI.parse(request.url).query
@original_log_id = CGI.parse(query_params)["original_log_id"][0]&.to_i if query_params.present? original_log_id = CGI.parse(query_params)["original_log_id"][0]&.to_i if query_params.present?
@original_log = if params[:sales_log_id].present?
current_user.sales_logs.find_by(id: original_log_id)
else
current_user.lettings_logs.find_by(id: original_log_id)
end
end end
end end

52
app/controllers/form_controller.rb

@ -48,7 +48,7 @@ class FormController < ApplicationController
def show_page def show_page
if request.params["referrer"] == "interruption_screen" && request.headers["HTTP_REFERER"].present? if request.params["referrer"] == "interruption_screen" && request.headers["HTTP_REFERER"].present?
@interruption_page_id = URI.parse(request.headers["HTTP_REFERER"]).path.split("/").last.underscore @interruption_page_id = URI.parse(request.headers["HTTP_REFERER"]).path.split("/").last.underscore
@interruption_page_referrer_type = referrer_from_query @interruption_page_referrer_type = from_referrer_query("referrer")
end end
if @log if @log
@ -130,10 +130,10 @@ private
end end
def is_referrer_type?(referrer_type) def is_referrer_type?(referrer_type)
referrer_from_query == referrer_type from_referrer_query("referrer") == referrer_type
end end
def referrer_from_query def from_referrer_query(query_param)
referrer = request.headers["HTTP_REFERER"] referrer = request.headers["HTTP_REFERER"]
return unless referrer return unless referrer
@ -141,7 +141,7 @@ private
return unless query_params return unless query_params
parsed_params = CGI.parse(query_params) parsed_params = CGI.parse(query_params)
parsed_params["referrer"]&.first parsed_params[query_param]&.first
end end
def original_duplicate_log_id_from_query def original_duplicate_log_id_from_query
@ -163,11 +163,15 @@ private
def successful_redirect_path def successful_redirect_path
if FeatureToggle.deduplication_flow_enabled? if FeatureToggle.deduplication_flow_enabled?
if @log.lettings? if is_referrer_type?("duplicate_logs")
if current_user.lettings_logs.duplicate_logs(@log).count.positive? return correcting_duplicate_logs_redirect_path
return send("lettings_log_duplicate_logs_path", @log, original_log_id: @log.id) end
end
elsif current_user.sales_logs.duplicate_logs(@log).count.positive? if @log.lettings? && current_user.lettings_logs.duplicate_logs(@log).count.positive?
return send("lettings_log_duplicate_logs_path", @log, original_log_id: @log.id)
end
if @log.sales? && current_user.sales_logs.duplicate_logs(@log).count.positive?
return send("sales_log_duplicate_logs_path", @log, original_log_id: @log.id) return send("sales_log_duplicate_logs_path", @log, original_log_id: @log.id)
end end
end end
@ -237,4 +241,34 @@ private
end end
CONFIRMATION_PAGE_IDS = %w[uprn_confirmation].freeze CONFIRMATION_PAGE_IDS = %w[uprn_confirmation].freeze
def correcting_duplicate_logs_redirect_path
class_name = @log.class.name.underscore
original_log = current_user.send(class_name.pluralize).find_by(id: from_referrer_query("original_log_id"))
if original_log.present? && current_user.send(class_name.pluralize).duplicate_logs(original_log).count.positive?
flash[:notice] = deduplication_success_banner unless current_user.send(class_name.pluralize).duplicate_logs(@log).count.positive?
send("#{class_name}_duplicate_logs_path", original_log, original_log_id: original_log.id)
else
flash[:notice] = deduplication_success_banner
send("#{class_name}_duplicate_logs_path", "#{class_name}_id".to_sym => from_referrer_query("first_remaining_duplicate_id"), original_log_id: from_referrer_query("original_log_id"))
end
end
def deduplication_success_banner
deduplicated_log_link = "<a class=\"govuk-notification-banner__link govuk-!-font-weight-bold\" href=\"#{send("#{@log.class.name.underscore}_path", @log)}\">Log #{@log.id}</a>"
changed_labels = {
property_postcode: "postcode",
lead_tenant_age: "lead tenant’s age",
rent_4_weekly: "household rent and charges",
rent_bi_weekly: "household rent and charges",
rent_monthly: "household rent and charges",
rent_or_other_charges: "household rent and charges",
address: "postcode",
}
changed_question_label = changed_labels[@page.id.to_sym] || (@page.questions.first.check_answer_label.to_s.presence || @page.questions.first.header.to_s).downcase
I18n.t("notification.duplicate_logs.deduplication_success_banner", log_link: deduplicated_log_link, changed_question_label:).html_safe
end
end end

13
app/helpers/duplicate_logs_helper.rb

@ -1,18 +1,18 @@
module DuplicateLogsHelper module DuplicateLogsHelper
include GovukLinkHelper include GovukLinkHelper
def duplicate_logs_continue_button(all_duplicates, duplicate_log, original_log_id) def duplicate_logs_continue_button(all_duplicates, duplicate_log, original_log)
if all_duplicates.count > 1 if all_duplicates.count > 1
return govuk_button_link_to "Keep this log and delete duplicates", url_for( return govuk_button_link_to "Keep this log and delete duplicates", url_for(
controller: "duplicate_logs", controller: "duplicate_logs",
action: "delete_duplicates", action: "delete_duplicates",
"#{duplicate_log.class.name.underscore}_id": duplicate_log.id, "#{duplicate_log.class.name.underscore}_id": duplicate_log.id,
original_log_id:, original_log_id: original_log.id,
) )
end end
if original_log_id == duplicate_log.id if !original_log.deleted?
govuk_button_link_to "Back to Log #{duplicate_log.id}", send("#{duplicate_log.class.name.underscore}_path", duplicate_log) govuk_button_link_to "Back to Log #{original_log.id}", send("#{original_log.class.name.underscore}_path", original_log)
else else
type = duplicate_log.lettings? ? "lettings" : "sales" type = duplicate_log.lettings? ? "lettings" : "sales"
govuk_button_link_to "Back to #{type} logs", url_for(duplicate_log.class) govuk_button_link_to "Back to #{type} logs", url_for(duplicate_log.class)
@ -22,4 +22,9 @@ module DuplicateLogsHelper
def duplicate_logs_action_href(log, page_id, original_log_id) def duplicate_logs_action_href(log, page_id, original_log_id)
send("#{log.model_name.param_key}_#{page_id}_path", log, referrer: "interruption_screen", original_log_id:) send("#{log.model_name.param_key}_#{page_id}_path", log, referrer: "interruption_screen", original_log_id:)
end end
def change_duplicate_logs_action_href(log, page_id, all_duplicates, original_log_id)
first_remaining_duplicate_id = all_duplicates.map(&:id).reject { |id| id == log.id }.first
send("#{log.model_name.param_key}_#{page_id}_path", log, referrer: "duplicate_logs", first_remaining_duplicate_id:, original_log_id:)
end
end end

18
app/models/form/sales/pages/organisation.rb

@ -10,25 +10,19 @@ class Form::Sales::Pages::Organisation < ::Form::Page
] ]
end end
def routed_to?(log, current_user) def routed_to?(_log, current_user)
if FeatureToggle.merge_organisations_enabled? if FeatureToggle.merge_organisations_enabled?
return false unless current_user return false unless current_user
return true if current_user.support? return true if current_user.support?
stock_owners = current_user.organisation.stock_owners + current_user.organisation.absorbed_organisations.where(holds_own_stock: true) absorbed_stock_owners = current_user.organisation.absorbed_organisations.where(holds_own_stock: true)
if current_user.organisation.holds_own_stock? if current_user.organisation.holds_own_stock?
if current_user.organisation.absorbed_organisations.any?(&:holds_own_stock?) return true if absorbed_stock_owners.count >= 1
return true
end
return true if stock_owners.count >= 1
log.update!(owning_organisation: current_user.organisation)
else else
return false if stock_owners.count.zero? return false if absorbed_stock_owners.count.zero?
return true if stock_owners.count > 1 return true if absorbed_stock_owners.count > 1
log.update!(owning_organisation: stock_owners.first)
end end
false false

35
app/models/form/sales/questions/owning_organisation_id.rb

@ -17,20 +17,35 @@ class Form::Sales::Questions::OwningOrganisationId < ::Form::Question
return answer_opts unless log return answer_opts unless log
if log.owning_organisation_id.present? if log.owning_organisation_id.present?
answer_opts = answer_opts.merge({ log.owning_organisation.id => log.owning_organisation.name }) answer_opts[log.owning_organisation.id] = log.owning_organisation.name
end end
recently_absorbed_organisations = user.organisation.absorbed_organisations.merged_during_open_collection_period
if !user.support? && user.organisation.holds_own_stock? if !user.support? && user.organisation.holds_own_stock?
answer_opts[user.organisation.id] = "#{user.organisation.name} (Your organisation)" answer_opts[user.organisation.id] = if recently_absorbed_organisations.exists?
"#{user.organisation.name} (Your organisation, active as of #{user.organisation.created_at.to_fs(:govuk_date)})"
else
"#{user.organisation.name} (Your organisation)"
end
end end
user_answer_options = if user.support? if user.support?
Organisation.where(holds_own_stock: true) Organisation.where(holds_own_stock: true).find_each do |org|
else if org.merge_date.present?
user.organisation.stock_owners + user.organisation.absorbed_organisations.where(holds_own_stock: true) answer_opts[org.id] = "#{org.name} (inactive as of #{org.merge_date.to_fs(:govuk_date)})" if org.merge_date >= FormHandler.instance.start_date_of_earliest_open_for_editing_collection_period
end.pluck(:id, :name).to_h elsif org.absorbed_organisations.merged_during_open_collection_period.exists?
answer_opts[org.id] = "#{org.name} (active as of #{org.created_at.to_fs(:govuk_date)})"
else
answer_opts[org.id] = org.name
end
end
else
recently_absorbed_organisations.each do |absorbed_org|
answer_opts[absorbed_org.id] = merged_organisation_label(absorbed_org.name, absorbed_org.merge_date) if absorbed_org.holds_own_stock?
end
end
answer_opts.merge(user_answer_options) answer_opts
else else
Organisation.select(:id, :name).each_with_object(answer_opts) do |organisation, hsh| Organisation.select(:id, :name).each_with_object(answer_opts) do |organisation, hsh|
hsh[organisation.id] = organisation.name hsh[organisation.id] = organisation.name
@ -82,4 +97,8 @@ private
false false
end end
end end
def merged_organisation_label(name, merge_date)
"#{name} (inactive as of #{merge_date.to_fs(:govuk_date)})"
end
end end

2
app/models/lettings_log.rb

@ -79,7 +79,7 @@ class LettingsLog < Log
NUM_OF_WEEKS_FROM_PERIOD = { 2 => 26, 3 => 13, 4 => 12, 5 => 50, 6 => 49, 7 => 48, 8 => 47, 9 => 46, 1 => 52, 10 => 53 }.freeze NUM_OF_WEEKS_FROM_PERIOD = { 2 => 26, 3 => 13, 4 => 12, 5 => 50, 6 => 49, 7 => 48, 8 => 47, 9 => 46, 1 => 52, 10 => 53 }.freeze
SUFFIX_FROM_PERIOD = { 2 => "every 2 weeks", 3 => "every 4 weeks", 4 => "every month" }.freeze SUFFIX_FROM_PERIOD = { 2 => "every 2 weeks", 3 => "every 4 weeks", 4 => "every month" }.freeze
RETIREMENT_AGES = { "M" => 67, "F" => 60, "X" => 67 }.freeze RETIREMENT_AGES = { "M" => 67, "F" => 60, "X" => 67 }.freeze
DUPLICATE_LOG_ATTRIBUTES = %w[tenancycode startdate age1_known age1 sex1 ecstat1 tcharge household_charge chcharge].freeze DUPLICATE_LOG_ATTRIBUTES = %w[owning_organisation_id tenancycode startdate age1_known age1 sex1 ecstat1 tcharge household_charge chcharge].freeze
def form def form
FormHandler.instance.get_form(form_name) || FormHandler.instance.current_lettings_form FormHandler.instance.get_form(form_name) || FormHandler.instance.current_lettings_form

1
app/models/organisation.rb

@ -32,6 +32,7 @@ class Organisation < ApplicationRecord
scope :search_by_name, ->(name) { where("name ILIKE ?", "%#{name}%") } scope :search_by_name, ->(name) { where("name ILIKE ?", "%#{name}%") }
scope :search_by, ->(param) { search_by_name(param) } scope :search_by, ->(param) { search_by_name(param) }
scope :merged_during_open_collection_period, -> { where("merge_date >= ?", FormHandler.instance.start_date_of_earliest_open_for_editing_collection_period) }
has_paper_trail has_paper_trail

2
app/models/sales_log.rb

@ -55,7 +55,7 @@ class SalesLog < Log
OPTIONAL_FIELDS = %w[purchid othtype].freeze OPTIONAL_FIELDS = %w[purchid othtype].freeze
RETIREMENT_AGES = { "M" => 65, "F" => 60, "X" => 65 }.freeze RETIREMENT_AGES = { "M" => 65, "F" => 60, "X" => 65 }.freeze
DUPLICATE_LOG_ATTRIBUTES = %w[purchid saledate age1_known age1 sex1 ecstat1 postcode_full].freeze DUPLICATE_LOG_ATTRIBUTES = %w[owning_organisation_id purchid saledate age1_known age1 sex1 ecstat1 postcode_full].freeze
def lettings? def lettings?
false false

128
app/models/validations/setup_validations.rb

@ -14,6 +14,8 @@ module Validations::SetupValidations
unless record.startdate.between?(first_collection_start_date, current_collection_end_date) unless record.startdate.between?(first_collection_start_date, current_collection_end_date)
record.errors.add :startdate, startdate_validation_error_message record.errors.add :startdate, startdate_validation_error_message
end end
validate_merged_organisations_start_date(record)
end end
def validate_irproduct_other(record) def validate_irproduct_other(record)
@ -46,6 +48,33 @@ module Validations::SetupValidations
record.errors.add :owning_organisation_id, I18n.t("validations.setup.owning_organisation.invalid") record.errors.add :owning_organisation_id, I18n.t("validations.setup.owning_organisation.invalid")
record.errors.add :managing_organisation_id, I18n.t("validations.setup.managing_organisation.invalid") record.errors.add :managing_organisation_id, I18n.t("validations.setup.managing_organisation.invalid")
end end
return unless record.startdate
if owning_organisation.present?
if owning_organisation&.merge_date.present? && owning_organisation.merge_date <= record.startdate
record.errors.add :owning_organisation_id, I18n.t("validations.setup.owning_organisation.inactive_merged_organisation",
owning_organisation: record.owning_organisation.name,
owning_organisation_merge_date: record.owning_organisation.merge_date.to_formatted_s(:govuk_date),
owning_absorbing_organisation: record.owning_organisation.absorbing_organisation.name)
elsif owning_organisation&.absorbed_organisations.present? && owning_organisation.created_at.to_date > record.startdate.to_date
record.errors.add :owning_organisation_id, I18n.t("validations.setup.owning_organisation.inactive_absorbing_organisation",
owning_organisation: record.owning_organisation.name,
owning_organisation_available_from: record.owning_organisation.created_at.to_formatted_s(:govuk_date))
end
end
if managing_organisation.present?
if managing_organisation&.merge_date.present? && managing_organisation.merge_date <= record.startdate
record.errors.add :managing_organisation_id, I18n.t("validations.setup.managing_organisation.inactive_merged_organisation",
managing_organisation: record.managing_organisation.name,
managing_organisation_merge_date: record.managing_organisation.merge_date.to_formatted_s(:govuk_date),
managing_absorbing_organisation: record.managing_organisation.absorbing_organisation.name)
elsif managing_organisation&.absorbed_organisations.present? && managing_organisation.created_at.to_date > record.startdate.to_date
record.errors.add :managing_organisation_id, I18n.t("validations.setup.managing_organisation.inactive_absorbing_organisation",
managing_organisation: record.managing_organisation.name,
managing_organisation_available_from: record.managing_organisation.created_at.to_formatted_s(:govuk_date))
end
end
end end
def validate_managing_organisation_data_sharing_agremeent_signed(record) def validate_managing_organisation_data_sharing_agremeent_signed(record)
@ -98,4 +127,103 @@ private
def intermediate_product_rent_type?(record) def intermediate_product_rent_type?(record)
record.rent_type == 5 record.rent_type == 5
end end
def validate_merged_organisations_start_date(record)
return add_same_merge_organisation_error(record) if record.owning_organisation == record.managing_organisation
return add_same_merge_error(record) if organisations_belong_to_same_merge?(record.owning_organisation, record.managing_organisation)
add_merged_organisations_errors(record)
add_absorbing_organisations_errors(record)
end
def add_same_merge_organisation_error(record)
if merged_owning_organisation_inactive?(record)
record.errors.add :startdate, I18n.t("validations.setup.startdate.invalid_merged_organisations_start_date.same_organisation",
owning_organisation: record.owning_organisation.name,
owning_organisation_merge_date: record.owning_organisation.merge_date.to_formatted_s(:govuk_date),
owning_absorbing_organisation: record.owning_organisation.absorbing_organisation.name)
elsif absorbing_owning_organisation_inactive?(record)
record.errors.add :startdate, I18n.t("validations.setup.startdate.invalid_absorbing_organisations_start_date.same_organisation",
owning_organisation: record.owning_organisation.name,
owning_organisation_available_from: record.owning_organisation.created_at.to_formatted_s(:govuk_date))
end
end
def add_same_merge_error(record)
if merged_owning_organisation_inactive?(record)
record.errors.add :startdate, I18n.t("validations.setup.startdate.invalid_merged_organisations_start_date.same_merge",
owning_organisation: record.owning_organisation.name,
managing_organisation: record.managing_organisation.name,
owning_organisation_merge_date: record.owning_organisation.merge_date.to_formatted_s(:govuk_date),
owning_absorbing_organisation: record.owning_organisation.absorbing_organisation.name)
end
end
def add_merged_organisations_errors(record)
if merged_owning_organisation_inactive?(record) && merged_managing_organisation_inactive?(record)
record.errors.add :startdate, I18n.t("validations.setup.startdate.invalid_merged_organisations_start_date.different_merge",
owning_organisation: record.owning_organisation.name,
owning_organisation_merge_date: record.owning_organisation.merge_date.to_formatted_s(:govuk_date),
owning_absorbing_organisation: record.owning_organisation.absorbing_organisation.name,
managing_organisation: record.managing_organisation.name,
managing_organisation_merge_date: record.managing_organisation.merge_date.to_formatted_s(:govuk_date),
managing_absorbing_organisation: record.managing_organisation.absorbing_organisation.name)
else
if merged_owning_organisation_inactive?(record)
record.errors.add :startdate, I18n.t("validations.setup.startdate.invalid_merged_organisations_start_date.owning_organisation",
owning_organisation: record.owning_organisation.name,
owning_organisation_merge_date: record.owning_organisation.merge_date.to_formatted_s(:govuk_date),
owning_absorbing_organisation: record.owning_organisation.absorbing_organisation.name)
end
if merged_managing_organisation_inactive?(record)
record.errors.add :startdate, I18n.t("validations.setup.startdate.invalid_merged_organisations_start_date.managing_organisation",
managing_organisation: record.managing_organisation.name,
managing_organisation_merge_date: record.managing_organisation.merge_date.to_formatted_s(:govuk_date),
managing_absorbing_organisation: record.managing_organisation.absorbing_organisation.name)
end
end
end
def add_absorbing_organisations_errors(record)
if absorbing_owning_organisation_inactive?(record) && absorbing_managing_organisation_inactive?(record)
record.errors.add :startdate, I18n.t("validations.setup.startdate.invalid_absorbing_organisations_start_date.different_organisations",
owning_organisation: record.owning_organisation.name,
owning_organisation_active_from: record.owning_organisation.created_at.to_formatted_s(:govuk_date),
managing_organisation: record.managing_organisation.name,
managing_organisation_active_from: record.managing_organisation.created_at.to_formatted_s(:govuk_date))
else
if absorbing_owning_organisation_inactive?(record)
record.errors.add :startdate, I18n.t("validations.setup.startdate.invalid_absorbing_organisations_start_date.owning_organisation",
owning_organisation: record.owning_organisation.name,
owning_organisation_available_from: record.owning_organisation.created_at.to_formatted_s(:govuk_date))
end
if absorbing_managing_organisation_inactive?(record)
record.errors.add :startdate, I18n.t("validations.setup.startdate.invalid_absorbing_organisations_start_date.managing_organisation",
managing_organisation: record.managing_organisation.name,
managing_organisation_available_from: record.managing_organisation.created_at.to_formatted_s(:govuk_date))
end
end
end
def merged_owning_organisation_inactive?(record)
record.owning_organisation&.merge_date.present? && record.owning_organisation.merge_date <= record.startdate
end
def merged_managing_organisation_inactive?(record)
record.managing_organisation&.merge_date.present? && record.managing_organisation.merge_date <= record.startdate
end
def absorbing_owning_organisation_inactive?(record)
record.owning_organisation&.absorbed_organisations.present? && record.owning_organisation.created_at.to_date > record.startdate.to_date
end
def absorbing_managing_organisation_inactive?(record)
record.managing_organisation&.absorbed_organisations.present? && record.managing_organisation.created_at.to_date > record.startdate.to_date
end
def organisations_belong_to_same_merge?(organisation_a, organisation_b)
organisation_a&.merge_date.present? && organisation_b&.merge_date.present? && organisation_a.merge_date == organisation_b.merge_date && organisation_a.absorbing_organisation == organisation_b.absorbing_organisation
end
end end

27
app/views/duplicate_logs/_duplicate_log_check_answers.erb

@ -7,14 +7,14 @@
<% row.value do %> <% row.value do %>
<%= simple_format( <%= simple_format(
get_answer_label(question, @log), get_answer_label(question, log),
wrapper_tag: "span", wrapper_tag: "span",
class: "govuk-!-margin-right-4", class: "govuk-!-margin-right-4",
) %> ) %>
<% extra_value = question.get_extra_check_answer_value(@log) %> <% extra_value = question.get_extra_check_answer_value(log) %>
<% if extra_value && question.answer_label(@log, current_user).present? %> <% if extra_value && question.answer_label(log, current_user).present? %>
<%= simple_format( <%= simple_format(
extra_value, extra_value,
wrapper_tag: "span", wrapper_tag: "span",
@ -22,16 +22,23 @@
) %> ) %>
<% end %> <% end %>
<% question.get_inferred_answers(@log).each do |inferred_answer| %> <% question.get_inferred_answers(log).each do |inferred_answer| %>
<span class="govuk-!-font-weight-regular app-!-colour-muted"><%= inferred_answer %></span> <span class="govuk-!-font-weight-regular app-!-colour-muted"><%= inferred_answer %></span>
<% end %> <% end %>
<% end %> <% end %>
<% if @all_duplicates.many? %>
<% row.action( <% row.action(
text: question.action_text(@log), text: question.action_text(log),
href: duplicate_logs_action_href(@log, question.page.id, @original_log_id), href: change_duplicate_logs_action_href(log, question.page.id, @all_duplicates, @original_log.id),
visually_hidden_text: question.check_answer_label.to_s.downcase, visually_hidden_text: question.check_answer_label.to_s.downcase,
) %> ) %>
<% else %>
<% row.action(
text: question.action_text(log),
href: duplicate_logs_action_href(log, question.page.id, @original_log.id),
visually_hidden_text: question.check_answer_label.to_s.downcase,
) %>
<% end %>
<% end %> <% end %>
<% end %> <% end %>
<% end %> <% end %>

4
app/views/duplicate_logs/show.html.erb

@ -1,7 +1,7 @@
<% content_for :title, "Check duplicate logs" %> <% content_for :title, "Check duplicate logs" %>
<div class="govuk-grid-row"> <div class="govuk-grid-row">
<div class="govuk-grid-column-two-thirds"> <div class="govuk-grid-column-two-thirds">
<% if @all_duplicates.count > 1 %> <% if @all_duplicates.many? %>
<%= govuk_panel( <%= govuk_panel(
classes: "app-panel--interruption", classes: "app-panel--interruption",
) do %> ) do %>
@ -18,7 +18,7 @@
<% @all_duplicates.each_with_index do |log, index| %> <% @all_duplicates.each_with_index do |log, index| %>
<%= render partial: "duplicate_log", locals: { log: } %> <%= render partial: "duplicate_log", locals: { log: } %>
<%= render partial: "duplicate_log_check_answers", locals: { log: } %> <%= render partial: "duplicate_log_check_answers", locals: { log: } %>
<%= duplicate_logs_continue_button(@all_duplicates, log, @original_log_id) %> <%= duplicate_logs_continue_button(@all_duplicates, log, @original_log) %>
<% if index < @all_duplicates.count - 1 %> <% if index < @all_duplicates.count - 1 %>
<hr class="govuk-section-break govuk-section-break--visible govuk-section-break--m"> <hr class="govuk-section-break govuk-section-break--visible govuk-section-break--m">
<% end %> <% end %>

2
app/views/logs/delete_duplicates.html.erb

@ -29,7 +29,7 @@
<%= govuk_button_to @duplicate_logs.count == 1 ? "Delete this log" : "Delete these logs", <%= govuk_button_to @duplicate_logs.count == 1 ? "Delete this log" : "Delete these logs",
send("delete_logs_#{@log.class.name.underscore}s_path"), send("delete_logs_#{@log.class.name.underscore}s_path"),
method: "delete", method: "delete",
params: { ids: @duplicate_logs.map(&:id), original_log_id: @original_log_id, remaining_log_id: @log.id } %> params: { ids: @duplicate_logs.map(&:id), original_log_id: @original_log.id, remaining_log_id: @log.id } %>
<%= govuk_button_link_to( <%= govuk_button_link_to(
"Cancel", "Cancel",
send("#{@log.class.name.underscore}_duplicate_logs_path", @log), send("#{@log.class.name.underscore}_duplicate_logs_path", @log),

17
config/locales/en.yml

@ -187,6 +187,8 @@ en:
duplicate_logs_deleted: duplicate_logs_deleted:
one: "%{log_ids} has been deleted." one: "%{log_ids} has been deleted."
other: "%{log_ids} have been deleted." other: "%{log_ids} have been deleted."
duplicate_logs:
deduplication_success_banner: "%{log_link} is no longer a duplicate and has been removed from the list.<p class=\"govuk-body govuk-!-margin-top-4\">You changed the %{changed_question_label}.</p>"
validations: validations:
organisation: organisation:
@ -252,6 +254,17 @@ en:
year_not_two_digits: Tenancy start year must be 2 digits year_not_two_digits: Tenancy start year must be 2 digits
ten_years_after_void_date: "Enter a tenancy start date that is no more than 10 years after the void date" ten_years_after_void_date: "Enter a tenancy start date that is no more than 10 years after the void date"
ten_years_after_mrc_date: "Enter a tenancy start date that is no more than 10 years after the major repairs completion date" ten_years_after_mrc_date: "Enter a tenancy start date that is no more than 10 years after the major repairs completion date"
invalid_merged_organisations_start_date:
same_organisation: "Enter a date when the owning and managing organisation was active. %{owning_organisation} became inactive on %{owning_organisation_merge_date} and was replaced by %{owning_absorbing_organisation}."
same_merge: "Enter a date when the owning and managing organisations were active. %{owning_organisation} and %{managing_organisation} became inactive on %{owning_organisation_merge_date} and were replaced by %{owning_absorbing_organisation}."
owning_organisation: "Enter a date when the owning organisation was active. %{owning_organisation} became inactive on %{owning_organisation_merge_date} and was replaced by %{owning_absorbing_organisation}."
managing_organisation: "Enter a date when the managing organisation was active. %{managing_organisation} became inactive on %{managing_organisation_merge_date} and was replaced by %{managing_absorbing_organisation}."
different_merge: "Enter a date when the owning and managing organisations were active. %{owning_organisation} became inactive on %{owning_organisation_merge_date} and was replaced by %{owning_absorbing_organisation}. %{managing_organisation} became inactive on %{managing_organisation_merge_date} and was replaced by %{managing_absorbing_organisation}."
invalid_absorbing_organisations_start_date:
same_organisation: "Enter a date when the owning and managing organisation was active. %{owning_organisation} became active on %{owning_organisation_available_from}."
owning_organisation: "Enter a date when the owning organisation was active. %{owning_organisation} became active on %{owning_organisation_available_from}."
managing_organisation: "Enter a date when the managing organisation was active. %{managing_organisation} became active on %{managing_organisation_available_from}."
different_organisations: "Enter a date when the owning and managing organisations were active. %{owning_organisation} became active on %{owning_organisation_active_from}, and %{managing_organisation} became active on %{managing_organisation_active_from}."
location: location:
deactivated: deactivated:
@ -273,9 +286,13 @@ en:
owning_organisation: owning_organisation:
invalid: "Please select the owning organisation or managing organisation that you belong to" invalid: "Please select the owning organisation or managing organisation that you belong to"
data_sharing_agreement_not_signed: "The organisation must accept the Data Sharing Agreement before it can be selected as the owning organisation." data_sharing_agreement_not_signed: "The organisation must accept the Data Sharing Agreement before it can be selected as the owning organisation."
inactive_merged_organisation: "The owning organisation must be active on the tenancy start date. %{owning_organisation} became inactive on %{owning_organisation_merge_date} and was replaced by %{owning_absorbing_organisation}."
inactive_absorbing_organisation: "The owning organisation must be active on the tenancy start date. %{owning_organisation} became active on %{owning_organisation_available_from}."
managing_organisation: managing_organisation:
invalid: "Please select the owning organisation or managing organisation that you belong to" invalid: "Please select the owning organisation or managing organisation that you belong to"
data_sharing_agreement_not_signed: "The organisation must accept the Data Sharing Agreement before it can be selected as the managing organisation." data_sharing_agreement_not_signed: "The organisation must accept the Data Sharing Agreement before it can be selected as the managing organisation."
inactive_merged_organisation: "The managing organisation must be active on the tenancy start date. %{managing_organisation} became inactive on %{managing_organisation_merge_date} and was replaced by %{managing_absorbing_organisation}."
inactive_absorbing_organisation: "The managing organisation must be active on the tenancy start date. %{managing_organisation} became active on %{managing_organisation_available_from}."
created_by: created_by:
invalid: "Please select the owning organisation or managing organisation that you belong to" invalid: "Please select the owning organisation or managing organisation that you belong to"
lettype: lettype:

23
spec/features/lettings_log_spec.rb

@ -505,6 +505,29 @@ RSpec.describe "Lettings Log Features" do
expect(page).to have_current_path("/lettings-logs/#{duplicate_log.id}/duplicate-logs?original_log_id=#{lettings_log.id}") expect(page).to have_current_path("/lettings-logs/#{duplicate_log.id}/duplicate-logs?original_log_id=#{lettings_log.id}")
expect(page).to have_link("Back to lettings logs", href: "/lettings-logs") expect(page).to have_link("Back to lettings logs", href: "/lettings-logs")
end end
it "allows deduplicating logs by changing the answers on the duplicate log" do
expect(page).to have_current_path("/lettings-logs/#{lettings_log.id}/duplicate-logs?original_log_id=#{lettings_log.id}")
click_link("Change", href: "/lettings-logs/#{duplicate_log.id}/tenant-code?first_remaining_duplicate_id=#{lettings_log.id}&original_log_id=#{lettings_log.id}&referrer=duplicate_logs")
fill_in("lettings-log-tenancycode-field", with: "something else")
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{lettings_log.id}/duplicate-logs?original_log_id=#{lettings_log.id}")
expect(page).to have_link("Back to Log #{lettings_log.id}", href: "/lettings-logs/#{lettings_log.id}")
expect(page).to have_css(".govuk-notification-banner.govuk-notification-banner--success")
expect(page).to have_content("Log #{duplicate_log.id} is no longer a duplicate and has been removed from the list")
expect(page).to have_content("You changed the tenant code.")
end
it "allows deduplicating logs by changing the answers on the original log" do
click_link("Change", href: "/lettings-logs/#{lettings_log.id}/tenant-code?first_remaining_duplicate_id=#{duplicate_log.id}&original_log_id=#{lettings_log.id}&referrer=duplicate_logs")
fill_in("lettings-log-tenancycode-field", with: "something else")
click_button("Save and continue")
expect(page).to have_current_path("/lettings-logs/#{duplicate_log.id}/duplicate-logs?original_log_id=#{lettings_log.id}")
expect(page).to have_link("Back to Log #{lettings_log.id}", href: "/lettings-logs/#{lettings_log.id}")
expect(page).to have_css(".govuk-notification-banner.govuk-notification-banner--success")
expect(page).to have_content("Log #{lettings_log.id} is no longer a duplicate and has been removed from the list")
expect(page).to have_content("You changed the tenant code.")
end
end end
end end
end end

23
spec/features/sales_log_spec.rb

@ -244,5 +244,28 @@ RSpec.describe "Sales Log Features" do
expect(page).to have_current_path("/sales-logs/#{duplicate_log.id}/duplicate-logs?original_log_id=#{sales_log.id}") expect(page).to have_current_path("/sales-logs/#{duplicate_log.id}/duplicate-logs?original_log_id=#{sales_log.id}")
expect(page).to have_link("Back to sales logs", href: "/sales-logs") expect(page).to have_link("Back to sales logs", href: "/sales-logs")
end end
it "allows deduplicating logs by changing the answers on the duplicate log" do
expect(page).to have_current_path("/sales-logs/#{sales_log.id}/duplicate-logs?original_log_id=#{sales_log.id}")
click_link("Change", href: "/sales-logs/#{duplicate_log.id}/purchaser-code?first_remaining_duplicate_id=#{sales_log.id}&original_log_id=#{sales_log.id}&referrer=duplicate_logs")
fill_in("sales-log-purchid-field", with: "something else")
click_button("Save and continue")
expect(page).to have_current_path("/sales-logs/#{sales_log.id}/duplicate-logs?original_log_id=#{sales_log.id}")
expect(page).to have_link("Back to Log #{sales_log.id}", href: "/sales-logs/#{sales_log.id}")
expect(page).to have_css(".govuk-notification-banner.govuk-notification-banner--success")
expect(page).to have_content("Log #{duplicate_log.id} is no longer a duplicate and has been removed from the list")
expect(page).to have_content("You changed the purchaser code.")
end
it "allows deduplicating logs by changing the answers on the original log" do
click_link("Change", href: "/sales-logs/#{sales_log.id}/purchaser-code?first_remaining_duplicate_id=#{duplicate_log.id}&original_log_id=#{sales_log.id}&referrer=duplicate_logs")
fill_in("sales-log-purchid-field", with: "something else")
click_button("Save and continue")
expect(page).to have_current_path("/sales-logs/#{duplicate_log.id}/duplicate-logs?original_log_id=#{sales_log.id}")
expect(page).to have_link("Back to Log #{sales_log.id}", href: "/sales-logs/#{sales_log.id}")
expect(page).to have_css(".govuk-notification-banner.govuk-notification-banner--success")
expect(page).to have_content("Log #{sales_log.id} is no longer a duplicate and has been removed from the list")
expect(page).to have_content("You changed the purchaser code.")
end
end end
end end

32
spec/models/form/sales/pages/organisation_spec.rb

@ -88,8 +88,8 @@ RSpec.describe Form::Sales::Pages::Organisation, type: :model do
expect(page.routed_to?(log, user)).to eq(false) expect(page.routed_to?(log, user)).to eq(false)
end end
it "updates owning_organisation_id" do it "does not update owning_organisation_id" do
expect { page.routed_to?(log, user) }.to change(log.reload, :owning_organisation).from(nil).to(stock_owner) expect { page.routed_to?(log, user) }.not_to change(log.reload, :owning_organisation)
end end
end end
@ -111,11 +111,7 @@ RSpec.describe Form::Sales::Pages::Organisation, type: :model do
end end
it "is not shown" do it "is not shown" do
expect(page.routed_to?(log, user)).to eq(true) expect(page.routed_to?(log, user)).to eq(false)
end
it "updates owning_organisation_id" do
expect { page.routed_to?(log, user) }.not_to change(log.reload, :owning_organisation)
end end
end end
end end
@ -129,12 +125,6 @@ RSpec.describe Form::Sales::Pages::Organisation, type: :model do
it "is not shown" do it "is not shown" do
expect(page.routed_to?(log, user)).to eq(false) expect(page.routed_to?(log, user)).to eq(false)
end end
it "updates owning_organisation_id to user organisation" do
expect {
page.routed_to?(log, user)
}.to change(log.reload, :owning_organisation).from(nil).to(user.organisation)
end
end end
context "with >0 stock_owners" do context "with >0 stock_owners" do
@ -143,12 +133,20 @@ RSpec.describe Form::Sales::Pages::Organisation, type: :model do
create(:organisation_relationship, child_organisation: user.organisation) create(:organisation_relationship, child_organisation: user.organisation)
end end
it "is shown" do it "is not shown" do
expect(page.routed_to?(log, user)).to eq(true) expect(page.routed_to?(log, user)).to eq(false)
end end
end
it "does not update owning_organisation_id" do context "with merged organisations" do
expect { page.routed_to?(log, user) }.not_to change(log.reload, :owning_organisation).from(nil) let(:merged_org) { create(:organisation) }
before do
merged_org.update!(absorbing_organisation: user.organisation, merge_date: Time.zone.now)
end
it "is shown" do
expect(page.routed_to?(log, user)).to eq(true)
end end
end end
end end

132
spec/models/form/sales/questions/owning_organisation_id_spec.rb

@ -70,53 +70,99 @@ RSpec.describe Form::Sales::Questions::OwningOrganisationId, type: :model do
"" => "Select an option", "" => "Select an option",
owning_org_1.id => "Owning org 1", owning_org_1.id => "Owning org 1",
user.organisation.id => "User org (Your organisation)", user.organisation.id => "User org (Your organisation)",
owning_org_2.id => "Owning org 2",
} }
end end
it "shows current stock owner at top, followed by user's org (with hint), followed by the stock owners of the user's org" do it "does not show stock owner" do
user.organisation.update!(holds_own_stock: true) user.organisation.update!(holds_own_stock: true)
expect(question.displayed_answer_options(log, user)).to eq(options) expect(question.displayed_answer_options(log, user)).to eq(options)
end end
end
context "when the owning-managing organisation relationship is deleted" do context "when user's org doesn't own stock" do
let(:options) do let(:options) do
{ {
"" => "Select an option", "" => "Select an option",
user.organisation.id => "User org (Your organisation)", owning_org_1.id => "Owning org 1",
owning_org_2.id => "Owning org 2", }
} end
end
it "doesn't remove the housing provider from the list of allowed housing providers" do it "shows current log owner" do
log.update!(owning_organisation: owning_org_2) user.organisation.update!(holds_own_stock: false)
expect(question.displayed_answer_options(log, user)).to eq(options) expect(question.displayed_answer_options(log, user)).to eq(options)
org_rel.destroy!
expect(question.displayed_answer_options(log, user)).to eq(options)
end
end end
end end
context "when user's org doesn't own stock" do context "when user's org has recently absorbed other orgs" do
let(:merged_organisation) { create(:organisation, name: "Merged org") }
let(:options) do let(:options) do
{ {
"" => "Select an option", "" => "Select an option",
user.organisation.id => "User org (Your organisation, active as of 2 February 2021)",
owning_org_1.id => "Owning org 1", owning_org_1.id => "Owning org 1",
owning_org_2.id => "Owning org 2", merged_organisation.id => "Merged org (inactive as of 2 February 2023)",
} }
end end
it "shows current stock owner at top, followed by the stock owners of the user's org" do before do
user.organisation.update!(holds_own_stock: false) merged_organisation.update!(merge_date: Time.zone.local(2023, 2, 2), absorbing_organisation: user.organisation)
user.organisation.update!(created_at: Time.zone.local(2021, 2, 2))
end
it "shows merged organisation as an option" do
expect(question.displayed_answer_options(log, user)).to eq(options)
end
end
context "when user's org has recently absorbed other orgs with parent organisations" do
let(:merged_organisation) { create(:organisation, name: "Merged org") }
let(:options) do
{
"" => "Select an option",
user.organisation.id => "User org (Your organisation, active as of 2 February 2021)",
owning_org_1.id => "Owning org 1",
merged_organisation.id => "Merged org (inactive as of 2 February 2023)",
}
end
before do
org_rel.update!(child_organisation: merged_organisation)
merged_organisation.update!(merge_date: Time.zone.local(2023, 2, 2), absorbing_organisation: user.organisation)
user.organisation.update!(created_at: Time.zone.local(2021, 2, 2))
end
it "does not show merged organisations stock owners as options" do
expect(question.displayed_answer_options(log, user)).to eq(options)
end
end
context "when user's org has absorbed other orgs with parent organisations during closed collection periods" do
let(:merged_organisation) { create(:organisation, name: "Merged org") }
let(:options) do
{
"" => "Select an option",
user.organisation.id => "User org (Your organisation)",
owning_org_1.id => "Owning org 1",
}
end
before do
Timecop.freeze(Time.zone.local(2023, 4, 2))
org_rel.update!(child_organisation: merged_organisation)
merged_organisation.update!(merge_date: Time.zone.local(2021, 6, 2), absorbing_organisation: user.organisation)
user.organisation.update!(created_at: Time.zone.local(2021, 2, 2))
end
it "shows merged organisation as an option" do
expect(question.displayed_answer_options(log, user)).to eq(options) expect(question.displayed_answer_options(log, user)).to eq(options)
end end
end end
end end
context "when user is support" do context "when user is support" do
let(:user) { create(:user, :support) } let(:user) { create(:user, :support, organisation: organisation_1) }
let(:log) { create(:lettings_log) } let(:log) { create(:lettings_log, created_by: user) }
let(:non_stock_organisation) { create(:organisation, holds_own_stock: false) } let(:non_stock_organisation) { create(:organisation, holds_own_stock: false) }
let(:expected_opts) do let(:expected_opts) do
@ -130,6 +176,48 @@ RSpec.describe Form::Sales::Questions::OwningOrganisationId, type: :model do
expect(question.displayed_answer_options(log, user)).to eq(expected_opts) expect(question.displayed_answer_options(log, user)).to eq(expected_opts)
expect(question.displayed_answer_options(log, user)).not_to include(non_stock_organisation.id) expect(question.displayed_answer_options(log, user)).not_to include(non_stock_organisation.id)
end end
context "when an org has recently absorbed other orgs" do
let(:merged_organisation) { create(:organisation, name: "Merged org") }
let(:options) do
{
"" => "Select an option",
organisation_1.id => "first test org (active as of 2 February 2021)",
organisation_2.id => "second test org",
merged_organisation.id => "Merged org (inactive as of 2 February 2023)",
}
end
before do
merged_organisation.update!(merge_date: Time.zone.local(2023, 2, 2), absorbing_organisation: organisation_1)
organisation_1.update!(created_at: Time.zone.local(2021, 2, 2))
end
it "shows merged organisation as an option" do
expect(question.displayed_answer_options(log, user)).to eq(options)
end
end
context "when user's org has absorbed other orgs during closed collection periods" do
let(:merged_organisation) { create(:organisation, name: "Merged org") }
let(:options) do
{
"" => "Select an option",
organisation_1.id => "first test org",
organisation_2.id => "second test org",
}
end
before do
Timecop.freeze(Time.zone.local(2023, 4, 2))
merged_organisation.update!(merge_date: Time.zone.local(2021, 6, 2), absorbing_organisation: user.organisation)
user.organisation.update!(created_at: Time.zone.local(2021, 2, 2))
end
it "shows merged organisation as an option" do
expect(question.displayed_answer_options(log, user)).to eq(options)
end
end
end end
end end

31
spec/models/lettings_log_spec.rb

@ -2836,8 +2836,9 @@ RSpec.describe LettingsLog do
end end
context "when filtering duplicate logs" do context "when filtering duplicate logs" do
let(:log) { create(:lettings_log, :duplicate) } let(:organisation) { create(:organisation) }
let!(:duplicate_log) { create(:lettings_log, :duplicate) } let(:log) { create(:lettings_log, :duplicate, owning_organisation: organisation) }
let!(:duplicate_log) { create(:lettings_log, :duplicate, owning_organisation: organisation) }
it "returns all duplicate logs for given log" do it "returns all duplicate logs for given log" do
expect(described_class.duplicate_logs(log).count).to eq(1) expect(described_class.duplicate_logs(log).count).to eq(1)
@ -2852,7 +2853,7 @@ RSpec.describe LettingsLog do
end end
context "when there is a deleted duplicate log" do context "when there is a deleted duplicate log" do
let!(:deleted_duplicate_log) { create(:lettings_log, :duplicate, discarded_at: Time.zone.now) } let!(:deleted_duplicate_log) { create(:lettings_log, :duplicate, discarded_at: Time.zone.now, owning_organisation: organisation) }
it "does not return the deleted log as a duplicate" do it "does not return the deleted log as a duplicate" do
expect(described_class.duplicate_logs(log)).not_to include(deleted_duplicate_log) expect(described_class.duplicate_logs(log)).not_to include(deleted_duplicate_log)
@ -2860,7 +2861,7 @@ RSpec.describe LettingsLog do
end end
context "when there is a log with a different start date" do context "when there is a log with a different start date" do
let!(:different_start_date_log) { create(:lettings_log, :duplicate, startdate: Time.zone.tomorrow) } let!(:different_start_date_log) { create(:lettings_log, :duplicate, startdate: Time.zone.tomorrow, owning_organisation: organisation) }
it "does not return a log with a different start date as a duplicate" do it "does not return a log with a different start date as a duplicate" do
expect(described_class.duplicate_logs(log)).not_to include(different_start_date_log) expect(described_class.duplicate_logs(log)).not_to include(different_start_date_log)
@ -2868,7 +2869,7 @@ RSpec.describe LettingsLog do
end end
context "when there is a log with a different age1" do context "when there is a log with a different age1" do
let!(:different_age1) { create(:lettings_log, :duplicate, age1: 50) } let!(:different_age1) { create(:lettings_log, :duplicate, age1: 50, owning_organisation: organisation) }
it "does not return a log with a different age1 as a duplicate" do it "does not return a log with a different age1 as a duplicate" do
expect(described_class.duplicate_logs(log)).not_to include(different_age1) expect(described_class.duplicate_logs(log)).not_to include(different_age1)
@ -2876,7 +2877,7 @@ RSpec.describe LettingsLog do
end end
context "when there is a log with a different sex1" do context "when there is a log with a different sex1" do
let!(:different_sex1) { create(:lettings_log, :duplicate, sex1: "F") } let!(:different_sex1) { create(:lettings_log, :duplicate, sex1: "F", owning_organisation: organisation) }
it "does not return a log with a different sex1 as a duplicate" do it "does not return a log with a different sex1 as a duplicate" do
expect(described_class.duplicate_logs(log)).not_to include(different_sex1) expect(described_class.duplicate_logs(log)).not_to include(different_sex1)
@ -2884,7 +2885,7 @@ RSpec.describe LettingsLog do
end end
context "when there is a log with a different ecstat1" do context "when there is a log with a different ecstat1" do
let!(:different_ecstat1) { create(:lettings_log, :duplicate, ecstat1: 1) } let!(:different_ecstat1) { create(:lettings_log, :duplicate, ecstat1: 1, owning_organisation: organisation) }
it "does not return a log with a different ecstat1 as a duplicate" do it "does not return a log with a different ecstat1 as a duplicate" do
expect(described_class.duplicate_logs(log)).not_to include(different_ecstat1) expect(described_class.duplicate_logs(log)).not_to include(different_ecstat1)
@ -2892,7 +2893,7 @@ RSpec.describe LettingsLog do
end end
context "when there is a log with a different tcharge" do context "when there is a log with a different tcharge" do
let!(:different_tcharge) { create(:lettings_log, :duplicate, brent: 100) } let!(:different_tcharge) { create(:lettings_log, :duplicate, brent: 100, owning_organisation: organisation) }
it "does not return a log with a different tcharge as a duplicate" do it "does not return a log with a different tcharge as a duplicate" do
expect(described_class.duplicate_logs(log)).not_to include(different_tcharge) expect(described_class.duplicate_logs(log)).not_to include(different_tcharge)
@ -2900,7 +2901,7 @@ RSpec.describe LettingsLog do
end end
context "when there is a log with a different tenancycode" do context "when there is a log with a different tenancycode" do
let!(:different_tenancycode) { create(:lettings_log, :duplicate, tenancycode: "different") } let!(:different_tenancycode) { create(:lettings_log, :duplicate, tenancycode: "different", owning_organisation: organisation) }
it "does not return a log with a different tenancycode as a duplicate" do it "does not return a log with a different tenancycode as a duplicate" do
expect(described_class.duplicate_logs(log)).not_to include(different_tenancycode) expect(described_class.duplicate_logs(log)).not_to include(different_tenancycode)
@ -2908,7 +2909,7 @@ RSpec.describe LettingsLog do
end end
context "when there is a log with a different postcode_full" do context "when there is a log with a different postcode_full" do
let!(:different_postcode_full) { create(:lettings_log, :duplicate, postcode_full: "B1 1AA") } let!(:different_postcode_full) { create(:lettings_log, :duplicate, postcode_full: "B1 1AA", owning_organisation: organisation) }
it "does not return a log with a different postcode_full as a duplicate" do it "does not return a log with a different postcode_full as a duplicate" do
expect(described_class.duplicate_logs(log)).not_to include(different_postcode_full) expect(described_class.duplicate_logs(log)).not_to include(different_postcode_full)
@ -2916,7 +2917,7 @@ RSpec.describe LettingsLog do
end end
context "when there is a log with nil values for duplicate check fields" do context "when there is a log with nil values for duplicate check fields" do
let!(:duplicate_check_fields_not_given) { create(:lettings_log, :duplicate, age1: nil, sex1: nil, ecstat1: nil, postcode_known: 2, postcode_full: nil) } let!(:duplicate_check_fields_not_given) { create(:lettings_log, :duplicate, age1: nil, sex1: nil, ecstat1: nil, postcode_known: 2, postcode_full: nil, owning_organisation: organisation) }
it "does not return a log with nil values as a duplicate" do it "does not return a log with nil values as a duplicate" do
log.update!(age1: nil, sex1: nil, ecstat1: nil, postcode_known: 2, postcode_full: nil) log.update!(age1: nil, sex1: nil, ecstat1: nil, postcode_known: 2, postcode_full: nil)
@ -2925,7 +2926,7 @@ RSpec.describe LettingsLog do
end end
context "when there is a log with nil values for tenancycode" do context "when there is a log with nil values for tenancycode" do
let!(:tenancycode_not_given) { create(:lettings_log, :duplicate, tenancycode: nil) } let!(:tenancycode_not_given) { create(:lettings_log, :duplicate, tenancycode: nil, owning_organisation: organisation) }
it "returns the log as a duplicate if tenancy code is nil" do it "returns the log as a duplicate if tenancy code is nil" do
log.update!(tenancycode: nil) log.update!(tenancycode: nil)
@ -2934,7 +2935,7 @@ RSpec.describe LettingsLog do
end end
context "when there is a log with age1 not known" do context "when there is a log with age1 not known" do
let!(:age1_not_known) { create(:lettings_log, :duplicate, age1_known: 1, age1: nil) } let!(:age1_not_known) { create(:lettings_log, :duplicate, age1_known: 1, age1: nil, owning_organisation: organisation) }
it "returns the log as a duplicate if age1 is not known" do it "returns the log as a duplicate if age1 is not known" do
log.update!(age1_known: 1, age1: nil) log.update!(age1_known: 1, age1: nil)
@ -2946,8 +2947,8 @@ RSpec.describe LettingsLog do
let(:scheme) { create(:scheme) } let(:scheme) { create(:scheme) }
let(:location) { create(:location, scheme:) } let(:location) { create(:location, scheme:) }
let(:location_2) { create(:location, scheme:) } let(:location_2) { create(:location, scheme:) }
let(:supported_housing_log) { create(:lettings_log, :duplicate, needstype: 2, location:, scheme:) } let(:supported_housing_log) { create(:lettings_log, :duplicate, needstype: 2, location:, scheme:, owning_organisation: organisation) }
let!(:duplicate_supported_housing_log) { create(:lettings_log, :duplicate, needstype: 2, location:, scheme:) } let!(:duplicate_supported_housing_log) { create(:lettings_log, :duplicate, needstype: 2, location:, scheme:, owning_organisation: organisation) }
it "returns the log as a duplicate" do it "returns the log as a duplicate" do
expect(described_class.duplicate_logs(supported_housing_log)).to include(duplicate_supported_housing_log) expect(described_class.duplicate_logs(supported_housing_log)).to include(duplicate_supported_housing_log)

29
spec/models/sales_log_spec.rb

@ -161,8 +161,9 @@ RSpec.describe SalesLog, type: :model do
end end
context "when filtering duplicate logs" do context "when filtering duplicate logs" do
let(:log) { create(:sales_log, :duplicate) } let(:organisation) { create(:organisation) }
let!(:duplicate_log) { create(:sales_log, :duplicate) } let(:log) { create(:sales_log, :duplicate, owning_organisation: organisation) }
let!(:duplicate_log) { create(:sales_log, :duplicate, owning_organisation: organisation) }
it "returns all duplicate logs for given log" do it "returns all duplicate logs for given log" do
expect(described_class.duplicate_logs(log).count).to eq(1) expect(described_class.duplicate_logs(log).count).to eq(1)
@ -177,7 +178,7 @@ RSpec.describe SalesLog, type: :model do
end end
context "when there is a deleted duplicate log" do context "when there is a deleted duplicate log" do
let!(:deleted_duplicate_log) { create(:sales_log, :duplicate, discarded_at: Time.zone.now) } let!(:deleted_duplicate_log) { create(:sales_log, :duplicate, discarded_at: Time.zone.now, owning_organisation: organisation) }
it "does not return the deleted log as a duplicate" do it "does not return the deleted log as a duplicate" do
expect(described_class.duplicate_logs(log)).not_to include(deleted_duplicate_log) expect(described_class.duplicate_logs(log)).not_to include(deleted_duplicate_log)
@ -185,7 +186,7 @@ RSpec.describe SalesLog, type: :model do
end end
context "when there is a log with a different sale date" do context "when there is a log with a different sale date" do
let!(:different_sale_date_log) { create(:sales_log, :duplicate, saledate: Time.zone.tomorrow) } let!(:different_sale_date_log) { create(:sales_log, :duplicate, saledate: Time.zone.tomorrow, owning_organisation: organisation) }
it "does not return a log with a different sale date as a duplicate" do it "does not return a log with a different sale date as a duplicate" do
expect(described_class.duplicate_logs(log)).not_to include(different_sale_date_log) expect(described_class.duplicate_logs(log)).not_to include(different_sale_date_log)
@ -193,7 +194,7 @@ RSpec.describe SalesLog, type: :model do
end end
context "when there is a log with a different age1" do context "when there is a log with a different age1" do
let!(:different_age1) { create(:sales_log, :duplicate, age1: 50) } let!(:different_age1) { create(:sales_log, :duplicate, age1: 50, owning_organisation: organisation) }
it "does not return a log with a different age1 as a duplicate" do it "does not return a log with a different age1 as a duplicate" do
expect(described_class.duplicate_logs(log)).not_to include(different_age1) expect(described_class.duplicate_logs(log)).not_to include(different_age1)
@ -201,7 +202,7 @@ RSpec.describe SalesLog, type: :model do
end end
context "when there is a log with a different sex1" do context "when there is a log with a different sex1" do
let!(:different_sex1) { create(:sales_log, :duplicate, sex1: "M") } let!(:different_sex1) { create(:sales_log, :duplicate, sex1: "M", owning_organisation: organisation) }
it "does not return a log with a different sex1 as a duplicate" do it "does not return a log with a different sex1 as a duplicate" do
expect(described_class.duplicate_logs(log)).not_to include(different_sex1) expect(described_class.duplicate_logs(log)).not_to include(different_sex1)
@ -209,7 +210,7 @@ RSpec.describe SalesLog, type: :model do
end end
context "when there is a log with a different ecstat1" do context "when there is a log with a different ecstat1" do
let!(:different_ecstat1) { create(:sales_log, :duplicate, ecstat1: 0) } let!(:different_ecstat1) { create(:sales_log, :duplicate, ecstat1: 0, owning_organisation: organisation) }
it "does not return a log with a different ecstat1 as a duplicate" do it "does not return a log with a different ecstat1 as a duplicate" do
expect(described_class.duplicate_logs(log)).not_to include(different_ecstat1) expect(described_class.duplicate_logs(log)).not_to include(different_ecstat1)
@ -217,7 +218,7 @@ RSpec.describe SalesLog, type: :model do
end end
context "when there is a log with a different purchid" do context "when there is a log with a different purchid" do
let!(:different_purchid) { create(:sales_log, :duplicate, purchid: "different") } let!(:different_purchid) { create(:sales_log, :duplicate, purchid: "different", owning_organisation: organisation) }
it "does not return a log with a different purchid as a duplicate" do it "does not return a log with a different purchid as a duplicate" do
expect(described_class.duplicate_logs(log)).not_to include(different_purchid) expect(described_class.duplicate_logs(log)).not_to include(different_purchid)
@ -225,7 +226,7 @@ RSpec.describe SalesLog, type: :model do
end end
context "when there is a log with a different postcode_full" do context "when there is a log with a different postcode_full" do
let!(:different_postcode_full) { create(:sales_log, :duplicate, postcode_full: "B1 1AA") } let!(:different_postcode_full) { create(:sales_log, :duplicate, postcode_full: "B1 1AA", owning_organisation: organisation) }
it "does not return a log with a different postcode_full as a duplicate" do it "does not return a log with a different postcode_full as a duplicate" do
expect(described_class.duplicate_logs(log)).not_to include(different_postcode_full) expect(described_class.duplicate_logs(log)).not_to include(different_postcode_full)
@ -233,7 +234,7 @@ RSpec.describe SalesLog, type: :model do
end end
context "when there is a log with nil values for duplicate check fields" do context "when there is a log with nil values for duplicate check fields" do
let!(:duplicate_check_fields_not_given) { create(:sales_log, :duplicate, age1: nil, sex1: nil, ecstat1: nil, pcodenk: 1, postcode_full: nil) } let!(:duplicate_check_fields_not_given) { create(:sales_log, :duplicate, age1: nil, sex1: nil, ecstat1: nil, pcodenk: 1, postcode_full: nil, owning_organisation: organisation) }
it "does not return a log with nil values as a duplicate" do it "does not return a log with nil values as a duplicate" do
log.update!(age1: nil, sex1: nil, ecstat1: nil, pcodenk: 1, postcode_full: nil) log.update!(age1: nil, sex1: nil, ecstat1: nil, pcodenk: 1, postcode_full: nil)
@ -242,7 +243,7 @@ RSpec.describe SalesLog, type: :model do
end end
context "when there is a log with nil values for purchid" do context "when there is a log with nil values for purchid" do
let!(:purchid_not_given) { create(:sales_log, :duplicate, purchid: nil) } let!(:purchid_not_given) { create(:sales_log, :duplicate, purchid: nil, owning_organisation: organisation) }
it "returns the log as a duplicate if purchid is nil" do it "returns the log as a duplicate if purchid is nil" do
log.update!(purchid: nil) log.update!(purchid: nil)
@ -251,7 +252,7 @@ RSpec.describe SalesLog, type: :model do
end end
context "when there is a log age not known" do context "when there is a log age not known" do
let!(:age1_not_known) { create(:sales_log, :duplicate, age1_known: 1, age1: nil) } let!(:age1_not_known) { create(:sales_log, :duplicate, age1_known: 1, age1: nil, owning_organisation: organisation) }
it "returns the log as a duplicate if age is not known" do it "returns the log as a duplicate if age is not known" do
log.update!(age1_known: 1, age1: nil) log.update!(age1_known: 1, age1: nil)
@ -260,7 +261,7 @@ RSpec.describe SalesLog, type: :model do
end end
context "when there is a log age pefers not to say" do context "when there is a log age pefers not to say" do
let!(:age1_prefers_not_to_say) { create(:sales_log, :duplicate, age1_known: 2, age1: nil) } let!(:age1_prefers_not_to_say) { create(:sales_log, :duplicate, age1_known: 2, age1: nil, owning_organisation: organisation) }
it "returns the log as a duplicate if age is prefers not to say" do it "returns the log as a duplicate if age is prefers not to say" do
log.update!(age1_known: 2, age1: nil) log.update!(age1_known: 2, age1: nil)
@ -269,7 +270,7 @@ RSpec.describe SalesLog, type: :model do
end end
context "when there is a log age pefers not to say and not known" do context "when there is a log age pefers not to say and not known" do
let!(:age1_prefers_not_to_say) { create(:sales_log, :duplicate, age1_known: 2, age1: nil) } let!(:age1_prefers_not_to_say) { create(:sales_log, :duplicate, age1_known: 2, age1: nil, owning_organisation: organisation) }
it "does not return the log as a duplicate if age is prefers not to say" do it "does not return the log as a duplicate if age is prefers not to say" do
log.update!(age1_known: 1, age1: nil) log.update!(age1_known: 1, age1: nil)

256
spec/models/validations/setup_validations_spec.rb

@ -128,6 +128,186 @@ RSpec.describe Validations::SetupValidations do
end end
end end
end end
context "when organisations were merged" do
around do |example|
Timecop.freeze(Time.zone.local(2023, 5, 1))
example.run
Timecop.return
end
let(:absorbing_organisation) { create(:organisation, created_at: Time.zone.local(2023, 2, 1, 4, 5, 6), name: "Absorbing org") }
let(:absorbing_organisation_2) { create(:organisation, created_at: Time.zone.local(2023, 2, 1), name: "Absorbing org 2") }
let(:merged_organisation) { create(:organisation, name: "Merged org") }
let(:merged_organisation_2) { create(:organisation, name: "Merged org 2") }
before do
merged_organisation.update!(absorbing_organisation:, merge_date: Time.zone.local(2023, 2, 2))
merged_organisation_2.update!(absorbing_organisation:, merge_date: Time.zone.local(2023, 2, 2))
end
context "and owning organisation is no longer active" do
it "does not allow startate after organisation has been merged" do
record.startdate = Time.zone.local(2023, 3, 1)
record.owning_organisation_id = merged_organisation.id
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to include(match "Enter a date when the owning organisation was active. Merged org became inactive on 2 February 2023 and was replaced by Absorbing org.")
end
it "allows startate before organisation has been merged" do
record.startdate = Time.zone.local(2023, 1, 1)
record.owning_organisation_id = merged_organisation.id
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to be_empty
end
end
context "and owning organisation is not yet active during the startdate" do
it "does not allow startate before absorbing organisation has been created" do
record.startdate = Time.zone.local(2023, 1, 1)
record.owning_organisation_id = absorbing_organisation.id
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to include(match "Enter a date when the owning organisation was active. Absorbing org became active on 1 February 2023.")
end
it "allows startate after absorbing organisation has been created" do
record.startdate = Time.zone.local(2023, 2, 2)
record.owning_organisation_id = absorbing_organisation.id
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to be_empty
end
end
context "and managing organisation is no longer active during the startdate" do
it "does not allow startate after organisation has been merged" do
record.startdate = Time.zone.local(2023, 3, 1)
record.managing_organisation_id = merged_organisation.id
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to include(match "Enter a date when the managing organisation was active. Merged org became inactive on 2 February 2023 and was replaced by Absorbing org.")
end
it "allows startate before organisation has been merged" do
record.startdate = Time.zone.local(2023, 1, 1)
record.managing_organisation_id = merged_organisation.id
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to be_empty
end
end
context "and managing organisation is not yet active during the startdate" do
it "does not allow startate before absorbing organisation has been created" do
record.startdate = Time.zone.local(2023, 1, 1)
record.managing_organisation_id = absorbing_organisation.id
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to include(match "Enter a date when the managing organisation was active. Absorbing org became active on 1 February 2023.")
end
it "allows startate after absorbing organisation has been created" do
record.startdate = Time.zone.local(2023, 2, 2)
record.managing_organisation_id = absorbing_organisation.id
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to be_empty
end
end
context "and owning and managing organisation is no longer active during the startdate" do
it "does not allow startate after organisation has been merged" do
record.startdate = Time.zone.local(2023, 3, 1)
record.managing_organisation_id = merged_organisation.id
record.owning_organisation_id = merged_organisation.id
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to include(match "Enter a date when the owning and managing organisation was active. Merged org became inactive on 2 February 2023 and was replaced by Absorbing org.")
end
it "allows startate before organisation has been merged" do
record.startdate = Time.zone.local(2023, 1, 1)
record.managing_organisation_id = merged_organisation.id
record.owning_organisation_id = merged_organisation.id
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to be_empty
end
end
context "and owning and managing organisation is not yet active during the startdate" do
it "does not allow startate before absorbing organisation has been created" do
record.startdate = Time.zone.local(2023, 1, 1)
record.managing_organisation_id = absorbing_organisation.id
record.owning_organisation_id = absorbing_organisation.id
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to include(match "Enter a date when the owning and managing organisation was active. Absorbing org became active on 1 February 2023.")
end
it "allows startate after absorbing organisation has been created" do
record.startdate = Time.zone.local(2023, 2, 1)
record.managing_organisation_id = absorbing_organisation.id
record.owning_organisation_id = absorbing_organisation.id
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to be_empty
end
end
context "and owning and managing organisations are no longer active during the startdate" do
it "does not allow startate after organisation have been merged" do
record.startdate = Time.zone.local(2023, 2, 2)
record.managing_organisation_id = merged_organisation.id
record.owning_organisation_id = merged_organisation_2.id
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to include(match "Enter a date when the owning and managing organisations were active. Merged org 2 and Merged org became inactive on 2 February 2023 and were replaced by Absorbing org.")
end
it "allows startate before organisations have been merged" do
record.startdate = Time.zone.local(2023, 1, 1)
record.managing_organisation_id = merged_organisation.id
record.owning_organisation_id = merged_organisation_2.id
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to be_empty
end
end
context "and owning and managing organisations are from different merges and no longer active during the startdate" do
before do
merged_organisation_2.update!(absorbing_organisation: absorbing_organisation_2, merge_date: Time.zone.local(2023, 2, 2))
end
it "does not allow startate after organisations have been merged" do
record.startdate = Time.zone.local(2023, 3, 1)
record.managing_organisation_id = merged_organisation.id
record.owning_organisation_id = merged_organisation_2.id
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to include(match "Enter a date when the owning and managing organisations were active. Merged org 2 became inactive on 2 February 2023 and was replaced by Absorbing org 2. Merged org became inactive on 2 February 2023 and was replaced by Absorbing org.")
end
it "allows startate before organisations have been merged" do
record.startdate = Time.zone.local(2023, 1, 1)
record.managing_organisation_id = merged_organisation.id
record.owning_organisation_id = merged_organisation_2.id
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to be_empty
end
end
context "and owning and managing organisation have different merges and are not yet active during the startdate" do
before do
merged_organisation_2.update!(absorbing_organisation: absorbing_organisation_2, merge_date: Time.zone.local(2023, 2, 2))
end
it "does not allow startate before absorbing organisation has been created" do
record.startdate = Time.zone.local(2023, 1, 1)
record.managing_organisation_id = absorbing_organisation.id
record.owning_organisation_id = absorbing_organisation_2.id
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to include(match "Enter a date when the owning and managing organisations were active. Absorbing org 2 became active on 1 February 2023, and Absorbing org became active on 1 February 2023.")
end
it "allows startate after absorbing organisation has been created" do
record.startdate = Time.zone.local(2023, 2, 2)
record.managing_organisation_id = absorbing_organisation.id
record.owning_organisation_id = absorbing_organisation.id
setup_validator.validate_startdate_setup(record)
expect(record.errors["startdate"]).to be_empty
end
end
end
end end
describe "#validate_irproduct" do describe "#validate_irproduct" do
@ -521,6 +701,82 @@ RSpec.describe Validations::SetupValidations do
expect(record.errors["owning_organisation_id"]).to be_empty expect(record.errors["owning_organisation_id"]).to be_empty
expect(record.errors["managing_organisation_id"]).to be_empty expect(record.errors["managing_organisation_id"]).to be_empty
end end
context "when organisations are merged" do
let(:absorbing_organisation) { create(:organisation, created_at: Time.zone.local(2023, 2, 1, 4, 5, 6), name: "Absorbing org") }
let(:merged_organisation) { create(:organisation, name: "Merged org") }
around do |example|
Timecop.freeze(Time.zone.local(2023, 5, 1))
merged_organisation.update!(merge_date: Time.zone.local(2023, 2, 2), absorbing_organisation:)
example.run
Timecop.return
end
context "and owning organisation is no longer active" do
it "does not allow organisation that has been merged" do
record.startdate = Time.zone.local(2023, 3, 1)
record.owning_organisation_id = merged_organisation.id
setup_validator.validate_organisation(record)
expect(record.errors["owning_organisation_id"]).to include(match "The owning organisation must be active on the tenancy start date. Merged org became inactive on 2 February 2023 and was replaced by Absorbing org.")
end
it "allows organisation before it has been merged" do
record.startdate = Time.zone.local(2023, 1, 1)
record.owning_organisation_id = merged_organisation.id
setup_validator.validate_organisation(record)
expect(record.errors["owning_organisation_id"]).to be_empty
end
end
context "and owning organisation is not yet active during the startdate" do
it "does not allow absorbing organisation before it had been created" do
record.startdate = Time.zone.local(2023, 1, 1)
record.owning_organisation_id = absorbing_organisation.id
setup_validator.validate_organisation(record)
expect(record.errors["owning_organisation_id"]).to include(match "The owning organisation must be active on the tenancy start date. Absorbing org became active on 1 February 2023.")
end
it "allows absorbing organisation after it has been created" do
record.startdate = Time.zone.local(2023, 2, 2)
record.owning_organisation_id = absorbing_organisation.id
setup_validator.validate_organisation(record)
expect(record.errors["owning_organisation_id"]).to be_empty
end
end
context "when managing organisation is no longer active" do
it "does not allow organisation that has been merged" do
record.startdate = Time.zone.local(2023, 3, 1)
record.managing_organisation_id = merged_organisation.id
setup_validator.validate_organisation(record)
expect(record.errors["managing_organisation_id"]).to include(match "The managing organisation must be active on the tenancy start date. Merged org became inactive on 2 February 2023 and was replaced by Absorbing org.")
end
it "allows organisation before it has been merged" do
record.startdate = Time.zone.local(2023, 1, 1)
record.managing_organisation_id = merged_organisation.id
setup_validator.validate_organisation(record)
expect(record.errors["managing_organisation_id"]).to be_empty
end
end
context "when managing organisation is not yet active during the startdate" do
it "does not allow absorbing organisation before it had been created" do
record.startdate = Time.zone.local(2023, 1, 1)
record.managing_organisation_id = absorbing_organisation.id
setup_validator.validate_organisation(record)
expect(record.errors["managing_organisation_id"]).to include(match "The managing organisation must be active on the tenancy start date. Absorbing org became active on 1 February 2023.")
end
it "allows absorbing organisation after it has been created" do
record.startdate = Time.zone.local(2023, 2, 2)
record.managing_organisation_id = absorbing_organisation.id
setup_validator.validate_organisation(record)
expect(record.errors["managing_organisation_id"]).to be_empty
end
end
end
end end
describe "#validate_scheme_has_confirmed_locations_validation" do describe "#validate_scheme_has_confirmed_locations_validation" do

173
spec/requests/duplicate_logs_controller_spec.rb

@ -34,68 +34,131 @@ RSpec.describe DuplicateLogsController, type: :request do
sign_in user sign_in user
end end
context "with multiple duplicate lettings logs" do context "when viewing lettings logs duplicates" do
let(:duplicate_logs) { create_list(:lettings_log, 2, :completed) } context "when there are multiple duplicate logs" do
let(:duplicate_logs) { create_list(:lettings_log, 2, :completed) }
before do
allow(LettingsLog).to receive(:duplicate_logs).and_return(duplicate_logs) before do
get "/lettings-logs/#{lettings_log.id}/duplicate-logs?original_log_id=#{lettings_log.id}" allow(LettingsLog).to receive(:duplicate_logs).and_return(duplicate_logs)
end get "/lettings-logs/#{lettings_log.id}/duplicate-logs?original_log_id=#{lettings_log.id}"
end
it "displays links to all the duplicate logs" do
expect(page).to have_link("Log #{lettings_log.id}", href: "/lettings-logs/#{lettings_log.id}") it "displays links to all the duplicate logs" do
expect(page).to have_link("Log #{duplicate_logs.first.id}", href: "/lettings-logs/#{duplicate_logs.first.id}") expect(page).to have_link("Log #{lettings_log.id}", href: "/lettings-logs/#{lettings_log.id}")
expect(page).to have_link("Log #{duplicate_logs.second.id}", href: "/lettings-logs/#{duplicate_logs.second.id}") expect(page).to have_link("Log #{duplicate_logs.first.id}", href: "/lettings-logs/#{duplicate_logs.first.id}")
end expect(page).to have_link("Log #{duplicate_logs.second.id}", href: "/lettings-logs/#{duplicate_logs.second.id}")
end
it "displays check your answers for each log with correct questions" do
expect(page).to have_content("Q5 - Tenancy start date", count: 3) it "displays check your answers for each log with correct questions" do
expect(page).to have_content("Q7 - Tenant code", count: 3) expect(page).to have_content("Q5 - Tenancy start date", count: 3)
expect(page).to have_content("Q12 - Postcode", count: 3) expect(page).to have_content("Q7 - Tenant code", count: 3)
expect(page).to have_content("Q32 - Lead tenant’s age", count: 3) expect(page).to have_content("Q12 - Postcode", count: 3)
expect(page).to have_content("Q33 - Lead tenant’s gender identity", count: 3) expect(page).to have_content("Q32 - Lead tenant’s age", count: 3)
expect(page).to have_content("Q37 - Lead tenant’s working situation", count: 3) expect(page).to have_content("Q33 - Lead tenant’s gender identity", count: 3)
expect(page).to have_content("Household rent and charges", count: 3) expect(page).to have_content("Q37 - Lead tenant’s working situation", count: 3)
expect(page).to have_link("Change", count: 21) expect(page).to have_content("Household rent and charges", count: 3)
expect(page).to have_link("Change", count: 21)
expect(page).to have_link("Change", href: "/lettings-logs/#{lettings_log.id}/tenant-code?first_remaining_duplicate_id=#{duplicate_logs[0].id}&original_log_id=#{lettings_log.id}&referrer=duplicate_logs")
expect(page).to have_link("Change", href: "/lettings-logs/#{duplicate_logs[0].id}/tenant-code?first_remaining_duplicate_id=#{lettings_log.id}&original_log_id=#{lettings_log.id}&referrer=duplicate_logs")
expect(page).to have_link("Change", href: "/lettings-logs/#{duplicate_logs[1].id}/tenant-code?first_remaining_duplicate_id=#{lettings_log.id}&original_log_id=#{lettings_log.id}&referrer=duplicate_logs")
end
it "displays buttons to delete" do
expect(page).to have_link("Keep this log and delete duplicates", count: 3)
expect(page).to have_link("Keep this log and delete duplicates", href: "/lettings-logs/#{lettings_log.id}/delete-duplicates?original_log_id=#{lettings_log.id}")
expect(page).to have_link("Keep this log and delete duplicates", href: "/lettings-logs/#{duplicate_logs.first.id}/delete-duplicates?original_log_id=#{lettings_log.id}")
expect(page).to have_link("Keep this log and delete duplicates", href: "/lettings-logs/#{duplicate_logs.second.id}/delete-duplicates?original_log_id=#{lettings_log.id}")
end
end end
it "displays buttons to delete" do context "when there are no more duplicate logs" do
expect(page).to have_link("Keep this log and delete duplicates", count: 3) before do
expect(page).to have_link("Keep this log and delete duplicates", href: "/lettings-logs/#{lettings_log.id}/delete-duplicates?original_log_id=#{lettings_log.id}") allow(LettingsLog).to receive(:duplicate_logs).and_return(LettingsLog.none)
expect(page).to have_link("Keep this log and delete duplicates", href: "/lettings-logs/#{duplicate_logs.first.id}/delete-duplicates?original_log_id=#{lettings_log.id}") get "/lettings-logs/#{lettings_log.id}/duplicate-logs?original_log_id=#{lettings_log.id}"
expect(page).to have_link("Keep this log and delete duplicates", href: "/lettings-logs/#{duplicate_logs.second.id}/delete-duplicates?original_log_id=#{lettings_log.id}") end
it "displays check your answers for each log with correct questions" do
expect(page).to have_content("Q5 - Tenancy start date", count: 1)
expect(page).to have_content("Q7 - Tenant code", count: 1)
expect(page).to have_content("Q12 - Postcode", count: 1)
expect(page).to have_content("Q32 - Lead tenant’s age", count: 1)
expect(page).to have_content("Q33 - Lead tenant’s gender identity", count: 1)
expect(page).to have_content("Q37 - Lead tenant’s working situation", count: 1)
expect(page).to have_content("Household rent and charges", count: 1)
expect(page).to have_link("Change", count: 7)
expect(page).to have_link("Change", href: "/lettings-logs/#{lettings_log.id}/tenant-code?original_log_id=#{lettings_log.id}&referrer=interruption_screen")
end
it "displays buttons to return to log" do
expect(page).to have_link("Back to Log #{lettings_log.id}", href: "/lettings-logs/#{lettings_log.id}")
end
it "displays no duplicates banner" do
expect(page).to have_content("This log had the same answers but it is no longer a duplicate. Make sure the answers are correct.")
end
end end
end end
context "with multiple duplicate sales logs" do context "when viewing sales logs duplicates" do
let(:duplicate_logs) { create_list(:sales_log, 2, :completed) } context "when there are multiple duplicate logs" do
let(:duplicate_logs) { create_list(:sales_log, 2, :completed) }
before do
allow(SalesLog).to receive(:duplicate_logs).and_return(duplicate_logs) before do
get "/sales-logs/#{sales_log.id}/duplicate-logs?original_log_id=#{sales_log.id}" allow(SalesLog).to receive(:duplicate_logs).and_return(duplicate_logs)
end get "/sales-logs/#{sales_log.id}/duplicate-logs?original_log_id=#{sales_log.id}"
end
it "displays links to all the duplicate logs" do
expect(page).to have_link("Log #{sales_log.id}", href: "/sales-logs/#{sales_log.id}") it "displays links to all the duplicate logs" do
expect(page).to have_link("Log #{duplicate_logs.first.id}", href: "/sales-logs/#{duplicate_logs.first.id}") expect(page).to have_link("Log #{sales_log.id}", href: "/sales-logs/#{sales_log.id}")
expect(page).to have_link("Log #{duplicate_logs.second.id}", href: "/sales-logs/#{duplicate_logs.second.id}") expect(page).to have_link("Log #{duplicate_logs.first.id}", href: "/sales-logs/#{duplicate_logs.first.id}")
end expect(page).to have_link("Log #{duplicate_logs.second.id}", href: "/sales-logs/#{duplicate_logs.second.id}")
end
it "displays check your answers for each log with correct questions" do
expect(page).to have_content("Q1 - Sale completion date", count: 3) it "displays check your answers for each log with correct questions" do
expect(page).to have_content("Q2 - Purchaser code", count: 3) expect(page).to have_content("Q1 - Sale completion date", count: 3)
expect(page).to have_content("Q20 - Lead buyer’s age", count: 3) expect(page).to have_content("Q2 - Purchaser code", count: 3)
expect(page).to have_content("Q21 - Buyer 1’s gender identity", count: 3) expect(page).to have_content("Q20 - Lead buyer’s age", count: 3)
expect(page).to have_content("Q25 - Buyer 1's working situation", count: 3) expect(page).to have_content("Q21 - Buyer 1’s gender identity", count: 3)
expect(page).to have_content("Q15 - Postcode", count: 3) expect(page).to have_content("Q25 - Buyer 1's working situation", count: 3)
expect(page).to have_link("Change", count: 18) expect(page).to have_content("Q15 - Postcode", count: 3)
expect(page).to have_link("Change", count: 18)
expect(page).to have_link("Change", href: "/sales-logs/#{sales_log.id}/purchaser-code?first_remaining_duplicate_id=#{duplicate_logs[0].id}&original_log_id=#{sales_log.id}&referrer=duplicate_logs")
expect(page).to have_link("Change", href: "/sales-logs/#{duplicate_logs[0].id}/purchaser-code?first_remaining_duplicate_id=#{sales_log.id}&original_log_id=#{sales_log.id}&referrer=duplicate_logs")
expect(page).to have_link("Change", href: "/sales-logs/#{duplicate_logs[1].id}/purchaser-code?first_remaining_duplicate_id=#{sales_log.id}&original_log_id=#{sales_log.id}&referrer=duplicate_logs")
end
it "displays buttons to delete" do
expect(page).to have_link("Keep this log and delete duplicates", count: 3)
expect(page).to have_link("Keep this log and delete duplicates", href: "/sales-logs/#{sales_log.id}/delete-duplicates?original_log_id=#{sales_log.id}")
expect(page).to have_link("Keep this log and delete duplicates", href: "/sales-logs/#{duplicate_logs.first.id}/delete-duplicates?original_log_id=#{sales_log.id}")
expect(page).to have_link("Keep this log and delete duplicates", href: "/sales-logs/#{duplicate_logs.second.id}/delete-duplicates?original_log_id=#{sales_log.id}")
end
end end
it "displays buttons to delete" do context "when there are no more duplicate logs" do
expect(page).to have_link("Keep this log and delete duplicates", count: 3) before do
expect(page).to have_link("Keep this log and delete duplicates", href: "/sales-logs/#{sales_log.id}/delete-duplicates?original_log_id=#{sales_log.id}") allow(SalesLog).to receive(:duplicate_logs).and_return(SalesLog.none)
expect(page).to have_link("Keep this log and delete duplicates", href: "/sales-logs/#{duplicate_logs.first.id}/delete-duplicates?original_log_id=#{sales_log.id}") get "/sales-logs/#{sales_log.id}/duplicate-logs?original_log_id=#{sales_log.id}"
expect(page).to have_link("Keep this log and delete duplicates", href: "/sales-logs/#{duplicate_logs.second.id}/delete-duplicates?original_log_id=#{sales_log.id}") end
it "displays check your answers for each log with correct questions" do
expect(page).to have_content("Q1 - Sale completion date", count: 1)
expect(page).to have_content("Q2 - Purchaser code", count: 1)
expect(page).to have_content("Q20 - Lead buyer’s age", count: 1)
expect(page).to have_content("Q21 - Buyer 1’s gender identity", count: 1)
expect(page).to have_content("Q25 - Buyer 1's working situation", count: 1)
expect(page).to have_content("Q15 - Postcode", count: 1)
expect(page).to have_link("Change", count: 6)
expect(page).to have_link("Change", href: "/sales-logs/#{sales_log.id}/purchaser-code?original_log_id=#{sales_log.id}&referrer=interruption_screen")
end
it "displays buttons to return to log" do
expect(page).to have_link("Back to Log #{sales_log.id}", href: "/sales-logs/#{sales_log.id}")
end
it "displays no duplicates banner" do
expect(page).to have_content("This log had the same answers but it is no longer a duplicate. Make sure the answers are correct.")
end
end end
end end
end end

82
spec/requests/form_controller_spec.rb

@ -732,6 +732,88 @@ RSpec.describe FormController, type: :request do
end end
end end
end end
context "when the question was accessed from a duplicate logs screen" do
let(:lettings_log) { create(:lettings_log, :duplicate, created_by: user) }
let(:duplicate_log) { create(:lettings_log, :duplicate, created_by: user) }
let(:referrer) { "/lettings-logs/#{lettings_log.id}/lead-tenant-age?referrer=duplicate_logs&first_remaining_duplicate_id=#{duplicate_log.id}&original_log_id=#{lettings_log.id}" }
let(:params) do
{
id: lettings_log.id,
lettings_log: {
page: "lead_tenant_age",
age1: 20,
age1_known: 1,
},
}
end
before do
post "/lettings-logs/#{lettings_log.id}/lead-tenant-age", params:, headers: headers.merge({ "HTTP_REFERER" => referrer })
end
it "redirects back to the duplicates page for remaining duplicates" do
expect(response).to redirect_to("/lettings-logs/#{duplicate_log.id}/duplicate-logs?original_log_id=#{lettings_log.id}")
end
context "and the answer didn't change" do
let(:params) do
{
id: lettings_log.id,
lettings_log: {
page: "lead_tenant_age",
age1: lettings_log.age1,
age1_known: lettings_log.age1_known,
},
}
end
it "redirects back to the duplicates page for remaining duplicates" do
expect(response).to have_http_status(:ok)
end
end
end
context "when the sales question was accessed from a duplicate logs screen" do
let(:sales_log) { create(:sales_log, :duplicate, created_by: user) }
let(:duplicate_log) { create(:sales_log, :duplicate, created_by: user) }
let(:referrer) { "/sales-logs/#{sales_log.id}/buyer-1-age?referrer=duplicate_logs&first_remaining_duplicate_id=#{duplicate_log.id}&original_log_id=#{sales_log.id}" }
let(:params) do
{
id: sales_log.id,
sales_log: {
page: "buyer_1_age",
age1: 20,
age1_known: 1,
},
}
end
before do
post "/sales-logs/#{sales_log.id}/buyer-1-age", params:, headers: headers.merge({ "HTTP_REFERER" => referrer })
end
it "redirects back to the duplicates page for remaining duplicates" do
expect(response).to redirect_to("/sales-logs/#{duplicate_log.id}/duplicate-logs?original_log_id=#{sales_log.id}")
end
context "and the answer didn't change" do
let(:params) do
{
id: sales_log.id,
sales_log: {
page: "buyer_1_age",
age1: sales_log.age1,
age1_known: sales_log.age1_known,
},
}
end
it "redirects back to the duplicates page for remaining duplicates" do
expect(response).to have_http_status(:ok)
end
end
end
end end
context "with checkbox questions" do context "with checkbox questions" do

8
spec/requests/sales_logs_controller_spec.rb

@ -354,8 +354,8 @@ RSpec.describe SalesLogsController, type: :request do
let(:user) { create(:user, organisation:) } let(:user) { create(:user, organisation:) }
let(:bulk_upload) { create(:bulk_upload, :sales, user:) } let(:bulk_upload) { create(:bulk_upload, :sales, user:) }
let!(:included_log) { create(:sales_log, :in_progress, bulk_upload:, owning_organisation: organisation) } let!(:included_log) { create(:sales_log, :in_progress, purchid: "included_id", bulk_upload:, owning_organisation: organisation) }
let!(:excluded_log) { create(:sales_log, :in_progress, owning_organisation: organisation) } let!(:excluded_log) { create(:sales_log, :in_progress, purchid: "excluded_id", owning_organisation: organisation) }
before do before do
create(:bulk_upload_error, bulk_upload:, col: "A", row: 1) create(:bulk_upload_error, bulk_upload:, col: "A", row: 1)
@ -364,8 +364,8 @@ RSpec.describe SalesLogsController, type: :request do
it "returns logs only associated with the bulk upload" do it "returns logs only associated with the bulk upload" do
get "/sales-logs?bulk_upload_id[]=#{bulk_upload.id}" get "/sales-logs?bulk_upload_id[]=#{bulk_upload.id}"
expect(page).to have_content(included_log.id) expect(page).to have_content(included_log.purchid)
expect(page).not_to have_content(excluded_log.id) expect(page).not_to have_content(excluded_log.purchid)
end end
it "dislays bulk upload banner" do it "dislays bulk upload banner" do

Loading…
Cancel
Save