diff --git a/app/helpers/collection_deadline_helper.rb b/app/helpers/collection_deadline_helper.rb new file mode 100644 index 000000000..3c4f7e502 --- /dev/null +++ b/app/helpers/collection_deadline_helper.rb @@ -0,0 +1,81 @@ +module CollectionDeadlineHelper + include CollectionTimeHelper + + QUARTERLY_DEADLINES = { + 2024 => { + first_quarter_deadline: Time.zone.local(2024, 7, 12), + second_quarter_deadline: Time.zone.local(2024, 10, 11), + third_quarter_deadline: Time.zone.local(2025, 1, 10), + fourth_quarter_deadline: Time.zone.local(2025, 6, 6), # Same as submission deadline + }, + 2025 => { + first_quarter_deadline: Time.zone.local(2025, 7, 11), + second_quarter_deadline: Time.zone.local(2025, 10, 10), + third_quarter_deadline: Time.zone.local(2026, 1, 16), + fourth_quarter_deadline: Time.zone.local(2026, 6, 5), # Same as submission deadline + }, + }.freeze + + def quarterly_cutoff_date(quarter, year) + send("#{quarter}_quarter", year)[:cutoff_date].strftime("%A %-d %B %Y") + end + + def quarter_deadlines_for_year(year) + QUARTERLY_DEADLINES[year] + end + + def first_quarter(year) + { + cutoff_date: quarter_deadlines_for_year(year)[:first_quarter_deadline], + start_date: Time.zone.local(year, 4, 1), + end_date: Time.zone.local(year, 6, 30), + } + end + + def second_quarter(year) + { + cutoff_date: quarter_deadlines_for_year(year)[:second_quarter_deadline], + start_date: Time.zone.local(year, 7, 1), + end_date: Time.zone.local(year, 9, 30), + } + end + + def third_quarter(year) + { + cutoff_date: quarter_deadlines_for_year(year)[:third_quarter_deadline], + start_date: Time.zone.local(year, 10, 1), + end_date: Time.zone.local(year, 12, 31), + } + end + + def fourth_quarter(year) + { + cutoff_date: quarter_deadlines_for_year(year)[:fourth_quarter_deadline], + start_date: Time.zone.local(year + 1, 1, 1), + end_date: Time.zone.local(year + 1, 3, 31), + } + end + + def quarter_dates(year) + [ + first_quarter(year).merge(quarter: "Q1"), + second_quarter(year).merge(quarter: "Q2"), + third_quarter(year).merge(quarter: "Q3"), + ] + end + + def quarter_for_date(date: Time.zone.now) + quarters = quarter_dates(current_collection_start_year) + + quarter = quarters.find { |q| date.between?(q[:start_date], q[:cutoff_date] + 1.day) } + + return unless quarter + + OpenStruct.new( + quarter: quarter[:quarter], + cutoff_date: quarter[:cutoff_date], + quarter_start_date: quarter[:start_date], + quarter_end_date: quarter[:end_date], + ) + end +end diff --git a/app/helpers/collection_time_helper.rb b/app/helpers/collection_time_helper.rb index 809cae5e7..acd56378b 100644 --- a/app/helpers/collection_time_helper.rb +++ b/app/helpers/collection_time_helper.rb @@ -30,6 +30,10 @@ module CollectionTimeHelper Time.zone.local(current_collection_start_year + 1, 3, 31).end_of_day end + def current_collection_end_year + current_collection_start_year + 1 + end + def previous_collection_end_date current_collection_end_date - 1.year end @@ -49,23 +53,4 @@ module CollectionTimeHelper def archived_collection_start_year current_collection_start_year - 2 end - - def quarter_for_date(date: Time.zone.now) - quarters = [ - { quarter: "Q1", cutoff_date: Time.zone.local(2024, 7, 12), start_date: Time.zone.local(2024, 4, 1), end_date: Time.zone.local(2024, 6, 30) }, - { quarter: "Q2", cutoff_date: Time.zone.local(2024, 10, 11), start_date: Time.zone.local(2024, 7, 1), end_date: Time.zone.local(2024, 9, 30) }, - { quarter: "Q3", cutoff_date: Time.zone.local(2025, 1, 10), start_date: Time.zone.local(2024, 10, 1), end_date: Time.zone.local(2024, 12, 31) }, - ] - - quarter = quarters.find { |q| date.between?(q[:start_date], q[:cutoff_date] + 1.day) } - - return unless quarter - - OpenStruct.new( - quarter: quarter[:quarter], - cutoff_date: quarter[:cutoff_date], - quarter_start_date: quarter[:start_date], - quarter_end_date: quarter[:end_date], - ) - end end diff --git a/app/views/home/_upcoming_deadlines.html.erb b/app/views/home/_upcoming_deadlines.html.erb index dbed05bfd..edb7d7490 100644 --- a/app/views/home/_upcoming_deadlines.html.erb +++ b/app/views/home/_upcoming_deadlines.html.erb @@ -1,33 +1,33 @@

Upcoming deadlines

+<% previous_lettings_form = FormHandler.instance.previous_lettings_form %> +<% current_lettings_form = FormHandler.instance.current_lettings_form %> +<% crossover_before_submission_deadline = FormHandler.instance.in_crossover_period? && previous_lettings_form.submission_deadline > Time.zone.now %> -<% open_lettings_form = FormHandler.instance.in_crossover_period? ? FormHandler.instance.previous_lettings_form : FormHandler.instance.current_lettings_form %> -<% formatted_deadline = "#{open_lettings_form.submission_deadline.strftime('%A')} #{open_lettings_form.submission_deadline.to_formatted_s(:govuk_date)}" %> -<% if FormHandler.instance.in_crossover_period? %> -

End of year deadline - <%= formatted_deadline %>: Deadline to submit logs for tenancies starting between <%= open_lettings_form.start_date.to_formatted_s(:govuk_date) %> to <%= collection_end_date(open_lettings_form.start_date).to_formatted_s(:govuk_date) %>

+<% if crossover_before_submission_deadline %> +

End of year deadline - <%= previous_lettings_form.submission_deadline.strftime("%A %-d %B %Y") %>: Deadline to submit logs for tenancies starting between <%= previous_lettings_form.start_date.to_formatted_s(:govuk_date) %> to <%= collection_end_date(previous_lettings_form.start_date).to_formatted_s(:govuk_date) %>

<% end %> <% current_quarter = quarter_for_date(date: Time.zone.now) %> <% if current_quarter.present? %> -

<%= "#{current_quarter.quarter} - #{current_quarter.cutoff_date.strftime('%A')} #{current_quarter.cutoff_date.to_formatted_s(:govuk_date)}" %>: Quarterly cut off date for tenancies and sales starting between <%= current_quarter.quarter_start_date.to_formatted_s(:govuk_date) %> and <%= current_quarter.quarter_end_date.to_formatted_s(:govuk_date) %>.

+

<%= "#{current_quarter.quarter} - #{current_quarter.cutoff_date.strftime('%A %-d %B %Y')}" %>: Quarterly cut off date for tenancies and sales starting between <%= current_quarter.quarter_start_date.to_formatted_s(:govuk_date) %> and <%= current_quarter.quarter_end_date.to_formatted_s(:govuk_date) %>.

<% end %> -<% if !FormHandler.instance.in_crossover_period? %> +<% unless crossover_before_submission_deadline %>

Try to complete your logs for each quarter by the cut-off date.

-

You can still create logs for a previous quarter after its cut-off date, as long as you complete them by the end-of-year deadline: <%= formatted_deadline %>.

+

You can still create logs for a previous quarter after its cut-off date, as long as you complete them by the end of year deadline: <%= current_lettings_form.submission_deadline.strftime("%A %-d %B %Y") %>.

<% end %> -<% if FormHandler.instance.in_crossover_period? %> -<% previous_lettings_form = FormHandler.instance.previous_lettings_form %> -

Prioritise completing logs for the closing collection year. You must complete all <%= previous_lettings_form.start_date.year %> to <%= previous_lettings_form.submission_deadline.year %> logs must by the end-of-year deadline. You can still create <%= open_lettings_form.start_date.year %> to <%= open_lettings_form.submission_deadline.year %> logs for this quarter after the quarterly cut-off date.

+<% if crossover_before_submission_deadline %> +

Prioritise completing logs for the closing collection year. You must complete all <%= previous_lettings_form.start_date.year %> to <%= previous_lettings_form.submission_deadline.year %> logs by the end of year deadline. You can still create <%= current_lettings_form.start_date.year %> to <%= current_lettings_form.submission_deadline.year %> logs for this quarter after the quarterly cut-off date.

<% end %> -<%= govuk_details(summary_text: "Quarterly cut-off dates for 2024 to 2025") do %> -

The 2024 to 2025 quarterly cut-off dates are:

+<%= govuk_details(summary_text: "Quarterly cut-off dates for #{current_collection_start_year} to #{current_collection_end_year}") do %> +

The <%= current_collection_start_year %> to <%= current_collection_end_year %> quarterly cut-off dates are:

It is important that you meet these cut-off dates because we submit data to the Office for National Statistics quarterly, helping them create essential inflation statistics.

Meeting these cut-off dates also gives you more accurate data for your own analysis, and reduces the burden at the end of the year.

diff --git a/spec/features/home_page_spec.rb b/spec/features/home_page_spec.rb new file mode 100644 index 000000000..0d6bc7570 --- /dev/null +++ b/spec/features/home_page_spec.rb @@ -0,0 +1,111 @@ +require "rails_helper" + +RSpec.describe "Home Page Features" do + include CollectionTimeHelper + + let!(:user) { FactoryBot.create(:user) } + let(:storage_service) { instance_double(Storage::S3Service, get_file_metadata: nil) } + + before do + sign_in user + allow(Storage::S3Service).to receive(:new).and_return(storage_service) + allow(storage_service).to receive(:configuration).and_return(OpenStruct.new(bucket_name: "core-test-collection-resources")) + end + + describe "_upcoming_deadlines" do + let(:current_collection_year) { 2024 } + let(:next_collection_year) { 2025 } + + context "when visiting during the current collection year" do + before do + allow(FormHandler.instance).to receive(:in_crossover_period?).and_return(false) + # rubocop:disable RSpec/AnyInstance + allow_any_instance_of(CollectionTimeHelper).to receive(:current_collection_start_year).and_return(current_collection_year) + allow_any_instance_of(CollectionTimeHelper).to receive(:current_collection_end_year).and_return(current_collection_year + 1) + # rubocop:enable RSpec/AnyInstance + end + + scenario "displays correct text for quarters" do + Timecop.freeze(Time.zone.local(current_collection_year, 4, 1)) do + visit root_path + find("span.govuk-details__summary-text", text: "Quarterly cut-off dates for 2024 to 2025").click + expect(page).to have_content("Q1 - Friday 12 July 2024") + expect(page).to have_content("Q2 - Friday 11 October 2024") + expect(page).to have_content("Q3 - Friday 10 January 2025") + expect(page).to have_content("End of year deadline - Friday 6 June 2025") + end + Timecop.return + end + + scenario "displays correct current quarter as Q1" do + Timecop.freeze(Time.zone.local(current_collection_year, 4, 1)) do + visit root_path + expect(page).to have_content("Q1 - Friday 12 July 2024") + end + Timecop.return + end + + scenario "displays correct current quarter as Q2" do + Timecop.freeze(Time.zone.local(current_collection_year, 8, 1)) do + visit root_path + expect(page).to have_content("Q2 - Friday 11 October 2024") + end + Timecop.return + end + + scenario "displays correct current quarter as Q3" do + Timecop.freeze(Time.zone.local(current_collection_year, 11, 1)) do + visit root_path + expect(page).to have_content("Q3 - Friday 10 January 2025") + end + Timecop.return + end + end + + context "when visiting during the next collection year" do + before do + allow(FormHandler.instance).to receive(:in_crossover_period?).and_return(false) + # rubocop:disable RSpec/AnyInstance + allow_any_instance_of(CollectionTimeHelper).to receive(:current_collection_start_year).and_return(next_collection_year) + allow_any_instance_of(CollectionTimeHelper).to receive(:current_collection_end_year).and_return(next_collection_year + 1) + # rubocop:enable RSpec/AnyInstance + end + + scenario "displays correct text for quarters" do + Timecop.freeze(Time.zone.local(next_collection_year, 4, 1)) do + visit root_path + find("span.govuk-details__summary-text", text: "Quarterly cut-off dates for 2025 to 2026").click + expect(page).to have_content("Q1 - Friday 11 July 2025") + expect(page).to have_content("Q2 - Friday 10 October 2025") + expect(page).to have_content("Q3 - Friday 16 January 2026") + expect(page).to have_content("End of year deadline - Friday 5 June 2026") + end + Timecop.return + end + + scenario "displays correct current quarter as Q1" do + Timecop.freeze(Time.zone.local(next_collection_year, 4, 1)) do + visit root_path + expect(page).to have_content("Q1 - Friday 11 July 2025") + end + Timecop.return + end + + scenario "displays correct current quarter as Q2" do + Timecop.freeze(Time.zone.local(next_collection_year, 8, 1)) do + visit root_path + expect(page).to have_content("Q2 - Friday 10 October 2025") + end + Timecop.return + end + + scenario "displays correct current quarter as Q3" do + Timecop.freeze(Time.zone.local(next_collection_year, 11, 1)) do + visit root_path + expect(page).to have_content("Q3 - Friday 16 January 2026") + end + Timecop.return + end + end + end +end diff --git a/spec/helpers/collection_deadline_helper_spec.rb b/spec/helpers/collection_deadline_helper_spec.rb new file mode 100644 index 000000000..95f430fd6 --- /dev/null +++ b/spec/helpers/collection_deadline_helper_spec.rb @@ -0,0 +1,29 @@ +require "rails_helper" + +RSpec.describe CollectionDeadlineHelper do + let(:current_user) { create(:user, :data_coordinator) } + let(:user) { create(:user, :data_coordinator) } + + describe "#quarter_for_date" do + it "returns correct cutoff date for the first quarter of 2024/25" do + quarter = quarter_for_date(date: Time.zone.local(2024, 4, 1)) + expect(quarter.cutoff_date).to eq(Time.zone.local(2024, 7, 12)) + expect(quarter.quarter_start_date).to eq(Time.zone.local(2024, 4, 1)) + expect(quarter.quarter_end_date).to eq(Time.zone.local(2024, 6, 30)) + end + + it "returns correct cutoff date for the second quarter of 2024/25" do + quarter = quarter_for_date(date: Time.zone.local(2024, 9, 30)) + expect(quarter.cutoff_date).to eq(Time.zone.local(2024, 10, 11)) + expect(quarter.quarter_start_date).to eq(Time.zone.local(2024, 7, 1)) + expect(quarter.quarter_end_date).to eq(Time.zone.local(2024, 9, 30)) + end + + it "returns correct cutoff date for the third quarter of 2024/25" do + quarter = quarter_for_date(date: Time.zone.local(2024, 10, 25)) + expect(quarter.cutoff_date).to eq(Time.zone.local(2025, 1, 10)) + expect(quarter.quarter_start_date).to eq(Time.zone.local(2024, 10, 1)) + expect(quarter.quarter_end_date).to eq(Time.zone.local(2024, 12, 31)) + end + end +end diff --git a/spec/helpers/collection_time_helper_spec.rb b/spec/helpers/collection_time_helper_spec.rb index bffc492c6..a23fc905d 100644 --- a/spec/helpers/collection_time_helper_spec.rb +++ b/spec/helpers/collection_time_helper_spec.rb @@ -106,27 +106,4 @@ RSpec.describe CollectionTimeHelper do end end end - - describe "#quarter_for_date" do - it "returns correct cutoff date for the first quarter of 2024/25" do - quarter = quarter_for_date(date: Time.zone.local(2024, 4, 1)) - expect(quarter.cutoff_date).to eq(Time.zone.local(2024, 7, 12)) - expect(quarter.quarter_start_date).to eq(Time.zone.local(2024, 4, 1)) - expect(quarter.quarter_end_date).to eq(Time.zone.local(2024, 6, 30)) - end - - it "returns correct cutoff date for the second quarter of 2024/25" do - quarter = quarter_for_date(date: Time.zone.local(2024, 9, 30)) - expect(quarter.cutoff_date).to eq(Time.zone.local(2024, 10, 11)) - expect(quarter.quarter_start_date).to eq(Time.zone.local(2024, 7, 1)) - expect(quarter.quarter_end_date).to eq(Time.zone.local(2024, 9, 30)) - end - - it "returns correct cutoff date for the third quarter of 2024/25" do - quarter = quarter_for_date(date: Time.zone.local(2024, 10, 25)) - expect(quarter.cutoff_date).to eq(Time.zone.local(2025, 1, 10)) - expect(quarter.quarter_start_date).to eq(Time.zone.local(2024, 10, 1)) - expect(quarter.quarter_end_date).to eq(Time.zone.local(2024, 12, 31)) - end - end end