Browse Source

Merge remote-tracking branch 'origin/main' into CLDC-3218-bu-bug-rent-freq

pull/2249/head
natdeanlewissoftwire 2 years ago
parent
commit
23870f46d3
  1. 2
      Gemfile
  2. 339
      Gemfile.lock
  3. 2
      app/components/sales_log_summary_component.html.erb
  4. 2
      app/controllers/organisations_controller.rb
  5. 4
      app/helpers/collection_time_helper.rb
  6. 12
      app/helpers/filters_helper.rb
  7. 6
      app/jobs/scheme_email_csv_job.rb
  8. 1
      app/models/bulk_upload.rb
  9. 23
      app/models/form/lettings/pages/reasonother_value_check.rb
  10. 10
      app/models/form/lettings/pages/stock_owner.rb
  11. 2
      app/models/form/lettings/questions/person_working_situation.rb
  12. 14
      app/models/form/lettings/questions/reasonother_value_check.rb
  13. 6
      app/models/form/lettings/questions/stock_owner.rb
  14. 1
      app/models/form/lettings/subsections/household_situation.rb
  15. 18
      app/models/form/sales/pages/managing_organisation.rb
  16. 11
      app/models/form/sales/pages/owning_organisation.rb
  17. 2
      app/models/form/sales/questions/age1.rb
  18. 2
      app/models/form/sales/questions/buyer1_age_known.rb
  19. 2
      app/models/form/sales/questions/buyer1_working_situation.rb
  20. 2
      app/models/form/sales/questions/buyer2_working_situation.rb
  21. 9
      app/models/form/sales/questions/number_joint_buyers.rb
  22. 75
      app/models/form/sales/questions/owning_organisation_id.rb
  23. 2
      app/models/form/sales/questions/person_working_situation.rb
  24. 2
      app/models/form/sales/questions/property_number_of_bedrooms.rb
  25. 4
      app/models/form/sales/questions/property_wheelchair_accessible.rb
  26. 1
      app/models/log.rb
  27. 2
      app/models/user.rb
  28. 20
      app/models/validations/household_validations.rb
  29. 8
      app/models/validations/sales/soft_validations.rb
  30. 38
      app/models/validations/soft_validations.rb
  31. 21
      app/services/bulk_upload/lettings/year2023/row_parser.rb
  32. 20
      app/services/bulk_upload/lettings/year2024/row_parser.rb
  33. 1
      app/services/bulk_upload/sales/log_creator.rb
  34. 9
      app/services/bulk_upload/sales/validator.rb
  35. 7
      app/services/bulk_upload/sales/year2023/csv_parser.rb
  36. 6
      app/services/bulk_upload/sales/year2023/row_parser.rb
  37. 7
      app/services/bulk_upload/sales/year2024/csv_parser.rb
  38. 15
      app/services/bulk_upload/sales/year2024/row_parser.rb
  39. 2
      app/services/csv/lettings_log_csv_service.rb
  40. 8
      app/services/feature_toggle.rb
  41. 2
      app/views/logs/_log_filters.html.erb
  42. 4
      app/views/organisations/show.html.erb
  43. 2
      config/environments/development.rb
  44. 2
      config/environments/production.rb
  45. 2
      config/environments/review.rb
  46. 2
      config/environments/staging.rb
  47. 2
      config/environments/test.rb
  48. 7
      config/locales/en.yml
  49. 5
      db/migrate/20240209153215_add_reasonother_value_check_to_lettings_logs.rb
  50. 5
      db/migrate/20240216163519_add_no_int_fix_marker_to_bulk_uploads.rb
  51. 4
      db/schema.rb
  52. 24
      lib/tasks/correct_noint_value.rake
  53. 2
      package.json
  54. 1
      spec/factories/bulk_upload.rb
  55. 1
      spec/factories/lettings_log.rb
  56. 21
      spec/features/organisation_spec.rb
  57. 4
      spec/fixtures/files/lettings_log_csv_export_codes_23.csv
  58. 4
      spec/fixtures/files/lettings_log_csv_export_codes_24.csv
  59. 4
      spec/fixtures/files/lettings_log_csv_export_labels_23.csv
  60. 4
      spec/fixtures/files/lettings_log_csv_export_labels_24.csv
  61. 38
      spec/helpers/filters_helper_spec.rb
  62. 81
      spec/jobs/scheme_email_csv_job_spec.rb
  63. 87
      spec/lib/tasks/correct_noint_value_spec.rb
  64. 86
      spec/models/form/lettings/subsections/household_situation_spec.rb
  65. 154
      spec/models/form/sales/pages/managing_organisation_spec.rb
  66. 2
      spec/models/form/sales/questions/age1_spec.rb
  67. 2
      spec/models/form/sales/questions/buyer1_age_known_spec.rb
  68. 2
      spec/models/form/sales/questions/buyer1_working_situation_spec.rb
  69. 2
      spec/models/form/sales/questions/buyer2_working_situation_spec.rb
  70. 16
      spec/models/form/sales/questions/number_joint_buyers_spec.rb
  71. 2
      spec/models/form/sales/questions/person_working_situation_spec.rb
  72. 4
      spec/models/form/sales/questions/property_wheelchair_accessible_spec.rb
  73. 20
      spec/models/lettings_log_spec.rb
  74. 50
      spec/models/log_spec.rb
  75. 130
      spec/models/validations/household_validations_spec.rb
  76. 23
      spec/models/validations/sales/soft_validations_spec.rb
  77. 38
      spec/models/validations/soft_validations_spec.rb
  78. 14
      spec/requests/duplicate_logs_controller_spec.rb
  79. 24
      spec/requests/sales_logs_controller_spec.rb
  80. 105
      spec/services/bulk_upload/lettings/year2023/row_parser_spec.rb
  81. 59
      spec/services/bulk_upload/lettings/year2024/row_parser_spec.rb
  82. 4
      spec/services/bulk_upload/sales/year2023/csv_parser_spec.rb
  83. 18
      spec/services/bulk_upload/sales/year2023/row_parser_spec.rb
  84. 4
      spec/services/bulk_upload/sales/year2024/csv_parser_spec.rb
  85. 87
      spec/services/bulk_upload/sales/year2024/row_parser_spec.rb
  86. 8
      yarn.lock

2
Gemfile

@ -18,7 +18,7 @@ gem "jsbundling-rails"
# Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", ">= 1.4.4", require: false
# GOV UK frontend components
gem "govuk-components", "~> 5.0"
gem "govuk-components", "~> 5.1"
# GOV UK component form builder DSL
gem "govuk_design_system_formbuilder", "~> 5.0"
# Convert Markdown into GOV.UK frontend-styled HTML

339
Gemfile.lock

