diff --git a/Gemfile.lock b/Gemfile.lock index 9e0fe5371..2a9fb454f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -225,11 +225,11 @@ GEM net-protocol timeout nio4r (2.5.8) - nokogiri (1.13.8-arm64-darwin) + nokogiri (1.13.9-arm64-darwin) racc (~> 1.4) - nokogiri (1.13.8-x86_64-darwin) + nokogiri (1.13.9-x86_64-darwin) racc (~> 1.4) - nokogiri (1.13.8-x86_64-linux) + nokogiri (1.13.9-x86_64-linux) racc (~> 1.4) notifications-ruby-client (5.3.0) jwt (>= 1.5, < 3) diff --git a/app/components/search_component.html.erb b/app/components/search_component.html.erb index c63039b8c..2c10f3ed8 100644 --- a/app/components/search_component.html.erb +++ b/app/components/search_component.html.erb @@ -10,6 +10,6 @@ autocomplete: "off", class: "app-search__input" %> - <%= f.govuk_submit "Search", classes: "app-search__button" %> + <%= f.govuk_submit "Search", classes: "app-search__button govuk-button--secondary" %> <% end %> diff --git a/app/components/search_component.rb b/app/components/search_component.rb index 035500b54..e9fe83a3a 100644 --- a/app/components/search_component.rb +++ b/app/components/search_component.rb @@ -15,6 +15,10 @@ class SearchComponent < ViewComponent::Base request.path elsif request.path.include?("organisations") && request.path.include?("schemes") request.path + elsif request.path.include?("organisations") && request.path.include?("housing-providers") + request.path + elsif request.path.include?("organisations") && request.path.include?("managing-agents") + request.path elsif request.path.include?("users") user_path(current_user) elsif request.path.include?("organisations") diff --git a/app/controllers/organisation_relationships_controller.rb b/app/controllers/organisation_relationships_controller.rb new file mode 100644 index 000000000..f731209a8 --- /dev/null +++ b/app/controllers/organisation_relationships_controller.rb @@ -0,0 +1,125 @@ +class OrganisationRelationshipsController < ApplicationController + include Pagy::Backend + include Modules::SearchFilter + + before_action :authenticate_user! + before_action :authenticate_scope! + + def housing_providers + housing_providers = organisation.housing_providers + unpaginated_filtered_housing_providers = filtered_collection(housing_providers, search_term) + organisations = Organisation.where.not(id: @organisation.id).pluck(:id, :name) + respond_to do |format| + format.html do + @pagy, @housing_providers = pagy(unpaginated_filtered_housing_providers) + @organisations = organisations + @searched = search_term.presence + @total_count = housing_providers.size + render "organisation_relationships/housing_providers", layout: "application" + end + end + end + + def managing_agents + managing_agents = organisation.managing_agents + unpaginated_filtered_managing_agents = filtered_collection(managing_agents, search_term) + organisations = Organisation.where.not(id: @organisation.id).pluck(:id, :name) + respond_to do |format| + format.html do + @pagy, @managing_agents = pagy(unpaginated_filtered_managing_agents) + @organisations = organisations + @searched = search_term.presence + @total_count = managing_agents.size + render "organisation_relationships/managing_agents", layout: "application" + end + end + end + + def add_housing_provider + @organisations = Organisation.where.not(id: @organisation.id).pluck(:id, :name) + respond_to do |format| + format.html do + render "organisation_relationships/add_housing_provider", layout: "application" + end + end + end + + def add_managing_agent + @organisations = Organisation.where.not(id: @organisation.id).pluck(:id, :name) + respond_to do |format| + format.html do + render "organisation_relationships/add_managing_agent", layout: "application" + end + end + end + + def create_housing_provider + child_organisation_id = @organisation.id + parent_organisation_id = related_organisation_id + relationship_type = OrganisationRelationship::OWNING + if related_organisation_id.empty? + @organisation.errors.add :related_organisation_id, "You must choose a housing provider" + @organisations = Organisation.where.not(id: child_organisation_id).pluck(:id, :name) + render "organisation_relationships/add_housing_provider" + return + elsif OrganisationRelationship.exists?(child_organisation_id:, parent_organisation_id:, relationship_type:) + @organisation.errors.add :related_organisation_id, "You have already added this housing provider" + @organisations = Organisation.where.not(id: child_organisation_id).pluck(:id, :name) + render "organisation_relationships/add_housing_provider" + return + end + create!(child_organisation_id:, parent_organisation_id:, relationship_type:) + redirect_to housing_providers_organisation_path(related_organisation_id:) + end + + def create_managing_agent + parent_organisation_id = @organisation.id + child_organisation_id = related_organisation_id + relationship_type = OrganisationRelationship::MANAGING + + if related_organisation_id.empty? + @organisation.errors.add :related_organisation_id, "You must choose a managing agent" + @organisations = Organisation.where.not(id: parent_organisation_id).pluck(:id, :name) + render "organisation_relationships/add_managing_agent" + return + elsif OrganisationRelationship.exists?(child_organisation_id:, parent_organisation_id:, relationship_type:) + @organisation.errors.add :related_organisation_id, "You have already added this managing agent" + @organisations = Organisation.where.not(id: parent_organisation_id).pluck(:id, :name) + render "organisation_relationships/add_managing_agent" + return + end + + create!(child_organisation_id:, parent_organisation_id:, relationship_type:) + redirect_to managing_agents_organisation_path(related_organisation_id:) + end + +private + + def create!(child_organisation_id:, parent_organisation_id:, relationship_type:) + @resource = OrganisationRelationship.new(child_organisation_id:, parent_organisation_id:, relationship_type:) + @resource.save! + end + + def create(child_organisation_id, parent_organisation_id, relationship_type) + @resource = OrganisationRelationship.new(child_organisation_id:, parent_organisation_id:, relationship_type:) + @resource.save! + end + + def related_organisation_id + params["organisation"]["related_organisation_id"] + end + + def organisation + @organisation ||= Organisation.find(params[:id]) + end + + def search_term + params["search"] + end + + def authenticate_scope! + if current_user.organisation != organisation && !current_user.support? + render_not_found + end + end +end diff --git a/app/frontend/styles/_accessible-autocomplete.scss b/app/frontend/styles/_accessible-autocomplete.scss index 28e1b7e25..a59b38f44 100644 --- a/app/frontend/styles/_accessible-autocomplete.scss +++ b/app/frontend/styles/_accessible-autocomplete.scss @@ -5,12 +5,22 @@ .autocomplete__input { font-family: inherit; + background-image: url("data:image/svg+xml,%3Csvg class='app-search__icon' width='20' height='20' viewBox='0 0 27 27' fill='none' xmlns='http://www.w3.org/2000/svg' aria-hidden='true' focusable='false'%3E%3Ccircle cx='12.0161' cy='11.0161' r='8.51613' stroke='currentColor' stroke-width='3'%3E%3C/circle%3E%3Cline x1='17.8668' y1='17.3587' x2='26.4475' y2='25.9393' stroke='currentColor' stroke-width='3'%3E%3C/line%3E%3C/svg%3E"); + background-repeat: no-repeat; + background-size: 1em 1em; + background-position: 7px center; + text-indent: govuk-spacing(6); } .autocomplete__option__append { font-weight: bold; } +.autocomplete__hint { + font-family: inherit; + text-indent: govuk-spacing(6); +} + .autocomplete__option__hint { display: block; color: $govuk-secondary-text-colour; diff --git a/app/helpers/navigation_items_helper.rb b/app/helpers/navigation_items_helper.rb index 3ac422c2d..e99ee4a26 100644 --- a/app/helpers/navigation_items_helper.rb +++ b/app/helpers/navigation_items_helper.rb @@ -17,6 +17,8 @@ module NavigationItemsHelper NavigationItem.new("Schemes", "/schemes", subnav_supported_housing_schemes_path?(path)), NavigationItem.new("Users", users_organisation_path(current_user.organisation), subnav_users_path?(path)), NavigationItem.new("About your organisation", "/organisations/#{current_user.organisation.id}", subnav_details_path?(path)), + (NavigationItem.new("Housing providers", housing_providers_organisation_path(current_user.organisation), housing_providers_path?(path)) if FeatureToggle.managing_owning_enabled?), + (NavigationItem.new("Managing agents", managing_agents_organisation_path(current_user.organisation), managing_agents_path?(path)) if FeatureToggle.managing_owning_enabled?), ].compact else [ @@ -24,6 +26,8 @@ module NavigationItemsHelper FeatureToggle.sales_log_enabled? ? NavigationItem.new("Sales logs", sales_logs_path, sales_logs_current?(path)) : nil, NavigationItem.new("Users", users_organisation_path(current_user.organisation), subnav_users_path?(path)), NavigationItem.new("About your organisation", "/organisations/#{current_user.organisation.id}", subnav_details_path?(path)), + (NavigationItem.new("Housing providers", housing_providers_organisation_path(current_user.organisation), housing_providers_path?(path)) if FeatureToggle.managing_owning_enabled?), + (NavigationItem.new("Managing agents", managing_agents_organisation_path(current_user.organisation), managing_agents_path?(path)) if FeatureToggle.managing_owning_enabled?), ].compact end end @@ -31,18 +35,22 @@ module NavigationItemsHelper def secondary_items(path, current_organisation_id) if current_user.organisation.holds_own_stock? [ - NavigationItem.new("Lettings logs", "/organisations/#{current_organisation_id}/lettings-logs", subnav_logs_path?(path)), - FeatureToggle.sales_log_enabled? ? NavigationItem.new("Sales logs", "/organisations/#{current_organisation_id}/sales-logs", sales_logs_current?(path)) : nil, + NavigationItem.new("Lettings logs", "/organisations/#{current_organisation_id}/lettings-logs", subnav_lettings_logs_path?(path)), + FeatureToggle.sales_log_enabled? ? NavigationItem.new("Sales logs", "/organisations/#{current_organisation_id}/sales-logs", subnav_sales_logs_path?(path)) : nil, NavigationItem.new("Schemes", "/organisations/#{current_organisation_id}/schemes", subnav_supported_housing_schemes_path?(path)), NavigationItem.new("Users", "/organisations/#{current_organisation_id}/users", subnav_users_path?(path)), NavigationItem.new("About this organisation", "/organisations/#{current_organisation_id}", subnav_details_path?(path)), + (NavigationItem.new("Housing providers", housing_providers_organisation_path(current_user.organisation), housing_providers_path?(path)) if FeatureToggle.managing_owning_enabled?), + (NavigationItem.new("Managing agents", managing_agents_organisation_path(current_user.organisation), managing_agents_path?(path)) if FeatureToggle.managing_owning_enabled?), ].compact else [ - NavigationItem.new("Lettings logs", "/organisations/#{current_organisation_id}/lettings-logs", subnav_logs_path?(path)), + NavigationItem.new("Lettings logs", "/organisations/#{current_organisation_id}/lettings-logs", subnav_lettings_logs_path?(path)), FeatureToggle.sales_log_enabled? ? NavigationItem.new("Sales logs", "/organisations/#{current_organisation_id}/sales-logs", sales_logs_current?(path)) : nil, NavigationItem.new("Users", "/organisations/#{current_organisation_id}/users", subnav_users_path?(path)), NavigationItem.new("About this organisation", "/organisations/#{current_organisation_id}", subnav_details_path?(path)), + (NavigationItem.new("Housing providers", housing_providers_organisation_path(current_user.organisation), housing_providers_path?(path)) if FeatureToggle.managing_owning_enabled?), + (NavigationItem.new("Managing agents", managing_agents_organisation_path(current_user.organisation), managing_agents_path?(path)) if FeatureToggle.managing_owning_enabled?), ].compact end end @@ -84,11 +92,23 @@ private (path.include?("/organisations") && path.include?("/users")) || path.include?("/users/") end - def subnav_logs_path?(path) + def subnav_lettings_logs_path?(path) path.include?("/organisations") && path.include?("/lettings-logs") end + def subnav_sales_logs_path?(path) + path.include?("/organisations") && path.include?("/sales-logs") + end + def subnav_details_path?(path) path.include?("/organisations") && path.include?("/details") end + + def housing_providers_path?(path) + path.include?("/housing-providers") + end + + def managing_agents_path?(path) + path.include?("/managing-agents") + end end diff --git a/app/models/bulk_upload.rb b/app/models/bulk_upload.rb index 183dc274e..fa2a7a0e9 100644 --- a/app/models/bulk_upload.rb +++ b/app/models/bulk_upload.rb @@ -35,10 +35,7 @@ class BulkUpload created_by: current_user, ) map_row(row).each do |attr_key, attr_val| - update = lettings_log.update(attr_key => attr_val) - unless update - # TODO: determine what to do when a bulk upload contains field values that don't pass validations - end + _update = lettings_log.update(attr_key => attr_val) rescue ArgumentError # TODO: determine what we want to do when bulk upload contains totally invalid data for a field. end diff --git a/app/models/form/lettings/questions/scheme_id.rb b/app/models/form/lettings/questions/scheme_id.rb index 064be8032..7d7966c00 100644 --- a/app/models/form/lettings/questions/scheme_id.rb +++ b/app/models/form/lettings/questions/scheme_id.rb @@ -33,10 +33,6 @@ class Form::Lettings::Questions::SchemeId < ::Form::Question !supported_housing_selected?(lettings_log) end - def answer_selected?(lettings_log, answer) - lettings_log[id] == answer.name || lettings_log[id] == answer.resource - end - private def supported_housing_selected?(lettings_log) diff --git a/app/models/form/sales/pages/buyer1_income.rb b/app/models/form/sales/pages/buyer1_income.rb new file mode 100644 index 000000000..e4f88be81 --- /dev/null +++ b/app/models/form/sales/pages/buyer1_income.rb @@ -0,0 +1,16 @@ +class Form::Sales::Pages::Buyer1Income < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "buyer_1_income" + @header = "" + @description = "" + @subsection = subsection + end + + def questions + @questions ||= [ + Form::Sales::Questions::Buyer1IncomeKnown.new(nil, nil, self), + Form::Sales::Questions::Buyer1Income.new(nil, nil, self), + ] + end +end diff --git a/app/models/form/sales/pages/property_local_authority.rb b/app/models/form/sales/pages/property_local_authority.rb new file mode 100644 index 000000000..1698ace47 --- /dev/null +++ b/app/models/form/sales/pages/property_local_authority.rb @@ -0,0 +1,16 @@ +class Form::Sales::Pages::PropertyLocalAuthority < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "property_local_authority" + @header = "" + @description = "" + @subsection = subsection + end + + def questions + @questions ||= [ + Form::Sales::Questions::PropertyLocalAuthorityKnown.new(nil, nil, self), + Form::Sales::Questions::PropertyLocalAuthority.new(nil, nil, self), + ] + end +end diff --git a/app/models/form/sales/questions/buyer1_income.rb b/app/models/form/sales/questions/buyer1_income.rb new file mode 100644 index 000000000..f4e586b39 --- /dev/null +++ b/app/models/form/sales/questions/buyer1_income.rb @@ -0,0 +1,14 @@ +class Form::Sales::Questions::Buyer1Income < ::Form::Question + def initialize(id, hsh, page) + super + @id = "income1" + @check_answer_label = "Buyer 1’s gross annual income" + @header = "Buyer 1’s gross annual income" + @type = "numeric" + @page = page + @min = 0 + @step = 1 + @width = 5 + @prefix = "£" + end +end diff --git a/app/models/form/sales/questions/buyer1_income_known.rb b/app/models/form/sales/questions/buyer1_income_known.rb new file mode 100644 index 000000000..923045ef9 --- /dev/null +++ b/app/models/form/sales/questions/buyer1_income_known.rb @@ -0,0 +1,21 @@ +class Form::Sales::Questions::Buyer1IncomeKnown < ::Form::Question + def initialize(id, hsh, page) + super + @id = "income1nk" + @check_answer_label = "Buyer 1’s gross annual income" + @header = "Do you know buyer 1’s annual income?" + @type = "radio" + @answer_options = ANSWER_OPTIONS + @page = page + @guidance_position = GuidancePosition::BOTTOM + @guidance_partial = "what_counts_as_income_sales" + @conditional_for = { + "income1" => [0], + } + end + + ANSWER_OPTIONS = { + "0" => { "value" => "Yes" }, + "1" => { "value" => "No" }, + }.freeze +end diff --git a/app/models/form/sales/questions/property_local_authority.rb b/app/models/form/sales/questions/property_local_authority.rb new file mode 100644 index 000000000..462956eeb --- /dev/null +++ b/app/models/form/sales/questions/property_local_authority.rb @@ -0,0 +1,331 @@ +class Form::Sales::Questions::PropertyLocalAuthority < ::Form::Question + def initialize(id, hsh, page) + super + @id = "la" + @check_answer_label = "Local authority" + @header = "What is the local authority of the property?" + @type = "select" + @answer_options = ANSWER_OPTIONS + @page = page + end + + ANSWER_OPTIONS = { + "" => "Select an option", + "E07000223" => "Adur", + "E07000026" => "Allerdale", + "E07000032" => "Amber Valley", + "E07000224" => "Arun", + "E07000170" => "Ashfield", + "E07000105" => "Ashford", + "E07000200" => "Babergh", + "E09000002" => "Barking and Dagenham", + "E09000003" => "Barnet", + "E08000016" => "Barnsley", + "E07000027" => "Barrow-in-Furness", + "E07000066" => "Basildon", + "E07000084" => "Basingstoke and Deane", + "E07000171" => "Bassetlaw", + "E06000022" => "Bath and North East Somerset", + "E06000055" => "Bedford", + "E09000004" => "Bexley", + "E08000025" => "Birmingham", + "E07000129" => "Blaby", + "E06000008" => "Blackburn with Darwen", + "E06000009" => "Blackpool", + "E07000033" => "Bolsover", + "E08000001" => "Bolton", + "E07000136" => "Boston", + "E06000058" => "Bournemouth, Christchurch and Poole", + "E06000036" => "Bracknell Forest", + "E08000032" => "Bradford", + "E07000067" => "Braintree", + "E07000143" => "Breckland", + "E09000005" => "Brent", + "E07000068" => "Brentwood", + "E06000043" => "Brighton and Hove", + "E06000023" => "Bristol, City of", + "E07000144" => "Broadland", + "E09000006" => "Bromley", + "E07000234" => "Bromsgrove", + "E07000095" => "Broxbourne", + "E07000172" => "Broxtowe", + "E06000060" => "Buckinghamshire", + "E07000117" => "Burnley", + "E08000002" => "Bury", + "E08000033" => "Calderdale", + "E07000008" => "Cambridge", + "E09000007" => "Camden", + "E07000192" => "Cannock Chase", + "E07000106" => "Canterbury", + "E07000028" => "Carlisle", + "E07000069" => "Castle Point", + "E06000056" => "Central Bedfordshire", + "E07000130" => "Charnwood", + "E07000070" => "Chelmsford", + "E07000078" => "Cheltenham", + "E07000177" => "Cherwell", + "E06000049" => "Cheshire East", + "E06000050" => "Cheshire West and Chester", + "E07000034" => "Chesterfield", + "E07000225" => "Chichester", + "E07000118" => "Chorley", + "E09000001" => "City of London", + "E07000071" => "Colchester", + "E07000029" => "Copeland", + "E07000150" => "Corby", + "E06000052" => "Cornwall", + "E07000079" => "Cotswold", + "E06000047" => "County Durham", + "E08000026" => "Coventry", + "E07000163" => "Craven", + "E07000226" => "Crawley", + "E09000008" => "Croydon", + "E07000096" => "Dacorum", + "E06000005" => "Darlington", + "E07000107" => "Dartford", + "E07000151" => "Daventry", + "E06000015" => "Derby", + "E07000035" => "Derbyshire Dales", + "E08000017" => "Doncaster", + "E06000059" => "Dorset", + "E07000108" => "Dover", + "E08000027" => "Dudley", + "E09000009" => "Ealing", + "E07000009" => "East Cambridgeshire", + "E07000040" => "East Devon", + "E07000085" => "East Hampshire", + "E07000242" => "East Hertfordshire", + "E07000137" => "East Lindsey", + "E07000152" => "East Northamptonshire", + "E06000011" => "East Riding of Yorkshire", + "E07000193" => "East Staffordshire", + "E07000244" => "East Suffolk", + "E07000061" => "Eastbourne", + "E07000086" => "Eastleigh", + "E07000030" => "Eden", + "E07000207" => "Elmbridge", + "E09000010" => "Enfield", + "E07000072" => "Epping Forest", + "E07000208" => "Epsom and Ewell", + "E07000036" => "Erewash", + "E07000041" => "Exeter", + "E07000087" => "Fareham", + "E07000010" => "Fenland", + "E07000112" => "Folkestone and Hythe", + "E07000080" => "Forest of Dean", + "E07000119" => "Fylde", + "E08000037" => "Gateshead", + "E07000173" => "Gedling", + "E07000081" => "Gloucester", + "E07000088" => "Gosport", + "E07000109" => "Gravesham", + "E07000145" => "Great Yarmouth", + "E09000011" => "Greenwich", + "E07000209" => "Guildford", + "W06000002" => "Gwynedd", + "E09000012" => "Hackney", + "E06000006" => "Halton", + "E07000164" => "Hambleton", + "E09000013" => "Hammersmith and Fulham", + "E07000131" => "Harborough", + "E09000014" => "Haringey", + "E07000073" => "Harlow", + "E07000165" => "Harrogate", + "E09000015" => "Harrow", + "E07000089" => "Hart", + "E06000001" => "Hartlepool", + "E07000062" => "Hastings", + "E07000090" => "Havant", + "E09000016" => "Havering", + "E06000019" => "Herefordshire, County of", + "E07000098" => "Hertsmere", + "E07000037" => "High Peak", + "S12000017" => "Highland", + "E09000017" => "Hillingdon", + "E07000132" => "Hinckley and Bosworth", + "E07000227" => "Horsham", + "E09000018" => "Hounslow", + "E07000011" => "Huntingdonshire", + "E07000120" => "Hyndburn", + "E07000202" => "Ipswich", + "E06000046" => "Isle of Wight", + "E06000053" => "Isles of Scilly", + "E09000019" => "Islington", + "E09000020" => "Kensington and Chelsea", + "E07000153" => "Kettering", + "E07000146" => "King’s Lynn and West Norfolk", + "E06000010" => "Kingston upon Hull, City of", + "E09000021" => "Kingston upon Thames", + "E08000034" => "Kirklees", + "E08000011" => "Knowsley", + "E09000022" => "Lambeth", + "E07000121" => "Lancaster", + "E08000035" => "Leeds", + "E06000016" => "Leicester", + "E07000063" => "Lewes", + "E09000023" => "Lewisham", + "E07000194" => "Lichfield", + "E07000138" => "Lincoln", + "E08000012" => "Liverpool", + "E06000032" => "Luton", + "E07000110" => "Maidstone", + "E07000074" => "Maldon", + "E07000235" => "Malvern Hills", + "E08000003" => "Manchester", + "E07000174" => "Mansfield", + "E06000035" => "Medway", + "E07000133" => "Melton", + "E07000187" => "Mendip", + "E09000024" => "Merton", + "E07000042" => "Mid Devon", + "E07000203" => "Mid Suffolk", + "E07000228" => "Mid Sussex", + "E06000002" => "Middlesbrough", + "E06000042" => "Milton Keynes", + "E07000210" => "Mole Valley", + "E07000091" => "New Forest", + "E07000175" => "Newark and Sherwood", + "E08000021" => "Newcastle upon Tyne", + "E07000195" => "Newcastle-under-Lyme", + "E09000025" => "Newham", + "E07000043" => "North Devon", + "E07000038" => "North East Derbyshire", + "E06000012" => "North East Lincolnshire", + "E07000099" => "North Hertfordshire", + "E07000139" => "North Kesteven", + "E06000013" => "North Lincolnshire", + "E07000147" => "North Norfolk", + "E06000024" => "North Somerset", + "E08000022" => "North Tyneside", + "E07000218" => "North Warwickshire", + "E07000134" => "North West Leicestershire", + "E07000154" => "Northampton", + "E06000057" => "Northumberland", + "E07000148" => "Norwich", + "E06000018" => "Nottingham", + "E07000219" => "Nuneaton and Bedworth", + "E07000135" => "Oadby and Wigston", + "E08000004" => "Oldham", + "E07000178" => "Oxford", + "E07000122" => "Pendle", + "E06000031" => "Peterborough", + "E06000026" => "Plymouth", + "E06000044" => "Portsmouth", + "E07000123" => "Preston", + "E06000038" => "Reading", + "E09000026" => "Redbridge", + "E06000003" => "Redcar and Cleveland", + "E07000236" => "Redditch", + "E07000211" => "Reigate and Banstead", + "E07000124" => "Ribble Valley", + "E09000027" => "Richmond upon Thames", + "E07000166" => "Richmondshire", + "E08000005" => "Rochdale", + "E07000075" => "Rochford", + "E07000125" => "Rossendale", + "E07000064" => "Rother", + "E08000018" => "Rotherham", + "E07000220" => "Rugby", + "E07000212" => "Runnymede", + "E07000176" => "Rushcliffe", + "E07000092" => "Rushmoor", + "E06000017" => "Rutland", + "E07000167" => "Ryedale", + "E08000006" => "Salford", + "E08000028" => "Sandwell", + "E07000168" => "Scarborough", + "E07000188" => "Sedgemoor", + "E08000014" => "Sefton", + "E07000169" => "Selby", + "E07000111" => "Sevenoaks", + "E08000019" => "Sheffield", + "E06000051" => "Shropshire", + "E06000039" => "Slough", + "E08000029" => "Solihull", + "E07000246" => "Somerset West and Taunton", + "E07000012" => "South Cambridgeshire", + "E07000039" => "South Derbyshire", + "E06000025" => "South Gloucestershire", + "E07000044" => "South Hams", + "E07000140" => "South Holland", + "E07000141" => "South Kesteven", + "E07000031" => "South Lakeland", + "E07000149" => "South Norfolk", + "E07000155" => "South Northamptonshire", + "E07000179" => "South Oxfordshire", + "E07000126" => "South Ribble", + "E07000189" => "South Somerset", + "E07000196" => "South Staffordshire", + "E08000023" => "South Tyneside", + "E06000045" => "Southampton", + "E06000033" => "Southend-on-Sea", + "E09000028" => "Southwark", + "E07000213" => "Spelthorne", + "E07000240" => "St Albans", + "E08000013" => "St. Helens", + "E07000197" => "Stafford", + "E07000198" => "Staffordshire Moorlands", + "E07000243" => "Stevenage", + "E08000007" => "Stockport", + "E06000004" => "Stockton-on-Tees", + "E06000021" => "Stoke-on-Trent", + "E07000221" => "Stratford-on-Avon", + "E07000082" => "Stroud", + "E08000024" => "Sunderland", + "E07000214" => "Surrey Heath", + "E09000029" => "Sutton", + "E07000113" => "Swale", + "E06000030" => "Swindon", + "E08000008" => "Tameside", + "E07000199" => "Tamworth", + "E07000215" => "Tandridge", + "E07000045" => "Teignbridge", + "E06000020" => "Telford and Wrekin", + "E07000076" => "Tendring", + "E07000093" => "Test Valley", + "E07000083" => "Tewkesbury", + "E07000114" => "Thanet", + "E07000102" => "Three Rivers", + "E06000034" => "Thurrock", + "E07000115" => "Tonbridge and Malling", + "E06000027" => "Torbay", + "E07000046" => "Torridge", + "E09000030" => "Tower Hamlets", + "E08000009" => "Trafford", + "E07000116" => "Tunbridge Wells", + "E07000077" => "Uttlesford", + "E07000180" => "Vale of White Horse", + "E08000036" => "Wakefield", + "E08000030" => "Walsall", + "E09000031" => "Waltham Forest", + "E09000032" => "Wandsworth", + "E06000007" => "Warrington", + "E07000222" => "Warwick", + "E07000103" => "Watford", + "E07000216" => "Waverley", + "E07000065" => "Wealden", + "E07000156" => "Wellingborough", + "E07000241" => "Welwyn Hatfield", + "E06000037" => "West Berkshire", + "E07000047" => "West Devon", + "E07000127" => "West Lancashire", + "E07000142" => "West Lindsey", + "E07000181" => "West Oxfordshire", + "E07000245" => "West Suffolk", + "E09000033" => "Westminster", + "E08000010" => "Wigan", + "E06000054" => "Wiltshire", + "E07000094" => "Winchester", + "E06000040" => "Windsor and Maidenhead", + "E08000015" => "Wirral", + "E07000217" => "Woking", + "E06000041" => "Wokingham", + "E08000031" => "Wolverhampton", + "E07000237" => "Worcester", + "E07000229" => "Worthing", + "E07000238" => "Wychavon", + "E07000128" => "Wyre", + "E07000239" => "Wyre Forest", + "E06000014" => "York", + }.freeze +end diff --git a/app/models/form/sales/questions/property_local_authority_known.rb b/app/models/form/sales/questions/property_local_authority_known.rb new file mode 100644 index 000000000..11ebeca6a --- /dev/null +++ b/app/models/form/sales/questions/property_local_authority_known.rb @@ -0,0 +1,24 @@ +class Form::Sales::Questions::PropertyLocalAuthorityKnown < ::Form::Question + def initialize(id, hsh, page) + super + @id = "la_known" + @check_answer_label = "Local authority known" + @header = "Do you know the local authority of the property?" + @type = "radio" + @answer_options = ANSWER_OPTIONS + @conditional_for = { "la" => [1] } + @hidden_in_check_answers = { + "depends_on" => [ + { + "la_known" => 1, + }, + ], + } + @page = page + end + + ANSWER_OPTIONS = { + "1" => { "value" => "Yes" }, + "0" => { "value" => "No" }, + }.freeze +end diff --git a/app/models/form/sales/sections/finances.rb b/app/models/form/sales/sections/finances.rb new file mode 100644 index 000000000..c2c4082fd --- /dev/null +++ b/app/models/form/sales/sections/finances.rb @@ -0,0 +1,12 @@ +class Form::Sales::Sections::Finances < ::Form::Section + def initialize(id, hsh, form) + super + @id = "finances" + @label = "Finances" + @description = "" + @form = form + @subsections = [ + Form::Sales::Subsections::IncomeBenefitsAndOutgoings.new(nil, nil, self), + ] + end +end diff --git a/app/models/form/sales/subsections/income_benefits_and_outgoings.rb b/app/models/form/sales/subsections/income_benefits_and_outgoings.rb new file mode 100644 index 000000000..2c9d779b4 --- /dev/null +++ b/app/models/form/sales/subsections/income_benefits_and_outgoings.rb @@ -0,0 +1,15 @@ +class Form::Sales::Subsections::IncomeBenefitsAndOutgoings < ::Form::Subsection + def initialize(id, hsh, section) + super + @id = "income_benefits_and_outgoings" + @label = "Income, benefits and outgoings" + @section = section + @depends_on = [{ "setup" => "completed" }] + end + + def pages + @pages ||= [ + Form::Sales::Pages::Buyer1Income.new(nil, nil, self), + ] + end +end diff --git a/app/models/form/sales/subsections/property_information.rb b/app/models/form/sales/subsections/property_information.rb index 61791cb79..5ebe7b581 100644 --- a/app/models/form/sales/subsections/property_information.rb +++ b/app/models/form/sales/subsections/property_information.rb @@ -12,6 +12,7 @@ class Form::Sales::Subsections::PropertyInformation < ::Form::Subsection Form::Sales::Pages::PropertyNumberOfBedrooms.new(nil, nil, self), Form::Sales::Pages::PropertyBuildingType.new(nil, nil, self), Form::Sales::Pages::PropertyUnitType.new(nil, nil, self), + Form::Sales::Pages::PropertyLocalAuthority.new(nil, nil, self), ] end end diff --git a/app/models/form_handler.rb b/app/models/form_handler.rb index c9d45e876..c6dde13ab 100644 --- a/app/models/form_handler.rb +++ b/app/models/form_handler.rb @@ -22,6 +22,7 @@ class FormHandler sales_sections = [ Form::Sales::Sections::PropertyInformation, Form::Sales::Sections::Household, + Form::Sales::Sections::Finances, ] current_form = Form.new(nil, current_collection_start_year, sales_sections, "sales") previous_form = Form.new(nil, current_collection_start_year - 1, sales_sections, "sales") diff --git a/app/models/organisation.rb b/app/models/organisation.rb index 9eb039ab1..e420ca9d8 100644 --- a/app/models/organisation.rb +++ b/app/models/organisation.rb @@ -13,9 +13,13 @@ class Organisation < ApplicationRecord has_many :child_organisation_relationships, foreign_key: :parent_organisation_id, class_name: "OrganisationRelationship" has_many :child_organisations, through: :child_organisation_relationships + has_many :housing_provider_relationships, -> { where(relationship_type: OrganisationRelationship::OWNING) }, foreign_key: :child_organisation_id, class_name: "OrganisationRelationship" + has_many :housing_providers, through: :housing_provider_relationships, source: :parent_organisation + has_many :managing_agent_relationships, -> { where(relationship_type: OrganisationRelationship::MANAGING) }, foreign_key: :parent_organisation_id, class_name: "OrganisationRelationship" + has_many :managing_agents, through: :managing_agent_relationships, source: :child_organisation + scope :search_by_name, ->(name) { where("name ILIKE ?", "%#{name}%") } scope :search_by, ->(param) { search_by_name(param) } - has_paper_trail auto_strip_attributes :name @@ -82,9 +86,9 @@ class Organisation < ApplicationRecord { name: "Registration number", value: housing_registration_no || "", editable: false }, { name: "Rent_periods", value: rent_period_labels, editable: false, format: :bullet }, { name: "Owns housing stock", value: holds_own_stock ? "Yes" : "No", editable: false }, - { name: "Other stock owners", value: other_stock_owners, editable: false }, - { name: "Managing agents", value: managing_agents, editable: false }, + ({ name: "Other stock owners", value: other_stock_owners, editable: false } unless FeatureToggle.managing_owning_enabled?), + ({ name: "Managing agents", value: managing_agents_label, editable: false } unless FeatureToggle.managing_owning_enabled?), { name: "Data protection agreement", value: data_protection_agreement_string, editable: false }, - ] + ].compact end end diff --git a/app/models/organisation_relationship.rb b/app/models/organisation_relationship.rb index 034fc5d0e..acda8d2c4 100644 --- a/app/models/organisation_relationship.rb +++ b/app/models/organisation_relationship.rb @@ -1,4 +1,13 @@ class OrganisationRelationship < ApplicationRecord belongs_to :child_organisation, class_name: "Organisation" belongs_to :parent_organisation, class_name: "Organisation" + + OWNING = "owning".freeze + MANAGING = "managing".freeze + RELATIONSHIP_TYPE = { + OWNING => 0, + MANAGING => 1, + }.freeze + + enum relationship_type: RELATIONSHIP_TYPE end diff --git a/app/views/form/guidance/_what_counts_as_income_sales.html.erb b/app/views/form/guidance/_what_counts_as_income_sales.html.erb new file mode 100644 index 000000000..c5e2c7116 --- /dev/null +++ b/app/views/form/guidance/_what_counts_as_income_sales.html.erb @@ -0,0 +1,17 @@ +<%= govuk_details(summary_text: "What counts as income?") do %> +

