diff --git a/app/controllers/collection_resources_controller.rb b/app/controllers/collection_resources_controller.rb
new file mode 100644
index 000000000..dc7225832
--- /dev/null
+++ b/app/controllers/collection_resources_controller.rb
@@ -0,0 +1,12 @@
+class CollectionResourcesController < ApplicationController
+ include CollectionResourcesHelper
+
+ before_action :authenticate_user!
+
+ def index
+ render_not_found unless current_user.support?
+
+ @mandatory_lettings_collection_resources_per_year = MandatoryCollectionResourcesService.generate_resources("lettings", editable_collection_resource_years)
+ @mandatory_sales_collection_resources_per_year = MandatoryCollectionResourcesService.generate_resources("sales", editable_collection_resource_years)
+ end
+end
diff --git a/app/controllers/start_controller.rb b/app/controllers/start_controller.rb
index 0c54013b2..62bb3add7 100644
--- a/app/controllers/start_controller.rb
+++ b/app/controllers/start_controller.rb
@@ -1,7 +1,10 @@
class StartController < ApplicationController
include CollectionTimeHelper
+ include CollectionResourcesHelper
def index
+ @mandatory_lettings_collection_resources_per_year = MandatoryCollectionResourcesService.generate_resources("lettings", displayed_collection_resource_years)
+ @mandatory_sales_collection_resources_per_year = MandatoryCollectionResourcesService.generate_resources("sales", displayed_collection_resource_years)
if current_user
@homepage_presenter = HomepagePresenter.new(current_user)
render "home/index"
diff --git a/app/helpers/collection_resources_helper.rb b/app/helpers/collection_resources_helper.rb
index 2c4389c38..70b4f0edf 100644
--- a/app/helpers/collection_resources_helper.rb
+++ b/app/helpers/collection_resources_helper.rb
@@ -54,4 +54,24 @@ module CollectionResourcesHelper
def short_underscored_year_range_format(year)
"#{year % 100}_#{(year + 1) % 100}"
end
+
+ def document_list_component_items(resources)
+ resources.map do |resource|
+ {
+ name: "Download the #{resource.display_name}",
+ href: send(resource.download_path),
+ metadata: file_type_size_and_pages(resource.download_filename),
+ }
+ end
+ end
+
+ def document_list_edit_component_items(resources)
+ resources.map do |resource|
+ {
+ name: resource.download_filename,
+ href: send(resource.download_path),
+ metadata: file_type_size_and_pages(resource.download_filename),
+ }
+ end
+ end
end
diff --git a/app/models/collection_resource.rb b/app/models/collection_resource.rb
new file mode 100644
index 000000000..8e9740484
--- /dev/null
+++ b/app/models/collection_resource.rb
@@ -0,0 +1,5 @@
+class CollectionResource
+ include ActiveModel::Model
+
+ attr_accessor :display_name, :short_display_name, :year, :log_type, :download_filename, :download_path
+end
diff --git a/app/services/mandatory_collection_resources_service.rb b/app/services/mandatory_collection_resources_service.rb
new file mode 100644
index 000000000..199a81ca3
--- /dev/null
+++ b/app/services/mandatory_collection_resources_service.rb
@@ -0,0 +1,60 @@
+class MandatoryCollectionResourcesService
+ MANDATORY_RESOURCES = %w[paper_form bulk_upload_template bulk_upload_specification].freeze
+
+ def self.generate_resources(log_type, collection_years)
+ mandatory_resources_per_year = {}
+ collection_years.map do |year|
+ mandatory_resources_per_year[year] = resources_per_year(year, log_type)
+ end
+ mandatory_resources_per_year
+ end
+
+ def self.resources_per_year(year, log_type)
+ MANDATORY_RESOURCES.map do |resource|
+ CollectionResource.new(
+ display_name: display_name(resource, year, log_type),
+ short_display_name: resource.humanize,
+ year:,
+ log_type:,
+ download_filename: download_filename(resource, year, log_type),
+ download_path: download_path(resource, year, log_type),
+ )
+ end
+ end
+
+ def self.display_name(resource, year, log_type)
+ year_range = "#{year} to #{year + 1}"
+ case resource
+ when "paper_form"
+ "#{log_type} log for tenants (#{year_range})"
+ when "bulk_upload_template"
+ "#{log_type} bulk upload template (#{year_range})"
+ when "bulk_upload_specification"
+ "#{log_type} bulk upload specification (#{year_range})"
+ end
+ end
+
+ def self.download_path(resource, year, log_type)
+ year_range = "#{year % 100}_#{(year + 1) % 100}"
+ case resource
+ when "paper_form"
+ "download_#{year_range}_#{log_type}_form_path"
+ when "bulk_upload_template"
+ "download_#{year_range}_#{log_type}_bulk_upload_template_path"
+ when "bulk_upload_specification"
+ "download_#{year_range}_#{log_type}_bulk_upload_specification_path"
+ end
+ end
+
+ def self.download_filename(resource, year, log_type)
+ year_range = "#{year}_#{(year + 1) % 100}"
+ case resource
+ when "paper_form"
+ "#{year_range}_#{log_type}_paper_form.pdf"
+ when "bulk_upload_template"
+ "bulk-upload-#{log_type}-template-#{year_range.dasherize}.xlsx"
+ when "bulk_upload_specification"
+ "bulk-upload-#{log_type}-specification-#{year_range.dasherize}.xlsx"
+ end
+ end
+end
diff --git a/app/views/collection_resources/_collection_resource_summary_list.erb b/app/views/collection_resources/_collection_resource_summary_list.erb
new file mode 100644
index 000000000..272a82272
--- /dev/null
+++ b/app/views/collection_resources/_collection_resource_summary_list.erb
@@ -0,0 +1,14 @@
+<%= govuk_summary_list do |summary_list| %>
+ <% mandatory_resources.each do |resource| %>
+ <% summary_list.with_row do |row| %>
+ <% row.with_key { resource.short_display_name } %>
+ <% row.with_value do %>
+ <%= render DocumentListComponent.new(items: document_list_edit_component_items([resource]), label: "") %>
+ <% end %>
+ <% row.with_action(
+ text: "Change",
+ href: "/",
+ ) %>
+ <% end %>
+ <% end %>
+<% end %>
\ No newline at end of file
diff --git a/app/views/collection_resources/index.html.erb b/app/views/collection_resources/index.html.erb
new file mode 100644
index 000000000..7ce6d5eb6
--- /dev/null
+++ b/app/views/collection_resources/index.html.erb
@@ -0,0 +1,23 @@
+<% title = "Collection resources" %>
+<% content_for :title, title %>
+<% content_for :before_content do %>
+ <%= govuk_back_link(href: :back) %>
+<% end %>
+
+
<%= title %>
+
+<% @mandatory_lettings_collection_resources_per_year.each do |year, mandatory_resources| %>
+
+ Lettings <%= text_year_range_format(year) %>
+
+ <%= render partial: "collection_resource_summary_list", locals: { mandatory_resources: } %>
+
+<% end %>
+
+<% @mandatory_sales_collection_resources_per_year.each do |year, mandatory_resources| %>
+
+ Sales <%= text_year_range_format(year) %>
+
+ <%= render partial: "collection_resource_summary_list", locals: { mandatory_resources: } %>
+
+<% end %>
diff --git a/app/views/layouts/_collection_resources.html.erb b/app/views/layouts/_collection_resources.html.erb
index c49dfe00a..59718d65f 100644
--- a/app/views/layouts/_collection_resources.html.erb
+++ b/app/views/layouts/_collection_resources.html.erb
@@ -5,56 +5,22 @@
<% else %>
Collection resources
<% end %>
-<% collection_resource_years.each do |collection_start_year| %>
+<% displayed_collection_resource_years.each do |collection_start_year| %>
Use the <%= collection_start_year %> to <%= collection_start_year + 1 %> forms for lettings that start and sales that complete between 1 April <%= collection_start_year %> and 31 March <%= collection_start_year + 1 %>.
<% end %>
<%= govuk_tabs(title: "Collection resources", classes: %w[app-tab__small-headers]) do |c| %>
- <% collection_resource_years.each do |collection_start_year| %>
- <% c.with_tab(label: "Lettings #{year_range_format(collection_start_year)}") do %>
- <%= render DocumentListComponent.new(
- items: [
- {
- name: "Download the lettings log for tenants (#{text_year_range_format(collection_start_year)})",
- href: send("download_#{short_underscored_year_range_format(collection_start_year)}_lettings_form_path"),
- metadata: file_type_size_and_pages("#{underscored_file_year_format(collection_start_year)}_lettings_paper_form.pdf", number_of_pages: 8),
- },
- {
- name: "Download the lettings bulk upload template (#{text_year_range_format(collection_start_year)})",
- href: send("download_#{short_underscored_year_range_format(collection_start_year)}_lettings_bulk_upload_template_path"),
- metadata: file_type_size_and_pages("bulk-upload-lettings-template-#{dasherised_file_year_format(collection_start_year)}.xlsx"),
- },
- {
- name: "Download the lettings bulk upload specification (#{text_year_range_format(collection_start_year)})",
- href: send("download_#{short_underscored_year_range_format(collection_start_year)}_lettings_bulk_upload_specification_path"),
- metadata: file_type_size_and_pages("bulk-upload-lettings-specification-#{dasherised_file_year_format(collection_start_year)}.xlsx"),
- },
- ],
- label: "Lettings #{text_year_range_format(collection_start_year)}",
- ) %>
+ <% @mandatory_lettings_collection_resources_per_year.each do |year, resources| %>
+ <% c.with_tab(label: "Lettings #{year_range_format(year)}") do %>
+ <%= render DocumentListComponent.new(items: document_list_component_items(resources), label: "Lettings #{text_year_range_format(year)}") %>
<% end %>
- <% c.with_tab(label: "Sales #{year_range_format(collection_start_year)}") do %>
- <%= render DocumentListComponent.new(
- items: [
- {
- name: "Download the sales log for buyers (#{text_year_range_format(collection_start_year)})",
- href: send("download_#{short_underscored_year_range_format(collection_start_year)}_sales_form_path"),
- metadata: file_type_size_and_pages("#{underscored_file_year_format(collection_start_year)}_sales_paper_form.pdf", number_of_pages: 8),
- },
- {
- name: "Download the sales bulk upload template (#{text_year_range_format(collection_start_year)})",
- href: send("download_#{short_underscored_year_range_format(collection_start_year)}_sales_bulk_upload_template_path"),
- metadata: file_type_size_and_pages("bulk-upload-sales-template-#{dasherised_file_year_format(collection_start_year)}.xlsx"),
- },
- {
- name: "Download the sales bulk upload specification (#{text_year_range_format(collection_start_year)})",
- href: send("download_#{short_underscored_year_range_format(collection_start_year)}_sales_bulk_upload_specification_path"),
- metadata: file_type_size_and_pages("bulk-upload-sales-specification-#{dasherised_file_year_format(collection_start_year)}.xlsx"),
- },
- ],
- label: "Sales #{text_year_range_format(collection_start_year)}",
- ) %>
+ <% end %>
+ <% @mandatory_sales_collection_resources_per_year.each do |year, resources| %>
+ <% c.with_tab(label: "Sales #{year_range_format(year)}") do %>
+ <%= render DocumentListComponent.new(items: document_list_component_items(resources), label: "Sales #{text_year_range_format(year)}") %>
<% end %>
<% end %>
<% end %>
+
+<%= govuk_button_link_to "Manage collection resources", collection_resources_path, secondary: true, class: "govuk-!-margin-bottom-2" if current_user.support? %>
diff --git a/config/routes.rb b/config/routes.rb
index ed6f47bbd..1a5f69ad5 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -40,26 +40,31 @@ Rails.application.routes.draw do
get "/service-moved", to: "maintenance#service_moved"
get "/service-unavailable", to: "maintenance#service_unavailable"
- get "/download-23-24-lettings-form", to: "start#download_23_24_lettings_form"
- get "/download-23-24-lettings-bulk-upload-template", to: "start#download_23_24_lettings_bulk_upload_template"
get "/download-23-24-lettings-bulk-upload-legacy-template", to: "start#download_23_24_lettings_bulk_upload_legacy_template"
- get "/download-23-24-lettings-bulk-upload-specification", to: "start#download_23_24_lettings_bulk_upload_specification"
-
- get "/download-23-24-sales-form", to: "start#download_23_24_sales_form"
- get "/download-23-24-sales-bulk-upload-template", to: "start#download_23_24_sales_bulk_upload_template"
get "/download-23-24-sales-bulk-upload-legacy-template", to: "start#download_23_24_sales_bulk_upload_legacy_template"
- get "/download-23-24-sales-bulk-upload-specification", to: "start#download_23_24_sales_bulk_upload_specification"
- get "/download-24-25-lettings-form", to: "start#download_24_25_lettings_form"
- get "/download-24-25-lettings-bulk-upload-template", to: "start#download_24_25_lettings_bulk_upload_template"
- get "/download-24-25-lettings-bulk-upload-specification", to: "start#download_24_25_lettings_bulk_upload_specification"
+ FormHandler.instance.years_of_available_lettings_forms.each do |year|
+ short_underscored_year = "#{year % 100}_#{(year + 1) % 100}"
+ short_dasherized_year = short_underscored_year.dasherize
+
+ get "/download-#{short_dasherized_year}-lettings-form", to: "start#download_#{short_underscored_year}_lettings_form"
+ get "/download-#{short_dasherized_year}-lettings-bulk-upload-template", to: "start#download_#{short_underscored_year}_lettings_bulk_upload_template"
+ get "/download-#{short_dasherized_year}-lettings-bulk-upload-specification", to: "start#download_#{short_underscored_year}_lettings_bulk_upload_specification"
+ end
+
+ FormHandler.instance.years_of_available_sales_forms.each do |year|
+ short_underscored_year = "#{year % 100}_#{(year + 1) % 100}"
+ short_dasherized_year = short_underscored_year.dasherize
- get "/download-24-25-sales-form", to: "start#download_24_25_sales_form"
- get "/download-24-25-sales-bulk-upload-template", to: "start#download_24_25_sales_bulk_upload_template"
- get "/download-24-25-sales-bulk-upload-specification", to: "start#download_24_25_sales_bulk_upload_specification"
+ get "/download-#{short_dasherized_year}-sales-form", to: "start#download_#{short_underscored_year}_sales_form"
+ get "/download-#{short_dasherized_year}-sales-bulk-upload-template", to: "start#download_#{short_underscored_year}_sales_bulk_upload_template"
+ get "/download-#{short_dasherized_year}-sales-bulk-upload-specification", to: "start#download_#{short_underscored_year}_sales_bulk_upload_specification"
+ end
get "clear-filters", to: "sessions#clear_filters"
+ get "collection-resources", to: "collection_resources#index"
+
resource :account, only: %i[show edit], controller: "users" do
get "edit/password", to: "users#edit_password"
end
diff --git a/spec/requests/collection_resources_controller_spec.rb b/spec/requests/collection_resources_controller_spec.rb
new file mode 100644
index 000000000..d5b0a72a5
--- /dev/null
+++ b/spec/requests/collection_resources_controller_spec.rb
@@ -0,0 +1,86 @@
+require "rails_helper"
+
+RSpec.describe CollectionResourcesController, type: :request do
+ let(:page) { Capybara::Node::Simple.new(response.body) }
+
+ describe "GET #index" do
+ context "when user is not signed in" do
+ it "redirects to the sign in page" do
+ get collection_resources_path
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
+
+ context "when user is signed in as a data coordinator" do
+ let(:user) { create(:user, :data_coordinator) }
+
+ before do
+ sign_in user
+ end
+
+ it "returns page not found" do
+ get collection_resources_path
+ expect(response).to have_http_status(:not_found)
+ end
+ end
+
+ context "when user is signed in as a data provider" do
+ let(:user) { create(:user, :data_provider) }
+
+ before do
+ sign_in user
+ end
+
+ it "returns page not found" do
+ get collection_resources_path
+ expect(response).to have_http_status(:not_found)
+ end
+ end
+
+ context "when user is signed in as a support user" do
+ let(:user) { create(:user, :support) }
+
+ before do
+ allow(Time.zone).to receive(:today).and_return(Time.zone.local(2025, 1, 8))
+ allow(user).to receive(:need_two_factor_authentication?).and_return(false)
+ sign_in user
+ get collection_resources_path
+ end
+
+ it "displays collection resources" do
+ expect(page).to have_content("Lettings 2024 to 2025")
+ expect(page).to have_content("Lettings 2025 to 2026")
+ expect(page).to have_content("Sales 2024 to 2025")
+ expect(page).to have_content("Sales 2025 to 2026")
+ end
+
+ it "displays mandatory filed" do
+ expect(page).to have_content("Paper form")
+ expect(page).to have_content("Bulk upload template")
+ expect(page).to have_content("Bulk upload specification")
+ end
+
+ context "when files are on S3" do
+ it "displays file names with download links" do
+ expect(page).to have_link("2024_25_lettings_paper_form.pdf", href: download_24_25_lettings_form_path)
+ expect(page).to have_link("bulk-upload-lettings-template-2024-25.xlsx", href: download_24_25_lettings_bulk_upload_template_path)
+ expect(page).to have_link("bulk-upload-lettings-specification-2024-25.xlsx", href: download_24_25_lettings_bulk_upload_specification_path)
+ expect(page).to have_link("2024_25_sales_paper_form.pdf", href: download_24_25_sales_form_path)
+ expect(page).to have_link("bulk-upload-sales-template-2024-25.xlsx", href: download_24_25_sales_bulk_upload_template_path)
+ expect(page).to have_link("bulk-upload-sales-specification-2024-25.xlsx", href: download_24_25_sales_bulk_upload_specification_path)
+
+ expect(page).to have_link("2025_26_lettings_paper_form.pdf", href: download_25_26_lettings_form_path)
+ expect(page).to have_link("bulk-upload-lettings-template-2025-26.xlsx", href: download_25_26_lettings_bulk_upload_template_path)
+ expect(page).to have_link("bulk-upload-lettings-specification-2025-26.xlsx", href: download_25_26_lettings_bulk_upload_specification_path)
+ expect(page).to have_link("2025_26_sales_paper_form.pdf", href: download_25_26_sales_form_path)
+ expect(page).to have_link("bulk-upload-sales-template-2025-26.xlsx", href: download_25_26_sales_bulk_upload_template_path)
+ expect(page).to have_link("bulk-upload-sales-specification-2025-26.xlsx", href: download_25_26_sales_bulk_upload_specification_path)
+ end
+
+ it "displays change links" do
+ expect(page).to have_selector(:link_or_button, "Change", count: 12)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/requests/start_controller_spec.rb b/spec/requests/start_controller_spec.rb
index f7503f2bd..40f52f59c 100644
--- a/spec/requests/start_controller_spec.rb
+++ b/spec/requests/start_controller_spec.rb
@@ -367,6 +367,24 @@ RSpec.describe StartController, type: :request do
get root_path
expect(page).to have_content("About this service")
end
+
+ context "with support user" do
+ let(:user) { create(:user, :support) }
+
+ it "displays link to edit collection resources" do
+ get root_path
+
+ expect(page).to have_link("Manage collection resources", href: collection_resources_path)
+ end
+ end
+
+ context "with data coordinator" do
+ it "does not display the link to edit collection resources" do
+ get root_path
+
+ expect(page).not_to have_link("Manage collection resources", href: collection_resources_path)
+ end
+ end
end
end