From 8c6dc56f5ee74a87fafe7527fe075b4109d4c786 Mon Sep 17 00:00:00 2001 From: J G <7750475+moarpheus@users.noreply.github.com> Date: Thu, 7 Jul 2022 17:24:29 +0100 Subject: [PATCH 01/11] CLDC-1291 Permitted user can edit scheme name (#717) * feature to test editing a scheme * adding editing buttons * adding scheme_edit_name route * controller tests for editing name * edit-name template missing * edit-name controller action * edit-name controller action - leftovers * padding for checkbox fieldset * added Which organisation owns the housing stock for this scheme? to the check * testing editing name via controller * last test * lint * wrong button name * legend is gone * Save changes --- app/controllers/schemes_controller.rb | 8 +- app/models/scheme.rb | 6 +- app/views/schemes/details.html.erb | 15 ++-- app/views/schemes/edit_name.html.erb | 47 ++++++++++ app/views/schemes/new.html.erb | 13 +-- app/views/schemes/show.html.erb | 2 + config/routes.rb | 1 + spec/features/schemes_spec.rb | 59 ++++++++++++ spec/requests/schemes_controller_spec.rb | 110 ++++++++++++++++++++++- 9 files changed, 245 insertions(+), 16 deletions(-) create mode 100644 app/views/schemes/edit_name.html.erb diff --git a/app/controllers/schemes_controller.rb b/app/controllers/schemes_controller.rb index 7edd7ecd8..9c5e4dcc5 100644 --- a/app/controllers/schemes_controller.rb +++ b/app/controllers/schemes_controller.rb @@ -79,6 +79,10 @@ class SchemesController < ApplicationController render "schemes/check_answers" end + def edit_name + render "schemes/edit_name" + end + private def confirm_secondary_page?(page) @@ -97,6 +101,8 @@ private new_location_path when "details" scheme_primary_client_group_path(@scheme) + when "edit-name" + scheme_path(@scheme) end end @@ -132,7 +138,7 @@ private def authenticate_scope! head :unauthorized and return unless current_user.data_coordinator? || current_user.support? - if %w[show locations primary_client_group confirm_secondary_client_group secondary_client_group support details check_answers].include?(action_name) && !((current_user.organisation == @scheme.owning_organisation) || current_user.support?) + if %w[show locations primary_client_group confirm_secondary_client_group secondary_client_group support details check_answers edit_name].include?(action_name) && !((current_user.organisation == @scheme.owning_organisation) || current_user.support?) render_not_found and return end end diff --git a/app/models/scheme.rb b/app/models/scheme.rb index 9dc9c62a0..13f090797 100644 --- a/app/models/scheme.rb +++ b/app/models/scheme.rb @@ -130,9 +130,9 @@ class Scheme < ApplicationRecord def display_attributes [ { name: "Service code", value: id_to_display }, - { name: "Name", value: service_name }, - { name: "Confidential information", value: sensitive }, - { name: "Housing stock owned by", value: owning_organisation.name }, + { name: "Name", value: service_name, edit: true }, + { name: "Confidential information", value: sensitive, edit: true }, + { name: "Housing stock owned by", value: owning_organisation.name, edit: true }, { name: "Managed by", value: managing_organisation&.name }, { name: "Type of scheme", value: scheme_type }, { name: "Registered under Care Standards Act 2000", value: registered_under_care_act }, diff --git a/app/views/schemes/details.html.erb b/app/views/schemes/details.html.erb index 229165fd4..b59f4ce37 100644 --- a/app/views/schemes/details.html.erb +++ b/app/views/schemes/details.html.erb @@ -18,12 +18,15 @@ label: { text: "Scheme name", size: "m" }, hint: { text: "This is how you’ll refer to this supported housing scheme within your organisation. For example, the name could relate to the address or location. You’ll be able to see the client group when selecting it." } %> - <%= f.govuk_check_box :sensitive, - 1, - 0, - checked: @scheme.sensitive?, - multiple: false, - label: { text: "This scheme contains confidential information" } %> + <%= f.govuk_check_boxes_fieldset :sensitive, + legend: nil do %> + <%= f.govuk_check_box :sensitive, + 1, + 0, + multiple: false, + checked: @scheme.sensitive == "Yes", + label: { text: "This scheme contains confidential information" } %> + <% end %> <% null_option = [OpenStruct.new(id: "", name: "Select an option")] %> <% organisations = Organisation.all.map { |org| OpenStruct.new(id: org.id, name: org.name) } %> diff --git a/app/views/schemes/edit_name.html.erb b/app/views/schemes/edit_name.html.erb new file mode 100644 index 000000000..d967c24a2 --- /dev/null +++ b/app/views/schemes/edit_name.html.erb @@ -0,0 +1,47 @@ +<% content_for :title, "Scheme details" %> + + <% content_for :before_content do %> + <%= govuk_back_link( + text: "Back", + href: :back, + ) %> + <% end %> + + <%= render partial: "organisations/headings", locals: { main: "Scheme details", sub: @scheme.service_name } %> + + <%= form_for(@scheme, method: :patch) do |f| %> +
+
+ <%= f.govuk_error_summary %> + + <%= f.govuk_text_field :service_name, + label: { text: "Scheme name", size: "m" }, + hint: { text: "This is how you’ll refer to this supported housing scheme within your organisation. For example, the name could relate to the address or location. You’ll be able to see the client group when selecting it." } %> + + <%= f.govuk_check_boxes_fieldset :sensitive, + legend: nil do %> + <%= f.govuk_check_box :sensitive, + 1, + 0, + multiple: false, + checked: @scheme.sensitive == "Yes", + label: { text: "This scheme contains confidential information" } %> + <% end %> + + <% organisations = Organisation.all.map { |org| OpenStruct.new(id: org.id, name: org.name) } %> + + <% if current_user.support? %> + <%= f.govuk_collection_select :owning_organisation_id, + organisations, + :id, + :name, + label: { text: "Which organisation owns the housing stock for this scheme?", size: "m" }, + "data-controller": %w[accessible-autocomplete conditional-filter] %> + <% end %> + + <%= f.hidden_field :page, value: "edit-name" %> + + <%= f.govuk_submit "Save changes" %> +
+
+ <% end %> diff --git a/app/views/schemes/new.html.erb b/app/views/schemes/new.html.erb index f4cbc2827..b58e461c0 100644 --- a/app/views/schemes/new.html.erb +++ b/app/views/schemes/new.html.erb @@ -20,11 +20,14 @@ label: { text: "Scheme name", size: "m" }, hint: { text: "This is how you refer to this supported housing scheme within your organisation. For example, the name could relate to the address or location. You’ll be able to see the client group when selecting it." } %> - <%= f.govuk_check_box :sensitive, - "Yes", - checked: @scheme.sensitive?, - multiple: false, - label: { text: "This scheme contains confidential information" } %> + <%= f.govuk_check_boxes_fieldset :sensitive, + legend: nil do %> + <%= f.govuk_check_box :sensitive, + 1, + 0, + multiple: false, + label: { text: "This scheme contains confidential information" } %> + <% end %> <% null_option = [OpenStruct.new(id: "", name: "Select an option")] %> <% organisations = Organisation.all.map { |org| OpenStruct.new(id: org.id, name: org.name) } %> diff --git a/app/views/schemes/show.html.erb b/app/views/schemes/show.html.erb index e9cbc909f..dab90cd8a 100644 --- a/app/views/schemes/show.html.erb +++ b/app/views/schemes/show.html.erb @@ -16,9 +16,11 @@
<%= govuk_summary_list do |summary_list| %> <% @scheme.display_attributes.each do |attr| %> + <% next if current_user.data_coordinator? && attr[:name] == ("Housing stock owned by") %> <%= summary_list.row do |row| %> <% row.key { attr[:name].eql?("Registered under Care Standards Act 2000") ? "Registered under Care Standards Act 2000" : attr[:name].to_s.humanize } %> <% row.value { details_html(attr) } %> + <% row.action(text: "Change", href: scheme_edit_name_path(scheme_id: @scheme.id)) if attr[:edit] %> <% end %> <% end %> <% end %> diff --git a/config/routes.rb b/config/routes.rb index a643f2ab4..7b18a6fce 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -42,6 +42,7 @@ Rails.application.routes.draw do get "support", to: "schemes#support" get "details", to: "schemes#details" get "check-answers", to: "schemes#check_answers" + get "edit-name", to: "schemes#edit_name" member do resources :locations diff --git a/spec/features/schemes_spec.rb b/spec/features/schemes_spec.rb index 6408bbf68..5999d09a0 100644 --- a/spec/features/schemes_spec.rb +++ b/spec/features/schemes_spec.rb @@ -665,5 +665,64 @@ RSpec.describe "Schemes scheme Features" do end end end + + context "when editing a scheme" do + context "when I visit schemes page" do + before do + visit("schemes") + end + + it "shows list of links to schemes" do + schemes.each do |scheme| + expect(page).to have_link(scheme.service_name) + expect(page).to have_content(scheme.primary_client_group) + end + end + + context "when I click to see individual scheme" do + let(:scheme) { schemes.first } + + before do + click_link(scheme.service_name) + end + + it "shows me details about the selected scheme" do + expect(page).to have_content(schemes.first.id_to_display) + expect(page).to have_content(schemes.first.service_name) + expect(page).to have_content(schemes.first.sensitive) + expect(page).to have_content(schemes.first.scheme_type) + expect(page).to have_content(schemes.first.registered_under_care_act) + expect(page).to have_content(schemes.first.primary_client_group) + expect(page).to have_content(schemes.first.secondary_client_group) + expect(page).to have_content(schemes.first.support_type) + expect(page).to have_content(schemes.first.intended_stay) + end + + context "when I click to change scheme name" do + before do + click_link("Change", href: "/schemes/#{scheme.id}/edit-name", match: :first) + end + + it "shows available fields to edit" do + expect(page).to have_current_path("/schemes/#{scheme.id}/edit-name") + expect(page).to have_content "Scheme details" + end + + context "when I edit details" do + before do + fill_in "Scheme name", with: "FooBar" + check "This scheme contains confidential information" + click_button "Save changes" + end + + it "lets me see amended details on the show page" do + expect(page).to have_content "FooBar" + expect(page).to have_current_path("/schemes/#{scheme.id}") + end + end + end + end + end + end end end diff --git a/spec/requests/schemes_controller_spec.rb b/spec/requests/schemes_controller_spec.rb index 0f7ef59a5..2d92c7385 100644 --- a/spec/requests/schemes_controller_spec.rb +++ b/spec/requests/schemes_controller_spec.rb @@ -213,7 +213,6 @@ RSpec.describe SchemesController, type: :request do get "/schemes/#{specific_scheme.id}" expect(page).to have_content(specific_scheme.id_to_display) expect(page).to have_content(specific_scheme.service_name) - expect(page).to have_content(specific_scheme.owning_organisation.name) expect(page).to have_content(specific_scheme.sensitive) expect(page).to have_content(specific_scheme.id_to_display) expect(page).to have_content(specific_scheme.service_name) @@ -615,6 +614,22 @@ RSpec.describe SchemesController, type: :request do end end end + + context "when editing scheme name details" do + let(:params) { { scheme: { service_name: "testy", sensitive: "1", page: "edit-name" } } } + + it "renders scheme show page after successful update" do + follow_redirect! + expect(response).to have_http_status(:ok) + expect(page).to have_content(scheme_to_update.reload.service_name) + end + + it "updates a scheme with valid params" do + follow_redirect! + expect(scheme_to_update.reload.service_name).to eq("testy") + expect(scheme_to_update.reload.sensitive).to eq("Yes") + end + end end context "when signed in as a support" do @@ -810,6 +825,29 @@ RSpec.describe SchemesController, type: :request do end end end + + context "when editing scheme name details" do + let(:another_organisation) { FactoryBot.create(:organisation) } + let(:params) do + { scheme: { service_name: "testy", + sensitive: "1", + page: "edit-name", + owning_organisation_id: another_organisation.id } } + end + + it "renders scheme show page after successful update" do + follow_redirect! + expect(response).to have_http_status(:ok) + expect(page).to have_content(scheme_to_update.reload.service_name) + expect(scheme_to_update.reload.owning_organisation_id).to eq(another_organisation.id) + end + + it "updates a scheme with valid params" do + follow_redirect! + expect(scheme_to_update.reload.service_name).to eq("testy") + expect(scheme_to_update.reload.sensitive).to eq("Yes") + end + end end end @@ -1208,4 +1246,74 @@ RSpec.describe SchemesController, type: :request do end end end + + describe "#edit_name" do + context "when not signed in" do + it "redirects to the sign in page" do + get "/schemes/1/edit-name" + expect(response).to redirect_to("/account/sign-in") + end + end + + context "when signed in as a data provider" do + let(:user) { FactoryBot.create(:user) } + + before do + sign_in user + get "/schemes/1/edit-name" + end + + it "returns 401 unauthorized" do + request + expect(response).to have_http_status(:unauthorized) + end + end + + context "when signed in as a data coordinator" do + let(:user) { FactoryBot.create(:user, :data_coordinator) } + let!(:scheme) { FactoryBot.create(:scheme, owning_organisation: user.organisation) } + let!(:another_scheme) { FactoryBot.create(:scheme) } + + before do + sign_in user + get "/schemes/#{scheme.id}/edit-name" + end + + it "returns a template for a edit-name" do + expect(response).to have_http_status(:ok) + expect(page).to have_content("Scheme details") + expect(page).to have_content("This scheme contains confidential information") + expect(page).not_to have_content("Which organisation owns the housing stock for this scheme?") + end + + context "when attempting to access secondary-client-group scheme page for another organisation" do + before do + get "/schemes/#{another_scheme.id}/edit-name" + end + + it "returns 404 not_found" do + request + expect(response).to have_http_status(:not_found) + end + end + end + + context "when signed in as a support user" do + let(:user) { FactoryBot.create(:user, :support) } + let!(:scheme) { FactoryBot.create(:scheme) } + + before do + allow(user).to receive(:need_two_factor_authentication?).and_return(false) + sign_in user + get "/schemes/#{scheme.id}/edit-name" + end + + it "returns a template for a secondary-client-group" do + expect(response).to have_http_status(:ok) + expect(page).to have_content("Scheme details") + expect(page).to have_content("This scheme contains confidential information") + expect(page).to have_content("Which organisation owns the housing stock for this scheme?") + end + end + end end From 3e920511a1da24d5e2f30de870adc53f93738f6e Mon Sep 17 00:00:00 2001 From: baarkerlounger <5101747+baarkerlounger@users.noreply.github.com> Date: Fri, 8 Jul 2022 10:58:22 +0100 Subject: [PATCH 02/11] CLDC-1329: Add plausible analytics script (#718) * Add plausible analytics script * Lint --- app/views/layouts/application.html.erb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index cd71ae510..859fe4249 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -33,6 +33,10 @@ console.log(<%= session.to_json.html_safe %>) <% end %> + + <% if Rails.env.production? %> + + <% end %> From 47c32d6cbeab0720dd1c9ec1e8be51e415dbb6f6 Mon Sep 17 00:00:00 2001 From: baarkerlounger Date: Fri, 8 Jul 2022 11:33:01 +0100 Subject: [PATCH 03/11] Bump deps --- Gemfile.lock | 4 +- app/views/layouts/application.html.erb | 2 +- yarn.lock | 108 ++++++++++++------------- 3 files changed, 57 insertions(+), 57 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index e2827bbed..bc6d661d7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -82,7 +82,7 @@ GEM public_suffix (>= 2.0.2, < 5.0) ast (2.4.2) aws-eventstream (1.2.0) - aws-partitions (1.602.0) + aws-partitions (1.603.0) aws-sdk-core (3.131.2) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.525.0) @@ -168,7 +168,7 @@ GEM ffi (1.15.5) globalid (1.0.0) activesupport (>= 5.0) - govuk-components (3.1.2) + govuk-components (3.1.3) actionpack (>= 6.1) activemodel (>= 6.1) html-attributes-utils (~> 0.9, >= 0.9.2) diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 859fe4249..72f51f2f1 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -35,7 +35,7 @@ <% end %> <% if Rails.env.production? %> - + <% end %> diff --git a/yarn.lock b/yarn.lock index eb2ae96be..a5df5932c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -86,9 +86,9 @@ "@babel/highlight" "^7.18.6" "@babel/compat-data@^7.13.11", "@babel/compat-data@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.6.tgz#8b37d24e88e8e21c499d4328db80577d8882fa53" - integrity sha512-tzulrgDT0QD6U7BJ4TKVk2SDDg7wlP39P9yAx1RfLy7vP/7rsDRlWVfbWxElslu56+r7QOhB2NSDsabYYruoZQ== + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.8.tgz#2483f565faca607b8535590e84e7de323f27764d" + integrity sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ== "@babel/core@^7.17.7": version "7.18.6" @@ -111,7 +111,7 @@ json5 "^2.2.1" semver "^6.3.0" -"@babel/generator@^7.18.6": +"@babel/generator@^7.18.6", "@babel/generator@^7.18.7": version "7.18.7" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.7.tgz#2aa78da3c05aadfc82dbac16c99552fc802284bd" integrity sha512-shck+7VLlY72a2w9c3zYWuE1pwOKEiQHV7GTUbSnhyl5eu3i04t30tBY82ZRWrDfo3gkakCFtevExnxbkf2a3A== @@ -222,9 +222,9 @@ "@babel/types" "^7.18.6" "@babel/helper-module-transforms@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.6.tgz#57e3ca669e273d55c3cda55e6ebf552f37f483c8" - integrity sha512-L//phhB4al5uucwzlimruukHB3jRd5JGClwRMD/ROrVjXfLqovYnvQrK/JK36WYyVwGGO7OD3kMyVTjx+WVPhw== + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.8.tgz#4f8408afead0188cfa48672f9d0e5787b61778c8" + integrity sha512-che3jvZwIcZxrwh63VfnFTUzcAM9v/lznYkkRxIBGMPt1SudOKHAEec0SIRCfiuIzTcF7VGj/CaTT6gY4eWxvA== dependencies: "@babel/helper-environment-visitor" "^7.18.6" "@babel/helper-module-imports" "^7.18.6" @@ -232,8 +232,8 @@ "@babel/helper-split-export-declaration" "^7.18.6" "@babel/helper-validator-identifier" "^7.18.6" "@babel/template" "^7.18.6" - "@babel/traverse" "^7.18.6" - "@babel/types" "^7.18.6" + "@babel/traverse" "^7.18.8" + "@babel/types" "^7.18.8" "@babel/helper-optimise-call-expression@^7.18.6": version "7.18.6" @@ -327,10 +327,10 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.18.6", "@babel/parser@^7.6.0", "@babel/parser@^7.9.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.6.tgz#845338edecad65ebffef058d3be851f1d28a63bc" - integrity sha512-uQVSa9jJUe/G/304lXspfWVpKpK4euFLgGiMQFOCpM/bgcAdeoHwi/OQz23O9GK2osz26ZiXRRV9aV+Yl1O8tw== +"@babel/parser@^7.18.6", "@babel/parser@^7.18.8", "@babel/parser@^7.6.0", "@babel/parser@^7.9.6": + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.8.tgz#822146080ac9c62dac0823bb3489622e0bc1cbdf" + integrity sha512-RSKRfYX20dyH+elbJK2uqAkVyucL+xXzhqlMD5/ZXx+dAAwpyB7HsvnHe/ZUGOF+xLr5Wx9/JoXVTj6BQE2/oA== "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.18.6": version "7.18.6" @@ -613,9 +613,9 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-classes@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.6.tgz#3501a8f3f4c7d5697c27a3eedbee71d68312669f" - integrity sha512-XTg8XW/mKpzAF3actL554Jl/dOYoJtv3l8fxaEczpgz84IeeVf+T1u2CSvPHuZbt0w3JkIx4rdn/MRQI7mo0HQ== + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.8.tgz#7e85777e622e979c85c701a095280360b818ce49" + integrity sha512-RySDoXdF6hgHSHuAW4aLGyVQdmvEX/iJtjVre52k0pxRq4hzqze+rAVP++NmNv596brBpYmaiKgTZby7ziBnVg== dependencies: "@babel/helper-annotate-as-pure" "^7.18.6" "@babel/helper-environment-visitor" "^7.18.6" @@ -664,9 +664,9 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-transform-for-of@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.6.tgz#e0fdb813be908e91ccc9ec87b30cc2eabf046f7c" - integrity sha512-WAjoMf4wIiSsy88KmG7tgj2nFdEK7E46tArVtcgED7Bkj6Fg/tG5SbvNIOKxbFS2VFgNh6+iaPswBeQZm4ox8w== + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz#6ef8a50b244eb6a0bdbad0c7c61877e4e30097c1" + integrity sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ== dependencies: "@babel/helper-plugin-utils" "^7.18.6" @@ -755,9 +755,9 @@ "@babel/helper-replace-supers" "^7.18.6" "@babel/plugin-transform-parameters@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.6.tgz#cbe03d5a4c6385dd756034ac1baa63c04beab8dc" - integrity sha512-FjdqgMv37yVl/gwvzkcB+wfjRI8HQmc5EgOG9iGNvUY1ok+TjsoaMP7IqCDZBhkFcM5f3OPVMs6Dmp03C5k4/A== + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz#ee9f1a0ce6d78af58d0956a9378ea3427cccb48a" + integrity sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg== dependencies: "@babel/helper-plugin-utils" "^7.18.6" @@ -954,26 +954,26 @@ "@babel/parser" "^7.18.6" "@babel/types" "^7.18.6" -"@babel/traverse@^7.13.0", "@babel/traverse@^7.18.6": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.6.tgz#a228562d2f46e89258efa4ddd0416942e2fd671d" - integrity sha512-zS/OKyqmD7lslOtFqbscH6gMLFYOfG1YPqCKfAW5KrTeolKqvB8UelR49Fpr6y93kYkW2Ik00mT1LOGiAGvizw== +"@babel/traverse@^7.13.0", "@babel/traverse@^7.18.6", "@babel/traverse@^7.18.8": + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.8.tgz#f095e62ab46abf1da35e5a2011f43aee72d8d5b0" + integrity sha512-UNg/AcSySJYR/+mIcJQDCv00T+AqRO7j/ZEJLzpaYtgM48rMg5MnkJgyNqkzo88+p4tfRvZJCEiwwfG6h4jkRg== dependencies: "@babel/code-frame" "^7.18.6" - "@babel/generator" "^7.18.6" + "@babel/generator" "^7.18.7" "@babel/helper-environment-visitor" "^7.18.6" "@babel/helper-function-name" "^7.18.6" "@babel/helper-hoist-variables" "^7.18.6" "@babel/helper-split-export-declaration" "^7.18.6" - "@babel/parser" "^7.18.6" - "@babel/types" "^7.18.6" + "@babel/parser" "^7.18.8" + "@babel/types" "^7.18.8" debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.18.6", "@babel/types@^7.18.7", "@babel/types@^7.4.4", "@babel/types@^7.6.1", "@babel/types@^7.9.6": - version "7.18.7" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.7.tgz#a4a2c910c15040ea52cdd1ddb1614a65c8041726" - integrity sha512-QG3yxTcTIBoAcQmkCs+wAPYZhu7Dk9rXKacINfNbdJDNERTbLQbHGyVG8q/YGMPeCJRIhSY0+fTc5+xuh6WPSQ== +"@babel/types@^7.18.6", "@babel/types@^7.18.7", "@babel/types@^7.18.8", "@babel/types@^7.4.4", "@babel/types@^7.6.1", "@babel/types@^7.9.6": + version "7.18.8" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.8.tgz#c5af199951bf41ba4a6a9a6d0d8ad722b30cd42f" + integrity sha512-qwpdsmraq0aJ3osLJRApsc2ouSJCdnMeZwB0DhbtHAtRpZNZCdlbRnHIgcRKzdE1g0iOGg644fzjOBcdOz9cPw== dependencies: "@babel/helper-validator-identifier" "^7.18.6" to-fast-properties "^2.0.0" @@ -1045,9 +1045,9 @@ "@jridgewell/trace-mapping" "^0.3.9" "@jridgewell/resolve-uri@^3.0.3": - version "3.0.8" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.8.tgz#687cc2bbf243f4e9a868ecf2262318e2658873a1" - integrity sha512-YK5G9LaddzGbcucK4c8h5tWFmMPBvRZ/uyWmN1/SbBdIvqGUdWGkJ5BAaccgs6XbzVLsqbPJrBSFwKv3kT9i7w== + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== "@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1": version "1.1.2" @@ -1228,9 +1228,9 @@ integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== "@types/node@*", "@types/node@>=10.0.0": - version "18.0.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.1.tgz#e91bd73239b338557a84d1f67f7b9e0f25643870" - integrity sha512-CmR8+Tsy95hhwtZBKJBs0/FFq4XX7sDZHlGGf+0q+BRZfMbOTkzkj0AFAuTyXbObDIoanaBBW0+KEW+m3N16Wg== + version "18.0.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.3.tgz#463fc47f13ec0688a33aec75d078a0541a447199" + integrity sha512-HzNRZtp4eepNitP+BD6k2L6DROIDG4Q0fm4x+dwfsr6LGmROENnok75VGw40628xf+iR24WeMFcHuuBDUAzzsQ== "@types/normalize-package-data@^2.4.0": version "2.4.1" @@ -2384,9 +2384,9 @@ ejs@^3.1.6: jake "^10.8.5" electron-to-chromium@^1.4.172: - version "1.4.178" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.178.tgz#3dae6fda486007bb54bbfed420ebd40881a3de45" - integrity sha512-aWuhJXkwIdoQzGR8p2QvR3N0OzdUKZSP8+P/hzuMzNQIPZoEa8HiCGM75bQBHjyz+eKT5PB9dVCzkK/tyQ4B5Q== + version "1.4.184" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.184.tgz#381d4d111fc82d3376ed690dfb621e675f9078a9" + integrity sha512-IADi390FRdvxWfVX3hjzfTDNVHiTqVo9ar53/7em/SfhUG9YcjVhyQecY/XwmBHRKden/wFud7RWOUH7+7LFng== element-closest@^2.0.2: version "2.0.2" @@ -3126,9 +3126,9 @@ globjoin@^0.1.4: integrity sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg== govuk-eleventy-plugin@^2.4.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/govuk-eleventy-plugin/-/govuk-eleventy-plugin-2.7.0.tgz#f767d12a7202a2410dde2e914d2dcdec0b57df4e" - integrity sha512-WlaZR9Ml9atHJUXFFgXqEfrE8RlPNLfm6/rTa22gkZPazV22VrfVtAeqmGMcSWNx0My8neFUM8HeIGI12oSgfg== + version "2.7.2" + resolved "https://registry.yarnpkg.com/govuk-eleventy-plugin/-/govuk-eleventy-plugin-2.7.2.tgz#629e5e0c1c8c99e301e5a3ad72afca2d17d71325" + integrity sha512-CsqK39J0uSodQFzNjCjZv1FdyyZvTpMQ1jIhTu7wohCdVTlnzMgNQojkE5Nn4LKxFsV1OZ9DSzgeqn+aeozXtw== dependencies: "@11ty/eleventy" "^1.0.0" "@11ty/eleventy-navigation" "^0.3.2" @@ -3757,9 +3757,9 @@ jstransformer@1.0.0: promise "^7.0.1" "jsx-ast-utils@^2.4.1 || ^3.0.0": - version "3.3.1" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.1.tgz#a3e0f1cb7e230954eab4dcbce9f6288a78f8ba44" - integrity sha512-pxrjmNpeRw5wwVeWyEAk7QJu2GnBO3uzPFmHCKJJFPKK2Cy0cWL23krGtLdnMmbIi6/FjlrQpPyfQI19ByPOhQ== + version "3.3.2" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.2.tgz#afe5efe4332cd3515c065072bd4d6b0aa22152bd" + integrity sha512-4ZCADZHRkno244xlNnn4AOG6sRQ7iBZ5BbgZ4vW4y5IZw7cVUD1PPeblm1xx/nfmMxPdt/LHsXZW8z/j58+l9Q== dependencies: array-includes "^3.1.5" object.assign "^4.1.2" @@ -3822,9 +3822,9 @@ linkify-it@^3.0.1: uc.micro "^1.0.1" liquidjs@^9.36.1: - version "9.37.0" - resolved "https://registry.yarnpkg.com/liquidjs/-/liquidjs-9.37.0.tgz#58e0dd2fa779635ead589e82cfa9baffe49f490e" - integrity sha512-qDj9iiNdB+QNZTR4iKjiQzoHQma7V8Itx5oZG/ZCP7xjebh1LI+s5IG2ZYUbs1ALO6hBzmW36Ptd8RR4eohuDA== + version "9.38.0" + resolved "https://registry.yarnpkg.com/liquidjs/-/liquidjs-9.38.0.tgz#0fb4d380007ecde00d8c43c5fd5535d6189b7778" + integrity sha512-LDGPbOfc8L9LG7ZSG0NueTcCe0AZzJAIa0BjYgMnCR+4VO0yS+AnOZjx0WOih8mtLRNSIYo9fik5exY6Cf4TOQ== list-to-array@^1.1.0: version "1.1.0" @@ -5038,9 +5038,9 @@ rimraf@^3.0.2: glob "^7.1.3" rollup@^2.62.0: - version "2.75.7" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.75.7.tgz#221ff11887ae271e37dcc649ba32ce1590aaa0b9" - integrity sha512-VSE1iy0eaAYNCxEXaleThdFXqZJ42qDBatAwrfnPlENEZ8erQ+0LYX4JXOLPceWfZpV1VtZwZ3dFCuOZiSyFtQ== + version "2.76.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.76.0.tgz#c69fe03db530ac53fcb9523b3caa0d3c0b9491a1" + integrity sha512-9jwRIEY1jOzKLj3nsY/yot41r19ITdQrhs+q3ggNWhr9TQgduHqANvPpS32RNpzGklJu3G1AJfvlZLi/6wFgWA== optionalDependencies: fsevents "~2.3.2" From e87fc8bae65c4d61b8767fbab8b439a84a07513e Mon Sep 17 00:00:00 2001 From: baarkerlounger Date: Fri, 8 Jul 2022 12:37:48 +0100 Subject: [PATCH 04/11] Domain string --- app/views/layouts/application.html.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 72f51f2f1..0774567c3 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -35,7 +35,7 @@ <% end %> <% if Rails.env.production? %> - + <% end %> From 7801a142f9a716a9f01fec14240deab641d87864 Mon Sep 17 00:00:00 2001 From: baarkerlounger Date: Fri, 8 Jul 2022 14:52:49 +0100 Subject: [PATCH 05/11] Add spec command to docker dev setup --- docs/developer_setup.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/developer_setup.md b/docs/developer_setup.md index acc1542a7..d01ddb982 100644 --- a/docs/developer_setup.md +++ b/docs/developer_setup.md @@ -193,3 +193,9 @@ We recommend using [RBenv](https://github.com/rbenv/rbenv) to manage Ruby versio If this is not needed you can run `docker-compose up` as normal The Rails server will start on . + +5. To run the test suite in docker: + + ```bash + docker-compose run --rm app /bin/bash -c ' RAILS_ENV=test rspec' + ``` From 3aa7765194f72e1edd7121cf2b70ffef07097634 Mon Sep 17 00:00:00 2001 From: J G <7750475+moarpheus@users.noreply.github.com> Date: Fri, 8 Jul 2022 15:03:01 +0100 Subject: [PATCH 06/11] Cldc 1292 permitted user can edit location name (#719) * added test to check locations * added test to click to change location * added edit name to routes and front * edit name request specs * finilised * tab nav helper test * specs for update * rubo --- app/controllers/locations_controller.rb | 17 ++- app/helpers/tab_nav_helper.rb | 5 + app/views/locations/edit.html.erb | 2 + app/views/locations/edit_name.html.erb | 26 +++++ app/views/locations/index.html.erb | 2 +- config/routes.rb | 4 +- db/seeds.rb | 12 +-- spec/features/schemes_spec.rb | 47 ++++++++ spec/helpers/tab_nav_helper_spec.rb | 7 ++ spec/requests/locations_controller_spec.rb | 120 ++++++++++++++++++--- 10 files changed, 217 insertions(+), 25 deletions(-) create mode 100644 app/views/locations/edit_name.html.erb diff --git a/app/controllers/locations_controller.rb b/app/controllers/locations_controller.rb index d12968cc7..d08a14209 100644 --- a/app/controllers/locations_controller.rb +++ b/app/controllers/locations_controller.rb @@ -27,9 +27,18 @@ class LocationsController < ApplicationController def edit; end + def edit_name; end + def update + page = params[:location][:page] + if @location.update(location_params) - location_params[:add_another_location] == "Yes" ? redirect_to(new_location_path(@location.scheme)) : redirect_to(scheme_check_answers_path(@scheme, anchor: "locations")) + case page + when "edit" + location_params[:add_another_location] == "Yes" ? redirect_to(new_location_path(@location.scheme)) : redirect_to(scheme_check_answers_path(@scheme, anchor: "locations")) + when "edit-name" + redirect_to(locations_path(@scheme)) + end else render :edit, status: :unprocessable_entity end @@ -38,7 +47,7 @@ class LocationsController < ApplicationController private def find_scheme - @scheme = if %w[new create index].include?(action_name) + @scheme = if %w[new create index edit_name].include?(action_name) Scheme.find(params[:id]) else @location.scheme @@ -46,7 +55,7 @@ private end def find_location - @location = Location.find(params[:id]) + @location = params[:location_id].present? ? Location.find(params[:location_id]) : Location.find(params[:id]) end def authenticate_scope! @@ -54,7 +63,7 @@ private end def authenticate_action! - if %w[new edit update create index].include?(action_name) && !((current_user.organisation == @scheme.owning_organisation) || current_user.support?) + if %w[new edit update create index edit_name].include?(action_name) && !((current_user.organisation == @scheme.owning_organisation) || current_user.support?) render_not_found and return end end diff --git a/app/helpers/tab_nav_helper.rb b/app/helpers/tab_nav_helper.rb index 3ef211401..0cba9f8e4 100644 --- a/app/helpers/tab_nav_helper.rb +++ b/app/helpers/tab_nav_helper.rb @@ -11,6 +11,11 @@ module TabNavHelper [govuk_link_to(link_text, "/schemes/#{location.scheme.id}/locations/#{location.id}/edit", method: :patch), "Location #{location.name}"].join("\n") end + def edit_location_name_cell(location) + link_text = location.postcode + [govuk_link_to(link_text, "/schemes/#{location.scheme.id}/locations/#{location.id}/edit-name", method: :patch), "Location #{location.name}"].join("\n") + end + def scheme_cell(scheme) link_text = scheme.service_name [govuk_link_to(link_text, scheme), "Scheme #{scheme.primary_client_group}"].join("\n") diff --git a/app/views/locations/edit.html.erb b/app/views/locations/edit.html.erb index bbcccdef6..e8a38ecb3 100644 --- a/app/views/locations/edit.html.erb +++ b/app/views/locations/edit.html.erb @@ -57,6 +57,8 @@ inline: true, legend: { text: "Do you want to add another location?", size: "m" } %> + <%= f.hidden_field :page, value: "edit" %> + <%= f.govuk_submit "Save and continue" %>
diff --git a/app/views/locations/edit_name.html.erb b/app/views/locations/edit_name.html.erb new file mode 100644 index 000000000..22ce4be1f --- /dev/null +++ b/app/views/locations/edit_name.html.erb @@ -0,0 +1,26 @@ +<% content_for :title, "Location name for #{@location.postcode}" %> + +<% content_for :before_content do %> + <%= govuk_back_link( + text: "Back", + href: "/schemes/#{@scheme.id}/locations", + ) %> +<% end %> + +<%= render partial: "organisations/headings", locals: { main: "Location name for #{@location.postcode}", sub: @scheme.service_name } %> + +<%= form_for(@location, method: :patch, url: location_path(location_id: @location.id)) do |f| %> +
+
+ <%= f.govuk_error_summary %> + + <%= f.govuk_text_field :name, + label: { hidden: true }, + hint: { text: "This is how you refer to this location within your organisation" } %> + + <%= f.hidden_field :page, value: "edit-name" %> + + <%= f.govuk_submit "Save and continue" %> +
+
+<% end %> diff --git a/app/views/locations/index.html.erb b/app/views/locations/index.html.erb index 6d3cc3de3..88bff9ca4 100644 --- a/app/views/locations/index.html.erb +++ b/app/views/locations/index.html.erb @@ -36,7 +36,7 @@ <%= table.body do |body| %> <%= body.row do |row| %> <% row.cell(text: location.id) %> - <% row.cell(text: location.postcode) %> + <% row.cell(text: simple_format(edit_location_name_cell(location), { class: "govuk-!-font-weight-bold" }, wrapper_tag: "div")) %> <% row.cell(text: location.total_units) %> <% row.cell(text: simple_format("#{location.type_of_unit}#{location.wheelchair_adaptation == 'Yes' ? "\nWith wheelchair adaptations" : ''}")) %> <% end %> diff --git a/config/routes.rb b/config/routes.rb index 7b18a6fce..de42be41a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -45,7 +45,9 @@ Rails.application.routes.draw do get "edit-name", to: "schemes#edit_name" member do - resources :locations + resources :locations do + get "edit-name", to: "locations#edit_name" + end end end diff --git a/db/seeds.rb b/db/seeds.rb index 175922921..be13a937c 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -79,7 +79,7 @@ unless Rails.env.test? intended_stay: "M", primary_client_group: "O", secondary_client_group: "H", - organisation: org, + owning_organisation: org, created_at: Time.zone.now, ) @@ -92,7 +92,7 @@ unless Rails.env.test? intended_stay: "S", primary_client_group: "D", secondary_client_group: "E", - organisation: org, + owning_organisation: org, created_at: Time.zone.now, ) @@ -105,14 +105,14 @@ unless Rails.env.test? intended_stay: "X", primary_client_group: "G", secondary_client_group: "R", - organisation: dummy_org, + owning_organisation: dummy_org, created_at: Time.zone.now, ) Location.create!( scheme: scheme1, location_code: "S254-CU193AA", - postcode: "CU19 3AA", + postcode: "CU193AA", name: "Rectory Road", type_of_unit: 4, type_of_building: "Purpose-built", @@ -123,7 +123,7 @@ unless Rails.env.test? Location.create!( scheme: scheme1, location_code: "S254-DM250DC", - postcode: "DM25 0DC", + postcode: "DM250DC", name: "Smithy Lane", type_of_unit: 1, type_of_building: "Converted from previous residential or non-residential property", @@ -134,7 +134,7 @@ unless Rails.env.test? Location.create!( scheme: scheme2, location_code: "S254-YX130WP", - postcode: "YX13 0WP", + postcode: "YX130WP", name: "Smithy Lane", type_of_unit: 2, type_of_building: "Converted from previous residential or non-residential property", diff --git a/spec/features/schemes_spec.rb b/spec/features/schemes_spec.rb index 5999d09a0..43f966c1c 100644 --- a/spec/features/schemes_spec.rb +++ b/spec/features/schemes_spec.rb @@ -681,6 +681,7 @@ RSpec.describe "Schemes scheme Features" do context "when I click to see individual scheme" do let(:scheme) { schemes.first } + let!(:location) { FactoryBot.create(:location, scheme:) } before do click_link(scheme.service_name) @@ -721,6 +722,52 @@ RSpec.describe "Schemes scheme Features" do end end end + + context "when I click to see locations" do + before do + click_link "1 location" + end + + it "I see location details" do + expect(page).to have_content scheme.locations.first.id + expect(page).to have_current_path("/schemes/#{scheme.id}/locations") + end + + context "when I click to change location name" do + before do + click_link(location.postcode) + end + + it "shows available fields to edit" do + expect(page).to have_current_path("/schemes/#{scheme.id}/locations/#{location.id}/edit-name") + expect(page).to have_content "Location name for #{location.postcode}" + end + + context "when I press the back button" do + before do + click_link "Back" + end + + it "I see location details" do + expect(page).to have_content scheme.locations.first.id + expect(page).to have_current_path("/schemes/#{scheme.id}/locations") + end + end + + context "and I change the location name" do + before do + fill_in "location-name-field", with: "NewName" + click_button "Save and continue" + end + + it "returns to locations page and shows the new name" do + expect(page).to have_content location.id + expect(page).to have_content "NewName" + expect(page).to have_current_path("/schemes/#{scheme.id}/locations") + end + end + end + end end end end diff --git a/spec/helpers/tab_nav_helper_spec.rb b/spec/helpers/tab_nav_helper_spec.rb index 3403ce490..8afc45193 100644 --- a/spec/helpers/tab_nav_helper_spec.rb +++ b/spec/helpers/tab_nav_helper_spec.rb @@ -20,6 +20,13 @@ RSpec.describe TabNavHelper do end end + describe "#edit_location_name_cell" do + it "returns the location link to the postcode with optional name" do + expected_html = "#{location.postcode}\nLocation #{location.name}" + expect(edit_location_name_cell(location)).to match(expected_html) + end + end + describe "#location_cell" do it "returns the location link to the postcode with optional name" do expected_html = "#{location.postcode}\nLocation #{location.name}" diff --git a/spec/requests/locations_controller_spec.rb b/spec/requests/locations_controller_spec.rb index cba28a541..e3909e754 100644 --- a/spec/requests/locations_controller_spec.rb +++ b/spec/requests/locations_controller_spec.rb @@ -390,7 +390,7 @@ RSpec.describe LocationsController, type: :request do let(:user) { FactoryBot.create(:user, :data_coordinator) } let!(:scheme) { FactoryBot.create(:scheme, owning_organisation: user.organisation) } let!(:location) { FactoryBot.create(:location, scheme:) } - let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", add_another_location: "No", postcode: "ZZ1 1ZZ" } } } + let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", add_another_location: "No", postcode: "ZZ1 1ZZ", page: "edit" } } } before do sign_in user @@ -412,8 +412,22 @@ RSpec.describe LocationsController, type: :request do expect(Location.last.wheelchair_adaptation).to eq("No") end + context "when updating from edit-name page" do + let(:params) { { location: { name: "Test", page: "edit-name" } } } + + it "updates existing location for scheme with valid params and redirects to correct page" do + follow_redirect! + expect(response).to have_http_status(:ok) + expect(page).to have_content("1 location") + end + + it "updates existing location for scheme with valid params" do + expect(Location.last.name).to eq("Test") + end + end + context "when postcode is submitted with lower case" do - let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", add_another_location: "No", postcode: "zz1 1zz" } } } + let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", add_another_location: "No", postcode: "zz1 1zz", page: "edit" } } } it "updates existing location for scheme with postcode " do expect(Location.last.postcode).to eq("ZZ11ZZ") @@ -423,7 +437,7 @@ RSpec.describe LocationsController, type: :request do context "when trying to update location for a scheme that belongs to another organisation" do let(:another_scheme) { FactoryBot.create(:scheme) } let(:another_location) { FactoryBot.create(:location) } - let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", add_another_location: "No", postcode: "ZZ1 1ZZ" } } } + let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", add_another_location: "No", postcode: "ZZ1 1ZZ", page: "edit" } } } it "displays the new page with an error message" do patch "/schemes/#{another_scheme.id}/locations/#{another_location.id}", params: params @@ -432,7 +446,7 @@ RSpec.describe LocationsController, type: :request do end context "when required postcode param is invalid" do - let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", add_another_location: "No", postcode: "invalid" } } } + let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", add_another_location: "No", postcode: "invalid", page: "edit" } } } it "displays the new page with an error message" do expect(response).to have_http_status(:unprocessable_entity) @@ -441,7 +455,7 @@ RSpec.describe LocationsController, type: :request do end context "when do you want to add another location is selected as yes" do - let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", add_another_location: "Yes", postcode: "ZZ1 1ZZ" } } } + let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", add_another_location: "Yes", postcode: "ZZ1 1ZZ", page: "edit" } } } it "updates existing location for scheme with valid params and redirects to correct page" do follow_redirect! @@ -459,7 +473,7 @@ RSpec.describe LocationsController, type: :request do end context "when do you want to add another location is selected as no" do - let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", add_another_location: "No", postcode: "ZZ1 1ZZ" } } } + let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", add_another_location: "No", postcode: "ZZ1 1ZZ", page: "edit" } } } it "updates existing location for scheme with valid params and redirects to correct page" do follow_redirect! @@ -477,7 +491,7 @@ RSpec.describe LocationsController, type: :request do end context "when do you want to add another location is not selected" do - let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", postcode: "ZZ1 1ZZ" } } } + let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", postcode: "ZZ1 1ZZ", page: "edit" } } } it "updates existing location for scheme with valid params and redirects to correct page" do follow_redirect! @@ -499,7 +513,7 @@ RSpec.describe LocationsController, type: :request do let(:user) { FactoryBot.create(:user, :data_coordinator) } let!(:scheme) { FactoryBot.create(:scheme, owning_organisation: user.organisation) } let!(:location) { FactoryBot.create(:location, scheme:) } - let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", add_another_location: "No", postcode: "ZZ1 1ZZ" } } } + let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", add_another_location: "No", postcode: "ZZ1 1ZZ", page: "edit" } } } before do allow(user).to receive(:need_two_factor_authentication?).and_return(false) @@ -521,8 +535,22 @@ RSpec.describe LocationsController, type: :request do expect(Location.last.wheelchair_adaptation).to eq("No") end + context "when updating from edit-name page" do + let(:params) { { location: { name: "Test", page: "edit-name" } } } + + it "updates existing location for scheme with valid params and redirects to correct page" do + follow_redirect! + expect(response).to have_http_status(:ok) + expect(page).to have_content("1 location") + end + + it "updates existing location for scheme with valid params" do + expect(Location.last.name).to eq("Test") + end + end + context "when postcode is submitted with lower case" do - let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", add_another_location: "No", postcode: "zz1 1zz" } } } + let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", add_another_location: "No", postcode: "zz1 1zz", page: "edit" } } } it "updates a location for scheme with postcode " do expect(Location.last.postcode).to eq("ZZ11ZZ") @@ -530,7 +558,7 @@ RSpec.describe LocationsController, type: :request do end context "when required postcode param is missing" do - let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", add_another_location: "No", postcode: "invalid" } } } + let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", add_another_location: "No", postcode: "invalid", page: "edit" } } } it "displays the new page with an error message" do expect(response).to have_http_status(:unprocessable_entity) @@ -539,7 +567,7 @@ RSpec.describe LocationsController, type: :request do end context "when do you want to add another location is selected as yes" do - let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", add_another_location: "Yes", postcode: "ZZ1 1ZZ" } } } + let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", add_another_location: "Yes", postcode: "ZZ1 1ZZ", page: "edit" } } } it "updates location for scheme with valid params and redirects to correct page" do follow_redirect! @@ -556,7 +584,7 @@ RSpec.describe LocationsController, type: :request do end context "when do you want to add another location is selected as no" do - let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", add_another_location: "No", postcode: "ZZ1 1ZZ" } } } + let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", add_another_location: "No", postcode: "ZZ1 1ZZ", page: "edit" } } } it "updates a location for scheme with valid params and redirects to correct page" do follow_redirect! @@ -573,7 +601,7 @@ RSpec.describe LocationsController, type: :request do end context "when do you want to add another location is not selected" do - let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", postcode: "ZZ1 1ZZ" } } } + let(:params) { { location: { name: "Test", total_units: "5", type_of_unit: "Bungalow", wheelchair_adaptation: "No", postcode: "ZZ1 1ZZ", page: "edit" } } } it "updates a location for scheme with valid params and redirects to correct page" do follow_redirect! @@ -781,4 +809,70 @@ RSpec.describe LocationsController, type: :request do end end end + + describe "#edit-name" do + context "when not signed in" do + it "redirects to the sign in page" do + get "/schemes/1/locations/1/edit-name" + expect(response).to redirect_to("/account/sign-in") + end + end + + context "when signed in as a data provider" do + let(:user) { FactoryBot.create(:user) } + + before do + sign_in user + get "/schemes/1/locations/1/edit-name" + end + + it "returns 401 unauthorized" do + request + expect(response).to have_http_status(:unauthorized) + end + end + + context "when signed in as a data coordinator" do + let(:user) { FactoryBot.create(:user, :data_coordinator) } + let!(:scheme) { FactoryBot.create(:scheme, owning_organisation: user.organisation) } + let!(:location) { FactoryBot.create(:location, scheme:) } + + before do + sign_in user + get "/schemes/#{scheme.id}/locations/#{location.id}/edit-name" + end + + it "returns a template for a edit-name" do + expect(response).to have_http_status(:ok) + expect(page).to have_content("Location name for #{location.postcode}") + end + + context "when trying to edit location name of location that belongs to another organisation" do + let(:another_scheme) { FactoryBot.create(:scheme) } + let(:another_location) { FactoryBot.create(:location, scheme: another_scheme) } + + it "displays the new page with an error message" do + get "/schemes/#{another_scheme.id}/locations/#{another_location.id}/edit-name" + expect(response).to have_http_status(:not_found) + end + end + end + + context "when signed in as a support user" do + let(:user) { FactoryBot.create(:user, :support) } + let!(:scheme) { FactoryBot.create(:scheme, owning_organisation: user.organisation) } + let!(:location) { FactoryBot.create(:location, scheme:) } + + before do + allow(user).to receive(:need_two_factor_authentication?).and_return(false) + sign_in user + get "/schemes/#{scheme.id}/locations/#{location.id}/edit-name" + end + + it "returns a template for a new location" do + expect(response).to have_http_status(:ok) + expect(page).to have_content("Location name for #{location.postcode}") + end + end + end end From 4afd3321ebf32089bddf7e553a818a0f31fe387e Mon Sep 17 00:00:00 2001 From: J G <7750475+moarpheus@users.noreply.github.com> Date: Mon, 11 Jul 2022 09:00:11 +0100 Subject: [PATCH 07/11] Small refactorings (#721) * location cell ref * extracted regex into initializer * extracted regex into initializer - part 2 * added PostcodeService to extract behavior * rubo * better test name * moved .delete.upcase to the PostcodeService class --- app/controllers/locations_controller.rb | 2 +- app/helpers/tab_nav_helper.rb | 9 ++------- app/models/case_log.rb | 4 ++-- app/models/location.rb | 3 +-- app/models/validations/local_authority_validations.rb | 2 -- app/models/validations/property_validations.rb | 1 - app/services/imports/case_logs_import_service.rb | 1 - app/services/postcode_service.rb | 5 +++++ app/views/locations/index.html.erb | 2 +- app/views/schemes/check_answers.html.erb | 2 +- config/initializers/postcode_regex.rb | 1 + spec/helpers/tab_nav_helper_spec.rb | 10 ++-------- spec/services/postcode_service_spec.rb | 9 +++++++++ 13 files changed, 25 insertions(+), 26 deletions(-) create mode 100644 app/services/postcode_service.rb create mode 100644 config/initializers/postcode_regex.rb create mode 100644 spec/services/postcode_service_spec.rb diff --git a/app/controllers/locations_controller.rb b/app/controllers/locations_controller.rb index d08a14209..e900a12ff 100644 --- a/app/controllers/locations_controller.rb +++ b/app/controllers/locations_controller.rb @@ -70,7 +70,7 @@ private def location_params required_params = params.require(:location).permit(:postcode, :name, :total_units, :type_of_unit, :wheelchair_adaptation, :add_another_location).merge(scheme_id: @scheme.id) - required_params[:postcode] = required_params[:postcode].delete(" ").upcase.encode("ASCII", "UTF-8", invalid: :replace, undef: :replace, replace: "") if required_params[:postcode] + required_params[:postcode] = PostcodeService.clean(required_params[:postcode]) if required_params[:postcode] required_params end end diff --git a/app/helpers/tab_nav_helper.rb b/app/helpers/tab_nav_helper.rb index 0cba9f8e4..1f6db638e 100644 --- a/app/helpers/tab_nav_helper.rb +++ b/app/helpers/tab_nav_helper.rb @@ -6,14 +6,9 @@ module TabNavHelper [govuk_link_to(link_text, user), "User #{user.email}"].join("\n") end - def location_cell(location) + def location_cell(location, link) link_text = location.postcode - [govuk_link_to(link_text, "/schemes/#{location.scheme.id}/locations/#{location.id}/edit", method: :patch), "Location #{location.name}"].join("\n") - end - - def edit_location_name_cell(location) - link_text = location.postcode - [govuk_link_to(link_text, "/schemes/#{location.scheme.id}/locations/#{location.id}/edit-name", method: :patch), "Location #{location.name}"].join("\n") + [govuk_link_to(link_text, link, method: :patch), "Location #{location.name}"].join("\n") end def scheme_cell(scheme) diff --git a/app/models/case_log.rb b/app/models/case_log.rb index 49c3a8a73..305582db2 100644 --- a/app/models/case_log.rb +++ b/app/models/case_log.rb @@ -585,12 +585,12 @@ private def get_inferred_la(postcode) # Avoid network calls when postcode is invalid - return unless postcode.match(Validations::PropertyValidations::POSTCODE_REGEXP) + return unless postcode.match(POSTCODE_REGEXP) postcode_lookup = nil begin # URI encoding only supports ASCII characters - ascii_postcode = postcode.encode("ASCII", "UTF-8", invalid: :replace, undef: :replace, replace: "") + ascii_postcode = PostcodeService.clean(postcode) Timeout.timeout(5) { postcode_lookup = PIO.lookup(ascii_postcode) } rescue Timeout::Error Rails.logger.warn("Postcodes.io lookup timed out") diff --git a/app/models/location.rb b/app/models/location.rb index c8be513eb..6718c79a7 100644 --- a/app/models/location.rb +++ b/app/models/location.rb @@ -1,5 +1,4 @@ class Location < ApplicationRecord - include Validations::PropertyValidations validate :validate_postcode belongs_to :scheme @@ -36,7 +35,7 @@ class Location < ApplicationRecord private def validate_postcode - if postcode.nil? || !postcode&.match(Validations::PropertyValidations::POSTCODE_REGEXP) + if postcode.nil? || !postcode&.match(POSTCODE_REGEXP) error_message = I18n.t("validations.postcode") errors.add :postcode, error_message end diff --git a/app/models/validations/local_authority_validations.rb b/app/models/validations/local_authority_validations.rb index a7b3ed30d..c895880bd 100644 --- a/app/models/validations/local_authority_validations.rb +++ b/app/models/validations/local_authority_validations.rb @@ -1,6 +1,4 @@ module Validations::LocalAuthorityValidations - POSTCODE_REGEXP = Validations::PropertyValidations::POSTCODE_REGEXP - def validate_previous_accommodation_postcode(record) postcode = record.ppostcode_full if record.previous_postcode_known? && (postcode.blank? || !postcode.match(POSTCODE_REGEXP)) diff --git a/app/models/validations/property_validations.rb b/app/models/validations/property_validations.rb index 050cdbd37..dc14fc8fd 100644 --- a/app/models/validations/property_validations.rb +++ b/app/models/validations/property_validations.rb @@ -1,7 +1,6 @@ module Validations::PropertyValidations # Validations methods need to be called 'validate_' to run on model save # or 'validate_' to run on submit as well - POSTCODE_REGEXP = /^(([A-Z]{1,2}[0-9][A-Z0-9]?|ASCN|STHL|TDCU|BBND|[BFS]IQQ|PCRN|TKCA) ?[0-9][A-Z]{2}|BFPO ?[0-9]{1,4}|(KY[0-9]|MSR|VG|AI)[ -]?[0-9]{4}|[A-Z]{2} ?[0-9]{2}|GE ?CX|GIR ?0A{2}|SAN ?TA1)$/i def validate_property_number_of_times_relet(record) return unless record.offered diff --git a/app/services/imports/case_logs_import_service.rb b/app/services/imports/case_logs_import_service.rb index 936218838..2a3f129df 100644 --- a/app/services/imports/case_logs_import_service.rb +++ b/app/services/imports/case_logs_import_service.rb @@ -417,7 +417,6 @@ module Imports end end - POSTCODE_REGEXP = Validations::PropertyValidations::POSTCODE_REGEXP def compose_postcode(xml_doc, outcode, incode) outcode_value = string_or_nil(xml_doc, outcode) incode_value = string_or_nil(xml_doc, incode) diff --git a/app/services/postcode_service.rb b/app/services/postcode_service.rb new file mode 100644 index 000000000..737e3fd9c --- /dev/null +++ b/app/services/postcode_service.rb @@ -0,0 +1,5 @@ +class PostcodeService + def self.clean(postcode) + postcode.encode("ASCII", "UTF-8", invalid: :replace, undef: :replace, replace: "").delete(" ").upcase + end +end diff --git a/app/views/locations/index.html.erb b/app/views/locations/index.html.erb index 88bff9ca4..a610fc80a 100644 --- a/app/views/locations/index.html.erb +++ b/app/views/locations/index.html.erb @@ -36,7 +36,7 @@ <%= table.body do |body| %> <%= body.row do |row| %> <% row.cell(text: location.id) %> - <% row.cell(text: simple_format(edit_location_name_cell(location), { class: "govuk-!-font-weight-bold" }, wrapper_tag: "div")) %> + <% row.cell(text: simple_format(location_cell(location, "/schemes/#{@scheme.id}/locations/#{location.id}/edit-name"), { class: "govuk-!-font-weight-bold" }, wrapper_tag: "div")) %> <% row.cell(text: location.total_units) %> <% row.cell(text: simple_format("#{location.type_of_unit}#{location.wheelchair_adaptation == 'Yes' ? "\nWith wheelchair adaptations" : ''}")) %> <% end %> diff --git a/app/views/schemes/check_answers.html.erb b/app/views/schemes/check_answers.html.erb index 2b521fcd6..7043fa502 100644 --- a/app/views/schemes/check_answers.html.erb +++ b/app/views/schemes/check_answers.html.erb @@ -89,7 +89,7 @@ <%= table.body do |body| %> <%= body.row do |row| %> <% row.cell(text: location.id) %> - <% row.cell(text: simple_format(location_cell(location), { class: "govuk-!-font-weight-bold" }, wrapper_tag: "div")) %> + <% row.cell(text: simple_format(location_cell(location, "/schemes/#{@scheme.id}/locations/#{location.id}/edit"), { class: "govuk-!-font-weight-bold" }, wrapper_tag: "div")) %> <% row.cell(text: location.total_units) %> <% row.cell(text: simple_format("#{location.type_of_unit}#{location.wheelchair_adaptation == 'Yes' ? "\nWith wheelchair adaptations" : ''}")) %> <% end %> diff --git a/config/initializers/postcode_regex.rb b/config/initializers/postcode_regex.rb new file mode 100644 index 000000000..1d68e6dec --- /dev/null +++ b/config/initializers/postcode_regex.rb @@ -0,0 +1 @@ +POSTCODE_REGEXP = /^(([A-Z]{1,2}[0-9][A-Z0-9]?|ASCN|STHL|TDCU|BBND|[BFS]IQQ|PCRN|TKCA) ?[0-9][A-Z]{2}|BFPO ?[0-9]{1,4}|(KY[0-9]|MSR|VG|AI)[ -]?[0-9]{4}|[A-Z]{2} ?[0-9]{2}|GE ?CX|GIR ?0A{2}|SAN ?TA1)$/i diff --git a/spec/helpers/tab_nav_helper_spec.rb b/spec/helpers/tab_nav_helper_spec.rb index 8afc45193..aa93b839d 100644 --- a/spec/helpers/tab_nav_helper_spec.rb +++ b/spec/helpers/tab_nav_helper_spec.rb @@ -20,17 +20,11 @@ RSpec.describe TabNavHelper do end end - describe "#edit_location_name_cell" do - it "returns the location link to the postcode with optional name" do - expected_html = "#{location.postcode}\nLocation #{location.name}" - expect(edit_location_name_cell(location)).to match(expected_html) - end - end - describe "#location_cell" do it "returns the location link to the postcode with optional name" do + link = "/schemes/#{location.scheme.id}/locations/#{location.id}/edit" expected_html = "#{location.postcode}\nLocation #{location.name}" - expect(location_cell(location)).to match(expected_html) + expect(location_cell(location, link)).to match(expected_html) end end diff --git a/spec/services/postcode_service_spec.rb b/spec/services/postcode_service_spec.rb new file mode 100644 index 000000000..ecf20fdac --- /dev/null +++ b/spec/services/postcode_service_spec.rb @@ -0,0 +1,9 @@ +require "rails_helper" + +describe PostcodeService do + let(:postcode) { "s r81LS\u00A0" } + + it "returns clean postcode" do + expect(described_class.clean(postcode)).to eq "SR81LS" + end +end From 75b46ff0f91d2ace20466086f3b61da0a1cee5cb Mon Sep 17 00:00:00 2001 From: baarkerlounger <5101747+baarkerlounger@users.noreply.github.com> Date: Mon, 11 Jul 2022 11:20:43 +0100 Subject: [PATCH 08/11] Install geckodriver in docker_dev (#720) * Install geckodriver in docker_dev * Add master key to docker builds since we don't currently build and store them anywhere --- .dockerignore | 2 -- Dockerfile_dev | 8 ++++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/.dockerignore b/.dockerignore index c4b1508ec..51af90c05 100644 --- a/.dockerignore +++ b/.dockerignore @@ -11,8 +11,6 @@ storage public/assets .byebug_history -config/master.key - public/packs public/packs-test node_modules diff --git a/Dockerfile_dev b/Dockerfile_dev index 81a3101c9..086e874ba 100644 --- a/Dockerfile_dev +++ b/Dockerfile_dev @@ -23,6 +23,14 @@ RUN bundle install ${BUNDLE_FLAGS} COPY package.json yarn.lock /app/ RUN yarn install --frozen-lockfile +# Install gecko driver for Capybara tests +RUN apk add firefox +RUN wget https://github.com/mozilla/geckodriver/releases/download/v0.31.0/geckodriver-v0.31.0-linux64.tar.gz \ + && tar -xvzf geckodriver-v0.31.0-linux64.tar.gz \ + && rm geckodriver-v0.31.0-linux64.tar.gz \ + && chmod +x geckodriver \ + && mv geckodriver /usr/local/bin/ + # Copy all files to /app (except what is defined in .dockerignore) COPY . /app/ From 8bd39704f940a2335858f8d0e69732c16d77464e Mon Sep 17 00:00:00 2001 From: kosiakkatrina <54268893+kosiakkatrina@users.noreply.github.com> Date: Mon, 11 Jul 2022 11:33:10 +0100 Subject: [PATCH 09/11] Cldc 809 supported housing questions (#713) * infer case_log values from schemes * only display relevant property information questions * Add unittype_sh column * Display the correct number of completed sections * fix schema and migration * Fix test failing in CI This test was failing due to some different between UTC and BST time as the record from the DB comes back with a UTC timezone. Comparing the integer values of both will ensure that both timestamps are identical and should fix the issue in the CI where it thinks the values are different * only run query for scheme locations size once Co-authored-by: Dushan * extract TYPE_OF_UNIT_MAP * lint * Use find insted of select Co-authored-by: Dushan Despotovic --- app/helpers/tasklist_helper.rb | 4 +- .../derived_variables/case_log_variables.rb | 28 +++++++- app/models/form/subsection.rb | 2 +- app/views/case_logs/_tasklist.html.erb | 16 +++-- config/forms/2021_2022.json | 35 +++++++-- db/migrate/20220706104313_add_unit_type_sh.rb | 7 ++ db/schema.rb | 3 +- db/seeds.rb | 2 +- spec/factories/location.rb | 2 +- spec/features/form/tasklist_page_spec.rb | 2 +- spec/fixtures/exports/case_logs.csv | 4 +- spec/fixtures/exports/case_logs.xml | 1 + spec/helpers/tasklist_helper_spec.rb | 2 +- spec/models/case_log_spec.rb | 72 ++++++++++++++++++- 14 files changed, 153 insertions(+), 27 deletions(-) create mode 100644 db/migrate/20220706104313_add_unit_type_sh.rb diff --git a/app/helpers/tasklist_helper.rb b/app/helpers/tasklist_helper.rb index 5ca37b56c..d9b402221 100644 --- a/app/helpers/tasklist_helper.rb +++ b/app/helpers/tasklist_helper.rb @@ -6,9 +6,9 @@ module TasklistHelper end def get_subsections_count(case_log, status = :all) - return case_log.form.subsections.count if status == :all + return case_log.form.subsections.count { |subsection| subsection.applicable_questions(case_log).count.positive? } if status == :all - case_log.form.subsections.count { |subsection| subsection.status(case_log) == status } + case_log.form.subsections.count { |subsection| subsection.status(case_log) == status && subsection.applicable_questions(case_log).count.positive? } end def next_page_or_check_answers(subsection, case_log, current_user) diff --git a/app/models/derived_variables/case_log_variables.rb b/app/models/derived_variables/case_log_variables.rb index 8a63727b8..33fcef3d1 100644 --- a/app/models/derived_variables/case_log_variables.rb +++ b/app/models/derived_variables/case_log_variables.rb @@ -1,5 +1,13 @@ module DerivedVariables::CaseLogVariables RENT_TYPE_MAPPING = { 0 => 1, 1 => 2, 2 => 2, 3 => 3, 4 => 3, 5 => 3 }.freeze + TYPE_OF_UNIT_MAP = { + "Self-contained flat or bedsit" => 1, + "Self-contained flat or bedsit with common facilities" => 2, + "Shared flat" => 3, + "Shared house or hostel" => 4, + "Bungalow" => 5, + "Self-contained house" => 6, + }.freeze def supported_housing_schemes_enabled? FeatureToggle.supported_housing_schemes_enabled? @@ -8,7 +16,8 @@ module DerivedVariables::CaseLogVariables def scheme_has_multiple_locations? return false unless scheme - scheme.locations.size > 1 + @scheme_locations_count ||= scheme.locations.size + @scheme_locations_count > 1 end def set_derived_fields! @@ -67,8 +76,21 @@ module DerivedVariables::CaseLogVariables self.new_old = new_or_existing_tenant self.vacdays = property_vacant_days - if is_supported_housing? && (scheme && scheme.locations.size == 1) - self.location = scheme.locations.first + if is_supported_housing? && scheme + if scheme.locations.size == 1 + self.location = scheme.locations.first + end + if location + self.la = location.county + self.postcode_full = location.postcode + self.unittype_sh = TYPE_OF_UNIT_MAP[location.type_of_unit] + self.builtype = form.questions.find { |x| x.id == "builtype" }.answer_options.find { |_key, value| value["value"] == location.type_of_building }.first + wheelchair_adaptation_map = { 1 => 1, 0 => 2 } + self.wchair = wheelchair_adaptation_map[location.wheelchair_adaptation.to_i] + end + if is_renewal? + self.voiddate = startdate + end end end diff --git a/app/models/form/subsection.rb b/app/models/form/subsection.rb index 7c6d86698..80a4db102 100644 --- a/app/models/form/subsection.rb +++ b/app/models/form/subsection.rb @@ -34,7 +34,7 @@ class Form::Subsection qs = applicable_questions(case_log) qs_optional_removed = qs.reject { |q| case_log.optional_fields.include?(q.id) } - return :not_started if qs.all? { |question| case_log[question.id].blank? || question.read_only? || question.derived? } + return :not_started if qs.count.positive? && qs.all? { |question| case_log[question.id].blank? || question.read_only? || question.derived? } return :completed if qs_optional_removed.all? { |question| question.completed?(case_log) } :in_progress diff --git a/app/views/case_logs/_tasklist.html.erb b/app/views/case_logs/_tasklist.html.erb index 14ff87274..ff64d5b74 100644 --- a/app/views/case_logs/_tasklist.html.erb +++ b/app/views/case_logs/_tasklist.html.erb @@ -9,13 +9,15 @@ <% end %>
    <% section.subsections.map do |subsection| %> - <% subsection_status = subsection.status(@case_log) %> -
  • - - <%= subsection_link(subsection, @case_log, current_user) %> - - <%= status_tag(subsection_status, "app-task-list__tag") %> -
  • + <% if subsection.applicable_questions(@case_log).count > 0 || !subsection.enabled?(@case_log) %> + <% subsection_status = subsection.status(@case_log) %> +
  • + + <%= subsection_link(subsection, @case_log, current_user) %> + + <%= status_tag(subsection_status, "app-task-list__tag") %> +
  • + <% end %> <% end %>