You should include any income from:

+ + +

Don’t include:

+ +<% end %> diff --git a/app/views/form/review.html.erb b/app/views/form/review.html.erb index 59e0bde40..127e52762 100644 --- a/app/views/form/review.html.erb +++ b/app/views/form/review.html.erb @@ -1,7 +1,7 @@ <% content_for :title, "Review lettings log" %> <% content_for :breadcrumbs, govuk_breadcrumbs(breadcrumbs: { "Logs" => "/logs", - "Log #{@log.id}" => "/logs/#{@log.id}", + "Log #{@log.id}" => "/lettings-logs/#{@log.id}", "Review lettings log" => "", }) %> diff --git a/app/views/logs/index.html.erb b/app/views/logs/index.html.erb index f84a487df..431ca0f45 100644 --- a/app/views/logs/index.html.erb +++ b/app/views/logs/index.html.erb @@ -1,9 +1,13 @@ -<% item_label = format_label(@pagy.count, "log") %> +<% item_label = format_label(@pagy.count, "logs") %> <% title = format_title(@searched, "Logs", current_user, item_label, @pagy.count, nil) %> <% content_for :title, title %> -<%= render partial: "organisations/headings", locals: current_user.support? ? { main: "Logs", sub: nil } : { main: "Logs", sub: current_user.organisation.name } %> +<% if current_page?(controller: 'lettings_logs', action: 'index') %> + <%= render partial: "organisations/headings", locals: current_user.support? ? { main: "Lettings logs", sub: nil } : { main: "Lettings logs", sub: current_user.organisation.name } %> +<% elsif current_page?(controller: 'sales_logs', action: 'index') %> + <%= render partial: "organisations/headings", locals: current_user.support? ? { main: "Sales logs", sub: nil } : { main: "Sales logs", sub: current_user.organisation.name } %> +<% end %>
diff --git a/app/views/organisation_relationships/_housing_provider_list.erb b/app/views/organisation_relationships/_housing_provider_list.erb new file mode 100644 index 000000000..e43766c5b --- /dev/null +++ b/app/views/organisation_relationships/_housing_provider_list.erb @@ -0,0 +1,22 @@ +
+ <%= govuk_table do |table| %> + <%= table.caption(classes: %w[govuk-!-font-size-19 govuk-!-font-weight-regular]) do |caption| %> + <%= render(SearchResultCaptionComponent.new(searched:, count: pagy.count, item_label:, total_count:, item: "housing providers", path: request.path)) %> + <% end %> + <% @housing_providers.each do |housing_provider| %> + <%= table.body do |body| %> + <%= body.row do |row| %> + <% row.cell(text: housing_provider.name) %> + <% if current_user.data_coordinator? || current_user.support? %> + <% row.cell(html_attributes: { + scope: "row", + class: "govuk-!-text-align-right", + }) do %> + <%= govuk_link_to("Remove", "housing-providers/#{housing_provider.id}") %> + <% end %> + <% end %> + <% end %> + <% end %> + <% end %> + <% end %> +
diff --git a/app/views/organisation_relationships/_managing_agent_list.erb b/app/views/organisation_relationships/_managing_agent_list.erb new file mode 100644 index 000000000..3c69bbf71 --- /dev/null +++ b/app/views/organisation_relationships/_managing_agent_list.erb @@ -0,0 +1,22 @@ +
+ <%= govuk_table do |table| %> + <%= table.caption(classes: %w[govuk-!-font-size-19 govuk-!-font-weight-regular]) do |caption| %> + <%= render(SearchResultCaptionComponent.new(searched:, count: pagy.count, item_label:, total_count:, item: "agents", path: request.path)) %> + <% end %> + <% @managing_agents.each do |managing_agent| %> + <%= table.body do |body| %> + <%= body.row do |row| %> + <% row.cell(text: managing_agent.name) %> + <% if current_user.data_coordinator? || current_user.support? %> + <% row.cell(html_attributes: { + scope: "row", + class: "govuk-!-text-align-right", + }) do %> + <%= govuk_link_to("Remove", "managing-agents/#{managing_agent.id}") %> + <% end %> + <% end %> + <% end %> + <% end %> + <% end %> + <% end %> +
diff --git a/app/views/organisation_relationships/_related_organisation_select_question.html.erb b/app/views/organisation_relationships/_related_organisation_select_question.html.erb new file mode 100644 index 000000000..cc27c2b8b --- /dev/null +++ b/app/views/organisation_relationships/_related_organisation_select_question.html.erb @@ -0,0 +1,3 @@ +<% answers = question.answer_options.map { |key, value| OpenStruct.new(id: key, name: value) } %> +<%= f.govuk_collection_select :related_organisation_id, answers, :id, :name, label: { hidden: true }, "data-controller": "accessible-autocomplete" do %> +<% end %> diff --git a/app/views/organisation_relationships/add_housing_provider.html.erb b/app/views/organisation_relationships/add_housing_provider.html.erb new file mode 100644 index 000000000..3cce90db1 --- /dev/null +++ b/app/views/organisation_relationships/add_housing_provider.html.erb @@ -0,0 +1,34 @@ +<%= form_with model: @organisation, url: housing_providers_organisation_path, method: "post", local: true do |f| %> + <% if current_user.support? %> + <%= render partial: "organisations/headings", locals: { main: @organisation.name, sub: nil } %> + <%= render SubNavigationComponent.new(items: secondary_items(request.path, @organisation.id)) %> +

