diff --git a/app/models/form/sales/pages/managing_organisation.rb b/app/models/form/sales/pages/managing_organisation.rb new file mode 100644 index 000000000..0c9ed7337 --- /dev/null +++ b/app/models/form/sales/pages/managing_organisation.rb @@ -0,0 +1,21 @@ +class Form::Sales::Pages::ManagingOrganisation < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "managing_organisation" + end + + def questions + @questions ||= [ + Form::Sales::Questions::ManagingOrganisation.new(nil, nil, self), + ] + end + + def routed_to?(log, current_user) + return false unless current_user + return false unless current_user.support? + return false unless FeatureToggle.sales_managing_organisation_enabled? + return false unless log.owning_organisation + + log.owning_organisation.managing_agents.count >= 1 + end +end diff --git a/app/models/form/sales/questions/managing_organisation.rb b/app/models/form/sales/questions/managing_organisation.rb new file mode 100644 index 000000000..7fba0b131 --- /dev/null +++ b/app/models/form/sales/questions/managing_organisation.rb @@ -0,0 +1,78 @@ +class Form::Sales::Questions::ManagingOrganisation < ::Form::Question + def initialize(id, hsh, page) + super + @id = "managing_organisation_id" + @check_answer_label = "Reported by" + @header = "Which organisation is reporting this sales log?" + @type = "select" + @question_number = 2 + end + + def answer_options(log = nil, user = nil) + opts = { "" => "Select an option" } + + return opts unless ActiveRecord::Base.connected? + return opts unless user + return opts unless log + + if log.managing_organisation.present? + opts = opts.merge({ log.managing_organisation.id => log.managing_organisation.name }) + end + + if user.support? + if log.owning_organisation.holds_own_stock? + opts[log.owning_organisation.id] = "#{log.owning_organisation.name} (Owning organisation)" + end + elsif user.organisation.absorbed_organisations.exists? && user.organisation.available_from.present? + opts[user.organisation.id] = "#{user.organisation.name} (Your organisation, active as of #{user.organisation.available_from.to_fs(:govuk_date)})" + else + opts[user.organisation.id] = "#{user.organisation.name} (Your organisation)" + end + + orgs = if user.support? + log.owning_organisation.managing_agents + elsif user.organisation.absorbed_organisations.include?(log.owning_organisation) + user.organisation.managing_agents + log.owning_organisation.managing_agents + else + user.organisation.managing_agents + end.pluck(:id, :name).to_h + + user.organisation.absorbed_organisations.each do |absorbed_org| + opts[absorbed_org.id] = "#{absorbed_org.name} (inactive as of #{absorbed_org.merge_date.to_fs(:govuk_date)})" + end + + opts.merge(orgs) + end + + def displayed_answer_options(log, user) + answer_options(log, user) + end + + def label_from_value(value, _log = nil, _user = nil) + return unless value + + answer_options[value] + end + + def derived? + true + end + + def hidden_in_check_answers?(log, user = nil) + user.nil? || !user.support? || !@page.routed_to?(log, user) + end + + def enabled + true + end + + def answer_label(log, _current_user = nil) + Organisation.find_by(id: log.managing_organisation_id)&.name + end + +private + + def selected_answer_option_is_derived?(_log) + true + end +end diff --git a/app/models/form/sales/subsections/setup.rb b/app/models/form/sales/subsections/setup.rb index 1fbc2ac9e..67c160e52 100644 --- a/app/models/form/sales/subsections/setup.rb +++ b/app/models/form/sales/subsections/setup.rb @@ -8,6 +8,7 @@ class Form::Sales::Subsections::Setup < ::Form::Subsection def pages @pages ||= [ Form::Sales::Pages::Organisation.new(nil, nil, self), + Form::Sales::Pages::ManagingOrganisation.new(nil, nil, self), Form::Sales::Pages::CreatedBy.new(nil, nil, self), Form::Sales::Pages::SaleDate.new(nil, nil, self), Form::Sales::Pages::PurchaserCode.new(nil, nil, self), diff --git a/spec/models/form/sales/pages/managing_organisation_spec.rb b/spec/models/form/sales/pages/managing_organisation_spec.rb new file mode 100644 index 000000000..0a34554cb --- /dev/null +++ b/spec/models/form/sales/pages/managing_organisation_spec.rb @@ -0,0 +1,106 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Pages::ManagingOrganisation, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection) } + + let(:page_id) { nil } + let(:page_definition) { nil } + let(:subsection) { instance_double(Form::Subsection) } + let(:form) { instance_double(Form) } + + it "has correct subsection" do + expect(page.subsection).to eq(subsection) + end + + it "has correct questions" do + expect(page.questions.map(&:id)).to eq(%w[managing_organisation_id]) + end + + it "has the correct id" do + expect(page.id).to eq("managing_organisation") + end + + it "has the correct header" do + expect(page.header).to be_nil + end + + it "has the correct description" do + expect(page.description).to be_nil + end + + it "has the correct depends_on" do + expect(page.depends_on).to be nil + end + + describe "#routed_to?" do + let(:log) { create(:lettings_log) } + let(:organisation) { create(:organisation) } + + context "when user nil" do + it "is not shown" do + expect(page.routed_to?(log, nil)).to eq(false) + end + end + + context "when user is not support" do + let(:user) { create(:user) } + + it "is not shown" do + expect(page.routed_to?(log, nil)).to eq(false) + end + end + + context "when support" do + let(:user) { create(:user, :support) } + + context "when owning_organisation not set" do + let(:log) { create(:lettings_log, owning_organisation: nil) } + + it "is not shown" do + expect(page.routed_to?(log, user)).to eq(false) + end + end + + context "with 0 managing_agents" do + it "is not shown" do + expect(page.routed_to?(log, user)).to eq(false) + end + end + + context "with >1 managing_agents" do + before do + create(:organisation_relationship, parent_organisation: log.owning_organisation) + create(:organisation_relationship, parent_organisation: log.owning_organisation) + end + + it "is shown" do + expect(page.routed_to?(log, user)).to eq(true) + end + end + + context "with 1 managing_agents" do + let(:managing_agent) { create(:organisation) } + + before do + create( + :organisation_relationship, + child_organisation: managing_agent, + parent_organisation: log.owning_organisation, + ) + end + + it "is shown" do + expect(page.routed_to?(log, user)).to eq(true) + end + end + end + + context "when not support" do + let(:user) { create(:user, :data_coordinator, organisation: create(:organisation, holds_own_stock: false)) } + + it "is not shown" do + expect(page.routed_to?(log, user)).to eq(false) + end + end + end +end diff --git a/spec/models/form/sales/questions/managing_organisation_spec.rb b/spec/models/form/sales/questions/managing_organisation_spec.rb new file mode 100644 index 000000000..a6dd23d59 --- /dev/null +++ b/spec/models/form/sales/questions/managing_organisation_spec.rb @@ -0,0 +1,257 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Questions::ManagingOrganisation, type: :model do + subject(:question) { described_class.new(question_id, question_definition, page) } + + let(:question_id) { nil } + let(:question_definition) { nil } + let(:page) { instance_double(Form::Page) } + let(:subsection) { instance_double(Form::Subsection) } + let(:form) { instance_double(Form) } + + it "has correct page" do + expect(question.page).to eq(page) + end + + it "has the correct id" do + expect(question.id).to eq("managing_organisation_id") + end + + it "has the correct header" do + expect(question.header).to eq("Which organisation is reporting this sales log?") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to eq("Reported by") + end + + it "has the correct type" do + expect(question.type).to eq("select") + end + + it "has the correct hint_text" do + expect(question.hint_text).to be_nil + end + + describe "#displayed_answer_options" do + let(:options) { { "" => "Select an option" } } + + context "when current_user nil" do + let(:log) { create(:lettings_log) } + + it "shows default options" do + expect(question.displayed_answer_options(log, nil)).to eq(options) + end + end + + context "when log nil" do + let(:user) { create(:user) } + + it "shows default options" do + expect(question.displayed_answer_options(nil, user)).to eq(options) + end + end + + context "when user is support" do + let(:user) { create(:user, :support) } + let(:log_owning_org) { create(:organisation, name: "Owning org") } + + let(:managing_org1) { create(:organisation, name: "Managing org 1") } + let(:managing_org2) { create(:organisation, name: "Managing org 2") } + let(:managing_org3) { create(:organisation, name: "Managing org 3") } + + let(:log) do + create(:lettings_log, owning_organisation: log_owning_org, managing_organisation: managing_org1, + created_by: nil) + end + let!(:org_rel1) do + create(:organisation_relationship, parent_organisation: log_owning_org, child_organisation: managing_org2) + end + let!(:org_rel2) do + create(:organisation_relationship, parent_organisation: log_owning_org, child_organisation: managing_org3) + end + + context "when org owns stock" do + let(:options) do + { + "" => "Select an option", + log.managing_organisation.id => "Managing org 1", + log_owning_org.id => "Owning org (Owning organisation)", + org_rel1.child_organisation.id => "Managing org 2", + org_rel2.child_organisation.id => "Managing org 3", + } + end + + it "shows current managing agent at top, followed by the current owning organisation (with hint), followed by the managing agents of the current owning organisation" do + log_owning_org.update!(holds_own_stock: true) + expect(question.displayed_answer_options(log, user)).to eq(options) + end + end + + context "when org does not own stock" do + let(:options) do + { + "" => "Select an option", + log.managing_organisation.id => "Managing org 1", + org_rel1.child_organisation.id => "Managing org 2", + org_rel2.child_organisation.id => "Managing org 3", + } + end + + it "shows current managing agent at top, followed by the managing agents of the current owning organisation" do + log_owning_org.update!(holds_own_stock: false) + expect(question.displayed_answer_options(log, user)).to eq(options) + end + end + end + + context "when the owning-managing organisation relationship is deleted" do + let(:user) { create(:user, :support) } + + let(:owning_org) { create(:organisation, name: "Owning org", holds_own_stock: true) } + let(:managing_org) { create(:organisation, name: "Managing org", holds_own_stock: false) } + let(:org_rel) do + create(:organisation_relationship, parent_organisation: owning_org, child_organisation: managing_org) + end + let(:log) do + create(:lettings_log, owning_organisation: owning_org, managing_organisation: managing_org, created_by: nil) + end + + let(:options) do + { + "" => "Select an option", + owning_org.id => "Owning org (Owning organisation)", + managing_org.id => "Managing org", + } + end + + it "doesn't remove the managing org from the list of allowed managing orgs" do + org_rel.destroy! + expect(question.displayed_answer_options(log, user)).to eq(options) + end + end + + context "when organisation has merged" do + let(:absorbing_org) { create(:organisation, name: "Absorbing org", holds_own_stock: true) } + let!(:merged_org) { create(:organisation, name: "Merged org", holds_own_stock: false) } + let(:user) { create(:user, :support, organisation: absorbing_org) } + + let(:log) do + merged_org.update!(merge_date: Time.zone.local(2023, 8, 2), absorbing_organisation_id: absorbing_org.id) + create(:lettings_log, owning_organisation: absorbing_org, managing_organisation: nil) + end + + it "displays merged organisation on the list of choices" do + options = { + "" => "Select an option", + absorbing_org.id => "Absorbing org (Owning organisation)", + merged_org.id => "Merged org (inactive as of 2 August 2023)", + merged_org.id => "Merged org (inactive as of 2 August 2023)", + } + expect(question.displayed_answer_options(log, user)).to eq(options) + end + + it "displays active date for absorbing organisation if available from is given" do + absorbing_org.update!(available_from: Time.zone.local(2023, 8, 3)) + options = { + "" => "Select an option", + absorbing_org.id => "Absorbing org (Owning organisation)", + merged_org.id => "Merged org (inactive as of 2 August 2023)", + merged_org.id => "Merged org (inactive as of 2 August 2023)", + } + expect(question.displayed_answer_options(log, user)).to eq(options) + end + + it "displays managing agents of merged organisation selected as owning org" do + managing_agent = create(:organisation, name: "Managing org 1") + create(:organisation_relationship, parent_organisation: merged_org, child_organisation: managing_agent) + + options = { + "" => "Select an option", + merged_org.id => "Merged org (inactive as of 2 August 2023)", + managing_agent.id => "Managing org 1", + } + + log.update!(owning_organisation: merged_org) + expect(question.displayed_answer_options(log, user)).to eq(options) + end + end + end + + it "is marked as derived" do + expect(question.derived?).to be true + end + + describe "#hidden_in_check_answers?" do + before do + allow(page).to receive(:routed_to?).and_return(true) + end + + context "when user is non support" do + let(:user) { create(:user) } + + it "is hidden in check answers" do + expect(question.hidden_in_check_answers?(nil, user)).to be true + end + end + + context "when user is support" do + let(:user) { create(:user, :support) } + + it "is not hidden in check answers" do + expect(question.hidden_in_check_answers?(nil, user)).to be false + end + end + + context "when user not provided" do + it "is hidden in check answers" do + expect(question.hidden_in_check_answers?(nil)).to be true + end + end + + context "when the page is not routed to" do + let(:user) { create(:user, :data_coordinator, organisation: create(:organisation, holds_own_stock: true)) } + let(:log) { create(:lettings_log, owning_organisation: user.organisation) } + + before do + allow(page).to receive(:routed_to?).and_return(false) + end + + it "is hidden in check answers" do + expect(question.hidden_in_check_answers?(log, user)).to be true + end + end + end + + describe "#answer_label" do + context "when answered" do + let(:managing_organisation) { create(:organisation) } + let(:log) { create(:lettings_log, managing_organisation:) } + + it "returns org name" do + expect(question.answer_label(log)).to eq(managing_organisation.name) + end + end + + context "when unanswered" do + let(:log) { create(:lettings_log, managing_organisation: nil) } + + it "returns nil" do + expect(question.answer_label(log)).to be_nil + end + end + + context "when org does not exist" do + let(:managing_organisation) { create(:organisation) } + let(:log) { create(:lettings_log, managing_organisation:) } + + before do + allow(Organisation).to receive(:find_by).and_return(nil) + end + + it "returns nil" do + expect(question.answer_label(log)).to be_nil + end + end + end +end diff --git a/spec/models/form/sales/subsections/setup_spec.rb b/spec/models/form/sales/subsections/setup_spec.rb index 7a71e946c..71bff2e32 100644 --- a/spec/models/form/sales/subsections/setup_spec.rb +++ b/spec/models/form/sales/subsections/setup_spec.rb @@ -16,6 +16,7 @@ RSpec.describe Form::Sales::Subsections::Setup, type: :model do expect(setup.pages.map(&:id)).to eq( %w[ organisation + managing_organisation created_by completion_date purchaser_code