diff --git a/app/presenters/homepage_presenter.rb b/app/presenters/homepage_presenter.rb new file mode 100644 index 000000000..e05045e23 --- /dev/null +++ b/app/presenters/homepage_presenter.rb @@ -0,0 +1,110 @@ +class HomepagePresenter + include Rails.application.routes.url_helpers + + attr_reader :current_year_in_progress_lettings_data, :current_year_completed_lettings_data, :current_year_in_progress_sales_data, :current_year_completed_sales_data, :last_year_in_progress_lettings_data, :last_year_completed_lettings_data, :last_year_in_progress_sales_data, :last_year_completed_sales_data, :incomplete_schemes_data + + def initialize(user) + @user = user + @organisation_logs_sales = organisation_has_ever_logged_sales? + @in_crossover_period = FormHandler.instance.in_crossover_period? + @current_year = FormHandler.instance.current_lettings_form.start_date.year + @current_year_in_progress_lettings_data = data_box_data(:lettings, @current_year, :in_progress) + @current_year_completed_lettings_data = data_box_data(:lettings, @current_year, :completed) + @current_year_in_progress_sales_data = data_box_data(:sales, @current_year, :in_progress) if organisation_logs_sales? + @current_year_completed_sales_data = data_box_data(:sales, @current_year, :completed) if organisation_logs_sales? + @last_year = @current_year - 1 + @last_year_in_progress_lettings_data = data_box_data(:lettings, @last_year, :in_progress) if in_crossover_period? + @last_year_completed_lettings_data = data_box_data(:lettings, @last_year, :completed) + @last_year_in_progress_sales_data = data_box_data(:sales, @last_year, :in_progress) if in_crossover_period? && organisation_logs_sales? + @last_year_completed_sales_data = data_box_data(:sales, @last_year, :completed) if organisation_logs_sales? + if display_schemes? + @incomplete_schemes_data = { + count: @user.schemes.incomplete.count, + text: data_box_text(type: :schemes, status: :incomplete), + path: schemes_path(status: [:incomplete], owning_organisation_select: "all"), + } + end + end + + def title_text_for_user + if @user.support? + "Manage all data" + elsif @user.data_coordinator? + "Manage your organisation's logs" + else + "Manage logs assigned to you" + end + end + + def organisation_logs_sales? + @organisation_logs_sales + end + + def in_crossover_period? + @in_crossover_period + end + + def subheading_for_current_year + subheading_from_year @current_year + end + + def subheading_for_last_year + subheading = subheading_from_year @last_year + in_crossover_period? ? subheading : "#{subheading} (Closed collection year)" + end + + def display_schemes? + !@user.data_provider? + end + +private + + def subheading_from_year(year) + return "AAAAH" if year.nil? + + "#{year} to #{year + 1} Logs" + end + + def data_box_data(type, year, status) + { + count: logs_count(type:, year:, status:), + text: data_box_text(type:, status:), + path: logs_link(type:, year:, status:), + } + end + + def data_box_text(type:, status:) + text = [status, type] + text.reverse! if status == :in_progress + text.join(" ").humanize + end + + def logs_link(type:, year:, status:) + params = { + status: [status], + years: [year], + assigned_to: @user.data_provider? ? "you" : "all", + owning_organisation_select: "all", + managing_organisation_select: "all", + } + case type + when :lettings then lettings_logs_path(params) + when :sales then sales_logs_path(params) + end + end + + def logs_count(type:, year:, status:) + query = case type + when :lettings then @user.lettings_logs + when :sales then @user.sales_logs + end + query = query.where(created_by: @user) if @user.data_provider? + query.filter_by_year(year) + .where(status:) + .count + end + + def organisation_has_ever_logged_sales? + @user.organisation.sales_logs.exists? + end +end diff --git a/spec/factories/lettings_log.rb b/spec/factories/lettings_log.rb index ebf94230e..9136dc0dc 100644 --- a/spec/factories/lettings_log.rb +++ b/spec/factories/lettings_log.rb @@ -87,7 +87,7 @@ FactoryBot.define do rsnvac { 6 } unittype_gn { 7 } beds { 3 } - voiddate { 2.days.ago } + voiddate { startdate - 2.days } offered { 2 } wchair { 1 } earnings { 268 } @@ -154,7 +154,7 @@ FactoryBot.define do hbrentshortfall { 1 } tshortfall { 12 } property_relet { 0 } - mrcdate { 1.day.ago } + mrcdate { startdate - 1.day } incref { 0 } armedforces { 1 } builtype { 1 } @@ -171,6 +171,14 @@ FactoryBot.define do ppcodenk { 1 } tshortfall_known { 1 } end + trait :completed2024 do + completed + address_line1_input { address_line1 } + postcode_full_input { postcode_full } + nationality_all_group { 826 } + uprn { 1 } + uprn_selection { 1 } + end trait :export do tenancycode { "987654" } ppostcode_full { "LE5 1QP" } diff --git a/spec/factories/sales_log.rb b/spec/factories/sales_log.rb index f0cea588f..94347c6f1 100644 --- a/spec/factories/sales_log.rb +++ b/spec/factories/sales_log.rb @@ -154,6 +154,15 @@ FactoryBot.define do buy2living { 3 } proplen_asked { 1 } end + trait :completed2024 do + completed + address_line1_input { address_line1 } + postcode_full_input { postcode_full } + nationality_all_group { 826 } + nationality_all_buyer2_group { 826 } + uprn { 1 } + uprn_selection { 1 } + end trait :with_uprn do uprn { rand(999_999_999_999).to_s } uprn_known { 1 } diff --git a/spec/factories/user.rb b/spec/factories/user.rb index 935bd30f6..f898c5504 100644 --- a/spec/factories/user.rb +++ b/spec/factories/user.rb @@ -1,9 +1,9 @@ FactoryBot.define do factory :user do - sequence(:email) { |i| "test#{i}@example.com" } + sequence(:email) { "test#{SecureRandom.hex}@example.com" } name { "Danny Rojas" } password { "pAssword1" } - organisation + organisation { association :organisation } role { "data_provider" } phone { "1234512345123" } trait :data_coordinator do diff --git a/spec/presenters/homepage_presenter_spec.rb b/spec/presenters/homepage_presenter_spec.rb new file mode 100644 index 000000000..7d1be7e0c --- /dev/null +++ b/spec/presenters/homepage_presenter_spec.rb @@ -0,0 +1,309 @@ +require "rails_helper" + +RSpec.describe HomepagePresenter do + let(:organisation) { create(:organisation) } + let(:user) { create(:user, organisation:) } + let(:in_crossover_period) { true } + let(:presenter) { described_class.new(user) } + let(:date_this_year) { Time.zone.today } + let(:date_last_year) { Time.zone.today - 1.year } + let(:expected_count) { rand 1..10 } + + before do + allow(FormHandler.instance).to receive(:in_crossover_period?).and_return(in_crossover_period) + end + + context "when the user is support" do + let(:user) { create(:user, :support) } + + it "sets the correct title" do + expect(presenter.title_text_for_user).to eq "Manage all data" + end + + it "returns that schemes should be displayed" do + expect(presenter.display_schemes?).to be true + end + end + + context "when the user is a data coordinator" do + let(:user) { create(:user, :data_coordinator) } + + it "sets the correct title" do + expect(presenter.title_text_for_user).to eq "Manage your organisation's logs" + end + + it "returns that schemes should be displayed" do + expect(presenter.display_schemes?).to be true + end + end + + context "when the user is a data provider" do + let(:user) { create(:user, :data_provider) } + + it "sets the correct title" do + expect(presenter.title_text_for_user).to eq "Manage logs assigned to you" + end + + it "returns that schemes should not be displayed" do + expect(presenter.display_schemes?).to be false + end + end + + context "when the user's organisation has never submitted sales logs" do + it "shows the user's organisation does not log sales" do + expect(presenter.organisation_logs_sales?).to be false + end + + context "when in the crossover period" do + let(:in_crossover_period) { true } + + it "leaves all sales related data as nil" do + sales_data = [ + presenter.current_year_in_progress_sales_data, + presenter.current_year_completed_sales_data, + presenter.last_year_in_progress_sales_data, + presenter.last_year_completed_sales_data, + ] + expect(sales_data).to all be nil + end + end + + context "when not in the crossover period" do + let(:in_crossover_period) { false } + + it "leaves all sales related data as nil" do + sales_data = [ + presenter.current_year_in_progress_sales_data, + presenter.current_year_completed_sales_data, + presenter.last_year_in_progress_sales_data, + presenter.last_year_completed_sales_data, + ] + expect(sales_data).to all be nil + end + end + end + + context "when the user's organisation has submitted sales logs" do + before do + create(:sales_log, created_by: user) + end + + it "shows the user's organisation logs sales" do + expect(presenter.organisation_logs_sales?).to be true + end + + context "when in the crossover period" do + let(:in_crossover_period) { true } + + it "populates all sales related data" do + sales_data = [ + presenter.current_year_in_progress_sales_data, + presenter.current_year_completed_sales_data, + presenter.last_year_in_progress_sales_data, + presenter.last_year_completed_sales_data, + ] + expect(sales_data).to all be_an_instance_of(Hash) + end + end + + context "when not in the crossover period" do + let(:in_crossover_period) { false } + + it "populates all relevant sales related data" do + sales_data = [ + presenter.current_year_in_progress_sales_data, + presenter.current_year_completed_sales_data, + presenter.last_year_completed_sales_data, + ] + expect(sales_data).to all be_an_instance_of(Hash) + end + + it "does not populate data for last year's in progress logs" do + last_year_in_progress_data = [ + presenter.last_year_in_progress_lettings_data, + presenter.last_year_in_progress_sales_data, + ] + expect(last_year_in_progress_data).to all be nil + end + end + end + + context "when in the crossover period" do + let(:in_crossover_period) { true } + + it "returns that we are in the crossover period" do + expect(presenter.in_crossover_period?).to be true + end + end + + context "when not in the crossover period" do + let(:in_crossover_period) { false } + + it "returns that we are in the crossover period" do + expect(presenter.in_crossover_period?).to be false + end + end + + context "when testing the data collected and exposed by the presenter" do + context "with lettings logs" do + let(:type) { :lettings_log } + + context "with in progress status" do + let(:status) { :in_progress } + + context "and the current year" do + let(:startdate) { date_this_year } + + it "exposes the correct data for the data box" do + create_list(type, expected_count, status, created_by: user, startdate:) + data = presenter.current_year_in_progress_lettings_data + + expect(data[:count]).to be expected_count + expect(data[:text]).to eq "Lettings in progress" + uri = URI.parse(data[:path]) + expect(uri.path).to eq "/#{type.to_s.dasherize}s" + query_params = CGI.parse(uri.query) + expect(query_params["status[]"]).to eq [status.to_s] + expect(query_params["years[]"]).to eq [date_this_year.year.to_s] + end + end + + context "and the last year" do + let(:startdate) { date_last_year } + + it "exposes the correct data for the data box" do + create_list(type, expected_count, status, created_by: user, startdate:) + data = presenter.last_year_in_progress_lettings_data + + expect(data[:count]).to be expected_count + expect(data[:text]).to eq "Lettings in progress" + uri = URI.parse(data[:path]) + expect(uri.path).to eq "/#{type.to_s.dasherize}s" + query_params = CGI.parse(uri.query) + expect(query_params["status[]"]).to eq [status.to_s] + expect(query_params["years[]"]).to eq [date_last_year.year.to_s] + end + end + end + + context "with completed status" do + let(:status) { :completed } + + context "and the current year" do + let(:startdate) { date_this_year } + + it "exposes the correct data for the data box" do + create_list(type, expected_count, :completed2024, created_by: user, startdate:) + data = presenter.current_year_completed_lettings_data + + expect(data[:count]).to be expected_count + expect(data[:text]).to eq "Completed lettings" + uri = URI.parse(data[:path]) + expect(uri.path).to eq "/#{type.to_s.dasherize}s" + query_params = CGI.parse(uri.query) + expect(query_params["status[]"]).to eq [status.to_s] + expect(query_params["years[]"]).to eq [date_this_year.year.to_s] + end + end + + context "and the last year" do + let(:startdate) { date_last_year } + + it "exposes the correct data for the data box" do + create_list(type, expected_count, status, created_by: user, startdate:) + data = presenter.last_year_completed_lettings_data + + expect(data[:count]).to be expected_count + expect(data[:text]).to eq "Completed lettings" + uri = URI.parse(data[:path]) + expect(uri.path).to eq "/#{type.to_s.dasherize}s" + query_params = CGI.parse(uri.query) + expect(query_params["status[]"]).to eq [status.to_s] + expect(query_params["years[]"]).to eq [date_last_year.year.to_s] + end + end + end + end + + context "with sales logs" do + let(:type) { :sales_log } + + context "with in progress status" do + let(:status) { :in_progress } + + context "and the current year" do + let(:saledate) { date_this_year } + + it "exposes the correct data for the data box" do + create_list(type, expected_count, status, created_by: user, saledate:) + data = presenter.current_year_in_progress_sales_data + + expect(data[:count]).to be expected_count + expect(data[:text]).to eq "Sales in progress" + uri = URI.parse(data[:path]) + expect(uri.path).to eq "/#{type.to_s.dasherize}s" + query_params = CGI.parse(uri.query) + expect(query_params["status[]"]).to eq [status.to_s] + expect(query_params["years[]"]).to eq [date_this_year.year.to_s] + end + end + + context "and the last year" do + let(:saledate) { date_last_year } + + it "exposes the correct data for the data box" do + create_list(type, expected_count, status, created_by: user, saledate:) + data = presenter.last_year_in_progress_sales_data + + expect(data[:count]).to be expected_count + expect(data[:text]).to eq "Sales in progress" + uri = URI.parse(data[:path]) + expect(uri.path).to eq "/#{type.to_s.dasherize}s" + query_params = CGI.parse(uri.query) + expect(query_params["status[]"]).to eq [status.to_s] + expect(query_params["years[]"]).to eq [date_last_year.year.to_s] + end + end + end + + context "with completed status" do + let(:status) { :completed } + + context "and the current year" do + let(:saledate) { date_this_year } + + it "exposes the correct data for the data box" do + create_list(type, expected_count, :completed2024, created_by: user, saledate:) + data = presenter.current_year_completed_sales_data + + binding.pry + expect(data[:count]).to be expected_count + expect(data[:text]).to eq "Completed sales" + uri = URI.parse(data[:path]) + expect(uri.path).to eq "/#{type.to_s.dasherize}s" + query_params = CGI.parse(uri.query) + expect(query_params["status[]"]).to eq [status.to_s] + expect(query_params["years[]"]).to eq [date_this_year.year.to_s] + end + end + + context "and the last year" do + let(:saledate) { date_last_year } + + it "exposes the correct data for the data box" do + create_list(type, expected_count, status, created_by: user, saledate:) + data = presenter.last_year_completed_sales_data + + expect(data[:count]).to be expected_count + expect(data[:text]).to eq "Completed sales" + uri = URI.parse(data[:path]) + expect(uri.path).to eq "/#{type.to_s.dasherize}s" + query_params = CGI.parse(uri.query) + expect(query_params["status[]"]).to eq [status.to_s] + expect(query_params["years[]"]).to eq [date_last_year.year.to_s] + end + end + end + end + end +end diff --git a/spec/request_helper.rb b/spec/request_helper.rb index 8c5759bec..346bd5f7c 100644 --- a/spec/request_helper.rb +++ b/spec/request_helper.rb @@ -83,6 +83,9 @@ module RequestHelper WebMock.stub_request(:get, "https://api.os.uk/search/places/v1/uprn?key=OS_DATA_KEY&uprn=1234567890123") .to_return(status: 404, body: "", headers: {}) + + WebMock.stub_request(:get, /api\.os\.uk/) + .to_return(status: 200, body: { results: [{ DPA: { MATCH: 0.9, BUILDING_NAME: "result address line 1", POST_TOWN: "result town or city", POSTCODE: "AA1 1AA", UPRN: "1" } }] }.to_json, headers: {}) end def self.real_http_requests