Add Housing Provider

+ <%= govuk_back_link(href: :back) %> + <%= render partial: "organisations/headings", locals: { main: "What is the name of this organisation's housing provider?", sub: nil } %> +

Start typing to search for a housing provider

+ <% else %> + <% content_for :before_content do %> + <%= govuk_back_link(href: :back) %> + <% end %> + <%= render partial: "organisations/headings", locals: { main: "What is the name of your housing provider?", sub: nil } %> +

Start typing to search for your housing provider

+ <% end %> + <% answer_options = { "" => "Select an option" } %> + <% @organisations.each do |organisation| %> + <% answer_options[organisation[0]] = organisation[1] %> + <% end %> + <%= render partial: "organisation_relationships/related_organisation_select_question", locals: { + question: Form::Question.new("", { "answer_options" => answer_options }, nil), + f:, + } %> + <%= f.govuk_submit "Add" %> + <%= govuk_details(summary_text: "Can't find the housing provider you're looking for?") do %> + + <% end %> +<% end %> diff --git a/app/views/organisation_relationships/add_managing_agent.html.erb b/app/views/organisation_relationships/add_managing_agent.html.erb new file mode 100644 index 000000000..bf5c380d5 --- /dev/null +++ b/app/views/organisation_relationships/add_managing_agent.html.erb @@ -0,0 +1,34 @@ +<%= form_with model: @organisation, url: managing_agents_organisation_path, method: "post", local: true do |f| %> + <% if current_user.support? %> + <%= render partial: "organisations/headings", locals: { main: @organisation.name, sub: nil } %> + <%= render SubNavigationComponent.new(items: secondary_items(request.path, @organisation.id)) %> +