@ -1,134 +1,137 @@
GEM
remote: https://rubygems.org/
specs:
actioncable (7.0.7.2)
actionpack (= 7.0.7.2)
activesupport (= 7.0.7.2)
actioncable (7.0.8.1)
actionpack (= 7.0.8.1)
activesupport (= 7.0.8.1)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
actionmailbox (7.0.7.2)
actionpack (= 7.0.7.2)
activejob (= 7.0.7.2)
activerecord (= 7.0.7.2)
activestorage (= 7.0.7.2)
activesupport (= 7.0.7.2)
actionmailbox (7.0.8.1)
actionpack (= 7.0.8.1)
activejob (= 7.0.8.1)
activerecord (= 7.0.8.1)
activestorage (= 7.0.8.1)
activesupport (= 7.0.8.1)
mail (>= 2.7.1)
net-imap
net-pop
net-smtp
actionmailer (7.0.7.2)
actionpack (= 7.0.7.2)
actionview (= 7.0.7.2)
activejob (= 7.0.7.2)
activesupport (= 7.0.7.2)
actionmailer (7.0.8.1)
actionpack (= 7.0.8.1)
actionview (= 7.0.8.1)
activejob (= 7.0.8.1)
activesupport (= 7.0.8.1)
mail (~> 2.5, >= 2.5.4)
net-imap
net-pop
net-smtp
rails-dom-testing (~> 2.0)
actionpack (7.0.7.2)
actionview (= 7.0.7.2)
activesupport (= 7.0.7.2)
actionpack (7.0.8.1)
actionview (= 7.0.8.1)
activesupport (= 7.0.8.1)
rack (~> 2.0, >= 2.2.4)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.2.0)
actiontext (7.0.7.2)
actionpack (= 7.0.7.2)
activerecord (= 7.0.7.2)
activestorage (= 7.0.7.2)
activesupport (= 7.0.7.2)
actiontext (7.0.8.1)
actionpack (= 7.0.8.1)
activerecord (= 7.0.8.1)
activestorage (= 7.0.8.1)
activesupport (= 7.0.8.1)
globalid (>= 0.6.0)
nokogiri (>= 1.8.5)
actionview (7.0.7.2)
activesupport (= 7.0.7.2)
actionview (7.0.8.1)
activesupport (= 7.0.8.1)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.1, >= 1.2.0)
activejob (7.0.7.2)
activesupport (= 7.0.7.2)
activejob (7.0.8.1)
activesupport (= 7.0.8.1)
globalid (>= 0.3.6)
activemodel (7.0.7.2)
activesupport (= 7.0.7.2)
activerecord (7.0.7.2)
activemodel (= 7.0.7.2)
activesupport (= 7.0.7.2)
activestorage (7.0.7.2)
actionpack (= 7.0.7.2)
activejob (= 7.0.7.2)
activerecord (= 7.0.7.2)
activesupport (= 7.0.7.2)
activemodel (7.0.8.1)
activesupport (= 7.0.8.1)
activerecord (7.0.8.1)
activemodel (= 7.0.8.1)
activesupport (= 7.0.8.1)
activestorage (7.0.8.1)
actionpack (= 7.0.8.1)
activejob (= 7.0.8.1)
activerecord (= 7.0.8.1)
activesupport (= 7.0.8.1)
marcel (~> 1.0)
mini_mime (>= 1.1.0)
activesupport (7.0.7.2)
activesupport (7.0.8.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
addressable (2.8.1)
addressable (2.8.6)
public_suffix (>= 2.0.2, < 6.0)
ast (2.4.2)
auto_strip_attributes (2.6.0)
activerecord (>= 4.0)
aws-eventstream (1.2.0)
aws-partitions (1.714.0)
aws-sdk-core (3.170.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-eventstream (1.3.0)
aws-partitions (1.894.0)
aws-sdk-core (3.191.3)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.5)
aws-sigv4 (~> 1.8)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.62.0)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sdk-kms (1.77.0)
aws-sdk-core (~> 3, >= 3.191.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.119.1)
aws-sdk-core (~> 3, >= 3.165.0)
aws-sdk-s3 (1.143.0)
aws-sdk-core (~> 3, >= 3.191.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.4)
aws-sigv4 (1.5.2)
aws-sigv4 (~> 1.8)
aws-sigv4 (1.8.0)
aws-eventstream (~> 1, >= 1.0.2)
bcrypt (3.1.18)
better_html (2.0.1)
base64 (0.2.0)
bcrypt (3.1.20)
better_html (2.0.2)
actionview (>= 6.0)
activesupport (>= 6.0)
ast (~> 2.0)
erubi (~> 1.4)
parser (>= 2.4)
smart_properties
bigdecimal (3.1.6)
bindex (0.8.1)
bootsnap (1.16.0)
bootsnap (1.18.3)
msgpack (~> 1.2)
builder (3.2.4)
bundler-audit (0.9.1)
bundler (>= 1.2.0, < 3)
thor (~> 1.0)
byebug (11.1.3)
capybara (3.38.0)
capybara (3.40.0)
addressable
matrix
mini_mime (>= 0.1.3)
nokogiri (~> 1.8)
nokogiri (~> 1.11)
rack (>= 1.6.0)
rack-test (>= 0.6.3)
regexp_parser (>= 1.5, < 3.0)
xpath (~> 3.2)
capybara-lockstep (1.3.0)
activesupport (>= 3.2)
capybara (>= 2.0)
capybara-lockstep (2.2.0)
activesupport (>= 4.2)
capybara (>= 3.0)
ruby2_keywords
selenium-webdriver (>= 3)
selenium-webdriver (>= 4.0)
capybara-screenshot (1.0.26)
capybara (>= 1.0, < 4)
launchy
childprocess (4.1.0)
childprocess (5.0.0)
coderay (1.1.3)
concurrent-ruby (1.2.2)
concurrent-ruby (1.2.3)
connection_pool (2.4.1)
crack (0.4.5)
crack (1.0.0)
bigdecimal
rexml
crass (1.0.6)
date (3.3.3)
devise (4.8.1)
date (3.3.4)
devise (4.9.3)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0)
@ -140,14 +143,14 @@ GEM
rails (>= 3.1.1)
randexp
rotp (>= 4.0.0)
diff-lcs (1.5.0)
diff-lcs (1.5.1)
docile (1.4.0)
dotenv (2.8.1)
dotenv-rails (2.8.1)
dotenv (= 2.8.1)
railties (>= 3.2)
dotenv (3.0.2)
dotenv-rails (3.0.2)
dotenv (= 3.0.2)
railties (>= 6.1)
encryptor (3.0.0)
erb_lint (0.3.1)
erb_lint (0.5.0)
activesupport
better_html (>= 2.0.1)
parser (>= 2.7.1.4)
@ -157,47 +160,48 @@ GEM
erubi (1.12.0)
et-orbi (1.2.7)
tzinfo
excon (0.99.0)
factory_bot (6.2.1)
excon (0.109.0)
factory_bot (6.4.6)
activesupport (>= 5.0.0)
factory_bot_rails (6.2.0)
factory_bot (~> 6.2.0)
factory_bot_rails (6.4.3)
factory_bot (~> 6.4)
railties (>= 5.0.0)
faker (3.1.1)
faker (3.2.3)
i18n (>= 1.8.11, < 2)
ffi (1.15.5)
fugit (1.8.1)
ffi (1.16.3)
fugit (1.10.0)
et-orbi (~> 1, >= 1.2.7)
raabro (~> 1.4)
globalid (1.1.0)
activesupport (>= 5.0)
govuk-components (5.0.2)
globalid (1.2.1)
activesupport (>= 6.1)
govuk-components (5.2.1)
html-attributes-utils (~> 1.0.0, >= 1.0.0)
pagy (~> 6.0)
view_component (>= 3.9, < 3.10)
govuk_design_system_formbuilder (5.0.0)
view_component (>= 3.9, < 3.11)
govuk_design_system_formbuilder (5.2.0)
actionview (>= 6.1)
activemodel (>= 6.1)
activesupport (>= 6.1)
html-attributes-utils (~> 1)
govuk_markdown (2.0.0)
govuk_markdown (2.0.1)
activesupport
redcarpet
hashdiff (1.0.1)
hashdiff (1.1.0)
html-attributes-utils (1.0.2)
activesupport (>= 6.1.4.4)
i18n (1.14.1)
concurrent-ruby (~> 1.0)
iniparse (1.5.0)
jmespath (1.6.2)
jsbundling-rails (1.1.1)
jsbundling-rails (1.3.0)
railties (>= 6.0.0)
json-schema (3.0.0)
json-schema (4.1.1)
addressable (>= 2.8)
jwt (2.7.0)
jwt (2.8.0)
base64
launchy (2.5.2)
addressable (~> 2.8)
listen (3.8.0)
listen (3.9.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
loofah (2.22.0)
@ -212,16 +216,16 @@ GEM
matrix (0.4.2)
method_source (1.0.0)
mini_mime (1.1.5)
minitest (5.20.0)
msgpack (1.6.0)
net-imap (0.3.7)
minitest (5.22.2)
msgpack (1.7.2)
net-imap (0.4.10)
date
net-protocol
net-pop (0.1.2)
net-protocol
net-protocol (0.2.1)
net-protocol (0.2.2)
timeout
net-smtp (0.3.3)
net-smtp (0.4.0.1)
net-protocol
nio4r (2.7.0)
nokogiri (1.16.2-arm64-darwin)
@ -230,30 +234,31 @@ GEM
racc (~> 1.4)
nokogiri (1.16.2-x86_64-linux)
racc (~> 1.4)
notifications-ruby-client (5.4.0)
notifications-ruby-client (6.0.0)
jwt (>= 1.5, < 3)
orm_adapter (0.5.0)
overcommit (0.60.0)
childprocess (>= 0.6.3, < 5)
overcommit (0.63.0)
childprocess (>= 0.6.3, < 6)
iniparse (~> 1.4)
rexml (~> 3.2)
pagy (6.2.0)
paper_trail (14.0.0)
activerecord (>= 6.0)
pagy (6.5.0)
paper_trail (15.1.0)
activerecord (>= 6.1)
request_store (~> 1.4)
paper_trail-globalid (0.2.0)
globalid
paper_trail (>= 3.0.0)
parallel (1.22.1)
parallel_tests (4.2.0)
parallel (1.24.0)
parallel_tests (4.5.1)
parallel
parser (3.2.1.0)
parser (3.3.0.5)
ast (~> 2.4.1)
pg (1.4.5)
racc
pg (1.5.5)
possessive (1.0.1)
postcodes_io (0.4.0)
excon (~> 0.39)
propshaft (0.6.4)
propshaft (0.8.0)
actionpack (>= 7.0.0)
activesupport (>= 7.0.0)
rack
@ -264,34 +269,34 @@ GEM
pry-byebug (3.10.1)
byebug (~> 11.0)
pry (>= 0.13, < 0.15)
public_suffix (5.0.1)
public_suffix (5.0.4)
puma (5.6.8)
nio4r (~> 2.0)
pundit (2.3.0)
pundit (2.3.1)
activesupport (>= 3.0.0)
raabro (1.4.0)
racc (1.7.3)
rack (2.2.8)
rack-attack (6.6.1)
rack (>= 1.0, < 3)
rack (2.2.8.1)
rack-attack (6.7.0)
rack (>= 1.0, < 4)
rack-mini-profiler (2.3.4)
rack (>= 1.2.0)
rack-test (2.1.0)
rack (>= 1.3)
rails (7.0.7.2)
actioncable (= 7.0.7.2)
actionmailbox (= 7.0.7.2)
actionmailer (= 7.0.7.2)
actionpack (= 7.0.7.2)
actiontext (= 7.0.7.2)
actionview (= 7.0.7.2)
activejob (= 7.0.7.2)
activemodel (= 7.0.7.2)
activerecord (= 7.0.7.2)
activestorage (= 7.0.7.2)
activesupport (= 7.0.7.2)
rails (7.0.8.1)
actioncable (= 7.0.8.1)
actionmailbox (= 7.0.8.1)
actionmailer (= 7.0.8.1)
actionpack (= 7.0.8.1)
actiontext (= 7.0.8.1)
actionview (= 7.0.8.1)
activejob (= 7.0.8.1)
activemodel (= 7.0.8.1)
activerecord (= 7.0.8.1)
activestorage (= 7.0.8.1)
activesupport (= 7.0.8.1)
bundler (>= 1.15.0)
railties (= 7.0.7.2)
railties (= 7.0.8.1)
rails-dom-testing (2.2.0)
activesupport (>= 5.0.0)
minitest
@ -299,51 +304,51 @@ GEM
rails-html-sanitizer (1.6.0)
loofah (~> 2.21)
nokogiri (~> 1.14)
railties (7.0.7.2)
actionpack (= 7.0.7.2)
activesupport (= 7.0.7.2)
railties (7.0.8.1)
actionpack (= 7.0.8.1)
activesupport (= 7.0.8.1)
method_source
rake (>= 12.2)
thor (~> 1.0)
zeitwerk (~> 2.5)
rainbow (3.1.1)
rake (13.0.6)
rake (13.1.0)
randexp (0.1.7)
rb-fsevent (0.11.2)
rb-inotify (0.10.1)
ffi (~> 1.0)
redcarpet (3.6.0)
redis (4.8.1)
redis-client (0.17.0)
redis-client (0.20.0)
connection_pool
regexp_parser (2.7.0)
request_store (1.5.1)
regexp_parser (2.9.0)
request_store (1.6.0)
rack (>= 1.4)
responders (3.1.0)
responders (3.1.1)
actionpack (>= 5.2)
railties (>= 5.2)
rexml (3.2.5)
roo (2.10.0)
rexml (3.2.6)
roo (2.10.1)
nokogiri (~> 1)
rubyzip (>= 1.3.0, < 3.0.0)
rotp (6.2.2)
rspec-core (3.12.1)
rspec-support (~> 3.12.0)
rspec-expectations (3.12.2)
rotp (6.3.0)
rspec-core (3.13.0)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-mocks (3.12.3)
rspec-support (~> 3.13.0)
rspec-mocks (3.13.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-rails (6.0.1)
rspec-support (~> 3.13.0)
rspec-rails (6.1.1)
actionpack (>= 6.1)
activesupport (>= 6.1)
railties (>= 6.1)
rspec-core (~> 3.11)
rspec-expectations (~> 3.11)
rspec-mocks (~> 3.11)
rspec-support (~> 3.11)
rspec-support (3.12.0)
rspec-core (~> 3.12)
rspec-expectations (~> 3.12)
rspec-mocks (~> 3.12)
rspec-support (~> 3.12)
rspec-support (3.13.1)
rubocop (1.25.0)
parallel (~> 1.10)
parser (>= 3.1.0.0)
@ -361,7 +366,7 @@ GEM
rubocop-rails (= 2.13.2)
rubocop-rake (= 0.6.0)
rubocop-rspec (= 2.7.0)
rubocop-performance (1.16.0)
rubocop-performance (1.19.1)
rubocop (>= 1.7.0, < 2.0)
rubocop-ast (>= 0.4.0)
rubocop-rails (2.13.2)
@ -372,26 +377,28 @@ GEM
rubocop (~> 1.0)
rubocop-rspec (2.7.0)
rubocop (~> 1.19)
ruby-progressbar (1.11.0)
ruby-progressbar (1.13.0)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
selenium-webdriver (4.8.1)
selenium-webdriver (4.18.1)
base64 (~> 0.2)
rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2, < 3.0)
websocket (~> 1.0)
sentry-rails (5.8.0)
sentry-rails (5.16.1)
railties (>= 5.0)
sentry-ruby (~> 5.8.0)
sentry-ruby (5.8.0)
sentry-ruby (~> 5.16.1)
sentry-ruby (5.16.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
sidekiq (7.1.3)
sidekiq (7.2.2)
concurrent-ruby (< 2)
connection_pool (>= 2.3.0)
rack (>= 2.2.4)
redis-client (>= 0.14.0)
sidekiq-cron (1.9.1)
redis-client (>= 0.19.0)
sidekiq-cron (1.12.0)
fugit (~> 1.8)
sidekiq (>= 4.2.1)
globalid (>= 1.0.1)
sidekiq (>= 6)
simplecov (0.22.0)
docile (~> 1.1)
simplecov-html (~> 0.11)
@ -399,39 +406,39 @@ GEM
simplecov-html (0.12.3)
simplecov_json_formatter (0.1.4)
smart_properties (1.17.0)
stimulus-rails (1.2.1)
stimulus-rails (1.3.3)
railties (>= 6.0.0)
thor (1.2.2)
timecop (0.9.6)
timeout (0.4.0)
thor (1.3.0)
timecop (0.9.8)
timeout (0.4.1)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
uk_postcode (2.1.8)
unicode-display_width (2.4.2)
unread (0.13.0)
unicode-display_width (2.5.0)
unread (0.13.1)
activerecord (>= 6.1)
view_component (3.9.0)
view_component (3.10.0)
activesupport (>= 5.2.0, < 8.0)
concurrent-ruby (~> 1.0)
method_source (~> 1.0)
warden (1.2.9)
rack (>= 2.0.9)
web-console (4.2.0)
web-console (4.2.1)
actionview (>= 6.0.0)
activemodel (>= 6.0.0)
bindex (>= 0.4.0)
railties (>= 6.0.0)
webmock (3.18.1)
webmock (3.23.0)
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
websocket (1.2.9)
websocket (1.2.10)
websocket-driver (0.7.6)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
xpath (3.2.0)
nokogiri (~> 1.8)
zeitwerk (2.6.11)
zeitwerk (2.6.13)
PLATFORMS
arm64-darwin-21
@ -458,7 +465,7 @@ DEPENDENCIES
erb_lint
factory_bot_rails
faker
govuk-components (~> 5.0)
govuk-components (~> 5.1)
govuk_design_system_formbuilder (~> 5.0)
govuk_markdown
jsbundling-rails

2
app/components/sales_log_summary_component.html.erb

@ -32,7 +32,7 @@
<dd class="app-metadata__definition"><%= log.owning_organisation&.name %></dd>
</div>
<% end %>
<% if log.managing_organisation && FeatureToggle.sales_managing_organisation_enabled? %>
<% if log.managing_organisation %>
<div class="app-metadata__item">
<dt class="app-metadata__term">Reported by</dt>
<dd class="app-metadata__definition"><%= log.managing_organisation&.name %></dd>

2
app/controllers/organisations_controller.rb

@ -33,7 +33,7 @@ class OrganisationsController < ApplicationController
organisation_schemes = Scheme.where(owning_organisation: [@organisation] + @organisation.parent_organisations)
unpaginated_filtered_schemes = filter_manager.filtered_schemes(organisation_schemes, search_term, session_filters)
render "schemes/download_csv", locals: { search_term:, post_path: email_csv_schemes_path, download_type: params[:download_type], schemes: unpaginated_filtered_schemes }
render "schemes/download_csv", locals: { search_term:, post_path: schemes_email_csv_organisation_path, download_type: params[:download_type], schemes: unpaginated_filtered_schemes }
end
def email_schemes_csv

4
app/helpers/collection_time_helper.rb

@ -46,6 +46,10 @@ module CollectionTimeHelper
current_collection_start_date - 1.year
end
def archived_collection_start_year
current_collection_start_year - 2
end
def quarter_for_date(date: Time.zone.now)
quarters = [
{ quarter: "Q3", cutoff_date: Time.zone.local(2024, 1, 12), start_date: Time.zone.local(2023, 10, 1), end_date: Time.zone.local(2023, 12, 31) },

12
app/helpers/filters_helper.rb

@ -1,4 +1,6 @@
module FiltersHelper
include CollectionTimeHelper
def filter_selected?(filter, value, filter_type)
return false unless session[session_name_for(filter_type)]
@ -93,7 +95,11 @@ module FiltersHelper
end
def collection_year_options
{ "2023": "2023/24", "2022": "2022/23", "2021": "2021/22" }
{
current_collection_start_year.to_s => year_combo(current_collection_start_year),
previous_collection_start_year.to_s => year_combo(previous_collection_start_year),
archived_collection_start_year.to_s => year_combo(archived_collection_start_year),
}
end
def filters_applied_text(filter_type)
@ -174,4 +180,8 @@ private
end
end
end
def year_combo(year)
"#{year}/#{year - 2000 + 1}"
end
end

6
app/jobs/scheme_email_csv_job.rb

@ -6,7 +6,11 @@ class SchemeEmailCsvJob < ApplicationJob
EXPIRATION_TIME = 24.hours.to_i
def perform(user, search_term = nil, filters = {}, all_orgs = false, organisation = nil, download_type = "combined") # rubocop:disable Style/OptionalBooleanParameter - sidekiq can't serialise named params
unfiltered_schemes = organisation.present? && user.support? ? Scheme.where(owning_organisation_id: organisation.id) : user.schemes
unfiltered_schemes = if organisation.present? && user.support?
Scheme.where(owning_organisation: [organisation] + organisation.parent_organisations)
else
user.schemes
end
filtered_schemes = FilterManager.filter_schemes(unfiltered_schemes, search_term, filters, all_orgs, user)
csv_string = Csv::SchemeCsvService.new(download_type:).prepare_csv(filtered_schemes)

1
app/models/bulk_upload.rb

@ -1,5 +1,6 @@
class BulkUpload < ApplicationRecord
enum log_type: { lettings: "lettings", sales: "sales" }
enum noint_fix_status: { not_applied: "not_applied", applied: "applied", not_needed: "not_needed" }
belongs_to :user

23
app/models/form/lettings/pages/reasonother_value_check.rb

@ -0,0 +1,23 @@
class Form::Lettings::Pages::ReasonotherValueCheck < ::Form::Page
def initialize(id, hsh, subsection)
super
@id = "reasonother_value_check"
@depends_on = [{ "reasonother_might_be_existing_category?" => true }]
@title_text = {
"translation" => "soft_validations.reasonother.title_text",
"arguments" => [{ "key" => "reasonother", "i18n_template" => "reasonother" }],
}
@informative_text = {
"translation" => "soft_validations.reasonother.informative_text",
"arguments" => [],
}
end
def questions
@questions ||= [Form::Lettings::Questions::ReasonotherValueCheck.new(nil, nil, self)]
end
def interruption_screen_question_ids
%w[reason reasonother]
end
end

10
app/models/form/lettings/pages/stock_owner.rb

@ -14,16 +14,10 @@ class Form::Lettings::Pages::StockOwner < ::Form::Page
return false unless current_user
return true if current_user.support?
stock_owners = if FeatureToggle.merge_organisations_enabled?
current_user.organisation.stock_owners + current_user.organisation.absorbed_organisations.where(holds_own_stock: true)
else
current_user.organisation.stock_owners
end
stock_owners = current_user.organisation.stock_owners + current_user.organisation.absorbed_organisations.where(holds_own_stock: true)
if current_user.organisation.holds_own_stock?
if FeatureToggle.merge_organisations_enabled? && current_user.organisation.absorbed_organisations.any?(&:holds_own_stock?)
return true
end
return true if current_user.organisation.absorbed_organisations.any?(&:holds_own_stock?)
return true if stock_owners.count >= 1
log.update!(owning_organisation: current_user.organisation)

2
app/models/form/lettings/questions/person_working_situation.rb

@ -12,8 +12,8 @@ class Form::Lettings::Questions::PersonWorkingSituation < ::Form::Question
end
ANSWER_OPTIONS = {
"2" => { "value" => "Part-time – Less than 30 hours" },
"1" => { "value" => "Full-time – 30 hours or more" },
"2" => { "value" => "Part-time – Less than 30 hours" },
"7" => { "value" => "Full-time student" },
"3" => { "value" => "In government training into work, such as New Deal" },
"4" => { "value" => "Jobseeker" },

14
app/models/form/lettings/questions/reasonother_value_check.rb

@ -0,0 +1,14 @@
class Form::Lettings::Questions::ReasonotherValueCheck < ::Form::Question
def initialize(id, hsh, page)
super
@id = "reasonother_value_check"
@check_answer_label = "Reason other confirmation"
@header = "Are you sure this doesn’t fit an existing category?"
@type = "interruption_screen"
@check_answers_card_number = 0
@answer_options = ANSWER_OPTIONS
@hidden_in_check_answers = { "depends_on" => [{ "reasonother_value_check" => 0 }, { "reasonother_value_check" => 1 }] }
end
ANSWER_OPTIONS = { "0" => { "value" => "Yes" }, "1" => { "value" => "No" } }.freeze
end

6
app/models/form/lettings/questions/stock_owner.rb

@ -67,11 +67,7 @@ class Form::Lettings::Questions::StockOwner < ::Form::Question
def hidden_in_check_answers?(_log, user = nil)
return false if user.support?
stock_owners = if FeatureToggle.merge_organisations_enabled?
user.organisation.stock_owners + user.organisation.absorbed_organisations.where(holds_own_stock: true)
else
user.organisation.stock_owners
end
stock_owners = user.organisation.stock_owners + user.organisation.absorbed_organisations.where(holds_own_stock: true)
if user.organisation.holds_own_stock?
stock_owners.count.zero?

1
app/models/form/lettings/subsections/household_situation.rb

@ -12,6 +12,7 @@ class Form::Lettings::Subsections::HouseholdSituation < ::Form::Subsection
Form::Lettings::Pages::TimeOnWaitingList.new(nil, nil, self),
Form::Lettings::Pages::ReasonForLeavingLastSettledHome.new(nil, nil, self),
Form::Lettings::Pages::ReasonForLeavingLastSettledHomeRenewal.new(nil, nil, self),
(Form::Lettings::Pages::ReasonotherValueCheck.new(nil, nil, self) if form.start_year_after_2024?),
Form::Lettings::Pages::PreviousHousingSituation.new(nil, nil, self),
Form::Lettings::Pages::PreviousHousingSituationRenewal.new(nil, nil, self),
Form::Lettings::Pages::Homelessness.new("homelessness", nil, self),

18
app/models/form/sales/pages/managing_organisation.rb

@ -12,10 +12,20 @@ class Form::Sales::Pages::ManagingOrganisation < ::Form::Page
def routed_to?(log, current_user)
return false unless current_user
return false unless current_user.support?
return false unless FeatureToggle.sales_managing_organisation_enabled?
return false unless log.owning_organisation
log.owning_organisation.managing_agents.count >= 1
if form.start_year_after_2024?
organisation = current_user.support? ? log.owning_organisation : current_user.organisation
return false unless organisation
return false if log.owning_organisation != organisation && !organisation.holds_own_stock?
return true unless organisation.holds_own_stock?
organisation.managing_agents.count >= 1
else
return false unless current_user.support?
return false unless log.owning_organisation
log.owning_organisation.managing_agents.count >= 1
end
end
end

11
app/models/form/sales/pages/owning_organisation.rb

@ -13,19 +13,12 @@ class Form::Sales::Pages::OwningOrganisation < ::Form::Page
def routed_to?(log, current_user)
return false unless current_user
return true if current_user.support?
return false unless FeatureToggle.sales_managing_organisation_enabled?
return true if has_multiple_stock_owners_with_own_stock?(current_user)
stock_owners = if FeatureToggle.merge_organisations_enabled?
current_user.organisation.stock_owners.where(holds_own_stock: true) + current_user.organisation.absorbed_organisations.where(holds_own_stock: true)
else
current_user.organisation.stock_owners.where(holds_own_stock: true)
end
stock_owners = current_user.organisation.stock_owners.where(holds_own_stock: true) + current_user.organisation.absorbed_organisations.where(holds_own_stock: true)
if current_user.organisation.holds_own_stock?
if FeatureToggle.merge_organisations_enabled? && current_user.organisation.absorbed_organisations.any?(&:holds_own_stock?)
return true
end
return true if current_user.organisation.absorbed_organisations.any?(&:holds_own_stock?)
return true if stock_owners.count >= 1
log.update!(owning_organisation: current_user.organisation)

2
app/models/form/sales/questions/age1.rb

@ -2,7 +2,7 @@ class Form::Sales::Questions::Age1 < ::Form::Question
def initialize(id, hsh, page)
super
@id = "age1"
@check_answer_label = "Lead buyer’s age"
@check_answer_label = "Buyer 1’s age"
@header = "Age"
@type = "numeric"
@width = 2

2
app/models/form/sales/questions/buyer1_age_known.rb

@ -2,7 +2,7 @@ class Form::Sales::Questions::Buyer1AgeKnown < ::Form::Question
def initialize(id, hsh, page)
super
@id = "age1_known"
@check_answer_label = "Lead buyer’s age"
@check_answer_label = "Buyer 1’s age"
@header = "Do you know buyer 1’s age?"
@type = "radio"
@answer_options = ANSWER_OPTIONS

2
app/models/form/sales/questions/buyer1_working_situation.rb

@ -18,8 +18,8 @@ class Form::Sales::Questions::Buyer1WorkingSituation < ::Form::Question
end
ANSWER_OPTIONS = {
"2" => { "value" => "Part-time - Less than 30 hours" },
"1" => { "value" => "Full-time - 30 hours or more" },
"2" => { "value" => "Part-time - Less than 30 hours" },
"3" => { "value" => "In government training into work, such as New Deal" },
"4" => { "value" => "Jobseeker" },
"6" => { "value" => "Not seeking work" },

2
app/models/form/sales/questions/buyer2_working_situation.rb

@ -17,8 +17,8 @@ class Form::Sales::Questions::Buyer2WorkingSituation < ::Form::Question
end
ANSWER_OPTIONS = {
"2" => { "value" => "Part-time - Less than 30 hours" },
"1" => { "value" => "Full-time - 30 hours or more" },
"2" => { "value" => "Part-time - Less than 30 hours" },
"3" => { "value" => "In government training into work, such as New Deal" },
"4" => { "value" => "Jobseeker" },
"6" => { "value" => "Not seeking work" },

9
app/models/form/sales/questions/number_joint_buyers.rb

@ -4,7 +4,6 @@ class Form::Sales::Questions::NumberJointBuyers < ::Form::Question
@id = "jointmore"
@check_answer_label = "More than 2 joint buyers"
@header = "Are there more than 2 joint buyers of this property?"
@hint_text = "You should still try to answer all questions even if the buyer wasn't interviewed in person"
@type = "radio"
@answer_options = ANSWER_OPTIONS
@question_number = 10
@ -15,4 +14,12 @@ class Form::Sales::Questions::NumberJointBuyers < ::Form::Question
"2" => { "value" => "No" },
"3" => { "value" => "Don’t know" },
}.freeze
def hint_text
if form.start_year_after_2024?
nil
else
"You should still try to answer all questions even if the buyer wasn't interviewed in person"
end
end
end

75
app/models/form/sales/questions/owning_organisation_id.rb

@ -14,7 +14,7 @@ class Form::Sales::Questions::OwningOrganisationId < ::Form::Question
return answer_opts unless user
return answer_opts unless log
if FeatureToggle.sales_managing_organisation_enabled? && !user.support?
unless user.support?
if log.owning_organisation_id.present?
answer_opts[log.owning_organisation.id] = log.owning_organisation.name
end
@ -28,43 +28,36 @@ class Form::Sales::Questions::OwningOrganisationId < ::Form::Question
end
end
if FeatureToggle.merge_organisations_enabled?
if log.owning_organisation_id.present?
answer_opts[log.owning_organisation.id] = log.owning_organisation.name
end
if log.owning_organisation_id.present?
answer_opts[log.owning_organisation.id] = log.owning_organisation.name
end
recently_absorbed_organisations = user.organisation.absorbed_organisations.merged_during_open_collection_period
if !user.support? && user.organisation.holds_own_stock?
answer_opts[user.organisation.id] = if recently_absorbed_organisations.exists? && user.organisation.available_from.present?
"#{user.organisation.name} (Your organisation, active as of #{user.organisation.available_from.to_fs(:govuk_date)})"
else
"#{user.organisation.name} (Your organisation)"
end
end
recently_absorbed_organisations = user.organisation.absorbed_organisations.merged_during_open_collection_period
if !user.support? && user.organisation.holds_own_stock?
answer_opts[user.organisation.id] = if recently_absorbed_organisations.exists? && user.organisation.available_from.present?
"#{user.organisation.name} (Your organisation, active as of #{user.organisation.available_from.to_fs(:govuk_date)})"
else
"#{user.organisation.name} (Your organisation)"
end
end
if user.support?
Organisation.where(holds_own_stock: true).find_each do |org|
if org.merge_date.present?
answer_opts[org.id] = "#{org.name} (inactive as of #{org.merge_date.to_fs(:govuk_date)})" if org.merge_date >= FormHandler.instance.start_date_of_earliest_open_for_editing_collection_period
elsif org.absorbed_organisations.merged_during_open_collection_period.exists? && org.available_from.present?
answer_opts[org.id] = "#{org.name} (active as of #{org.available_from.to_fs(:govuk_date)})"
else
answer_opts[org.id] = org.name
end
end
else
recently_absorbed_organisations.each do |absorbed_org|
answer_opts[absorbed_org.id] = merged_organisation_label(absorbed_org.name, absorbed_org.merge_date) if absorbed_org.holds_own_stock?
if user.support?
Organisation.where(holds_own_stock: true).find_each do |org|
if org.merge_date.present?
answer_opts[org.id] = "#{org.name} (inactive as of #{org.merge_date.to_fs(:govuk_date)})" if org.merge_date >= FormHandler.instance.start_date_of_earliest_open_for_editing_collection_period
elsif org.absorbed_organisations.merged_during_open_collection_period.exists? && org.available_from.present?
answer_opts[org.id] = "#{org.name} (active as of #{org.available_from.to_fs(:govuk_date)})"
else
answer_opts[org.id] = org.name
end
end
answer_opts
else
Organisation.select(:id, :name).each_with_object(answer_opts) do |organisation, hsh|
hsh[organisation.id] = organisation.name
hsh
recently_absorbed_organisations.each do |absorbed_org|
answer_opts[absorbed_org.id] = merged_organisation_label(absorbed_org.name, absorbed_org.merge_date) if absorbed_org.holds_own_stock?
end
end
answer_opts
end
def displayed_answer_options(log, user = nil)
@ -82,18 +75,14 @@ class Form::Sales::Questions::OwningOrganisationId < ::Form::Question
end
def hidden_in_check_answers?(_log, user = nil)
if FeatureToggle.merge_organisations_enabled?
return false if user.support?
return false if user.support?
stock_owners = user.organisation.stock_owners + user.organisation.absorbed_organisations.where(holds_own_stock: true)
stock_owners = user.organisation.stock_owners + user.organisation.absorbed_organisations.where(holds_own_stock: true)
if user.organisation.holds_own_stock?
stock_owners.count.zero?
else
stock_owners.count <= 1
end
if user.organisation.holds_own_stock?
stock_owners.count.zero?
else
!current_user.support?
stock_owners.count <= 1
end
end
@ -104,11 +93,7 @@ class Form::Sales::Questions::OwningOrganisationId < ::Form::Question
private
def selected_answer_option_is_derived?(_log)
if FeatureToggle.merge_organisations_enabled?
true
else
false
end
true
end
def merged_organisation_label(name, merge_date)

2
app/models/form/sales/questions/person_working_situation.rb

@ -16,8 +16,8 @@ class Form::Sales::Questions::PersonWorkingSituation < ::Form::Question
end
ANSWER_OPTIONS = {
"2" => { "value" => "Part-time - Less than 30 hours" },
"1" => { "value" => "Full-time - 30 hours or more" },
"2" => { "value" => "Part-time - Less than 30 hours" },
"3" => { "value" => "In government training into work, such as New Deal" },
"4" => { "value" => "Jobseeker" },
"6" => { "value" => "Not seeking work" },

2
app/models/form/sales/questions/property_number_of_bedrooms.rb

@ -6,7 +6,7 @@ class Form::Sales::Questions::PropertyNumberOfBedrooms < ::Form::Question
@header = "How many bedrooms does the property have?"
@hint_text = "A bedsit has 1 bedroom"
@type = "numeric"
@width = 10
@width = 2
@min = 1
@max = 9
@step = 1

4
app/models/form/sales/questions/property_wheelchair_accessible.rb

@ -2,8 +2,8 @@ class Form::Sales::Questions::PropertyWheelchairAccessible < ::Form::Question
def initialize(id, hsh, page)
super
@id = "wchair"
@check_answer_label = "Property build or adapted to wheelchair-user standards"
@header = "Is the property build or adapted to wheelchair-user standards?"
@check_answer_label = "Property built or adapted to wheelchair-user standards"
@header = "Is the property built or adapted to wheelchair-user standards?"
@type = "radio"
@answer_options = ANSWER_OPTIONS
@question_number = 17

1
app/models/log.rb

@ -179,6 +179,7 @@ class Log < ApplicationRecord
def blank_compound_invalid_non_setup_fields!
self.ppcodenk = nil if errors.attribute_names.include? :ppostcode_full
self.previous_la_known = nil if errors.attribute_names.include? :prevloc
if errors.of_kind?(:uprn, :uprn_error)
self.uprn_known = nil

2
app/models/user.rb

@ -113,7 +113,7 @@ class User < ApplicationRecord
if support?
Scheme.all
else
Scheme.filter_by_owning_organisation(organisation.absorbed_organisations + [organisation])
Scheme.filter_by_owning_organisation(organisation.absorbed_organisations + [organisation] + organisation.parent_organisations)
end
end

20
app/models/validations/household_validations.rb

@ -9,6 +9,20 @@ module Validations::HouseholdValidations
end
end
PHRASES_INDICATING_HOMELESSNESS = [
"Homeless",
"Homelessness",
"Temporary accommodation",
"Temp accommodation",
"TA",
"Sleeping rough",
"Rough sleeping",
].freeze
PHRASES_INDICATING_HOMELESSNESS_REGEX = Regexp.union(
PHRASES_INDICATING_HOMELESSNESS.map { |phrase| Regexp.new("\\A[^[:alpha:]]*#{phrase}[^[:alpha:]]*\\Z", Regexp::IGNORECASE) },
)
def validate_reason_for_leaving_last_settled_home(record)
if record.reason == 32 && record.underoccupation_benefitcap != 4
record.errors.add :underoccupation_benefitcap, I18n.t("validations.household.underoccupation_benefitcap.dont_know_required")
@ -20,6 +34,12 @@ module Validations::HouseholdValidations
record.errors.add :referral, I18n.t("validations.household.referral.reason_permanently_decanted")
record.errors.add :reason, I18n.t("validations.household.reason.not_internal_transfer")
end
return unless record.form.start_year_after_2024?
if record.reason == 20 && PHRASES_INDICATING_HOMELESSNESS_REGEX.match?(record.reasonother)
record.errors.add :reason, I18n.t("validations.household.reason.other_not_settled")
end
end
def validate_armed_forces(record)

8
app/models/validations/sales/soft_validations.rb

@ -89,9 +89,11 @@ module Validations::Sales::SoftValidations
return unless cashdis || !is_type_discount?
return unless deposit && value && equity
cash_discount = cashdis || 0
mortgage_value = mortgage || 0
mortgage_value + deposit + cash_discount != value * equity / 100
!within_tolerance?(mortgage_deposit_and_discount_total, value * equity / 100, 1)
end
def within_tolerance?(expected, actual, tolerance)
(expected - actual).abs <= tolerance
end
def mortgage_plus_deposit_less_than_discounted_value?

38
app/models/validations/soft_validations.rb

@ -150,6 +150,44 @@ module Validations::SoftValidations
weekly_supcharg > soft_max && weekly_supcharg <= hard_max
end
PHRASES_LIKELY_TO_INDICATE_EXISTING_REASON_CATEGORY = [
"Decant",
"Decanted",
"Refugee",
"Asylum",
"Ukraine",
"Ukrainian",
"Army",
"Military",
"Domestic Abuse",
"Domestic Violence",
"DA",
"DV",
"Relationship breakdown",
"Overcrowding",
"Overcrowded",
"Too small",
"More space",
"Bigger property",
"Damp",
"Mould",
"Fire",
"Repossession",
"Death",
"Deceased",
"Passed away",
"Prison",
"Hospital",
].freeze
PHRASES_LIKELY_TO_INDICATE_EXISTING_REASON_CATEGORY_REGEX = Regexp.union(
PHRASES_LIKELY_TO_INDICATE_EXISTING_REASON_CATEGORY.map { |phrase| Regexp.new("\\b[^[:alpha]]*#{phrase}[^[:alpha:]]*\\b", Regexp::IGNORECASE) },
)
def reasonother_might_be_existing_category?
PHRASES_LIKELY_TO_INDICATE_EXISTING_REASON_CATEGORY_REGEX.match?(reasonother)
end
private
def details_known_or_lead_tenant?(tenant_number)

21
app/services/bulk_upload/lettings/year2023/row_parser.rb

@ -391,6 +391,7 @@ class BulkUpload::Lettings::Year2023::RowParser
validate :validate_correct_intermediate_rent_type, on: :after_log, if: proc { renttype == :intermediate }
validate :validate_correct_affordable_rent_type, on: :after_log, if: proc { renttype == :affordable }
validate :validate_all_charges_given, on: :after_log, if: proc { is_carehome.zero? }
def self.question_for_field(field)
QUESTIONS[field]
@ -854,6 +855,20 @@ private
end
end
def validate_all_charges_given
return if supported_housing? && field_125 == 1
{ field_128: "basic rent",
field_129: "service charge",
field_130: "personal service charge",
field_131: "support charge",
field_132: "total charge" }.each do |field, charge|
if public_send(field.to_sym).blank?
errors.add(field, I18n.t("validations.financial.charges.missing_charges", question: charge))
end
end
end
def setup_question?(question)
log.form.setup_sections[0].subsections[0].questions.include?(question)
end
@ -1192,7 +1207,7 @@ private
attributes["supcharg"] = field_131
attributes["tcharge"] = field_132
attributes["chcharge"] = field_127
attributes["is_carehome"] = field_127.present? ? 1 : 0
attributes["is_carehome"] = is_carehome
attributes["household_charge"] = supported_housing? ? field_125 : nil
attributes["hbrentshortfall"] = field_133
attributes["tshortfall_known"] = tshortfall_known
@ -1574,4 +1589,8 @@ private
0
end
end
def is_carehome
field_127.present? ? 1 : 0
end
end

20
app/services/bulk_upload/lettings/year2024/row_parser.rb

@ -382,6 +382,7 @@ class BulkUpload::Lettings::Year2024::RowParser
validate :validate_uprn_exists_if_any_key_address_fields_are_blank, on: :after_log, unless: -> { supported_housing? }
validate :validate_incomplete_soft_validations, on: :after_log
validate :validate_all_charges_given, on: :after_log, if: proc { is_carehome.zero? }
def self.question_for_field(field)
QUESTIONS[field]
@ -810,6 +811,19 @@ private
end
end
def validate_all_charges_given
return if supported_housing? && field_125 == 1
{ field_125: "basic rent",
field_126: "service charge",
field_127: "personal service charge",
field_128: "support charge" }.each do |field, charge|
if public_send(field.to_sym).blank?
errors.add(field, I18n.t("validations.financial.charges.missing_charges", question: charge))
end
end
end
def setup_question?(question)
log.form.setup_sections[0].subsections[0].questions.include?(question)
end
@ -1152,7 +1166,7 @@ private
attributes["pscharge"] = field_127
attributes["supcharg"] = field_128
attributes["chcharge"] = field_124
attributes["is_carehome"] = field_124.present? ? 1 : 0
attributes["is_carehome"] = is_carehome
attributes["household_charge"] = supported_housing? ? field_122 : nil
attributes["hbrentshortfall"] = field_129
attributes["tshortfall_known"] = tshortfall_known
@ -1479,4 +1493,8 @@ private
12
end
def is_carehome
field_124.present? ? 1 : 0
end
end

1
app/services/bulk_upload/sales/log_creator.rb

@ -7,6 +7,7 @@ class BulkUpload::Sales::LogCreator
end
def call
@bulk_upload.update!(noint_fix_status: BulkUpload.noint_fix_statuses[:not_needed])
row_parsers.each do |row_parser|
row_parser.valid?

9
app/services/bulk_upload/sales/validator.rb

@ -5,6 +5,7 @@ class BulkUpload::Sales::Validator
attr_reader :bulk_upload, :path
validate :validate_file_not_empty
validate :validate_field_numbers_count
validate :validate_max_columns
validate :validate_missing_required_headers
validate :validate_correct_template
@ -166,6 +167,14 @@ private
if csv_parser.missing_required_headers?
errors.add :base, I18n.t("activemodel.errors.models.bulk_upload/sales/validator.attributes.base.no_headers", guidance_link: bulk_upload_sales_log_url(id: "guidance", form: { year: bulk_upload.year }, host: ENV["APP_HOST"], anchor: "using-the-bulk-upload-template"))
end
end
def validate_field_numbers_count
return if halt_validations?
unless csv_parser.correct_field_count?
errors.add(:base, :wrong_field_numbers_count)
halt_validations!
end
end

7
app/services/bulk_upload/sales/year2023/csv_parser.rb

@ -4,6 +4,7 @@ class BulkUpload::Sales::Year2023::CsvParser
include CollectionTimeHelper
MAX_COLUMNS = 142
FIELDS = 135
FORM_YEAR = 2023
attr_reader :path
@ -59,6 +60,12 @@ class BulkUpload::Sales::Year2023::CsvParser
false
end
def correct_field_count?
valid_field_numbers_count = field_numbers.count { |f| f != "field_blank" }
valid_field_numbers_count == FIELDS
end
private
def default_field_numbers

6
app/services/bulk_upload/sales/year2023/row_parser.rb

@ -455,12 +455,12 @@ class BulkUpload::Sales::Year2023::RowParser
validate :validate_owning_org_data_given, on: :after_log
validate :validate_owning_org_exists, on: :after_log
validate :validate_owning_org_owns_stock, on: :after_log if FeatureToggle.sales_managing_organisation_enabled?
validate :validate_owning_org_owns_stock, on: :after_log
validate :validate_owning_org_permitted, on: :after_log
validate :validate_created_by_exists, on: :after_log
validate :validate_created_by_related, on: :after_log
validate :validate_managing_org_related, on: :after_log if FeatureToggle.sales_managing_organisation_enabled?
validate :validate_managing_org_related, on: :after_log
validate :validate_relevant_collection_window, on: :after_log
validate :validate_incomplete_soft_validations, on: :after_log
@ -791,7 +791,7 @@ private
attributes["purchid"] = purchaser_code
attributes["saledate"] = saledate
attributes["noint"] = 2 if field_28 == 1
attributes["noint"] = field_28
attributes["age1_known"] = age1_known?
attributes["age1"] = field_30 if attributes["age1_known"]&.zero? && field_30&.match(/\A\d{1,3}\z|\AR\z/)

7
app/services/bulk_upload/sales/year2024/csv_parser.rb

@ -3,6 +3,7 @@ require "csv"
class BulkUpload::Sales::Year2024::CsvParser
include CollectionTimeHelper
FIELDS = 131
MAX_COLUMNS = 142
FORM_YEAR = 2024
@ -59,6 +60,12 @@ class BulkUpload::Sales::Year2024::CsvParser
!with_headers?
end
def correct_field_count?
valid_field_numbers_count = field_numbers.count { |f| f != "field_blank" }
valid_field_numbers_count == FIELDS
end
private
def default_field_numbers

15
app/services/bulk_upload/sales/year2024/row_parser.rb

@ -455,12 +455,12 @@ class BulkUpload::Sales::Year2024::RowParser
validate :validate_owning_org_data_given, on: :after_log
validate :validate_owning_org_exists, on: :after_log
validate :validate_owning_org_owns_stock, on: :after_log if FeatureToggle.sales_managing_organisation_enabled?
validate :validate_owning_org_owns_stock, on: :after_log
validate :validate_owning_org_permitted, on: :after_log
validate :validate_created_by_exists, on: :after_log
validate :validate_created_by_related, on: :after_log
validate :validate_managing_org_related, on: :after_log if FeatureToggle.sales_managing_organisation_enabled?
validate :validate_managing_org_related, on: :after_log
validate :validate_relevant_collection_window, on: :after_log
validate :validate_incomplete_soft_validations, on: :after_log
@ -732,6 +732,7 @@ private
discount: %i[field_116],
othtype: %i[field_12],
owning_organisation_id: %i[field_1],
managing_organisation_id: [:field_2],
created_by: %i[field_3],
hhregres: %i[field_72],
hhregresstill: %i[field_73],
@ -785,7 +786,7 @@ private
attributes["purchid"] = purchaser_code
attributes["saledate"] = saledate
attributes["noint"] = 2 if field_17 == 1
attributes["noint"] = field_17
attributes["age1_known"] = age1_known?
attributes["age1"] = field_31 if attributes["age1_known"]&.zero? && field_31&.match(/\A\d{1,3}\z|\AR\z/)
@ -1211,9 +1212,7 @@ private
end
def managing_organisation
return owning_organisation if created_by&.organisation&.absorbed_organisations&.include?(owning_organisation)
created_by&.organisation || bulk_upload.user.organisation
Organisation.find_by_id_on_multiple_fields(field_2)
end
def nationality_group(nationality_value)
@ -1228,8 +1227,8 @@ private
if owning_organisation && managing_organisation && !owning_organisation.can_be_managed_by?(organisation: managing_organisation)
block_log_creation!
if errors[:field_3].blank?
errors.add(:field_3, "This user belongs to an organisation that does not have a relationship with the owning organisation", category: :setup)
if errors[:field_2].blank?
errors.add(:field_2, "This organisation does not have a relationship with the owning organisation", category: :setup)
end
end
end

2
app/services/csv/lettings_log_csv_service.rb

@ -296,7 +296,7 @@ module Csv
"letting_allocation_unknown" => %w[letting_allocation_none],
}.freeze
SUPPORT_ONLY_ATTRIBUTES = %w[net_income_value_check first_time_property_let_as_social_housing postcode_known is_la_inferred totchild totelder totadult net_income_known previous_la_known is_previous_la_inferred age1_known age2_known age3_known age4_known age5_known age6_known age7_known age8_known details_known_2 details_known_3 details_known_4 details_known_5 details_known_6 details_known_7 details_known_8 wrent wscharge wpschrge wsupchrg wtcharge wtshortfall rent_value_check old_form_id old_id retirement_value_check tshortfall_known pregnancy_value_check hhtype new_old la prevloc updated_by_id bulk_upload_id uprn_confirmed].freeze
SUPPORT_ONLY_ATTRIBUTES = %w[net_income_value_check first_time_property_let_as_social_housing postcode_known is_la_inferred totchild totelder totadult net_income_known previous_la_known is_previous_la_inferred age1_known age2_known age3_known age4_known age5_known age6_known age7_known age8_known details_known_2 details_known_3 details_known_4 details_known_5 details_known_6 details_known_7 details_known_8 wrent wscharge wpschrge wsupchrg wtcharge wtshortfall rent_value_check old_form_id old_id retirement_value_check tshortfall_known pregnancy_value_check hhtype new_old la prevloc updated_by_id bulk_upload_id uprn_confirmed reasonother_value_check].freeze
def lettings_log_attributes
ordered_questions = FormHandler.instance.ordered_lettings_questions_for_all_years

8
app/services/feature_toggle.rb

@ -28,10 +28,6 @@ class FeatureToggle
false
end
def self.merge_organisations_enabled?
true
end
def self.deduplication_flow_enabled?
true
end
@ -47,8 +43,4 @@ class FeatureToggle
def self.service_moved?
false
end
def self.sales_managing_organisation_enabled?
true
end
end

2
app/views/logs/_log_filters.html.erb

@ -93,7 +93,7 @@
} %>
<% end %>
<% if (current_user.support? || non_support_with_managing_orgs?) && (user_or_org_lettings_path? || FeatureToggle.sales_managing_organisation_enabled?) %>
<% if current_user.support? || non_support_with_managing_orgs? %>
<%= render partial: "filters/radio_filter", locals: {
f:,
options: {

4
app/views/organisations/show.html.erb

@ -36,9 +36,7 @@
<% end %>
<%= data_sharing_agreement_row(organisation: @organisation, user: current_user, summary_list:) %>
<% end %>
<% if FeatureToggle.merge_organisations_enabled? %>
<p>To report a merge or update your organisation details, <%= govuk_link_to "contact the helpdesk", GlobalConstants::HELPDESK_URL %>.</p>
<% end %>
<p>To report a merge or update your organisation details, <%= govuk_link_to "contact the helpdesk", GlobalConstants::HELPDESK_URL %>.</p>
<%= render partial: "organisations/merged_organisation_details" %>
</div>
</div>

2
config/environments/development.rb

@ -82,7 +82,7 @@ Rails.application.configure do
# config.action_cable.disable_request_forgery_protection = true
# see https://discuss.rubyonrails.org/t/cve-2022-32224-possible-rce-escalation-bug-with-serialized-columns-in-active-record/81017
config.active_record.yaml_column_permitted_classes = [Time]
config.active_record.yaml_column_permitted_classes = [Time, BigDecimal]
config.active_job.queue_adapter = :inline
end

2
config/environments/production.rb

@ -130,7 +130,7 @@ Rails.application.configure do
# config.active_record.shard_resolver = ->(request) { Tenant.find_by!(host: request.host).shard }
# see https://discuss.rubyonrails.org/t/cve-2022-32224-possible-rce-escalation-bug-with-serialized-columns-in-active-record/81017
config.active_record.yaml_column_permitted_classes = [Time]
config.active_record.yaml_column_permitted_classes = [Time, BigDecimal]
# From https://github.com/paper-trail-gem/paper_trail/wiki/Setting-whodunnit-in-the-rails-console
console do

2
config/environments/review.rb

@ -126,5 +126,5 @@ Rails.application.configure do
# config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
# see https://discuss.rubyonrails.org/t/cve-2022-32224-possible-rce-escalation-bug-with-serialized-columns-in-active-record/81017
config.active_record.yaml_column_permitted_classes = [Time]
config.active_record.yaml_column_permitted_classes = [Time, BigDecimal]
end

2
config/environments/staging.rb

@ -126,5 +126,5 @@ Rails.application.configure do
# config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session
# see https://discuss.rubyonrails.org/t/cve-2022-32224-possible-rce-escalation-bug-with-serialized-columns-in-active-record/81017
config.active_record.yaml_column_permitted_classes = [Time]
config.active_record.yaml_column_permitted_classes = [Time, BigDecimal]
end

2
config/environments/test.rb

@ -64,7 +64,7 @@ Rails.application.configure do
Faker::Config.locale = "en-GB"
# see https://discuss.rubyonrails.org/t/cve-2022-32224-possible-rce-escalation-bug-with-serialized-columns-in-active-record/81017
config.active_record.yaml_column_permitted_classes = [Time]
config.active_record.yaml_column_permitted_classes = [Time, BigDecimal]
config.active_job.queue_adapter = :test
end

7
config/locales/en.yml

@ -418,6 +418,7 @@ en:
above_hard_max: "Rent is higher than the absolute maximum expected for a property of this type based on this period"
charges:
complete_1_of_3: "Answer either the ‘household rent and charges’ question or ‘is this accommodation a care home‘, or select ‘no’ for ‘does the household pay rent or charges for the accommodation?’"
missing_charges: "Please enter the %{question}. If there is no %{question}, please enter '0'."
tcharge:
under_10: "Enter a total charge that is at least £10.00 per week"
rent_period:
@ -543,6 +544,7 @@ en:
reason:
not_internal_transfer: "Answer cannot be ‘permanently decanted from another property owned by this landlord’ as you told us the source of referral for this tenancy was not an internal transfer"
renewal_reason_needed: 'The reason for leaving must be "End of assured shorthold tenancy - no fault" or "End of fixed term tenancy - no fault" if the letting is a renewal'
other_not_settled: "Please give the reason for the tenant leaving their last settled home. This is where they were living before they became homeless, were living in temporary accommodation or sleeping rough"
condition_effects:
no_choices: "You cannot answer this question as you told us nobody in the household has a physical or mental health condition (or other illness) expected to last 12 months or more"
postcode:
@ -740,6 +742,11 @@ Make sure these answers are correct."
deposit_and_mortgage:
title_text: "You told us the mortgage amount was %{mortgage}, the cash deposit was %{deposit} and the discount was %{discount}."
hint_text: "We would expect the mortgage amount and the deposit added together to be the same as the purchase price minus the discount."
reasonother:
title_text: "You told us that the tenant’s main reason for leaving their last settled home was %{reasonother}"
informative_text: "The reason you have entered looks very similar to one of the existing response categories.
Please check the categories and select the appropriate one.
If the existing categories are not suitable, please confirm here to move onto the next question."
devise:
email:

5
db/migrate/20240209153215_add_reasonother_value_check_to_lettings_logs.rb

@ -0,0 +1,5 @@
class AddReasonotherValueCheckToLettingsLogs < ActiveRecord::Migration[7.0]
def change
add_column :lettings_logs, :reasonother_value_check, :integer
end
end

5
db/migrate/20240216163519_add_no_int_fix_marker_to_bulk_uploads.rb

@ -0,0 +1,5 @@
class AddNoIntFixMarkerToBulkUploads < ActiveRecord::Migration[7.0]
def change
add_column :bulk_uploads, :noint_fix_status, :string, default: "not_applied"
end
end

4
db/schema.rb

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.0].define(version: 2024_01_30_084707) do
ActiveRecord::Schema[7.0].define(version: 2024_02_16_163519) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -41,6 +41,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_01_30_084707) do
t.integer "needstype"
t.text "choice"
t.integer "total_logs_count"
t.string "noint_fix_status", default: "not_applied"
t.index ["identifier"], name: "index_bulk_uploads_on_identifier", unique: true
t.index ["user_id"], name: "index_bulk_uploads_on_user_id"
end
@ -305,6 +306,7 @@ ActiveRecord::Schema[7.0].define(version: 2024_01_30_084707) do
t.integer "duplicate_set_id"
t.integer "nationality_all"
t.integer "nationality_all_group"
t.integer "reasonother_value_check"
t.integer "accessible_register"
t.index ["bulk_upload_id"], name: "index_lettings_logs_on_bulk_upload_id"
t.index ["created_by_id"], name: "index_lettings_logs_on_created_by_id"

24
lib/tasks/correct_noint_value.rake

@ -0,0 +1,24 @@
desc "Alter noint values for bulk uploaded sales logs where these have not been set in the service"
task correct_noint_value: :environment do
update_counts = {
in_progress: 0,
completed: 0,
pending: 0,
deleted: 0,
}
affected_uploads = BulkUpload.where(log_type: "sales", noint_fix_status: BulkUpload.noint_fix_statuses[:not_applied])
affected_uploads.each do |upload|
upload.logs.where(noint: 2).each do |log|
noint_at_upload = log.versions.length == 1 ? log.noint : log.versions.first.next.reify.noint
next unless noint_at_upload == 2
Rails.logger.info("Updating noint value on log #{log.id}, owning org #{log.owning_organisation_id}")
update_counts[log.status.to_sym] += 1
log.noint = 1
log.skip_update_status = true
log.save!
end
upload.update!(noint_fix_status: BulkUpload.noint_fix_statuses[:applied])
end
Rails.logger.info("Logs updated; #{update_counts}")
end

2
package.json

@ -20,7 +20,7 @@
"css-loader": "^6.7.1",
"custom-event-polyfill": "^1.0.7",
"file-loader": "^6.2.0",
"govuk-frontend": "5.0.0",
"govuk-frontend": "5.1.0",
"html5shiv": "^3.7.3",
"intersection-observer": "^0.12.0",
"mini-css-extract-plugin": "^2.6.0",

1
spec/factories/bulk_upload.rb

@ -8,6 +8,7 @@ FactoryBot.define do
identifier { SecureRandom.uuid }
sequence(:filename) { |n| "bulk-upload-#{n}.csv" }
needstype { 1 }
noint_fix_status { BulkUpload.noint_fix_statuses.values.sample }
trait(:sales) do
log_type { BulkUpload.log_types[:sales] }

1
spec/factories/lettings_log.rb

@ -10,6 +10,7 @@ FactoryBot.define do
renewal { 0 }
needstype { 1 }
rent_type { 1 }
declaration { 1 }
end
trait :in_progress do
status { 1 }

21
spec/features/organisation_spec.rb

@ -196,9 +196,9 @@ RSpec.describe "User Features" do
end
it "can filter lettings logs by year" do
check("years-2021-field")
check("years-2022-field")
click_button("Apply filters")
expect(page).to have_current_path("/organisations/#{org_id}/lettings-logs?years[]=&years[]=2021&status[]=&needstypes[]=&assigned_to=all&user=&owning_organisation_select=all&owning_organisation=&managing_organisation_select=all&managing_organisation=")
expect(page).to have_current_path("/organisations/#{org_id}/lettings-logs?years[]=&years[]=2022&status[]=&needstypes[]=&assigned_to=all&user=&owning_organisation_select=all&owning_organisation=&managing_organisation_select=all&managing_organisation=")
expect(page).not_to have_link first_log.id.to_s, href: "/lettings-logs/#{first_log.id}"
end
@ -241,9 +241,9 @@ RSpec.describe "User Features" do
organisation.sales_logs.map(&:id).each do |sales_log_id|
expect(page).to have_link sales_log_id.to_s, href: "/sales-logs/#{sales_log_id}"
end
check("years-2021-field")
check("years-2022-field")
click_button("Apply filters")
expect(page).to have_current_path("/organisations/#{org_id}/sales-logs?years[]=&years[]=2021&status[]=&assigned_to=all&user=&owning_organisation_select=all&owning_organisation=&managing_organisation_select=all&managing_organisation=")
expect(page).to have_current_path("/organisations/#{org_id}/sales-logs?years[]=&years[]=2022&status[]=&assigned_to=all&user=&owning_organisation_select=all&owning_organisation=&managing_organisation_select=all&managing_organisation=")
expect(page).not_to have_link first_log.id.to_s, href: "/sales-logs/#{first_log.id}"
end
end
@ -327,6 +327,19 @@ RSpec.describe "User Features" do
end
end
context "when viewing schemes for specific organisation" do
before do
create(:scheme, owning_organisation: organisation)
visit("/organisations/#{org_id}/schemes")
end
it "allows downloading schemes csv for the specific org" do
click_link("Download schemes (CSV)")
click_button("Send email")
expect(page).to have_current_path("/organisations/#{org_id}/schemes/csv-confirmation")
end
end
context "and the organisation does not hold housing stock" do
before do
organisation.update!(holds_own_stock: false)

4
spec/fixtures/files/lettings_log_csv_export_codes_23.csv vendored

@ -1,2 +1,2 @@
id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,declaration,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,nationality_all,national,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,letting_allocation_none,referral,referral_value_check,net_income_known,incref,earnings,incfreq,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate
,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2023-11-26T00:00:00+00:00,1,,,2023,DLUHC,DLUHC,1,7,0,2023-11-26,2,2,1,,2,HIJKLMN,ABCDEFG,1,0,,,fake address,,London,,NW9 5LL,false,Barnet,E09000003,0,2,6,2,2,7,1,1,3,2023-11-24,,,1,2023-11-25,,3,1,4,,2,,1,4,,1,4,0,0,2,35,,F,0,2,,13,0,0,P,32,M,6,1,R,-9,R,10,0,R,-9,R,10,,,,,,,,,,,,,,,,,,,,,1,4,1,2,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,2,7,4,,6,2,1,0,TN23 6LZ,1,false,Ashford,E07000105,1,0,1,0,0,0,0,0,1,,2,,0,0,268,1,,6,1,1,,0,2,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,1,0,12.0,6.0,,,,,,,,,,,,,,,,,,,,
id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,declaration,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,nationality_all,national,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,letting_allocation_none,referral,referral_value_check,net_income_known,incref,earnings,incfreq,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate
,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2023-11-26T00:00:00+00:00,1,,,2023,DLUHC,DLUHC,1,7,0,2023-11-26,2,2,1,,2,HIJKLMN,ABCDEFG,1,0,,,fake address,,London,,NW9 5LL,false,Barnet,E09000003,0,2,6,2,2,7,1,1,3,2023-11-24,,,1,2023-11-25,,3,1,4,,2,,1,4,,1,4,0,0,2,35,,F,0,2,,13,0,0,P,32,M,6,1,R,-9,R,10,0,R,-9,R,10,,,,,,,,,,,,,,,,,,,,,1,4,1,2,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,2,7,4,,,6,2,1,0,TN23 6LZ,1,false,Ashford,E07000105,1,0,1,0,0,0,0,0,1,,2,,0,0,268,1,,6,1,1,,0,2,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,1,0,12.0,6.0,,,,,,,,,,,,,,,,,,,,

1 id status duplicate_set_id created_by is_dpo created_at updated_by updated_at creation_method old_id old_form_id collection_start_year owning_organisation_name managing_organisation_name needstype lettype renewal startdate renttype renttype_detail irproduct irproduct_other lar tenancycode propcode postcode_known uprn_known uprn uprn_confirmed address_line1 address_line2 town_or_city county postcode_full is_la_inferred la_label la first_time_property_let_as_social_housing unitletas rsnvac newprop offered unittype_gn builtype wchair beds voiddate vacdays void_date_value_check majorrepairs mrcdate major_repairs_date_value_check joint startertenancy tenancy tenancyother tenancylength sheltered declaration hhmemb pregnancy_value_check refused hhtype totchild totelder totadult age1 retirement_value_check sex1 ethnic_group ethnic nationality_all national ecstat1 details_known_2 relat2 age2 sex2 ecstat2 details_known_3 relat3 age3 sex3 ecstat3 details_known_4 relat4 age4 sex4 ecstat4 details_known_5 relat5 age5 sex5 ecstat5 details_known_6 relat6 age6 sex6 ecstat6 details_known_7 relat7 age7 sex7 ecstat7 details_known_8 relat8 age8 sex8 ecstat8 armedforces leftreg reservist preg_occ housingneeds housingneeds_type housingneeds_a housingneeds_b housingneeds_c housingneeds_f housingneeds_g housingneeds_h housingneeds_other illness illness_type_4 illness_type_5 illness_type_2 illness_type_6 illness_type_7 illness_type_3 illness_type_9 illness_type_8 illness_type_1 illness_type_10 layear waityear reason reasonother reasonother_value_check prevten new_old homeless ppcodenk ppostcode_full previous_la_known is_previous_la_inferred prevloc_label prevloc reasonpref rp_homeless rp_insan_unsat rp_medwel rp_hardship rp_dontknow cbl cap chr letting_allocation_none referral referral_value_check net_income_known incref earnings incfreq net_income_value_check hb has_benefits benefits household_charge nocharge period is_carehome chcharge wchchrg carehome_charges_value_check brent wrent rent_value_check scharge wscharge pscharge wpschrge supcharg wsupchrg tcharge wtcharge scharge_value_check pscharge_value_check supcharg_value_check hbrentshortfall tshortfall_known tshortfall wtshortfall scheme_code scheme_service_name scheme_sensitive SCHTYPE scheme_registered_under_care_act scheme_owning_organisation_name scheme_primary_client_group scheme_has_other_client_group scheme_secondary_client_group scheme_support_type scheme_intended_stay scheme_created_at location_code location_postcode location_name location_units location_type_of_unit location_mobility_type location_local_authority location_startdate
2 completed s.port@jeemayle.com false 2023-11-26T00:00:00+00:00 2023-11-26T00:00:00+00:00 1 2023 DLUHC DLUHC 1 7 0 2023-11-26 2 2 1 2 HIJKLMN ABCDEFG 1 0 fake address London NW9 5LL false Barnet E09000003 0 2 6 2 2 7 1 1 3 2023-11-24 1 2023-11-25 3 1 4 2 1 4 1 4 0 0 2 35 F 0 2 13 0 0 P 32 M 6 1 R -9 R 10 0 R -9 R 10 1 4 1 2 1 0 1 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 2 7 4 6 2 1 0 TN23 6LZ 1 false Ashford E07000105 1 0 1 0 0 0 0 0 1 2 0 0 268 1 6 1 1 0 2 200.0 100.0 50.0 25.0 40.0 20.0 35.0 17.5 325.0 162.5 1 0 12.0 6.0

4
spec/fixtures/files/lettings_log_csv_export_codes_24.csv vendored

@ -1,2 +1,2 @@
id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,declaration,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,accessible_register,letting_allocation_none,referral,referral_value_check,net_income_known,incref,earnings,incfreq,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate
,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2024-04-01T00:00:00+01:00,1,,,2023,DLUHC,DLUHC,1,7,0,2023-11-26,2,2,1,,2,HIJKLMN,ABCDEFG,1,1,0,,,fake address,,London,,NW9 5LL,false,Barnet,E09000003,0,2,6,2,2,7,1,1,3,2023-11-24,,,1,2023-11-25,,3,1,4,,2,,4,,1,4,0,0,2,35,,F,0,2,13,,0,0,P,32,M,6,1,R,-9,R,10,0,R,-9,R,10,,,,,,,,,,,,,,,,,,,,,1,4,1,2,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,2,7,4,,6,2,1,0,TN23 6LZ,1,false,Ashford,E07000105,1,0,1,0,0,0,0,0,1,0,,2,,0,0,268,1,,6,1,1,,0,2,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,1,0,12.0,6.0,,,,,,,,,,,,,,,,,,,,
id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,declaration,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,accessible_register,letting_allocation_none,referral,referral_value_check,net_income_known,incref,earnings,incfreq,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate
,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2024-04-01T00:00:00+01:00,1,,,2023,DLUHC,DLUHC,1,7,0,2023-11-26,2,2,1,,2,HIJKLMN,ABCDEFG,1,1,0,,,fake address,,London,,NW9 5LL,false,Barnet,E09000003,0,2,6,2,2,7,1,1,3,2023-11-24,,,1,2023-11-25,,3,1,4,,2,,4,,1,4,0,0,2,35,,F,0,2,13,,0,0,P,32,M,6,1,R,-9,R,10,0,R,-9,R,10,,,,,,,,,,,,,,,,,,,,,1,4,1,2,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,2,7,4,,,6,2,1,0,TN23 6LZ,1,false,Ashford,E07000105,1,0,1,0,0,0,0,0,1,0,,2,,0,0,268,1,,6,1,1,,0,2,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,1,0,12.0,6.0,,,,,,,,,,,,,,,,,,,,

1 id status duplicate_set_id created_by is_dpo created_at updated_by updated_at creation_method old_id old_form_id collection_start_year owning_organisation_name managing_organisation_name needstype lettype renewal startdate renttype renttype_detail irproduct irproduct_other lar tenancycode propcode declaration postcode_known uprn_known uprn uprn_confirmed address_line1 address_line2 town_or_city county postcode_full is_la_inferred la_label la first_time_property_let_as_social_housing unitletas rsnvac newprop offered unittype_gn builtype wchair beds voiddate vacdays void_date_value_check majorrepairs mrcdate major_repairs_date_value_check joint startertenancy tenancy tenancyother tenancylength sheltered hhmemb pregnancy_value_check refused hhtype totchild totelder totadult age1 retirement_value_check sex1 ethnic_group ethnic national nationality_all ecstat1 details_known_2 relat2 age2 sex2 ecstat2 details_known_3 relat3 age3 sex3 ecstat3 details_known_4 relat4 age4 sex4 ecstat4 details_known_5 relat5 age5 sex5 ecstat5 details_known_6 relat6 age6 sex6 ecstat6 details_known_7 relat7 age7 sex7 ecstat7 details_known_8 relat8 age8 sex8 ecstat8 armedforces leftreg reservist preg_occ housingneeds housingneeds_type housingneeds_a housingneeds_b housingneeds_c housingneeds_f housingneeds_g housingneeds_h housingneeds_other illness illness_type_4 illness_type_5 illness_type_2 illness_type_6 illness_type_7 illness_type_3 illness_type_9 illness_type_8 illness_type_1 illness_type_10 layear waityear reason reasonother reasonother_value_check prevten new_old homeless ppcodenk ppostcode_full previous_la_known is_previous_la_inferred prevloc_label prevloc reasonpref rp_homeless rp_insan_unsat rp_medwel rp_hardship rp_dontknow cbl cap chr accessible_register letting_allocation_none referral referral_value_check net_income_known incref earnings incfreq net_income_value_check hb has_benefits benefits household_charge nocharge period is_carehome chcharge wchchrg carehome_charges_value_check brent wrent rent_value_check scharge wscharge pscharge wpschrge supcharg wsupchrg tcharge wtcharge scharge_value_check pscharge_value_check supcharg_value_check hbrentshortfall tshortfall_known tshortfall wtshortfall scheme_code scheme_service_name scheme_sensitive SCHTYPE scheme_registered_under_care_act scheme_owning_organisation_name scheme_primary_client_group scheme_has_other_client_group scheme_secondary_client_group scheme_support_type scheme_intended_stay scheme_created_at location_code location_postcode location_name location_units location_type_of_unit location_mobility_type location_local_authority location_startdate
2 completed s.port@jeemayle.com false 2023-11-26T00:00:00+00:00 2024-04-01T00:00:00+01:00 1 2023 DLUHC DLUHC 1 7 0 2023-11-26 2 2 1 2 HIJKLMN ABCDEFG 1 1 0 fake address London NW9 5LL false Barnet E09000003 0 2 6 2 2 7 1 1 3 2023-11-24 1 2023-11-25 3 1 4 2 4 1 4 0 0 2 35 F 0 2 13 0 0 P 32 M 6 1 R -9 R 10 0 R -9 R 10 1 4 1 2 1 0 1 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 2 7 4 6 2 1 0 TN23 6LZ 1 false Ashford E07000105 1 0 1 0 0 0 0 0 1 0 2 0 0 268 1 6 1 1 0 2 200.0 100.0 50.0 25.0 40.0 20.0 35.0 17.5 325.0 162.5 1 0 12.0 6.0

4
spec/fixtures/files/lettings_log_csv_export_labels_23.csv vendored

@ -1,2 +1,2 @@
id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,declaration,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,nationality_all,national,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,letting_allocation_none,referral,referral_value_check,net_income_known,incref,earnings,incfreq,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate
,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2023-11-26T00:00:00+00:00,single log,,,2023,DLUHC,DLUHC,General needs,Affordable rent general needs local authority,No,2023-11-26,Affordable Rent,Affordable Rent,Rent to Buy,,No,HIJKLMN,ABCDEFG,Yes,No,,,fake address,,London,,NW9 5LL,No,Barnet,E09000003,No,Affordable rent basis,Tenant abandoned property,No,2,House,Purpose built,Yes,3,2023-11-24,,,Yes,2023-11-25,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,Yes,4,,Yes,4,0,0,2,35,,Female,White,Irish,,Tenant prefers not to say,Other,Yes,Partner,32,Male,Not seeking work,No,Prefers not to say,Not known,Prefers not to say,Prefers not to say,Yes,Person prefers not to say,Not known,Person prefers not to say,Person prefers not to say,,,,,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,Yes,No,No,No,No,No,No,Yes,No,No,Yes,No,No,No,No,No,No,No,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,Other supported housing,2,No,Yes,TN23 6LZ,Yes,No,Ashford,E07000105,Yes,,Yes,,,,No,No,Yes,,Tenant applied directly (no referral or nomination),,Yes,No,268,Weekly,,Universal Credit housing element,Yes,All,,No,Every 2 weeks,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,Yes,Yes,12.0,6.0,,,,,,,,,,,,,,,,,,,,
id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,declaration,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,nationality_all,national,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,letting_allocation_none,referral,referral_value_check,net_income_known,incref,earnings,incfreq,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate
,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2023-11-26T00:00:00+00:00,single log,,,2023,DLUHC,DLUHC,General needs,Affordable rent general needs local authority,No,2023-11-26,Affordable Rent,Affordable Rent,Rent to Buy,,No,HIJKLMN,ABCDEFG,Yes,No,,,fake address,,London,,NW9 5LL,No,Barnet,E09000003,No,Affordable rent basis,Tenant abandoned property,No,2,House,Purpose built,Yes,3,2023-11-24,,,Yes,2023-11-25,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,Yes,4,,Yes,4,0,0,2,35,,Female,White,Irish,,Tenant prefers not to say,Other,Yes,Partner,32,Male,Not seeking work,No,Prefers not to say,Not known,Prefers not to say,Prefers not to say,Yes,Person prefers not to say,Not known,Person prefers not to say,Person prefers not to say,,,,,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,Yes,No,No,No,No,No,No,Yes,No,No,Yes,No,No,No,No,No,No,No,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,,Other supported housing,2,No,Yes,TN23 6LZ,Yes,No,Ashford,E07000105,Yes,,Yes,,,,No,No,Yes,,Tenant applied directly (no referral or nomination),,Yes,No,268,Weekly,,Universal Credit housing element,Yes,All,,No,Every 2 weeks,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,Yes,Yes,12.0,6.0,,,,,,,,,,,,,,,,,,,,

1 id status duplicate_set_id created_by is_dpo created_at updated_by updated_at creation_method old_id old_form_id collection_start_year owning_organisation_name managing_organisation_name needstype lettype renewal startdate renttype renttype_detail irproduct irproduct_other lar tenancycode propcode postcode_known uprn_known uprn uprn_confirmed address_line1 address_line2 town_or_city county postcode_full is_la_inferred la_label la first_time_property_let_as_social_housing unitletas rsnvac newprop offered unittype_gn builtype wchair beds voiddate vacdays void_date_value_check majorrepairs mrcdate major_repairs_date_value_check joint startertenancy tenancy tenancyother tenancylength sheltered declaration hhmemb pregnancy_value_check refused hhtype totchild totelder totadult age1 retirement_value_check sex1 ethnic_group ethnic nationality_all national ecstat1 details_known_2 relat2 age2 sex2 ecstat2 details_known_3 relat3 age3 sex3 ecstat3 details_known_4 relat4 age4 sex4 ecstat4 details_known_5 relat5 age5 sex5 ecstat5 details_known_6 relat6 age6 sex6 ecstat6 details_known_7 relat7 age7 sex7 ecstat7 details_known_8 relat8 age8 sex8 ecstat8 armedforces leftreg reservist preg_occ housingneeds housingneeds_type housingneeds_a housingneeds_b housingneeds_c housingneeds_f housingneeds_g housingneeds_h housingneeds_other illness illness_type_4 illness_type_5 illness_type_2 illness_type_6 illness_type_7 illness_type_3 illness_type_9 illness_type_8 illness_type_1 illness_type_10 layear waityear reason reasonother reasonother_value_check prevten new_old homeless ppcodenk ppostcode_full previous_la_known is_previous_la_inferred prevloc_label prevloc reasonpref rp_homeless rp_insan_unsat rp_medwel rp_hardship rp_dontknow cbl cap chr letting_allocation_none referral referral_value_check net_income_known incref earnings incfreq net_income_value_check hb has_benefits benefits household_charge nocharge period is_carehome chcharge wchchrg carehome_charges_value_check brent wrent rent_value_check scharge wscharge pscharge wpschrge supcharg wsupchrg tcharge wtcharge scharge_value_check pscharge_value_check supcharg_value_check hbrentshortfall tshortfall_known tshortfall wtshortfall scheme_code scheme_service_name scheme_sensitive SCHTYPE scheme_registered_under_care_act scheme_owning_organisation_name scheme_primary_client_group scheme_has_other_client_group scheme_secondary_client_group scheme_support_type scheme_intended_stay scheme_created_at location_code location_postcode location_name location_units location_type_of_unit location_mobility_type location_local_authority location_startdate
2 completed s.port@jeemayle.com false 2023-11-26T00:00:00+00:00 2023-11-26T00:00:00+00:00 single log 2023 DLUHC DLUHC General needs Affordable rent general needs local authority No 2023-11-26 Affordable Rent Affordable Rent Rent to Buy No HIJKLMN ABCDEFG Yes No fake address London NW9 5LL No Barnet E09000003 No Affordable rent basis Tenant abandoned property No 2 House Purpose built Yes 3 2023-11-24 Yes 2023-11-25 Don’t know Yes Assured Shorthold Tenancy (AST) – Fixed term 2 Yes 4 Yes 4 0 0 2 35 Female White Irish Tenant prefers not to say Other Yes Partner 32 Male Not seeking work No Prefers not to say Not known Prefers not to say Prefers not to say Yes Person prefers not to say Not known Person prefers not to say Person prefers not to say Yes – the person is a current or former regular No – they left up to and including 5 years ago Yes No Yes Fully wheelchair accessible housing Yes No No No No No No Yes No No Yes No No No No No No No Less than 1 year 1 year but under 2 years Loss of tied accommodation Other supported housing 2 No Yes TN23 6LZ Yes No Ashford E07000105 Yes Yes No No Yes Tenant applied directly (no referral or nomination) Yes No 268 Weekly Universal Credit housing element Yes All No Every 2 weeks 200.0 100.0 50.0 25.0 40.0 20.0 35.0 17.5 325.0 162.5 Yes Yes 12.0 6.0

4
spec/fixtures/files/lettings_log_csv_export_labels_24.csv vendored

@ -1,2 +1,2 @@
id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,declaration,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,accessible_register,letting_allocation_none,referral,referral_value_check,net_income_known,incref,earnings,incfreq,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate
,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2024-04-01T00:00:00+01:00,single log,,,2023,DLUHC,DLUHC,General needs,Affordable rent general needs local authority,No,2023-11-26,Affordable Rent,Affordable Rent,Rent to Buy,,No,HIJKLMN,ABCDEFG,Yes,Yes,No,,,fake address,,London,,NW9 5LL,No,Barnet,E09000003,No,Affordable rent basis,Tenant abandoned property,No,2,House,Purpose built,Yes,3,2023-11-24,,,Yes,2023-11-25,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,4,,Yes,4,0,0,2,35,,Female,White,Irish,Tenant prefers not to say,,Other,Yes,Partner,32,Male,Not seeking work,No,Prefers not to say,Not known,Prefers not to say,Prefers not to say,Yes,Person prefers not to say,Not known,Person prefers not to say,Person prefers not to say,,,,,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,Yes,No,No,No,No,No,No,Yes,No,No,Yes,No,No,No,No,No,No,No,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,Other supported housing,2,No,Yes,TN23 6LZ,Yes,No,Ashford,E07000105,Yes,,Yes,,,,No,No,Yes,No,,Tenant applied directly (no referral or nomination),,Yes,No,268,Weekly,,Universal Credit housing element,Yes,All,,No,Every 2 weeks,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,Yes,Yes,12.0,6.0,,,,,,,,,,,,,,,,,,,,
id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,declaration,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,details_known_2,relat2,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,accessible_register,letting_allocation_none,referral,referral_value_check,net_income_known,incref,earnings,incfreq,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate
,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2024-04-01T00:00:00+01:00,single log,,,2023,DLUHC,DLUHC,General needs,Affordable rent general needs local authority,No,2023-11-26,Affordable Rent,Affordable Rent,Rent to Buy,,No,HIJKLMN,ABCDEFG,Yes,Yes,No,,,fake address,,London,,NW9 5LL,No,Barnet,E09000003,No,Affordable rent basis,Tenant abandoned property,No,2,House,Purpose built,Yes,3,2023-11-24,,,Yes,2023-11-25,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,4,,Yes,4,0,0,2,35,,Female,White,Irish,Tenant prefers not to say,,Other,Yes,Partner,32,Male,Not seeking work,No,Prefers not to say,Not known,Prefers not to say,Prefers not to say,Yes,Person prefers not to say,Not known,Person prefers not to say,Person prefers not to say,,,,,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,Yes,No,No,No,No,No,No,Yes,No,No,Yes,No,No,No,No,No,No,No,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,,Other supported housing,2,No,Yes,TN23 6LZ,Yes,No,Ashford,E07000105,Yes,,Yes,,,,No,No,Yes,No,,Tenant applied directly (no referral or nomination),,Yes,No,268,Weekly,,Universal Credit housing element,Yes,All,,No,Every 2 weeks,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,Yes,Yes,12.0,6.0,,,,,,,,,,,,,,,,,,,,

1 id status duplicate_set_id created_by is_dpo created_at updated_by updated_at creation_method old_id old_form_id collection_start_year owning_organisation_name managing_organisation_name needstype lettype renewal startdate renttype renttype_detail irproduct irproduct_other lar tenancycode propcode declaration postcode_known uprn_known uprn uprn_confirmed address_line1 address_line2 town_or_city county postcode_full is_la_inferred la_label la first_time_property_let_as_social_housing unitletas rsnvac newprop offered unittype_gn builtype wchair beds voiddate vacdays void_date_value_check majorrepairs mrcdate major_repairs_date_value_check joint startertenancy tenancy tenancyother tenancylength sheltered hhmemb pregnancy_value_check refused hhtype totchild totelder totadult age1 retirement_value_check sex1 ethnic_group ethnic national nationality_all ecstat1 details_known_2 relat2 age2 sex2 ecstat2 details_known_3 relat3 age3 sex3 ecstat3 details_known_4 relat4 age4 sex4 ecstat4 details_known_5 relat5 age5 sex5 ecstat5 details_known_6 relat6 age6 sex6 ecstat6 details_known_7 relat7 age7 sex7 ecstat7 details_known_8 relat8 age8 sex8 ecstat8 armedforces leftreg reservist preg_occ housingneeds housingneeds_type housingneeds_a housingneeds_b housingneeds_c housingneeds_f housingneeds_g housingneeds_h housingneeds_other illness illness_type_4 illness_type_5 illness_type_2 illness_type_6 illness_type_7 illness_type_3 illness_type_9 illness_type_8 illness_type_1 illness_type_10 layear waityear reason reasonother reasonother_value_check prevten new_old homeless ppcodenk ppostcode_full previous_la_known is_previous_la_inferred prevloc_label prevloc reasonpref rp_homeless rp_insan_unsat rp_medwel rp_hardship rp_dontknow cbl cap chr accessible_register letting_allocation_none referral referral_value_check net_income_known incref earnings incfreq net_income_value_check hb has_benefits benefits household_charge nocharge period is_carehome chcharge wchchrg carehome_charges_value_check brent wrent rent_value_check scharge wscharge pscharge wpschrge supcharg wsupchrg tcharge wtcharge scharge_value_check pscharge_value_check supcharg_value_check hbrentshortfall tshortfall_known tshortfall wtshortfall scheme_code scheme_service_name scheme_sensitive SCHTYPE scheme_registered_under_care_act scheme_owning_organisation_name scheme_primary_client_group scheme_has_other_client_group scheme_secondary_client_group scheme_support_type scheme_intended_stay scheme_created_at location_code location_postcode location_name location_units location_type_of_unit location_mobility_type location_local_authority location_startdate
2 completed s.port@jeemayle.com false 2023-11-26T00:00:00+00:00 2024-04-01T00:00:00+01:00 single log 2023 DLUHC DLUHC General needs Affordable rent general needs local authority No 2023-11-26 Affordable Rent Affordable Rent Rent to Buy No HIJKLMN ABCDEFG Yes Yes No fake address London NW9 5LL No Barnet E09000003 No Affordable rent basis Tenant abandoned property No 2 House Purpose built Yes 3 2023-11-24 Yes 2023-11-25 Don’t know Yes Assured Shorthold Tenancy (AST) – Fixed term 2 4 Yes 4 0 0 2 35 Female White Irish Tenant prefers not to say Other Yes Partner 32 Male Not seeking work No Prefers not to say Not known Prefers not to say Prefers not to say Yes Person prefers not to say Not known Person prefers not to say Person prefers not to say Yes – the person is a current or former regular No – they left up to and including 5 years ago Yes No Yes Fully wheelchair accessible housing Yes No No No No No No Yes No No Yes No No No No No No No Less than 1 year 1 year but under 2 years Loss of tied accommodation Other supported housing 2 No Yes TN23 6LZ Yes No Ashford E07000105 Yes Yes No No Yes No Tenant applied directly (no referral or nomination) Yes No 268 Weekly Universal Credit housing element Yes All No Every 2 weeks 200.0 100.0 50.0 25.0 40.0 20.0 35.0 17.5 325.0 162.5 Yes Yes 12.0 6.0

38
spec/helpers/filters_helper_spec.rb

@ -240,12 +240,38 @@ RSpec.describe FiltersHelper do
end
describe "#collection_year_options" do
it "includes 2023/2024 option" do
expect(collection_year_options).to eq(
{
"2021": "2021/22", "2022": "2022/23", "2023": "2023/24"
},
)
context "with 23/24 as the current collection year" do
around do |example|
Timecop.freeze(Time.zone.local(2023, 5, 1)) do
example.run
end
Timecop.return
end
it "has the correct options" do
expect(collection_year_options).to eq(
{
"2023" => "2023/24", "2022" => "2022/23", "2021" => "2021/22"
},
)
end
end
context "with 24/25 as the current collection year" do
around do |example|
Timecop.freeze(Time.zone.local(2024, 5, 1)) do
example.run
end
Timecop.return
end
it "has the correct options" do
expect(collection_year_options).to eq(
{
"2024" => "2024/25", "2023" => "2023/24", "2022" => "2022/23"
},
)
end
end
end

81
spec/jobs/scheme_email_csv_job_spec.rb

@ -6,41 +6,52 @@ describe SchemeEmailCsvJob do
test_url = :test_url
let(:job) { described_class.new }
let(:storage_service) { instance_double(Storage::S3Service, write_file: nil, get_presigned_url: test_url) }
let(:mailer) { instance_double(CsvDownloadMailer, send_csv_download_mail: nil) }
let(:user) { FactoryBot.create(:user) }
let(:storage_service) { instance_double(Storage::S3Service) }
let(:mailer) { instance_double(CsvDownloadMailer) }
let(:scheme_csv_service) { instance_double(Csv::SchemeCsvService) }
let(:search_term) { "meaning" }
let(:filters) { { "owning_organisation" => organisation.id, "status" => %w[active] } }
let(:all_orgs) { false }
let(:organisation) { build(:organisation) }
let(:download_type) { "combined" }
let(:schemes) { build_list(:scheme, 5, owning_organisation: organisation) }
let(:locations) { build_list(:location, 5, scheme: schemes.first) }
before do
allow(Storage::S3Service).to receive(:new).and_return(storage_service)
allow(storage_service).to receive(:write_file)
allow(storage_service).to receive(:get_presigned_url).and_return(test_url)
allow(Csv::SchemeCsvService).to receive(:new).and_return(scheme_csv_service)
allow(scheme_csv_service).to receive(:prepare_csv).and_return("")
allow(CsvDownloadMailer).to receive(:new).and_return(mailer)
allow(mailer).to receive(:send_csv_download_mail)
end
context "when exporting" do
let(:scheme_csv_service) { instance_double(Csv::SchemeCsvService) }
let(:organisation) { user.organisation }
let(:download_type) { "combined" }
let(:schemes) { create_list(:scheme, 1, owning_organisation: organisation) }
before do
allow(FilterManager).to receive(:filter_schemes).and_return(schemes)
create_list(:location, 2, scheme: schemes.first)
end
context "when download type schemes" do
let(:download_type) { "schemes" }
it "uses an appropriate filename in S3" do
expect(storage_service).to receive(:write_file).with(/schemes-.*\.csv/, anything)
job.perform(user)
it "uses an appropriate filename in S3 and exports the correct schemes" do
expect(storage_service).to receive(:write_file).with(/schemes-.*\.csv/, anything) do |_, content|
expect(content).not_to be_nil
expect(content).not_to be_nil
expect(CSV.parse(content).count).to eq(2)
end
job.perform(user, nil, {}, nil, nil, download_type)
end
context "and there are stock owner schemes" do
let(:parent_organisation) { create(:organisation) }
before do
create(:scheme, owning_organisation: parent_organisation)
create(:organisation_relationship, parent_organisation:, child_organisation: organisation)
end
it "exports the correct number of schemes" do
expect(storage_service).to receive(:write_file).with(/schemes-.*\.csv/, anything) do |_, content|
expect(content).not_to be_nil
expect(CSV.parse(content).count).to eq(3)
end
job.perform(user, nil, {}, nil, nil, download_type)
end
end
end
@ -49,7 +60,7 @@ describe SchemeEmailCsvJob do
it "uses an appropriate filename in S3" do
expect(storage_service).to receive(:write_file).with(/locations-.*\.csv/, anything)
job.perform(user)
job.perform(user, nil, {}, nil, nil, download_type)
end
end
@ -58,7 +69,7 @@ describe SchemeEmailCsvJob do
it "uses an appropriate filename in S3" do
expect(storage_service).to receive(:write_file).with(/schemes-and-locations.*\.csv/, anything)
job.perform(user)
job.perform(user, nil, {}, nil, nil, download_type)
end
end
@ -67,12 +78,27 @@ describe SchemeEmailCsvJob do
job.perform(user, nil, {}, nil, organisation, "combined")
end
it "calls the filter manager with the arguments provided" do
expect(FilterManager).to receive(:filter_schemes).with(a_kind_of(ActiveRecord::Relation), search_term, filters, all_orgs, user)
job.perform(user, search_term, filters, all_orgs, organisation, "combined")
context "when resources are filtered" do
let(:search_term) { "meaning" }
let(:filters) { { "owning_organisation" => organisation.id, "status" => %w[active] } }
let(:all_orgs) { false }
before do
allow(Csv::SchemeCsvService).to receive(:new).and_return(scheme_csv_service)
allow(scheme_csv_service).to receive(:prepare_csv).and_return("")
allow(FilterManager).to receive(:filter_schemes).and_return(schemes)
end
it "calls the filter manager with the arguments provided" do
expect(FilterManager).to receive(:filter_schemes).with(a_kind_of(ActiveRecord::Relation), search_term, filters, all_orgs, user)
job.perform(user, search_term, filters, all_orgs, organisation, "combined")
end
end
it "creates a SchemeCsvService with the correct download type" do
allow(Csv::SchemeCsvService).to receive(:new).and_return(scheme_csv_service)
allow(scheme_csv_service).to receive(:prepare_csv).and_return("")
expect(Csv::SchemeCsvService).to receive(:new).with(download_type: "schemes")
job.perform(user, nil, {}, nil, nil, "schemes")
expect(Csv::SchemeCsvService).to receive(:new).with(download_type: "locations")
@ -82,6 +108,9 @@ describe SchemeEmailCsvJob do
end
it "passes the schemes returned by the filter manager to the csv service" do
allow(Csv::SchemeCsvService).to receive(:new).and_return(scheme_csv_service)
allow(scheme_csv_service).to receive(:prepare_csv).and_return("")
expect(scheme_csv_service).to receive(:prepare_csv).with(schemes)
job.perform(user, nil, {}, nil, nil, "combined")
end

87
spec/lib/tasks/correct_noint_value_spec.rb

@ -0,0 +1,87 @@
require "rails_helper"
require "rake"
RSpec.describe "correct_noint_value" do
describe ":correct_noint_value", type: :task do
subject(:task) { Rake::Task["correct_noint_value"] }
before do
Rake.application.rake_require("tasks/correct_noint_value")
Rake::Task.define_task(:environment)
task.reenable
end
context "when the rake task is run" do
context "and there is a sales bulk upload with the fix needed" do
let(:bulk_upload) { create(:bulk_upload, :sales, noint_fix_status: BulkUpload.noint_fix_statuses[:not_applied]) }
before do
bulk_upload.save!
end
it "updates the noint value on a log with noint = 2 where it was set to 2 on create" do
log = create(:sales_log, :completed, noint: 2, bulk_upload:)
task.invoke
log.reload
expect(log.noint).to be(1)
end
it "updates the noint value on a log with noint = 2 where it was set to 2 on create and other fields have since changed" do
log = create(:sales_log, :in_progress, noint: 2, bulk_upload:)
log.update!(status: Log.statuses[:completed])
task.invoke
log.reload
expect(log.noint).to be(1)
end
it "does not update the noint value on a log that has noint = 1" do
log = create(:sales_log, :completed, noint: 2, bulk_upload:)
log.update!(noint: 1)
task.invoke
log.reload
expect(log.noint).to be(1)
end
it "does not update the noint value on a log with noint = 2 where noint was nil on create" do
log = create(:sales_log, :completed, noint: nil, bulk_upload:)
log.update!(noint: 2)
task.invoke
log.reload
expect(log.noint).to be(2)
end
it "updates the noint_fix_status value on the bulk upload" do
task.invoke
bulk_upload.reload
expect(bulk_upload.noint_fix_status).to eq(BulkUpload.noint_fix_statuses[:applied])
end
end
context "and there is a sales bulk upload with the fix marked as not needed" do
let(:bulk_upload) { create(:bulk_upload, :sales, noint_fix_status: BulkUpload.noint_fix_statuses[:not_needed]) }
before do
bulk_upload.save!
end
it "does not update the noint values on logs" do
log = create(:sales_log, :completed, noint: 2, bulk_upload:)
task.invoke
log.reload
expect(log.noint).to be(2)
end
end
end
end
end

86
spec/models/form/lettings/subsections/household_situation_spec.rb

@ -6,33 +6,75 @@ RSpec.describe Form::Lettings::Subsections::HouseholdSituation, type: :model do
let(:subsection_id) { nil }
let(:subsection_definition) { nil }
let(:section) { instance_double(Form::Lettings::Sections::Household) }
let(:form) { instance_double(Form) }
before do
allow(section).to receive(:form).and_return(form)
end
it "has correct section" do
expect(household_situation.section).to eq(section)
end
it "has correct pages" do
expect(household_situation.pages.map(&:id)).to eq(
%w[
time_lived_in_local_authority
time_on_waiting_list
reason_for_leaving_last_settled_home
reason_for_leaving_last_settled_home_renewal
previous_housing_situation
previous_housing_situation_renewal
homelessness
previous_postcode
previous_local_authority
reasonable_preference
reasonable_preference_reason
allocation_system
referral
referral_prp
referral_supported_housing
referral_supported_housing_prp
referral_value_check
],
)
context "with form year before 2024" do
before do
allow(form).to receive(:start_year_after_2024?).and_return(false)
end
it "has correct pages" do
expect(household_situation.pages.map(&:id)).to eq(
%w[
time_lived_in_local_authority
time_on_waiting_list
reason_for_leaving_last_settled_home
reason_for_leaving_last_settled_home_renewal
previous_housing_situation
previous_housing_situation_renewal
homelessness
previous_postcode
previous_local_authority
reasonable_preference
reasonable_preference_reason
allocation_system
referral
referral_prp
referral_supported_housing
referral_supported_housing_prp
referral_value_check
],
)
end
end
context "with form year >= 2024" do
before do
allow(form).to receive(:start_year_after_2024?).and_return(true)
end
it "has correct pages" do
expect(household_situation.pages.map(&:id)).to eq(
%w[
time_lived_in_local_authority
time_on_waiting_list
reason_for_leaving_last_settled_home
reason_for_leaving_last_settled_home_renewal
reasonother_value_check
previous_housing_situation
previous_housing_situation_renewal
homelessness
previous_postcode
previous_local_authority
reasonable_preference
reasonable_preference_reason
allocation_system
referral
referral_prp
referral_supported_housing
referral_supported_housing_prp
referral_value_check
],
)
end
end
it "has the correct id" do

154
spec/models/form/sales/pages/managing_organisation_spec.rb

@ -5,9 +5,13 @@ RSpec.describe Form::Sales::Pages::ManagingOrganisation, type: :model do
let(:page_id) { nil }
let(:page_definition) { nil }
let(:subsection) { instance_double(Form::Subsection) }
let(:subsection) { instance_double(Form::Subsection, form:) }
let(:form) { instance_double(Form) }
before do
allow(form).to receive(:start_year_after_2024?).and_return(false)
end
it "has correct subsection" do
expect(page.subsection).to eq(subsection)
end
@ -32,8 +36,8 @@ RSpec.describe Form::Sales::Pages::ManagingOrganisation, type: :model do
expect(page.depends_on).to be nil
end
describe "#routed_to?" do
let(:log) { create(:lettings_log) }
describe "#routed_to? with 2023 logs" do
let(:log) { create(:sales_log) }
let(:organisation) { create(:organisation) }
context "when user nil" do
@ -54,7 +58,7 @@ RSpec.describe Form::Sales::Pages::ManagingOrganisation, type: :model do
let(:user) { create(:user, :support) }
context "when owning_organisation not set" do
let(:log) { create(:lettings_log, owning_organisation: nil) }
let(:log) { create(:sales_log, owning_organisation: nil) }
it "is not shown" do
expect(page.routed_to?(log, user)).to eq(false)
@ -103,4 +107,146 @@ RSpec.describe Form::Sales::Pages::ManagingOrganisation, type: :model do
end
end
end
describe "#routed_to? with 2024 logs" do
let(:log) { create(:sales_log) }
let(:organisation) { create(:organisation) }
before do
allow(form).to receive(:start_year_after_2024?).and_return(true)
end
context "when user nil" do
it "is not shown" do
expect(page.routed_to?(log, nil)).to eq(false)
end
end
context "when support" do
context "when does not hold own stock" do
let(:user) do
create(:user, :support, organisation: create(:organisation, holds_own_stock: false))
end
let(:log) { create(:sales_log, owning_organisation: user.organisation) }
it "is shown" do
expect(page.routed_to?(log, user)).to eq(true)
end
end
context "when owning_organisation not set" do
let(:user) { create(:user, :support) }
let(:log) { create(:sales_log, owning_organisation: nil) }
it "is not shown" do
expect(page.routed_to?(log, user)).to eq(false)
end
end
context "when holds own stock" do
let(:user) do
create(:user, :support, organisation: create(:organisation, holds_own_stock: true))
end
context "with 0 managing_agents" do
it "is not shown" do
expect(page.routed_to?(log, user)).to eq(false)
end
end
context "with >1 managing_agents" do
before do
create(:organisation_relationship, parent_organisation: log.owning_organisation)
create(:organisation_relationship, parent_organisation: log.owning_organisation)
end
it "is shown" do
expect(page.routed_to?(log, user)).to eq(true)
end
end
context "with 1 managing_agents" do
let(:managing_agent) { create(:organisation) }
before do
create(
:organisation_relationship,
child_organisation: managing_agent,
parent_organisation: log.owning_organisation,
)
end
it "is shown" do
expect(page.routed_to?(log, user)).to eq(true)
end
end
end
end
context "when not support" do
context "when does not hold own stock" do
let(:user) { create(:user, :data_coordinator, organisation: create(:organisation, holds_own_stock: false)) }
context "and the user's organisation is selected as owning organisation" do
let(:log) { create(:sales_log, owning_organisation: user.organisation) }
it "is shown" do
expect(page.routed_to?(log, user)).to eq(true)
end
end
context "and a different than the user's organisation is selected as owning organisation" do
let(:stock_owner) { create(:organisation, holds_own_stock: true) }
let(:log) { create(:sales_log, owning_organisation: stock_owner) }
before do
create(:organisation_relationship, parent_organisation: stock_owner, child_organisation: user.organisation)
end
it "is not shown" do
expect(page.routed_to?(log, user)).to eq(false)
end
end
end
context "when holds own stock" do
let(:user) do
create(:user, :data_coordinator, organisation: create(:organisation, holds_own_stock: true))
end
context "with 0 managing_agents" do
it "is not shown" do
expect(page.routed_to?(log, user)).to eq(false)
end
end
context "with >1 managing_agents" do
before do
create(:organisation_relationship, parent_organisation: user.organisation)
create(:organisation_relationship, parent_organisation: user.organisation)
end
it "is shown" do
expect(page.routed_to?(log, user)).to eq(true)
end
end
context "with 1 managing_agents" do
let(:managing_agent) { create(:organisation) }
before do
create(
:organisation_relationship,
child_organisation: managing_agent,
parent_organisation: user.organisation,
)
end
it "is shown" do
expect(page.routed_to?(log, user)).to eq(true)
end
end
end
end
end
end

2
spec/models/form/sales/questions/age1_spec.rb

@ -20,7 +20,7 @@ RSpec.describe Form::Sales::Questions::Age1, type: :model do
end
it "has the correct check_answer_label" do
expect(question.check_answer_label).to eq("Lead buyer’s age")
expect(question.check_answer_label).to eq("Buyer 1’s age")
end
it "has the correct type" do

2
spec/models/form/sales/questions/buyer1_age_known_spec.rb

@ -20,7 +20,7 @@ RSpec.describe Form::Sales::Questions::Buyer1AgeKnown, type: :model do
end
it "has the correct check_answer_label" do
expect(question.check_answer_label).to eq("Lead buyer’s age")
expect(question.check_answer_label).to eq("Buyer 1’s age")
end
it "has the correct type" do

2
spec/models/form/sales/questions/buyer1_working_situation_spec.rb

@ -33,8 +33,8 @@ RSpec.describe Form::Sales::Questions::Buyer1WorkingSituation, type: :model do
it "has the correct answer_options" do
expect(question.answer_options).to eq({
"2" => { "value" => "Part-time - Less than 30 hours" },
"1" => { "value" => "Full-time - 30 hours or more" },
"2" => { "value" => "Part-time - Less than 30 hours" },
"3" => { "value" => "In government training into work, such as New Deal" },
"4" => { "value" => "Jobseeker" },
"6" => { "value" => "Not seeking work" },

2
spec/models/form/sales/questions/buyer2_working_situation_spec.rb

@ -37,8 +37,8 @@ RSpec.describe Form::Sales::Questions::Buyer2WorkingSituation, type: :model do
it "has the correct answer_options" do
expect(question.answer_options).to eq({
"2" => { "value" => "Part-time - Less than 30 hours" },
"1" => { "value" => "Full-time - 30 hours or more" },
"2" => { "value" => "Part-time - Less than 30 hours" },
"3" => { "value" => "In government training into work, such as New Deal" },
"4" => { "value" => "Jobseeker" },
"6" => { "value" => "Not seeking work" },

16
spec/models/form/sales/questions/number_joint_buyers_spec.rb

@ -6,6 +6,12 @@ RSpec.describe Form::Sales::Questions::NumberJointBuyers, type: :model do
let(:question_id) { nil }
let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) }
let(:subsection) { instance_double(Form::Subsection) }
before do
allow(page).to receive(:subsection).and_return(subsection)
allow(subsection).to receive(:form).and_return(instance_double(Form, start_year_after_2024?: false))
end
it "has correct page" do
expect(question.page).to eq(page)
@ -42,4 +48,14 @@ RSpec.describe Form::Sales::Questions::NumberJointBuyers, type: :model do
"3" => { "value" => "Don’t know" },
})
end
context "with 2024 form" do
before do
allow(subsection).to receive(:form).and_return(instance_double(Form, start_year_after_2024?: true))
end
it "has no hint_text" do
expect(question.hint_text).to be_nil
end
end
end

2
spec/models/form/sales/questions/person_working_situation_spec.rb

@ -22,8 +22,8 @@ RSpec.describe Form::Sales::Questions::PersonWorkingSituation, type: :model do
it "has the correct answer_options" do
expect(question.answer_options).to eq({
"2" => { "value" => "Part-time - Less than 30 hours" },
"1" => { "value" => "Full-time - 30 hours or more" },
"2" => { "value" => "Part-time - Less than 30 hours" },
"3" => { "value" => "In government training into work, such as New Deal" },
"4" => { "value" => "Jobseeker" },
"6" => { "value" => "Not seeking work" },

4
spec/models/form/sales/questions/property_wheelchair_accessible_spec.rb

@ -22,11 +22,11 @@ RSpec.describe Form::Sales::Questions::PropertyWheelchairAccessible, type: :mode
end
it "has the correct header" do
expect(question.header).to eq("Is the property build or adapted to wheelchair-user standards?")
expect(question.header).to eq("Is the property built or adapted to wheelchair-user standards?")
end
it "has the correct check_answer_label" do
expect(question.check_answer_label).to eq("Property build or adapted to wheelchair-user standards")
expect(question.check_answer_label).to eq("Property built or adapted to wheelchair-user standards")
end
it "has the correct type" do

20
spec/models/lettings_log_spec.rb

@ -3382,26 +3382,6 @@ RSpec.describe LettingsLog do
end
end
describe "#blank_invalid_non_setup_fields!" do
context "when a setup field is invalid" do
subject(:model) { described_class.new(needstype: 404) }
it "does not blank it" do
model.valid?
expect { model.blank_invalid_non_setup_fields! }.not_to change(model, :needstype)
end
end
context "when a non setup field is invalid" do
subject(:model) { build(:lettings_log, :completed, offered: 234) }
it "blanks it" do
model.valid?
expect { model.blank_invalid_non_setup_fields! }.to change(model, :offered)
end
end
end
describe "#beds_for_la_rent_range" do
context "when beds nil" do
let(:lettings_log) { build(:lettings_log, beds: nil) }

50
spec/models/log_spec.rb

@ -27,4 +27,54 @@ RSpec.describe Log, type: :model do
expect(in_progress_lettings_log.calculate_status).to eq "in_progress"
end
end
describe "#blank_invalid_non_setup_fields!" do
context "when a setup field is invalid for a lettings log" do
subject(:model) { build(:lettings_log, needstype: 404) }
it "does not blank it" do
model.valid?
expect { model.blank_invalid_non_setup_fields! }.not_to change(model, :needstype)
end
end
context "when a setup field is invalid for a sales log" do
subject(:model) { build(:sales_log, companybuy: 404) }
it "does not blank it" do
model.valid?
expect { model.blank_invalid_non_setup_fields! }.not_to change(model, :companybuy)
end
end
context "when a non setup field is invalid for a lettings log" do
subject(:model) { build(:lettings_log, :completed, offered: 234) }
it "blanks it" do
model.valid?
model.blank_invalid_non_setup_fields!
expect(model.offered).to be_nil
end
end
context "when a non setup field is invalid for a sales log" do
subject(:model) { build(:sales_log, :completed, age1: 10) }
it "blanks it" do
model.valid?
model.blank_invalid_non_setup_fields!
expect(model.age1).to be_nil
end
end
context "when prevloc is invalid for a lettings log" do
subject(:model) { build(:lettings_log, :completed, previous_la_known: 1, prevloc: nil) }
it "blanks previous_la_known" do
model.valid?
model.blank_invalid_non_setup_fields!
expect(model.previous_la_known).to be_nil
end
end
end
end

130
spec/models/validations/household_validations_spec.rb

@ -4,11 +4,15 @@ RSpec.describe Validations::HouseholdValidations do
subject(:household_validator) { validator_class.new }
let(:validator_class) { Class.new { include Validations::HouseholdValidations } }
let(:record) { FactoryBot.create(:lettings_log) }
let(:fake_2021_2022_form) { Form.new("spec/fixtures/forms/2021_2022.json") }
let(:log_date) { Time.zone.now }
let(:record) { FactoryBot.create(:lettings_log, :setup_completed, startdate: log_date) }
before do
allow(FormHandler.instance).to receive(:current_lettings_form).and_return(fake_2021_2022_form)
Timecop.freeze(log_date + 1)
end
after do
Timecop.return
end
describe "reasonable preference validations" do
@ -53,6 +57,44 @@ RSpec.describe Validations::HouseholdValidations do
household_validator.validate_reason_for_leaving_last_settled_home(record)
expect(record.errors["reasonother"]).to be_empty
end
context "when form year is before 2024" do
let(:log_date) { Time.zone.local(2024, 1, 1) }
it "does not validate the content of reasonother for phrases indicating homelessness" do
record.reason = 20
record.reasonother = "Temp accommodation"
household_validator.validate_reason_for_leaving_last_settled_home(record)
expect(record.errors["reason"]).to be_empty
end
end
context "when form year is >= 2024" do
let(:log_date) { Time.zone.local(2024, 4, 1) }
context "when checking the content of reasonother" do
it "validates that the reason doesn't match phrase indicating homelessness" do
record.reason = 20
record.reasonother = "Temp accommodation"
household_validator.validate_reason_for_leaving_last_settled_home(record)
expect(record.errors["reason"]).to include(I18n.t("validations.household.reason.other_not_settled"))
end
it "allows reasons that don't exactly match a phrase indicating homelessness" do
record.reason = 20
record.reasonother = "Not quite homeless but some other reason"
household_validator.validate_reason_for_leaving_last_settled_home(record)
expect(record.errors["reason"]).to be_empty
end
it "ignores surrounding non-alphabet characters and casing when determining a match" do
record.reason = 20
record.reasonother = " 0homelessness ! "
household_validator.validate_reason_for_leaving_last_settled_home(record)
expect(record.errors["reason"]).to include(I18n.t("validations.household.reason.other_not_settled"))
end
end
end
end
context "when reason is not other" do
@ -231,6 +273,26 @@ RSpec.describe Validations::HouseholdValidations do
end
describe "household member validations" do
it "validates that the number of household members cannot be less than 1" do
record.hhmemb = 0
household_validator.validate_numeric_min_max(record)
expect(record.errors["hhmemb"])
.to include(match I18n.t("validations.numeric.within_range", field: "Number of household members", min: 1, max: 8))
end
it "validates that the number of household members cannot be more than 8" do
record.hhmemb = 9
household_validator.validate_numeric_min_max(record)
expect(record.errors["hhmemb"])
.to include(match I18n.t("validations.numeric.within_range", field: "Number of household members", min: 1, max: 8))
end
it "expects that the number of other household members is between the min and max" do
record.hhmemb = 5
household_validator.validate_numeric_min_max(record)
expect(record.errors["hhmemb"]).to be_empty
end
it "validates that only 1 partner exists" do
record.relat2 = "P"
record.relat3 = "P"
@ -394,26 +456,6 @@ RSpec.describe Validations::HouseholdValidations do
expect(record.errors["sex2"]).to be_empty
expect(record.errors["age2"]).to be_empty
end
it "validates that the number of household members cannot be less than 0" do
record.hhmemb = -1
household_validator.validate_numeric_min_max(record)
expect(record.errors["hhmemb"])
.to include(match I18n.t("validations.numeric.within_range", field: "Number of Household Members", min: 0, max: 8))
end
it "validates that the number of household members cannot be more than 8" do
record.hhmemb = 9
household_validator.validate_numeric_min_max(record)
expect(record.errors["hhmemb"])
.to include(match I18n.t("validations.numeric.within_range", field: "Number of Household Members", min: 0, max: 8))
end
it "expects that the number of other household members is between the min and max" do
record.hhmemb = 5
household_validator.validate_numeric_min_max(record)
expect(record.errors["hhmemb"]).to be_empty
end
end
context "when the household contains a retired female" do
@ -651,24 +693,30 @@ RSpec.describe Validations::HouseholdValidations do
.to be_empty
end
it "prevten cannot be 3" do
record.referral = 1
record.prevten = 3
household_validator.validate_previous_housing_situation(record)
expect(record.errors["prevten"])
.to include(match I18n.t("validations.household.prevten.internal_transfer", prevten: ""))
expect(record.errors["referral"])
.to include(match I18n.t("validations.household.referral.prevten_invalid", prevten: ""))
end
it "prevten cannot be 4, 10, 13, 19, 23, 24, 25, 26, 28, 29" do
record.referral = 1
record.prevten = 4
household_validator.validate_previous_housing_situation(record)
expect(record.errors["prevten"])
.to include(match I18n.t("validations.household.prevten.internal_transfer", prevten: ""))
expect(record.errors["referral"])
.to include(match I18n.t("validations.household.referral.prevten_invalid", prevten: ""))
[
{ code: 3, label: "Private sector tenancy" },
{ code: 4, label: "Tied housing or rented with job" },
{ code: 7, label: "Direct access hostel" },
{ code: 10, label: "Hospital" },
{ code: 13, label: "Children’s home or foster care" },
{ code: 14, label: "Bed and breakfast" },
{ code: 19, label: "Rough sleeping" },
{ code: 23, label: "Mobile home or caravan" },
{ code: 24, label: "Home Office Asylum Support" },
{ code: 25, label: "Any other accommodation" },
{ code: 26, label: "Owner occupation (private)" },
{ code: 28, label: "Living with friends or family" },
{ code: 29, label: "Prison or approved probation hostel" },
].each do |prevten|
it "prevten cannot be #{prevten[:code]}" do
record.referral = 1
record.prevten = prevten[:code]
household_validator.validate_previous_housing_situation(record)
expect(record.errors["prevten"])
.to include(match I18n.t("validations.household.prevten.internal_transfer", prevten: prevten[:label]))
expect(record.errors["referral"])
.to include(match I18n.t("validations.household.referral.prevten_invalid", prevten: ""))
end
end
end
end

23
spec/models/validations/sales/soft_validations_spec.rb

@ -415,6 +415,17 @@ RSpec.describe Validations::Sales::SoftValidations do
.not_to be_shared_ownership_deposit_invalid
end
it "returns false if MORTGAGE + DEPOSIT + CASHDIS are within 1£ of VALUE * EQUITY/100" do
record.mortgage = 500
record.deposit = 500
record.cashdis = 500
record.value = 3001
record.equity = 50
expect(record)
.not_to be_shared_ownership_deposit_invalid
end
it "returns false if mortgage is used and no mortgage is given" do
record.mortgage = nil
record.deposit = 1000
@ -473,6 +484,18 @@ RSpec.describe Validations::Sales::SoftValidations do
.to be_shared_ownership_deposit_invalid
end
it "returns false if no cashdis not routed to and MORTGAGE + DEPOSIT are within 1£ of VALUE * EQUITY/100" do
record.mortgage = 500
record.deposit = 500
record.type = 2
record.cashdis = nil
record.value = 1999
record.equity = 50
expect(record)
.not_to be_shared_ownership_deposit_invalid
end
it "returns false if no value is given" do
record.mortgage = 1000
record.deposit = 1000

38
spec/models/validations/soft_validations_spec.rb

@ -1233,4 +1233,42 @@ RSpec.describe Validations::SoftValidations do
end
end
end
describe "reasonother_might_be_existing_category?" do
it "returns true if reasonother is exactly in the 'likely existing category' list" do
record.reasonother = "Domestic Abuse"
expect(record).to be_reasonother_might_be_existing_category
end
it "returns true if any word of reasonother is exactly in the 'likely existing category' list" do
record.reasonother = "Was decanted from somewhere"
expect(record).to be_reasonother_might_be_existing_category
end
it "is not case sensitive when matching" do
record.reasonother = "domestic abuse"
expect(record).to be_reasonother_might_be_existing_category
end
it "returns false if no part of reasonother is in the 'likely existing category' list" do
record.reasonother = "other"
expect(record).not_to be_reasonother_might_be_existing_category
end
it "returns false if match to the 'likely existing category' list is only part of a word" do
record.reasonother = "wasdecanted"
expect(record).not_to be_reasonother_might_be_existing_category
end
it "ignores neighbouring non-alphabet for matching" do
record.reasonother = "1Domestic abuse."
expect(record).to be_reasonother_might_be_existing_category
end
end
end

14
spec/requests/duplicate_logs_controller_spec.rb

@ -169,7 +169,7 @@ RSpec.describe DuplicateLogsController, type: :request do
it "displays check your answers for each log with correct questions" do
expect(page).to have_content("Q1 - Sale completion date", count: 3)
expect(page).to have_content("Q2 - Purchaser code", count: 3)
expect(page).to have_content("Q20 - Lead buyer’s age", count: 3)
expect(page).to have_content("Q20 - Buyer 1’s age", count: 3)
expect(page).to have_content("Q21 - Buyer 1’s gender identity", count: 3)
expect(page).to have_content("Q25 - Buyer 1's working situation", count: 3)
expect(page).to have_content("Q15 - Postcode", count: 3)
@ -187,7 +187,7 @@ RSpec.describe DuplicateLogsController, type: :request do
expect(page).to have_content("Q1 - Sale completion date", count: 3)
expect(page).to have_content("Q2 - Purchaser code", count: 3)
expect(page).to have_content("Q20 - Lead buyer’s age", count: 3)
expect(page).to have_content("Q20 - Buyer 1’s age", count: 3)
expect(page).to have_content("Q21 - Buyer 1’s gender identity", count: 3)
expect(page).to have_content("Q25 - Buyer 1's working situation", count: 3)
expect(page).to have_content("Postcode (from UPRN)", count: 3)
@ -215,7 +215,7 @@ RSpec.describe DuplicateLogsController, type: :request do
it "displays check your answers for each log with correct questions" do
expect(page).to have_content("Q1 - Sale completion date", count: 1)
expect(page).to have_content("Q2 - Purchaser code", count: 1)
expect(page).to have_content("Q20 - Lead buyer’s age", count: 1)
expect(page).to have_content("Q20 - Buyer 1’s age", count: 1)
expect(page).to have_content("Q21 - Buyer 1’s gender identity", count: 1)
expect(page).to have_content("Q25 - Buyer 1's working situation", count: 1)
expect(page).to have_content("Q15 - Postcode", count: 1)
@ -241,7 +241,7 @@ RSpec.describe DuplicateLogsController, type: :request do
it "displays check your answers for each log with correct questions" do
expect(page).to have_content("Q1 - Sale completion date", count: 1)
expect(page).to have_content("Q2 - Purchaser code", count: 1)
expect(page).to have_content("Q20 - Lead buyer’s age", count: 1)
expect(page).to have_content("Q20 - Buyer 1’s age", count: 1)
expect(page).to have_content("Q21 - Buyer 1’s gender identity", count: 1)
expect(page).to have_content("Q25 - Buyer 1's working situation", count: 1)
expect(page).to have_content("Q15 - Postcode", count: 1)
@ -379,7 +379,7 @@ RSpec.describe DuplicateLogsController, type: :request do
it "displays check your answers for each log with correct questions" do
expect(page).to have_content("Q1 - Sale completion date", count: 3)
expect(page).to have_content("Q2 - Purchaser code", count: 3)
expect(page).to have_content("Q20 - Lead buyer’s age", count: 3)
expect(page).to have_content("Q20 - Buyer 1’s age", count: 3)
expect(page).to have_content("Q21 - Buyer 1’s gender identity", count: 3)
expect(page).to have_content("Q25 - Buyer 1's working situation", count: 3)
expect(page).to have_content("Q15 - Postcode", count: 3)
@ -407,7 +407,7 @@ RSpec.describe DuplicateLogsController, type: :request do
it "displays check your answers for each log with correct questions" do
expect(page).to have_content("Q1 - Sale completion date", count: 1)
expect(page).to have_content("Q2 - Purchaser code", count: 1)
expect(page).to have_content("Q20 - Lead buyer’s age", count: 1)
expect(page).to have_content("Q20 - Buyer 1’s age", count: 1)
expect(page).to have_content("Q21 - Buyer 1’s gender identity", count: 1)
expect(page).to have_content("Q25 - Buyer 1's working situation", count: 1)
expect(page).to have_content("Q15 - Postcode", count: 1)
@ -433,7 +433,7 @@ RSpec.describe DuplicateLogsController, type: :request do
it "displays check your answers for each log with correct questions" do
expect(page).to have_content("Q1 - Sale completion date", count: 1)
expect(page).to have_content("Q2 - Purchaser code", count: 1)
expect(page).to have_content("Q20 - Lead buyer’s age", count: 1)
expect(page).to have_content("Q20 - Buyer 1’s age", count: 1)
expect(page).to have_content("Q21 - Buyer 1’s gender identity", count: 1)
expect(page).to have_content("Q25 - Buyer 1's working situation", count: 1)
expect(page).to have_content("Q15 - Postcode", count: 1)

24
spec/requests/sales_logs_controller_spec.rb

@ -161,30 +161,6 @@ RSpec.describe SalesLogsController, type: :request do
expect(sales_log.managing_organisation.name).to eq("User org")
end
end
context "when the user's org doesn't hold stock and merge_organisations_enabled is false" do
let(:organisation) { FactoryBot.create(:organisation, name: "User org", holds_own_stock: false) }
let(:user) { FactoryBot.create(:user, :data_coordinator, organisation:) }
before do
RequestHelper.stub_http_requests
sign_in user
allow(FeatureToggle).to receive(:merge_organisations_enabled?).and_return(false)
post "/sales-logs", headers:
end
it "does not set owning organisation" do
created_id = response.location.match(/[0-9]+/)[0]
sales_log = SalesLog.find_by(id: created_id)
expect(sales_log.owning_organisation).to be_nil
end
it "sets managing organisation as the user organisation" do
created_id = response.location.match(/[0-9]+/)[0]
sales_log = SalesLog.find_by(id: created_id)
expect(sales_log.managing_organisation.name).to eq("User org")
end
end
end
end
end

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

@ -2294,19 +2294,76 @@ RSpec.describe BulkUpload::Lettings::Year2023::RowParser do
end
describe "#chcharge" do
let(:attributes) { { bulk_upload:, field_127: "123.45" } }
let(:attributes) { { bulk_upload:, field_127: "123.45", field_131: "123.45", field_130: "123.45", field_129: "123.45", field_128: "123.45" } }
it "sets value given" do
expect(parser.log.chcharge).to eq(123.45)
end
it "sets is care home to yes" do
expect(parser.log.is_carehome).to eq(1)
end
it "clears any other given charges" do
parser.log.save!
expect(parser.log.tcharge).to be_nil
expect(parser.log.brent).to be_nil
expect(parser.log.supcharg).to be_nil
expect(parser.log.pscharge).to be_nil
expect(parser.log.scharge).to be_nil
end
end
describe "#tcharge" do
let(:attributes) { { bulk_upload:, field_132: "123.45" } }
let(:attributes) { { bulk_upload:, field_132: "123.45", field_127: "123.45", field_128: "123.45", field_129: "123.45", field_130: "123.45", field_131: "123.45" } }
it "sets value given" do
expect(parser.log.tcharge).to eq(123.45)
end
context "when other charges are not given" do
context "and it is carehome" do
let(:attributes) { { bulk_upload:, field_132: "123.45", field_127: "123.45", field_128: nil, field_129: nil, field_130: nil, field_131: nil } }
it "does not set charges values" do
parser.log.save!
expect(parser.log.tcharge).to be_nil
expect(parser.log.brent).to be_nil
expect(parser.log.supcharg).to be_nil
expect(parser.log.pscharge).to be_nil
expect(parser.log.scharge).to be_nil
end
it "does not add errors to missing charges" do
parser.valid?
expect(parser.errors[:field_128]).to be_empty
expect(parser.errors[:field_129]).to be_empty
expect(parser.errors[:field_130]).to be_empty
expect(parser.errors[:field_131]).to be_empty
end
end
context "and it is not carehome" do
let(:attributes) { { bulk_upload:, field_132: "123.45", field_127: nil, field_128: nil, field_129: nil, field_130: nil, field_131: nil } }
it "does not set charges values" do
parser.log.save!
expect(parser.log.tcharge).to be_nil
expect(parser.log.brent).to be_nil
expect(parser.log.supcharg).to be_nil
expect(parser.log.pscharge).to be_nil
expect(parser.log.scharge).to be_nil
end
it "adds an error to all missing charges" do
parser.valid?
expect(parser.errors[:field_128]).to eql(["Please enter the basic rent. If there is no basic rent, please enter '0'."])
expect(parser.errors[:field_129]).to eql(["Please enter the service charge. If there is no service charge, please enter '0'."])
expect(parser.errors[:field_130]).to eql(["Please enter the personal service charge. If there is no personal service charge, please enter '0'."])
expect(parser.errors[:field_131]).to eql(["Please enter the support charge. If there is no support charge, please enter '0'."])
end
end
end
end
describe "#supcharg" do
@ -2315,6 +2372,50 @@ RSpec.describe BulkUpload::Lettings::Year2023::RowParser do
it "sets value given" do
expect(parser.log.supcharg).to eq(123.45)
end
context "when other charges are not given" do
context "and it is carehome" do
let(:attributes) { { bulk_upload:, field_132: nil, field_127: "123.45", field_128: nil, field_129: nil, field_130: nil, field_131: "123.45" } }
it "does not set charges values" do
parser.log.save!
expect(parser.log.tcharge).to be_nil
expect(parser.log.brent).to be_nil
expect(parser.log.supcharg).to be_nil
expect(parser.log.pscharge).to be_nil
expect(parser.log.scharge).to be_nil
end
it "does not add errors to missing charges" do
parser.valid?
expect(parser.errors[:field_128]).to be_empty
expect(parser.errors[:field_129]).to be_empty
expect(parser.errors[:field_130]).to be_empty
expect(parser.errors[:field_131]).to be_empty
end
end
context "and it is not carehome" do
let(:attributes) { { bulk_upload:, field_132: "123.45", field_127: nil, field_128: nil, field_129: nil, field_130: nil, field_131: nil } }
it "does not set charges values" do
parser.log.save!
expect(parser.log.tcharge).to be_nil
expect(parser.log.brent).to be_nil
expect(parser.log.supcharg).to be_nil
expect(parser.log.pscharge).to be_nil
expect(parser.log.scharge).to be_nil
end
it "adds an error to all missing charges" do
parser.valid?
expect(parser.errors[:field_128]).to eql(["Please enter the basic rent. If there is no basic rent, please enter '0'."])
expect(parser.errors[:field_129]).to eql(["Please enter the service charge. If there is no service charge, please enter '0'."])
expect(parser.errors[:field_130]).to eql(["Please enter the personal service charge. If there is no personal service charge, please enter '0'."])
expect(parser.errors[:field_131]).to eql(["Please enter the support charge. If there is no support charge, please enter '0'."])
end
end
end
end
describe "#pscharge" do

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

@ -2159,11 +2159,24 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
end
describe "#chcharge" do
let(:attributes) { { bulk_upload:, field_124: "123.45" } }
let(:attributes) { { bulk_upload:, field_124: "123.45", field_125: "123.45", field_126: "123.45", field_127: "123.45", field_128: "123.45" } }
it "sets value given" do
expect(parser.log.chcharge).to eq(123.45)
end
it "sets is care home to yes" do
expect(parser.log.is_carehome).to eq(1)
end
it "clears any other given charges" do
parser.log.save!
expect(parser.log.tcharge).to be_nil
expect(parser.log.brent).to be_nil
expect(parser.log.supcharg).to be_nil
expect(parser.log.pscharge).to be_nil
expect(parser.log.scharge).to be_nil
end
end
describe "#supcharg" do
@ -2172,6 +2185,50 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
it "sets value given" do
expect(parser.log.supcharg).to eq(123.45)
end
context "when other charges are not given" do
context "and it is carehome" do
let(:attributes) { { bulk_upload:, field_128: "123.45", field_124: "123.45", field_125: nil, field_126: nil, field_127: nil } }
it "does not set charges values" do
parser.log.save!
expect(parser.log.tcharge).to be_nil
expect(parser.log.brent).to be_nil
expect(parser.log.supcharg).to be_nil
expect(parser.log.pscharge).to be_nil
expect(parser.log.scharge).to be_nil
end
it "does not add errors to missing charges" do
parser.valid?
expect(parser.errors[:field_125]).to be_empty
expect(parser.errors[:field_126]).to be_empty
expect(parser.errors[:field_127]).to be_empty
expect(parser.errors[:field_128]).to be_empty
end
end
context "and it is not carehome" do
let(:attributes) { { bulk_upload:, field_128: "123.45", field_124: nil, field_125: nil, field_126: nil, field_127: nil } }
it "does not set charges values" do
parser.log.save!
expect(parser.log.tcharge).to be_nil
expect(parser.log.brent).to be_nil
expect(parser.log.supcharg).to be_nil
expect(parser.log.pscharge).to be_nil
expect(parser.log.scharge).to be_nil
end
it "adds an error to all missing charges" do
parser.valid?
expect(parser.errors[:field_125]).to eql(["Please enter the basic rent. If there is no basic rent, please enter '0'."])
expect(parser.errors[:field_126]).to eql(["Please enter the service charge. If there is no service charge, please enter '0'."])
expect(parser.errors[:field_127]).to eql(["Please enter the personal service charge. If there is no personal service charge, please enter '0'."])
expect(parser.errors[:field_128]).to be_empty
end
end
end
end
describe "#pscharge" do

4
spec/services/bulk_upload/sales/year2023/csv_parser_spec.rb

@ -28,6 +28,10 @@ RSpec.describe BulkUpload::Sales::Year2023::CsvParser do
it "parses csv correctly" do
expect(service.row_parsers[0].field_19).to eql(log.uprn)
end
it "counts the number of valid field numbers correctly" do
expect(service).to be_correct_field_count
end
end
context "when parsing csv with headers in arbitrary order" do

18
spec/services/bulk_upload/sales/year2023/row_parser_spec.rb

@ -1001,6 +1001,24 @@ RSpec.describe BulkUpload::Sales::Year2023::RowParser do
end
describe "#log" do
describe "#noint" do
context "when field is set to 1" do
let(:attributes) { valid_attributes.merge({ field_28: 1 }) }
it "is correctly set" do
expect(parser.log.noint).to be(1)
end
end
context "when field is set to 2" do
let(:attributes) { valid_attributes.merge({ field_28: 2 }) }
it "is correctly set" do
expect(parser.log.noint).to be(2)
end
end
end
describe "#uprn" do
let(:attributes) { setup_section_params.merge({ field_19: "12" }) }

4
spec/services/bulk_upload/sales/year2024/csv_parser_spec.rb

@ -28,6 +28,10 @@ RSpec.describe BulkUpload::Sales::Year2024::CsvParser do
it "parses csv correctly" do
expect(service.row_parsers[0].field_22).to eql(log.uprn)
end
it "counts the number of valid field numbers correctly" do
expect(service).to be_correct_field_count
end
end
context "when parsing csv with headers in arbitrary order" do

87
spec/services/bulk_upload/sales/year2024/row_parser_spec.rb

@ -9,11 +9,13 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do
let(:bulk_upload) { create(:bulk_upload, :sales, user:, year: 2024) }
let(:user) { create(:user, organisation: owning_org) }
let(:owning_org) { create(:organisation, :with_old_visible_id) }
let(:managing_org) { create(:organisation, :with_old_visible_id) }
let(:setup_section_params) do
{
bulk_upload:,
field_1: owning_org.old_visible_id, # organisation
field_2: owning_org.old_visible_id, # organisation
field_2: managing_org.old_visible_id, # organisation
field_3: user.email, # user
field_4: now.day.to_s, # sale day
field_5: now.month.to_s, # sale month
@ -31,7 +33,7 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do
{
bulk_upload:,
field_1: owning_org.old_visible_id,
field_2: owning_org.old_visible_id,
field_2: managing_org.old_visible_id,
field_4: "12",
field_5: "5",
@ -114,6 +116,8 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do
end
around do |example|
create(:organisation_relationship, parent_organisation: owning_org, child_organisation: managing_org)
Timecop.freeze(Time.zone.local(2025, 2, 22)) do
Singleton.__init__(FormHandler)
example.run
@ -287,7 +291,7 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do
it "has errors on correct setup fields" do
errors = parser.errors.select { |e| e.options[:category] == :setup }.map(&:attribute).sort
expect(errors).to eql(%i[field_1 field_17 field_18 field_4 field_5 field_6 field_8])
expect(errors).to eql(%i[field_1 field_17 field_18 field_2 field_4 field_5 field_6 field_8])
end
end
@ -303,7 +307,7 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do
it "has errors on correct setup fields" do
errors = parser.errors.select { |e| e.options[:category] == :setup }.map(&:attribute).sort
expect(errors).to eql(%i[field_1 field_15 field_17 field_18 field_4 field_5 field_6 field_9])
expect(errors).to eql(%i[field_1 field_15 field_17 field_18 field_2 field_4 field_5 field_6 field_9])
end
end
@ -321,7 +325,7 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do
it "has errors on correct setup fields" do
errors = parser.errors.select { |e| e.options[:category] == :setup }.map(&:attribute).sort
expect(errors).to eql(%i[field_1 field_16 field_17 field_18 field_4 field_5 field_6])
expect(errors).to eql(%i[field_1 field_16 field_17 field_18 field_2 field_4 field_5 field_6])
end
end
@ -338,7 +342,7 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do
it "has errors on correct setup fields" do
errors = parser.errors.select { |e| e.options[:category] == :setup }.map(&:attribute).sort
expect(errors).to eql(%i[field_1 field_10 field_15 field_17 field_18 field_4 field_5 field_6])
expect(errors).to eql(%i[field_1 field_10 field_15 field_17 field_18 field_2 field_4 field_5 field_6])
end
end
@ -346,7 +350,6 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do
let(:attributes) do
{
bulk_upload:,
field_17: "test id",
field_31: "2",
field_46: "8",
field_39: "1",
@ -356,7 +359,7 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do
it "has errors on correct setup fields" do
errors = parser.errors.select { |e| e.options[:category] == :setup }.map(&:attribute).sort
expect(errors).to eql(%i[field_1 field_17 field_18 field_4 field_5 field_6 field_8])
expect(errors).to eql(%i[field_1 field_17 field_18 field_2 field_4 field_5 field_6 field_8])
end
end
@ -372,7 +375,7 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do
it "has errors on correct setup fields" do
errors = parser.errors.select { |e| e.options[:category] == :setup }.map(&:attribute).sort
expect(errors).to eql(%i[field_1 field_11 field_13 field_14 field_17 field_18 field_4 field_5 field_6])
expect(errors).to eql(%i[field_1 field_11 field_13 field_14 field_17 field_18 field_2 field_4 field_5 field_6])
end
end
@ -390,7 +393,7 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do
it "has errors on correct setup fields" do
errors = parser.errors.select { |e| e.options[:category] == :setup }.map(&:attribute).sort
expect(errors).to eql(%i[field_1 field_12 field_14 field_15 field_17 field_18 field_4 field_5 field_6])
expect(errors).to eql(%i[field_1 field_12 field_14 field_15 field_17 field_18 field_2 field_4 field_5 field_6])
end
end
@ -1023,6 +1026,24 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do
end
describe "#log" do
describe "#noint" do
context "when field is set to 1" do
let(:attributes) { valid_attributes.merge({ field_17: 1 }) }
it "is correctly set" do
expect(parser.log.noint).to be(1)
end
end
context "when field is set to 2" do
let(:attributes) { valid_attributes.merge({ field_17: 2 }) }
it "is correctly set" do
expect(parser.log.noint).to be(2)
end
end
end
describe "#uprn" do
let(:attributes) { setup_section_params.merge({ field_22: "12" }) }
@ -1446,39 +1467,55 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do
let(:attributes) { setup_section_params }
context "when user is part of the owning organisation" do
it "sets managing organisation to the users organisation" do
it "sets managing organisation to the correct organisation" do
parser.valid?
expect(parser.log.owning_organisation_id).to be(owning_org.id)
expect(parser.log.managing_organisation_id).to be(owning_org.id)
expect(parser.log.managing_organisation_id).to be(managing_org.id)
end
end
context "when user is part of an organisation affiliated with owning org" do
let(:managing_agent) { create(:organisation) }
let(:user) { create(:user, organisation: managing_agent) }
let(:attributes) { setup_section_params }
context "when blank" do
let(:attributes) { { bulk_upload:, field_2: "" } }
before do
create(:organisation_relationship, child_organisation: managing_agent, parent_organisation: owning_org)
it "is not permitted as setup error" do
parser.valid?
setup_errors = parser.errors.select { |e| e.options[:category] == :setup }
expect(setup_errors.find { |e| e.attribute == :field_2 }.message).to eql("You must answer reported by")
end
it "blocks log creation" do
parser.valid?
expect(parser).to be_block_log_creation
end
end
context "when cannot find managing org" do
let(:attributes) { { bulk_upload:, field_2: "donotexist" } }
it "is not permitted as setup error" do
parser.valid?
expect(parser.log.owning_organisation_id).to be(owning_org.id)
expect(parser.log.managing_organisation_id).to be(managing_agent.id)
setup_errors = parser.errors.select { |e| e.options[:category] == :setup }
expect(setup_errors.find { |e| e.attribute == :field_2 }.message).to eql("You must answer reported by")
end
it "blocks log creation" do
parser.valid?
expect(parser).to be_block_log_creation
end
end
context "when user is part of an organisation not affiliated with owning org" do
let(:unaffiliated_org) { create(:organisation) }
let(:user) { create(:user, organisation: unaffiliated_org) }
let(:attributes) { setup_section_params }
context "when not affiliated with managing org" do
let(:unaffiliated_org) { create(:organisation, :with_old_visible_id) }
let(:attributes) { { bulk_upload:, field_1: owning_org.old_visible_id, field_2: unaffiliated_org.old_visible_id } }
it "is not permitted as setup error" do
parser.valid?
setup_errors = parser.errors.select { |e| e.options[:category] == :setup }
expect(setup_errors.find { |e| e.attribute == :field_3 }.message).to eql("This user belongs to an organisation that does not have a relationship with the owning organisation")
expect(setup_errors.find { |e| e.attribute == :field_2 }.message).to eql("This organisation does not have a relationship with the owning organisation")
end
it "blocks log creation" do

8
yarn.lock

@ -3245,10 +3245,10 @@ govuk-frontend@4.7.0:
resolved "https://registry.yarnpkg.com/govuk-frontend/-/govuk-frontend-4.7.0.tgz#69950b6c2e69f435ffe9aa60d8dee232dac977de"
integrity sha512-0OsdCusF5qvLWwKziU8zqxiC0nq6WP0ZQuw51ymZ/1V0tO71oIKMlSLN2S9bm8RcEGSoidPt2A34gKxePrLjvg==
govuk-frontend@5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/govuk-frontend/-/govuk-frontend-5.0.0.tgz#c08a4d1115fb31eb39b6d19979c627f816185dd7"
integrity sha512-3WSfvQ+3kw/q/m8jrq/t8XnMUA8D2r0uhGyZaDbIh1gWTJBQzJBHbHiKYI9nc9ixIXdCFsc9RozkgEm57a795g==
govuk-frontend@5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/govuk-frontend/-/govuk-frontend-5.1.0.tgz#55e520940b587ddd023e96251efaa076acc9bd5f"
integrity sha512-Dc3J+uOI4i2VR3BVyfxbf6qVjTT4n4bBqbD0/Io6feP8pt/4IfKdP1vWimZf+BwMKKMXacw10hmdy5UcD6Cr8w==
govuk-prototype-kit@^13.14.1:
version "13.16.0"

Loading…
Cancel
Save