diff --git a/config/forms/2021_2022.json b/config/forms/2021_2022.json index 49c38f47c..d93f04e22 100644 --- a/config/forms/2021_2022.json +++ b/config/forms/2021_2022.json @@ -54,7 +54,12 @@ "value": "Not known" } } - } + }, + "depends_on": [ + { + "needstype": 1 + } + ] }, "property_local_authority": { "header": "", @@ -388,7 +393,8 @@ }, "depends_on": [ { - "is_la_inferred": false + "is_la_inferred": false, + "needstype": 1 } ] }, @@ -617,7 +623,12 @@ } } } - } + }, + "depends_on": [ + { + "needstype": 1 + } + ] }, "property_building_type": { "header": "", @@ -637,7 +648,12 @@ } } } - } + }, + "depends_on": [ + { + "needstype": 1 + } + ] }, "property_wheelchair_accessible": { "header": "", @@ -657,7 +673,12 @@ } } } - } + }, + "depends_on": [ + { + "needstype": 1 + } + ] }, "property_number_of_bedrooms": { "header": "", @@ -6840,7 +6861,9 @@ }, "net_income_value_check": { "depends_on": [{ "net_income_soft_validation_triggered?": true }], - "title_text": { "translation": "soft_validations.net_income.title_text" }, + "title_text": { + "translation": "soft_validations.net_income.title_text" + }, "informative_text": { "translation": "soft_validations.net_income.hint_text", "arguments": [ diff --git a/db/migrate/20220706104313_add_unit_type_sh.rb b/db/migrate/20220706104313_add_unit_type_sh.rb new file mode 100644 index 000000000..fa7aa9732 --- /dev/null +++ b/db/migrate/20220706104313_add_unit_type_sh.rb @@ -0,0 +1,7 @@ +class AddUnitTypeSh < ActiveRecord::Migration[7.0] + def change + change_table :case_logs, bulk: true do |t| + t.integer :unittype_sh + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 429738353..10a390d90 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2022_07_05_130923) do +ActiveRecord::Schema[7.0].define(version: 2022_07_06_104313) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -200,6 +200,7 @@ ActiveRecord::Schema[7.0].define(version: 2022_07_05_130923) do t.integer "vacdays" t.bigint "scheme_id" t.bigint "location_id" + t.integer "unittype_sh" t.index ["created_by_id"], name: "index_case_logs_on_created_by_id" t.index ["location_id"], name: "index_case_logs_on_location_id" t.index ["managing_organisation_id"], name: "index_case_logs_on_managing_organisation_id" diff --git a/db/seeds.rb b/db/seeds.rb index be13a937c..3ac0aa7d5 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -115,7 +115,7 @@ unless Rails.env.test? postcode: "CU193AA", name: "Rectory Road", type_of_unit: 4, - type_of_building: "Purpose-built", + type_of_building: "Purpose built", county: "Mid Sussex", wheelchair_adaptation: 0, ) diff --git a/spec/factories/location.rb b/spec/factories/location.rb index 53f8d2cd0..efec1aa76 100644 --- a/spec/factories/location.rb +++ b/spec/factories/location.rb @@ -4,7 +4,7 @@ FactoryBot.define do postcode { Faker::Address.postcode.delete(" ") } name { Faker::Address.street_name } type_of_unit { Faker::Number.within(range: 1..6) } - type_of_building { Faker::Lorem.word } + type_of_building { "Purpose built" } wheelchair_adaptation { 0 } county { Faker::Address.state } scheme diff --git a/spec/features/form/tasklist_page_spec.rb b/spec/features/form/tasklist_page_spec.rb index c2c4da0c6..25f2824ac 100644 --- a/spec/features/form/tasklist_page_spec.rb +++ b/spec/features/form/tasklist_page_spec.rb @@ -54,7 +54,7 @@ RSpec.describe "Task List" do it "shows number of completed sections if one section is completed" do visit("/logs/#{setup_completed_log.id}") - expect(page).to have_content("1 of 9 sections completed.") + expect(page).to have_content("1 of 8 sections completed.") end it "show skip link for next incomplete section" do diff --git a/spec/fixtures/exports/case_logs.csv b/spec/fixtures/exports/case_logs.csv index 95e47a3d6..3122967a2 100644 --- a/spec/fixtures/exports/case_logs.csv +++ b/spec/fixtures/exports/case_logs.csv @@ -1,2 +1,2 @@ -status,tenancycode,age1,sex1,ethnic,national,prevten,ecstat1,hhmemb,age2,sex2,ecstat2,age3,sex3,ecstat3,age4,sex4,ecstat4,age5,sex5,ecstat5,age6,sex6,ecstat6,age7,sex7,ecstat7,age8,sex8,ecstat8,homeless,underoccupation_benefitcap,leftreg,reservist,illness,preg_occ,startertenancy,tenancylength,tenancy,ppostcode_full,rsnvac,unittype_gn,beds,offered,wchair,earnings,incfreq,benefits,period,layear,waityear,postcode_full,reasonpref,cbl,chr,cap,reasonother,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,illness_type_1,illness_type_2,illness_type_3,illness_type_4,illness_type_8,illness_type_5,illness_type_6,illness_type_7,illness_type_9,illness_type_10,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,tenancyother,irproduct_other,reason,propcode,la,prevloc,hb,hbrentshortfall,mrcdate,incref,startdate,armedforces,unitletas,builtype,voiddate,renttype,needstype,lettype,totchild,totelder,totadult,nocharge,referral,brent,scharge,pscharge,supcharg,tcharge,tshortfall,chcharge,ppcodenk,has_benefits,renewal,wrent,wscharge,wpschrge,wsupchrg,wtcharge,wtshortfall,refused,housingneeds,wchchrg,newprop,relat2,relat3,relat4,relat5,relat6,relat7,relat8,lar,irproduct,joint,sheltered,hhtype,new_old,vacdays,form,owningorgid,owningorgname,hcnum,maningorgid,maningorgname,manhcnum,createddate,uploaddate -2,BZ737,35,F,2,4,6,0,2,32,M,6,,,,,,,,,,,,,,,,,,,1,0,1,0,1,2,0,5,1,SE26RT,6,7,3,2,1,68,1,1,2,2,1,NW15TY,1,1,1,2,,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,,,4,123,E09000003,E07000105,6,1,2020-05-05 10:36:49 UTC,0,2022-02-02 10:36:49 UTC,1,2,1,2019-11-03 00:00:00 UTC,2,1,7,0,0,2,0,,200.0,50.0,40.0,35.0,325.0,12.0,,1,1,0,100.0,25.0,20.0,17.5,162.5,6.0,0,1,,2,P,,,,,,,,,,0,4,2,638,{id},{owning_org_id},DLUHC,1234,{managing_org_id},DLUHC,1234,2022-02-08 16:52:15 UTC,2022-02-08 16:52:15 UTC +status,tenancycode,age1,sex1,ethnic,national,prevten,ecstat1,hhmemb,age2,sex2,ecstat2,age3,sex3,ecstat3,age4,sex4,ecstat4,age5,sex5,ecstat5,age6,sex6,ecstat6,age7,sex7,ecstat7,age8,sex8,ecstat8,homeless,underoccupation_benefitcap,leftreg,reservist,illness,preg_occ,startertenancy,tenancylength,tenancy,ppostcode_full,rsnvac,unittype_gn,beds,offered,wchair,earnings,incfreq,benefits,period,layear,waityear,postcode_full,reasonpref,cbl,chr,cap,reasonother,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,illness_type_1,illness_type_2,illness_type_3,illness_type_4,illness_type_8,illness_type_5,illness_type_6,illness_type_7,illness_type_9,illness_type_10,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,tenancyother,irproduct_other,reason,propcode,la,prevloc,hb,hbrentshortfall,mrcdate,incref,startdate,armedforces,unitletas,builtype,voiddate,renttype,needstype,lettype,totchild,totelder,totadult,nocharge,referral,brent,scharge,pscharge,supcharg,tcharge,tshortfall,chcharge,ppcodenk,has_benefits,renewal,wrent,wscharge,wpschrge,wsupchrg,wtcharge,wtshortfall,refused,housingneeds,wchchrg,newprop,relat2,relat3,relat4,relat5,relat6,relat7,relat8,lar,irproduct,joint,sheltered,hhtype,new_old,vacdays,unittype_sh,form,owningorgid,owningorgname,hcnum,maningorgid,maningorgname,manhcnum,createddate,uploaddate +2,BZ737,35,F,2,4,6,0,2,32,M,6,,,,,,,,,,,,,,,,,,,1,0,1,0,1,2,0,5,1,SE26RT,6,7,3,2,1,68,1,1,2,2,1,NW15TY,1,1,1,2,,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,,,4,123,E09000003,E07000105,6,1,2020-05-05 10:36:49 UTC,0,2022-02-02 10:36:49 UTC,1,2,1,2019-11-03 00:00:00 UTC,2,1,7,0,0,2,0,,200.0,50.0,40.0,35.0,325.0,12.0,,1,1,0,100.0,25.0,20.0,17.5,162.5,6.0,0,1,,2,P,,,,,,,,,,0,4,2,638,,{id},{owning_org_id},DLUHC,1234,{managing_org_id},DLUHC,1234,2022-02-08 16:52:15 UTC,2022-02-08 16:52:15 UTC diff --git a/spec/fixtures/exports/case_logs.xml b/spec/fixtures/exports/case_logs.xml index 469d8f2f0..2608bf92e 100644 --- a/spec/fixtures/exports/case_logs.xml +++ b/spec/fixtures/exports/case_logs.xml @@ -135,6 +135,7 @@ 4 2 638 +
{id}
{owning_org_id} DLUHC diff --git a/spec/helpers/tasklist_helper_spec.rb b/spec/helpers/tasklist_helper_spec.rb index 0e13fa805..4401d1739 100644 --- a/spec/helpers/tasklist_helper_spec.rb +++ b/spec/helpers/tasklist_helper_spec.rb @@ -17,7 +17,7 @@ RSpec.describe TasklistHelper do describe "get sections count" do it "returns the total of sections if no status is given" do - expect(get_subsections_count(empty_case_log)).to eq(9) + expect(get_subsections_count(empty_case_log)).to eq(8) end it "returns 0 sections for completed sections if no sections are completed" do diff --git a/spec/models/case_log_spec.rb b/spec/models/case_log_spec.rb index 23176a005..ae5c550d6 100644 --- a/spec/models/case_log_spec.rb +++ b/spec/models/case_log_spec.rb @@ -1680,7 +1680,12 @@ RSpec.describe CaseLog do end context "when a case log is a supported housing log" do - before { case_log.needstype = 2 } + let(:real_2021_2022_form) { Form.new("config/forms/2021_2022.json", "2021_2022") } + + before do + case_log.needstype = 2 + allow(FormHandler.instance).to receive(:get_form).and_return(real_2021_2022_form) + end context "and a scheme with a single log is selected" do let(:scheme) { FactoryBot.create(:scheme) } @@ -1694,6 +1699,71 @@ RSpec.describe CaseLog do expect(case_log["location_id"]).to eq(location.id) end end + + context "and not renewal" do + let(:scheme) { FactoryBot.create(:scheme) } + let(:location) { FactoryBot.create(:location, scheme:, county: "E07000041", type_of_unit: 1, type_of_building: "Purpose built", wheelchair_adaptation: 0) } + + let!(:supported_housing_case_log) do + described_class.create!({ + managing_organisation: owning_organisation, + owning_organisation:, + created_by: created_by_user, + needstype: 2, + scheme_id: scheme.id, + location_id: location.id, + renewal: 0, + }) + end + + it "correctly infers and saves la" do + record_from_db = ActiveRecord::Base.connection.execute("SELECT la from case_logs WHERE id=#{supported_housing_case_log.id}").to_a[0] + expect(record_from_db["la"]).to eq(location.county) + end + + it "correctly infers and saves postcode" do + record_from_db = ActiveRecord::Base.connection.execute("SELECT postcode_full from case_logs WHERE id=#{supported_housing_case_log.id}").to_a[0] + expect(record_from_db["postcode_full"]).to eq(location.postcode) + end + + it "correctly infers and saves type of unit" do + record_from_db = ActiveRecord::Base.connection.execute("SELECT unittype_sh from case_logs WHERE id=#{supported_housing_case_log.id}").to_a[0] + expect(record_from_db["unittype_sh"]).to eq(1) + end + + it "correctly infers and saves type of building" do + record_from_db = ActiveRecord::Base.connection.execute("SELECT builtype from case_logs WHERE id=#{supported_housing_case_log.id}").to_a[0] + expect(record_from_db["builtype"]).to eq(1) + end + + it "correctly infers and saves wchair" do + record_from_db = ActiveRecord::Base.connection.execute("SELECT wchair from case_logs WHERE id=#{supported_housing_case_log.id}").to_a[0] + expect(record_from_db["wchair"]).to eq(2) + end + end + + context "and renewal" do + let(:scheme) { FactoryBot.create(:scheme) } + let(:location) { FactoryBot.create(:location, scheme:) } + + let!(:supported_housing_case_log) do + described_class.create!({ + managing_organisation: owning_organisation, + owning_organisation:, + created_by: created_by_user, + needstype: 2, + scheme_id: scheme.id, + location_id: location.id, + renewal: 1, + startdate: Time.zone.now, + }) + end + + it "correcly infers and saves the renewal date" do + record_from_db = ActiveRecord::Base.connection.execute("SELECT voiddate from case_logs where id=#{supported_housing_case_log.id}").to_a[0] + expect(record_from_db["voiddate"].to_i).to eq(supported_housing_case_log.startdate.to_i) + end + end end end From 44273a000a9692b4efd919c8339054fb882636ce Mon Sep 17 00:00:00 2001 From: Dushan <47317567+dushan-madetech@users.noreply.github.com> Date: Mon, 11 Jul 2022 13:43:06 +0100 Subject: [PATCH 10/11] Form documentation (#722) * Form documentation Adding documentation for the form definition including elements such as the sections, subsections, pages and questions * update docs * add link to new docs to form runner doc --- docs/form/form.md | 86 +++++++++++++++++++++++++++++++++++++++++ docs/form/page.md | 28 ++++++++++++++ docs/form/question.md | 82 +++++++++++++++++++++++++++++++++++++++ docs/form/section.md | 26 +++++++++++++ docs/form/subsection.md | 28 ++++++++++++++ docs/form_builder.md | 4 ++ docs/form_runner.md | 4 ++ 7 files changed, 258 insertions(+) create mode 100644 docs/form/form.md create mode 100644 docs/form/page.md create mode 100644 docs/form/question.md create mode 100644 docs/form/section.md create mode 100644 docs/form/subsection.md diff --git a/docs/form/form.md b/docs/form/form.md new file mode 100644 index 000000000..9a3658d64 --- /dev/null +++ b/docs/form/form.md @@ -0,0 +1,86 @@ +## Form Definition + +The current system is built around a form definition written in JSON. At the top level every form will expect to have the following attributes: + +- Form type: this is to define whether the form is a lettings form or a sales form. The questions will differ between the types. +- Start date: the start of the collection window for the form, this will usually be in April. +- End date: the end date of the collection window for the form, this will usually be in July, a year after the start date. +- Sections: the sections in the form, this block is where the bulk of the form definition will be. + +An example of this might look like the following: +```JSON +{ + "form_type": "lettings", + "start_date": "2021-04-01T00:00:00.000+01:00", + "end_date": "2022-07-01T00:00:00.000+01:00", + "sections": { + ... + } +} +``` + +Note that the end date of one form will overlap the start date of another to allow for late submissions. This means that every year there will be a period of time in which two forms are running simultaneously. + +### How is the form split up? + +A summary of how the form is split up is as follows: + +- A form is divided up into one or more sections. +- Each section can have one or more subsections. +- Each subsection can have one or more pages. +- Each page can have one or more questions. + +More information about these form elements can be found in the following links: + +- [Section](docs/form/section.md) +- [Subsection](docs/form/subsection.md) +- [Page](docs/form/page.md) +- [Question](docs/form/question.md) + +### The Form Model, Views and Controller + +Rails uses the Model, View, Controller (MVC) pattern which we follow. + +#### The Form Model + +There is no need to manually initialise a form object as this is handled by the FormHandler class at boot time. If a new form needs to be added then a JSON file containing the form definition should be added to `config/forms` where the FormHandler will be able to locate it and instantiate it. + +A form has the following attributes: + +- name: The name of the form +- setup_sections: The setup section (this is not defined in the JSON, for more information see this) +- form_definition: The parsed form JSON +- form_sections: The sections found within the form definition JSON +- type: The type of form (this is used to indicate if the form is for a sale or a letting) +- sections: The combination of the setup section with those found in the JSON definition +- subsections: The subsections of the form (these live under the sections) +- pages: The pages of the form (these live under the subsections) +- questions: The questions of the form (these live under the pages) +- start_date: The start date of the form, in iso8601 format +- end_date: The end date of the form, in iso8601 format + + +#### The Form Views + +The main view used for rendering the form is the `app/views/form/page.html.erb` view as the Form contains multiple pages (which live in subsections within sections). This page view then renders the appropriate partials for the question types of the questions on the current page. + +We currently have views for the following question types: +- Numerical +- Date +- Checkbox +- Radio +- Select +- Text +- Textarea +- Interruption screen + +Interruption screen questions are radio questions used for soft validation of fields. They usually have yes and no options for a user to confirm a value is correct. + +#### The Form Controller + +The form controller handles the form submission as well as the rendering of the check answers page and the review page. + +### The FormHandler helper class + +The FormHandler helper is a helper that loads all of the defined forms and initialises them as Form objects. It can also be used to get specific forms if needed. + diff --git a/docs/form/page.md b/docs/form/page.md new file mode 100644 index 000000000..ab47b4f0d --- /dev/null +++ b/docs/form/page.md @@ -0,0 +1,28 @@ +## Page + +Pages are under the subsection level of the form definition. A example page might look something like this: + +```JSON +"property_postcode": { + "header": "", + "description": "", + "questions": { + ... + }, + "depends_on": [ + { + "needstype": 1 + } + ] +} +``` + +In the above example the the subsection has the id `property_postcode`. This id is used for the url of the web page, but the underscore is replaced with a hash, so the url for this page would be `[environment-url]/logs/[log-id]/property-postcode` e.g. on staging this url might look like the following: `https://dluhc-core-staging.london.cloudapps.digital/logs/1234/property-postcode`. + +The header is optional but if provided is used for the heading displayed on the page. + +The description is optional but if provided is used for a paragraph displayed under the page header. + +It's worth noting that like subsections a page can also have a `depends_on` which contains the set of conditions that must be met for the section to be accessibile to a data provider. If the conditions are not met then the page is not routed to as part of the form flow. The `depends_on` for a page will usually depend on answers given to questions, most likely to be questions in the setup section. In the above example the page is dependent on the answer to the `needstype` question being `1`, which corresponds to picking `General needs` on that question as displayed to the data provider. + +Pages can contain one or more questions. \ No newline at end of file diff --git a/docs/form/question.md b/docs/form/question.md new file mode 100644 index 000000000..4050531f9 --- /dev/null +++ b/docs/form/question.md @@ -0,0 +1,82 @@ +## Question + +Questions are under the page level of the form definition. A example question might look something like this: + +```JSON +"postcode_known": { + "check_answer_label": "Do you know the property postcode?", + "header": "Do you know the property’s postcode?", + "hint_text": "", + "type": "radio", + "answer_options": { + "1": { + "value": "Yes" + }, + "0": { + "value": "No" + } + }, + "conditional_for": { + "postcode_full": [1] + }, + "hidden_in_check_answers": true +} +``` + +In the above example the the question has the id `postcode_known`. + +The `check_answer_label` contains the text that will be displayed in the label of the table on the check answers page. + +The header is text that is displayed for the question. + +Hint text is optional, but if provided it sits under the header and is normally given to provide the data inputters with guidance when answering the question, for example it might inform them about terms used in the question. + +The type is question type, which is used to determine the view rendered for the question. In the above example the question is a radio type so the `app/views/form/_radio_question.html.erb` partial will be rendered on the page when this question is displayed to the user. + +The `conditional_for` contains the value needed to be selected by the data inputter in order to display another question that appears on the same page. In the example above the `postcode_full` question depends on the answer to `postcode_known` being selected as `1` or `Yes`, this would then display the `postcode_full` underneath the `Yes` option on the page, allowing the provide the provide the postcode if they have indicated they know it. If the user has JavaScript enabled then this realtime conditional display is handled by the `app/frontend/controllers/conditional_question_controller.js` file. + +the `hidden_in_check_answers` is used to hide a value from displaying on the check answers page. You only need to provide this if you want to set it to true in order to hide the value for some reason e.g. it's one of two questions appearing on a page and the other question is displayed on the check answers page. It's also worth noting that you can declare this as a with a `depends_on` which can be useful for conditionally displaying values on the check answers page. For example: + +```JSON +"hidden_in_check_answers": { + "depends_on": [ + { + "age6_known": 0 + }, + { + "age6_known": 1 + } + ] +} +``` + +Would mean the question the above is attached to would be hidden in the check answers page if the value of age6_known is either `0` or `1`. + +The answer the data inputter provides to some questions allows us to infer the values of other questions we might have asked in the form, allowing us to save the data inputters some time. An example of how this might look is as follows: + +```JSON +"postcode_full": { + "check_answer_label": "Postcode", + "header": "What is the property’s postcode?", + "hint_text": "", + "type": "text", + "width": 5, + "inferred_answers": { + "la": { + "is_la_inferred": true + } + }, + "inferred_check_answers_value": { + "condition": { + "postcode_known": 0 + }, + "value": "Not known" + } +} +``` + +In the above example the width is an optional attribute and can be provided for text type questions to determine the width of the text box on the page when when the question is displayed to a user (this allows you to match the width of the text box on the page to that of the design for a question). + +The above example links to the first example as both of these questions would be on the same page. The `inferred_check_answers_value` is what should be displayed on the check answers page for this question if we infer it. If the value of `postcode_known` was given as `0` (which is a no), as seen in the condition part of `inferred_check_answers_value` then we can infer that the data inputter does not know the postcode and so we would display the value of `Not known` on the check answers page for the postcode. + +In the above example the `inferred_answers` refers to a question where we can infer the answer based on the answer of this question. In this case the `la` question can be inferred from the postcode value given by the data inputter as we are able to lookup the local authority based on the postcode given. We then set a property on the case log `is_la_inferred` to true to indicate that this is an answer we've inferred. \ No newline at end of file diff --git a/docs/form/section.md b/docs/form/section.md new file mode 100644 index 000000000..9454a6569 --- /dev/null +++ b/docs/form/section.md @@ -0,0 +1,26 @@ +## Section + +Sections are under the top level of the form definition. A example section might look something like this: + +```JSON +"sections": { + "tenancy_and_property": { + "label": "Property and tenancy information", + "subsections": { + "property_information": { + ... + }, + "tenancy_information": { + ... + } + } + }, + ... +} +``` + +In the above example the section id would be `tenancy_and_property` and its subsections would be `property_information` and `tenancy_information`. + +The label contains the text that users will see for that section in the tasklist page of a case log. + +Sections can contain one or more subsections. \ No newline at end of file diff --git a/docs/form/subsection.md b/docs/form/subsection.md new file mode 100644 index 000000000..b65f064c6 --- /dev/null +++ b/docs/form/subsection.md @@ -0,0 +1,28 @@ +## Subsection + +Subsections are under the section level of the form definition. A example subsection might look something like this: + +```JSON +"property_information": { + "label": "Property information", + "depends_on": [ + { + "setup": "completed" + } + ], + "pages": { + "property_postcode": { + ... + }, + "property_local_authority": { + ... + } + } +} +``` + +In the above example the the subsection has the id `property_information`. The `depends_on` contains the set of conditions that must be met for the section to be accessibile to a data provider, in this example subsection depends on the completion of the setup section/subsection (note that this is a common condition as the answers provided to questions in the setup subsection often have an impact on what questions are asked of the data provider in later subsections of the form). + +The label contains the text that users will see for that subsection in the tasklist page of a case log. + +The pages of the subsection in the example would be `property_postcode` and `property_local_authority`. Subsections can contain one or more pages. \ No newline at end of file diff --git a/docs/form_builder.md b/docs/form_builder.md index 556b086d0..cc1c16db6 100644 --- a/docs/form_builder.md +++ b/docs/form_builder.md @@ -181,6 +181,10 @@ rake form_definition:validate_all This will validate all forms in directories `["config/forms", "spec/fixtures/forms"]` +## Form models and definition + +For information about the form model and related models (section, subsection, page, question) and how these relate to each other follow [this link](docs/form/form.md) + ## Improvements that could be made - JSON schema definition could be expanded such that we can better automatically validate that a given config is valid and internally consistent diff --git a/docs/form_runner.md b/docs/form_runner.md index 23173c74b..cec88153f 100644 --- a/docs/form_runner.md +++ b/docs/form_runner.md @@ -19,3 +19,7 @@ ERB templates: Routes for each form page are generated by looping over each Page instance in each Form instance held by the form handler and defining a `GET` path. The corresponding controller method is also auto-generated with meta-programming via the same looping in `app/controllers/form_controller.rb` All form pages submit to the same controller method (`app/controllers/form_controller.rb#submit_form`) which validates and persists the data, and then redirects to the next form page that identifies as `routed_to` given the current case log state. + +## Form models and definition + +For information about the form model and related models (section, subsection, page, question) and how these relate to each other follow [this link](docs/form/form.md) \ No newline at end of file From 2ef45f491b00eea719c6d732c2640c0f597e9d18 Mon Sep 17 00:00:00 2001 From: Paul Robert Lloyd Date: Mon, 11 Jul 2022 14:08:40 +0100 Subject: [PATCH 11/11] Scheme tweaks (#723) --- app/views/locations/edit.html.erb | 9 +- app/views/locations/edit_name.html.erb | 6 +- app/views/locations/index.html.erb | 74 +++++----- app/views/locations/new.html.erb | 6 +- app/views/schemes/check_answers.html.erb | 2 - app/views/schemes/confirm_secondary.html.erb | 2 - app/views/schemes/details.html.erb | 128 +++++++++--------- app/views/schemes/edit_name.html.erb | 89 ++++++------ app/views/schemes/new.html.erb | 2 - .../schemes/primary_client_group.html.erb | 3 - .../schemes/secondary_client_group.html.erb | 11 +- app/views/schemes/show.html.erb | 4 +- app/views/schemes/support.html.erb | 5 +- spec/features/schemes_spec.rb | 6 +- spec/helpers/navigation_items_helper_spec.rb | 8 +- spec/requests/locations_controller_spec.rb | 4 +- 16 files changed, 169 insertions(+), 190 deletions(-) diff --git a/app/views/locations/edit.html.erb b/app/views/locations/edit.html.erb index e8a38ecb3..4d516b020 100644 --- a/app/views/locations/edit.html.erb +++ b/app/views/locations/edit.html.erb @@ -2,9 +2,9 @@ <% content_for :before_content do %> <%= govuk_back_link( - text: "Back", - href: "/schemes/#{@scheme.id}/support", - ) %> + text: "Back", + href: "/schemes/#{@scheme.id}/support", + ) %> <% end %> <%= render partial: "organisations/headings", locals: { main: "Add a location to this scheme", sub: @scheme.service_name } %> @@ -30,7 +30,6 @@ autofocus: true %> <% type_of_units_selection = Location.type_of_units.keys.map { |key, _| OpenStruct.new(id: key, name: key.to_s.humanize) } %> - <%= f.govuk_collection_radio_buttons :type_of_unit, type_of_units_selection, :id, @@ -38,7 +37,6 @@ legend: { text: "What is this type of scheme?", size: "m" } %> <% wheelchair_user_selection = Location.wheelchair_adaptations.keys.map { |key, _| OpenStruct.new(id: key, name: key.to_s.humanize) } %> - <%= f.govuk_collection_radio_buttons :wheelchair_adaptation, wheelchair_user_selection, :id, @@ -49,7 +47,6 @@ <%= govuk_section_break(visible: true, size: "m") %> <% another_location_selection = %w[Yes no].map { |key, _| OpenStruct.new(id: key, name: key.to_s.humanize) } %> - <%= f.govuk_collection_radio_buttons :add_another_location, another_location_selection, :id, diff --git a/app/views/locations/edit_name.html.erb b/app/views/locations/edit_name.html.erb index 22ce4be1f..0bc469a94 100644 --- a/app/views/locations/edit_name.html.erb +++ b/app/views/locations/edit_name.html.erb @@ -2,9 +2,9 @@ <% content_for :before_content do %> <%= govuk_back_link( - text: "Back", - href: "/schemes/#{@scheme.id}/locations", - ) %> + text: "Back", + href: "/schemes/#{@scheme.id}/locations", + ) %> <% end %> <%= render partial: "organisations/headings", locals: { main: "Location name for #{@location.postcode}", sub: @scheme.service_name } %> diff --git a/app/views/locations/index.html.erb b/app/views/locations/index.html.erb index a610fc80a..3770c612a 100644 --- a/app/views/locations/index.html.erb +++ b/app/views/locations/index.html.erb @@ -1,49 +1,47 @@ <% title = @scheme.service_name %> <% content_for :title, title %> + <% content_for :before_content do %> <%= govuk_back_link( - text: "Back", - href: "/schemes/#{@scheme.id}", - ) %> + text: "Back", + href: "/schemes/#{@scheme.id}", + ) %> <% end %> + <%= render partial: "organisations/headings", locals: { main: @scheme.service_name, sub: nil } %> -<% location_caption = @scheme.locations.count.eql?(1) ? "1 location" : "#{@scheme.locations.count} locations" %> -<%= render SubNavigationComponent.new(items: scheme_items(request.path, @scheme.id, location_caption)) %> -
-
- <%= govuk_table do |table| %> - <%= table.caption(classes: %w[govuk-!-font-size-19 govuk-!-font-weight-regular]) do |caption| %> - <%= @scheme.locations.count %> <%= @scheme.locations.count.eql?(1) ? "location" : "locations" %>. - <% end %> - <%= table.head do |head| %> - <%= head.row do |row| %> - <% row.cell(header: true, text: "Code", html_attributes: { - scope: "col", - }) %> - <% row.cell(header: true, text: "Postcode", html_attributes: { - scope: "col", - }) %> - <% row.cell(header: true, text: "Units", html_attributes: { - scope: "col", - }) %> - <% row.cell(header: true, text: "Common unit type", html_attributes: { - scope: "col", - }) %> - <% end %> - <% end %> - <% @locations.each do |location| %> - <%= table.body do |body| %> - <%= body.row do |row| %> - <% row.cell(text: location.id) %> - <% row.cell(text: simple_format(location_cell(location, "/schemes/#{@scheme.id}/locations/#{location.id}/edit-name"), { class: "govuk-!-font-weight-bold" }, wrapper_tag: "div")) %> - <% row.cell(text: location.total_units) %> - <% row.cell(text: simple_format("#{location.type_of_unit}#{location.wheelchair_adaptation == 'Yes' ? "\nWith wheelchair adaptations" : ''}")) %> - <% end %> - <% end %> +<%= render SubNavigationComponent.new(items: scheme_items(request.path, @scheme.id, "Locations")) %> + +<%= govuk_table do |table| %> + <%= table.caption(classes: %w[govuk-!-font-size-19 govuk-!-font-weight-regular]) do |caption| %> + <%= @scheme.locations.count %> <%= @scheme.locations.count.eql?(1) ? "location" : "locations" %> + <% end %> + <%= table.head do |head| %> + <%= head.row do |row| %> + <% row.cell(header: true, text: "Code", html_attributes: { + scope: "col", + }) %> + <% row.cell(header: true, text: "Postcode", html_attributes: { + scope: "col", + }) %> + <% row.cell(header: true, text: "Units", html_attributes: { + scope: "col", + }) %> + <% row.cell(header: true, text: "Common unit type", html_attributes: { + scope: "col", + }) %> + <% end %> + <% end %> + <% @locations.each do |location| %> + <%= table.body do |body| %> + <%= body.row do |row| %> + <% row.cell(text: location.id) %> + <% row.cell(text: simple_format(location_cell(location, "/schemes/#{@scheme.id}/locations/#{location.id}/edit-name"), { class: "govuk-!-font-weight-bold" }, wrapper_tag: "div")) %> + <% row.cell(text: location.total_units) %> + <% row.cell(text: simple_format("#{location.type_of_unit}#{location.wheelchair_adaptation == 'Yes' ? "\nWith wheelchair adaptations" : ''}")) %> <% end %> <% end %> -
-
+ <% end %> +<% end %> <%== render partial: "pagy/nav", locals: { pagy: @pagy, item_name: "locations" } %> diff --git a/app/views/locations/new.html.erb b/app/views/locations/new.html.erb index 8c8ff23c5..19c2ae125 100644 --- a/app/views/locations/new.html.erb +++ b/app/views/locations/new.html.erb @@ -2,9 +2,9 @@ <% content_for :before_content do %> <%= govuk_back_link( - text: "Back", - href: "/schemes/#{@scheme.id}/support", - ) %> + text: "Back", + href: "/schemes/#{@scheme.id}/support", + ) %> <% end %> <%= render partial: "organisations/headings", locals: { main: "Add a location to this scheme", sub: @scheme.service_name } %> diff --git a/app/views/schemes/check_answers.html.erb b/app/views/schemes/check_answers.html.erb index 7043fa502..f211ba784 100644 --- a/app/views/schemes/check_answers.html.erb +++ b/app/views/schemes/check_answers.html.erb @@ -2,8 +2,6 @@ <%= render partial: "organisations/headings", locals: { main: "Check your changes before creating this scheme", sub: @scheme.service_name } %> -<% location_caption = @scheme.locations.count.eql?(1) ? "1 location" : "#{@scheme.locations.count} locations" %> -
<%= govuk_tabs(title: "Check your answers before creating this scheme") do |component| %> diff --git a/app/views/schemes/confirm_secondary.html.erb b/app/views/schemes/confirm_secondary.html.erb index b511c5a01..c145e573d 100644 --- a/app/views/schemes/confirm_secondary.html.erb +++ b/app/views/schemes/confirm_secondary.html.erb @@ -12,9 +12,7 @@ <%= form_for(@scheme, method: :patch) do |f| %>
- <% selection = [OpenStruct.new(id: "Yes", name: "Yes"), OpenStruct.new(id: "No", name: "No")] %> - <%= f.govuk_collection_radio_buttons :has_other_client_group, selection, :id, diff --git a/app/views/schemes/details.html.erb b/app/views/schemes/details.html.erb index b59f4ce37..4ae640208 100644 --- a/app/views/schemes/details.html.erb +++ b/app/views/schemes/details.html.erb @@ -1,79 +1,79 @@ <% content_for :title, "Create a new supported housing scheme" %> - <% content_for :before_content do %> - <%= govuk_back_link( - text: "Back", - href: :back, - ) %> - <% end %> +<% content_for :before_content do %> + <%= govuk_back_link( + text: "Back", + href: :back, + ) %> +<% end %> - <%= render partial: "organisations/headings", locals: { main: "Create a new supported housing scheme", sub: nil } %> +<%= render partial: "organisations/headings", locals: { main: "Create a new supported housing scheme", sub: nil } %> - <%= form_for(@scheme, method: :patch) do |f| %> -
-
- <%= f.govuk_error_summary %> +<%= form_for(@scheme, method: :patch) do |f| %> +
+
+ <%= f.govuk_error_summary %> - <%= f.govuk_text_field :service_name, - label: { text: "Scheme name", size: "m" }, - hint: { text: "This is how you’ll refer to this supported housing scheme within your organisation. For example, the name could relate to the address or location. You’ll be able to see the client group when selecting it." } %> + <%= f.govuk_text_field :service_name, + label: { text: "Scheme name", size: "m" }, + hint: { text: "This is how you refer to this supported housing scheme within your organisation. For example, the name could relate to the address or location. You’ll be able to see the client group when selecting it." } %> - <%= f.govuk_check_boxes_fieldset :sensitive, - legend: nil do %> - <%= f.govuk_check_box :sensitive, - 1, - 0, - multiple: false, - checked: @scheme.sensitive == "Yes", - label: { text: "This scheme contains confidential information" } %> - <% end %> + <%= f.govuk_check_boxes_fieldset :sensitive, + legend: nil do %> + <%= f.govuk_check_box :sensitive, + 1, + 0, + multiple: false, + checked: @scheme.sensitive == "Yes", + label: { text: "This scheme contains confidential information" } %> + <% end %> - <% null_option = [OpenStruct.new(id: "", name: "Select an option")] %> - <% organisations = Organisation.all.map { |org| OpenStruct.new(id: org.id, name: org.name) } %> - <% managing_org_answer_options = null_option + organisations %> + <% null_option = [OpenStruct.new(id: "", name: "Select an option")] %> + <% organisations = Organisation.all.map { |org| OpenStruct.new(id: org.id, name: org.name) } %> + <% managing_org_answer_options = null_option + organisations %> - <%= f.govuk_collection_select :managing_organisation_id, - managing_org_answer_options, - :id, - :name, - label: { text: "Which organisation manages this scheme?", size: "m" }, - options: { required: true }, - "data-controller": %w[accessible-autocomplete conditional-filter] %> + <%= f.govuk_collection_select :managing_organisation_id, + managing_org_answer_options, + :id, + :name, + label: { text: "Which organisation manages this scheme?", size: "m" }, + options: { required: true }, + "data-controller": %w[accessible-autocomplete conditional-filter] %> - <% if current_user.support? %> - <%= f.govuk_collection_select :owning_organisation_id, - organisations, - :id, - :name, - label: { text: "Which organisation owns the housing stock for this scheme?", size: "m" }, - "data-controller": %w[accessible-autocomplete conditional-filter] %> - <% end %> + <% if current_user.support? %> + <%= f.govuk_collection_select :owning_organisation_id, + organisations, + :id, + :name, + label: { text: "Which organisation owns the housing stock for this scheme?", size: "m" }, + "data-controller": %w[accessible-autocomplete conditional-filter] %> + <% end %> - <% if current_user.data_coordinator? %> - <%= f.hidden_field :owning_organisation_id, value: current_user.organisation.id %> - <% end %> + <% if current_user.data_coordinator? %> + <%= f.hidden_field :owning_organisation_id, value: current_user.organisation.id %> + <% end %> - <% scheme_types_selection = Scheme.scheme_types.keys.excluding("Missing").map { |key, _| OpenStruct.new(id: key, name: key.to_s.humanize) } %> + <% scheme_types_selection = Scheme.scheme_types.keys.excluding("Missing").map { |key, _| OpenStruct.new(id: key, name: key.to_s.humanize) } %> - <%= f.govuk_collection_radio_buttons :scheme_type, - scheme_types_selection, - :id, - :name, - legend: { text: "What is this type of scheme?", size: "m" } %> + <%= f.govuk_collection_radio_buttons :scheme_type, + scheme_types_selection, + :id, + :name, + legend: { text: "What is this type of scheme?", size: "m" } %> - <% care_acts_selection = Scheme.registered_under_care_acts.keys.reverse.map { |key, _| OpenStruct.new(id: key, name: key.to_s.humanize) } %> + <% care_acts_selection = Scheme.registered_under_care_acts.keys.reverse.map { |key, _| OpenStruct.new(id: key, name: key.to_s.humanize) } %> - <%= f.govuk_collection_radio_buttons :registered_under_care_act, - care_acts_selection, - :id, - :name, - legend: { text: "Is this scheme registered under the Care Standards Act 2000?", size: "m" } %> + <%= f.govuk_collection_radio_buttons :registered_under_care_act, + care_acts_selection, + :id, + :name, + legend: { text: "Is this scheme registered under the Care Standards Act 2000?", size: "m" } %> - <%= f.hidden_field :page, value: "details" %> - <% if request.query_parameters["check_answers"] %> - <%= f.hidden_field :check_answers, value: "true" %> - <% end %> - <%= f.govuk_submit "Save and continue" %> -
-
- <% end %> + <%= f.hidden_field :page, value: "details" %> + <% if request.query_parameters["check_answers"] %> + <%= f.hidden_field :check_answers, value: "true" %> + <% end %> + <%= f.govuk_submit "Save and continue" %> +
+
+<% end %> diff --git a/app/views/schemes/edit_name.html.erb b/app/views/schemes/edit_name.html.erb index d967c24a2..876e73a25 100644 --- a/app/views/schemes/edit_name.html.erb +++ b/app/views/schemes/edit_name.html.erb @@ -1,47 +1,46 @@ <% content_for :title, "Scheme details" %> - <% content_for :before_content do %> - <%= govuk_back_link( - text: "Back", - href: :back, - ) %> - <% end %> - - <%= render partial: "organisations/headings", locals: { main: "Scheme details", sub: @scheme.service_name } %> - - <%= form_for(@scheme, method: :patch) do |f| %> -
-
- <%= f.govuk_error_summary %> - - <%= f.govuk_text_field :service_name, - label: { text: "Scheme name", size: "m" }, - hint: { text: "This is how you’ll refer to this supported housing scheme within your organisation. For example, the name could relate to the address or location. You’ll be able to see the client group when selecting it." } %> - - <%= f.govuk_check_boxes_fieldset :sensitive, - legend: nil do %> - <%= f.govuk_check_box :sensitive, - 1, - 0, - multiple: false, - checked: @scheme.sensitive == "Yes", - label: { text: "This scheme contains confidential information" } %> - <% end %> - - <% organisations = Organisation.all.map { |org| OpenStruct.new(id: org.id, name: org.name) } %> - - <% if current_user.support? %> - <%= f.govuk_collection_select :owning_organisation_id, - organisations, - :id, - :name, - label: { text: "Which organisation owns the housing stock for this scheme?", size: "m" }, - "data-controller": %w[accessible-autocomplete conditional-filter] %> - <% end %> - - <%= f.hidden_field :page, value: "edit-name" %> - - <%= f.govuk_submit "Save changes" %> -
-
- <% end %> +<% content_for :before_content do %> + <%= govuk_back_link( + text: "Back", + href: :back, + ) %> +<% end %> + +<%= render partial: "organisations/headings", locals: { main: "Scheme details", sub: @scheme.service_name } %> + +<%= form_for(@scheme, method: :patch) do |f| %> +
+
+ <%= f.govuk_error_summary %> + + <%= f.govuk_text_field :service_name, + label: { text: "Scheme name", size: "m" }, + hint: { text: "This is how you refer to this supported housing scheme within your organisation. For example, the name could relate to the address or location. You’ll be able to see the client group when selecting it." } %> + + <%= f.govuk_check_boxes_fieldset :sensitive, + legend: nil do %> + <%= f.govuk_check_box :sensitive, + 1, + 0, + multiple: false, + checked: @scheme.sensitive == "Yes", + label: { text: "This scheme contains confidential information" } %> + <% end %> + + <% organisations = Organisation.all.map { |org| OpenStruct.new(id: org.id, name: org.name) } %> + <% if current_user.support? %> + <%= f.govuk_collection_select :owning_organisation_id, + organisations, + :id, + :name, + label: { text: "Which organisation owns the housing stock for this scheme?", size: "m" }, + "data-controller": %w[accessible-autocomplete conditional-filter] %> + <% end %> + + <%= f.hidden_field :page, value: "edit-name" %> + + <%= f.govuk_submit "Save changes" %> +
+
+<% end %> diff --git a/app/views/schemes/new.html.erb b/app/views/schemes/new.html.erb index b58e461c0..297af9cef 100644 --- a/app/views/schemes/new.html.erb +++ b/app/views/schemes/new.html.erb @@ -53,7 +53,6 @@ <% end %> <% scheme_types_selection = Scheme.scheme_types.keys.excluding("Missing").map { |key, _| OpenStruct.new(id: key, name: key.to_s.humanize) } %> - <%= f.govuk_collection_radio_buttons :scheme_type, scheme_types_selection, :id, @@ -61,7 +60,6 @@ legend: { text: "What is this type of scheme?", size: "m" } %> <% care_acts_selection = Scheme.registered_under_care_acts.keys.reverse.map { |key, _| OpenStruct.new(id: key, name: key.to_s.humanize) } %> - <%= f.govuk_collection_radio_buttons :registered_under_care_act, care_acts_selection, :id, diff --git a/app/views/schemes/primary_client_group.html.erb b/app/views/schemes/primary_client_group.html.erb index af3ea80e5..893eaff59 100644 --- a/app/views/schemes/primary_client_group.html.erb +++ b/app/views/schemes/primary_client_group.html.erb @@ -14,9 +14,6 @@
<%= f.govuk_error_summary %> - - - <% primary_client_group_selection = Scheme.primary_client_groups.keys.excluding("Missing").map { |key, _| OpenStruct.new(id: key, name: key.to_s.humanize) } %> <%= f.govuk_collection_radio_buttons :primary_client_group, primary_client_group_selection, diff --git a/app/views/schemes/secondary_client_group.html.erb b/app/views/schemes/secondary_client_group.html.erb index f785fb887..eb88881c4 100644 --- a/app/views/schemes/secondary_client_group.html.erb +++ b/app/views/schemes/secondary_client_group.html.erb @@ -14,9 +14,6 @@
<%= f.govuk_error_summary %> - - - <% secondary_client_group_selection = Scheme.secondary_client_groups.keys.excluding("Missing").map { |key, _| OpenStruct.new(id: key, name: key.to_s.humanize) } %> <%= f.govuk_collection_radio_buttons :secondary_client_group, secondary_client_group_selection, @@ -24,10 +21,10 @@ :name, legend: nil %> - <%= f.hidden_field :page, value: "secondary-client-group" %> - <% if request.query_parameters["check_answers"] == "true" %> - <%= f.hidden_field :check_answers, value: "true" %> - <% end %> + <%= f.hidden_field :page, value: "secondary-client-group" %> + <% if request.query_parameters["check_answers"] == "true" %> + <%= f.hidden_field :check_answers, value: "true" %> + <% end %> <%= f.govuk_submit "Save and continue" %>
diff --git a/app/views/schemes/show.html.erb b/app/views/schemes/show.html.erb index dab90cd8a..8e091bc02 100644 --- a/app/views/schemes/show.html.erb +++ b/app/views/schemes/show.html.erb @@ -10,10 +10,10 @@ <%= render partial: "organisations/headings", locals: { main: @scheme.service_name, sub: nil } %> -<%= render SubNavigationComponent.new(items: scheme_items(request.path, @scheme.id, @scheme.locations.count.eql?(1) ? "1 location" : "#{@scheme.locations.count} locations")) %> +<%= render SubNavigationComponent.new(items: scheme_items(request.path, @scheme.id, "Locations")) %>
-
+
<%= govuk_summary_list do |summary_list| %> <% @scheme.display_attributes.each do |attr| %> <% next if current_user.data_coordinator? && attr[:name] == ("Housing stock owned by") %> diff --git a/app/views/schemes/support.html.erb b/app/views/schemes/support.html.erb index 317b1d4f1..b4482bf66 100644 --- a/app/views/schemes/support.html.erb +++ b/app/views/schemes/support.html.erb @@ -14,9 +14,6 @@
<%= f.govuk_error_summary %> - - - <% support_type_selection = Scheme.support_types.keys.excluding("Missing").map { |key, _| OpenStruct.new(id: key, name: key.to_s.humanize) } %> <%= f.govuk_collection_radio_buttons :support_type, support_type_selection, @@ -31,7 +28,7 @@ :name, legend: { text: "Intended length of stay", size: "m" } %> - <%= f.hidden_field :page, value: "support" %> + <%= f.hidden_field :page, value: "support" %> <%= f.govuk_submit "Save and continue" %>
diff --git a/spec/features/schemes_spec.rb b/spec/features/schemes_spec.rb index 43f966c1c..838b28801 100644 --- a/spec/features/schemes_spec.rb +++ b/spec/features/schemes_spec.rb @@ -198,12 +198,12 @@ RSpec.describe "Schemes scheme Features" do it "shows service and locations tab" do expect(page).to have_link("Scheme") - expect(page).to have_link("#{scheme.locations.count} locations") + expect(page).to have_link("Locations") end context "when I click locations link" do before do - click_link("#{scheme.locations.count} locations") + click_link("Locations") end it "shows details of those locations" do @@ -725,7 +725,7 @@ RSpec.describe "Schemes scheme Features" do context "when I click to see locations" do before do - click_link "1 location" + click_link "Locations" end it "I see location details" do diff --git a/spec/helpers/navigation_items_helper_spec.rb b/spec/helpers/navigation_items_helper_spec.rb index 90a96017b..60d0f3d0e 100644 --- a/spec/helpers/navigation_items_helper_spec.rb +++ b/spec/helpers/navigation_items_helper_spec.rb @@ -190,13 +190,13 @@ RSpec.describe NavigationItemsHelper do let(:expected_scheme_items) do [ NavigationItemsHelper::NavigationItem.new("Scheme", "/schemes/1", true), - NavigationItemsHelper::NavigationItem.new("1 location", "/schemes/1/locations", false), + NavigationItemsHelper::NavigationItem.new("Locations", "/schemes/1/locations", false), ] end it "returns navigation items with Schemes item set as current" do expect(primary_items("/schemes/1", current_user)).to eq(expected_navigation_items) - expect(scheme_items("/schemes/1", 1, "1 location")).to eq(expected_scheme_items) + expect(scheme_items("/schemes/1", 1, "Locations")).to eq(expected_scheme_items) end end @@ -213,13 +213,13 @@ RSpec.describe NavigationItemsHelper do let(:expected_scheme_items) do [ NavigationItemsHelper::NavigationItem.new("Scheme", "/schemes/1", false), - NavigationItemsHelper::NavigationItem.new("1 location", "/schemes/1/locations", true), + NavigationItemsHelper::NavigationItem.new("Locations", "/schemes/1/locations", true), ] end it "returns navigation items with Schemes item set as current" do expect(primary_items("/schemes/1/locations", current_user)).to eq(expected_navigation_items) - expect(scheme_items("/schemes/1/locations", 1, "1 location")).to eq(expected_scheme_items) + expect(scheme_items("/schemes/1/locations", 1, "Locations")).to eq(expected_scheme_items) end end diff --git a/spec/requests/locations_controller_spec.rb b/spec/requests/locations_controller_spec.rb index e3909e754..8d1fce823 100644 --- a/spec/requests/locations_controller_spec.rb +++ b/spec/requests/locations_controller_spec.rb @@ -418,7 +418,7 @@ RSpec.describe LocationsController, type: :request do it "updates existing location for scheme with valid params and redirects to correct page" do follow_redirect! expect(response).to have_http_status(:ok) - expect(page).to have_content("1 location") + expect(page).to have_content("Locations") end it "updates existing location for scheme with valid params" do @@ -541,7 +541,7 @@ RSpec.describe LocationsController, type: :request do it "updates existing location for scheme with valid params and redirects to correct page" do follow_redirect! expect(response).to have_http_status(:ok) - expect(page).to have_content("1 location") + expect(page).to have_content("Locations") end it "updates existing location for scheme with valid params" do