Add Managing Agent

+ <%= govuk_back_link(href: :back) %> + <%= render partial: "organisations/headings", locals: { main: "What is the name of this organisation's managing agent?", sub: nil } %> +

Start typing to search for a managing agent

+ <% else %> + <% content_for :before_content do %> + <%= govuk_back_link(href: :back) %> + <% end %> + <%= render partial: "organisations/headings", locals: { main: "What is the name of your managing agent?", sub: nil } %> +

Start typing to search for your managing agent

+ <% end %> + <% answer_options = { "" => "Select an option" } %> + <% @organisations.each do |organisation| %> + <% answer_options[organisation[0]] = organisation[1] %> + <% end %> + <%= render partial: "organisation_relationships/related_organisation_select_question", locals: { + question: Form::Question.new("", { "answer_options" => answer_options }, nil), + f:, + } %> + <%= f.govuk_submit "Add" %> + <%= govuk_details(summary_text: "Can't find the managing agent you're looking for?") do %> + + <% end %> +<% end %> diff --git a/app/views/organisation_relationships/housing_providers.html.erb b/app/views/organisation_relationships/housing_providers.html.erb new file mode 100644 index 000000000..9ff96e68d --- /dev/null +++ b/app/views/organisation_relationships/housing_providers.html.erb @@ -0,0 +1,48 @@ +<% item_label = format_label(@pagy.count, "housing providers") %> + +<% if current_user.data_coordinator? %> + <% if params["related_organisation_id"] %> + <%= govuk_notification_banner( + title_text: "Success", + success: true, title_heading_level: 3, + title_id: "swanky-notifications" + ) do |notification_banner| + notification_banner.heading(text: "#{Organisation.find(params['related_organisation_id']).name} is now one of your housing providers") + end %> + <% end %> +<% end %> +<% if current_user.support? %> + <%= render partial: "organisations/headings", locals: { main: @organisation.name, sub: nil } %> + <%= render SubNavigationComponent.new(items: secondary_items(request.path, @organisation.id)) %> +

