diff --git a/app/controllers/locations_controller.rb b/app/controllers/locations_controller.rb index b84185b51..2b75da1a0 100644 --- a/app/controllers/locations_controller.rb +++ b/app/controllers/locations_controller.rb @@ -14,8 +14,8 @@ class LocationsController < ApplicationController def index authorize @scheme - @pagy, @locations = pagy(filter_manager.filtered_locations(@scheme.locations, search_term, session_filters)) - @total_count = @scheme.locations.size + @pagy, @locations = pagy(filter_manager.filtered_locations(@scheme.locations.visible, search_term, session_filters)) + @total_count = @scheme.locations.visible.size @searched = search_term.presence @filter_type = "scheme_locations" end @@ -230,6 +230,11 @@ class LocationsController < ApplicationController end end + def delete + @location.discard! + redirect_to scheme_locations_path(@scheme), notice: I18n.t("notification.location_deleted", postcode: @location.postcode) + end + private def authorize_user diff --git a/app/controllers/organisations_controller.rb b/app/controllers/organisations_controller.rb index 4612e6bc9..dc5a36c9b 100644 --- a/app/controllers/organisations_controller.rb +++ b/app/controllers/organisations_controller.rb @@ -21,7 +21,7 @@ class OrganisationsController < ApplicationController end def schemes - organisation_schemes = Scheme.where(owning_organisation: [@organisation] + @organisation.parent_organisations) + organisation_schemes = Scheme.visible.where(owning_organisation: [@organisation] + @organisation.parent_organisations) @pagy, @schemes = pagy(filter_manager.filtered_schemes(organisation_schemes, search_term, session_filters)) @searched = search_term.presence diff --git a/app/controllers/schemes_controller.rb b/app/controllers/schemes_controller.rb index 5eec2a294..cfc6fe8a0 100644 --- a/app/controllers/schemes_controller.rb +++ b/app/controllers/schemes_controller.rb @@ -13,11 +13,11 @@ class SchemesController < ApplicationController def index redirect_to schemes_organisation_path(current_user.organisation) unless current_user.support? - all_schemes = Scheme.all + all_visible_schemes = Scheme.visible - @pagy, @schemes = pagy(filter_manager.filtered_schemes(all_schemes, search_term, session_filters)) + @pagy, @schemes = pagy(filter_manager.filtered_schemes(all_visible_schemes, search_term, session_filters)) @searched = search_term.presence - @total_count = all_schemes.size + @total_count = all_visible_schemes.size @filter_type = "schemes" end @@ -223,6 +223,11 @@ class SchemesController < ApplicationController def csv_confirmation; end + def delete + @scheme.discard! + redirect_to schemes_organisation_path(@scheme.owning_organisation), notice: I18n.t("notification.scheme_deleted", service_name: @scheme.service_name) + end + private def authorize_user diff --git a/app/helpers/locations_helper.rb b/app/helpers/locations_helper.rb index f718e9576..f963c7040 100644 --- a/app/helpers/locations_helper.rb +++ b/app/helpers/locations_helper.rb @@ -73,6 +73,10 @@ module LocationsHelper return govuk_button_link_to "Reactivate this location", scheme_location_new_reactivation_path(location.scheme, location) if location.deactivated? end + def delete_location_link(location) + govuk_button_link_to "Delete this location", scheme_location_delete_confirmation_path(location.scheme, location), warning: true + end + def location_creation_success_notice(location) if location.confirmed "#{location.postcode} #{location.startdate.blank? || location.startdate.before?(Time.zone.now) ? 'has been' : 'will be'} added to this scheme" diff --git a/app/helpers/schemes_helper.rb b/app/helpers/schemes_helper.rb index 078419619..1cc89d3d5 100644 --- a/app/helpers/schemes_helper.rb +++ b/app/helpers/schemes_helper.rb @@ -15,6 +15,10 @@ module SchemesHelper return govuk_button_link_to "Reactivate this scheme", scheme_new_reactivation_path(scheme) if scheme.deactivated? end + def delete_scheme_link(scheme) + govuk_button_link_to "Delete this scheme", scheme_delete_confirmation_path(scheme), warning: true + end + def owning_organisation_options(current_user) all_orgs = Organisation.all.map { |org| OpenStruct.new(id: org.id, name: org.name) } user_org = [OpenStruct.new(id: current_user.organisation_id, name: current_user.organisation.name)] diff --git a/app/models/form/lettings/questions/location_id.rb b/app/models/form/lettings/questions/location_id.rb index cbc9b840a..d79bcab76 100644 --- a/app/models/form/lettings/questions/location_id.rb +++ b/app/models/form/lettings/questions/location_id.rb @@ -20,7 +20,7 @@ class Form::Lettings::Questions::LocationId < ::Form::Question answer_opts = {} return answer_opts unless ActiveRecord::Base.connected? - Location.started_in_2_weeks.select(:id, :postcode, :name).each_with_object(answer_opts) do |location, hsh| + Location.visible.started_in_2_weeks.select(:id, :postcode, :name).each_with_object(answer_opts) do |location, hsh| hsh[location.id.to_s] = { "value" => location.postcode, "hint" => location.name } hsh end @@ -29,7 +29,7 @@ class Form::Lettings::Questions::LocationId < ::Form::Question def displayed_answer_options(lettings_log, _user = nil) return {} unless lettings_log.scheme - scheme_location_ids = lettings_log.scheme.locations.confirmed.pluck(:id) + scheme_location_ids = lettings_log.scheme.locations.visible.confirmed.pluck(:id) answer_options.select { |k, _v| scheme_location_ids.include?(k.to_i) } end diff --git a/app/models/form/lettings/questions/nationality_all.rb b/app/models/form/lettings/questions/nationality_all.rb index 8d59a37fb..a8324595f 100644 --- a/app/models/form/lettings/questions/nationality_all.rb +++ b/app/models/form/lettings/questions/nationality_all.rb @@ -15,4 +15,11 @@ class Form::Lettings::Questions::NationalityAll < ::Form::Question end QUESTION_NUMBER_FROM_YEAR = { 2023 => 36, 2024 => 35 }.freeze + + def label_from_value(value) + return unless value + return "Tenant prefers not to say" if value.to_i.zero? + + answer_options[value.to_s]["name"] + end end diff --git a/app/models/form/lettings/questions/scheme_id.rb b/app/models/form/lettings/questions/scheme_id.rb index 4c533f43a..ef7904cc8 100644 --- a/app/models/form/lettings/questions/scheme_id.rb +++ b/app/models/form/lettings/questions/scheme_id.rb @@ -19,8 +19,8 @@ class Form::Lettings::Questions::SchemeId < ::Form::Question answer_opts = { "" => "Select an option" } return answer_opts unless ActiveRecord::Base.connected? - Scheme.select(:id, :service_name, :primary_client_group, - :secondary_client_group).each_with_object(answer_opts) do |scheme, hsh| + Scheme.visible.select(:id, :service_name, :primary_client_group, + :secondary_client_group).each_with_object(answer_opts) do |scheme, hsh| hsh[scheme.id.to_s] = scheme hsh end @@ -29,10 +29,10 @@ class Form::Lettings::Questions::SchemeId < ::Form::Question def displayed_answer_options(lettings_log, _user = nil) organisation = lettings_log.owning_organisation || lettings_log.created_by&.organisation schemes = if organisation - Scheme.includes(:locations).select(:id).where(owning_organisation_id: organisation.id, - confirmed: true) + Scheme.visible.includes(:locations).select(:id).where(owning_organisation_id: organisation.id, + confirmed: true) else - Scheme.includes(:locations).select(:id).where(confirmed: true) + Scheme.visible.includes(:locations).select(:id).where(confirmed: true) end filtered_scheme_ids = schemes.joins(:locations).merge(Location.started_in_2_weeks).map(&:id) answer_options.select do |k, _v| diff --git a/app/models/form/sales/questions/nationality_all.rb b/app/models/form/sales/questions/nationality_all.rb index dd8377830..68ef122bf 100644 --- a/app/models/form/sales/questions/nationality_all.rb +++ b/app/models/form/sales/questions/nationality_all.rb @@ -21,4 +21,11 @@ class Form::Sales::Questions::NationalityAll < ::Form::Question @buyer_index == 1 ? 26 : 34 end end + + def label_from_value(value) + return unless value + return "Buyer prefers not to say" if value.to_i.zero? + + answer_options[value.to_s]["name"] + end end diff --git a/app/models/location.rb b/app/models/location.rb index bfe9f77a4..43285bfbb 100644 --- a/app/models/location.rb +++ b/app/models/location.rb @@ -79,6 +79,8 @@ class Location < ApplicationRecord .where.not(id: activating_soon.pluck(:id)) } + scope :visible, -> { where(discarded_at: nil) } + LOCAL_AUTHORITIES = LocalAuthority.all.map { |la| [la.name, la.code] }.to_h enum local_authorities: LOCAL_AUTHORITIES @@ -138,6 +140,7 @@ class Location < ApplicationRecord end def status_at(date) + return :deleted if discarded_at.present? return :incomplete unless confirmed return :deactivated if open_deactivation&.deactivation_date.present? && date >= open_deactivation.deactivation_date return :deactivating_soon if open_deactivation&.deactivation_date.present? && date < open_deactivation.deactivation_date @@ -190,6 +193,10 @@ class Location < ApplicationRecord LocalAuthority.where(id: [la.id] + la.linked_local_authority_ids) end + def discard! + update!(discarded_at: Time.zone.now) + end + private PIO = PostcodeService.new diff --git a/app/models/scheme.rb b/app/models/scheme.rb index 0bfd56373..2518293a0 100644 --- a/app/models/scheme.rb +++ b/app/models/scheme.rb @@ -77,6 +77,8 @@ class Scheme < ApplicationRecord .where.not(id: activating_soon.pluck(:id)) } + scope :visible, -> { where(discarded_at: nil) } + validate :validate_confirmed validate :validate_owning_organisation @@ -229,7 +231,7 @@ class Scheme < ApplicationRecord end def validate_confirmed - required_attributes = attribute_names - %w[id created_at updated_at old_id old_visible_id confirmed end_date sensitive secondary_client_group total_units deactivation_date deactivation_date_type startdate] + required_attributes = attribute_names - %w[id created_at updated_at old_id old_visible_id confirmed end_date sensitive secondary_client_group total_units deactivation_date deactivation_date_type startdate discarded_at] if confirmed == true required_attributes.any? do |attribute| @@ -264,6 +266,7 @@ class Scheme < ApplicationRecord end def status_at(date) + return :deleted if discarded_at.present? return :incomplete unless confirmed && locations.confirmed.any? return :deactivated if open_deactivation&.deactivation_date.present? && date >= open_deactivation.deactivation_date return :deactivating_soon if open_deactivation&.deactivation_date.present? && date < open_deactivation.deactivation_date @@ -288,4 +291,9 @@ class Scheme < ApplicationRecord def deactivates_in_a_long_time? status_at(6.months.from_now) == :deactivating_soon end + + def discard! + update!(discarded_at: Time.zone.now) + locations.each(&:discard!) + end end diff --git a/app/policies/location_policy.rb b/app/policies/location_policy.rb index 5d6d6d467..436b961c6 100644 --- a/app/policies/location_policy.rb +++ b/app/policies/location_policy.rb @@ -26,6 +26,17 @@ class LocationPolicy user.data_coordinator? && scheme_owned_by_user_org_or_stock_owner end + def delete_confirmation? + delete? + end + + def delete? + return false unless user.support? + return false unless location.status == :incomplete || location.status == :deactivated + + !has_any_logs_in_editable_collection_period + end + %w[ update_postcode? update_local_authority? @@ -75,4 +86,10 @@ private def scheme_owned_by_user_org_or_stock_owner scheme&.owning_organisation == user.organisation || user.organisation.stock_owners.exists?(scheme&.owning_organisation_id) end + + def has_any_logs_in_editable_collection_period + editable_from_date = FormHandler.instance.earliest_open_for_editing_collection_start_date + + LettingsLog.where(location_id: location.id).after_date(editable_from_date).or(LettingsLog.where(startdate: nil, location_id: location.id)).any? + end end diff --git a/app/policies/scheme_policy.rb b/app/policies/scheme_policy.rb index f2710eb06..6b97a46de 100644 --- a/app/policies/scheme_policy.rb +++ b/app/policies/scheme_policy.rb @@ -65,9 +65,26 @@ class SchemePolicy end end + def delete_confirmation? + delete? + end + + def delete? + return false unless user.support? + return false unless scheme.status == :incomplete || scheme.status == :deactivated + + !has_any_logs_in_editable_collection_period + end + private def scheme_owned_by_user_org_or_stock_owner scheme&.owning_organisation == user.organisation || user.organisation.stock_owners.exists?(scheme&.owning_organisation_id) end + + def has_any_logs_in_editable_collection_period + editable_from_date = FormHandler.instance.earliest_open_for_editing_collection_start_date + + LettingsLog.where(scheme_id: scheme.id).after_date(editable_from_date).or(LettingsLog.where(startdate: nil, scheme_id: scheme.id)).any? + end end diff --git a/app/services/feature_toggle.rb b/app/services/feature_toggle.rb index 22d43f513..f145b7132 100644 --- a/app/services/feature_toggle.rb +++ b/app/services/feature_toggle.rb @@ -26,4 +26,12 @@ class FeatureToggle def self.service_moved? false end + + def self.delete_scheme_enabled? + !Rails.env.production? + end + + def self.delete_location_enabled? + !Rails.env.production? + end end diff --git a/app/views/locations/check_answers.html.erb b/app/views/locations/check_answers.html.erb index 63a48d4d5..8cd8bde2a 100644 --- a/app/views/locations/check_answers.html.erb +++ b/app/views/locations/check_answers.html.erb @@ -42,6 +42,9 @@ <% if LocationPolicy.new(current_user, @location).create? %>
<%= govuk_button_to "Save and return to locations", scheme_location_confirm_path(@scheme, @location, route: params[:route]), method: :patch %> + <% if LocationPolicy.new(current_user, @location).delete? && FeatureToggle.delete_location_enabled? %> + <%= delete_location_link(@location) %> + <% end %> <%= govuk_button_link_to "Cancel", scheme_locations_path(@scheme), secondary: true %>
<% end %> diff --git a/app/views/locations/delete_confirmation.html.erb b/app/views/locations/delete_confirmation.html.erb new file mode 100644 index 000000000..0eea3adc8 --- /dev/null +++ b/app/views/locations/delete_confirmation.html.erb @@ -0,0 +1,24 @@ +<% content_for :before_content do %> + <% content_for :title, "Are you sure you want to delete this location?" %> + <%= govuk_back_link(href: :back) %> +<% end %> + +
+
+ Delete <%= @location.postcode %> +

+ <%= content_for(:title) %> +

+ + <%= govuk_warning_text(text: "You will not be able to undo this action.") %> + +
+ <%= govuk_button_to( + "Delete this location", + scheme_location_delete_path(@scheme, @location), + method: :delete, + ) %> + <%= govuk_button_link_to "Cancel", scheme_location_path(@scheme, @location), html: { method: :get }, secondary: true %> +
+
+
diff --git a/app/views/locations/show.html.erb b/app/views/locations/show.html.erb index 9b11e4052..86de3a362 100644 --- a/app/views/locations/show.html.erb +++ b/app/views/locations/show.html.erb @@ -19,7 +19,12 @@ <%= summary_list.with_row do |row| %> <% row.with_key { attr[:name] } %> <% if attr[:attribute].eql?("status") %> - <%= row.with_value { status_tag_from_resource(@location) } %> + <%= row.with_value do %> + <%= details_html({ name: "Status", value: status_tag_from_resource(@location), id: "status" }) %> + <% if @location.deactivated? && current_user.support? && !LocationPolicy.new(current_user, @location).delete? %> + This location was active in an open or editable collection year, and cannot be deleted. + <% end %> + <% end %> <% elsif attr[:attribute].eql?("postcode") && @location.is_la_inferred %> <% row.with_value do %> <%= details_html(attr) %> @@ -45,3 +50,7 @@ <% if LocationPolicy.new(current_user, @location).deactivate? %> <%= toggle_location_link(@location) %> <% end %> + +<% if LocationPolicy.new(current_user, @location).delete? && FeatureToggle.delete_location_enabled? %> + <%= delete_location_link(@location) %> +<% end %> diff --git a/app/views/schemes/check_answers.html.erb b/app/views/schemes/check_answers.html.erb index 71e23b25c..3f8365f6e 100644 --- a/app/views/schemes/check_answers.html.erb +++ b/app/views/schemes/check_answers.html.erb @@ -23,4 +23,8 @@ <% if SchemePolicy.new(current_user, @scheme).create? %> <%= f.govuk_submit button_label %> <% end %> + + <% if SchemePolicy.new(current_user, @scheme).delete? && FeatureToggle.delete_scheme_enabled? %> + <%= delete_scheme_link(@scheme) %> + <% end %> <% end %> diff --git a/app/views/schemes/delete_confirmation.html.erb b/app/views/schemes/delete_confirmation.html.erb new file mode 100644 index 000000000..d4b0dd5ea --- /dev/null +++ b/app/views/schemes/delete_confirmation.html.erb @@ -0,0 +1,24 @@ +<% content_for :before_content do %> + <% content_for :title, "Are you sure you want to delete this scheme?" %> + <%= govuk_back_link(href: :back) %> +<% end %> + +
+
+ Delete <%= @scheme.service_name %> +

+ <%= content_for(:title) %> +

+ + <%= govuk_warning_text(text: "You will not be able to undo this action.") %> + +
+ <%= govuk_button_to( + "Delete this scheme", + scheme_delete_path(@scheme), + method: :delete, + ) %> + <%= govuk_button_link_to "Cancel", scheme_path(@scheme), html: { method: :get }, secondary: true %> +
+
+
diff --git a/app/views/schemes/show.html.erb b/app/views/schemes/show.html.erb index c45cefb14..31ca1cba9 100644 --- a/app/views/schemes/show.html.erb +++ b/app/views/schemes/show.html.erb @@ -29,6 +29,9 @@ <% if @scheme.confirmed? && @scheme.locations.confirmed.none? && LocationPolicy.new(current_user, @scheme.locations.new).create? %> Complete this scheme by adding a location using the <%= govuk_link_to("‘locations’ tab", scheme_locations_path(@scheme)) %>. <% end %> + <% if @scheme.deactivated? && current_user.support? && !SchemePolicy.new(current_user, @scheme).delete? %> + This scheme was active in an open or editable collection year, and cannot be deleted. + <% end %> <% elsif attr[:id] != "secondary_client_group" || @scheme.has_other_client_group == "Yes" %> @@ -49,3 +52,7 @@ <% if SchemePolicy.new(current_user, @scheme).deactivate? %> <%= toggle_scheme_link(@scheme) %> <% end %> + +<% if SchemePolicy.new(current_user, @scheme).delete? && FeatureToggle.delete_scheme_enabled? %> + <%= delete_scheme_link(@scheme) %> +<% end %> diff --git a/config/locales/en.yml b/config/locales/en.yml index e2934273f..6a105b213 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -196,6 +196,8 @@ en: duplicate_sets: one: "There is %{count} set of duplicate logs" other: "There are %{count} sets of duplicate logs" + location_deleted: "%{postcode} has been deleted." + scheme_deleted: "%{service_name} has been deleted." validations: organisation: diff --git a/config/routes.rb b/config/routes.rb index 99ac0cc31..f0f497291 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -79,6 +79,8 @@ Rails.application.routes.draw do patch "new-deactivation", to: "schemes#new_deactivation" patch "deactivate", to: "schemes#deactivate" patch "reactivate", to: "schemes#reactivate" + get "delete-confirmation", to: "schemes#delete_confirmation" + delete "delete", to: "schemes#delete" collection do get "csv-download", to: "schemes#download_csv" @@ -111,6 +113,8 @@ Rails.application.routes.draw do patch "new-deactivation", to: "locations#new_deactivation" patch "deactivate", to: "locations#deactivate" patch "reactivate", to: "locations#reactivate" + get "delete-confirmation", to: "locations#delete_confirmation" + delete "delete", to: "locations#delete" end end get "scheme-changes", to: "schemes#changes" diff --git a/db/migrate/20240301125651_add_discarded_at_column.rb b/db/migrate/20240301125651_add_discarded_at_column.rb new file mode 100644 index 000000000..ed752d650 --- /dev/null +++ b/db/migrate/20240301125651_add_discarded_at_column.rb @@ -0,0 +1,5 @@ +class AddDiscardedAtColumn < ActiveRecord::Migration[7.0] + def change + add_column :locations, :discarded_at, :datetime + end +end diff --git a/db/migrate/20240304100017_add_discarded_at_column_to_schemes.rb b/db/migrate/20240304100017_add_discarded_at_column_to_schemes.rb new file mode 100644 index 000000000..57ced4dee --- /dev/null +++ b/db/migrate/20240304100017_add_discarded_at_column_to_schemes.rb @@ -0,0 +1,5 @@ +class AddDiscardedAtColumnToSchemes < ActiveRecord::Migration[7.0] + def change + add_column :schemes, :discarded_at, :datetime + end +end diff --git a/db/schema.rb b/db/schema.rb index 5c754b39c..da9c4b0aa 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -374,6 +374,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_03_19_122706) do t.string "location_admin_district" t.boolean "confirmed" t.boolean "is_la_inferred" + t.datetime "discarded_at" t.index ["old_id"], name: "index_locations_on_old_id", unique: true t.index ["scheme_id"], name: "index_locations_on_scheme_id" end @@ -722,6 +723,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_03_19_122706) do t.integer "total_units" t.boolean "confirmed" t.datetime "startdate" + t.datetime "discarded_at" t.index ["owning_organisation_id"], name: "index_schemes_on_owning_organisation_id" end diff --git a/spec/fixtures/files/lettings_log_csv_export_labels_23_during_24_period.csv b/spec/fixtures/files/lettings_log_csv_export_labels_23_during_24_period.csv new file mode 100644 index 000000000..e05d7c0f0 --- /dev/null +++ b/spec/fixtures/files/lettings_log_csv_export_labels_23_during_24_period.csv @@ -0,0 +1,2 @@ +id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,address_line1_as_entered,address_line2_as_entered,town_or_city_as_entered,county_as_entered,postcode_full_as_entered,la_as_entered,assigned_to,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,declaration,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1_input,postcode_full_input,address_search_value_check,uprn_selection,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,details_known_2,relat2,partner_under_16_value_check,multiple_partners_value_check,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,accessible_register,letting_allocation_none,referral,referral_value_check,net_income_known,incref,incfreq,earnings,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate +,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2024-04-01T00:00:00+01:00,single log,,,2023,address line 1 as entered,address line 2 as entered,town or city as entered,county as entered,AB1 2CD,la as entered,,DLUHC,DLUHC,General needs,Affordable rent general needs local authority,No,2023-11-26,Affordable Rent,Affordable Rent,Rent to Buy,,No,HIJKLMN,ABCDEFG,Yes,Yes,No,,,,,,,fake address,,London,,NW9 5LL,No,Barnet,E09000003,No,Affordable rent basis,Tenant abandoned property,No,2,House,Purpose built,Yes,3,2023-11-24,,,Yes,2023-11-25,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,4,,Yes,4,0,0,2,35,,Female,White,Irish,Tenant prefers not to say,,Other,Yes,Partner,,,32,Male,Not seeking work,No,Prefers not to say,Not known,Prefers not to say,Prefers not to say,Yes,Person prefers not to say,Not known,Person prefers not to say,Person prefers not to say,,,,,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,Yes,No,No,No,No,No,No,Yes,No,No,Yes,No,No,No,No,No,No,No,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,,Other supported housing,2,No,Yes,TN23 6LZ,Yes,No,Ashford,E07000105,Yes,,Yes,,,,No,No,Yes,No,,Tenant applied directly (no referral or nomination),,Yes,No,Weekly,268,,Universal Credit housing element,Yes,All,,No,Every 2 weeks,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,Yes,Yes,12.0,6.0,,,,,,,,,,,,,,,,,,,, diff --git a/spec/fixtures/files/lettings_log_csv_export_labels_24.csv b/spec/fixtures/files/lettings_log_csv_export_labels_24.csv index e05d7c0f0..a4674d290 100644 --- a/spec/fixtures/files/lettings_log_csv_export_labels_24.csv +++ b/spec/fixtures/files/lettings_log_csv_export_labels_24.csv @@ -1,2 +1,2 @@ id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,address_line1_as_entered,address_line2_as_entered,town_or_city_as_entered,county_as_entered,postcode_full_as_entered,la_as_entered,assigned_to,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,declaration,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1_input,postcode_full_input,address_search_value_check,uprn_selection,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,details_known_2,relat2,partner_under_16_value_check,multiple_partners_value_check,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,accessible_register,letting_allocation_none,referral,referral_value_check,net_income_known,incref,incfreq,earnings,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate -,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2024-04-01T00:00:00+01:00,single log,,,2023,address line 1 as entered,address line 2 as entered,town or city as entered,county as entered,AB1 2CD,la as entered,,DLUHC,DLUHC,General needs,Affordable rent general needs local authority,No,2023-11-26,Affordable Rent,Affordable Rent,Rent to Buy,,No,HIJKLMN,ABCDEFG,Yes,Yes,No,,,,,,,fake address,,London,,NW9 5LL,No,Barnet,E09000003,No,Affordable rent basis,Tenant abandoned property,No,2,House,Purpose built,Yes,3,2023-11-24,,,Yes,2023-11-25,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,4,,Yes,4,0,0,2,35,,Female,White,Irish,Tenant prefers not to say,,Other,Yes,Partner,,,32,Male,Not seeking work,No,Prefers not to say,Not known,Prefers not to say,Prefers not to say,Yes,Person prefers not to say,Not known,Person prefers not to say,Person prefers not to say,,,,,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,Yes,No,No,No,No,No,No,Yes,No,No,Yes,No,No,No,No,No,No,No,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,,Other supported housing,2,No,Yes,TN23 6LZ,Yes,No,Ashford,E07000105,Yes,,Yes,,,,No,No,Yes,No,,Tenant applied directly (no referral or nomination),,Yes,No,Weekly,268,,Universal Credit housing element,Yes,All,,No,Every 2 weeks,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,Yes,Yes,12.0,6.0,,,,,,,,,,,,,,,,,,,, +,in_progress,,s.port@jeemayle.com,false,2024-04-01T00:00:00+01:00,,2024-04-01T00:00:00+01:00,single log,,,2024,address line 1 as entered,address line 2 as entered,town or city as entered,county as entered,AB1 2CD,la as entered,,DLUHC,DLUHC,General needs,Affordable rent general needs local authority,No,2024-04-01,Affordable Rent,Affordable Rent,,,No,HIJKLMN,ABCDEFG,Yes,Yes,No,,,,,,,fake address,,London,,NW9 5LL,No,Barnet,E09000003,No,Affordable rent basis,Tenant abandoned property,No,2,House,Purpose built,Yes,3,2024-03-30,,,Yes,2024-03-31,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,4,,Yes,4,0,0,2,35,,Female,White,Irish,,Australia,Other,Yes,Partner,,,32,Male,Not seeking work,No,Prefers not to say,Not known,Prefers not to say,Prefers not to say,Yes,Person prefers not to say,Not known,Person prefers not to say,Person prefers not to say,,,,,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,Yes,No,No,No,No,No,No,Yes,No,No,Yes,No,No,No,No,No,No,No,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,,Other supported housing,2,No,Yes,TN23 6LZ,Yes,No,Ashford,E07000105,Yes,,Yes,,,,No,No,Yes,No,,Tenant applied directly (no referral or nomination),,Yes,No,Weekly,268,,Universal Credit housing element,Yes,All,,No,Every 2 weeks,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,Yes,Yes,12.0,6.0,,,,,,,,,,,,,,,,,,,, diff --git a/spec/fixtures/files/sales_logs_csv_export_labels_23_during_24_period.csv b/spec/fixtures/files/sales_logs_csv_export_labels_23_during_24_period.csv new file mode 100644 index 000000000..360e2a49d --- /dev/null +++ b/spec/fixtures/files/sales_logs_csv_export_labels_23_during_24_period.csv @@ -0,0 +1,2 @@ +id,status,duplicate_set_id,created_at,updated_at,old_form_id,collection_start_year,creation_method,is_dpo,address_line1_as_entered,address_line2_as_entered,town_or_city_as_entered,county_as_entered,postcode_full_as_entered,la_as_entered,assigned_to,owning_organisation_name,managing_organisation_name,created_by,day,month,year,purchid,ownershipsch,type,othtype,companybuy,buylivein,jointpur,jointmore,noint,privacynotice,uprn,uprn_confirmed,address_line1_input,postcode_full_input,uprn_selection,address_line1,address_line2,town_or_city,county,pcode1,pcode2,la_known,la,la_label,beds,proptype,builtype,pcodenk,wchair,age1,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,buy1livein,relat2,age2,sex2,ethnic_group2,ethnicbuy2,nationalbuy2,nationality_all_buyer2,ecstat2,buy2livein,hholdcount,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,prevten,ppcodenk,ppostc1,ppostc2,previous_la_known,prevloc,prevloc_label,pregyrha,pregother,pregla,pregghb,pregblank,buy2living,prevtenbuy2,hhregres,hhregresstill,armedforcesspouse,disabled,wheel,income1nk,income1,inc1mort,income2nk,income2,inc2mort,hb,savingsnk,savings,prevown,prevshared,proplen,staircase,stairbought,stairowned,staircasesale,resale,exday,exmonth,exyear,hoday,homonth,hoyear,lanomagr,soctenant,frombeds,fromprop,socprevten,value,equity,mortgageused,mortgage,mortgagelender,mortgagelenderother,mortlen,extrabor,deposit,cashdis,mrent,has_mscharge,mscharge,discount,grant +,completed,,2023-12-08T00:00:00+00:00,2024-05-01T00:00:00+01:00,,2023,single log,false,address line 1 as entered,address line 2 as entered,town or city as entered,county as entered,AB1 2CD,la as entered,,DLUHC,DLUHC,billyboy@eyeklaud.com,8,12,2023,,Yes - a discounted ownership scheme,Right to Acquire (RTA),,,,Yes,Yes,Yes,1,,,,,,Address line 1,,Town or city,,SW1A,1AA,1,E09000003,Barnet,2,Flat or maisonette,Purpose built,0,Yes,30,Non-binary,Buyer prefers not to say,17,United Kingdom,,Full-time - 30 hours or more,Yes,Partner,35,Non-binary,Buyer prefers not to say,,Buyer prefers not to say,,Full-time - 30 hours or more,Yes,3,Child,14,Non-binary,,Other,Not known,Non-binary,"In government training into work, such as New Deal",Prefers not to say,Not known,Prefers not to say,Prefers not to say,,,,,Local authority tenant,No,,,No,,,1,1,1,1,,Don't know,,Yes,Yes,No,Yes,Yes,Yes,10000,Yes,Yes,10000,Yes,"Don’t know ",No,,Yes,No,10,,,,,,,,,,,,,,,,,110000.0,,Yes,20000.0,Cambridge Building Society,,10,Yes,80000.0,,,Yes,100.0,,10000.0 diff --git a/spec/fixtures/files/sales_logs_csv_export_labels_24.csv b/spec/fixtures/files/sales_logs_csv_export_labels_24.csv index 360e2a49d..5e9659290 100644 --- a/spec/fixtures/files/sales_logs_csv_export_labels_24.csv +++ b/spec/fixtures/files/sales_logs_csv_export_labels_24.csv @@ -1,2 +1,2 @@ id,status,duplicate_set_id,created_at,updated_at,old_form_id,collection_start_year,creation_method,is_dpo,address_line1_as_entered,address_line2_as_entered,town_or_city_as_entered,county_as_entered,postcode_full_as_entered,la_as_entered,assigned_to,owning_organisation_name,managing_organisation_name,created_by,day,month,year,purchid,ownershipsch,type,othtype,companybuy,buylivein,jointpur,jointmore,noint,privacynotice,uprn,uprn_confirmed,address_line1_input,postcode_full_input,uprn_selection,address_line1,address_line2,town_or_city,county,pcode1,pcode2,la_known,la,la_label,beds,proptype,builtype,pcodenk,wchair,age1,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,buy1livein,relat2,age2,sex2,ethnic_group2,ethnicbuy2,nationalbuy2,nationality_all_buyer2,ecstat2,buy2livein,hholdcount,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,prevten,ppcodenk,ppostc1,ppostc2,previous_la_known,prevloc,prevloc_label,pregyrha,pregother,pregla,pregghb,pregblank,buy2living,prevtenbuy2,hhregres,hhregresstill,armedforcesspouse,disabled,wheel,income1nk,income1,inc1mort,income2nk,income2,inc2mort,hb,savingsnk,savings,prevown,prevshared,proplen,staircase,stairbought,stairowned,staircasesale,resale,exday,exmonth,exyear,hoday,homonth,hoyear,lanomagr,soctenant,frombeds,fromprop,socprevten,value,equity,mortgageused,mortgage,mortgagelender,mortgagelenderother,mortlen,extrabor,deposit,cashdis,mrent,has_mscharge,mscharge,discount,grant -,completed,,2023-12-08T00:00:00+00:00,2024-05-01T00:00:00+01:00,,2023,single log,false,address line 1 as entered,address line 2 as entered,town or city as entered,county as entered,AB1 2CD,la as entered,,DLUHC,DLUHC,billyboy@eyeklaud.com,8,12,2023,,Yes - a discounted ownership scheme,Right to Acquire (RTA),,,,Yes,Yes,Yes,1,,,,,,Address line 1,,Town or city,,SW1A,1AA,1,E09000003,Barnet,2,Flat or maisonette,Purpose built,0,Yes,30,Non-binary,Buyer prefers not to say,17,United Kingdom,,Full-time - 30 hours or more,Yes,Partner,35,Non-binary,Buyer prefers not to say,,Buyer prefers not to say,,Full-time - 30 hours or more,Yes,3,Child,14,Non-binary,,Other,Not known,Non-binary,"In government training into work, such as New Deal",Prefers not to say,Not known,Prefers not to say,Prefers not to say,,,,,Local authority tenant,No,,,No,,,1,1,1,1,,Don't know,,Yes,Yes,No,Yes,Yes,Yes,10000,Yes,Yes,10000,Yes,"Don’t know ",No,,Yes,No,10,,,,,,,,,,,,,,,,,110000.0,,Yes,20000.0,Cambridge Building Society,,10,Yes,80000.0,,,Yes,100.0,,10000.0 +,in_progress,,2024-05-01T00:00:00+01:00,2024-05-01T00:00:00+01:00,,2024,single log,false,address line 1 as entered,address line 2 as entered,town or city as entered,county as entered,AB1 2CD,la as entered,,DLUHC,DLUHC,billyboy@eyeklaud.com,1,5,2024,,Yes - a discounted ownership scheme,Right to Acquire (RTA),,,,Yes,Yes,Yes,1,,,,,,Address line 1,,Town or city,,SW1A,1AA,1,E09000003,Barnet,2,Flat or maisonette,Purpose built,0,Yes,30,Non-binary,Buyer prefers not to say,17,,Australia,Full-time - 30 hours or more,Yes,Partner,35,Non-binary,Buyer prefers not to say,,13,,Full-time - 30 hours or more,Yes,3,Child,14,Non-binary,Child under 16,Other,Not known,Non-binary,"In government training into work, such as New Deal",Prefers not to say,Not known,Prefers not to say,Prefers not to say,,,,,Local authority tenant,Yes,SW1A,1AA,Yes,E09000003,Barnet,1,1,1,1,,Don't know,,Yes,Yes,No,Yes,Yes,Yes,10000,Yes,Yes,10000,Yes,"Don’t know ",No,,Yes,No,10,,,,,,,,,,,,,,,,,110000.0,,Yes,20000.0,Cambridge Building Society,,10,Yes,80000.0,,,Yes,100.0,,10000.0 diff --git a/spec/models/form/lettings/questions/location_id_spec.rb b/spec/models/form/lettings/questions/location_id_spec.rb index a2c41af80..8406b8119 100644 --- a/spec/models/form/lettings/questions/location_id_spec.rb +++ b/spec/models/form/lettings/questions/location_id_spec.rb @@ -80,6 +80,18 @@ RSpec.describe Form::Lettings::Questions::LocationId, type: :model do end end + context "and all the locations are deleted" do + before do + FactoryBot.create(:location, scheme:, discarded_at: Time.utc(2022, 5, 12)) + FactoryBot.create(:location, scheme:, discarded_at: Time.utc(2022, 5, 12)) + lettings_log.update!(scheme:) + end + + it "the displayed_answer_options is an empty hash" do + expect(question.displayed_answer_options(lettings_log)).to eq({}) + end + end + context "and all but one of the locations have a startdate more than 2 weeks in the future" do before do FactoryBot.create(:location, scheme:, startdate: Time.utc(2022, 5, 13)) diff --git a/spec/models/form/lettings/questions/scheme_id_spec.rb b/spec/models/form/lettings/questions/scheme_id_spec.rb index c0cf6fa3b..ec9283113 100644 --- a/spec/models/form/lettings/questions/scheme_id_spec.rb +++ b/spec/models/form/lettings/questions/scheme_id_spec.rb @@ -147,6 +147,19 @@ RSpec.describe Form::Lettings::Questions::SchemeId, type: :model do expect(question.displayed_answer_options(lettings_log)).to eq(expected_answer) end end + + context "when the scheme is deleted" do + let(:scheme) { FactoryBot.create(:scheme, owning_organisation: organisation, discarded_at: Time.zone.yesterday) } + + before do + FactoryBot.create(:location, startdate: Time.zone.tomorrow, scheme:) + end + + it "has the correct answer_options based on the schemes the user's organisation owns or manages" do + expected_answer = { "" => "Select an option" } + expect(question.displayed_answer_options(lettings_log)).to eq(expected_answer) + end + end end context "when there are no schemes with locations" do diff --git a/spec/models/scheme_spec.rb b/spec/models/scheme_spec.rb index 2f1036c1a..9b663595c 100644 --- a/spec/models/scheme_spec.rb +++ b/spec/models/scheme_spec.rb @@ -304,6 +304,14 @@ RSpec.describe Scheme, type: :model do expect(scheme.status).to eq(:activating_soon) end end + + context "when scheme has discarded_at value" do + let(:scheme) { FactoryBot.create(:scheme, discarded_at: Time.zone.now) } + + it "returns deleted" do + expect(scheme.status).to eq(:deleted) + end + end end describe "status_at" do diff --git a/spec/policies/location_policy_spec.rb b/spec/policies/location_policy_spec.rb new file mode 100644 index 000000000..efc56978b --- /dev/null +++ b/spec/policies/location_policy_spec.rb @@ -0,0 +1,92 @@ +require "rails_helper" + +RSpec.describe LocationPolicy do + subject(:policy) { described_class } + + let(:data_provider) { FactoryBot.create(:user, :data_provider) } + let(:data_coordinator) { FactoryBot.create(:user, :data_coordinator) } + let(:support) { FactoryBot.create(:user, :support) } + + permissions :delete? do + let(:location) { FactoryBot.create(:location) } + + context "with active location" do + it "does not allow deleting a location as a provider" do + expect(policy).not_to permit(data_provider, location) + end + + it "does not allow allows deleting a location as a coordinator" do + expect(policy).not_to permit(data_coordinator, location) + end + + it "does not allow deleting a location as a support user" do + expect(policy).not_to permit(support, location) + end + end + + context "with incomplete location" do + before do + location.update!(units: nil) + end + + it "does not allow deleting a location as a provider" do + expect(policy).not_to permit(data_provider, location) + end + + it "does not allow allows deleting a location as a coordinator" do + expect(policy).not_to permit(data_coordinator, location) + end + + it "allows deleting a location as a support user" do + expect(policy).to permit(support, location) + end + end + + context "with deactivated location" do + before do + location.location_deactivation_periods << create(:location_deactivation_period, deactivation_date: Time.zone.local(2024, 4, 10), location:) + location.save! + Timecop.freeze(Time.utc(2024, 4, 10)) + log = create(:lettings_log, scheme: location.scheme, location:) + log.startdate = Time.zone.local(2022, 10, 10) + log.save!(validate: false) + end + + after do + Timecop.unfreeze + end + + context "and associated logs in editable collection period" do + before do + create(:lettings_log, scheme: location.scheme, location:) + end + + it "does not allow deleting a location as a provider" do + expect(policy).not_to permit(data_provider, location) + end + + it "does not allow allows deleting a location as a coordinator" do + expect(policy).not_to permit(data_coordinator, location) + end + + it "does not allow deleting a location as a support user" do + expect(policy).not_to permit(support, location) + end + end + + context "and no associated logs in editable collection period" do + it "does not allow deleting a location as a provider" do + expect(policy).not_to permit(data_provider, location) + end + + it "does not allow allows deleting a location as a coordinator" do + expect(policy).not_to permit(data_coordinator, location) + end + + it "allows deleting a location as a support user" do + expect(policy).to permit(support, location) + end + end + end + end +end diff --git a/spec/policies/scheme_policy_spec.rb b/spec/policies/scheme_policy_spec.rb new file mode 100644 index 000000000..c22be81bb --- /dev/null +++ b/spec/policies/scheme_policy_spec.rb @@ -0,0 +1,94 @@ +require "rails_helper" + +RSpec.describe SchemePolicy do + subject(:policy) { described_class } + + let(:data_provider) { create(:user, :data_provider) } + let(:data_coordinator) { create(:user, :data_coordinator) } + let(:support) { create(:user, :support) } + + permissions :delete? do + let(:scheme) { create(:scheme) } + + before do + create(:location, scheme:) + end + + context "with active scheme" do + it "does not allow deleting a scheme as a provider" do + expect(policy).not_to permit(data_provider, scheme) + end + + it "does not allow allows deleting a scheme as a coordinator" do + expect(policy).not_to permit(data_coordinator, scheme) + end + + it "does not allow deleting a scheme as a support user" do + expect(policy).not_to permit(support, scheme) + end + end + + context "with incomplete scheme" do + let(:scheme) { create(:scheme, :incomplete) } + + it "does not allow deleting a scheme as a provider" do + expect(policy).not_to permit(data_provider, scheme) + end + + it "does not allow allows deleting a scheme as a coordinator" do + expect(policy).not_to permit(data_coordinator, scheme) + end + + it "allows deleting a scheme as a support user" do + expect(policy).to permit(support, scheme) + end + end + + context "with deactivated scheme" do + before do + scheme.scheme_deactivation_periods << create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2024, 4, 10), scheme:) + scheme.save! + Timecop.freeze(Time.utc(2024, 4, 10)) + log = create(:lettings_log, :sh, owning_organisation: scheme.owning_organisation, scheme:) + log.startdate = Time.zone.local(2022, 10, 10) + log.save!(validate: false) + end + + after do + Timecop.unfreeze + end + + context "and associated logs in editable collection period" do + before do + create(:lettings_log, :sh, owning_organisation: scheme.owning_organisation, scheme:, startdate: Time.zone.local(2024, 4, 9)) + end + + it "does not allow deleting a scheme as a provider" do + expect(policy).not_to permit(data_provider, scheme) + end + + it "does not allow allows deleting a scheme as a coordinator" do + expect(policy).not_to permit(data_coordinator, scheme) + end + + it "does not allow deleting a scheme as a support user" do + expect(policy).not_to permit(support, scheme) + end + end + + context "and no associated logs in editable collection period" do + it "does not allow deleting a scheme as a provider" do + expect(policy).not_to permit(data_provider, scheme) + end + + it "does not allow allows deleting a scheme as a coordinator" do + expect(policy).not_to permit(data_coordinator, scheme) + end + + it "allows deleting a scheme as a support user" do + expect(policy).to permit(support, scheme) + end + end + end + end +end diff --git a/spec/requests/locations_controller_spec.rb b/spec/requests/locations_controller_spec.rb index 996dd3de0..751953b6f 100644 --- a/spec/requests/locations_controller_spec.rb +++ b/spec/requests/locations_controller_spec.rb @@ -1405,6 +1405,23 @@ RSpec.describe LocationsController, type: :request do expect(page).to have_content("Check your answers") end + context "with an active location" do + it "does not render delete this location" do + expect(location.status).to eq(:active) + expect(page).not_to have_link("Delete this location", href: "/schemes/#{scheme.id}/locations/#{location.id}/delete-confirmation") + end + end + + context "with an incomplete location" do + it "renders delete this location" do + location.update!(units: nil) + get "/schemes/#{scheme.id}/locations/#{location.id}/check-answers" + + expect(location.reload.status).to eq(:incomplete) + expect(page).to have_link("Delete this location", href: "/schemes/#{scheme.id}/locations/#{location.id}/delete-confirmation") + end + end + context "when location is confirmed" do let(:params) { { location: { confirmed: true } } } @@ -1825,6 +1842,11 @@ RSpec.describe LocationsController, type: :request do expect(response).to have_http_status(:ok) expect(page).to have_link("Reactivate this location", href: "/schemes/#{scheme.id}/locations/#{location.id}/new-reactivation") end + + it "does not render delete this location" do + expect(response).to have_http_status(:ok) + expect(page).not_to have_link("Delete this location", href: "/schemes/#{scheme.id}/locations/#{location.id}/delete-confirmation") + end end context "with location that's deactivating soon" do @@ -1883,6 +1905,108 @@ RSpec.describe LocationsController, type: :request do end end end + + context "when signed in as a support user" do + let(:user) { create(:user, :support) } + let(:scheme) { create(:scheme) } + let(:location) { create(:location, scheme:) } + let(:add_deactivations) { location.location_deactivation_periods << location_deactivation_period } + + before do + Timecop.freeze(Time.utc(2022, 10, 10)) + allow(user).to receive(:need_two_factor_authentication?).and_return(false) + sign_in user + add_deactivations + location.save! + get "/schemes/#{scheme.id}/locations/#{location.id}" + end + + after do + Timecop.unfreeze + end + + context "with active location" do + let(:add_deactivations) {} + + it "does not render delete this location" do + expect(response).to have_http_status(:ok) + expect(page).not_to have_link("Delete this location", href: "/schemes/#{scheme.id}/locations/#{location.id}/delete-confirmation") + end + + it "does not render informative text about deleting the location" do + expect(response).to have_http_status(:ok) + expect(page).not_to have_content("This location was active in an open or editable collection year, and cannot be deleted.") + end + end + + context "with deactivated location" do + let(:location_deactivation_period) { create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 10, 9), location:) } + + it "renders delete this location" do + expect(response).to have_http_status(:ok) + expect(page).to have_link("Delete this location", href: "/schemes/#{scheme.id}/locations/#{location.id}/delete-confirmation") + end + + context "and associated logs in editable collection period" do + before do + create(:lettings_log, :sh, location:, scheme:, startdate: Time.zone.local(2022, 9, 9), owning_organisation: user.organisation) + get "/schemes/#{scheme.id}/locations/#{location.id}" + end + + it "does not render delete this location" do + expect(response).to have_http_status(:ok) + expect(page).not_to have_link("Delete this location", href: "/schemes/#{scheme.id}/locations/#{location.id}/delete-confirmation") + end + + it "adds informative text about deleting the location" do + expect(response).to have_http_status(:ok) + expect(page).to have_content("This location was active in an open or editable collection year, and cannot be deleted.") + end + end + end + + context "with incomplete location" do + let(:add_deactivations) {} + + before do + location.update!(units: nil) + get "/schemes/#{scheme.id}/locations/#{location.id}" + end + + it "renders delete this location" do + expect(location.reload.status).to eq(:incomplete) + expect(response).to have_http_status(:ok) + expect(page).to have_link("Delete this location", href: "/schemes/#{scheme.id}/locations/#{location.id}/delete-confirmation") + end + end + + context "with location that's deactivating soon" do + let(:location_deactivation_period) { create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 10, 12), location:) } + + it "does not render delete this location" do + expect(response).to have_http_status(:ok) + expect(page).not_to have_link("Delete this location", href: "/schemes/#{scheme.id}/locations/#{location.id}/delete-confirmation") + end + end + + context "with location that's deactivating in more than 6 months" do + let(:location_deactivation_period) { create(:location_deactivation_period, deactivation_date: Time.zone.local(2023, 6, 12), location:) } + + it "does not render delete this location" do + expect(response).to have_http_status(:ok) + expect(page).not_to have_link("Delete this location", href: "/schemes/#{scheme.id}/locations/#{location.id}/delete-confirmation") + end + end + + context "with location that's reactivating soon" do + let(:location_deactivation_period) { create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 4, 12), reactivation_date: Time.zone.local(2022, 10, 12), location:) } + + it "does not render delete this location" do + expect(response).to have_http_status(:ok) + expect(page).not_to have_link("Delete this location", href: "/schemes/#{scheme.id}/locations/#{location.id}/delete-confirmation") + end + end + end end describe "#reactivate" do @@ -2040,4 +2164,150 @@ RSpec.describe LocationsController, type: :request do end end end + + describe "#delete-confirmation" do + let(:scheme) { create(:scheme, owning_organisation: user.organisation) } + let(:location) { create(:location, scheme:, created_at: Time.zone.local(2022, 4, 1)) } + + before do + get "/schemes/#{scheme.id}/locations/#{location.id}/delete-confirmation" + end + + context "when not signed in" do + it "redirects to the sign in page" do + expect(response).to redirect_to("/account/sign-in") + end + end + + context "when signed in" do + before do + Timecop.freeze(Time.utc(2022, 10, 10)) + location.location_deactivation_periods << create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 10, 9), location:) + location.save! + allow(user).to receive(:need_two_factor_authentication?).and_return(false) + sign_in user + get "/schemes/#{scheme.id}/locations/#{location.id}/delete-confirmation" + end + + after do + Timecop.unfreeze + end + + context "with a data provider user" do + let(:user) { create(:user) } + + it "returns 401 unauthorized" do + expect(response).to have_http_status(:unauthorized) + end + end + + context "with a data coordinator user" do + let(:user) { create(:user, :data_coordinator) } + + it "returns 401 unauthorized" do + expect(response).to have_http_status(:unauthorized) + end + end + + context "with a support user user" do + let(:user) { create(:user, :support) } + + it "shows the correct title" do + expect(page.find("h1").text).to include "Are you sure you want to delete this location?" + end + + it "shows a warning to the user" do + expect(page).to have_selector(".govuk-warning-text", text: "You will not be able to undo this action") + end + + it "shows a button to delete the selected location" do + expect(page).to have_selector("form.button_to button", text: "Delete this location") + end + + it "the delete location button submits the correct data to the correct path" do + form_containing_button = page.find("form.button_to") + + expect(form_containing_button[:action]).to eq scheme_location_delete_path(scheme, location) + expect(form_containing_button).to have_field "_method", type: :hidden, with: "delete" + end + + it "shows a cancel link with the correct style" do + expect(page).to have_selector("a.govuk-button--secondary", text: "Cancel") + end + + it "shows cancel link that links back to the location page" do + expect(page).to have_link(text: "Cancel", href: scheme_location_path(scheme, location)) + end + end + end + end + + describe "#delete" do + let(:scheme) { create(:scheme, owning_organisation: user.organisation) } + let(:location) { create(:location, scheme:, name: "Location to delete", created_at: Time.zone.local(2022, 4, 1)) } + + before do + Timecop.freeze(Time.utc(2022, 10, 10)) + location.location_deactivation_periods << create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 10, 9), location:) + location.save! + delete "/schemes/#{scheme.id}/locations/#{location.id}/delete" + end + + after do + Timecop.unfreeze + end + + context "when not signed in" do + it "redirects to the sign in page" do + expect(response).to redirect_to("/account/sign-in") + end + end + + context "when signed in" do + before do + allow(user).to receive(:need_two_factor_authentication?).and_return(false) + sign_in user + delete "/schemes/#{scheme.id}/locations/#{location.id}/delete" + end + + context "with a data provider user" do + let(:user) { create(:user) } + + it "returns 401 unauthorized" do + expect(response).to have_http_status(:unauthorized) + end + end + + context "with a data coordinator user" do + let(:user) { create(:user, :data_coordinator) } + + it "returns 401 unauthorized" do + expect(response).to have_http_status(:unauthorized) + end + end + + context "with a support user user" do + let(:user) { create(:user, :support) } + + it "deletes the location" do + location.reload + expect(location.status).to eq(:deleted) + expect(location.discarded_at).not_to be nil + end + + it "redirects to the scheme locations list and displays a notice that the location has been deleted" do + expect(response).to redirect_to scheme_locations_path(scheme) + follow_redirect! + expect(page).to have_selector(".govuk-notification-banner--success") + expect(page).to have_selector(".govuk-notification-banner--success", text: "has been deleted.") + end + + it "does not display the deleted location" do + expect(response).to redirect_to scheme_locations_path(scheme) + follow_redirect! + expect(page).not_to have_content("Location to delete") + end + end + end + end end diff --git a/spec/requests/organisations_controller_spec.rb b/spec/requests/organisations_controller_spec.rb index 68de93c51..22d74470c 100644 --- a/spec/requests/organisations_controller_spec.rb +++ b/spec/requests/organisations_controller_spec.rb @@ -44,6 +44,7 @@ RSpec.describe OrganisationsController, type: :request do let(:user) { create(:user, :support) } let!(:schemes) { create_list(:scheme, 5) } let!(:same_org_scheme) { create(:scheme, owning_organisation: user.organisation) } + let!(:deleted_scheme) { create(:scheme, owning_organisation: user.organisation, discarded_at: Time.zone.yesterday) } before do allow(user).to receive(:need_two_factor_authentication?).and_return(false) @@ -131,6 +132,10 @@ RSpec.describe OrganisationsController, type: :request do end end + it "does not show deleted schemes" do + expect(page).not_to have_content(deleted_scheme.id_to_display) + end + context "when searching" do let!(:searched_scheme) { create(:scheme, owning_organisation: user.organisation) } let(:search_param) { searched_scheme.id } diff --git a/spec/requests/schemes_controller_spec.rb b/spec/requests/schemes_controller_spec.rb index 6e00eb733..c33397983 100644 --- a/spec/requests/schemes_controller_spec.rb +++ b/spec/requests/schemes_controller_spec.rb @@ -56,6 +56,19 @@ RSpec.describe SchemesController, type: :request do end end + context "when there are deleted schemes" do + let!(:deleted_scheme) { create(:scheme, service_name: "deleted", discarded_at: Time.zone.yesterday, owning_organisation: user.organisation) } + + before do + get "/schemes" + end + + it "does not show deleted schemes" do + follow_redirect! + expect(page).not_to have_content(deleted_scheme.id_to_display) + end + end + context "when parent organisation has schemes" do let(:parent_organisation) { create(:organisation) } let!(:parent_schemes) { create_list(:scheme, 5, owning_organisation: parent_organisation) } @@ -191,6 +204,18 @@ RSpec.describe SchemesController, type: :request do expect(page).to have_content("Schemes") end + context "when there are deleted schemes" do + let!(:deleted_scheme) { create(:scheme, service_name: "deleted", discarded_at: Time.zone.yesterday, owning_organisation: user.organisation) } + + before do + get "/schemes" + end + + it "does not show deleted schemes" do + expect(page).not_to have_content(deleted_scheme.id_to_display) + end + end + describe "scheme and location csv downloads" do let!(:same_org_scheme) { create(:scheme, owning_organisation: user.organisation) } let!(:specific_organisation) { create(:organisation) } @@ -577,6 +602,11 @@ RSpec.describe SchemesController, type: :request do expect(response).to have_http_status(:ok) expect(page).to have_link("Reactivate this scheme", href: "/schemes/#{scheme.id}/new-reactivation") end + + it "does not render delete this scheme" do + expect(response).to have_http_status(:ok) + expect(page).not_to have_link("Delete this scheme", href: "/schemes/#{scheme.id}/delete-confirmation") + end end context "with scheme that's deactivating soon" do @@ -712,6 +742,92 @@ RSpec.describe SchemesController, type: :request do expect(page).to have_content(specific_scheme.support_type) expect(page).to have_content(specific_scheme.intended_stay) end + + context "when looking at scheme details" do + let!(:scheme) { create(:scheme, owning_organisation: user.organisation) } + let(:add_deactivations) { scheme.scheme_deactivation_periods << scheme_deactivation_period } + + before do + create(:location, scheme:) + Timecop.freeze(Time.utc(2022, 10, 10)) + sign_in user + add_deactivations + scheme.save! + get "/schemes/#{scheme.id}" + end + + after do + Timecop.unfreeze + end + + context "with active scheme" do + let(:add_deactivations) {} + + it "does not render delete this scheme" do + expect(response).to have_http_status(:ok) + expect(page).not_to have_link("Delete this scheme", href: "/schemes/#{scheme.id}/delete-confirmation") + end + + it "does not render informative text about deleting the scheme" do + expect(response).to have_http_status(:ok) + expect(page).not_to have_content("This scheme was active in an open or editable collection year, and cannot be deleted.") + end + end + + context "with deactivated scheme" do + let(:scheme_deactivation_period) { create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 10, 9), scheme:) } + + it "renders delete this scheme" do + expect(response).to have_http_status(:ok) + expect(page).to have_link("Delete this scheme", href: "/schemes/#{scheme.id}/delete-confirmation") + end + + context "and associated logs in editable collection period" do + before do + create(:lettings_log, :sh, scheme:, startdate: Time.zone.local(2022, 9, 9), owning_organisation: user.organisation) + get "/schemes/#{scheme.id}" + end + + it "does not render delete this scheme" do + expect(response).to have_http_status(:ok) + expect(page).not_to have_link("Delete this scheme", href: "/schemes/#{scheme.id}/delete-confirmation") + end + + it "adds informative text about deleting the scheme" do + expect(response).to have_http_status(:ok) + expect(page).to have_content("This scheme was active in an open or editable collection year, and cannot be deleted.") + end + end + end + + context "with scheme that's deactivating soon" do + let(:scheme_deactivation_period) { create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 10, 12), scheme:) } + + it "does not render delete this scheme" do + expect(response).to have_http_status(:ok) + expect(page).not_to have_link("Delete this scheme", href: "/schemes/#{scheme.id}/delete-confirmation") + end + end + + context "with scheme that's deactivating in more than 6 months" do + let(:scheme_deactivation_period) { create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2023, 5, 12), scheme:) } + + it "does not render delete this scheme" do + expect(response).to have_http_status(:ok) + expect(page).not_to have_link("Delete this scheme", href: "/schemes/#{scheme.id}/delete-confirmation") + end + end + + context "with incomplete scheme" do + let(:add_deactivations) {} + let!(:scheme) { create(:scheme, :incomplete, owning_organisation: user.organisation) } + + it "renders delete this scheme" do + expect(response).to have_http_status(:ok) + expect(page).to have_link("Delete this scheme", href: "/schemes/#{scheme.id}/delete-confirmation") + end + end + end end end @@ -2132,6 +2248,7 @@ RSpec.describe SchemesController, type: :request do let!(:scheme) { create(:scheme) } before do + create(:location, scheme:) allow(user).to receive(:need_two_factor_authentication?).and_return(false) sign_in user get "/schemes/#{scheme.id}/check-answers" @@ -2141,6 +2258,22 @@ RSpec.describe SchemesController, type: :request do expect(response).to have_http_status(:ok) expect(page).to have_content("Check your changes before creating this scheme") end + + context "with an active scheme" do + it "does not render delete this scheme" do + expect(scheme.status).to eq(:active) + expect(page).not_to have_link("Delete this scheme", href: "/schemes/#{scheme.id}/delete-confirmation") + end + end + + context "with an incomplete scheme" do + let(:scheme) { create(:scheme, :incomplete) } + + it "renders delete this scheme" do + expect(scheme.reload.status).to eq(:incomplete) + expect(page).to have_link("Delete this scheme", href: "/schemes/#{scheme.id}/delete-confirmation") + end + end end end @@ -2641,4 +2774,157 @@ RSpec.describe SchemesController, type: :request do end end end + + describe "#delete-confirmation" do + let(:scheme) { create(:scheme, owning_organisation: user.organisation) } + + before do + Timecop.freeze(Time.utc(2022, 10, 10)) + scheme.scheme_deactivation_periods << create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 10, 9), scheme:) + scheme.save! + get "/schemes/#{scheme.id}/delete-confirmation" + end + + after do + Timecop.unfreeze + end + + context "when not signed in" do + it "redirects to the sign in page" do + expect(response).to redirect_to("/account/sign-in") + end + end + + context "when signed in" do + before do + allow(user).to receive(:need_two_factor_authentication?).and_return(false) + sign_in user + get "/schemes/#{scheme.id}/delete-confirmation" + end + + context "with a data provider user" do + let(:user) { create(:user) } + + it "returns 401 unauthorized" do + expect(response).to have_http_status(:unauthorized) + end + end + + context "with a data coordinator user" do + let(:user) { create(:user, :data_coordinator) } + + it "returns 401 unauthorized" do + expect(response).to have_http_status(:unauthorized) + end + end + + context "with a support user user" do + let(:user) { create(:user, :support) } + + it "shows the correct title" do + expect(page.find("h1").text).to include "Are you sure you want to delete this scheme?" + end + + it "shows a warning to the user" do + expect(page).to have_selector(".govuk-warning-text", text: "You will not be able to undo this action") + end + + it "shows a button to delete the selected scheme" do + expect(page).to have_selector("form.button_to button", text: "Delete this scheme") + end + + it "the delete scheme button submits the correct data to the correct path" do + form_containing_button = page.find("form.button_to") + + expect(form_containing_button[:action]).to eq scheme_delete_path(scheme) + expect(form_containing_button).to have_field "_method", type: :hidden, with: "delete" + end + + it "shows a cancel link with the correct style" do + expect(page).to have_selector("a.govuk-button--secondary", text: "Cancel") + end + + it "shows cancel link that links back to the scheme page" do + expect(page).to have_link(text: "Cancel", href: scheme_path(scheme)) + end + end + end + end + + describe "#delete" do + let(:scheme) { create(:scheme, service_name: "Scheme to delete", owning_organisation: user.organisation) } + let!(:locations) { create_list(:location, 2, scheme:, created_at: Time.zone.local(2022, 4, 1)) } + + before do + delete "/schemes/#{scheme.id}/delete" + end + + context "when not signed in" do + it "redirects to the sign in page" do + expect(response).to redirect_to("/account/sign-in") + end + end + + context "when signed in" do + before do + Timecop.freeze(Time.utc(2022, 10, 10)) + scheme.scheme_deactivation_periods << create(:scheme_deactivation_period, deactivation_date: Time.zone.local(2022, 10, 9), scheme:) + scheme.save! + allow(user).to receive(:need_two_factor_authentication?).and_return(false) + sign_in user + delete "/schemes/#{scheme.id}/delete" + end + + after do + Timecop.unfreeze + end + + context "with a data provider user" do + let(:user) { create(:user) } + + it "returns 401 unauthorized" do + expect(response).to have_http_status(:unauthorized) + end + end + + context "with a data coordinator user" do + let(:user) { create(:user, :data_coordinator) } + + it "returns 401 unauthorized" do + expect(response).to have_http_status(:unauthorized) + end + end + + context "with a support user user" do + let(:user) { create(:user, :support) } + + it "deletes the scheme" do + scheme.reload + expect(scheme.status).to eq(:deleted) + expect(scheme.discarded_at).not_to be nil + end + + it "deletes associated locations" do + locations.each do |location| + location.reload + expect(location.status).to eq(:deleted) + expect(location.discarded_at).not_to be nil + end + end + + it "redirects to the schemes list and displays a notice that the scheme has been deleted" do + expect(response).to redirect_to schemes_organisation_path(scheme.owning_organisation) + follow_redirect! + expect(page).to have_selector(".govuk-notification-banner--success") + expect(page).to have_selector(".govuk-notification-banner--success", text: "Scheme to delete has been deleted.") + end + + it "does not display the deleted scheme" do + expect(response).to redirect_to schemes_organisation_path(scheme.owning_organisation) + follow_redirect! + expect(page).not_to have_link("Scheme to delete") + end + end + end + end end diff --git a/spec/services/csv/lettings_log_csv_service_spec.rb b/spec/services/csv/lettings_log_csv_service_spec.rb index c0232ef5d..fdd3b5b2c 100644 --- a/spec/services/csv/lettings_log_csv_service_spec.rb +++ b/spec/services/csv/lettings_log_csv_service_spec.rb @@ -172,14 +172,35 @@ RSpec.describe Csv::LettingsLogCsvService do context "when the current form is 2024" do let(:now) { Time.zone.local(2024, 4, 1) } - it "exports the CSV with 2024 ordering and all values correct" do - expected_content = CSV.read("spec/fixtures/files/lettings_log_csv_export_labels_24.csv") - values_to_delete = %w[id vacdays] - values_to_delete.each do |attribute| - index = csv.first.index(attribute) - csv.second[index] = nil + context "and the log is for 2024 collection period" do + let(:fixed_time) { Time.zone.local(2024, 4, 1) } + + before do + log.update!(national: nil) + log.update!(nationality_all: 36) + end + + it "exports the CSV with 2024 ordering and all values correct" do + expected_content = CSV.read("spec/fixtures/files/lettings_log_csv_export_labels_24.csv") + values_to_delete = %w[id vacdays] + values_to_delete.each do |attribute| + index = csv.first.index(attribute) + csv.second[index] = nil + end + expect(csv).to eq expected_content + end + end + + context "and the log is for 2023 collection period" do + it "exports the CSV with 2024 ordering and all values correct" do + expected_content = CSV.read("spec/fixtures/files/lettings_log_csv_export_labels_23_during_24_period.csv") + values_to_delete = %w[id vacdays] + values_to_delete.each do |attribute| + index = csv.first.index(attribute) + csv.second[index] = nil + end + expect(csv).to eq expected_content end - expect(csv).to eq expected_content end end diff --git a/spec/services/csv/sales_log_csv_service_spec.rb b/spec/services/csv/sales_log_csv_service_spec.rb index e34595942..205f81416 100644 --- a/spec/services/csv/sales_log_csv_service_spec.rb +++ b/spec/services/csv/sales_log_csv_service_spec.rb @@ -168,14 +168,35 @@ RSpec.describe Csv::SalesLogCsvService do context "when the current form is 2024" do let(:now) { Time.zone.local(2024, 5, 1) } - it "exports the CSV with the 2024 ordering and all values correct" do - expected_content = CSV.read("spec/fixtures/files/sales_logs_csv_export_labels_24.csv") - values_to_delete = %w[id] - values_to_delete.each do |attribute| - index = csv.first.index(attribute) - csv.second[index] = nil + context "and the log is for 2024 collection period" do + let(:fixed_time) { Time.zone.local(2024, 5, 1) } + + before do + log.update!(national: nil) + log.update!(nationality_all: 36) + end + + it "exports the CSV with the 2024 ordering and all values correct" do + expected_content = CSV.read("spec/fixtures/files/sales_logs_csv_export_labels_24.csv") + values_to_delete = %w[id] + values_to_delete.each do |attribute| + index = csv.first.index(attribute) + csv.second[index] = nil + end + expect(csv).to eq expected_content + end + end + + context "and the log is for 2023 collection period" do + it "exports the CSV with the 2024 ordering and all values correct" do + expected_content = CSV.read("spec/fixtures/files/sales_logs_csv_export_labels_23_during_24_period.csv") + values_to_delete = %w[id] + values_to_delete.each do |attribute| + index = csv.first.index(attribute) + csv.second[index] = nil + end + expect(csv).to eq expected_content end - expect(csv).to eq expected_content end end diff --git a/spec/views/locations/show.html.erb_spec.rb b/spec/views/locations/show.html.erb_spec.rb index 0b6dee65e..c2510c79b 100644 --- a/spec/views/locations/show.html.erb_spec.rb +++ b/spec/views/locations/show.html.erb_spec.rb @@ -51,6 +51,7 @@ RSpec.describe "locations/show.html.erb" do assign(:location, location) allow(view).to receive(:current_user).and_return(user) + allow(location).to receive(:deactivated?).and_return(false) render @@ -62,6 +63,7 @@ RSpec.describe "locations/show.html.erb" do assign(:location, location) allow(view).to receive(:current_user).and_return(user) + allow(location).to receive(:deactivated?).and_return(false) render