Compare commits

...

8 Commits

Author SHA1 Message Date
kosiakkatrina 9c41d0cca3
CLDC-2041 Display all errors for the page (#2840) 5 days ago
kosiakkatrina a437670874
CLDC-3239 Deduplicate BU forms (#2873) 5 days ago
kosiakkatrina 830adc0dd7
Update test file generation (#2868) 5 days ago
Rachael Booth e1bbbea742
Use assume ssl setting (#2878) 6 days ago
kosiakkatrina 54912a066c
CLDC-3744 Validate correct benefits value in the validation (#2769) 6 days ago
kosiakkatrina 2277585f1b
Do not force ssl (#2877) 6 days ago
kosiakkatrina 3f4cbc2010
Do not assign invalid postcode (#2855) 1 week ago
Rachael Booth 32ea130340
CLDC-3811: Upgrade postgres used in tests and docker compose to 13.18 (#2874) 1 week ago
  1. 12
      .github/workflows/run_tests.yml
  2. 5
      app/components/create_log_actions_component.html.erb
  3. 4
      app/components/create_log_actions_component.rb
  4. 10
      app/controllers/bulk_upload_lettings_logs_controller.rb
  5. 8
      app/controllers/bulk_upload_lettings_resume_controller.rb
  6. 6
      app/controllers/bulk_upload_lettings_soft_validations_check_controller.rb
  7. 10
      app/controllers/bulk_upload_sales_logs_controller.rb
  8. 8
      app/controllers/bulk_upload_sales_resume_controller.rb
  9. 6
      app/controllers/bulk_upload_sales_soft_validations_check_controller.rb
  10. 1
      app/controllers/form_controller.rb
  11. 14
      app/controllers/lettings_logs_controller.rb
  12. 14
      app/controllers/sales_logs_controller.rb
  13. 68
      app/controllers/test_data_controller.rb
  14. 14
      app/helpers/bulk_upload/lettings_log_to_csv.rb
  15. 12
      app/helpers/bulk_upload/sales_log_to_csv.rb
  16. 9
      app/models/forms/bulk_upload_form/checking_file.rb
  17. 13
      app/models/forms/bulk_upload_form/guidance.rb
  18. 21
      app/models/forms/bulk_upload_form/prepare_your_file.rb
  19. 13
      app/models/forms/bulk_upload_form/upload_your_file.rb
  20. 17
      app/models/forms/bulk_upload_form/year.rb
  21. 60
      app/models/forms/bulk_upload_lettings/prepare_your_file.rb
  22. 55
      app/models/forms/bulk_upload_lettings_resume/confirm.rb
  23. 28
      app/models/forms/bulk_upload_lettings_resume/deletion_report.rb
  24. 74
      app/models/forms/bulk_upload_lettings_resume/fix_choice.rb
  25. 31
      app/models/forms/bulk_upload_lettings_soft_validations_check/chosen.rb
  26. 9
      app/models/forms/bulk_upload_resume/chosen.rb
  27. 17
      app/models/forms/bulk_upload_resume/confirm.rb
  28. 9
      app/models/forms/bulk_upload_resume/deletion_report.rb
  29. 17
      app/models/forms/bulk_upload_resume/fix_choice.rb
  30. 32
      app/models/forms/bulk_upload_sales/checking_file.rb
  31. 51
      app/models/forms/bulk_upload_sales/guidance.rb
  32. 83
      app/models/forms/bulk_upload_sales/upload_your_file.rb
  33. 50
      app/models/forms/bulk_upload_sales/year.rb
  34. 31
      app/models/forms/bulk_upload_sales_soft_validations_check/chosen.rb
  35. 47
      app/models/forms/bulk_upload_sales_soft_validations_check/confirm.rb
  36. 53
      app/models/forms/bulk_upload_sales_soft_validations_check/confirm_soft_errors.rb
  37. 9
      app/models/forms/bulk_upload_soft_validations_check/chosen.rb
  38. 13
      app/models/forms/bulk_upload_soft_validations_check/confirm.rb
  39. 13
      app/models/forms/bulk_upload_soft_validations_check/confirm_soft_errors.rb
  40. 3
      app/models/lettings_log.rb
  41. 2
      app/models/log.rb
  42. 3
      app/models/sales_log.rb
  43. 6
      app/models/validations/financial_validations.rb
  44. 2
      app/views/bulk_upload_lettings_results/show.html.erb
  45. 2
      app/views/bulk_upload_lettings_results/summary.html.erb
  46. 2
      app/views/bulk_upload_sales_results/show.html.erb
  47. 2
      app/views/bulk_upload_sales_results/summary.html.erb
  48. 4
      config/environments/production.rb
  49. 4
      config/environments/review.rb
  50. 4
      config/environments/staging.rb
  51. 29
      config/locales/en.yml
  52. 14
      config/routes.rb
  53. 2
      docker-compose.yml
  54. 20
      lib/tasks/clear_invalid_benefits.rake
  55. 8
      spec/features/bulk_upload_lettings_logs_spec.rb
  56. 8
      spec/features/bulk_upload_sales_logs_spec.rb
  57. 27
      spec/features/lettings_log_spec.rb
  58. 27
      spec/features/sales_log_spec.rb
  59. 95
      spec/lib/tasks/clear_invalid_benefits_spec.rb
  60. 117
      spec/models/forms/bulk_upload_form/guidance_spec.rb
  61. 100
      spec/models/forms/bulk_upload_form/upload_your_file_spec.rb
  62. 101
      spec/models/forms/bulk_upload_form/year_spec.rb
  63. 60
      spec/models/forms/bulk_upload_lettings/guidance_spec.rb
  64. 61
      spec/models/forms/bulk_upload_lettings/upload_your_file_spec.rb
  65. 47
      spec/models/forms/bulk_upload_lettings/year_spec.rb
  66. 60
      spec/models/forms/bulk_upload_sales/guidance_spec.rb
  67. 59
      spec/models/forms/bulk_upload_sales/upload_your_file_spec.rb
  68. 51
      spec/models/forms/bulk_upload_sales/year_spec.rb
  69. 14
      spec/models/lettings_log_spec.rb
  70. 16
      spec/models/sales_log_spec.rb
  71. 14
      spec/models/validations/financial_validations_spec.rb
  72. 31
      spec/requests/form_controller_spec.rb
  73. 2
      spec/services/bulk_upload/lettings/year2023/row_parser_spec.rb
  74. 2
      spec/services/bulk_upload/lettings/year2024/row_parser_spec.rb

12
.github/workflows/run_tests.yml

@ -20,7 +20,7 @@ jobs:
services: services:
postgres: postgres:
image: postgres:13.5 image: postgres:13.18
env: env:
POSTGRES_PASSWORD: password POSTGRES_PASSWORD: password
POSTGRES_USER: postgres POSTGRES_USER: postgres
@ -79,7 +79,7 @@ jobs:
services: services:
postgres: postgres:
image: postgres:13.5 image: postgres:13.18
env: env:
POSTGRES_PASSWORD: password POSTGRES_PASSWORD: password
POSTGRES_USER: postgres POSTGRES_USER: postgres
@ -137,7 +137,7 @@ jobs:
services: services:
postgres: postgres:
image: postgres:13.5 image: postgres:13.18
env: env:
POSTGRES_PASSWORD: password POSTGRES_PASSWORD: password
POSTGRES_USER: postgres POSTGRES_USER: postgres
@ -195,7 +195,7 @@ jobs:
services: services:
postgres: postgres:
image: postgres:13.5 image: postgres:13.18
env: env:
POSTGRES_PASSWORD: password POSTGRES_PASSWORD: password
POSTGRES_USER: postgres POSTGRES_USER: postgres
@ -254,7 +254,7 @@ jobs:
services: services:
postgres: postgres:
image: postgres:13.5 image: postgres:13.18
env: env:
POSTGRES_PASSWORD: password POSTGRES_PASSWORD: password
POSTGRES_USER: postgres POSTGRES_USER: postgres
@ -313,7 +313,7 @@ jobs:
services: services:
postgres: postgres:
image: postgres:13.5 image: postgres:13.18
env: env:
POSTGRES_PASSWORD: password POSTGRES_PASSWORD: password
POSTGRES_USER: postgres POSTGRES_USER: postgres

5
app/components/create_log_actions_component.html.erb

@ -9,8 +9,9 @@
<% end %> <% end %>
<% if FeatureToggle.create_test_logs_enabled? %> <% if FeatureToggle.create_test_logs_enabled? %>
<%= govuk_button_link_to "Create test log", create_test_log_href, secondary: true %> <%= govuk_link_to "Create test log", create_test_log_href %>
<%= govuk_button_link_to "Create test log (setup only)", create_setup_test_log_href, secondary: true %> <%= govuk_link_to "Create test log (setup only)", create_setup_test_log_href %>
<%= govuk_link_to "Get test BU file (2024)", create_2024_test_bulk_upload_href %>
<% end %> <% end %>
<% end %> <% end %>
</div> </div>

4
app/components/create_log_actions_component.rb

@ -42,6 +42,10 @@ class CreateLogActionsComponent < ViewComponent::Base
send("create_setup_test_#{log_type}_log_path") send("create_setup_test_#{log_type}_log_path")
end end
def create_2024_test_bulk_upload_href
send("create_2024_test_#{log_type}_bulk_upload_path")
end
def view_uploads_button_copy def view_uploads_button_copy
"View #{log_type} bulk uploads" "View #{log_type} bulk uploads"
end end

10
app/controllers/bulk_upload_lettings_logs_controller.rb

@ -58,15 +58,15 @@ private
def form def form
@form ||= case params[:id] @form ||= case params[:id]
when "year" when "year"
Forms::BulkUploadLettings::Year.new(form_params) Forms::BulkUploadForm::Year.new(form_params.merge(log_type: "lettings"))
when "prepare-your-file" when "prepare-your-file"
Forms::BulkUploadLettings::PrepareYourFile.new(form_params) Forms::BulkUploadForm::PrepareYourFile.new(form_params.merge(log_type: "lettings"))
when "guidance" when "guidance"
Forms::BulkUploadLettings::Guidance.new(form_params.merge(referrer: params[:referrer])) Forms::BulkUploadForm::Guidance.new(form_params.merge(referrer: params[:referrer], log_type: "lettings"))
when "upload-your-file" when "upload-your-file"
Forms::BulkUploadLettings::UploadYourFile.new(form_params.merge(current_user:)) Forms::BulkUploadForm::UploadYourFile.new(form_params.merge(current_user:, log_type: "lettings"))
when "checking-file" when "checking-file"
Forms::BulkUploadLettings::CheckingFile.new(form_params) Forms::BulkUploadForm::CheckingFile.new(form_params.merge(log_type: "lettings"))
else else
raise "Page not found for path #{params[:id]}" raise "Page not found for path #{params[:id]}"
end end

8
app/controllers/bulk_upload_lettings_resume_controller.rb

@ -42,13 +42,13 @@ private
def form def form
@form ||= case params[:page] @form ||= case params[:page]
when "fix-choice" when "fix-choice"
Forms::BulkUploadLettingsResume::FixChoice.new(form_params.merge(bulk_upload: @bulk_upload)) Forms::BulkUploadResume::FixChoice.new(form_params.merge(bulk_upload: @bulk_upload, log_type: "lettings"))
when "chosen" when "chosen"
Forms::BulkUploadLettingsResume::Chosen.new(form_params.merge(bulk_upload: @bulk_upload)) Forms::BulkUploadResume::Chosen.new(form_params.merge(bulk_upload: @bulk_upload, log_type: "lettings"))
when "confirm" when "confirm"
Forms::BulkUploadLettingsResume::Confirm.new(form_params.merge(bulk_upload: @bulk_upload)) Forms::BulkUploadResume::Confirm.new(form_params.merge(bulk_upload: @bulk_upload, log_type: "lettings"))
when "deletion-report" when "deletion-report"
Forms::BulkUploadLettingsResume::DeletionReport.new(form_params.merge(bulk_upload: @bulk_upload)) Forms::BulkUploadResume::DeletionReport.new(form_params.merge(bulk_upload: @bulk_upload, log_type: "lettings"))
else else
raise "invalid form" raise "invalid form"
end end

6
app/controllers/bulk_upload_lettings_soft_validations_check_controller.rb

@ -36,11 +36,11 @@ private
def form def form
@form ||= case params[:page] @form ||= case params[:page]
when "confirm-soft-errors" when "confirm-soft-errors"
Forms::BulkUploadLettingsSoftValidationsCheck::ConfirmSoftErrors.new(form_params.merge(bulk_upload: @bulk_upload)) Forms::BulkUploadSoftValidationsCheck::ConfirmSoftErrors.new(form_params.merge(bulk_upload: @bulk_upload, log_type: "lettings"))
when "chosen" when "chosen"
Forms::BulkUploadLettingsSoftValidationsCheck::Chosen.new(form_params.merge(bulk_upload: @bulk_upload)) Forms::BulkUploadSoftValidationsCheck::Chosen.new(form_params.merge(bulk_upload: @bulk_upload, log_type: "lettings"))
when "confirm" when "confirm"
Forms::BulkUploadLettingsSoftValidationsCheck::Confirm.new(form_params.merge(bulk_upload: @bulk_upload)) Forms::BulkUploadSoftValidationsCheck::Confirm.new(form_params.merge(bulk_upload: @bulk_upload, log_type: "lettings"))
else else
raise "invalid form" raise "invalid form"
end end

10
app/controllers/bulk_upload_sales_logs_controller.rb

@ -58,15 +58,15 @@ private
def form def form
@form ||= case params[:id] @form ||= case params[:id]
when "year" when "year"
Forms::BulkUploadSales::Year.new(form_params) Forms::BulkUploadForm::Year.new(form_params.merge(log_type: "sales"))
when "prepare-your-file" when "prepare-your-file"
Forms::BulkUploadSales::PrepareYourFile.new(form_params) Forms::BulkUploadForm::PrepareYourFile.new(form_params.merge(log_type: "sales"))
when "guidance" when "guidance"
Forms::BulkUploadSales::Guidance.new(form_params.merge(referrer: params[:referrer])) Forms::BulkUploadForm::Guidance.new(form_params.merge(referrer: params[:referrer], log_type: "sales"))
when "upload-your-file" when "upload-your-file"
Forms::BulkUploadSales::UploadYourFile.new(form_params.merge(current_user:)) Forms::BulkUploadForm::UploadYourFile.new(form_params.merge(current_user:, log_type: "sales"))
when "checking-file" when "checking-file"
Forms::BulkUploadSales::CheckingFile.new(form_params) Forms::BulkUploadForm::CheckingFile.new(form_params.merge(log_type: "sales"))
else else
raise "Page not found for path #{params[:id]}" raise "Page not found for path #{params[:id]}"
end end

8
app/controllers/bulk_upload_sales_resume_controller.rb

@ -42,13 +42,13 @@ private
def form def form
@form ||= case params[:page] @form ||= case params[:page]
when "fix-choice" when "fix-choice"
Forms::BulkUploadSalesResume::FixChoice.new(form_params.merge(bulk_upload: @bulk_upload)) Forms::BulkUploadResume::FixChoice.new(form_params.merge(bulk_upload: @bulk_upload, log_type: "sales"))
when "chosen" when "chosen"
Forms::BulkUploadSalesResume::Chosen.new(form_params.merge(bulk_upload: @bulk_upload)) Forms::BulkUploadResume::Chosen.new(form_params.merge(bulk_upload: @bulk_upload, log_type: "sales"))
when "confirm" when "confirm"
Forms::BulkUploadSalesResume::Confirm.new(form_params.merge(bulk_upload: @bulk_upload)) Forms::BulkUploadResume::Confirm.new(form_params.merge(bulk_upload: @bulk_upload, log_type: "sales"))
when "deletion-report" when "deletion-report"
Forms::BulkUploadSalesResume::DeletionReport.new(form_params.merge(bulk_upload: @bulk_upload)) Forms::BulkUploadResume::DeletionReport.new(form_params.merge(bulk_upload: @bulk_upload, log_type: "sales"))
else else
raise "invalid form" raise "invalid form"
end end

6
app/controllers/bulk_upload_sales_soft_validations_check_controller.rb

@ -36,11 +36,11 @@ private
def form def form
@form ||= case params[:page] @form ||= case params[:page]
when "confirm-soft-errors" when "confirm-soft-errors"
Forms::BulkUploadSalesSoftValidationsCheck::ConfirmSoftErrors.new(form_params.merge(bulk_upload: @bulk_upload)) Forms::BulkUploadSoftValidationsCheck::ConfirmSoftErrors.new(form_params.merge(bulk_upload: @bulk_upload, log_type: "sales"))
when "chosen" when "chosen"
Forms::BulkUploadSalesSoftValidationsCheck::Chosen.new(form_params.merge(bulk_upload: @bulk_upload)) Forms::BulkUploadSoftValidationsCheck::Chosen.new(form_params.merge(bulk_upload: @bulk_upload, log_type: "sales"))
when "confirm" when "confirm"
Forms::BulkUploadSalesSoftValidationsCheck::Confirm.new(form_params.merge(bulk_upload: @bulk_upload)) Forms::BulkUploadSoftValidationsCheck::Confirm.new(form_params.merge(bulk_upload: @bulk_upload, log_type: "sales"))
else else
raise "invalid form" raise "invalid form"
end end

1
app/controllers/form_controller.rb

@ -32,6 +32,7 @@ class FormController < ApplicationController
pages_requiring_update = pages_requiring_update(shown_page_ids_with_unanswered_questions_before_update) pages_requiring_update = pages_requiring_update(shown_page_ids_with_unanswered_questions_before_update)
redirect_to(successful_redirect_path(pages_requiring_update)) redirect_to(successful_redirect_path(pages_requiring_update))
else else
@log.valid? if mandatory_questions_with_no_response.any?
mandatory_questions_with_no_response.map do |question| mandatory_questions_with_no_response.map do |question|
@log.errors.add question.id.to_sym, question.unanswered_error_message, category: :not_answered @log.errors.add question.id.to_sym, question.unanswered_error_message, category: :not_answered
end end

14
app/controllers/lettings_logs_controller.rb

@ -149,20 +149,6 @@ class LettingsLogsController < LogsController
end end
end end
def create_test_log
return render_not_found unless FeatureToggle.create_test_logs_enabled?
log = FactoryBot.create(:lettings_log, :completed, assigned_to: current_user, ppostcode_full: "SW1A 1AA")
redirect_to lettings_log_path(log)
end
def create_setup_test_log
return render_not_found unless FeatureToggle.create_test_logs_enabled?
log = FactoryBot.create(:lettings_log, :setup_completed, assigned_to: current_user)
redirect_to lettings_log_path(log)
end
private private
def session_filters def session_filters

14
app/controllers/sales_logs_controller.rb

@ -119,20 +119,6 @@ class SalesLogsController < LogsController
end end
end end
def create_test_log
return render_not_found unless FeatureToggle.create_test_logs_enabled?
log = FactoryBot.create(:sales_log, :completed, assigned_to: current_user)
redirect_to sales_log_path(log)
end
def create_setup_test_log
return render_not_found unless FeatureToggle.create_test_logs_enabled?
log = FactoryBot.create(:sales_log, :shared_ownership_setup_complete, assigned_to: current_user)
redirect_to sales_log_path(log)
end
private private
def session_filters def session_filters

68
app/controllers/test_data_controller.rb

@ -0,0 +1,68 @@
class TestDataController < ApplicationController
rescue_from ActiveRecord::RecordNotFound, with: :render_not_found
def create_test_lettings_log
return render_not_found unless FeatureToggle.create_test_logs_enabled?
log = FactoryBot.create(:lettings_log, :completed, assigned_to: current_user, ppostcode_full: "SW1A 1AA")
redirect_to lettings_log_path(log)
end
def create_setup_test_lettings_log
return render_not_found unless FeatureToggle.create_test_logs_enabled?
log = FactoryBot.create(:lettings_log, :setup_completed, assigned_to: current_user)
redirect_to lettings_log_path(log)
end
def create_2024_test_lettings_bulk_upload
return render_not_found unless FeatureToggle.create_test_logs_enabled?
file = Tempfile.new("test_lettings_log.csv")
log = FactoryBot.create(:lettings_log, :completed, assigned_to: current_user, ppostcode_full: "SW1A 1AA")
log_to_csv = BulkUpload::LettingsLogToCsv.new(log:, line_ending: "\n", overrides: { organisation_id: "ORG#{log.owning_organisation_id}", managing_organisation_id: "ORG#{log.owning_organisation_id}" })
file.write(log_to_csv.default_field_numbers_row)
file.write(log_to_csv.to_csv_row)
file.rewind
send_file file.path, type: "text/csv",
filename: "test_lettings_log.csv",
disposition: "attachment",
after_send: lambda {
file.close
file.unlink
}
end
def create_test_sales_log
return render_not_found unless FeatureToggle.create_test_logs_enabled?
log = FactoryBot.create(:sales_log, :completed, assigned_to: current_user)
redirect_to sales_log_path(log)
end
def create_setup_test_sales_log
return render_not_found unless FeatureToggle.create_test_logs_enabled?
log = FactoryBot.create(:sales_log, :shared_ownership_setup_complete, assigned_to: current_user)
redirect_to sales_log_path(log)
end
def create_2024_test_sales_bulk_upload
return render_not_found unless FeatureToggle.create_test_logs_enabled?
file = Tempfile.new("test_sales_log.csv")
log = FactoryBot.create(:sales_log, :completed, assigned_to: current_user, value: 180_000, deposit: 150_000)
log_to_csv = BulkUpload::SalesLogToCsv.new(log:, line_ending: "\n", overrides: { organisation_id: "ORG#{log.owning_organisation_id}", managing_organisation_id: "ORG#{log.owning_organisation_id}" })
file.write(log_to_csv.default_field_numbers_row)
file.write(log_to_csv.to_csv_row)
file.rewind
send_file file.path, type: "text/csv",
filename: "test_sales_log.csv",
disposition: "attachment",
after_send: lambda {
file.close
file.unlink
}
end
end

14
spec/support/bulk_upload/lettings_log_to_csv.rb → app/helpers/bulk_upload/lettings_log_to_csv.rb

@ -2,10 +2,12 @@ class BulkUpload::LettingsLogToCsv
attr_reader :log, :line_ending, :col_offset, :overrides attr_reader :log, :line_ending, :col_offset, :overrides
def initialize(log:, line_ending: "\n", col_offset: 1, overrides: {}) def initialize(log:, line_ending: "\n", col_offset: 1, overrides: {})
# rubocop:disable Rails/HelperInstanceVariable
@log = log @log = log
@line_ending = line_ending @line_ending = line_ending
@col_offset = col_offset @col_offset = col_offset
@overrides = overrides @overrides = overrides
# rubocop:enable Rails/HelperInstanceVariable
end end
def row_prefix def row_prefix
@ -145,8 +147,8 @@ class BulkUpload::LettingsLogToCsv
def to_2024_row def to_2024_row
[ [
log.owning_organisation&.old_visible_id, # 1 overrides[:organisation_id] || log.owning_organisation&.old_visible_id, # 1
log.managing_organisation&.old_visible_id, overrides[:managing_organisation_id] || log.managing_organisation&.old_visible_id,
log.assigned_to&.email, log.assigned_to&.email,
log.needstype, log.needstype,
log.scheme&.id ? "S#{log.scheme&.id}" : "", log.scheme&.id ? "S#{log.scheme&.id}" : "",
@ -162,10 +164,10 @@ class BulkUpload::LettingsLogToCsv
log.propcode, log.propcode,
log.declaration, log.declaration,
log.uprn, log.uprn,
log.address_line1, log.address_line1&.tr(",", " "),
log.address_line2, log.address_line2&.tr(",", " "),
log.town_or_city, log.town_or_city&.tr(",", " "),
log.county, # 20 log.county&.tr(",", " "), # 20
((log.postcode_full || "").split(" ") || [""]).first, ((log.postcode_full || "").split(" ") || [""]).first,
((log.postcode_full || "").split(" ") || [""]).last, ((log.postcode_full || "").split(" ") || [""]).last,

12
spec/support/bulk_upload/sales_log_to_csv.rb → app/helpers/bulk_upload/sales_log_to_csv.rb

@ -2,10 +2,12 @@ class BulkUpload::SalesLogToCsv
attr_reader :log, :line_ending, :col_offset, :overrides attr_reader :log, :line_ending, :col_offset, :overrides
def initialize(log:, line_ending: "\n", col_offset: 1, overrides: {}) def initialize(log:, line_ending: "\n", col_offset: 1, overrides: {})
# rubocop:disable Rails/HelperInstanceVariable
@log = log @log = log
@line_ending = line_ending @line_ending = line_ending
@col_offset = col_offset @col_offset = col_offset
@overrides = overrides @overrides = overrides
# rubocop:enable Rails/HelperInstanceVariable
end end
def row_prefix def row_prefix
@ -187,7 +189,7 @@ class BulkUpload::SalesLogToCsv
log.prevloc, # 40 log.prevloc, # 40
((log.ppostcode_full || "").split(" ") || [""]).first, ((log.ppostcode_full || "").split(" ") || [""]).first,
((log.ppostcode_full || "").split(" ") || [""]).last, ((log.ppostcode_full || "").split(" ") || [""]).last,
log.ppcodenk == 0 ? 1 : nil, log.ppcodenk&.zero? ? 1 : nil,
log.pregyrha, log.pregyrha,
log.pregla, log.pregla,
@ -311,10 +313,10 @@ class BulkUpload::SalesLogToCsv
log.builtype, log.builtype,
log.uprn, log.uprn,
log.address_line1, log.address_line1&.tr(",", " "),
log.address_line2, log.address_line2&.tr(",", " "),
log.town_or_city, log.town_or_city&.tr(",", " "),
log.county, log.county&.tr(",", " "),
((log.postcode_full || "").split(" ") || [""]).first, ((log.postcode_full || "").split(" ") || [""]).first,
((log.postcode_full || "").split(" ") || [""]).last, ((log.postcode_full || "").split(" ") || [""]).last,
log.la, log.la,

9
app/models/forms/bulk_upload_lettings/checking_file.rb → app/models/forms/bulk_upload_form/checking_file.rb

@ -1,22 +1,23 @@
module Forms module Forms
module BulkUploadLettings module BulkUploadForm
class CheckingFile class CheckingFile
include ActiveModel::Model include ActiveModel::Model
include ActiveModel::Attributes include ActiveModel::Attributes
include Rails.application.routes.url_helpers include Rails.application.routes.url_helpers
attribute :log_type
attribute :year, :integer attribute :year, :integer
attribute :organisation_id, :integer attribute :organisation_id, :integer
def view_path def view_path
"bulk_upload_lettings_logs/forms/checking_file" "bulk_upload_#{log_type}_logs/forms/checking_file"
end end
def back_path def back_path
if organisation_id.present? if organisation_id.present?
lettings_logs_organisation_path(organisation_id) send("#{log_type}_logs_organisation_path", organisation_id)
else else
bulk_upload_lettings_log_path(id: "start") send("bulk_upload_#{log_type}_log_path", id: "start")
end end
end end

13
app/models/forms/bulk_upload_lettings/guidance.rb → app/models/forms/bulk_upload_form/guidance.rb

@ -1,11 +1,12 @@
module Forms module Forms
module BulkUploadLettings module BulkUploadForm
class Guidance class Guidance
include ActiveModel::Model include ActiveModel::Model
include ActiveModel::Attributes include ActiveModel::Attributes
include Rails.application.routes.url_helpers include Rails.application.routes.url_helpers
include CollectionTimeHelper include CollectionTimeHelper
attribute :log_type
attribute :year, :integer attribute :year, :integer
attribute :referrer attribute :referrer
attribute :organisation_id, :integer attribute :organisation_id, :integer
@ -23,7 +24,7 @@ module Forms
def back_path def back_path
case referrer case referrer
when "prepare-your-file" when "prepare-your-file"
bulk_upload_lettings_log_path(id: "prepare-your-file", form: { year:, organisation_id: }.compact) send("bulk_upload_#{log_type}_log_path", id: "prepare-your-file", form: { year:, organisation_id: }.compact)
when "home" when "home"
root_path root_path
else else
@ -32,19 +33,19 @@ module Forms
end end
def lettings_template_path def lettings_template_path
Forms::BulkUploadLettings::PrepareYourFile.new(year:).template_path Forms::BulkUploadForm::PrepareYourFile.new(year:, log_type: "lettings").template_path
end end
def lettings_specification_path def lettings_specification_path
Forms::BulkUploadLettings::PrepareYourFile.new(year:).specification_path Forms::BulkUploadForm::PrepareYourFile.new(year:, log_type: "lettings").specification_path
end end
def sales_template_path def sales_template_path
Forms::BulkUploadSales::PrepareYourFile.new(year:).template_path Forms::BulkUploadForm::PrepareYourFile.new(year:, log_type: "sales").template_path
end end
def sales_specification_path def sales_specification_path
Forms::BulkUploadSales::PrepareYourFile.new(year:).specification_path Forms::BulkUploadForm::PrepareYourFile.new(year:, log_type: "sales").specification_path
end end
end end
end end

21
app/models/forms/bulk_upload_sales/prepare_your_file.rb → app/models/forms/bulk_upload_form/prepare_your_file.rb

@ -1,42 +1,43 @@
module Forms module Forms
module BulkUploadSales module BulkUploadForm
class PrepareYourFile class PrepareYourFile
include ActiveModel::Model include ActiveModel::Model
include ActiveModel::Attributes include ActiveModel::Attributes
include Rails.application.routes.url_helpers include Rails.application.routes.url_helpers
attribute :log_type
attribute :year, :integer attribute :year, :integer
attribute :organisation_id, :integer attribute :organisation_id, :integer
def view_path def view_path
case year case year
when 2023 when 2023
"bulk_upload_sales_logs/forms/prepare_your_file_2023" "bulk_upload_#{log_type}_logs/forms/prepare_your_file_2023"
when 2024 when 2024
"bulk_upload_sales_logs/forms/prepare_your_file_2024" "bulk_upload_#{log_type}_logs/forms/prepare_your_file_2024"
end end
end end
def back_path def back_path
if have_choice_of_year? if have_choice_of_year?
Rails.application.routes.url_helpers.bulk_upload_sales_log_path(id: "year", form: { year: }.compact) Rails.application.routes.url_helpers.send("bulk_upload_#{log_type}_log_path", id: "year", form: { year: }.compact)
elsif organisation_id.present? elsif organisation_id.present?
sales_logs_organisation_path(organisation_id) send("#{log_type}_logs_organisation_path", organisation_id)
else else
Rails.application.routes.url_helpers.sales_logs_path Rails.application.routes.url_helpers.send("#{log_type}_logs_path")
end end
end end
def next_path def next_path
bulk_upload_sales_log_path(id: "upload-your-file", form: { year:, organisation_id: }.compact) send("bulk_upload_#{log_type}_log_path", id: "upload-your-file", form: { year:, organisation_id: }.compact)
end end
def template_path def template_path
download_mandatory_collection_resource_path(year:, log_type: "sales", resource_type: "bulk_upload_template") download_mandatory_collection_resource_path(year:, log_type:, resource_type: "bulk_upload_template")
end end
def specification_path def specification_path
download_mandatory_collection_resource_path(year:, log_type: "sales", resource_type: "bulk_upload_specification") download_mandatory_collection_resource_path(year:, log_type:, resource_type: "bulk_upload_specification")
end end
def year_combo def year_combo
@ -52,7 +53,7 @@ module Forms
def have_choice_of_year? def have_choice_of_year?
return true if FeatureToggle.allow_future_form_use? return true if FeatureToggle.allow_future_form_use?
FormHandler.instance.sales_in_crossover_period? FormHandler.instance.send("#{log_type}_in_crossover_period?")
end end
end end
end end

13
app/models/forms/bulk_upload_lettings/upload_your_file.rb → app/models/forms/bulk_upload_form/upload_your_file.rb

@ -1,14 +1,14 @@
require "shellwords" require "shellwords"
module Forms module Forms
module BulkUploadLettings module BulkUploadForm
class UploadYourFile class UploadYourFile
include ActiveModel::Model include ActiveModel::Model
include ActiveModel::Attributes include ActiveModel::Attributes
include Rails.application.routes.url_helpers include Rails.application.routes.url_helpers
attribute :log_type
attribute :year, :integer attribute :year, :integer
attribute :needstype, :integer
attribute :file attribute :file
attribute :current_user attribute :current_user
attribute :organisation_id, :integer attribute :organisation_id, :integer
@ -18,11 +18,11 @@ module Forms
validate :validate_file_size validate :validate_file_size
def view_path def view_path
"bulk_upload_lettings_logs/forms/upload_your_file" "bulk_upload_#{log_type}_logs/forms/upload_your_file"
end end
def back_path def back_path
bulk_upload_lettings_log_path(id: "prepare-your-file", form: { year:, needstype:, organisation_id: }.compact) send("bulk_upload_#{log_type}_log_path", id: "prepare-your-file", form: { year:, organisation_id: }.compact)
end end
def year_combo def year_combo
@ -30,15 +30,14 @@ module Forms
end end
def next_path def next_path
bulk_upload_lettings_log_path(id: "checking-file", form: { year:, organisation_id: }.compact) send("bulk_upload_#{log_type}_log_path", id: "checking-file", form: { year:, organisation_id: }.compact)
end end
def save! def save!
bulk_upload = BulkUpload.create!( bulk_upload = BulkUpload.create!(
user: current_user, user: current_user,
log_type: BulkUpload.log_types[:lettings], log_type: BulkUpload.log_types[log_type.to_sym],
year:, year:,
needstype:,
filename: file.original_filename, filename: file.original_filename,
organisation_id: (organisation_id if current_user.support?) || current_user.organisation_id, organisation_id: (organisation_id if current_user.support?) || current_user.organisation_id,
) )

17
app/models/forms/bulk_upload_lettings/year.rb → app/models/forms/bulk_upload_form/year.rb

@ -1,17 +1,18 @@
module Forms module Forms
module BulkUploadLettings module BulkUploadForm
class Year class Year
include ActiveModel::Model include ActiveModel::Model
include ActiveModel::Attributes include ActiveModel::Attributes
include Rails.application.routes.url_helpers include Rails.application.routes.url_helpers
attribute :log_type
attribute :year, :integer attribute :year, :integer
attribute :organisation_id, :integer attribute :organisation_id, :integer
validates :year, presence: true validates :year, presence: true
def view_path def view_path
"bulk_upload_lettings_logs/forms/year" "bulk_upload_#{log_type}_logs/forms/year"
end end
def options def options
@ -22,14 +23,14 @@ module Forms
def back_path def back_path
if organisation_id.present? if organisation_id.present?
lettings_logs_organisation_path(organisation_id) send("#{log_type}_logs_organisation_path", organisation_id)
else else
lettings_logs_path send("#{log_type}_logs_path")
end end
end end
def next_path def next_path
bulk_upload_lettings_log_path(id: "prepare-your-file", form: { year:, organisation_id: }.compact) send("bulk_upload_#{log_type}_log_path", id: "prepare-your-file", form: { year:, organisation_id: }.compact)
end end
def save! def save!
@ -40,9 +41,9 @@ module Forms
def possible_years def possible_years
[ [
FormHandler.instance.lettings_forms["current_lettings"].start_date.year, FormHandler.instance.send("#{log_type}_forms")["current_#{log_type}"].start_date.year,
(FormHandler.instance.previous_lettings_form.start_date.year if FormHandler.instance.lettings_in_crossover_period?), (FormHandler.instance.send("previous_#{log_type}_form").start_date.year if FormHandler.instance.send("#{log_type}_in_crossover_period?")),
(FormHandler.instance.next_lettings_form.start_date.year if FeatureToggle.allow_future_form_use?), (FormHandler.instance.send("next_#{log_type}_form").start_date.year if FeatureToggle.allow_future_form_use?),
].compact ].compact
end end
end end

60
app/models/forms/bulk_upload_lettings/prepare_your_file.rb

@ -1,60 +0,0 @@
module Forms
module BulkUploadLettings
class PrepareYourFile
include ActiveModel::Model
include ActiveModel::Attributes
include Rails.application.routes.url_helpers
attribute :year, :integer
attribute :needstype, :integer
attribute :organisation_id, :integer
def view_path
case year
when 2023
"bulk_upload_lettings_logs/forms/prepare_your_file_2023"
when 2024
"bulk_upload_lettings_logs/forms/prepare_your_file_2024"
end
end
def back_path
if have_choice_of_year?
Rails.application.routes.url_helpers.bulk_upload_lettings_log_path(id: "year", form: { year:, organisation_id: }.compact)
elsif organisation_id.present?
lettings_logs_organisation_path(organisation_id)
else
Rails.application.routes.url_helpers.lettings_logs_path
end
end
def next_path
bulk_upload_lettings_log_path(id: "upload-your-file", form: { year:, needstype:, organisation_id: }.compact)
end
def template_path
download_mandatory_collection_resource_path(year:, log_type: "lettings", resource_type: "bulk_upload_template")
end
def specification_path
download_mandatory_collection_resource_path(year:, log_type: "lettings", resource_type: "bulk_upload_specification")
end
def year_combo
"#{year} to #{year + 1}"
end
def save!
true
end
private
def have_choice_of_year?
return true if FeatureToggle.allow_future_form_use?
FormHandler.instance.lettings_in_crossover_period?
end
end
end
end

55
app/models/forms/bulk_upload_lettings_resume/confirm.rb

@ -1,55 +0,0 @@
module Forms
module BulkUploadLettingsResume
class Confirm
include ActiveModel::Model
include ActiveModel::Attributes
include Rails.application.routes.url_helpers
attribute :bulk_upload
def view_path
"bulk_upload_lettings_resume/confirm"
end
def back_path
page_bulk_upload_lettings_resume_path(bulk_upload, page: "fix-choice")
end
def next_path
resume_bulk_upload_lettings_result_path(bulk_upload)
end
def error_report_path
if BulkUploadErrorSummaryTableComponent.new(bulk_upload:).errors?
summary_bulk_upload_lettings_result_path(bulk_upload)
else
bulk_upload_lettings_result_path(bulk_upload)
end
end
def save!
ApplicationRecord.transaction do
processor = BulkUpload::Processor.new(bulk_upload:)
processor.approve
bulk_upload.update!(choice: "create-fix-inline")
end
true
end
def preflight_valid?
bulk_upload.choice != "create-fix-inline" && bulk_upload.choice != "bulk-confirm-soft-validations"
end
def preflight_redirect
case bulk_upload.choice
when "create-fix-inline"
page_bulk_upload_lettings_resume_path(bulk_upload, :chosen)
when "bulk-confirm-soft-validations"
page_bulk_upload_lettings_soft_validations_check_path(bulk_upload, :chosen)
end
end
end
end
end

28
app/models/forms/bulk_upload_lettings_resume/deletion_report.rb

@ -1,28 +0,0 @@
module Forms
module BulkUploadLettingsResume
class DeletionReport
include ActiveModel::Model
include ActiveModel::Attributes
include Rails.application.routes.url_helpers
attribute :bulk_upload
def view_path
"bulk_upload_lettings_resume/deletion_report"
end
def preflight_valid?
bulk_upload.choice != "create-fix-inline" && bulk_upload.choice != "bulk-confirm-soft-validations"
end
def preflight_redirect
case bulk_upload.choice
when "create-fix-inline"
page_bulk_upload_lettings_resume_path(bulk_upload, :chosen)
when "bulk-confirm-soft-validations"
page_bulk_upload_lettings_soft_validations_check_path(bulk_upload, :chosen)
end
end
end
end
end

74
app/models/forms/bulk_upload_lettings_resume/fix_choice.rb

@ -1,74 +0,0 @@
module Forms
module BulkUploadLettingsResume
class FixChoice
include ActiveModel::Model
include ActiveModel::Attributes
include Rails.application.routes.url_helpers
attribute :bulk_upload
attribute :choice, :string
validates :choice, presence: true,
inclusion: { in: %w[create-fix-inline upload-again] }
def options
[
OpenStruct.new(id: "create-fix-inline", name: "Upload these logs and fix errors on CORE site"),
OpenStruct.new(id: "upload-again", name: "Fix errors in the CSV and upload the file again"),
]
end
def view_path
"bulk_upload_lettings_resume/fix_choice"
end
def next_path
case choice
when "create-fix-inline"
page_bulk_upload_lettings_resume_path(bulk_upload, page: "confirm")
when "upload-again"
error_report_path
else
raise "invalid choice"
end
end
def error_report_path
if BulkUploadErrorSummaryTableComponent.new(bulk_upload:).errors?
summary_bulk_upload_lettings_result_path(bulk_upload)
else
bulk_upload_lettings_result_path(bulk_upload)
end
end
def recommendation
if BulkUploadErrorSummaryTableComponent.new(bulk_upload:).errors?
"We recommend fixing these errors in the CSV, as you may be able to edit multiple fields at once. However, you can also upload these logs and fix the errors on the CORE site."
else
"We recommend uploading logs and fixing errors on site as you can easily see the questions and select the appropriate answer. However, you can also fix these errors in the CSV."
end
end
def save!
bulk_upload.update!(choice:) if choice == "upload-again"
true
end
def preflight_valid?
bulk_upload.choice.blank?
end
def preflight_redirect
case bulk_upload.choice
when "create-fix-inline"
page_bulk_upload_lettings_resume_path(bulk_upload, :chosen)
when "bulk-confirm-soft-validations"
page_bulk_upload_lettings_soft_validations_check_path(bulk_upload, :chosen)
else
bulk_upload_lettings_result_path(bulk_upload)
end
end
end
end
end

31
app/models/forms/bulk_upload_lettings_soft_validations_check/chosen.rb

@ -1,31 +0,0 @@
module Forms
module BulkUploadLettingsSoftValidationsCheck
class Chosen
include ActiveModel::Model
include ActiveModel::Attributes
include Rails.application.routes.url_helpers
attribute :bulk_upload
def view_path
"bulk_upload_lettings_soft_validations_check/chosen"
end
def back_path
lettings_logs_path
end
def next_path
lettings_logs_path
end
def save!
true
end
def preflight_valid?
true
end
end
end
end

9
app/models/forms/bulk_upload_lettings_resume/chosen.rb → app/models/forms/bulk_upload_resume/chosen.rb

@ -1,22 +1,23 @@
module Forms module Forms
module BulkUploadLettingsResume module BulkUploadResume
class Chosen class Chosen
include ActiveModel::Model include ActiveModel::Model
include ActiveModel::Attributes include ActiveModel::Attributes
include Rails.application.routes.url_helpers include Rails.application.routes.url_helpers
attribute :log_type
attribute :bulk_upload attribute :bulk_upload
def view_path def view_path
bulk_upload.completed? ? "bulk_upload_lettings_resume/completed" : "bulk_upload_lettings_resume/chosen" bulk_upload.completed? ? "bulk_upload_#{log_type}_resume/completed" : "bulk_upload_#{log_type}_resume/chosen"
end end
def back_path def back_path
lettings_logs_path send("#{log_type}_logs_path")
end end
def next_path def next_path
lettings_logs_path send("#{log_type}_logs_path")
end end
def save! def save!

17
app/models/forms/bulk_upload_sales_resume/confirm.rb → app/models/forms/bulk_upload_resume/confirm.rb

@ -1,29 +1,30 @@
module Forms module Forms
module BulkUploadSalesResume module BulkUploadResume
class Confirm class Confirm
include ActiveModel::Model include ActiveModel::Model
include ActiveModel::Attributes include ActiveModel::Attributes
include Rails.application.routes.url_helpers include Rails.application.routes.url_helpers
attribute :log_type
attribute :bulk_upload attribute :bulk_upload
def view_path def view_path
"bulk_upload_sales_resume/confirm" "bulk_upload_#{log_type}_resume/confirm"
end end
def back_path def back_path
page_bulk_upload_sales_resume_path(bulk_upload, page: "fix-choice") send("page_bulk_upload_#{log_type}_resume_path", bulk_upload, page: "fix-choice")
end end
def next_path def next_path
resume_bulk_upload_sales_result_path(bulk_upload) send("resume_bulk_upload_#{log_type}_result_path", bulk_upload)
end end
def error_report_path def error_report_path
if BulkUploadErrorSummaryTableComponent.new(bulk_upload:).errors? if BulkUploadErrorSummaryTableComponent.new(bulk_upload:).errors?
summary_bulk_upload_sales_result_path(bulk_upload) send("summary_bulk_upload_#{log_type}_result_path", bulk_upload)
else else
bulk_upload_sales_result_path(bulk_upload) send("bulk_upload_#{log_type}_result_path", bulk_upload)
end end
end end
@ -45,9 +46,9 @@ module Forms
def preflight_redirect def preflight_redirect
case bulk_upload.choice case bulk_upload.choice
when "create-fix-inline" when "create-fix-inline"
page_bulk_upload_sales_resume_path(bulk_upload, :chosen) send("page_bulk_upload_#{log_type}_resume_path", bulk_upload, :chosen)
when "bulk-confirm-soft-validations" when "bulk-confirm-soft-validations"
page_bulk_upload_sales_soft_validations_check_path(bulk_upload, :chosen) send("page_bulk_upload_#{log_type}_soft_validations_check_path", bulk_upload, :chosen)
end end
end end
end end

9
app/models/forms/bulk_upload_sales_resume/deletion_report.rb → app/models/forms/bulk_upload_resume/deletion_report.rb

@ -1,14 +1,15 @@
module Forms module Forms
module BulkUploadSalesResume module BulkUploadResume
class DeletionReport class DeletionReport
include ActiveModel::Model include ActiveModel::Model
include ActiveModel::Attributes include ActiveModel::Attributes
include Rails.application.routes.url_helpers include Rails.application.routes.url_helpers
attribute :log_type
attribute :bulk_upload attribute :bulk_upload
def view_path def view_path
"bulk_upload_sales_resume/deletion_report" "bulk_upload_#{log_type}_resume/deletion_report"
end end
def preflight_valid? def preflight_valid?
@ -18,9 +19,9 @@ module Forms
def preflight_redirect def preflight_redirect
case bulk_upload.choice case bulk_upload.choice
when "create-fix-inline" when "create-fix-inline"
page_bulk_upload_sales_resume_path(bulk_upload, :chosen) send("page_bulk_upload_#{log_type}_resume_path", bulk_upload, :chosen)
when "bulk-confirm-soft-validations" when "bulk-confirm-soft-validations"
page_bulk_upload_sales_soft_validations_check_path(bulk_upload, :chosen) send("page_bulk_upload_#{log_type}_soft_validations_check_path", bulk_upload, :chosen)
end end
end end
end end

17
app/models/forms/bulk_upload_sales_resume/fix_choice.rb → app/models/forms/bulk_upload_resume/fix_choice.rb

@ -1,10 +1,11 @@
module Forms module Forms
module BulkUploadSalesResume module BulkUploadResume
class FixChoice class FixChoice
include ActiveModel::Model include ActiveModel::Model
include ActiveModel::Attributes include ActiveModel::Attributes
include Rails.application.routes.url_helpers include Rails.application.routes.url_helpers
attribute :log_type
attribute :bulk_upload attribute :bulk_upload
attribute :choice, :string attribute :choice, :string
@ -19,13 +20,13 @@ module Forms
end end
def view_path def view_path
"bulk_upload_sales_resume/fix_choice" "bulk_upload_#{log_type}_resume/fix_choice"
end end
def next_path def next_path
case choice case choice
when "create-fix-inline" when "create-fix-inline"
page_bulk_upload_sales_resume_path(bulk_upload, page: "confirm") send("page_bulk_upload_#{log_type}_resume_path", bulk_upload, page: "confirm")
when "upload-again" when "upload-again"
error_report_path error_report_path
else else
@ -35,9 +36,9 @@ module Forms
def error_report_path def error_report_path
if BulkUploadErrorSummaryTableComponent.new(bulk_upload:).errors? if BulkUploadErrorSummaryTableComponent.new(bulk_upload:).errors?
summary_bulk_upload_sales_result_path(bulk_upload) send("summary_bulk_upload_#{log_type}_result_path", bulk_upload)
else else
bulk_upload_sales_result_path(bulk_upload) send("bulk_upload_#{log_type}_result_path", bulk_upload)
end end
end end
@ -62,11 +63,11 @@ module Forms
def preflight_redirect def preflight_redirect
case bulk_upload.choice case bulk_upload.choice
when "create-fix-inline" when "create-fix-inline"
page_bulk_upload_sales_resume_path(bulk_upload, :chosen) send("page_bulk_upload_#{log_type}_resume_path", bulk_upload, :chosen)
when "bulk-confirm-soft-validations" when "bulk-confirm-soft-validations"
page_bulk_upload_sales_soft_validations_check_path(bulk_upload, :chosen) send("page_bulk_upload_#{log_type}_soft_validations_check_path", bulk_upload, :chosen)
else else
bulk_upload_sales_result_path(bulk_upload) send("bulk_upload_#{log_type}_result_path", bulk_upload)
end end
end end
end end

32
app/models/forms/bulk_upload_sales/checking_file.rb

@ -1,32 +0,0 @@
module Forms
module BulkUploadSales
class CheckingFile
include ActiveModel::Model
include ActiveModel::Attributes
include Rails.application.routes.url_helpers
attribute :year, :integer
attribute :organisation_id, :integer
def view_path
"bulk_upload_sales_logs/forms/checking_file"
end
def back_path
if organisation_id.present?
sales_logs_organisation_path(organisation_id)
else
bulk_upload_sales_log_path(id: "start")
end
end
def year_combo
"#{year} to #{year + 1}"
end
def save!
true
end
end
end
end

51
app/models/forms/bulk_upload_sales/guidance.rb

@ -1,51 +0,0 @@
module Forms
module BulkUploadSales
class Guidance
include ActiveModel::Model
include ActiveModel::Attributes
include Rails.application.routes.url_helpers
include CollectionTimeHelper
attribute :year, :integer
attribute :referrer
attribute :organisation_id, :integer
def initialize(params)
super(params)
self.year = current_collection_start_year if year.nil?
end
def view_path
"bulk_upload_shared/guidance"
end
def back_path
case referrer
when "prepare-your-file"
bulk_upload_sales_log_path(id: "prepare-your-file", form: { year:, organisation_id: }.compact)
when "home"
root_path
else
guidance_path
end
end
def lettings_template_path
Forms::BulkUploadLettings::PrepareYourFile.new(year:).template_path
end
def lettings_specification_path
Forms::BulkUploadLettings::PrepareYourFile.new(year:).specification_path
end
def sales_template_path
Forms::BulkUploadSales::PrepareYourFile.new(year:).template_path
end
def sales_specification_path
Forms::BulkUploadSales::PrepareYourFile.new(year:).specification_path
end
end
end
end

83
app/models/forms/bulk_upload_sales/upload_your_file.rb

@ -1,83 +0,0 @@
require "shellwords"
module Forms
module BulkUploadSales
class UploadYourFile
include ActiveModel::Model
include ActiveModel::Attributes
include Rails.application.routes.url_helpers
attribute :year, :integer
attribute :file
attribute :current_user
attribute :organisation_id, :integer
validates :file, presence: true
validate :validate_file_is_csv
validate :validate_file_size
def view_path
"bulk_upload_sales_logs/forms/upload_your_file"
end
def back_path
bulk_upload_sales_log_path(id: "prepare-your-file", form: { year:, organisation_id: }.compact)
end
def year_combo
"#{year} to #{year + 1}"
end
def next_path
bulk_upload_sales_log_path(id: "checking-file", form: { year:, organisation_id: }.compact)
end
def save!
bulk_upload = BulkUpload.create!(
user: current_user,
log_type: BulkUpload.log_types[:sales],
year:,
filename: file.original_filename,
organisation_id: (organisation_id if current_user.support?) || current_user.organisation_id,
)
storage_service.write_file(bulk_upload.identifier, File.read(file.path))
ProcessBulkUploadJob.perform_later(bulk_upload:)
true
end
private
def storage_service
@storage_service ||= if FeatureToggle.upload_enabled?
Storage::S3Service.new(Configuration::EnvConfigurationService.new, ENV["BULK_UPLOAD_BUCKET"])
else
Storage::LocalDiskService.new
end
end
def validate_file_is_csv
return unless file
argv = %W[file --brief --mime-type -- #{file.path}]
output = `#{argv.shelljoin}`
unless output.match?(/text\/csv|text\/plain/)
errors.add(:file, :not_csv)
end
end
MAX_FILE_SIZE = 10.megabytes
def validate_file_size
return unless file
if file.size > MAX_FILE_SIZE
errors.add(:file, :file_too_large)
end
end
end
end
end

50
app/models/forms/bulk_upload_sales/year.rb

@ -1,50 +0,0 @@
module Forms
module BulkUploadSales
class Year
include ActiveModel::Model
include ActiveModel::Attributes
include Rails.application.routes.url_helpers
attribute :year, :integer
attribute :organisation_id, :integer
validates :year, presence: true
def view_path
"bulk_upload_sales_logs/forms/year"
end
def options
possible_years.map do |year|
OpenStruct.new(id: year, name: "#{year} to #{year + 1}")
end
end
def back_path
if organisation_id.present?
sales_logs_organisation_path(organisation_id)
else
sales_logs_path
end
end
def next_path
bulk_upload_sales_log_path(id: "prepare-your-file", form: { year:, organisation_id: }.compact)
end
def save!
true
end
private
def possible_years
[
FormHandler.instance.current_sales_form.start_date.year,
(FormHandler.instance.previous_sales_form.start_date.year if FormHandler.instance.sales_in_crossover_period?),
(FormHandler.instance.next_sales_form.start_date.year if FeatureToggle.allow_future_form_use?),
].compact
end
end
end
end

31
app/models/forms/bulk_upload_sales_soft_validations_check/chosen.rb

@ -1,31 +0,0 @@
module Forms
module BulkUploadSalesSoftValidationsCheck
class Chosen
include ActiveModel::Model
include ActiveModel::Attributes
include Rails.application.routes.url_helpers
attribute :bulk_upload
def view_path
"bulk_upload_sales_soft_validations_check/chosen"
end
def back_path
sales_logs_path
end
def next_path
sales_logs_path
end
def save!
true
end
def preflight_valid?
true
end
end
end
end

47
app/models/forms/bulk_upload_sales_soft_validations_check/confirm.rb

@ -1,47 +0,0 @@
module Forms
module BulkUploadSalesSoftValidationsCheck
class Confirm
include ActiveModel::Model
include ActiveModel::Attributes
include Rails.application.routes.url_helpers
attribute :bulk_upload
def view_path
"bulk_upload_sales_soft_validations_check/confirm"
end
def back_path
page_bulk_upload_sales_soft_validations_check_path(bulk_upload, page: "confirm-soft-errors")
end
def next_path
sales_logs_path
end
def save!
ApplicationRecord.transaction do
processor = BulkUpload::Processor.new(bulk_upload:)
processor.approve_and_confirm_soft_validations
bulk_upload.update!(choice: "bulk-confirm-soft-validations")
end
true
end
def preflight_valid?
bulk_upload.choice != "bulk-confirm-soft-validations" && bulk_upload.choice != "create-fix-inline"
end
def preflight_redirect
case bulk_upload.choice
when "bulk-confirm-soft-validations"
page_bulk_upload_sales_soft_validations_check_path(bulk_upload, :chosen)
when "create-fix-inline"
page_bulk_upload_sales_resume_path(bulk_upload, :chosen)
end
end
end
end
end

53
app/models/forms/bulk_upload_sales_soft_validations_check/confirm_soft_errors.rb

@ -1,53 +0,0 @@
module Forms
module BulkUploadSalesSoftValidationsCheck
class ConfirmSoftErrors
include ActiveModel::Model
include ActiveModel::Attributes
include Rails.application.routes.url_helpers
attribute :bulk_upload
attribute :confirm_soft_errors, :string
validates :confirm_soft_errors, presence: true
def options
[
OpenStruct.new(id: "yes", name: "Yes, these fields are correct"),
OpenStruct.new(id: "no", name: "No, there are errors"),
]
end
def view_path
"bulk_upload_sales_soft_validations_check/confirm_soft_errors"
end
def next_path
case confirm_soft_errors
when "no"
page_bulk_upload_sales_resume_path(bulk_upload, page: "fix-choice", soft_errors_only: true)
when "yes"
page_bulk_upload_sales_soft_validations_check_path(bulk_upload, page: "confirm")
else
raise "invalid choice"
end
end
def save!
true
end
def preflight_valid?
bulk_upload.choice != "bulk-confirm-soft-validations" && bulk_upload.choice != "create-fix-inline"
end
def preflight_redirect
case bulk_upload.choice
when "bulk-confirm-soft-validations"
page_bulk_upload_sales_soft_validations_check_path(bulk_upload, :chosen)
when "create-fix-inline"
page_bulk_upload_sales_resume_path(bulk_upload, :chosen)
end
end
end
end
end

9
app/models/forms/bulk_upload_sales_resume/chosen.rb → app/models/forms/bulk_upload_soft_validations_check/chosen.rb

@ -1,22 +1,23 @@
module Forms module Forms
module BulkUploadSalesResume module BulkUploadSoftValidationsCheck
class Chosen class Chosen
include ActiveModel::Model include ActiveModel::Model
include ActiveModel::Attributes include ActiveModel::Attributes
include Rails.application.routes.url_helpers include Rails.application.routes.url_helpers
attribute :log_type
attribute :bulk_upload attribute :bulk_upload
def view_path def view_path
bulk_upload.completed? ? "bulk_upload_sales_resume/completed" : "bulk_upload_sales_resume/chosen" "bulk_upload_#{log_type}_soft_validations_check/chosen"
end end
def back_path def back_path
sales_logs_path send("#{log_type}_logs_path")
end end
def next_path def next_path
sales_logs_path send("#{log_type}_logs_path")
end end
def save! def save!

13
app/models/forms/bulk_upload_lettings_soft_validations_check/confirm.rb → app/models/forms/bulk_upload_soft_validations_check/confirm.rb

@ -1,22 +1,23 @@
module Forms module Forms
module BulkUploadLettingsSoftValidationsCheck module BulkUploadSoftValidationsCheck
class Confirm class Confirm
include ActiveModel::Model include ActiveModel::Model
include ActiveModel::Attributes include ActiveModel::Attributes
include Rails.application.routes.url_helpers include Rails.application.routes.url_helpers
attribute :log_type
attribute :bulk_upload attribute :bulk_upload
def view_path def view_path
"bulk_upload_lettings_soft_validations_check/confirm" "bulk_upload_#{log_type}_soft_validations_check/confirm"
end end
def back_path def back_path
page_bulk_upload_lettings_soft_validations_check_path(bulk_upload, page: "confirm-soft-errors") send("page_bulk_upload_#{log_type}_soft_validations_check_path", bulk_upload, page: "confirm-soft-errors")
end end
def next_path def next_path
lettings_logs_path send("#{log_type}_logs_path")
end end
def save! def save!
@ -37,9 +38,9 @@ module Forms
def preflight_redirect def preflight_redirect
case bulk_upload.choice case bulk_upload.choice
when "bulk-confirm-soft-validations" when "bulk-confirm-soft-validations"
page_bulk_upload_lettings_soft_validations_check_path(bulk_upload, :chosen) send("page_bulk_upload_#{log_type}_soft_validations_check_path", bulk_upload, :chosen)
when "create-fix-inline" when "create-fix-inline"
page_bulk_upload_lettings_resume_path(bulk_upload, :chosen) send("page_bulk_upload_#{log_type}_resume_path", bulk_upload, :chosen)
end end
end end
end end

13
app/models/forms/bulk_upload_lettings_soft_validations_check/confirm_soft_errors.rb → app/models/forms/bulk_upload_soft_validations_check/confirm_soft_errors.rb

@ -1,10 +1,11 @@
module Forms module Forms
module BulkUploadLettingsSoftValidationsCheck module BulkUploadSoftValidationsCheck
class ConfirmSoftErrors class ConfirmSoftErrors
include ActiveModel::Model include ActiveModel::Model
include ActiveModel::Attributes include ActiveModel::Attributes
include Rails.application.routes.url_helpers include Rails.application.routes.url_helpers
attribute :log_type
attribute :bulk_upload attribute :bulk_upload
attribute :confirm_soft_errors, :string attribute :confirm_soft_errors, :string
@ -18,15 +19,15 @@ module Forms
end end
def view_path def view_path
"bulk_upload_lettings_soft_validations_check/confirm_soft_errors" "bulk_upload_#{log_type}_soft_validations_check/confirm_soft_errors"
end end
def next_path def next_path
case confirm_soft_errors case confirm_soft_errors
when "no" when "no"
page_bulk_upload_lettings_resume_path(bulk_upload, page: "fix-choice", soft_errors_only: true) send("page_bulk_upload_#{log_type}_resume_path", bulk_upload, page: "fix-choice", soft_errors_only: true)
when "yes" when "yes"
page_bulk_upload_lettings_soft_validations_check_path(bulk_upload, page: "confirm") send("page_bulk_upload_#{log_type}_soft_validations_check_path", bulk_upload, page: "confirm")
else else
raise "invalid choice" raise "invalid choice"
end end
@ -43,9 +44,9 @@ module Forms
def preflight_redirect def preflight_redirect
case bulk_upload.choice case bulk_upload.choice
when "bulk-confirm-soft-validations" when "bulk-confirm-soft-validations"
page_bulk_upload_lettings_soft_validations_check_path(bulk_upload, :chosen) send("page_bulk_upload_#{log_type}_soft_validations_check_path", bulk_upload, :chosen)
when "create-fix-inline" when "create-fix-inline"
page_bulk_upload_lettings_resume_path(bulk_upload, :chosen) send("page_bulk_upload_#{log_type}_resume_path", bulk_upload, :chosen)
end end
end end
end end

3
app/models/lettings_log.rb

@ -779,8 +779,7 @@ private
not_required << "previous_la_known" if postcode_known? not_required << "previous_la_known" if postcode_known?
not_required << "tshortfall" if tshortfall_unknown? not_required << "tshortfall" if tshortfall_unknown?
not_required << "tenancylength" if tenancylength_optional? not_required << "tenancylength" if tenancylength_optional?
not_required += %w[address_line2 county]
not_required |= %w[address_line2 county postcode_full] if startdate && collection_start_year_for_date(startdate) >= 2023
not_required not_required
end end

2
app/models/log.rb

@ -110,7 +110,7 @@ class Log < ApplicationRecord
self.address_line2 = nil self.address_line2 = nil
self.town_or_city = nil self.town_or_city = nil
self.county = nil self.county = nil
self.postcode_full = postcode_full_input self.postcode_full = postcode_full_input if postcode_full_input.match(POSTCODE_REGEXP)
process_postcode_changes! process_postcode_changes!
else else
self.uprn = uprn_selection self.uprn = uprn_selection

3
app/models/sales_log.rb

@ -132,8 +132,7 @@ class SalesLog < Log
not_required << "mortlen" if mortlen_optional? not_required << "mortlen" if mortlen_optional?
not_required << "frombeds" if frombeds_optional? not_required << "frombeds" if frombeds_optional?
not_required << "deposit" if form.start_year_2024_or_later? && stairowned_100? not_required << "deposit" if form.start_year_2024_or_later? && stairowned_100?
not_required += %w[address_line2 county]
not_required |= %w[address_line2 county postcode_full] if saledate && collection_start_year_for_date(saledate) >= 2023
not_required not_required
end end

6
app/models/validations/financial_validations.rb

@ -11,14 +11,14 @@ module Validations::FinancialValidations
end end
end end
EMPLOYED_STATUSES = [1, 0].freeze EMPLOYED_STATUSES = [1, 2].freeze
def validate_net_income_uc_proportion(record) def validate_net_income_uc_proportion(record)
(1..8).any? do |n| (1..8).any? do |n|
economic_status = record["ecstat#{n}"] economic_status = record["ecstat#{n}"]
is_employed = EMPLOYED_STATUSES.include?(economic_status) is_employed = EMPLOYED_STATUSES.include?(economic_status)
relationship = record["relat#{n}"] relationship = record["relat#{n}"]
is_partner_or_main = relationship == "P" || (relationship.nil? && economic_status.present?) is_partner_or_main = relationship == "P" || n == 1
if is_employed && is_partner_or_main && record.benefits&.zero? if is_employed && is_partner_or_main && record.benefits == 1
record.errors.add :benefits, I18n.t("validations.lettings.financial.benefits.part_or_full_time") record.errors.add :benefits, I18n.t("validations.lettings.financial.benefits.part_or_full_time")
end end
end end

2
app/views/bulk_upload_lettings_results/show.html.erb

@ -10,7 +10,7 @@
<h1 class="govuk-heading-l">We found <%= pluralize(@bulk_upload.bulk_upload_errors.count, "error") %> in your file</h1> <h1 class="govuk-heading-l">We found <%= pluralize(@bulk_upload.bulk_upload_errors.count, "error") %> in your file</h1>
<div class="govuk-body"> <div class="govuk-body">
Here’s a list of everything that you need to fix your spreadsheet. You can download the <%= govuk_link_to "specification", Forms::BulkUploadLettings::PrepareYourFile.new(year: @bulk_upload.year).specification_path, target: "_blank" %> to help you fix the cells in your CSV file. Here’s a list of everything that you need to fix your spreadsheet. You can download the <%= govuk_link_to "specification", Forms::BulkUploadForm::PrepareYourFile.new(year: @bulk_upload.year, log_type: "lettings").specification_path, target: "_blank" %> to help you fix the cells in your CSV file.
</div> </div>
<p class="govuk-!-font-size-19 govuk-!-margin-bottom-2"><strong>File name: </strong><%= @bulk_upload.filename %></p> <p class="govuk-!-font-size-19 govuk-!-margin-bottom-2"><strong>File name: </strong><%= @bulk_upload.filename %></p>

2
app/views/bulk_upload_lettings_results/summary.html.erb

@ -6,7 +6,7 @@
<h1 class="govuk-heading-l">Fix <%= pluralize(@bulk_upload.bulk_upload_errors.count, "error") %> and upload file again</h1> <h1 class="govuk-heading-l">Fix <%= pluralize(@bulk_upload.bulk_upload_errors.count, "error") %> and upload file again</h1>
<p class="govuk-body"> <p class="govuk-body">
We could not create logs from your bulk upload because of the following errors. Download the <%= govuk_link_to "specification", Forms::BulkUploadLettings::PrepareYourFile.new(year: @bulk_upload.year).specification_path, target: "_blank" %> to help you fix the cells in your CSV file. We could not create logs from your bulk upload because of the following errors. Download the <%= govuk_link_to "specification", Forms::BulkUploadForm::PrepareYourFile.new(year: @bulk_upload.year, log_type: "lettings").specification_path, target: "_blank" %> to help you fix the cells in your CSV file.
</p> </p>
<p class="govuk-!-font-size-19 govuk-!-margin-bottom-2"><strong>File name: </strong><%= @bulk_upload.filename %></p> <p class="govuk-!-font-size-19 govuk-!-margin-bottom-2"><strong>File name: </strong><%= @bulk_upload.filename %></p>

2
app/views/bulk_upload_sales_results/show.html.erb

@ -10,7 +10,7 @@
<h1 class="govuk-heading-l">We found <%= pluralize(@bulk_upload.bulk_upload_errors.count, "error") %> in your file</h1> <h1 class="govuk-heading-l">We found <%= pluralize(@bulk_upload.bulk_upload_errors.count, "error") %> in your file</h1>
<div class="govuk-body"> <div class="govuk-body">
Here’s a list of everything that you need to fix your spreadsheet. You can download the <%= govuk_link_to "specification", Forms::BulkUploadSales::PrepareYourFile.new(year: @bulk_upload.year).specification_path, target: "_blank" %> to help you fix the cells in your CSV file. Here’s a list of everything that you need to fix your spreadsheet. You can download the <%= govuk_link_to "specification", Forms::BulkUploadForm::PrepareYourFile.new(year: @bulk_upload.year, log_type: "sales").specification_path, target: "_blank" %> to help you fix the cells in your CSV file.
</div> </div>
<p class="govuk-!-font-size-19 govuk-!-margin-bottom-2"><strong>File name: </strong><%= @bulk_upload.filename %></p> <p class="govuk-!-font-size-19 govuk-!-margin-bottom-2"><strong>File name: </strong><%= @bulk_upload.filename %></p>

2
app/views/bulk_upload_sales_results/summary.html.erb

@ -6,7 +6,7 @@
<h1 class="govuk-heading-l">Fix <%= pluralize(@bulk_upload.bulk_upload_errors.count, "error") %> and upload file again</h1> <h1 class="govuk-heading-l">Fix <%= pluralize(@bulk_upload.bulk_upload_errors.count, "error") %> and upload file again</h1>
<p class="govuk-body"> <p class="govuk-body">
We could not create logs from your bulk upload because of the following errors. Download the <%= govuk_link_to "specification", Forms::BulkUploadSales::PrepareYourFile.new(year: @bulk_upload.year).specification_path, target: "_blank" %> to help you fix the cells in your CSV file. We could not create logs from your bulk upload because of the following errors. Download the <%= govuk_link_to "specification", Forms::BulkUploadForm::PrepareYourFile.new(year: @bulk_upload.year, log_type: "sales").specification_path, target: "_blank" %> to help you fix the cells in your CSV file.
</p> </p>
<p class="govuk-!-font-size-19 govuk-!-margin-bottom-2"><strong>File name: </strong><%= @bulk_upload.filename %></p> <p class="govuk-!-font-size-19 govuk-!-margin-bottom-2"><strong>File name: </strong><%= @bulk_upload.filename %></p>

4
config/environments/production.rb

@ -35,10 +35,10 @@ Rails.application.configure do
# Assume all access to the app is happening through a SSL-terminating reverse proxy. # Assume all access to the app is happening through a SSL-terminating reverse proxy.
# Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies. # Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies.
# config.assume_ssl = true config.assume_ssl = true
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
config.force_ssl = true # config.force_ssl = true
# Skip http-to-https redirect for the default health check endpoint. # Skip http-to-https redirect for the default health check endpoint.
# config.ssl_options = { redirect: { exclude: ->(request) { request.path == "/up" } } } # config.ssl_options = { redirect: { exclude: ->(request) { request.path == "/up" } } }

4
config/environments/review.rb

@ -39,6 +39,10 @@ Rails.application.configure do
# config.action_cable.url = 'wss://example.com/cable' # config.action_cable.url = 'wss://example.com/cable'
# config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]
# Assume all access to the app is happening through a SSL-terminating reverse proxy.
# Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies.
config.assume_ssl = true
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true # config.force_ssl = true

4
config/environments/staging.rb

@ -39,6 +39,10 @@ Rails.application.configure do
# config.action_cable.url = 'wss://example.com/cable' # config.action_cable.url = 'wss://example.com/cable'
# config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ]
# Assume all access to the app is happening through a SSL-terminating reverse proxy.
# Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies.
config.assume_ssl = true
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true # config.force_ssl = true

29
config/locales/en.yml

@ -61,45 +61,26 @@ en:
<<: *bulk_upload__row_parser__base <<: *bulk_upload__row_parser__base
bulk_upload/sales/year2023/row_parser: bulk_upload/sales/year2023/row_parser:
<<: *bulk_upload__row_parser__base <<: *bulk_upload__row_parser__base
forms/bulk_upload_lettings/year: forms/bulk_upload_form/year:
attributes: attributes:
year: year:
blank: "You must select a collection period to upload for." blank: "You must select a collection period to upload for."
forms/bulk_upload_sales/year: forms/bulk_upload_form/upload_your_file:
attributes:
year:
blank: "You must select a collection period to upload for."
forms/bulk_upload_lettings/upload_your_file:
attributes:
file:
blank: "Select which file to upload."
not_csv: "Your file must be in CSV format."
file_too_large: "File must be 10MB or less. Check your file and delete data that does not need to be uploaded."
forms/bulk_upload_sales/upload_your_file:
attributes: attributes:
file: file:
blank: "Select which file to upload." blank: "Select which file to upload."
not_csv: "Your file must be in CSV format." not_csv: "Your file must be in CSV format."
file_too_large: "File must be 10MB or less. Check your file and delete data that does not need to be uploaded." file_too_large: "File must be 10MB or less. Check your file and delete data that does not need to be uploaded."
forms/bulk_upload_lettings/needstype: forms/bulk_upload_form/needstype:
attributes: attributes:
needstype: needstype:
blank: "You must answer needs type." blank: "You must answer needs type."
forms/bulk_upload_lettings_resume/fix_choice: forms/bulk_upload_resume/fix_choice:
attributes: attributes:
choice: choice:
blank: "Select how you would like to fix these errors." blank: "Select how you would like to fix these errors."
inclusion: "You must select one of the following options for how you would like to fix these errors." inclusion: "You must select one of the following options for how you would like to fix these errors."
forms/bulk_upload_sales_resume/fix_choice: forms/bulk_upload_soft_validations_check/confirm_soft_errors:
attributes:
choice:
blank: "Select how you would like to fix these errors."
inclusion: "You must select one of the following options for how you would like to fix these errors."
forms/bulk_upload_lettings_soft_validations_check/confirm_soft_errors:
attributes:
confirm_soft_errors:
blank: "You must select if there are errors in these fields."
forms/bulk_upload_sales_soft_validations_check/confirm_soft_errors:
attributes: attributes:
confirm_soft_errors: confirm_soft_errors:
blank: "You must select if there are errors in these fields." blank: "You must select if there are errors in these fields."

14
config/routes.rb

@ -389,15 +389,19 @@ Rails.application.routes.draw do
end end
end end
get "create-test-lettings-log", to: "lettings_logs#create_test_log"
get "create-test-sales-log", to: "sales_logs#create_test_log"
get "create-setup-test-lettings-log", to: "lettings_logs#create_setup_test_log"
get "create-setup-test-sales-log", to: "sales_logs#create_setup_test_log"
scope via: :all do scope via: :all do
match "/404", to: "errors#not_found" match "/404", to: "errors#not_found"
match "/429", to: "errors#too_many_requests", status: 429 match "/429", to: "errors#too_many_requests", status: 429
match "/422", to: "errors#unprocessable_entity" match "/422", to: "errors#unprocessable_entity"
match "/500", to: "errors#internal_server_error" match "/500", to: "errors#internal_server_error"
end end
if FeatureToggle.create_test_logs_enabled?
get "create-test-lettings-log", to: "test_data#create_test_lettings_log"
get "create-setup-test-lettings-log", to: "test_data#create_setup_test_lettings_log"
get "create-2024-test-lettings-bulk-upload", to: "test_data#create_2024_test_lettings_bulk_upload"
get "create-test-sales-log", to: "test_data#create_test_sales_log"
get "create-setup-test-sales-log", to: "test_data#create_setup_test_sales_log"
get "create-2024-test-sales-bulk-upload", to: "test_data#create_2024_test_sales_bulk_upload"
end
end end

2
docker-compose.yml

@ -5,7 +5,7 @@ volumes:
services: services:
db: db:
image: postgres:13.5-alpine image: postgres:13.18-alpine
restart: always restart: always
# To preserve data between runs of docker-compose, we mount a folder from the host machine. # To preserve data between runs of docker-compose, we mount a folder from the host machine.
volumes: volumes:

20
lib/tasks/clear_invalid_benefits.rake

@ -0,0 +1,20 @@
desc "clear benefit value for logs that would trigger the validation"
task clear_invalid_benefits: :environment do
validation_trigger_condition = "ecstat1 = 1 OR ecstat1 = 2 OR (ecstat2 = 1 AND relat2 = 'P') OR (ecstat2 = 2 AND relat2 = 'P') OR (ecstat3 = 1 AND relat3 = 'P') OR (ecstat3 = 2 AND relat3 = 'P') OR (ecstat4 = 1 AND relat4 = 'P') OR (ecstat4 = 2 AND relat4 = 'P') OR (ecstat5 = 1 AND relat5 = 'P') OR (ecstat5 = 2 AND relat5 = 'P') OR (ecstat6 = 1 AND relat6 = 'P') OR (ecstat6 = 2 AND relat6 = 'P') OR (ecstat7 = 1 AND relat7 = 'P') OR (ecstat7 = 2 AND relat7 = 'P') OR (ecstat8 = 1 AND relat8 = 'P') OR (ecstat8 = 2 AND relat8 = 'P')"
LettingsLog.filter_by_year(2024).where(status: "pending", status_cache: "completed", benefits: 1).where(validation_trigger_condition).find_each do |log|
log.benefits = nil
log.status_cache = log.calculate_status
log.skip_update_status = true
unless log.save
Rails.logger.info "Could not save changes to pending lettings log #{log.id}"
end
end
LettingsLog.filter_by_year(2024).visible.where(benefits: 1).where(validation_trigger_condition).find_each do |log|
log.benefits = nil
unless log.save
Rails.logger.info "Could not save changes to lettings log #{log.id}"
end
end
end

8
spec/features/bulk_upload_lettings_logs_spec.rb

@ -55,13 +55,13 @@ RSpec.describe "Bulk upload lettings log" do
expect(page).to have_content("Upload your file") expect(page).to have_content("Upload your file")
click_button("Upload") click_button("Upload")
allow_any_instance_of(Forms::BulkUploadLettings::UploadYourFile).to receive(:`).and_return("not a csv") allow_any_instance_of(Forms::BulkUploadForm::UploadYourFile).to receive(:`).and_return("not a csv")
expect(page).to have_content("Select which file to upload") expect(page).to have_content("Select which file to upload")
attach_file "file", file_fixture("2023_24_lettings_bulk_upload.xlsx") attach_file "file", file_fixture("2023_24_lettings_bulk_upload.xlsx")
click_button("Upload") click_button("Upload")
allow_any_instance_of(Forms::BulkUploadLettings::UploadYourFile).to receive(:`).and_return("text/csv") allow_any_instance_of(Forms::BulkUploadForm::UploadYourFile).to receive(:`).and_return("text/csv")
expect(page).to have_content("Your file must be in CSV format") expect(page).to have_content("Your file must be in CSV format")
attach_file "file", file_fixture("blank_bulk_upload_sales.csv") attach_file "file", file_fixture("blank_bulk_upload_sales.csv")
@ -76,7 +76,7 @@ RSpec.describe "Bulk upload lettings log" do
end end
it "shows file to large error" do it "shows file to large error" do
stub_const("Forms::BulkUploadLettings::UploadYourFile::MAX_FILE_SIZE", 1.bytes) stub_const("Forms::BulkUploadForm::UploadYourFile::MAX_FILE_SIZE", 1.bytes)
visit("/lettings-logs") visit("/lettings-logs")
click_link("Upload lettings logs in bulk") click_link("Upload lettings logs in bulk")
@ -86,7 +86,7 @@ RSpec.describe "Bulk upload lettings log" do
click_button("Continue") click_button("Continue")
click_button("Continue") click_button("Continue")
allow_any_instance_of(Forms::BulkUploadLettings::UploadYourFile).to receive(:`).and_return("text/csv") allow_any_instance_of(Forms::BulkUploadForm::UploadYourFile).to receive(:`).and_return("text/csv")
attach_file "file", file_fixture("2023_24_lettings_bulk_upload.xlsx") attach_file "file", file_fixture("2023_24_lettings_bulk_upload.xlsx")
click_button("Upload") click_button("Upload")

8
spec/features/bulk_upload_sales_logs_spec.rb

@ -52,13 +52,13 @@ RSpec.describe "Bulk upload sales log" do
expect(page).to have_content("Upload your file") expect(page).to have_content("Upload your file")
click_button("Upload") click_button("Upload")
allow_any_instance_of(Forms::BulkUploadSales::UploadYourFile).to receive(:`).and_return("not a csv") allow_any_instance_of(Forms::BulkUploadForm::UploadYourFile).to receive(:`).and_return("not a csv")
expect(page).to have_content("Select which file to upload") expect(page).to have_content("Select which file to upload")
attach_file "file", file_fixture("2023_24_lettings_bulk_upload.xlsx") attach_file "file", file_fixture("2023_24_lettings_bulk_upload.xlsx")
click_button("Upload") click_button("Upload")
allow_any_instance_of(Forms::BulkUploadSales::UploadYourFile).to receive(:`).and_return("text/csv") allow_any_instance_of(Forms::BulkUploadForm::UploadYourFile).to receive(:`).and_return("text/csv")
expect(page).to have_content("Your file must be in CSV format") expect(page).to have_content("Your file must be in CSV format")
attach_file "file", file_fixture("blank_bulk_upload_sales.csv") attach_file "file", file_fixture("blank_bulk_upload_sales.csv")
@ -73,7 +73,7 @@ RSpec.describe "Bulk upload sales log" do
end end
it "shows file to large error" do it "shows file to large error" do
stub_const("Forms::BulkUploadSales::UploadYourFile::MAX_FILE_SIZE", 1.bytes) stub_const("Forms::BulkUploadForm::UploadYourFile::MAX_FILE_SIZE", 1.bytes)
visit("/sales-logs") visit("/sales-logs")
click_link("Upload sales logs in bulk") click_link("Upload sales logs in bulk")
@ -84,7 +84,7 @@ RSpec.describe "Bulk upload sales log" do
click_button("Continue") click_button("Continue")
click_button("Continue") click_button("Continue")
allow_any_instance_of(Forms::BulkUploadSales::UploadYourFile).to receive(:`).and_return("text/csv") allow_any_instance_of(Forms::BulkUploadForm::UploadYourFile).to receive(:`).and_return("text/csv")
attach_file "file", file_fixture("2023_24_lettings_bulk_upload.xlsx") attach_file "file", file_fixture("2023_24_lettings_bulk_upload.xlsx")
click_button("Upload") click_button("Upload")

27
spec/features/lettings_log_spec.rb

@ -1018,6 +1018,33 @@ RSpec.describe "Lettings Log Features" do
end end
end end
context "and the user selects 'address_not_listed' when partial postcode is entered" do
before do
fill_in("lettings_log[address_line1_input]", with: "Address line 1")
fill_in("lettings_log[postcode_full_input]", with: "AA1")
click_button("Search")
choose "The address is not listed, I want to enter the address manually"
click_button("Save and continue")
end
it "sets correct address fields" do
lettings_log.reload
expect(lettings_log.uprn_known).to eq(0) # no
expect(lettings_log.uprn).to eq(nil)
expect(lettings_log.uprn_confirmed).to eq(nil)
expect(lettings_log.uprn_selection).to eq("uprn_not_listed")
expect(lettings_log.postcode_known).to eq(nil)
expect(lettings_log.postcode_full).to eq(nil)
expect(lettings_log.address_line1).to eq("Address line 1")
expect(lettings_log.address_line2).to eq(nil)
expect(lettings_log.town_or_city).to eq(nil)
expect(lettings_log.address_line1_input).to eq("Address line 1")
expect(lettings_log.postcode_full_input).to eq("AA1")
expect(lettings_log.address_search_value_check).to eq(nil)
expect(lettings_log.la).to eq(nil)
end
end
context "and the user selects 'address_not_listed' and then changes their mind and selects an address" do context "and the user selects 'address_not_listed' and then changes their mind and selects an address" do
before do before do
fill_in("lettings_log[address_line1_input]", with: "Address line 1") fill_in("lettings_log[address_line1_input]", with: "Address line 1")

27
spec/features/sales_log_spec.rb

@ -599,6 +599,33 @@ RSpec.describe "Sales Log Features" do
end end
end end
context "and the user selects 'address_not_listed' when partial postcode is given" do
before do
fill_in("sales_log[address_line1_input]", with: "Address line 1")
fill_in("sales_log[postcode_full_input]", with: "1AA")
click_button("Search")
choose "The address is not listed, I want to enter the address manually"
click_button("Save and continue")
end
it "sets correct address fields" do
sales_log.reload
expect(sales_log.uprn_known).to eq(0) # no
expect(sales_log.uprn).to eq(nil)
expect(sales_log.uprn_confirmed).to eq(nil)
expect(sales_log.uprn_selection).to eq("uprn_not_listed")
expect(sales_log.pcodenk).to eq(nil)
expect(sales_log.postcode_full).to eq(nil)
expect(sales_log.address_line1).to eq("Address line 1")
expect(sales_log.address_line2).to eq(nil)
expect(sales_log.town_or_city).to eq(nil)
expect(sales_log.address_line1_input).to eq("Address line 1")
expect(sales_log.postcode_full_input).to eq("1AA")
expect(sales_log.address_search_value_check).to eq(nil)
expect(sales_log.la).to eq(nil)
end
end
context "and the user selects 'address_not_listed' and then changes their mind and selects an address" do context "and the user selects 'address_not_listed' and then changes their mind and selects an address" do
before do before do
fill_in("sales_log[address_line1_input]", with: "Address line 1") fill_in("sales_log[address_line1_input]", with: "Address line 1")

95
spec/lib/tasks/clear_invalid_benefits_spec.rb

@ -0,0 +1,95 @@
require "rails_helper"
require "rake"
RSpec.describe "clear_invalid_benefits" do
describe ":clear_invalid_benefits", type: :task do
subject(:task) { Rake::Task["clear_invalid_benefits"] }
before do
Rake.application.rake_require("tasks/clear_invalid_benefits")
Rake::Task.define_task(:environment)
task.reenable
end
context "when the rake task is run" do
context "and there is a completed lettings log that trips the validation" do
let(:log) { build(:lettings_log, :completed, ecstat1: 1, benefits: 1, assigned_to: create(:user), period: nil) }
before do
log.status = "completed"
log.skip_update_status = true
log.save!(validate: false)
end
it "clear benefits and sets the log to in progress" do
expect(log.reload.benefits).to eq(1)
task.invoke
log.reload
expect(log.benefits).to eq(nil)
expect(log.status).to eq("in_progress")
end
end
context "and there is a lettings log that trips the validation for person 2" do
let(:log) { build(:lettings_log, :completed, ecstat2: 2, benefits: 1, relat2: "P", assigned_to: create(:user), period: nil) }
before do
log.status = "completed"
log.skip_update_status = true
log.save!(validate: false)
end
it "clear benefits and sets the log to in progress" do
expect(log.reload.benefits).to eq(1)
task.invoke
log.reload
expect(log.benefits).to eq(nil)
expect(log.status).to eq("in_progress")
end
end
context "and there is a lettings log that trips the validation for person 8" do
let(:log) { build(:lettings_log, :completed, ecstat8: 1, benefits: 1, relat8: "P", assigned_to: create(:user), period: nil) }
before do
log.status = "completed"
log.skip_update_status = true
log.save!(validate: false)
end
it "clear benefits and sets the log to in progress" do
expect(log.reload.benefits).to eq(1)
task.invoke
log.reload
expect(log.benefits).to eq(nil)
expect(log.status).to eq("in_progress")
end
end
context "and there is a pending lettings log that trips the validation" do
let(:log) { build(:lettings_log, :completed, ecstat1: 1, benefits: 1, assigned_to: create(:user), period: nil) }
before do
log.status = "pending"
log.status_cache = "completed"
log.skip_update_status = true
log.save!(validate: false)
end
it "clears benefits and updates the status cache" do
expect(log.reload.benefits).to eq(1)
task.invoke
log.reload
expect(log.benefits).to eq(nil)
expect(log.status_cache).to eq("in_progress")
end
it "does not change the log status" do
task.invoke
log.reload
expect(log.status).to eq("pending")
end
end
end
end
end

117
spec/models/forms/bulk_upload_form/guidance_spec.rb

@ -0,0 +1,117 @@
require "rails_helper"
RSpec.describe Forms::BulkUploadForm::Guidance do
include Rails.application.routes.url_helpers
subject(:bu_guidance) { described_class.new(year:, referrer:, log_type:) }
let(:year) { 2024 }
let(:log_type) { "sales" }
let(:referrer) { nil }
describe "sales" do
describe "#back_path" do
context "when referrer is prepare-your-file" do
let(:referrer) { "prepare-your-file" }
it "returns the prepare your file path" do
expect(bu_guidance.back_path).to eq bulk_upload_sales_log_path(id: "prepare-your-file", form: { year: })
end
end
context "when referrer is home" do
let(:referrer) { "home" }
it "returns the root path" do
expect(bu_guidance.back_path).to eq root_path
end
end
context "when referrer is guidance" do
let(:referrer) { "guidance" }
it "returns the main guidance page path" do
expect(bu_guidance.back_path).to eq guidance_path
end
end
context "when referrer is absent" do
let(:referrer) { nil }
it "returns the main guidance page path" do
expect(bu_guidance.back_path).to eq guidance_path
end
end
end
describe "year" do
context "when year is not provided" do
let(:year) { nil }
before do
# rubocop:disable RSpec/AnyInstance
allow_any_instance_of(CollectionTimeHelper).to receive(:current_collection_start_year).and_return(2030)
# rubocop:enable RSpec/AnyInstance
end
it "is set to the current collection start year" do
expect(bu_guidance.year).to eq(2030)
end
end
end
end
describe "lettings" do
let(:log_type) { "lettings" }
describe "#back_path" do
context "when referrer is prepare-your-file" do
let(:referrer) { "prepare-your-file" }
it "returns the prepare your file path" do
expect(bu_guidance.back_path).to eq bulk_upload_lettings_log_path(id: "prepare-your-file", form: { year: })
end
end
context "when referrer is home" do
let(:referrer) { "home" }
it "returns the root path" do
expect(bu_guidance.back_path).to eq root_path
end
end
context "when referrer is guidance" do
let(:referrer) { "guidance" }
it "returns the main guidance page path" do
expect(bu_guidance.back_path).to eq guidance_path
end
end
context "when referrer is absent" do
let(:referrer) { nil }
it "returns the main guidance page path" do
expect(bu_guidance.back_path).to eq guidance_path
end
end
end
describe "year" do
context "when year is not provided" do
let(:year) { nil }
before do
# rubocop:disable RSpec/AnyInstance
allow_any_instance_of(CollectionTimeHelper).to receive(:current_collection_start_year).and_return(2030)
# rubocop:enable RSpec/AnyInstance
end
it "is set to the current collection start year" do
expect(bu_guidance.year).to eq(2030)
end
end
end
end
end

100
spec/models/forms/bulk_upload_form/upload_your_file_spec.rb

@ -0,0 +1,100 @@
require "rails_helper"
RSpec.describe Forms::BulkUploadForm::UploadYourFile do
subject(:form) { described_class.new(year:, file:, current_user:, log_type:) }
let(:year) { 2022 }
let(:actual_file) { File.open(file_fixture("blank_bulk_upload_sales.csv")) }
let(:file) do
ActionDispatch::Http::UploadedFile.new(
tempfile: actual_file,
filename: "my-file.csv",
)
end
let(:current_user) { create(:user) }
let(:mock_storage_service) { instance_double("S3Service") }
before do
vcap_services = { "aws-s3-bucket" => {} }
allow(ENV).to receive(:[])
allow(ENV).to receive(:[]).with("VCAP_SERVICES").and_return(vcap_services.to_json)
allow(Storage::S3Service).to receive(:new).and_return(mock_storage_service)
allow(mock_storage_service).to receive(:write_file)
end
describe "lettings" do
let(:log_type) { "lettings" }
describe "#save" do
it "persists a BulkUpload" do
expect { form.save! }.to change(BulkUpload, :count).by(1)
end
it "persists a BulkUpload correctly" do
form.save!
bulk_upload = BulkUpload.last
expect(bulk_upload.user).to eql(current_user)
expect(bulk_upload.log_type).to eql("lettings")
expect(bulk_upload.year).to eql(year)
expect(bulk_upload.filename).to eql("my-file.csv")
expect(bulk_upload.identifier).to be_present
end
it "uploads file via storage service" do
form.save!
bulk_upload = BulkUpload.last
expect(Storage::S3Service).to have_received(:new)
expect(mock_storage_service).to have_received(:write_file).with(bulk_upload.identifier, actual_file.read)
end
it "enqueues job to process bulk upload" do
expect {
form.save!
}.to have_enqueued_job(ProcessBulkUploadJob)
end
end
end
describe "sales" do
let(:log_type) { "sales" }
describe "#save" do
it "persists a BulkUpload" do
expect { form.save! }.to change(BulkUpload, :count).by(1)
end
it "persists a BulkUpload correctly" do
form.save!
bulk_upload = BulkUpload.last
expect(bulk_upload.user).to eql(current_user)
expect(bulk_upload.log_type).to eql("sales")
expect(bulk_upload.year).to eql(year)
expect(bulk_upload.filename).to eql("my-file.csv")
expect(bulk_upload.identifier).to be_present
end
it "uploads file via storage service" do
form.save!
bulk_upload = BulkUpload.last
expect(Storage::S3Service).to have_received(:new)
expect(mock_storage_service).to have_received(:write_file).with(bulk_upload.identifier, actual_file.read)
end
it "enqueues job to process bulk upload" do
expect {
form.save!
}.to have_enqueued_job(ProcessBulkUploadJob)
end
end
end
end

101
spec/models/forms/bulk_upload_form/year_spec.rb

@ -0,0 +1,101 @@
require "rails_helper"
RSpec.describe Forms::BulkUploadForm::Year do
subject(:form) { described_class.new(log_type:) }
describe "lettings" do
let(:log_type) { "lettings" }
describe "#options" do
before do
allow(FormHandler.instance).to receive(:lettings_forms).and_return({ "current_lettings" => instance_double(Form, start_date: Time.zone.local(2024, 4, 1)) })
allow(FormHandler.instance).to receive(:previous_lettings_form).and_return(instance_double(Form, start_date: Time.zone.local(2023, 4, 1)))
allow(FormHandler.instance).to receive(:next_lettings_form).and_return(instance_double(Form, start_date: Time.zone.local(2025, 4, 1)))
end
context "when in a crossover period" do
before do
allow(FormHandler.instance).to receive(:lettings_in_crossover_period?).and_return(true)
end
it "returns current and previous years" do
expect(form.options.map(&:id)).to eql([2024, 2023])
expect(form.options.map(&:name)).to eql(["2024 to 2025", "2023 to 2024"])
end
end
context "when not in a crossover period" do
before do
allow(FormHandler.instance).to receive(:lettings_in_crossover_period?).and_return(false)
end
it "returns the current year" do
expect(form.options.map(&:id)).to eql([2024])
expect(form.options.map(&:name)).to eql(["2024 to 2025"])
end
end
context "when allow_future_form_use is toggled on" do
before do
allow(FormHandler.instance).to receive(:lettings_in_crossover_period?).and_return(false)
allow(FeatureToggle).to receive(:allow_future_form_use?).and_return(true)
end
it "returns current and next years" do
expect(form.options.map(&:id)).to eql([2024, 2025])
expect(form.options.map(&:name)).to eql(["2024 to 2025", "2025 to 2026"])
end
end
end
end
describe "sales" do
let(:log_type) { "sales" }
describe "#options" do
before do
allow(FormHandler.instance).to receive(:sales_forms).and_return({ "current_sales" => instance_double(Form, start_date: Time.zone.local(2024, 4, 1)) })
allow(FormHandler.instance).to receive(:previous_sales_form).and_return(instance_double(Form, start_date: Time.zone.local(2023, 4, 1)))
allow(FormHandler.instance).to receive(:next_sales_form).and_return(instance_double(Form, start_date: Time.zone.local(2025, 4, 1)))
end
context "when in a crossover period" do
before do
allow(FormHandler.instance).to receive(:sales_in_crossover_period?).and_return(true)
end
it "returns current and previous years" do
expect(form.options.map(&:id)).to eql([2024, 2023])
expect(form.options.map(&:name)).to eql(["2024 to 2025", "2023 to 2024"])
end
end
context "when not in a crossover period" do
before do
allow(FormHandler.instance).to receive(:sales_in_crossover_period?).and_return(false)
end
it "returns the current year" do
expect(form.options.map(&:id)).to eql([2024])
expect(form.options.map(&:name)).to eql(["2024 to 2025"])
end
end
context "when allow_future_form_use is toggled on" do
before do
allow(FormHandler.instance).to receive(:sales_in_crossover_period?).and_return(false)
allow(FeatureToggle).to receive(:allow_future_form_use?).and_return(true)
end
after do
Timecop.return
end
it "returns current and next years" do
expect(form.options.map(&:id)).to eql([2024, 2025])
expect(form.options.map(&:name)).to eql(["2024 to 2025", "2025 to 2026"])
end
end
end
end
end

60
spec/models/forms/bulk_upload_lettings/guidance_spec.rb

@ -1,60 +0,0 @@
require "rails_helper"
RSpec.describe Forms::BulkUploadLettings::Guidance do
include Rails.application.routes.url_helpers
subject(:bu_guidance) { described_class.new(year:, referrer:) }
let(:year) { 2024 }
let(:referrer) { nil }
describe "#back_path" do
context "when referrer is prepare-your-file" do
let(:referrer) { "prepare-your-file" }
it "returns the prepare your file path" do
expect(bu_guidance.back_path).to eq bulk_upload_lettings_log_path(id: "prepare-your-file", form: { year: })
end
end
context "when referrer is home" do
let(:referrer) { "home" }
it "returns the root path" do
expect(bu_guidance.back_path).to eq root_path
end
end
context "when referrer is guidance" do
let(:referrer) { "guidance" }
it "returns the main guidance page path" do
expect(bu_guidance.back_path).to eq guidance_path
end
end
context "when referrer is absent" do
let(:referrer) { nil }
it "returns the main guidance page path" do
expect(bu_guidance.back_path).to eq guidance_path
end
end
end
describe "year" do
context "when year is not provided" do
let(:year) { nil }
before do
# rubocop:disable RSpec/AnyInstance
allow_any_instance_of(CollectionTimeHelper).to receive(:current_collection_start_year).and_return(2030)
# rubocop:enable RSpec/AnyInstance
end
it "is set to the current collection start year" do
expect(bu_guidance.year).to eq(2030)
end
end
end
end

61
spec/models/forms/bulk_upload_lettings/upload_your_file_spec.rb

@ -1,61 +0,0 @@
require "rails_helper"
RSpec.describe Forms::BulkUploadLettings::UploadYourFile do
subject(:form) { described_class.new(year:, needstype:, file:, current_user:) }
let(:year) { 2022 }
let(:needstype) { 2 }
let(:actual_file) { File.open(file_fixture("blank_bulk_upload_sales.csv")) }
let(:file) do
ActionDispatch::Http::UploadedFile.new(
tempfile: actual_file,
filename: "my-file.csv",
)
end
let(:current_user) { create(:user) }
let(:mock_storage_service) { instance_double("S3Service") }
before do
vcap_services = { "aws-s3-bucket" => {} }
allow(ENV).to receive(:[])
allow(ENV).to receive(:[]).with("VCAP_SERVICES").and_return(vcap_services.to_json)
allow(Storage::S3Service).to receive(:new).and_return(mock_storage_service)
allow(mock_storage_service).to receive(:write_file)
end
describe "#save" do
it "persists a BulkUpload" do
expect { form.save! }.to change(BulkUpload, :count).by(1)
end
it "persists a BulkUpload correctly" do
form.save!
bulk_upload = BulkUpload.last
expect(bulk_upload.user).to eql(current_user)
expect(bulk_upload.log_type).to eql("lettings")
expect(bulk_upload.year).to eql(year)
expect(bulk_upload.needstype).to eql(needstype)
expect(bulk_upload.filename).to eql("my-file.csv")
expect(bulk_upload.identifier).to be_present
end
it "uploads file via storage service" do
form.save!
bulk_upload = BulkUpload.last
expect(Storage::S3Service).to have_received(:new)
expect(mock_storage_service).to have_received(:write_file).with(bulk_upload.identifier, actual_file.read)
end
it "enqueues job to process bulk upload" do
expect {
form.save!
}.to have_enqueued_job(ProcessBulkUploadJob)
end
end
end

47
spec/models/forms/bulk_upload_lettings/year_spec.rb

@ -1,47 +0,0 @@
require "rails_helper"
RSpec.describe Forms::BulkUploadLettings::Year do
subject(:form) { described_class.new }
describe "#options" do
before do
allow(FormHandler.instance).to receive(:lettings_forms).and_return({ "current_lettings" => instance_double(Form, start_date: Time.zone.local(2024, 4, 1)) })
allow(FormHandler.instance).to receive(:previous_lettings_form).and_return(instance_double(Form, start_date: Time.zone.local(2023, 4, 1)))
allow(FormHandler.instance).to receive(:next_lettings_form).and_return(instance_double(Form, start_date: Time.zone.local(2025, 4, 1)))
end
context "when in a crossover period" do
before do
allow(FormHandler.instance).to receive(:lettings_in_crossover_period?).and_return(true)
end
it "returns current and previous years" do
expect(form.options.map(&:id)).to eql([2024, 2023])
expect(form.options.map(&:name)).to eql(["2024 to 2025", "2023 to 2024"])
end
end
context "when not in a crossover period" do
before do
allow(FormHandler.instance).to receive(:lettings_in_crossover_period?).and_return(false)
end
it "returns the current year" do
expect(form.options.map(&:id)).to eql([2024])
expect(form.options.map(&:name)).to eql(["2024 to 2025"])
end
end
context "when allow_future_form_use is toggled on" do
before do
allow(FormHandler.instance).to receive(:lettings_in_crossover_period?).and_return(false)
allow(FeatureToggle).to receive(:allow_future_form_use?).and_return(true)
end
it "returns current and next years" do
expect(form.options.map(&:id)).to eql([2024, 2025])
expect(form.options.map(&:name)).to eql(["2024 to 2025", "2025 to 2026"])
end
end
end
end

60
spec/models/forms/bulk_upload_sales/guidance_spec.rb

@ -1,60 +0,0 @@
require "rails_helper"
RSpec.describe Forms::BulkUploadSales::Guidance do
include Rails.application.routes.url_helpers
subject(:bu_guidance) { described_class.new(year:, referrer:) }
let(:year) { 2024 }
let(:referrer) { nil }
describe "#back_path" do
context "when referrer is prepare-your-file" do
let(:referrer) { "prepare-your-file" }
it "returns the prepare your file path" do
expect(bu_guidance.back_path).to eq bulk_upload_sales_log_path(id: "prepare-your-file", form: { year: })
end
end
context "when referrer is home" do
let(:referrer) { "home" }
it "returns the root path" do
expect(bu_guidance.back_path).to eq root_path
end
end
context "when referrer is guidance" do
let(:referrer) { "guidance" }
it "returns the main guidance page path" do
expect(bu_guidance.back_path).to eq guidance_path
end
end
context "when referrer is absent" do
let(:referrer) { nil }
it "returns the main guidance page path" do
expect(bu_guidance.back_path).to eq guidance_path
end
end
end
describe "year" do
context "when year is not provided" do
let(:year) { nil }
before do
# rubocop:disable RSpec/AnyInstance
allow_any_instance_of(CollectionTimeHelper).to receive(:current_collection_start_year).and_return(2030)
# rubocop:enable RSpec/AnyInstance
end
it "is set to the current collection start year" do
expect(bu_guidance.year).to eq(2030)
end
end
end
end

59
spec/models/forms/bulk_upload_sales/upload_your_file_spec.rb

@ -1,59 +0,0 @@
require "rails_helper"
RSpec.describe Forms::BulkUploadSales::UploadYourFile do
subject(:form) { described_class.new(year:, file:, current_user:) }
let(:year) { 2022 }
let(:actual_file) { File.open(file_fixture("blank_bulk_upload_sales.csv")) }
let(:file) do
ActionDispatch::Http::UploadedFile.new(
tempfile: actual_file,
filename: "my-file.csv",
)
end
let(:current_user) { create(:user) }
let(:mock_storage_service) { instance_double("S3Service") }
before do
vcap_services = { "aws-s3-bucket" => {} }
allow(ENV).to receive(:[])
allow(ENV).to receive(:[]).with("VCAP_SERVICES").and_return(vcap_services.to_json)
allow(Storage::S3Service).to receive(:new).and_return(mock_storage_service)
allow(mock_storage_service).to receive(:write_file)
end
describe "#save" do
it "persists a BulkUpload" do
expect { form.save! }.to change(BulkUpload, :count).by(1)
end
it "persists a BulkUpload correctly" do
form.save!
bulk_upload = BulkUpload.last
expect(bulk_upload.user).to eql(current_user)
expect(bulk_upload.log_type).to eql("sales")
expect(bulk_upload.year).to eql(year)
expect(bulk_upload.filename).to eql("my-file.csv")
expect(bulk_upload.identifier).to be_present
end
it "uploads file via storage service" do
form.save!
bulk_upload = BulkUpload.last
expect(Storage::S3Service).to have_received(:new)
expect(mock_storage_service).to have_received(:write_file).with(bulk_upload.identifier, actual_file.read)
end
it "enqueues job to process bulk upload" do
expect {
form.save!
}.to have_enqueued_job(ProcessBulkUploadJob)
end
end
end

51
spec/models/forms/bulk_upload_sales/year_spec.rb

@ -1,51 +0,0 @@
require "rails_helper"
RSpec.describe Forms::BulkUploadSales::Year do
subject(:form) { described_class.new }
describe "#options" do
before do
allow(FormHandler.instance).to receive(:sales_forms).and_return({ "current_sales" => instance_double(Form, start_date: Time.zone.local(2024, 4, 1)) })
allow(FormHandler.instance).to receive(:previous_sales_form).and_return(instance_double(Form, start_date: Time.zone.local(2023, 4, 1)))
allow(FormHandler.instance).to receive(:next_sales_form).and_return(instance_double(Form, start_date: Time.zone.local(2025, 4, 1)))
end
context "when in a crossover period" do
before do
allow(FormHandler.instance).to receive(:sales_in_crossover_period?).and_return(true)
end
it "returns current and previous years" do
expect(form.options.map(&:id)).to eql([2024, 2023])
expect(form.options.map(&:name)).to eql(["2024 to 2025", "2023 to 2024"])
end
end
context "when not in a crossover period" do
before do
allow(FormHandler.instance).to receive(:sales_in_crossover_period?).and_return(false)
end
it "returns the current year" do
expect(form.options.map(&:id)).to eql([2024])
expect(form.options.map(&:name)).to eql(["2024 to 2025"])
end
end
context "when allow_future_form_use is toggled on" do
before do
allow(FormHandler.instance).to receive(:sales_in_crossover_period?).and_return(false)
allow(FeatureToggle).to receive(:allow_future_form_use?).and_return(true)
end
after do
Timecop.return
end
it "returns current and next years" do
expect(form.options.map(&:id)).to eql([2024, 2025])
expect(form.options.map(&:name)).to eql(["2024 to 2025", "2025 to 2026"])
end
end
end
end

14
spec/models/lettings_log_spec.rb

@ -861,19 +861,6 @@ RSpec.describe LettingsLog do
end end
end end
context "when startdate is before 2023" do
let(:lettings_log) { build(:lettings_log, startdate: Time.zone.parse("2022-07-01")) }
it "returns optional fields" do
expect(lettings_log.optional_fields).to eq(%w[
tenancycode
propcode
chcharge
tenancylength
])
end
end
context "when startdate is after 2023" do context "when startdate is after 2023" do
let(:lettings_log) { build(:lettings_log, startdate: Time.zone.parse("2023-07-01")) } let(:lettings_log) { build(:lettings_log, startdate: Time.zone.parse("2023-07-01")) }
@ -885,7 +872,6 @@ RSpec.describe LettingsLog do
tenancylength tenancylength
address_line2 address_line2
county county
postcode_full
]) ])
end end
end end

16
spec/models/sales_log_spec.rb

@ -76,21 +76,6 @@ RSpec.describe SalesLog, type: :model do
end end
describe "#optional_fields" do describe "#optional_fields" do
context "when saledate is before 2023" do
let(:sales_log) { build(:sales_log, saledate: Time.zone.parse("2022-07-01")) }
it "returns optional fields" do
expect(sales_log.optional_fields).to eq(%w[
purchid
othtype
buyers_organisations
proplen
mortlen
frombeds
])
end
end
context "when saledate is after 2023" do context "when saledate is after 2023" do
let(:sales_log) { build(:sales_log, saledate: Time.zone.parse("2023-07-01")) } let(:sales_log) { build(:sales_log, saledate: Time.zone.parse("2023-07-01")) }
@ -101,7 +86,6 @@ RSpec.describe SalesLog, type: :model do
buyers_organisations buyers_organisations
address_line2 address_line2
county county
postcode_full
]) ])
end end
end end

14
spec/models/validations/financial_validations_spec.rb

@ -36,36 +36,36 @@ RSpec.describe Validations::FinancialValidations do
describe "benefits proportion validations" do describe "benefits proportion validations" do
context "when the proportion is all" do context "when the proportion is all" do
it "validates that the lead tenant is not in full time employment" do it "validates that the lead tenant is not in full time employment" do
record.benefits = 0 record.benefits = 1
record.ecstat1 = 1 record.ecstat1 = 1
financial_validator.validate_net_income_uc_proportion(record) financial_validator.validate_net_income_uc_proportion(record)
expect(record.errors["benefits"]).to include(match I18n.t("validations.lettings.financial.benefits.part_or_full_time")) expect(record.errors["benefits"]).to include(match I18n.t("validations.lettings.financial.benefits.part_or_full_time"))
end end
it "validates that the lead tenant is not in part time employment" do it "validates that the lead tenant is not in part time employment" do
record.benefits = 0 record.benefits = 1
record.ecstat1 = 0 record.ecstat1 = 2
financial_validator.validate_net_income_uc_proportion(record) financial_validator.validate_net_income_uc_proportion(record)
expect(record.errors["benefits"]).to include(match I18n.t("validations.lettings.financial.benefits.part_or_full_time")) expect(record.errors["benefits"]).to include(match I18n.t("validations.lettings.financial.benefits.part_or_full_time"))
end end
it "expects that the lead tenant is not in full-time or part-time employment" do it "expects that the lead tenant is not in full-time or part-time employment" do
record.benefits = 0 record.benefits = 1
record.ecstat1 = 4 record.ecstat1 = 4
financial_validator.validate_net_income_uc_proportion(record) financial_validator.validate_net_income_uc_proportion(record)
expect(record.errors["benefits"]).to be_empty expect(record.errors["benefits"]).to be_empty
end end
it "validates that the tenant’s partner is not in full time employment" do it "validates that the tenant’s partner is not in full time employment" do
record.benefits = 0 record.benefits = 1
record.ecstat2 = 0 record.ecstat2 = 2
record.relat2 = "P" record.relat2 = "P"
financial_validator.validate_net_income_uc_proportion(record) financial_validator.validate_net_income_uc_proportion(record)
expect(record.errors["benefits"]).to include(match I18n.t("validations.lettings.financial.benefits.part_or_full_time")) expect(record.errors["benefits"]).to include(match I18n.t("validations.lettings.financial.benefits.part_or_full_time"))
end end
it "expects that the tenant’s partner is not in full-time or part-time employment" do it "expects that the tenant’s partner is not in full-time or part-time employment" do
record.benefits = 0 record.benefits = 1
record.ecstat2 = 4 record.ecstat2 = 4
record.relat2 = "P" record.relat2 = "P"
financial_validator.validate_net_income_uc_proportion(record) financial_validator.validate_net_income_uc_proportion(record)

31
spec/requests/form_controller_spec.rb

@ -744,6 +744,35 @@ RSpec.describe FormController, type: :request do
end end
end end
context "with invalid multiple question answers" do
let(:page) { Capybara::Node::Simple.new(response.body) }
let(:page_id) { "rent" }
let(:params) do
{
id: lettings_log.id,
lettings_log: {
page: page_id,
"period" => 10,
"supcharg" => 1_000_000,
},
}
end
before do
allow(Rails.logger).to receive(:info)
end
it "shows not answered and invalid answer errors at the same time" do
post "/lettings-logs/#{lettings_log.id}/#{page_id.dasherize}", params: params
follow_redirect!
expect(page).to have_content("There is a problem")
expect(page).to have_content("Support Charge must be between 0 and 300.")
expect(page).to have_content("You must answer basic rent.")
expect(page).to have_content("You must answer personal service charge.")
expect(page).to have_content("You must answer service charge.")
end
end
context "with invalid organisation answers" do context "with invalid organisation answers" do
let(:page) { Capybara::Node::Simple.new(response.body) } let(:page) { Capybara::Node::Simple.new(response.body) }
let(:managing_organisation) { create(:organisation) } let(:managing_organisation) { create(:organisation) }
@ -1681,7 +1710,7 @@ RSpec.describe FormController, type: :request do
end end
before do before do
completed_lettings_log.update!(ecstat1: 1, earnings: 130, hhmemb: 1) # we're not routing to that page, so it gets cleared? completed_lettings_log.update!(ecstat1: 1, earnings: 130, hhmemb: 1, benefits: 4) # we're not routing to that page, so it gets cleared?
allow(completed_lettings_log).to receive(:net_income_soft_validation_triggered?).and_return(true) allow(completed_lettings_log).to receive(:net_income_soft_validation_triggered?).and_return(true)
allow(completed_lettings_log.form).to receive(:new_logs_end_date).and_return(Time.zone.today + 1.day) allow(completed_lettings_log.form).to receive(:new_logs_end_date).and_return(Time.zone.today + 1.day)
allow(completed_lettings_log.form).to receive(:edit_end_date).and_return(Time.zone.today + 2.months) allow(completed_lettings_log.form).to receive(:edit_end_date).and_return(Time.zone.today + 2.months)

2
spec/services/bulk_upload/lettings/year2023/row_parser_spec.rb

@ -206,7 +206,7 @@ RSpec.describe BulkUpload::Lettings::Year2023::RowParser do
field_122: "2300", field_122: "2300",
field_121: "2", field_121: "2",
field_123: "1", field_123: "1",
field_124: "1", field_124: "4",
field_126: "4", field_126: "4",
field_128: "1234.56", field_128: "1234.56",

2
spec/services/bulk_upload/lettings/year2024/row_parser_spec.rb

@ -227,7 +227,7 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
field_118: "2", field_118: "2",
field_119: "2300", field_119: "2300",
field_120: "1", field_120: "1",
field_121: "1", field_121: "4",
field_123: "4", field_123: "4",
field_125: "1234.56", field_125: "1234.56",

Loading…
Cancel
Save