Housing Providers

+ <% if params["related_organisation_id"] %> + <%= govuk_notification_banner( + title_text: "Success", + success: true, title_heading_level: 3, + title_id: "swanky-notifications" + ) do |notification_banner| + notification_banner.heading(text: "#{Organisation.find(params['related_organisation_id']).name} is now one of this organisation's housing providers") + end %> + <% end %> +

This organisation can submit logs for its housing providers.

+ <% if @total_count == 0 %> +

This organisation does not currently have any housing providers.

+ <% end %> +<% else %> + <%= render partial: "organisations/headings", locals: { main: "Your housing providers", sub: current_user.organisation.name } %> +

Your organisation can submit logs for its housing providers.

+ <% if @total_count == 0 %> +

You do not currently have any housing providers.

+ <% end %> +<% end %> + +<% if current_user.support? %> + <%= govuk_button_link_to "Add a housing provider", housing_providers_add_organisation_path(organisation_id: @organisation.id), html: { method: :get } %> + <% elsif current_user.data_coordinator? %> + <%= govuk_button_link_to "Add a housing provider", housing_providers_add_organisation_path, html: { method: :get } %> +<% end %> +<% if @total_count != 0 %> + <%= render SearchComponent.new(current_user:, search_label: "Search for a housing provider", value: @searched) %> + <%= render partial: "organisation_relationships/housing_provider_list", locals: { index: @housing_providers, title: "Housing providers", pagy: @pagy, searched: @searched, item_label:, total_count: @total_count } %> + <%= render partial: "pagy/nav", locals: { pagy: @pagy, item_name: "housing providers" } %> +<% end %> diff --git a/app/views/organisation_relationships/managing_agents.html.erb b/app/views/organisation_relationships/managing_agents.html.erb new file mode 100644 index 000000000..f09646454 --- /dev/null +++ b/app/views/organisation_relationships/managing_agents.html.erb @@ -0,0 +1,50 @@ +<% item_label = format_label(@pagy.count, "managing agents") %> + +<% if current_user.data_coordinator? %> + <% if params["related_organisation_id"] %> + <%= govuk_notification_banner( + title_text: "Success", + success: true, title_heading_level: 3, + title_id: "swanky-notifications" + ) do |notification_banner| + notification_banner.heading(text: "#{Organisation.find(params['related_organisation_id']).name} is now one of this organisation's managing agents") + end %> + <% end %> +<% end %> + +<% if current_user.support? %> + <%= render partial: "organisations/headings", locals: { main: @organisation.name, sub: nil } %> + <%= render SubNavigationComponent.new( + items: secondary_items(request.path, @organisation.id), + ) %> +

Managing Agents

+ <% if params["related_organisation_id"] %> + <%= govuk_notification_banner( + title_text: "Success", + success: true, title_heading_level: 3, + title_id: "swanky-notifications" + ) do |notification_banner| + notification_banner.heading(text: "#{Organisation.find(params['related_organisation_id']).name} is now one of this organisation's managing agents") + end %> + <% end %> +

A managing agent can submit logs for this organisation.

+ <% if @total_count == 0 %> +

This organisation does not currently have any managing agents.

+ <% end %> +<% else %> + <%= render partial: "organisations/headings", locals: { main: "This organisation managing agents", sub: current_user.organisation.name } %> +

A managing agent can submit logs for this organisation.

+ <% if @total_count == 0 %> +

This organisation does not currently have any managing agents.

+ <% end %> +<% end %> +<% if current_user.support? %> + <%= govuk_button_link_to "Add a managing agent", managing_agents_add_organisation_path(organisation_id: @organisation.id), html: { method: :get } %> +<% elsif current_user.data_coordinator? %> + <%= govuk_button_link_to "Add a managing agent", managing_agents_add_organisation_path, html: { method: :get } %> +<% end %> +<% if @total_count != 0 %> + <%= render SearchComponent.new(current_user:, search_label: "Search for a managing agent", value: @searched) %> + <%= render partial: "organisation_relationships/managing_agent_list", locals: { index: @managing_agents, title: "Managing agents", pagy: @pagy, searched: @searched, item_label:, total_count: @total_count } %> + <%= render partial: "pagy/nav", locals: { pagy: @pagy, item_name: "Managing agents" } %> +<% end %> diff --git a/app/views/organisations/index.html.erb b/app/views/organisations/index.html.erb index b81922c5e..75a4d799c 100644 --- a/app/views/organisations/index.html.erb +++ b/app/views/organisations/index.html.erb @@ -1,4 +1,4 @@ -<% item_label = format_label(@pagy.count, "organisation") %> +<% item_label = format_label(@pagy.count, "organisations") %> <% title = format_title(@searched, "Organisations", current_user, item_label, @pagy.count, nil) %> <% content_for :title, title %> diff --git a/app/views/organisations/logs.html.erb b/app/views/organisations/logs.html.erb index f954a0839..94fe8e9bc 100644 --- a/app/views/organisations/logs.html.erb +++ b/app/views/organisations/logs.html.erb @@ -1,4 +1,4 @@ -<% item_label = format_label(@pagy.count, "log") %> +<% item_label = format_label(@pagy.count, "logs") %> <% title = format_title(@searched, "Logs", current_user, item_label, @pagy.count, @organisation.name) %> <% content_for :title, title %> diff --git a/config/initializers/feature_toggle.rb b/config/initializers/feature_toggle.rb index 0e01531ca..ca4315e9e 100644 --- a/config/initializers/feature_toggle.rb +++ b/config/initializers/feature_toggle.rb @@ -8,4 +8,10 @@ class FeatureToggle false end + + def self.managing_owning_enabled? + return true unless Rails.env.production? + + false + end end diff --git a/config/routes.rb b/config/routes.rb index 0be5f5b6a..838887f1b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -79,6 +79,12 @@ Rails.application.routes.draw do post "logs/email-csv", to: "organisations#email_csv" get "logs/csv-confirmation", to: "lettings_logs#csv_confirmation" get "schemes", to: "organisations#schemes" + get "housing-providers", to: "organisation_relationships#housing_providers" + get "housing-providers/add", to: "organisation_relationships#add_housing_provider" + post "housing-providers", to: "organisation_relationships#create_housing_provider" + get "managing-agents", to: "organisation_relationships#managing_agents" + get "managing-agents/add", to: "organisation_relationships#add_managing_agent" + post "managing-agents", to: "organisation_relationships#create_managing_agent" end end diff --git a/db/migrate/20221007133155_add_la_to_sales_log.rb b/db/migrate/20221007133155_add_la_to_sales_log.rb new file mode 100644 index 000000000..9e40b3a59 --- /dev/null +++ b/db/migrate/20221007133155_add_la_to_sales_log.rb @@ -0,0 +1,8 @@ +class AddLaToSalesLog < ActiveRecord::Migration[7.0] + def change + change_table :sales_logs, bulk: true do |t| + t.column :la, :string + t.column :la_known, :integer + end + end +end diff --git a/db/migrate/20221007142742_add_income1_to_sales_log.rb b/db/migrate/20221007142742_add_income1_to_sales_log.rb new file mode 100644 index 000000000..a1e509532 --- /dev/null +++ b/db/migrate/20221007142742_add_income1_to_sales_log.rb @@ -0,0 +1,6 @@ +class AddIncome1ToSalesLog < ActiveRecord::Migration[7.0] + change_table :sales_logs, bulk: true do |t| + t.column :income1, :int + t.column :income1nk, :int + end +end diff --git a/db/migrate/20221017095918_add_relationship_type_to_org_relationships.rb b/db/migrate/20221017095918_add_relationship_type_to_org_relationships.rb new file mode 100644 index 000000000..a45cff1d9 --- /dev/null +++ b/db/migrate/20221017095918_add_relationship_type_to_org_relationships.rb @@ -0,0 +1,10 @@ +class AddRelationshipTypeToOrgRelationships < ActiveRecord::Migration[7.0] + def change + add_column( + :organisation_relationships, + :relationship_type, + :integer, + null: false, # rubocop:disable Rails/NotNullColumn + ) + end +end diff --git a/db/migrate/20221019082625_rename_managing_agents_column.rb b/db/migrate/20221019082625_rename_managing_agents_column.rb new file mode 100644 index 000000000..dd03a7435 --- /dev/null +++ b/db/migrate/20221019082625_rename_managing_agents_column.rb @@ -0,0 +1,5 @@ +class RenameManagingAgentsColumn < ActiveRecord::Migration[7.0] + def change + rename_column :organisations, :managing_agents, :managing_agents_label + end +end diff --git a/db/schema.rb b/db/schema.rb index 51aa4c704..02c7f3d90 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_10_11_094347) do +ActiveRecord::Schema[7.0].define(version: 2022_10_19_082625) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -277,6 +277,7 @@ ActiveRecord::Schema[7.0].define(version: 2022_10_11_094347) do t.integer "parent_organisation_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.integer "relationship_type", null: false end create_table "organisation_rent_periods", force: :cascade do |t| @@ -296,7 +297,7 @@ ActiveRecord::Schema[7.0].define(version: 2022_10_11_094347) do t.string "postcode" t.boolean "holds_own_stock" t.string "other_stock_owners" - t.string "managing_agents" + t.string "managing_agents_label" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.boolean "active" @@ -358,12 +359,16 @@ ActiveRecord::Schema[7.0].define(version: 2022_10_11_094347) do t.integer "hholdcount" t.integer "age3" t.integer "age3_known" + t.integer "income1" + t.integer "income1nk" t.integer "age4" t.integer "age4_known" t.integer "age5" t.integer "age5_known" t.integer "age6" t.integer "age6_known" + t.string "la" + t.integer "la_known" t.index ["created_by_id"], name: "index_sales_logs_on_created_by_id" t.index ["managing_organisation_id"], name: "index_sales_logs_on_managing_organisation_id" t.index ["owning_organisation_id"], name: "index_sales_logs_on_owning_organisation_id" diff --git a/db/seeds.rb b/db/seeds.rb index 2b05b34f4..e357e6efe 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -8,14 +8,35 @@ # rubocop:disable Rails/Output unless Rails.env.test? + housing_provider = Organisation.find_or_create_by!( + name: "Housing Provider", + address_line1: "2 Marsham Street", + address_line2: "London", + postcode: "SW1P 4DF", + holds_own_stock: true, + other_stock_owners: "None", + managing_agents_label: "None", + provider_type: "LA", + ) + managing_agent = Organisation.find_or_create_by!( + name: "Managing Agent", + address_line1: "2 Marsham Street", + address_line2: "London", + postcode: "SW1P 4DF", + holds_own_stock: true, + other_stock_owners: "None", + managing_agents_label: "None", + provider_type: "LA", + ) + org = Organisation.find_or_create_by!( name: "DLUHC", address_line1: "2 Marsham Street", address_line2: "London", postcode: "SW1P 4DF", - holds_own_stock: false, + holds_own_stock: true, other_stock_owners: "None", - managing_agents: "None", + managing_agents_label: "None", provider_type: "LA", ) do info = "Seeded DLUHC Organisation" @@ -26,6 +47,17 @@ unless Rails.env.test? end end + OrganisationRelationship.create!( + child_organisation: org, + parent_organisation: housing_provider, + relationship_type: OrganisationRelationship::OWNING, + ) + OrganisationRelationship.create!( + child_organisation: managing_agent, + parent_organisation: org, + relationship_type: OrganisationRelationship::MANAGING, + ) + if Rails.env.development? && User.count.zero? User.create!( name: "Provider", @@ -65,7 +97,7 @@ unless Rails.env.test? postcode: "BA21 4AT", holds_own_stock: false, other_stock_owners: "None", - managing_agents: "None", + managing_agents_label: "None", provider_type: "LA", ) diff --git a/spec/factories/organisation.rb b/spec/factories/organisation.rb index 8b02f030a..fa40663ac 100644 --- a/spec/factories/organisation.rb +++ b/spec/factories/organisation.rb @@ -17,9 +17,4 @@ FactoryBot.define do created_at { Time.zone.now } updated_at { Time.zone.now } end - - factory :organisation_relationship do - child_organisation { FactoryBot.create(:organisation) } - parent_organisation { FactoryBot.create(:organisation) } - end end diff --git a/spec/factories/organisation_relationship.rb b/spec/factories/organisation_relationship.rb new file mode 100644 index 000000000..418599902 --- /dev/null +++ b/spec/factories/organisation_relationship.rb @@ -0,0 +1,14 @@ +FactoryBot.define do + factory :organisation_relationship do + child_organisation { FactoryBot.create(:organisation) } + parent_organisation { FactoryBot.create(:organisation) } + + trait :owning do + relationship_type { OrganisationRelationship::OWNING } + end + + trait :managing do + relationship_type { OrganisationRelationship::MANAGING } + end + end +end diff --git a/spec/factories/sales_log.rb b/spec/factories/sales_log.rb index f35d60adb..31c4f1882 100644 --- a/spec/factories/sales_log.rb +++ b/spec/factories/sales_log.rb @@ -47,6 +47,10 @@ FactoryBot.define do age5 { 40 } age6_known { 0 } age6 { 40 } + income1nk { 0 } + income1 { 10_000 } + la_known { "1" } + la { "E09000003" } end end end diff --git a/spec/helpers/navigation_items_helper_spec.rb b/spec/helpers/navigation_items_helper_spec.rb index fc656d024..35cf00725 100644 --- a/spec/helpers/navigation_items_helper_spec.rb +++ b/spec/helpers/navigation_items_helper_spec.rb @@ -346,6 +346,8 @@ RSpec.describe NavigationItemsHelper do NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false), NavigationItemsHelper::NavigationItem.new("Users", users_path, false), NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false), + NavigationItemsHelper::NavigationItem.new("Housing providers", "/organisations/#{current_user.organisation.id}/housing-providers", false), + NavigationItemsHelper::NavigationItem.new("Managing agents", "/organisations/#{current_user.organisation.id}/managing-agents", false), ] end @@ -362,6 +364,8 @@ RSpec.describe NavigationItemsHelper do NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false), NavigationItemsHelper::NavigationItem.new("Users", users_path, false), NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false), + NavigationItemsHelper::NavigationItem.new("Housing providers", "/organisations/#{current_user.organisation.id}/housing-providers", false), + NavigationItemsHelper::NavigationItem.new("Managing agents", "/organisations/#{current_user.organisation.id}/managing-agents", false), ] end @@ -378,6 +382,8 @@ RSpec.describe NavigationItemsHelper do NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false), NavigationItemsHelper::NavigationItem.new("Users", users_path, true), NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false), + NavigationItemsHelper::NavigationItem.new("Housing providers", "/organisations/#{current_user.organisation.id}/housing-providers", false), + NavigationItemsHelper::NavigationItem.new("Managing agents", "/organisations/#{current_user.organisation.id}/managing-agents", false), ] end @@ -394,6 +400,8 @@ RSpec.describe NavigationItemsHelper do NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false), NavigationItemsHelper::NavigationItem.new("Users", users_path, false), NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, true), + NavigationItemsHelper::NavigationItem.new("Housing providers", "/organisations/#{current_user.organisation.id}/housing-providers", false), + NavigationItemsHelper::NavigationItem.new("Managing agents", "/organisations/#{current_user.organisation.id}/managing-agents", false), ] end @@ -410,6 +418,8 @@ RSpec.describe NavigationItemsHelper do NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false), NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false), NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false), + NavigationItemsHelper::NavigationItem.new("Housing providers", "/organisations/#{current_user.organisation.id}/housing-providers", false), + NavigationItemsHelper::NavigationItem.new("Managing agents", "/organisations/#{current_user.organisation.id}/managing-agents", false), ] end @@ -426,6 +436,8 @@ RSpec.describe NavigationItemsHelper do NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", false), NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", true), NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false), + NavigationItemsHelper::NavigationItem.new("Housing providers", "/organisations/#{current_user.organisation.id}/housing-providers", false), + NavigationItemsHelper::NavigationItem.new("Managing agents", "/organisations/#{current_user.organisation.id}/managing-agents", false), ] end @@ -442,6 +454,8 @@ RSpec.describe NavigationItemsHelper do NavigationItemsHelper::NavigationItem.new("Schemes", "/schemes", true), NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false), NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false), + NavigationItemsHelper::NavigationItem.new("Housing providers", "/organisations/#{current_user.organisation.id}/housing-providers", false), + NavigationItemsHelper::NavigationItem.new("Managing agents", "/organisations/#{current_user.organisation.id}/managing-agents", false), ] end @@ -618,6 +632,8 @@ RSpec.describe NavigationItemsHelper do NavigationItemsHelper::NavigationItem.new("Schemes", "/organisations/#{current_user.organisation.id}/schemes", false), NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false), NavigationItemsHelper::NavigationItem.new("About this organisation", "/organisations/#{current_user.organisation.id}", false), + NavigationItemsHelper::NavigationItem.new("Housing providers", "/organisations/#{current_user.organisation.id}/housing-providers", false), + NavigationItemsHelper::NavigationItem.new("Managing agents", "/organisations/#{current_user.organisation.id}/managing-agents", false), ] end @@ -646,6 +662,8 @@ RSpec.describe NavigationItemsHelper do NavigationItemsHelper::NavigationItem.new("Schemes", "/organisations/#{current_user.organisation.id}/schemes", false), NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", true), NavigationItemsHelper::NavigationItem.new("About this organisation", "/organisations/#{current_user.organisation.id}", false), + NavigationItemsHelper::NavigationItem.new("Housing providers", "/organisations/#{current_user.organisation.id}/housing-providers", false), + NavigationItemsHelper::NavigationItem.new("Managing agents", "/organisations/#{current_user.organisation.id}/managing-agents", false), ] end @@ -674,6 +692,8 @@ RSpec.describe NavigationItemsHelper do NavigationItemsHelper::NavigationItem.new("Schemes", "/organisations/#{current_user.organisation.id}/schemes", true), NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false), NavigationItemsHelper::NavigationItem.new("About this organisation", "/organisations/#{current_user.organisation.id}", false), + NavigationItemsHelper::NavigationItem.new("Housing providers", "/organisations/#{current_user.organisation.id}/housing-providers", false), + NavigationItemsHelper::NavigationItem.new("Managing agents", "/organisations/#{current_user.organisation.id}/managing-agents", false), ] end @@ -702,6 +722,8 @@ RSpec.describe NavigationItemsHelper do NavigationItemsHelper::NavigationItem.new("Schemes", "/organisations/#{current_user.organisation.id}/schemes", false), NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false), NavigationItemsHelper::NavigationItem.new("About this organisation", "/organisations/#{current_user.organisation.id}", true), + NavigationItemsHelper::NavigationItem.new("Housing providers", "/organisations/#{current_user.organisation.id}/housing-providers", false), + NavigationItemsHelper::NavigationItem.new("Managing agents", "/organisations/#{current_user.organisation.id}/managing-agents", false), ] end diff --git a/spec/models/form/sales/pages/buyer1_income_spec.rb b/spec/models/form/sales/pages/buyer1_income_spec.rb new file mode 100644 index 000000000..a95a8ee5f --- /dev/null +++ b/spec/models/form/sales/pages/buyer1_income_spec.rb @@ -0,0 +1,33 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Pages::Buyer1Income, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection) } + + let(:page_id) { nil } + let(:page_definition) { nil } + let(:subsection) { instance_double(Form::Subsection) } + + it "has correct subsection" do + expect(page.subsection).to eq(subsection) + end + + it "has correct questions" do + expect(page.questions.map(&:id)).to eq(%w[income1nk income1]) + end + + it "has the correct id" do + expect(page.id).to eq("buyer_1_income") + end + + it "has the correct header" do + expect(page.header).to eq("") + end + + it "has the correct description" do + expect(page.description).to eq("") + end + + it "has correct depends_on" do + expect(page.depends_on).to be_nil + end +end diff --git a/spec/models/form/sales/pages/household_wheelchair_spec.rb b/spec/models/form/sales/pages/household_wheelchair_spec.rb new file mode 100644 index 000000000..f727bcbac --- /dev/null +++ b/spec/models/form/sales/pages/household_wheelchair_spec.rb @@ -0,0 +1,33 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Pages::HouseholdWheelchair, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection) } + + let(:page_id) { nil } + let(:page_definition) { nil } + let(:subsection) { instance_double(Form::Subsection) } + + it "has correct subsection" do + expect(page.subsection).to eq(subsection) + end + + it "has correct questions" do + expect(page.questions.map(&:id)).to eq(%w[wheel]) + end + + it "has the correct id" do + expect(page.id).to eq("household_wheelchair") + end + + it "has the correct header" do + expect(page.header).to eq("") + end + + it "has the correct description" do + expect(page.description).to eq("") + end + + it "has correct depends_on" do + expect(page.depends_on).to be_nil + end +end diff --git a/spec/models/form/sales/questions/buyer1_income_known_spec.rb b/spec/models/form/sales/questions/buyer1_income_known_spec.rb new file mode 100644 index 000000000..81edb985e --- /dev/null +++ b/spec/models/form/sales/questions/buyer1_income_known_spec.rb @@ -0,0 +1,55 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Questions::Buyer1IncomeKnown, type: :model do + subject(:question) { described_class.new(question_id, question_definition, page) } + + let(:question_id) { nil } + let(:question_definition) { nil } + let(:page) { instance_double(Form::Page) } + + it "has correct page" do + expect(question.page).to eq(page) + end + + it "has the correct id" do + expect(question.id).to eq("income1nk") + end + + it "has the correct header" do + expect(question.header).to eq("Do you know buyer 1’s annual income?") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to eq("Buyer 1’s gross annual income") + end + + it "has the correct type" do + expect(question.type).to eq("radio") + end + + it "is not marked as derived" do + expect(question.derived?).to be false + end + + it "has the correct answer_options" do + expect(question.answer_options).to eq({ + "0" => { "value" => "Yes" }, + "1" => { "value" => "No" }, + }) + end + + it "has correct conditional for" do + expect(question.conditional_for).to eq({ + "income1" => [0], + }) + end + + it "has the correct guidance_partial" do + expect(question.guidance_partial).to eq("what_counts_as_income_sales") + end + + it "has the correct guidance position", :aggregate_failures do + expect(question.bottom_guidance?).to eq(true) + expect(question.top_guidance?).to eq(false) + end +end diff --git a/spec/models/form/sales/questions/buyer1_income_spec.rb b/spec/models/form/sales/questions/buyer1_income_spec.rb new file mode 100644 index 000000000..5ec84bb58 --- /dev/null +++ b/spec/models/form/sales/questions/buyer1_income_spec.rb @@ -0,0 +1,53 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Questions::Buyer1Income, type: :model do + subject(:question) { described_class.new(question_id, question_definition, page) } + + let(:question_id) { nil } + let(:question_definition) { nil } + let(:page) { instance_double(Form::Page) } + + it "has correct page" do + expect(question.page).to eq(page) + end + + it "has the correct id" do + expect(question.id).to eq("income1") + end + + it "has the correct header" do + expect(question.header).to eq("Buyer 1’s gross annual income") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to eq("Buyer 1’s gross annual income") + end + + it "has the correct type" do + expect(question.type).to eq("numeric") + end + + it "is not marked as derived" do + expect(question.derived?).to be false + end + + it "has the correct hint" do + expect(question.hint_text).to be_nil + end + + it "has correct width" do + expect(question.width).to eq(5) + end + + it "has correct step" do + expect(question.step).to eq(1) + end + + it "has correct prefix" do + expect(question.prefix).to eq("£") + end + + it "has correct min" do + expect(question.min).to eq(0) + end +end diff --git a/spec/models/form/sales/questions/household_wheelchair_spec.rb b/spec/models/form/sales/questions/household_wheelchair_spec.rb new file mode 100644 index 000000000..8d641aef7 --- /dev/null +++ b/spec/models/form/sales/questions/household_wheelchair_spec.rb @@ -0,0 +1,49 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Questions::HouseholdWheelchair, type: :model do + subject(:question) { described_class.new(question_id, question_definition, page) } + + let(:question_id) { nil } + let(:question_definition) { nil } + let(:page) { instance_double(Form::Page) } + + it "has correct page" do + expect(question.page).to eq(page) + end + + it "has the correct id" do + expect(question.id).to eq("wheel") + end + + it "has the correct header" do + expect(question.header).to eq("Does anyone in the household use a wheelchair?") + end + + it "has the correct check_answer_label" do + expect(question.check_answer_label).to be_nil + end + + it "has the correct type" do + expect(question.type).to eq("radio") + end + + it "is not marked as derived" do + expect(question.derived?).to be false + end + + it "has the correct answer_options" do + expect(question.answer_options).to eq({ + "1" => { "value" => "Yes" }, + "2" => { "value" => "No" }, + "3" => { "value" => "Don't know" }, + }) + end + + it "has correct conditional for" do + expect(question.conditional_for).to be_nil + end + + it "has the correct hint" do + expect(question.hint_text).to eq("This can be inside or outside the home") + end +end diff --git a/spec/models/form/sales/sections/finances_spec.rb b/spec/models/form/sales/sections/finances_spec.rb new file mode 100644 index 000000000..4797f6b4e --- /dev/null +++ b/spec/models/form/sales/sections/finances_spec.rb @@ -0,0 +1,33 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Sections::Finances, type: :model do + subject(:section) { described_class.new(section_id, section_definition, form) } + + let(:section_id) { nil } + let(:section_definition) { nil } + let(:form) { instance_double(Form) } + + it "has correct form" do + expect(section.form).to eq(form) + end + + it "has correct subsections" do + expect(section.subsections.map(&:id)).to eq( + %w[ + income_benefits_and_outgoings + ], + ) + end + + it "has the correct id" do + expect(section.id).to eq("finances") + end + + it "has the correct label" do + expect(section.label).to eq("Finances") + end + + it "has the correct description" do + expect(section.description).to eq("") + end +end diff --git a/spec/models/form/sales/subsections/income_benefits_and_outgoings_spec.rb b/spec/models/form/sales/subsections/income_benefits_and_outgoings_spec.rb new file mode 100644 index 000000000..add0a6952 --- /dev/null +++ b/spec/models/form/sales/subsections/income_benefits_and_outgoings_spec.rb @@ -0,0 +1,33 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Subsections::IncomeBenefitsAndOutgoings, type: :model do + subject(:subsection) { described_class.new(subsection_id, subsection_definition, section) } + + let(:subsection_id) { nil } + let(:subsection_definition) { nil } + let(:section) { instance_double(Form::Sales::Sections::Household) } + + it "has correct section" do + expect(subsection.section).to eq(section) + end + + it "has correct pages" do + expect(subsection.pages.map(&:id)).to eq( + %w[ + buyer_1_income + ], + ) + end + + it "has the correct id" do + expect(subsection.id).to eq("income_benefits_and_outgoings") + end + + it "has the correct label" do + expect(subsection.label).to eq("Income, benefits and outgoings") + end + + it "has correct depends on" do + expect(subsection.depends_on).to eq([{ "setup" => "completed" }]) + end +end diff --git a/spec/models/form/sales/subsections/property_information_spec.rb b/spec/models/form/sales/subsections/property_information_spec.rb index ab33936c5..284d0e02c 100644 --- a/spec/models/form/sales/subsections/property_information_spec.rb +++ b/spec/models/form/sales/subsections/property_information_spec.rb @@ -17,6 +17,7 @@ RSpec.describe Form::Sales::Subsections::PropertyInformation, type: :model do property_number_of_bedrooms property_building_type property_unit_type + property_local_authority ], ) end diff --git a/spec/models/form_handler_spec.rb b/spec/models/form_handler_spec.rb index 07390df41..87a04487a 100644 --- a/spec/models/form_handler_spec.rb +++ b/spec/models/form_handler_spec.rb @@ -61,14 +61,14 @@ RSpec.describe FormHandler do it "is able to load a current sales form" do form = form_handler.get_form("current_sales") expect(form).to be_a(Form) - expect(form.pages.count).to eq(39) + expect(form.pages.count).to eq(41) expect(form.name).to eq("2022_2023_sales") end it "is able to load a previous sales form" do form = form_handler.get_form("previous_sales") expect(form).to be_a(Form) - expect(form.pages.count).to eq(39) + expect(form.pages.count).to eq(41) expect(form.name).to eq("2021_2022_sales") end end diff --git a/spec/models/organisation_spec.rb b/spec/models/organisation_spec.rb index 7bc1d7cc1..d4d63b6a0 100644 --- a/spec/models/organisation_spec.rb +++ b/spec/models/organisation_spec.rb @@ -27,19 +27,101 @@ RSpec.describe Organisation, type: :model do .to raise_error(ActiveRecord::RecordInvalid, "Validation failed: Provider type #{I18n.t('validations.organisation.provider_type_missing')}") end - context "with parent/child association" do - let(:child_organisation) { FactoryBot.create(:organisation, name: "DLUHC Child") } + context "with parent/child associations", :aggregate_failures do + let!(:child_organisation) { FactoryBot.create(:organisation, name: "DLUHC Child") } + let!(:grandchild_organisation) { FactoryBot.create(:organisation, name: "DLUHC Grandchild") } before do - FactoryBot.create(:organisation_relationship, child_organisation:, parent_organisation: organisation) + FactoryBot.create( + :organisation_relationship, + :owning, + child_organisation:, + parent_organisation: organisation, + ) + + FactoryBot.create( + :organisation_relationship, + :owning, + child_organisation: grandchild_organisation, + parent_organisation: child_organisation, + ) + end + + it "has correct child_organisations" do + expect(organisation.child_organisations).to eq([child_organisation]) + expect(child_organisation.child_organisations).to eq([grandchild_organisation]) + end + + it "has correct parent_organisations" do + expect(child_organisation.parent_organisations).to eq([organisation]) + expect(grandchild_organisation.parent_organisations).to eq([child_organisation]) end + end + + context "with owning association", :aggregate_failures do + let!(:child_organisation) { FactoryBot.create(:organisation, name: "DLUHC Child") } + let!(:grandchild_organisation) { FactoryBot.create(:organisation, name: "DLUHC Grandchild") } + + before do + FactoryBot.create( + :organisation_relationship, + :managing, + child_organisation:, + parent_organisation: organisation, + ) + + FactoryBot.create( + :organisation_relationship, + :owning, + child_organisation:, + parent_organisation: organisation, + ) - it "has correct child" do - expect(organisation.child_organisations.first).to eq(child_organisation) + FactoryBot.create( + :organisation_relationship, + :owning, + child_organisation: grandchild_organisation, + parent_organisation: child_organisation, + ) + end + + it "has correct housing_providers" do + expect(child_organisation.housing_providers).to eq([organisation]) + expect(grandchild_organisation.housing_providers).to eq([child_organisation]) + end + end + + context "with managing association", :aggregate_failures do + let!(:child_organisation) { FactoryBot.create(:organisation, name: "DLUHC Child") } + let!(:grandchild_organisation) { FactoryBot.create(:organisation, name: "DLUHC Grandchild") } + + before do + FactoryBot.create( + :organisation_relationship, + :managing, + child_organisation:, + parent_organisation: organisation, + ) + + FactoryBot.create( + :organisation_relationship, + :owning, + child_organisation:, + parent_organisation: organisation, + ) + + FactoryBot.create( + :organisation_relationship, + :managing, + child_organisation: grandchild_organisation, + parent_organisation: child_organisation, + ) end - it "has correct parent" do - expect(child_organisation.parent_organisations.first).to eq(organisation) + it "has correct managing_agents" do + expect(organisation.managing_agents).to eq([child_organisation]) + expect(child_organisation.managing_agents).to eq([grandchild_organisation]) + expect(grandchild_organisation.managing_agents).to eq([]) end end diff --git a/spec/requests/form_controller_spec.rb b/spec/requests/form_controller_spec.rb index f879985b8..ade87cfde 100644 --- a/spec/requests/form_controller_spec.rb +++ b/spec/requests/form_controller_spec.rb @@ -158,7 +158,7 @@ RSpec.describe FormController, type: :request do before do Timecop.freeze(Time.zone.local(2022, 12, 1)) - get "/lettings-logs/#{lettings_log_2022.id}/setup/check-answers", headers: headers, params: {} + get "/lettings-logs/#{lettings_log_2022.id}/setup/check-answers", headers:, params: {} end after do @@ -267,7 +267,7 @@ RSpec.describe FormController, type: :request do it "logs that validation was triggered" do expect(Rails.logger).to receive(:info).with("User triggered validation(s) on: age1").once - post "/lettings-logs/#{lettings_log.id}/form", params: params + post "/lettings-logs/#{lettings_log.id}/form", params: end context "when the number of days is too high for the month" do diff --git a/spec/requests/lettings_logs_controller_spec.rb b/spec/requests/lettings_logs_controller_spec.rb index 651655139..db4226152 100644 --- a/spec/requests/lettings_logs_controller_spec.rb +++ b/spec/requests/lettings_logs_controller_spec.rb @@ -365,7 +365,7 @@ RSpec.describe LettingsLogsController, type: :request do it "has search results in the title" do get "/lettings-logs?search=#{log_to_search.id}", headers: headers, params: {} - expect(page).to have_title("Logs (1 log matching ‘#{log_to_search.id}’) - Submit social housing lettings and sales data (CORE) - GOV.UK") + expect(page).to have_title("Logs (1 logs matching ‘#{log_to_search.id}’) - Submit social housing lettings and sales data (CORE) - GOV.UK") end it "shows lettings logs matching the id" do diff --git a/spec/requests/locations_controller_spec.rb b/spec/requests/locations_controller_spec.rb index 66bd96c72..96b3d1b21 100644 --- a/spec/requests/locations_controller_spec.rb +++ b/spec/requests/locations_controller_spec.rb @@ -100,7 +100,7 @@ RSpec.describe LocationsController, type: :request do before do sign_in user - post "/schemes/#{scheme.id}/locations", params: params + post "/schemes/#{scheme.id}/locations", params: end it "creates a new location for scheme with valid params and redirects to correct page" do @@ -302,7 +302,7 @@ RSpec.describe LocationsController, type: :request do before do allow(user).to receive(:need_two_factor_authentication?).and_return(false) sign_in user - post "/schemes/#{scheme.id}/locations", params: params + post "/schemes/#{scheme.id}/locations", params: end it "creates a new location for scheme with valid params and redirects to correct page" do @@ -573,7 +573,7 @@ RSpec.describe LocationsController, type: :request do before do sign_in user - patch "/schemes/#{scheme.id}/locations/#{location.id}", params: params + patch "/schemes/#{scheme.id}/locations/#{location.id}", params: end it "updates existing location for scheme with valid params and redirects to correct page" do @@ -714,7 +714,7 @@ RSpec.describe LocationsController, type: :request do before do allow(user).to receive(:need_two_factor_authentication?).and_return(false) sign_in user - patch "/schemes/#{scheme.id}/locations/#{location.id}", params: params + patch "/schemes/#{scheme.id}/locations/#{location.id}", params: end it "updates a location for scheme with valid params and redirects to correct page" do diff --git a/spec/requests/organisation_relationships_controller_spec.rb b/spec/requests/organisation_relationships_controller_spec.rb new file mode 100644 index 000000000..9fdb01ec9 --- /dev/null +++ b/spec/requests/organisation_relationships_controller_spec.rb @@ -0,0 +1,473 @@ +require "rails_helper" + +RSpec.describe OrganisationRelationshipsController, type: :request do + let(:organisation) { user.organisation } + let!(:unauthorised_organisation) { FactoryBot.create(:organisation) } + let(:headers) { { "Accept" => "text/html" } } + let(:page) { Capybara::Node::Simple.new(response.body) } + + context "when user is signed in" do + let(:user) { FactoryBot.create(:user, :data_coordinator) } + + context "with a data coordinator user" do + before do + sign_in user + end + + context "when accessing the housing providers tab" do + context "with an organisation that the user belongs to" do + let!(:housing_provider) { FactoryBot.create(:organisation) } + let!(:other_org_housing_provider) { FactoryBot.create(:organisation, name: "Foobar LTD") } + let!(:other_organisation) { FactoryBot.create(:organisation, name: "Foobar LTD 2") } + + before do + FactoryBot.create(:organisation_relationship, child_organisation: organisation, parent_organisation: housing_provider, relationship_type: OrganisationRelationship.relationship_types[:owning]) + FactoryBot.create(:organisation_relationship, child_organisation: other_organisation, parent_organisation: other_org_housing_provider, relationship_type: OrganisationRelationship.relationship_types[:owning]) + get "/organisations/#{organisation.id}/housing-providers", headers:, params: {} + end + + it "shows the tab navigation" do + expected_html = "