Browse Source

CLDC-2068 request, validate UPRN and retrieve address (#1370)

* Add OS_DATA_KEY env var

* Add new UPRN and address columns to logs

* Bugfix: use dynamic optional fields

* Update optional fields

* Add UPRN validation

* Add UPRN Client

* Add UPRN Presenter

* UPRN questions and flows

* Skip to non addresss questions if UPRN unknown

* Address PO review comments and add missing specs

* Display LA correctly
pull/1378/head
Jack 2 years ago committed by GitHub
parent
commit
cff4cc45bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      .env.example
  2. 2
      .env.test
  3. 2
      .github/workflows/production_pipeline.yml
  4. 2
      .github/workflows/review_pipeline.yml
  5. 2
      .github/workflows/staging_pipeline.yml
  6. 2
      app/controllers/form_controller.rb
  7. 6
      app/helpers/question_view_helper.rb
  8. 9
      app/models/derived_variables/sales_log_variables.rb
  9. 2
      app/models/form.rb
  10. 6
      app/models/form/page.rb
  11. 5
      app/models/form/question.rb
  12. 23
      app/models/form/sales/pages/address.rb
  13. 16
      app/models/form/sales/pages/property_local_authority.rb
  14. 26
      app/models/form/sales/pages/uprn.rb
  15. 17
      app/models/form/sales/pages/uprn_confirmation.rb
  16. 12
      app/models/form/sales/pages/uprn_known.rb
  17. 37
      app/models/form/sales/questions/address_line1.rb
  18. 13
      app/models/form/sales/questions/address_line2.rb
  19. 13
      app/models/form/sales/questions/county.rb
  20. 25
      app/models/form/sales/questions/postcode_for_full_address.rb
  21. 4
      app/models/form/sales/questions/property_local_authority.rb
  22. 13
      app/models/form/sales/questions/town_or_city.rb
  23. 34
      app/models/form/sales/questions/uprn.rb
  24. 34
      app/models/form/sales/questions/uprn_confirmation.rb
  25. 21
      app/models/form/sales/questions/uprn_known.rb
  26. 25
      app/models/form/sales/subsections/property_information.rb
  27. 2
      app/models/lettings_log.rb
  28. 18
      app/models/log.rb
  29. 7
      app/models/sales_log.rb
  30. 8
      app/models/validations/property_validations.rb
  31. 8
      app/models/validations/sales/property_validations.rb
  32. 50
      app/services/uprn_client.rb
  33. 41
      app/services/uprn_data_presenter.rb
  34. 15
      app/views/form/_check_answers_summary_list.html.erb
  35. 2
      app/views/form/_numeric_output_question.html.erb
  36. 9
      app/views/form/_radio_question.html.erb
  37. 5
      app/views/form/page.html.erb
  38. 4
      config/locales/en.yml
  39. 15
      db/migrate/20230301170338_add_uprn_to_logs.rb
  40. 15
      db/migrate/20230306110210_add_address_to_logs.rb
  41. 14
      db/schema.rb
  42. 21
      spec/features/lettings_log_spec.rb
  43. 4
      spec/fixtures/files/lettings_logs_download.csv
  44. 4
      spec/fixtures/files/lettings_logs_download_codes_only.csv
  45. 4
      spec/fixtures/files/lettings_logs_download_non_support.csv
  46. 26
      spec/helpers/question_view_helper_spec.rb
  47. 73
      spec/models/form/sales/pages/address_spec.rb
  48. 47
      spec/models/form/sales/pages/property_local_authority_spec.rb
  49. 59
      spec/models/form/sales/pages/uprn_confirmation_spec.rb
  50. 33
      spec/models/form/sales/pages/uprn_known_spec.rb
  51. 73
      spec/models/form/sales/pages/uprn_spec.rb
  52. 75
      spec/models/form/sales/questions/address_line1_spec.rb
  53. 49
      spec/models/form/sales/questions/address_line2_spec.rb
  54. 49
      spec/models/form/sales/questions/county_spec.rb
  55. 62
      spec/models/form/sales/questions/postcode_for_full_address_spec.rb
  56. 30
      spec/models/form/sales/questions/property_local_authority_spec.rb
  57. 49
      spec/models/form/sales/questions/town_or_city_spec.rb
  58. 90
      spec/models/form/sales/questions/uprn_confirmation_spec.rb
  59. 59
      spec/models/form/sales/questions/uprn_known_spec.rb
  60. 88
      spec/models/form/sales/questions/uprn_spec.rb
  61. 33
      spec/models/form/sales/subsections/property_information_spec.rb
  62. 165
      spec/models/lettings_log_spec.rb
  63. 87
      spec/models/sales_log_spec.rb
  64. 29
      spec/models/validations/property_validations_spec.rb
  65. 39
      spec/models/validations/sales/property_validations_spec.rb
  66. 9
      spec/services/csv/lettings_log_csv_service_spec.rb
  67. 68
      spec/services/uprn_client_spec.rb
  68. 66
      spec/services/uprn_data_presenter_spec.rb

1
.env.example

@ -5,3 +5,4 @@ GOVUK_NOTIFY_API_KEY=<notify-key-here-if-testing-emails-or-admin-users>
OTP_SECRET_ENCRYPTION_KEY="<Generate this using bundle exec rake secret>"
APP_HOST="http://localhost:3000"
OS_DATA_KEY=OS_DATA_KEY

2
.env.test

@ -0,0 +1,2 @@
APP_HOST="http://localhost:3000"
OS_DATA_KEY=OS_DATA_KEY

2
.github/workflows/production_pipeline.yml

@ -237,6 +237,7 @@ jobs:
GOVUK_NOTIFY_API_KEY: ${{ secrets.GOVUK_NOTIFY_API_KEY }}
APP_HOST: ${{ secrets.APP_HOST }}
RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
OS_DATA_KEY: ${{ secrets.OS_DATA_KEY }}
IMPORT_PAAS_INSTANCE: ${{ secrets.IMPORT_PAAS_INSTANCE }}
EXPORT_PAAS_INSTANCE: ${{ secrets.EXPORT_PAAS_INSTANCE }}
S3_CONFIG: ${{ secrets.S3_CONFIG }}
@ -249,6 +250,7 @@ jobs:
cf set-env $APP_NAME GOVUK_NOTIFY_API_KEY $GOVUK_NOTIFY_API_KEY
cf set-env $APP_NAME APP_HOST $APP_HOST
cf set-env $APP_NAME RAILS_MASTER_KEY $RAILS_MASTER_KEY
cf set-env $APP_NAME OS_DATA_KEY $OS_DATA_KEY
cf set-env $APP_NAME IMPORT_PAAS_INSTANCE $IMPORT_PAAS_INSTANCE
cf set-env $APP_NAME EXPORT_PAAS_INSTANCE $EXPORT_PAAS_INSTANCE
cf set-env $APP_NAME S3_CONFIG $S3_CONFIG

2
.github/workflows/review_pipeline.yml

@ -110,6 +110,7 @@ jobs:
API_KEY: ${{ secrets.API_KEY }}
GOVUK_NOTIFY_API_KEY: ${{ secrets.GOVUK_NOTIFY_API_KEY }}
RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
OS_DATA_KEY: ${{ secrets.OS_DATA_KEY }}
IMPORT_PAAS_INSTANCE: ${{ secrets.IMPORT_PAAS_INSTANCE }}
EXPORT_PAAS_INSTANCE: ${{ secrets.EXPORT_PAAS_INSTANCE }}
S3_CONFIG: ${{ secrets.S3_CONFIG }}
@ -120,6 +121,7 @@ jobs:
cf set-env $APP_NAME API_KEY $API_KEY
cf set-env $APP_NAME GOVUK_NOTIFY_API_KEY $GOVUK_NOTIFY_API_KEY
cf set-env $APP_NAME RAILS_MASTER_KEY $RAILS_MASTER_KEY
cf set-env $APP_NAME OS_DATA_KEY $OS_DATA_KEY
cf set-env $APP_NAME IMPORT_PAAS_INSTANCE $IMPORT_PAAS_INSTANCE
cf set-env $APP_NAME EXPORT_PAAS_INSTANCE "dluhc-core-review-export-bucket"
cf set-env $APP_NAME S3_CONFIG $S3_CONFIG

2
.github/workflows/staging_pipeline.yml

@ -208,6 +208,7 @@ jobs:
GOVUK_NOTIFY_API_KEY: ${{ secrets.GOVUK_NOTIFY_API_KEY }}
APP_HOST: ${{ secrets.APP_HOST }}
RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }}
OS_DATA_KEY: ${{ secrets.OS_DATA_KEY }}
IMPORT_PAAS_INSTANCE: ${{ secrets.IMPORT_PAAS_INSTANCE }}
EXPORT_PAAS_INSTANCE: ${{ secrets.EXPORT_PAAS_INSTANCE }}
S3_CONFIG: ${{ secrets.S3_CONFIG }}
@ -222,6 +223,7 @@ jobs:
cf set-env $APP_NAME GOVUK_NOTIFY_API_KEY $GOVUK_NOTIFY_API_KEY
cf set-env $APP_NAME APP_HOST $APP_HOST
cf set-env $APP_NAME RAILS_MASTER_KEY $RAILS_MASTER_KEY
cf set-env $APP_NAME OS_DATA_KEY $OS_DATA_KEY
cf set-env $APP_NAME IMPORT_PAAS_INSTANCE $IMPORT_PAAS_INSTANCE
cf set-env $APP_NAME EXPORT_PAAS_INSTANCE $EXPORT_PAAS_INSTANCE
cf set-env $APP_NAME S3_CONFIG $S3_CONFIG

2
app/controllers/form_controller.rb

@ -160,7 +160,7 @@ private
end
def question_is_required?(question)
@log.class::OPTIONAL_FIELDS.exclude?(question.id) && required_questions.include?(question.id)
@log.optional_fields.exclude?(question.id) && required_questions.include?(question.id)
end
def required_questions

6
app/helpers/question_view_helper.rb

@ -8,14 +8,16 @@ module QuestionViewHelper
def legend(question, page_header, conditional)
{
text: [question.question_number_string(conditional:), question.header.html_safe].compact.join(" - "),
size: label_size(page_header, conditional),
size: label_size(page_header, conditional, question),
tag: label_tag(page_header, conditional),
}
end
private
def label_size(page_header, conditional)
def label_size(page_header, conditional, question)
return if question.plain_label.present?
page_header.blank? && !conditional ? "l" : "m"
end

9
app/models/derived_variables/sales_log_variables.rb

@ -23,6 +23,15 @@ module DerivedVariables::SalesLogVariables
self.totadult = total_adult + total_elder
self.hhmemb = number_of_household_members
self.hhtype = household_type
if uprn_known&.zero?
self.uprn = nil
end
if uprn_confirmed&.zero?
self.uprn = nil
self.uprn_known = 0
end
end
private

2
app/models/form.rb

@ -160,7 +160,7 @@ class Form
def invalidated_page_questions(log, current_user = nil)
# we're already treating these fields as a special case and reset their values upon saving a log
callback_questions = %w[postcode_known la ppcodenk previous_la_known prevloc postcode_full ppostcode_full location_id]
callback_questions = %w[postcode_known la ppcodenk previous_la_known prevloc postcode_full ppostcode_full location_id address_line1 address_line2 town_or_city county]
questions.reject { |q| q.page.routed_to?(log, current_user) || q.derived? || callback_questions.include?(q.id) } || []
end

6
app/models/form/page.rb

@ -1,6 +1,7 @@
class Form::Page
attr_accessor :id, :header, :header_partial, :description, :questions, :depends_on, :title_text,
:informative_text, :subsection, :hide_subsection_label, :next_unresolved_page_id
:informative_text, :subsection, :hide_subsection_label, :next_unresolved_page_id,
:skip_text
def initialize(id, hsh, subsection)
@id = id
@ -15,6 +16,7 @@ class Form::Page
@informative_text = hsh["informative_text"]
@hide_subsection_label = hsh["hide_subsection_label"]
@next_unresolved_page_id = hsh["next_unresolved_page_id"]
@skip_text = hsh["skip_text"]
end
end
@ -36,6 +38,8 @@ class Form::Page
questions.all? { |question| question.type == "interruption_screen" }
end
def skip_href(log = nil); end
private
def conditional_question_ids

5
app/models/form/question.rb

@ -4,7 +4,7 @@ class Form::Question
:conditional_for, :readonly, :answer_options, :page, :check_answer_label,
:inferred_answers, :hidden_in_check_answers, :inferred_check_answers_value,
:guidance_partial, :prefix, :suffix, :requires_js, :fields_added, :derived,
:check_answers_card_number, :unresolved_hint_text, :question_number
:check_answers_card_number, :unresolved_hint_text, :question_number, :plain_label
module GuidancePosition
TOP = 1
@ -41,6 +41,7 @@ class Form::Question
@check_answers_card_number = hsh["check_answers_card_number"] || 0
@unresolved_hint_text = hsh["unresolved_hint_text"]
@question_number = hsh["question_number"]
@plain_label = hsh["plain_label"]
end
end
@ -57,6 +58,8 @@ class Form::Question
inferred_answer_value(log) || answer_label
end
def notification_banner(_log = nil); end
def get_inferred_answers(log)
return [] unless inferred_answers

23
app/models/form/sales/pages/address.rb

@ -0,0 +1,23 @@
class Form::Sales::Pages::Address < ::Form::Page
def initialize(id, hsh, subsection)
super
@id = "address"
@header = "What is the property's address?"
end
def questions
@questions ||= [
Form::Sales::Questions::AddressLine1.new(nil, nil, self),
Form::Sales::Questions::AddressLine2.new(nil, nil, self),
Form::Sales::Questions::TownOrCity.new(nil, nil, self),
Form::Sales::Questions::County.new(nil, nil, self),
Form::Sales::Questions::PostcodeForFullAddress.new(nil, nil, self),
]
end
def routed_to?(log, _current_user = nil)
return false if log.uprn_known.nil?
log.uprn_confirmed != 1 || log.uprn_known.zero?
end
end

16
app/models/form/sales/pages/property_local_authority.rb

@ -9,8 +9,20 @@ class Form::Sales::Pages::PropertyLocalAuthority < ::Form::Page
def questions
@questions ||= [
Form::Sales::Questions::PropertyLocalAuthorityKnown.new(nil, nil, self),
la_known_question,
Form::Sales::Questions::PropertyLocalAuthority.new(nil, nil, self),
]
].compact
end
def routed_to?(log, _current_user = nil)
return false if log.uprn_known.nil? && form.start_date.year >= 2023
true
end
def la_known_question
if form.start_date.year < 2023
Form::Sales::Questions::PropertyLocalAuthorityKnown.new(nil, nil, self)
end
end
end

26
app/models/form/sales/pages/uprn.rb

@ -0,0 +1,26 @@
class Form::Sales::Pages::Uprn < ::Form::Page
def initialize(id, hsh, subsection)
super
@id = "uprn"
end
def questions
@questions ||= [
Form::Sales::Questions::Uprn.new(nil, nil, self),
]
end
def routed_to?(log, _current_user = nil)
log.uprn_known == 1
end
def skip_text
"Enter address instead"
end
def skip_href(log = nil)
return unless log
"/#{log.model_name.param_key.dasherize}s/#{log.id}/address"
end
end

17
app/models/form/sales/pages/uprn_confirmation.rb

@ -0,0 +1,17 @@
class Form::Sales::Pages::UprnConfirmation < ::Form::Page
def initialize(id, hsh, subsection)
super
@id = "uprn_confirmation"
@header = "We found an address that might be this property"
end
def questions
@questions ||= [
Form::Sales::Questions::UprnConfirmation.new(nil, nil, self),
]
end
def routed_to?(log, _current_user = nil)
log.uprn.present? && log.uprn_known == 1
end
end

12
app/models/form/sales/pages/uprn_known.rb

@ -0,0 +1,12 @@
class Form::Sales::Pages::UprnKnown < ::Form::Page
def initialize(id, hsh, subsection)
super
@id = "uprn_known"
end
def questions
@questions ||= [
Form::Sales::Questions::UprnKnown.new(nil, nil, self),
]
end
end

37
app/models/form/sales/questions/address_line1.rb

@ -0,0 +1,37 @@
class Form::Sales::Questions::AddressLine1 < ::Form::Question
def initialize(id, hsh, page)
super
@id = "address_line1"
@check_answer_label = "Address"
@header = "Address line 1"
@type = "text"
@plain_label = true
end
def hidden_in_check_answers?(log, _current_user = nil)
return true if log.uprn_known.nil?
return false if log.uprn_known&.zero?
return true if log.uprn_confirmed.nil? && log.uprn.present?
return true if log.uprn_known == 1 && log.uprn.blank?
log.uprn_confirmed == 1
end
def answer_label(log, _current_user = nil)
[
log.address_line1,
log.address_line2,
log.postcode_full,
log.town_or_city,
log.county,
].select(&:present?).join("\n")
end
def get_extra_check_answer_value(log)
return unless log.is_la_inferred?
la = LocalAuthority.find_by(code: log.la)&.name
la.presence
end
end

13
app/models/form/sales/questions/address_line2.rb

@ -0,0 +1,13 @@
class Form::Sales::Questions::AddressLine2 < ::Form::Question
def initialize(id, hsh, page)
super
@id = "address_line2"
@header = "Address line 2 (optional)"
@type = "text"
@plain_label = true
end
def hidden_in_check_answers?(_log = nil, _current_user = nil)
true
end
end

13
app/models/form/sales/questions/county.rb

@ -0,0 +1,13 @@
class Form::Sales::Questions::County < ::Form::Question
def initialize(id, hsh, page)
super
@id = "county"
@header = "County (optional)"
@type = "text"
@plain_label = true
end
def hidden_in_check_answers?(_log = nil, _current_user = nil)
true
end
end

25
app/models/form/sales/questions/postcode_for_full_address.rb

@ -0,0 +1,25 @@
class Form::Sales::Questions::PostcodeForFullAddress < ::Form::Question
def initialize(id, hsh, page)
super
@id = "postcode_full"
@header = "Postcode"
@type = "text"
@width = 5
@inferred_check_answers_value = [{
"condition" => {
"pcodenk" => 1,
},
"value" => "Not known",
}]
@inferred_answers = {
"la" => {
"is_la_inferred" => true,
},
}
@plain_label = true
end
def hidden_in_check_answers?(_log = nil, _current_user = nil)
true
end
end

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

@ -11,4 +11,8 @@ class Form::Sales::Questions::PropertyLocalAuthority < ::Form::Question
def answer_options
{ "" => "Select an option" }.merge(LocalAuthority.active(form.start_date).england.map { |la| [la.code, la.name] }.to_h)
end
def hidden_in_check_answers?(log, _current_user = nil)
log.saledate && log.saledate.year >= 2023 && log.is_la_inferred?
end
end

13
app/models/form/sales/questions/town_or_city.rb

@ -0,0 +1,13 @@
class Form::Sales::Questions::TownOrCity < ::Form::Question
def initialize(id, hsh, page)
super
@id = "town_or_city"
@header = "Town or city"
@type = "text"
@plain_label = true
end
def hidden_in_check_answers?(_log = nil, _current_user = nil)
true
end
end

34
app/models/form/sales/questions/uprn.rb

@ -0,0 +1,34 @@
class Form::Sales::Questions::Uprn < ::Form::Question
def initialize(id, hsh, page)
super
@id = "uprn"
@check_answer_label = "UPRN"
@header = "What is the property's UPRN"
@type = "text"
@hint_text = "The Unique Property Reference Number (UPRN) is a unique number system created by Ordnance Survey and used by housing providers and sectors UK-wide. For example 10010457355."
@width = 10
end
def unanswered_error_message
I18n.t("validations.property.uprn.invalid")
end
def get_extra_check_answer_value(log)
value = [
log.address_line1,
log.address_line2,
log.town_or_city,
log.county,
log.postcode_full,
(LocalAuthority.find_by(code: log.la)&.name if log.la.present?),
].select(&:present?)
return unless value.any?
"\n\n#{value.join("\n")}"
end
def hidden_in_check_answers?(log, _current_user = nil)
log.uprn_known != 1
end
end

34
app/models/form/sales/questions/uprn_confirmation.rb

@ -0,0 +1,34 @@
class Form::Sales::Questions::UprnConfirmation < ::Form::Question
def initialize(id, hsh, page)
super
@id = "uprn_confirmed"
@header = "Is this the property address?"
@type = "radio"
@answer_options = ANSWER_OPTIONS
@check_answer_label = "Is this the right address?"
end
ANSWER_OPTIONS = {
"1" => { "value" => "Yes" },
"0" => { "value" => "No, I want to enter the address manually" },
}.freeze
def notification_banner(log = nil)
return unless log&.uprn
{
title: "UPRN: #{log.uprn}",
heading: [
log.address_line1,
log.address_line2,
log.postcode_full,
log.town_or_city,
log.county,
].select(&:present?).join("\n"),
}
end
def hidden_in_check_answers?(log, _current_user = nil)
log.uprn_known != 1 || log.uprn_confirmed.present?
end
end

21
app/models/form/sales/questions/uprn_known.rb

@ -0,0 +1,21 @@
class Form::Sales::Questions::UprnKnown < ::Form::Question
def initialize(id, hsh, page)
super
@id = "uprn_known"
@check_answer_label = "UPRN known?"
@header = "Do you know the property UPRN?"
@type = "radio"
@answer_options = ANSWER_OPTIONS
@hint_text = "The Unique Property Reference Number (UPRN) is a unique number system created by Ordnance Survey and used by housing providers and sectors UK-wide. For example 10010457355.<br><br>
You can continue without the UPRN, but it means we will need you to enter the address of the property."
end
ANSWER_OPTIONS = {
"1" => { "value" => "Yes" },
"0" => { "value" => "No" },
}.freeze
def unanswered_error_message
I18n.t("validations.property.uprn_known.invalid")
end
end

25
app/models/form/sales/subsections/property_information.rb

@ -8,15 +8,36 @@ class Form::Sales::Subsections::PropertyInformation < ::Form::Subsection
def pages
@pages ||= [
uprn_questions,
Form::Sales::Pages::PropertyNumberOfBedrooms.new(nil, nil, self),
Form::Sales::Pages::AboutPriceValueCheck.new("about_price_bedrooms_value_check", nil, self),
Form::Sales::Pages::PropertyUnitType.new(nil, nil, self),
Form::Sales::Pages::MonthlyChargesValueCheck.new("monthly_charges_property_type_value_check", nil, self),
Form::Sales::Pages::PropertyBuildingType.new(nil, nil, self),
Form::Sales::Pages::Postcode.new(nil, nil, self),
Form::Sales::Pages::PropertyLocalAuthority.new(nil, nil, self),
postcode_and_la_questions,
Form::Sales::Pages::AboutPriceValueCheck.new("about_price_la_value_check", nil, self),
Form::Sales::Pages::PropertyWheelchairAccessible.new(nil, nil, self),
].flatten.compact
end
def uprn_questions
if form.start_date.year >= 2023
[
Form::Sales::Pages::UprnKnown.new(nil, nil, self),
Form::Sales::Pages::Uprn.new(nil, nil, self),
Form::Sales::Pages::UprnConfirmation.new(nil, nil, self),
Form::Sales::Pages::Address.new(nil, nil, self),
Form::Sales::Pages::PropertyLocalAuthority.new(nil, nil, self),
]
end
end
def postcode_and_la_questions
if form.start_date.year < 2023
[
Form::Sales::Pages::Postcode.new(nil, nil, self),
Form::Sales::Pages::PropertyLocalAuthority.new(nil, nil, self),
]
end
end
end

2
app/models/lettings_log.rb

@ -562,6 +562,8 @@ private
not_required << "tshortfall" if tshortfall_unknown?
not_required << "tenancylength" if tenancylength_optional?
not_required |= %w[address_line2 county postcode_full] if startdate && startdate.year >= 2023
not_required
end

18
app/models/log.rb

@ -31,6 +31,24 @@ class Log < ApplicationRecord
}
scope :created_by, ->(user) { where(created_by: user) }
def process_uprn_change!
if uprn.present?
service = UprnClient.new(uprn)
service.call
return errors.add(:uprn, service.error) if service.error.present?
presenter = UprnDataPresenter.new(service.result)
self.uprn_confirmed = nil
self.address_line1 = presenter.address_line1
self.address_line2 = presenter.address_line2
self.town_or_city = presenter.town_or_city
self.postcode_full = presenter.postcode
process_postcode_changes!
end
end
def collection_start_year
return @start_year if @start_year

7
app/models/sales_log.rb

@ -31,6 +31,7 @@ class SalesLog < Log
before_validation :reset_location_fields!, unless: :postcode_known?
before_validation :reset_previous_location_fields!, unless: :previous_postcode_known?
before_validation :set_derived_fields!
after_validation :process_uprn_change!, if: :should_process_uprn_change?
scope :filter_by_year, ->(year) { where(saledate: Time.zone.local(year.to_i, 4, 1)...Time.zone.local(year.to_i + 1, 4, 1)) }
scope :filter_by_purchaser_code, ->(purchid) { where("purchid ILIKE ?", "%#{purchid}%") }
@ -78,6 +79,8 @@ class SalesLog < Log
not_required = []
not_required << "proplen" if proplen_optional?
not_required |= %w[address_line2 county postcode_full] if saledate && saledate.year >= 2023
not_required
end
@ -309,4 +312,8 @@ class SalesLog < Log
field_value = public_send(field_name)
format_as_currency(field_value)
end
def should_process_uprn_change?
uprn_changed? && saledate && saledate.year >= 2023
end
end

8
app/models/validations/property_validations.rb

@ -75,4 +75,12 @@ module Validations::PropertyValidations
record.errors.add :beds, I18n.t("validations.property.beds.over_max")
end
end
def validate_uprn(record)
return unless record.uprn
return if record.uprn.match?(/^[0-9]{1,12}$/)
record.errors.add :uprn, I18n.t("validations.property.uprn.invalid")
end
end

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

@ -16,4 +16,12 @@ module Validations::Sales::PropertyValidations
record.errors.add :beds, I18n.t("validations.property.beds.bedsits_have_max_one_bedroom")
end
end
def validate_uprn(record)
return unless record.uprn
return if record.uprn.match?(/^[0-9]{1,12}$/)
record.errors.add :uprn, I18n.t("validations.property.uprn.invalid")
end
end

50
app/services/uprn_client.rb

@ -0,0 +1,50 @@
require "net/http"
class UprnClient
attr_reader :uprn
attr_accessor :error
ADDRESS = "api.os.uk".freeze
PATH = "/search/places/v1/uprn".freeze
def initialize(uprn)
@uprn = uprn
end
def call
unless response.is_a?(Net::HTTPSuccess) && result.present?
@error = "UPRN is not recognised. Check the number, or enter the address"
end
rescue JSON::ParserError
@error = "UPRN is not recognised. Check the number, or enter the address"
end
def result
@result ||= JSON.parse(response.body).dig("results", 0, "DPA")
end
private
def http_client
client = Net::HTTP.new(ADDRESS, 443)
client.use_ssl = true
client.verify_mode = OpenSSL::SSL::VERIFY_PEER
client.max_retries = 3
client.read_timeout = 10 # seconds
client
end
def endpoint_uri
uri = URI(PATH)
params = {
uprn:,
key: ENV["OS_DATA_KEY"],
}
uri.query = URI.encode_www_form(params)
uri.to_s
end
def response
@response ||= http_client.request_get(endpoint_uri)
end
end

41
app/services/uprn_data_presenter.rb

@ -0,0 +1,41 @@
require "net/http"
class UprnDataPresenter
attr_reader :data
def initialize(data)
@data = data
end
def postcode
data["POSTCODE"]
end
def address_line1
data.values_at(
"PO_BOX_NUMBER",
"ORGANISATION_NAME",
"DEPARTMENT_NAME",
"SUB_BUILDING_NAME",
"BUILDING_NAME",
"BUILDING_NUMBER",
"DEPENDENT_THOROUGHFARE_NAME",
"THOROUGHFARE_NAME",
).compact
.join(", ")
.titleize
end
def address_line2
data.values_at(
"DOUBLE_DEPENDENT_LOCALITY", "DEPENDENT_LOCALITY"
).compact
.join(", ")
.titleize
.presence
end
def town_or_city
data["POST_TOWN"].titleize
end
end

15
app/views/form/_check_answers_summary_list.html.erb

@ -3,12 +3,19 @@
<% summary_list.row do |row| %>
<% row.key { get_question_label(question) } %>
<% row.value do %>
<span class="govuk-!-margin-right-4"><%= get_answer_label(question, @log) %></span>
<%= simple_format(
get_answer_label(question, @log),
wrapper_tag: "span",
class: "govuk-!-margin-right-4",
) %>
<% extra_value = question.get_extra_check_answer_value(@log) %>
<% if extra_value %>
<span class="govuk-!-font-weight-regular app-!-colour-muted"><%= extra_value %></span>
<% if extra_value && question.answer_label(lettings_log, current_user).present? %>
<%= simple_format(
extra_value,
wrapper_tag: "span",
class: "govuk-!-font-weight-regular app-!-colour-muted",
) %>
<% end %>
<br>
<% question.get_inferred_answers(@log).each do |inferred_answer| %>
<span class="govuk-!-font-weight-regular app-!-colour-muted"><%= inferred_answer %></span>
<% end %>

2
app/views/form/_numeric_output_question.html.erb

@ -1,7 +1,7 @@
<%= render partial: "form/guidance/#{question.guidance_partial}" if question.top_guidance? %>
<div class="govuk-form-group">
<label class="govuk-label govuk-label--<%= label_size(page_header, conditional) %>" for="lettings-log-<%= question.id %>-field">
<label class="govuk-label govuk-label--<%= label_size(page_header, conditional, question) %>" for="lettings-log-<%= question.id %>-field">
<%= question.header.html_safe %>
</label>
<div class="govuk-hint">

9
app/views/form/_radio_question.html.erb

@ -1,4 +1,13 @@
<%= render partial: "form/guidance/#{question.guidance_partial}" if question.top_guidance? %>
<% banner = question.notification_banner(@log) %>
<% if banner %>
<%= govuk_notification_banner(
title_text: banner[:title],
title_heading_level: 3,
) do
simple_format(banner[:heading])
end %>
<% end %>
<%= f.govuk_radio_buttons_fieldset question.id.to_sym,
caption: caption(caption_text, page_header, conditional),

5
app/views/form/page.html.erb

@ -63,7 +63,10 @@
<div class="govuk-button-group">
<% if !@page.interruption_screen? && if request.query_parameters["referrer"] != "check_answers" %>
<%= f.govuk_submit "Save and continue" %>
<%= govuk_link_to "Skip for now", send(@log.form.next_page_redirect_path(@page, @log, current_user), @log) %>
<%= govuk_link_to(
(@page.skip_text || "Skip for now"),
(@page.skip_href(@log) || send(@log.form.next_page_redirect_path(@page, @log, current_user), @log)),
) %>
<% else %>
<%= f.govuk_submit "Save changes" %>
<%= govuk_link_to "Cancel", send(@log.form.cancel_path(@page, @log), @log) %>

4
config/locales/en.yml

@ -187,6 +187,10 @@ en:
supported_housing_mismatch: Lettings type must be a supported housing type because you selected supported housing when uploading the file
property:
uprn:
invalid: "UPRN must be 12 digits or less"
uprn_known:
invalid: "You must answer UPRN known?"
mrcdate:
before_tenancy_start: "Enter a major repairs date that is before the tenancy start date"
not_first_let: "Major repairs date must not be completed if the tenancy is a first let"

15
db/migrate/20230301170338_add_uprn_to_logs.rb

@ -0,0 +1,15 @@
class AddUprnToLogs < ActiveRecord::Migration[7.0]
def change
change_table :sales_logs, bulk: true do |t|
t.column :uprn, :string
t.column :uprn_known, :integer
t.column :uprn_confirmed, :integer
end
change_table :lettings_logs, bulk: true do |t|
t.column :uprn, :string
t.column :uprn_known, :integer
t.column :uprn_confirmed, :integer
end
end
end

15
db/migrate/20230306110210_add_address_to_logs.rb

@ -0,0 +1,15 @@
class AddAddressToLogs < ActiveRecord::Migration[7.0]
change_table :sales_logs, bulk: true do |t|
t.column :address_line1, :string
t.column :address_line2, :string
t.column :town_or_city, :string
t.column :county, :string
end
change_table :lettings_logs, bulk: true do |t|
t.column :address_line1, :string
t.column :address_line2, :string
t.column :town_or_city, :string
t.column :county, :string
end
end

14
db/schema.rb

@ -279,6 +279,13 @@ ActiveRecord::Schema[7.0].define(version: 2023_03_08_101826) do
t.boolean "unresolved"
t.bigint "updated_by_id"
t.bigint "bulk_upload_id"
t.string "uprn"
t.integer "uprn_known"
t.integer "uprn_confirmed"
t.string "address_line1"
t.string "address_line2"
t.string "town_or_city"
t.string "county"
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"
t.index ["location_id"], name: "index_lettings_logs_on_location_id"
@ -545,6 +552,13 @@ ActiveRecord::Schema[7.0].define(version: 2023_03_08_101826) do
t.integer "buy2living"
t.integer "prevtenbuy2"
t.integer "nationalbuy2"
t.string "uprn"
t.integer "uprn_known"
t.integer "uprn_confirmed"
t.string "address_line1"
t.string "address_line2"
t.string "town_or_city"
t.string "county"
t.index ["bulk_upload_id"], name: "index_sales_logs_on_bulk_upload_id"
t.index ["created_by_id"], name: "index_sales_logs_on_created_by_id"
t.index ["old_id"], name: "index_sales_logs_on_old_id", unique: true

21
spec/features/lettings_log_spec.rb

@ -89,7 +89,7 @@ RSpec.describe "Lettings Log Features" do
click_button("Save and continue")
log_id = page.current_path.scan(/\d/).join
visit("lettings-logs/#{log_id}/setup/check-answers")
expect(page).to have_content("Stock owner User org")
expect(page).to have_content("Stock owner User org", normalize_ws: true)
expect(page).to have_content("You have answered 2 of 8 questions")
end
end
@ -125,7 +125,7 @@ RSpec.describe "Lettings Log Features" do
select(managing_org.name, from: "lettings-log-managing-organisation-id-field")
click_button("Save and continue")
visit("lettings-logs/#{log_id}/setup/check-answers")
expect(page).to have_content("Managing agent Managing org")
expect(page).to have_content("Managing agent Managing org", normalize_ws: true)
expect(support_user.organisation.managing_agents).to eq([org_rel.child_organisation])
end
end
@ -164,7 +164,7 @@ RSpec.describe "Lettings Log Features" do
select(managing_org1.name, from: "lettings-log-managing-organisation-id-field")
click_button("Save and continue")
visit("lettings-logs/#{log_id}/setup/check-answers")
expect(page).to have_content("Managing agent Managing org 1")
expect(page).to have_content("Managing agent Managing org 1", normalize_ws: true)
end
context "and the owning organisation has 2 or more managing agents" do
@ -183,10 +183,10 @@ RSpec.describe "Lettings Log Features" do
select(managing_org1.name, from: "lettings-log-managing-organisation-id-field")
click_button("Save and continue")
visit("lettings-logs/#{log_id}/setup/check-answers")
expect(page).to have_content("Managing agent Managing org 1")
expect(page).to have_content("Managing agent Managing org 1", normalize_ws: true)
org_rel1.destroy!
visit("lettings-logs/#{log_id}/setup/check-answers")
expect(page).to have_content("Managing agent Managing org 1")
expect(page).to have_content("Managing agent Managing org 1", normalize_ws: true)
expect(support_user.organisation.managing_agents).to eq([org_rel2.child_organisation])
end
end
@ -237,7 +237,7 @@ RSpec.describe "Lettings Log Features" do
log_id = page.current_path.scan(/\d/).join
expect(page).to have_current_path("/lettings-logs/#{log_id}/stock-owner")
visit("lettings-logs/#{log_id}/setup/check-answers")
expect(page).to have_content("Stock owner User org")
expect(page).to have_content("Stock owner User org", normalize_ws: true)
end
context "and there are 3 or more potential stock owners" do
@ -254,10 +254,10 @@ RSpec.describe "Lettings Log Features" do
select(owning_org1.name, from: "lettings-log-owning-organisation-id-field")
click_button("Save and continue")
visit("lettings-logs/#{log_id}/setup/check-answers")
expect(page).to have_content("Stock owner Owning org 1")
expect(page).to have_content("Stock owner Owning org 1", normalize_ws: true)
org_rel1.destroy!
visit("lettings-logs/#{log_id}/setup/check-answers")
expect(page).to have_content("Stock owner Owning org 1")
expect(page).to have_content("Stock owner Owning org 1", normalize_ws: true)
expect(user.organisation.stock_owners).to eq([org_rel2.parent_organisation])
end
end
@ -283,7 +283,8 @@ RSpec.describe "Lettings Log Features" do
select(user.organisation.name, from: "lettings-log-managing-organisation-id-field")
click_button("Save and continue")
visit("lettings-logs/#{log_id}/setup/check-answers")
expect(page).to have_content("Managing agent User org")
expect(page).to have_content("Managing agent User org", normalize_ws: true)
expect(user.organisation.stock_owners).to eq([org_rel1.parent_organisation, org_rel2.parent_organisation])
end
end
@ -328,7 +329,7 @@ RSpec.describe "Lettings Log Features" do
select(managing_org.name, from: "lettings-log-managing-organisation-id-field")
click_button("Save and continue")
visit("lettings-logs/#{log_id}/setup/check-answers")
expect(page).to have_content("Managing agent Managing org")
expect(page).to have_content("Managing agent Managing org", normalize_ws: true)
expect(user.organisation.managing_agents).to eq([org_rel2.child_organisation])
end
end

4
spec/fixtures/files/lettings_logs_download.csv vendored

@ -1,2 +1,2 @@
id,status,created_at,updated_at,created_by_name,is_dpo,owning_organisation_name,managing_organisation_name,collection_start_year,needstype,renewal,startdate,rent_type_detail,irproduct_other,tenancycode,propcode,age1,sex1,ecstat1,hhmemb,relat2,age2,sex2,retirement_value_check,ecstat2,armedforces,leftreg,illness,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_h,is_previous_la_inferred,prevloc_label,prevloc,illness_type_1,illness_type_2,is_la_inferred,la_label,la,postcode_known,postcode_full,previous_la_known,wchair,preg_occ,cbl,earnings,incfreq,net_income_value_check,benefits,hb,period,brent,scharge,pscharge,supcharg,tcharge,offered,layear,ppostcode_full,mrcdate,declaration,ethnic,national,prevten,age3,sex3,ecstat3,age4,sex4,ecstat4,age5,sex5,ecstat5,age6,sex6,ecstat6,age7,sex7,ecstat7,age8,sex8,ecstat8,homeless,underoccupation_benefitcap,reservist,startertenancy,tenancylength,tenancy,rsnvac,unittype_gn,beds,waityear,reasonpref,chr,cap,reasonother,housingneeds_f,housingneeds_g,illness_type_3,illness_type_4,illness_type_8,illness_type_5,illness_type_6,illness_type_7,illness_type_9,illness_type_10,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,tenancyother,property_owner_organisation,property_manager_organisation,purchaser_code,reason,majorrepairs,hbrentshortfall,property_relet,incref,first_time_property_let_as_social_housing,unitletas,builtype,voiddate,renttype,lettype,totchild,totelder,totadult,net_income_known,nocharge,is_carehome,household_charge,referral,tshortfall,chcharge,ppcodenk,age1_known,age2_known,age3_known,age4_known,age5_known,age6_known,age7_known,age8_known,ethnic_group,letting_allocation_unknown,details_known_2,details_known_3,details_known_4,details_known_5,details_known_6,details_known_7,details_known_8,has_benefits,wrent,wscharge,wpschrge,wsupchrg,wtcharge,wtshortfall,refused,housingneeds,wchchrg,newprop,relat3,relat4,relat5,relat6,relat7,relat8,rent_value_check,old_form_id,lar,irproduct,old_id,joint,tshortfall_known,sheltered,pregnancy_value_check,hhtype,new_old,vacdays,major_repairs_date_value_check,void_date_value_check,housingneeds_type,housingneeds_other,unresolved,updated_by_id,unittype_sh,scheme_code,scheme_service_name,scheme_sensitive,scheme_type,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_admin_district,location_startdate
{id},in_progress,2022-02-08 16:52:15 +0000,2022-02-08 16:52:15 +0000,Danny Rojas,No,DLUHC,DLUHC,2021,Supported housing,,2 October 2021,London Affordable Rent,,,,,,,,,,,,,,,,,,,,No,,,,,No,Westminster,E09000033,,SE1 1TE,,No,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,8,0,0,0,,0,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,0,,,,,,,,,,,,,,,,,,,9,1,,,,,,,,6,{scheme_code},{scheme_service_name},{scheme_sensitive},Missing,No,DLUHC,{scheme_primary_client_group},,{scheme_secondary_client_group},{scheme_support_type},{scheme_intended_stay},2021-04-01 00:00:00 +0100,{location_code},SE1 1TE,Downing Street,20,Bungalow,Fitted with equipment and adaptations,Westminster,{location_startdate}
id,status,created_at,updated_at,created_by_name,is_dpo,owning_organisation_name,managing_organisation_name,collection_start_year,needstype,renewal,startdate,rent_type_detail,irproduct_other,tenancycode,propcode,age1,sex1,ecstat1,hhmemb,relat2,age2,sex2,retirement_value_check,ecstat2,armedforces,leftreg,illness,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_h,is_previous_la_inferred,prevloc_label,prevloc,illness_type_1,illness_type_2,is_la_inferred,la_label,la,postcode_known,postcode_full,previous_la_known,wchair,preg_occ,cbl,earnings,incfreq,net_income_value_check,benefits,hb,period,brent,scharge,pscharge,supcharg,tcharge,offered,layear,ppostcode_full,mrcdate,declaration,ethnic,national,prevten,age3,sex3,ecstat3,age4,sex4,ecstat4,age5,sex5,ecstat5,age6,sex6,ecstat6,age7,sex7,ecstat7,age8,sex8,ecstat8,homeless,underoccupation_benefitcap,reservist,startertenancy,tenancylength,tenancy,rsnvac,unittype_gn,beds,waityear,reasonpref,chr,cap,reasonother,housingneeds_f,housingneeds_g,illness_type_3,illness_type_4,illness_type_8,illness_type_5,illness_type_6,illness_type_7,illness_type_9,illness_type_10,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,tenancyother,property_owner_organisation,property_manager_organisation,purchaser_code,reason,majorrepairs,hbrentshortfall,property_relet,incref,first_time_property_let_as_social_housing,unitletas,builtype,voiddate,renttype,lettype,totchild,totelder,totadult,net_income_known,nocharge,is_carehome,household_charge,referral,tshortfall,chcharge,ppcodenk,age1_known,age2_known,age3_known,age4_known,age5_known,age6_known,age7_known,age8_known,ethnic_group,letting_allocation_unknown,details_known_2,details_known_3,details_known_4,details_known_5,details_known_6,details_known_7,details_known_8,has_benefits,wrent,wscharge,wpschrge,wsupchrg,wtcharge,wtshortfall,refused,housingneeds,wchchrg,newprop,relat3,relat4,relat5,relat6,relat7,relat8,rent_value_check,old_form_id,lar,irproduct,old_id,joint,tshortfall_known,sheltered,pregnancy_value_check,hhtype,new_old,vacdays,major_repairs_date_value_check,void_date_value_check,housingneeds_type,housingneeds_other,unresolved,updated_by_id,uprn,uprn_known,uprn_confirmed,address_line1,address_line2,town_or_city,county,unittype_sh,scheme_code,scheme_service_name,scheme_sensitive,scheme_type,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_admin_district,location_startdate
{id},in_progress,2022-02-08 16:52:15 +0000,2022-02-08 16:52:15 +0000,Danny Rojas,No,DLUHC,DLUHC,2021,Supported housing,,2 October 2021,London Affordable Rent,,,,,,,,,,,,,,,,,,,,No,,,,,No,Westminster,E09000033,,SE1 1TE,,No,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,8,0,0,0,,0,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,0,,,,,,,,,,,,,,,,,,,9,1,,,,,,,,,,,,,,,6,{scheme_code},{scheme_service_name},{scheme_sensitive},Missing,No,DLUHC,{scheme_primary_client_group},,{scheme_secondary_client_group},{scheme_support_type},{scheme_intended_stay},2021-04-01 00:00:00 +0100,{location_code},SE1 1TE,Downing Street,20,Bungalow,Fitted with equipment and adaptations,Westminster,{location_startdate}

1 id status created_at updated_at created_by_name is_dpo owning_organisation_name managing_organisation_name collection_start_year needstype renewal startdate rent_type_detail irproduct_other tenancycode propcode age1 sex1 ecstat1 hhmemb relat2 age2 sex2 retirement_value_check ecstat2 armedforces leftreg illness housingneeds_a housingneeds_b housingneeds_c housingneeds_h is_previous_la_inferred prevloc_label prevloc illness_type_1 illness_type_2 is_la_inferred la_label la postcode_known postcode_full previous_la_known wchair preg_occ cbl earnings incfreq net_income_value_check benefits hb period brent scharge pscharge supcharg tcharge offered layear ppostcode_full mrcdate declaration ethnic national prevten age3 sex3 ecstat3 age4 sex4 ecstat4 age5 sex5 ecstat5 age6 sex6 ecstat6 age7 sex7 ecstat7 age8 sex8 ecstat8 homeless underoccupation_benefitcap reservist startertenancy tenancylength tenancy rsnvac unittype_gn beds waityear reasonpref chr cap reasonother housingneeds_f housingneeds_g illness_type_3 illness_type_4 illness_type_8 illness_type_5 illness_type_6 illness_type_7 illness_type_9 illness_type_10 rp_homeless rp_insan_unsat rp_medwel rp_hardship rp_dontknow tenancyother property_owner_organisation property_manager_organisation purchaser_code reason majorrepairs hbrentshortfall property_relet incref first_time_property_let_as_social_housing unitletas builtype voiddate renttype lettype totchild totelder totadult net_income_known nocharge is_carehome household_charge referral tshortfall chcharge ppcodenk age1_known age2_known age3_known age4_known age5_known age6_known age7_known age8_known ethnic_group letting_allocation_unknown details_known_2 details_known_3 details_known_4 details_known_5 details_known_6 details_known_7 details_known_8 has_benefits wrent wscharge wpschrge wsupchrg wtcharge wtshortfall refused housingneeds wchchrg newprop relat3 relat4 relat5 relat6 relat7 relat8 rent_value_check old_form_id lar irproduct old_id joint tshortfall_known sheltered pregnancy_value_check hhtype new_old vacdays major_repairs_date_value_check void_date_value_check housingneeds_type housingneeds_other unresolved updated_by_id uprn uprn_known uprn_confirmed address_line1 address_line2 town_or_city county unittype_sh scheme_code scheme_service_name scheme_sensitive scheme_type 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_admin_district location_startdate
2 {id} in_progress 2022-02-08 16:52:15 +0000 2022-02-08 16:52:15 +0000 Danny Rojas No DLUHC DLUHC 2021 Supported housing 2 October 2021 London Affordable Rent No No Westminster E09000033 SE1 1TE No 2 8 0 0 0 0 0 0 9 1 6 {scheme_code} {scheme_service_name} {scheme_sensitive} Missing No DLUHC {scheme_primary_client_group} {scheme_secondary_client_group} {scheme_support_type} {scheme_intended_stay} 2021-04-01 00:00:00 +0100 {location_code} SE1 1TE Downing Street 20 Bungalow Fitted with equipment and adaptations Westminster {location_startdate}

4
spec/fixtures/files/lettings_logs_download_codes_only.csv vendored

@ -1,2 +1,2 @@
id,status,created_at,updated_at,created_by_name,is_dpo,owning_organisation_name,managing_organisation_name,collection_start_year,needstype,renewal,startdate,rent_type_detail,irproduct_other,tenancycode,propcode,age1,sex1,ecstat1,hhmemb,relat2,age2,sex2,retirement_value_check,ecstat2,armedforces,leftreg,illness,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_h,is_previous_la_inferred,prevloc_label,prevloc,illness_type_1,illness_type_2,is_la_inferred,la_label,la,postcode_known,postcode_full,previous_la_known,wchair,preg_occ,cbl,earnings,incfreq,net_income_value_check,benefits,hb,period,brent,scharge,pscharge,supcharg,tcharge,offered,layear,ppostcode_full,mrcdate,declaration,ethnic,national,prevten,age3,sex3,ecstat3,age4,sex4,ecstat4,age5,sex5,ecstat5,age6,sex6,ecstat6,age7,sex7,ecstat7,age8,sex8,ecstat8,homeless,underoccupation_benefitcap,reservist,startertenancy,tenancylength,tenancy,rsnvac,unittype_gn,beds,waityear,reasonpref,chr,cap,reasonother,housingneeds_f,housingneeds_g,illness_type_3,illness_type_4,illness_type_8,illness_type_5,illness_type_6,illness_type_7,illness_type_9,illness_type_10,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,tenancyother,property_owner_organisation,property_manager_organisation,purchaser_code,reason,majorrepairs,hbrentshortfall,property_relet,incref,first_time_property_let_as_social_housing,unitletas,builtype,voiddate,renttype,lettype,totchild,totelder,totadult,net_income_known,nocharge,is_carehome,household_charge,referral,tshortfall,chcharge,ppcodenk,age1_known,age2_known,age3_known,age4_known,age5_known,age6_known,age7_known,age8_known,ethnic_group,letting_allocation_unknown,details_known_2,details_known_3,details_known_4,details_known_5,details_known_6,details_known_7,details_known_8,has_benefits,wrent,wscharge,wpschrge,wsupchrg,wtcharge,wtshortfall,refused,housingneeds,wchchrg,newprop,relat3,relat4,relat5,relat6,relat7,relat8,rent_value_check,old_form_id,lar,irproduct,old_id,joint,tshortfall_known,sheltered,pregnancy_value_check,hhtype,new_old,vacdays,major_repairs_date_value_check,void_date_value_check,housingneeds_type,housingneeds_other,unresolved,updated_by_id,unittype_sh,scheme_code,scheme_service_name,scheme_sensitive,scheme_type,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_admin_district,location_startdate
{id},in_progress,2022-02-08 16:52:15 +0000,2022-02-08 16:52:15 +0000,Danny Rojas,false,DLUHC,DLUHC,2021,2,,2 October 2021,2,,,,,,,,,,,,,,,,,,,,false,,,,,false,Westminster,E09000033,,SE1 1TE,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,8,0,0,0,,0,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,0,,,,,,,,,,,,,,,,,,,9,1,,,,,,,,6,{scheme_code},{scheme_service_name},{scheme_sensitive},0,1,DLUHC,{scheme_primary_client_group},,{scheme_secondary_client_group},{scheme_support_type},{scheme_intended_stay},2021-04-01 00:00:00 +0100,{location_code},SE1 1TE,Downing Street,20,6,A,Westminster,{location_startdate}
id,status,created_at,updated_at,created_by_name,is_dpo,owning_organisation_name,managing_organisation_name,collection_start_year,needstype,renewal,startdate,rent_type_detail,irproduct_other,tenancycode,propcode,age1,sex1,ecstat1,hhmemb,relat2,age2,sex2,retirement_value_check,ecstat2,armedforces,leftreg,illness,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_h,is_previous_la_inferred,prevloc_label,prevloc,illness_type_1,illness_type_2,is_la_inferred,la_label,la,postcode_known,postcode_full,previous_la_known,wchair,preg_occ,cbl,earnings,incfreq,net_income_value_check,benefits,hb,period,brent,scharge,pscharge,supcharg,tcharge,offered,layear,ppostcode_full,mrcdate,declaration,ethnic,national,prevten,age3,sex3,ecstat3,age4,sex4,ecstat4,age5,sex5,ecstat5,age6,sex6,ecstat6,age7,sex7,ecstat7,age8,sex8,ecstat8,homeless,underoccupation_benefitcap,reservist,startertenancy,tenancylength,tenancy,rsnvac,unittype_gn,beds,waityear,reasonpref,chr,cap,reasonother,housingneeds_f,housingneeds_g,illness_type_3,illness_type_4,illness_type_8,illness_type_5,illness_type_6,illness_type_7,illness_type_9,illness_type_10,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,tenancyother,property_owner_organisation,property_manager_organisation,purchaser_code,reason,majorrepairs,hbrentshortfall,property_relet,incref,first_time_property_let_as_social_housing,unitletas,builtype,voiddate,renttype,lettype,totchild,totelder,totadult,net_income_known,nocharge,is_carehome,household_charge,referral,tshortfall,chcharge,ppcodenk,age1_known,age2_known,age3_known,age4_known,age5_known,age6_known,age7_known,age8_known,ethnic_group,letting_allocation_unknown,details_known_2,details_known_3,details_known_4,details_known_5,details_known_6,details_known_7,details_known_8,has_benefits,wrent,wscharge,wpschrge,wsupchrg,wtcharge,wtshortfall,refused,housingneeds,wchchrg,newprop,relat3,relat4,relat5,relat6,relat7,relat8,rent_value_check,old_form_id,lar,irproduct,old_id,joint,tshortfall_known,sheltered,pregnancy_value_check,hhtype,new_old,vacdays,major_repairs_date_value_check,void_date_value_check,housingneeds_type,housingneeds_other,unresolved,updated_by_id,uprn,uprn_known,uprn_confirmed,address_line1,address_line2,town_or_city,county,unittype_sh,scheme_code,scheme_service_name,scheme_sensitive,scheme_type,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_admin_district,location_startdate
{id},in_progress,2022-02-08 16:52:15 +0000,2022-02-08 16:52:15 +0000,Danny Rojas,false,DLUHC,DLUHC,2021,2,,2 October 2021,2,,,,,,,,,,,,,,,,,,,,false,,,,,false,Westminster,E09000033,,SE1 1TE,,2,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2,8,0,0,0,,0,,,,,,,,,,,,,,,,,,,,,,,,0,,,,,,,0,,,,,,,,,,,,,,,,,,,9,1,,,,,,,,,,,,,,,6,{scheme_code},{scheme_service_name},{scheme_sensitive},0,1,DLUHC,{scheme_primary_client_group},,{scheme_secondary_client_group},{scheme_support_type},{scheme_intended_stay},2021-04-01 00:00:00 +0100,{location_code},SE1 1TE,Downing Street,20,6,A,Westminster,{location_startdate}

1 id status created_at updated_at created_by_name is_dpo owning_organisation_name managing_organisation_name collection_start_year needstype renewal startdate rent_type_detail irproduct_other tenancycode propcode age1 sex1 ecstat1 hhmemb relat2 age2 sex2 retirement_value_check ecstat2 armedforces leftreg illness housingneeds_a housingneeds_b housingneeds_c housingneeds_h is_previous_la_inferred prevloc_label prevloc illness_type_1 illness_type_2 is_la_inferred la_label la postcode_known postcode_full previous_la_known wchair preg_occ cbl earnings incfreq net_income_value_check benefits hb period brent scharge pscharge supcharg tcharge offered layear ppostcode_full mrcdate declaration ethnic national prevten age3 sex3 ecstat3 age4 sex4 ecstat4 age5 sex5 ecstat5 age6 sex6 ecstat6 age7 sex7 ecstat7 age8 sex8 ecstat8 homeless underoccupation_benefitcap reservist startertenancy tenancylength tenancy rsnvac unittype_gn beds waityear reasonpref chr cap reasonother housingneeds_f housingneeds_g illness_type_3 illness_type_4 illness_type_8 illness_type_5 illness_type_6 illness_type_7 illness_type_9 illness_type_10 rp_homeless rp_insan_unsat rp_medwel rp_hardship rp_dontknow tenancyother property_owner_organisation property_manager_organisation purchaser_code reason majorrepairs hbrentshortfall property_relet incref first_time_property_let_as_social_housing unitletas builtype voiddate renttype lettype totchild totelder totadult net_income_known nocharge is_carehome household_charge referral tshortfall chcharge ppcodenk age1_known age2_known age3_known age4_known age5_known age6_known age7_known age8_known ethnic_group letting_allocation_unknown details_known_2 details_known_3 details_known_4 details_known_5 details_known_6 details_known_7 details_known_8 has_benefits wrent wscharge wpschrge wsupchrg wtcharge wtshortfall refused housingneeds wchchrg newprop relat3 relat4 relat5 relat6 relat7 relat8 rent_value_check old_form_id lar irproduct old_id joint tshortfall_known sheltered pregnancy_value_check hhtype new_old vacdays major_repairs_date_value_check void_date_value_check housingneeds_type housingneeds_other unresolved updated_by_id uprn uprn_known uprn_confirmed address_line1 address_line2 town_or_city county unittype_sh scheme_code scheme_service_name scheme_sensitive scheme_type 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_admin_district location_startdate
2 {id} in_progress 2022-02-08 16:52:15 +0000 2022-02-08 16:52:15 +0000 Danny Rojas false DLUHC DLUHC 2021 2 2 October 2021 2 false false Westminster E09000033 SE1 1TE 2 2 8 0 0 0 0 0 0 9 1 6 {scheme_code} {scheme_service_name} {scheme_sensitive} 0 1 DLUHC {scheme_primary_client_group} {scheme_secondary_client_group} {scheme_support_type} {scheme_intended_stay} 2021-04-01 00:00:00 +0100 {location_code} SE1 1TE Downing Street 20 6 A Westminster {location_startdate}

4
spec/fixtures/files/lettings_logs_download_non_support.csv vendored

@ -1,2 +1,2 @@
id,status,created_at,updated_at,created_by_name,is_dpo,owning_organisation_name,managing_organisation_name,collection_start_year,renewal,startdate,irproduct_other,tenancycode,propcode,age1,sex1,ecstat1,relat2,age2,sex2,ecstat2,armedforces,leftreg,illness,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_h,prevloc_label,illness_type_1,illness_type_2,la_label,postcode_full,wchair,preg_occ,cbl,earnings,incfreq,benefits,hb,period,brent,scharge,pscharge,supcharg,tcharge,offered,layear,ppostcode_full,mrcdate,declaration,ethnic,national,prevten,age3,sex3,ecstat3,age4,sex4,ecstat4,age5,sex5,ecstat5,age6,sex6,ecstat6,age7,sex7,ecstat7,age8,sex8,ecstat8,homeless,underoccupation_benefitcap,reservist,startertenancy,tenancylength,tenancy,rsnvac,unittype_gn,beds,waityear,reasonpref,chr,cap,reasonother,housingneeds_f,housingneeds_g,illness_type_3,illness_type_4,illness_type_8,illness_type_5,illness_type_6,illness_type_7,illness_type_9,illness_type_10,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,tenancyother,property_owner_organisation,property_manager_organisation,purchaser_code,reason,majorrepairs,hbrentshortfall,property_relet,incref,unitletas,builtype,voiddate,lettype,nocharge,household_charge,referral,tshortfall,chcharge,ppcodenk,ethnic_group,has_benefits,refused,housingneeds,wchchrg,newprop,relat3,relat4,relat5,relat6,relat7,relat8,lar,irproduct,joint,sheltered,major_repairs_date_value_check,void_date_value_check,housingneeds_type,housingneeds_other,unittype_sh,scheme_code,scheme_service_name,scheme_sensitive,scheme_type,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_admin_district,location_startdate
{id},in_progress,2022-02-08 16:52:15 +0000,2022-02-08 16:52:15 +0000,Danny Rojas,No,DLUHC,DLUHC,2021,,2 October 2021,,,,,,,,,,,,,,,,,,,,,Westminster,SE1 1TE,No,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,8,0,,,,,,,0,0,,,,,,,,,,,,,,,,,,6,{scheme_code},{scheme_service_name},{scheme_sensitive},Missing,No,DLUHC,{scheme_primary_client_group},,{scheme_secondary_client_group},{scheme_support_type},{scheme_intended_stay},2021-04-01 00:00:00 +0100,{location_code},SE1 1TE,Downing Street,20,Bungalow,Fitted with equipment and adaptations,Westminster,{location_startdate}
id,status,created_at,updated_at,created_by_name,is_dpo,owning_organisation_name,managing_organisation_name,collection_start_year,renewal,startdate,irproduct_other,tenancycode,propcode,age1,sex1,ecstat1,relat2,age2,sex2,ecstat2,armedforces,leftreg,illness,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_h,prevloc_label,illness_type_1,illness_type_2,la_label,postcode_full,wchair,preg_occ,cbl,earnings,incfreq,benefits,hb,period,brent,scharge,pscharge,supcharg,tcharge,offered,layear,ppostcode_full,mrcdate,declaration,ethnic,national,prevten,age3,sex3,ecstat3,age4,sex4,ecstat4,age5,sex5,ecstat5,age6,sex6,ecstat6,age7,sex7,ecstat7,age8,sex8,ecstat8,homeless,underoccupation_benefitcap,reservist,startertenancy,tenancylength,tenancy,rsnvac,unittype_gn,beds,waityear,reasonpref,chr,cap,reasonother,housingneeds_f,housingneeds_g,illness_type_3,illness_type_4,illness_type_8,illness_type_5,illness_type_6,illness_type_7,illness_type_9,illness_type_10,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,tenancyother,property_owner_organisation,property_manager_organisation,purchaser_code,reason,majorrepairs,hbrentshortfall,property_relet,incref,unitletas,builtype,voiddate,lettype,nocharge,household_charge,referral,tshortfall,chcharge,ppcodenk,ethnic_group,has_benefits,refused,housingneeds,wchchrg,newprop,relat3,relat4,relat5,relat6,relat7,relat8,lar,irproduct,joint,sheltered,major_repairs_date_value_check,void_date_value_check,housingneeds_type,housingneeds_other,uprn,uprn_known,uprn_confirmed,address_line1,address_line2,town_or_city,county,unittype_sh,scheme_code,scheme_service_name,scheme_sensitive,scheme_type,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_admin_district,location_startdate
{id},in_progress,2022-02-08 16:52:15 +0000,2022-02-08 16:52:15 +0000,Danny Rojas,No,DLUHC,DLUHC,2021,,2 October 2021,,,,,,,,,,,,,,,,,,,,,Westminster,SE1 1TE,No,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,8,0,,,,,,,0,0,,,,,,,,,,,,,,,,,,,,,,,,,6,{scheme_code},{scheme_service_name},{scheme_sensitive},Missing,No,DLUHC,{scheme_primary_client_group},,{scheme_secondary_client_group},{scheme_support_type},{scheme_intended_stay},2021-04-01 00:00:00 +0100,{location_code},SE1 1TE,Downing Street,20,Bungalow,Fitted with equipment and adaptations,Westminster,{location_startdate}

1 id status created_at updated_at created_by_name is_dpo owning_organisation_name managing_organisation_name collection_start_year renewal startdate irproduct_other tenancycode propcode age1 sex1 ecstat1 relat2 age2 sex2 ecstat2 armedforces leftreg illness housingneeds_a housingneeds_b housingneeds_c housingneeds_h prevloc_label illness_type_1 illness_type_2 la_label postcode_full wchair preg_occ cbl earnings incfreq benefits hb period brent scharge pscharge supcharg tcharge offered layear ppostcode_full mrcdate declaration ethnic national prevten age3 sex3 ecstat3 age4 sex4 ecstat4 age5 sex5 ecstat5 age6 sex6 ecstat6 age7 sex7 ecstat7 age8 sex8 ecstat8 homeless underoccupation_benefitcap reservist startertenancy tenancylength tenancy rsnvac unittype_gn beds waityear reasonpref chr cap reasonother housingneeds_f housingneeds_g illness_type_3 illness_type_4 illness_type_8 illness_type_5 illness_type_6 illness_type_7 illness_type_9 illness_type_10 rp_homeless rp_insan_unsat rp_medwel rp_hardship rp_dontknow tenancyother property_owner_organisation property_manager_organisation purchaser_code reason majorrepairs hbrentshortfall property_relet incref unitletas builtype voiddate lettype nocharge household_charge referral tshortfall chcharge ppcodenk ethnic_group has_benefits refused housingneeds wchchrg newprop relat3 relat4 relat5 relat6 relat7 relat8 lar irproduct joint sheltered major_repairs_date_value_check void_date_value_check housingneeds_type housingneeds_other uprn uprn_known uprn_confirmed address_line1 address_line2 town_or_city county unittype_sh scheme_code scheme_service_name scheme_sensitive scheme_type 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_admin_district location_startdate
2 {id} in_progress 2022-02-08 16:52:15 +0000 2022-02-08 16:52:15 +0000 Danny Rojas No DLUHC DLUHC 2021 2 October 2021 Westminster SE1 1TE No 8 0 0 0 6 {scheme_code} {scheme_service_name} {scheme_sensitive} Missing No DLUHC {scheme_primary_client_group} {scheme_secondary_client_group} {scheme_support_type} {scheme_intended_stay} 2021-04-01 00:00:00 +0100 {location_code} SE1 1TE Downing Street 20 Bungalow Fitted with equipment and adaptations Westminster {location_startdate}

26
spec/helpers/question_view_helper_spec.rb

@ -44,10 +44,16 @@ RSpec.describe QuestionViewHelper do
describe "legend" do
subject(:question_view_helper) { legend(question, page_header, conditional) }
question_stub = Struct.new(:header) do
let(:question_stub) do
Struct.new(:header) do
def question_number_string(_conditional)
nil
end
def plain_label
nil
end
end
end
let(:question) { question_stub.new("Some question header") }
@ -81,5 +87,23 @@ RSpec.describe QuestionViewHelper do
expect(question_view_helper).to eq(legend_options_hash)
end
end
context "when viewing a question with a plain label" do
let(:question_stub) do
Struct.new(:header) do
def question_number_string(_conditional)
nil
end
def plain_label
true
end
end
end
it "returns an options hash with nil size" do
expect(question_view_helper).to eq({ size: nil, tag: "div", text: "Some question header" })
end
end
end
end

73
spec/models/form/sales/pages/address_spec.rb

@ -0,0 +1,73 @@
require "rails_helper"
RSpec.describe Form::Sales::Pages::Address, type: :model do
subject(:page) { described_class.new(page_id, page_definition, subsection) }
let(:page_id) { nil }
let(:page_definition) { nil }
let(:subsection) { instance_double(Form::Subsection) }
it "has correct subsection" do
expect(page.subsection).to eq(subsection)
end
it "has correct questions" do
expect(page.questions.map(&:id)).to eq(%w[address_line1 address_line2 town_or_city county postcode_full])
end
it "has the correct id" do
expect(page.id).to eq("address")
end
it "has the correct header" do
expect(page.header).to eq("What is the property's address?")
end
it "has the correct description" do
expect(page.description).to be_nil
end
it "has correct depends_on" do
expect(page.depends_on).to be_nil
end
describe "has correct routed_to?" do
context "when uprn_known == nil" do
let(:log) { create(:sales_log, uprn_known: nil) }
it "returns false" do
expect(page.routed_to?(log)).to eq(false)
end
end
context "when uprn_confirmed != 1" do
let(:log) do
create(:sales_log, uprn_known: 1, uprn_confirmed: 0)
end
it "returns true" do
expect(page.routed_to?(log)).to eq(true)
end
end
context "when uprn_known == 0" do
let(:log) do
create(:sales_log, uprn_known: 0, uprn_confirmed: 0)
end
it "returns true" do
expect(page.routed_to?(log)).to eq(true)
end
end
context "when uprn_confirmed == 1 && uprn_known != 0" do
let(:log) do
create(:sales_log, uprn_known: 1, uprn_confirmed: 1)
end
it "returns true" do
expect(page.routed_to?(log)).to eq(false)
end
end
end
end

47
spec/models/form/sales/pages/property_local_authority_spec.rb

@ -12,6 +12,10 @@ RSpec.describe Form::Sales::Pages::PropertyLocalAuthority, type: :model do
expect(page.subsection).to eq(subsection)
end
describe "has correct questions" do
context "when 2022" do
let(:start_date) { Time.utc(2022, 2, 8) }
it "has correct questions" do
expect(page.questions.map(&:id)).to eq(
%w[
@ -20,6 +24,20 @@ RSpec.describe Form::Sales::Pages::PropertyLocalAuthority, type: :model do
],
)
end
end
context "when 2023" do
let(:start_date) { Time.utc(2023, 2, 8) }
it "has correct questions" do
expect(page.questions.map(&:id)).to eq(
%w[
la
],
)
end
end
end
it "has the correct id" do
expect(page.id).to eq("property_local_authority")
@ -38,4 +56,33 @@ RSpec.describe Form::Sales::Pages::PropertyLocalAuthority, type: :model do
"is_la_inferred" => false,
}])
end
describe "has correct routed_to?" do
context "when start_date < 2023" do
let(:log) { create(:sales_log, uprn_known: 1) }
let(:start_date) { Time.utc(2022, 2, 8) }
it "returns false" do
expect(page.routed_to?(log)).to eq(true)
end
end
context "when start_date >= 2023" do
let(:log) { create(:sales_log, uprn_known: 1) }
let(:start_date) { Time.utc(2023, 2, 8) }
it "returns true" do
expect(page.routed_to?(log)).to eq(true)
end
end
context "when start_date < 2023 and uprn_known: nil" do
let(:log) { create(:sales_log, uprn_known: nil) }
let(:start_date) { Time.utc(2023, 2, 8) }
it "returns true" do
expect(page.routed_to?(log)).to eq(false)
end
end
end
end

59
spec/models/form/sales/pages/uprn_confirmation_spec.rb

@ -0,0 +1,59 @@
require "rails_helper"
RSpec.describe Form::Sales::Pages::UprnConfirmation, type: :model do
subject(:page) { described_class.new(page_id, page_definition, subsection) }
let(:page_id) { nil }
let(:page_definition) { nil }
let(:subsection) { instance_double(Form::Subsection) }
it "has correct subsection" do
expect(page.subsection).to eq(subsection)
end
it "has correct questions" do
expect(page.questions.map(&:id)).to eq(%w[uprn_confirmed])
end
it "has the correct id" do
expect(page.id).to eq("uprn_confirmation")
end
it "has the correct header" do
expect(page.header).to eq("We found an address that might be this property")
end
it "has the correct description" do
expect(page.description).to be_nil
end
it "has correct depends_on" do
expect(page.depends_on).to be_nil
end
describe "has correct routed_to?" do
context "when uprn present && uprn_known == 1 " do
let(:log) { create(:sales_log, uprn_known: 1, uprn: "123456789") }
it "returns true" do
expect(page.routed_to?(log)).to eq(true)
end
end
context "when uprn = nil" do
let(:log) { create(:sales_log, uprn_known: 1, uprn: nil) }
it "returns false" do
expect(page.routed_to?(log)).to eq(false)
end
end
context "when uprn_known == 0" do
let(:log) { create(:sales_log, uprn_known: 0, uprn: "123456789") }
it "returns false" do
expect(page.routed_to?(log)).to eq(false)
end
end
end
end

33
spec/models/form/sales/pages/uprn_known_spec.rb

@ -0,0 +1,33 @@
require "rails_helper"
RSpec.describe Form::Sales::Pages::UprnKnown, type: :model do
subject(:page) { described_class.new(page_id, page_definition, subsection) }
let(:page_id) { nil }
let(:page_definition) { nil }
let(:subsection) { instance_double(Form::Subsection) }
it "has correct subsection" do
expect(page.subsection).to eq(subsection)
end
it "has correct questions" do
expect(page.questions.map(&:id)).to eq(%w[uprn_known])
end
it "has the correct id" do
expect(page.id).to eq("uprn_known")
end
it "has the correct header" do
expect(page.header).to be_nil
end
it "has the correct description" do
expect(page.description).to be_nil
end
it "has correct depends_on" do
expect(page.depends_on).to be_nil
end
end

73
spec/models/form/sales/pages/uprn_spec.rb

@ -0,0 +1,73 @@
require "rails_helper"
RSpec.describe Form::Sales::Pages::Uprn, type: :model do
subject(:page) { described_class.new(page_id, page_definition, subsection) }
let(:page_id) { nil }
let(:page_definition) { nil }
let(:subsection) { instance_double(Form::Subsection) }
it "has correct subsection" do
expect(page.subsection).to eq(subsection)
end
it "has correct questions" do
expect(page.questions.map(&:id)).to eq(%w[uprn])
end
it "has the correct id" do
expect(page.id).to eq("uprn")
end
it "has the correct header" do
expect(page.header).to be_nil
end
it "has the correct description" do
expect(page.description).to be_nil
end
it "has correct depends_on" do
expect(page.depends_on).to be_nil
end
it "has correct skip_text" do
expect(page.skip_text).to eq("Enter address instead")
end
describe "has correct routed_to?" do
context "when uprn_known != 1" do
let(:log) { create(:sales_log, uprn_known: 0) }
it "returns false" do
expect(page.routed_to?(log)).to eq(false)
end
end
context "when uprn_known == 1" do
let(:log) { create(:sales_log, uprn_known: 1) }
it "returns true" do
expect(page.routed_to?(log)).to eq(true)
end
end
end
describe "has correct skip_href" do
context "when log is nil" do
it "is nil" do
expect(page.skip_href).to be_nil
end
end
context "when log is present" do
let(:log) { create(:sales_log) }
it "points to address page" do
expect(page.skip_href(log)).to eq(
"/sales-logs/#{log.id}/address",
)
end
end
end
end

75
spec/models/form/sales/questions/address_line1_spec.rb

@ -0,0 +1,75 @@
require "rails_helper"
RSpec.describe Form::Sales::Questions::AddressLine1, type: :model do
subject(:question) { described_class.new(question_id, question_definition, page) }
let(:question_id) { nil }
let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) }
it "has correct page" do
expect(question.page).to eq(page)
end
it "has the correct id" do
expect(question.id).to eq("address_line1")
end
it "has the correct header" do
expect(question.header).to eq("Address line 1")
end
it "has the correct check_answer_label" do
expect(question.check_answer_label).to eq("Address")
end
it "has the correct type" do
expect(question.type).to eq("text")
end
it "is not marked as derived" do
expect(question.derived?).to be false
end
it "has the correct hint" do
expect(question.hint_text).to be_nil
end
it "has the correct inferred check answers value" do
expect(question.inferred_check_answers_value).to be_nil
end
it "has the correct check_answers_card_number" do
expect(question.check_answers_card_number).to be_nil
end
describe "has the correct get_extra_check_answer_value" do
context "when la is not present" do
let(:log) { create(:sales_log, la: nil) }
it "returns nil" do
expect(question.get_extra_check_answer_value(log)).to be_nil
end
end
context "when la is present but not inferred" do
let(:log) { create(:sales_log, la: "E09000003", is_la_inferred: false) }
it "returns nil" do
expect(question.get_extra_check_answer_value(log)).to be_nil
end
end
context "when la is present but inferred" do
let(:log) { create(:sales_log, la: "E09000003") }
before do
allow(log).to receive(:is_la_inferred?).and_return(true)
end
it "returns the la" do
expect(question.get_extra_check_answer_value(log)).to eq("Barnet")
end
end
end
end

49
spec/models/form/sales/questions/address_line2_spec.rb

@ -0,0 +1,49 @@
require "rails_helper"
RSpec.describe Form::Sales::Questions::AddressLine2, type: :model do
subject(:question) { described_class.new(question_id, question_definition, page) }
let(:question_id) { nil }
let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) }
it "has correct page" do
expect(question.page).to eq(page)
end
it "has the correct id" do
expect(question.id).to eq("address_line2")
end
it "has the correct header" do
expect(question.header).to eq("Address line 2 (optional)")
end
it "has the correct check_answer_label" do
expect(question.check_answer_label).to be_nil
end
it "has the correct type" do
expect(question.type).to eq("text")
end
it "is not marked as derived" do
expect(question.derived?).to be false
end
it "has the correct hint" do
expect(question.hint_text).to be_nil
end
it "has the correct inferred check answers value" do
expect(question.inferred_check_answers_value).to be_nil
end
it "has the correct check_answers_card_number" do
expect(question.check_answers_card_number).to be_nil
end
it "has the correct hidden_in_check_answers" do
expect(question.hidden_in_check_answers?).to eq(true)
end
end

49
spec/models/form/sales/questions/county_spec.rb

@ -0,0 +1,49 @@
require "rails_helper"
RSpec.describe Form::Sales::Questions::County, type: :model do
subject(:question) { described_class.new(question_id, question_definition, page) }
let(:question_id) { nil }
let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) }
it "has correct page" do
expect(question.page).to eq(page)
end
it "has the correct id" do
expect(question.id).to eq("county")
end
it "has the correct header" do
expect(question.header).to eq("County (optional)")
end
it "has the correct check_answer_label" do
expect(question.check_answer_label).to be_nil
end
it "has the correct type" do
expect(question.type).to eq("text")
end
it "is not marked as derived" do
expect(question.derived?).to be false
end
it "has the correct hint" do
expect(question.hint_text).to be_nil
end
it "has the correct inferred check answers value" do
expect(question.inferred_check_answers_value).to be_nil
end
it "has the correct check_answers_card_number" do
expect(question.check_answers_card_number).to be_nil
end
it "has the correct hidden_in_check_answers" do
expect(question.hidden_in_check_answers?).to eq(true)
end
end

62
spec/models/form/sales/questions/postcode_for_full_address_spec.rb

@ -0,0 +1,62 @@
require "rails_helper"
RSpec.describe Form::Sales::Questions::PostcodeForFullAddress, type: :model do
subject(:question) { described_class.new(question_id, question_definition, page) }
let(:question_id) { nil }
let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) }
it "has correct page" do
expect(question.page).to eq(page)
end
it "has the correct id" do
expect(question.id).to eq("postcode_full")
end
it "has the correct header" do
expect(question.header).to eq("Postcode")
end
it "has the correct check_answer_label" do
expect(question.check_answer_label).to be_nil
end
it "has the correct type" do
expect(question.type).to eq("text")
end
it "is not marked as derived" do
expect(question.derived?).to be false
end
it "has the correct hint" do
expect(question.hint_text).to be_nil
end
it "has the correct width" do
expect(question.width).to eq(5)
end
it "has the correct inferred_answers" do
expect(question.inferred_answers).to eq({
"la" => {
"is_la_inferred" => true,
},
})
end
it "has the correct inferred_check_answers_value" do
expect(question.inferred_check_answers_value).to eq([{
"condition" => {
"pcodenk" => 1,
},
"value" => "Not known",
}])
end
it "has the correct hidden_in_check_answers" do
expect(question.hidden_in_check_answers?).to eq(true)
end
end

30
spec/models/form/sales/questions/property_local_authority_spec.rb

@ -667,4 +667,34 @@ RSpec.describe Form::Sales::Questions::PropertyLocalAuthority, type: :model do
})
end
end
describe "has the correct hidden_in_check_answers" do
context "when saledate.year before 2023" do
let(:log) { build(:sales_log, saledate: Time.zone.parse("2022-07-01")) }
it "returns false" do
expect(question.hidden_in_check_answers?(log)).to eq(false)
end
end
context "when saledate.year >= 2023" do
let(:log) { build(:sales_log, saledate: Time.zone.parse("2023-07-01")) }
it "returns true" do
expect(question.hidden_in_check_answers?(log)).to eq(false)
end
end
context "when saledate.year >= 2023 and la inferred" do
let(:log) { build(:sales_log, saledate: Time.zone.parse("2023-07-01")) }
before do
allow(log).to receive(:is_la_inferred?).and_return(true)
end
it "returns true" do
expect(question.hidden_in_check_answers?(log)).to eq(true)
end
end
end
end

49
spec/models/form/sales/questions/town_or_city_spec.rb

@ -0,0 +1,49 @@
require "rails_helper"
RSpec.describe Form::Sales::Questions::TownOrCity, type: :model do
subject(:question) { described_class.new(question_id, question_definition, page) }
let(:question_id) { nil }
let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) }
it "has correct page" do
expect(question.page).to eq(page)
end
it "has the correct id" do
expect(question.id).to eq("town_or_city")
end
it "has the correct header" do
expect(question.header).to eq("Town or city")
end
it "has the correct check_answer_label" do
expect(question.check_answer_label).to be_nil
end
it "has the correct type" do
expect(question.type).to eq("text")
end
it "is not marked as derived" do
expect(question.derived?).to be false
end
it "has the correct hint" do
expect(question.hint_text).to be_nil
end
it "has the correct inferred check answers value" do
expect(question.inferred_check_answers_value).to be_nil
end
it "has the correct check_answers_card_number" do
expect(question.check_answers_card_number).to be_nil
end
it "has the correct hidden_in_check_answers" do
expect(question.hidden_in_check_answers?).to eq(true)
end
end

90
spec/models/form/sales/questions/uprn_confirmation_spec.rb

@ -0,0 +1,90 @@
require "rails_helper"
RSpec.describe Form::Sales::Questions::UprnConfirmation, type: :model do
subject(:question) { described_class.new(question_id, question_definition, page) }
let(:question_id) { nil }
let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) }
it "has correct page" do
expect(question.page).to eq(page)
end
it "has the correct id" do
expect(question.id).to eq("uprn_confirmed")
end
it "has the correct header" do
expect(question.header).to eq("Is this the property address?")
end
it "has the correct check_answer_label" do
expect(question.check_answer_label).to eq("Is this the right address?")
end
it "has the correct type" do
expect(question.type).to eq("radio")
end
it "is not marked as derived" do
expect(question.derived?).to be false
end
it "has the correct hint" do
expect(question.hint_text).to be_nil
end
it "has the correct unanswered_error_message" do
expect(question.unanswered_error_message).to eq("You must answer is this the right address?")
end
describe "notification_banner" do
context "when address is not present" do
it "returns nil" do
log = create(:sales_log)
expect(question.notification_banner(log)).to be_nil
end
end
context "when address is present" do
it "returns formatted value" do
log = create(:sales_log, address_line1: "1, Test Street", town_or_city: "Test Town", county: "Test County", postcode_full: "AA1 1AA", uprn: "1234")
expect(question.notification_banner(log)).to eq(
{
heading: "1, Test Street\nAA1 1AA\nTest Town\nTest County",
title: "UPRN: 1234",
},
)
end
end
end
describe "has the correct hidden_in_check_answers" do
context "when uprn_known != 1 && uprn_confirmed == nil" do
let(:log) { create(:sales_log, uprn_known: 0, uprn_confirmed: nil) }
it "returns true" do
expect(question.hidden_in_check_answers?(log)).to eq(true)
end
end
context "when uprn_known == 1 && uprn_confirmed == nil" do
let(:log) { create(:sales_log, uprn_known: 1, uprn_confirmed: nil) }
it "returns false" do
expect(question.hidden_in_check_answers?(log)).to eq(false)
end
end
context "when uprn_known != 1 && uprn_confirmed == 1" do
let(:log) { create(:sales_log, uprn_known: 1, uprn_confirmed: 1) }
it "returns true" do
expect(question.hidden_in_check_answers?(log)).to eq(true)
end
end
end
end

59
spec/models/form/sales/questions/uprn_known_spec.rb

@ -0,0 +1,59 @@
require "rails_helper"
RSpec.describe Form::Sales::Questions::UprnKnown, type: :model do
subject(:question) { described_class.new(question_id, question_definition, page) }
let(:question_id) { nil }
let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) }
it "has correct page" do
expect(question.page).to eq(page)
end
it "has the correct id" do
expect(question.id).to eq("uprn_known")
end
it "has the correct header" do
expect(question.header).to eq("Do you know the property UPRN?")
end
it "has the correct check_answer_label" do
expect(question.check_answer_label).to eq("UPRN known?")
end
it "has the correct type" do
expect(question.type).to eq("radio")
end
it "is not marked as derived" do
expect(question.derived?).to be false
end
it "has the correct answer_options" do
expect(question.answer_options).to eq({
"0" => { "value" => "No" },
"1" => { "value" => "Yes" },
})
end
it "has correct conditional for" do
expect(question.conditional_for).to be_nil
end
it "has the correct unanswered_error_message" do
expect(question.unanswered_error_message).to eq("You must answer UPRN known?")
end
it "has the correct hint" do
expect(question.hint_text).to eq(
"The Unique Property Reference Number (UPRN) is a unique number system created by Ordnance Survey and used by housing providers and sectors UK-wide. For example 10010457355.<br><br>
You can continue without the UPRN, but it means we will need you to enter the address of the property.",
)
end
it "has the correct hidden_in_check_answers" do
expect(question.hidden_in_check_answers).to be_nil
end
end

88
spec/models/form/sales/questions/uprn_spec.rb

@ -0,0 +1,88 @@
require "rails_helper"
RSpec.describe Form::Sales::Questions::Uprn, type: :model do
subject(:question) { described_class.new(question_id, question_definition, page) }
let(:question_id) { nil }
let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) }
it "has correct page" do
expect(question.page).to eq(page)
end
it "has the correct id" do
expect(question.id).to eq("uprn")
end
it "has the correct header" do
expect(question.header).to eq("What is the property's UPRN")
end
it "has the correct check_answer_label" do
expect(question.check_answer_label).to eq("UPRN")
end
it "has the correct type" do
expect(question.type).to eq("text")
end
it "is not marked as derived" do
expect(question.derived?).to be false
end
it "has the correct hint" do
expect(question.hint_text).to eq("The Unique Property Reference Number (UPRN) is a unique number system created by Ordnance Survey and used by housing providers and sectors UK-wide. For example 10010457355.")
end
it "has the correct unanswered_error_message" do
expect(question.unanswered_error_message).to eq("UPRN must be 12 digits or less")
end
describe "get_extra_check_answer_value" do
context "when address is not present" do
let(:log) { create(:sales_log) }
it "returns nil" do
expect(question.get_extra_check_answer_value(log)).to be_nil
end
end
context "when address is present" do
let(:log) do
create(
:sales_log,
address_line1: "1, Test Street",
town_or_city: "Test Town",
county: "Test County",
postcode_full: "AA1 1AA",
la: "E09000003",
)
end
it "returns formatted value" do
expect(question.get_extra_check_answer_value(log)).to eq(
"\n\n1, Test Street\nTest Town\nTest County\nAA1 1AA\nWestminster",
)
end
end
end
describe "has the correct hidden_in_check_answers" do
context "when uprn_known == 1" do
let(:log) { create(:sales_log, uprn_known: 1) }
it "returns false" do
expect(question.hidden_in_check_answers?(log)).to eq(false)
end
end
context "when uprn_known != 1" do
let(:log) { create(:sales_log, uprn_known: 0) }
it "returns false" do
expect(question.hidden_in_check_answers?(log)).to eq(true)
end
end
end
end

33
spec/models/form/sales/subsections/property_information_spec.rb

@ -11,8 +11,14 @@ RSpec.describe Form::Sales::Subsections::PropertyInformation, type: :model do
expect(property_information.section).to eq(section)
end
describe "pages" do
let(:section) { instance_double(Form::Sales::Sections::Household, form: instance_double(Form, start_date:)) }
context "when 2022" do
let(:start_date) { Time.utc(2022, 2, 8) }
it "has correct pages" do
expect(property_information.pages.map(&:id)).to eq(
expect(property_information.pages.compact.map(&:id)).to eq(
%w[
property_number_of_bedrooms
about_price_bedrooms_value_check
@ -26,6 +32,31 @@ RSpec.describe Form::Sales::Subsections::PropertyInformation, type: :model do
],
)
end
end
context "when 2023" do
let(:start_date) { Time.utc(2023, 2, 8) }
it "has correct pages" do
expect(property_information.pages.map(&:id)).to eq(
%w[
uprn_known
uprn
uprn_confirmation
address
property_local_authority
property_number_of_bedrooms
about_price_bedrooms_value_check
property_unit_type
monthly_charges_property_type_value_check
property_building_type
about_price_la_value_check
property_wheelchair_accessible
],
)
end
end
end
it "has the correct id" do
expect(property_information.id).to eq("property_information")

165
spec/models/lettings_log_spec.rb

@ -2,8 +2,8 @@ require "rails_helper"
require "shared/shared_examples_for_derived_fields"
RSpec.describe LettingsLog do
let(:different_managing_organisation) { FactoryBot.create(:organisation) }
let(:created_by_user) { FactoryBot.create(:user) }
let(:different_managing_organisation) { create(:organisation) }
let(:created_by_user) { create(:user) }
let(:owning_organisation) { created_by_user.organisation }
let(:fake_2021_2022_form) { Form.new("spec/fixtures/forms/2021_2022.json") }
@ -19,19 +19,19 @@ RSpec.describe LettingsLog do
end
it "is a not a sales log" do
lettings_log = FactoryBot.build(:lettings_log, created_by: created_by_user)
lettings_log = build(:lettings_log, created_by: created_by_user)
expect(lettings_log.sales?).to be false
end
it "is a lettings log" do
lettings_log = FactoryBot.build(:lettings_log, created_by: created_by_user)
lettings_log = build(:lettings_log, created_by: created_by_user)
expect(lettings_log).to be_lettings
end
describe "#form" do
let(:lettings_log) { FactoryBot.build(:lettings_log, created_by: created_by_user) }
let(:lettings_log_2) { FactoryBot.build(:lettings_log, startdate: Time.zone.local(2022, 1, 1), created_by: created_by_user) }
let(:lettings_log_year_2) { FactoryBot.build(:lettings_log, startdate: Time.zone.local(2023, 5, 1), created_by: created_by_user) }
let(:lettings_log) { build(:lettings_log, created_by: created_by_user) }
let(:lettings_log_2) { build(:lettings_log, startdate: Time.zone.local(2022, 1, 1), created_by: created_by_user) }
let(:lettings_log_year_2) { build(:lettings_log, startdate: Time.zone.local(2023, 5, 1), created_by: created_by_user) }
it "has returns the correct form based on the start date" do
expect(lettings_log.form_name).to be_nil
@ -43,7 +43,7 @@ RSpec.describe LettingsLog do
end
context "when a date outside the collection window is passed" do
let(:lettings_log) { FactoryBot.build(:lettings_log, startdate: Time.zone.local(2015, 1, 1), created_by: created_by_user) }
let(:lettings_log) { build(:lettings_log, startdate: Time.zone.local(2015, 1, 1), created_by: created_by_user) }
it "returns the first form" do
expect(lettings_log.form).to be_a(Form)
@ -70,7 +70,7 @@ RSpec.describe LettingsLog do
end
describe "#update" do
let(:lettings_log) { FactoryBot.create(:lettings_log, created_by: created_by_user) }
let(:lettings_log) { create(:lettings_log, created_by: created_by_user) }
let(:validator) { lettings_log._validators[nil].first }
after do
@ -168,9 +168,9 @@ RSpec.describe LettingsLog do
end
describe "status" do
let!(:empty_lettings_log) { FactoryBot.create(:lettings_log) }
let!(:in_progress_lettings_log) { FactoryBot.create(:lettings_log, :in_progress) }
let!(:completed_lettings_log) { FactoryBot.create(:lettings_log, :completed) }
let!(:empty_lettings_log) { create(:lettings_log) }
let!(:in_progress_lettings_log) { create(:lettings_log, :in_progress) }
let!(:completed_lettings_log) { create(:lettings_log, :completed) }
it "is set to not started for an empty lettings log" do
expect(empty_lettings_log.not_started?).to be(true)
@ -208,7 +208,7 @@ RSpec.describe LettingsLog do
describe "weekly_net_income" do
let(:net_income) { 5000 }
let(:lettings_log) { FactoryBot.build(:lettings_log, earnings: net_income) }
let(:lettings_log) { build(:lettings_log, earnings: net_income) }
it "returns input income if frequency is already weekly" do
lettings_log.incfreq = 1
@ -1860,8 +1860,8 @@ RSpec.describe LettingsLog do
end
context "and a scheme with a single log is selected" do
let(:scheme) { FactoryBot.create(:scheme) }
let!(:location) { FactoryBot.create(:location, scheme:) }
let(:scheme) { create(:scheme) }
let!(:location) { create(:location, scheme:) }
before { lettings_log.update!(startdate: Time.zone.local(2022, 4, 2), scheme:) }
@ -1873,8 +1873,8 @@ RSpec.describe LettingsLog do
end
context "and not renewal" do
let(:scheme) { FactoryBot.create(:scheme) }
let(:location) { FactoryBot.create(:location, scheme:, postcode: "M11AE", type_of_unit: 1, mobility_type: "W") }
let(:scheme) { create(:scheme) }
let(:location) { create(:location, scheme:, postcode: "M11AE", type_of_unit: 1, mobility_type: "W") }
let(:supported_housing_lettings_log) do
described_class.create!({
@ -1916,8 +1916,8 @@ RSpec.describe LettingsLog do
end
context "and renewal" do
let(:scheme) { FactoryBot.create(:scheme) }
let(:location) { FactoryBot.create(:location, scheme:) }
let(:scheme) { create(:scheme) }
let(:location) { create(:location, scheme:) }
let!(:supported_housing_lettings_log) do
described_class.create!({
@ -2035,7 +2035,7 @@ RSpec.describe LettingsLog do
end
describe "optional fields" do
let(:lettings_log) { FactoryBot.create(:lettings_log) }
let(:lettings_log) { create(:lettings_log) }
context "when tshortfall is marked as not known" do
it "makes tshortfall optional" do
@ -2043,13 +2043,42 @@ RSpec.describe LettingsLog do
expect(lettings_log.optional_fields).to include("tshortfall")
end
end
context "when saledate is before 2023" do
let(:lettings_log) { build(:lettings_log, startdate: Time.zone.parse("2022-07-01")) }
it "returns optional fields" do
expect(lettings_log.optional_fields).to eq(%w[
first_time_property_let_as_social_housing
tenancycode
propcode
tenancylength
])
end
end
context "when saledate is after 2023" do
let(:lettings_log) { build(:lettings_log, startdate: Time.zone.parse("2023-07-01")) }
it "returns optional fields" do
expect(lettings_log.optional_fields).to eq(%w[
first_time_property_let_as_social_housing
tenancycode
propcode
tenancylength
address_line2
county
postcode_full
])
end
end
end
describe "resetting invalidated fields" do
let(:scheme) { FactoryBot.create(:scheme, owning_organisation: created_by_user.organisation) }
let(:location) { FactoryBot.create(:location, location_code: "E07000223", scheme:) }
let(:scheme) { create(:scheme, owning_organisation: created_by_user.organisation) }
let(:location) { create(:location, location_code: "E07000223", scheme:) }
let(:lettings_log) do
FactoryBot.create(
create(
:lettings_log,
renewal: 0,
rsnvac: 5,
@ -2084,14 +2113,14 @@ RSpec.describe LettingsLog do
end
context "when a question that has already been answered, no longer has met dependencies" do
let(:lettings_log) { FactoryBot.create(:lettings_log, :in_progress, cbl: 1, preg_occ: 2, wchair: 2) }
let(:lettings_log) { create(:lettings_log, :in_progress, cbl: 1, preg_occ: 2, wchair: 2) }
it "clears the answer" do
expect { lettings_log.update!(preg_occ: nil) }.to change(lettings_log, :cbl).from(1).to(nil)
end
context "when the question type does not have answer options" do
let(:lettings_log) { FactoryBot.create(:lettings_log, :in_progress, housingneeds_a: 1, age1: 19) }
let(:lettings_log) { create(:lettings_log, :in_progress, housingneeds_a: 1, age1: 19) }
it "clears the answer" do
expect { lettings_log.update!(housingneeds_a: 0) }.to change(lettings_log, :age1).from(19).to(nil)
@ -2099,7 +2128,7 @@ RSpec.describe LettingsLog do
end
context "when the question type has answer options" do
let(:lettings_log) { FactoryBot.create(:lettings_log, :in_progress, illness: 1, illness_type_1: 1) }
let(:lettings_log) { create(:lettings_log, :in_progress, illness: 1, illness_type_1: 1) }
it "clears the answer" do
expect { lettings_log.update!(illness: 2) }.to change(lettings_log, :illness_type_1).from(1).to(nil)
@ -2108,7 +2137,7 @@ RSpec.describe LettingsLog do
end
context "with two pages having the same question key, only one's dependency is met" do
let(:lettings_log) { FactoryBot.create(:lettings_log, :in_progress, cbl: 0, preg_occ: 2, wchair: 2) }
let(:lettings_log) { create(:lettings_log, :in_progress, cbl: 0, preg_occ: 2, wchair: 2) }
it "does not clear the value for answers that apply to both pages" do
expect(lettings_log.cbl).to eq(0)
@ -2123,7 +2152,7 @@ RSpec.describe LettingsLog do
end
context "when a non select question associated with several pages is routed to" do
let(:lettings_log) { FactoryBot.create(:lettings_log, :in_progress, period: 2, needstype: 1, renewal: 0) }
let(:lettings_log) { create(:lettings_log, :in_progress, period: 2, needstype: 1, renewal: 0) }
it "does not clear the answer value" do
lettings_log.update!({ unitletas: 1 })
@ -2133,7 +2162,7 @@ RSpec.describe LettingsLog do
end
context "when the lettings log does not have a valid form set yet" do
let(:lettings_log) { FactoryBot.create(:lettings_log) }
let(:lettings_log) { create(:lettings_log) }
it "does not throw an error" do
expect { lettings_log.update(startdate: Time.zone.local(2015, 1, 1)) }.not_to raise_error
@ -2141,7 +2170,7 @@ RSpec.describe LettingsLog do
end
context "when it changes from a renewal to not a renewal" do
let(:lettings_log) { FactoryBot.create(:lettings_log) }
let(:lettings_log) { create(:lettings_log) }
it "resets inferred waityear value" do
lettings_log.update!({ renewal: 1 })
@ -2173,8 +2202,8 @@ RSpec.describe LettingsLog do
end
context "when it changes from a supported housing to not a supported housing" do
let(:location) { FactoryBot.create(:location, mobility_type: "A", postcode: "SW1P 4DG") }
let(:lettings_log) { FactoryBot.create(:lettings_log, location:) }
let(:location) { create(:location, mobility_type: "A", postcode: "SW1P 4DG") }
let(:lettings_log) { create(:lettings_log, location:) }
it "resets inferred wchair value" do
lettings_log.update!({ needstype: 2 })
@ -2203,7 +2232,7 @@ RSpec.describe LettingsLog do
end
context "when it is not a renewal" do
let(:lettings_log) { FactoryBot.create(:lettings_log) }
let(:lettings_log) { create(:lettings_log) }
it "saves waityear value" do
lettings_log.update!({ renewal: 0, waityear: 2 })
@ -2215,13 +2244,13 @@ RSpec.describe LettingsLog do
end
context "when a support user changes the owning organisation of the log" do
let(:lettings_log) { FactoryBot.create(:lettings_log, created_by: created_by_user) }
let(:organisation_2) { FactoryBot.create(:organisation) }
let(:lettings_log) { create(:lettings_log, created_by: created_by_user) }
let(:organisation_2) { create(:organisation) }
context "when the organisation selected doesn't match the scheme set" do
let(:scheme) { FactoryBot.create(:scheme, owning_organisation: created_by_user.organisation) }
let(:location) { FactoryBot.create(:location, scheme:) }
let(:lettings_log) { FactoryBot.create(:lettings_log, owning_organisation: nil, needstype: 2, scheme_id: scheme.id) }
let(:scheme) { create(:scheme, owning_organisation: created_by_user.organisation) }
let(:location) { create(:location, scheme:) }
let(:lettings_log) { create(:lettings_log, owning_organisation: nil, needstype: 2, scheme_id: scheme.id) }
it "clears the scheme value" do
lettings_log.update!(owning_organisation: organisation_2)
@ -2230,9 +2259,9 @@ RSpec.describe LettingsLog do
end
context "when the organisation selected still matches the scheme set" do
let(:scheme) { FactoryBot.create(:scheme, owning_organisation: organisation_2) }
let(:location) { FactoryBot.create(:location, scheme:) }
let(:lettings_log) { FactoryBot.create(:lettings_log, owning_organisation: nil, needstype: 2, scheme_id: scheme.id) }
let(:scheme) { create(:scheme, owning_organisation: organisation_2) }
let(:location) { create(:location, scheme:) }
let(:lettings_log) { create(:lettings_log, owning_organisation: nil, needstype: 2, scheme_id: scheme.id) }
it "does not clear the scheme value" do
lettings_log.update!(owning_organisation: organisation_2)
@ -2319,7 +2348,7 @@ RSpec.describe LettingsLog do
describe "tshortfall_unknown?" do
context "when tshortfall is nil" do
let(:lettings_log) { FactoryBot.create(:lettings_log, :in_progress, tshortfall_known: nil) }
let(:lettings_log) { create(:lettings_log, :in_progress, tshortfall_known: nil) }
it "returns false" do
expect(lettings_log.tshortfall_unknown?).to be false
@ -2327,7 +2356,7 @@ RSpec.describe LettingsLog do
end
context "when tshortfall is No" do
let(:lettings_log) { FactoryBot.create(:lettings_log, :in_progress, tshortfall_known: 1) }
let(:lettings_log) { create(:lettings_log, :in_progress, tshortfall_known: 1) }
it "returns false" do
expect(lettings_log.tshortfall_unknown?).to be true
@ -2335,7 +2364,7 @@ RSpec.describe LettingsLog do
end
context "when tshortfall is Yes" do
let(:lettings_log) { FactoryBot.create(:lettings_log, :in_progress, tshortfall_known: 0) }
let(:lettings_log) { create(:lettings_log, :in_progress, tshortfall_known: 0) }
it "returns false" do
expect(lettings_log.tshortfall_unknown?).to be false
@ -2344,7 +2373,7 @@ RSpec.describe LettingsLog do
end
describe "paper trail" do
let(:lettings_log) { FactoryBot.create(:lettings_log, :in_progress) }
let(:lettings_log) { create(:lettings_log, :in_progress) }
it "creates a record of changes to a log" do
expect { lettings_log.update!(age1: 64) }.to change(lettings_log.versions, :count).by(1)
@ -2357,7 +2386,7 @@ RSpec.describe LettingsLog do
end
describe "soft values for period" do
let(:lettings_log) { FactoryBot.create(:lettings_log) }
let(:lettings_log) { create(:lettings_log) }
before do
LaRentRange.create!(
@ -2404,12 +2433,12 @@ RSpec.describe LettingsLog do
end
describe "scopes" do
let!(:lettings_log_1) { FactoryBot.create(:lettings_log, :in_progress, startdate: Time.utc(2021, 5, 3), created_by: created_by_user) }
let!(:lettings_log_2) { FactoryBot.create(:lettings_log, :completed, startdate: Time.utc(2021, 5, 3), created_by: created_by_user) }
let!(:lettings_log_1) { create(:lettings_log, :in_progress, startdate: Time.utc(2021, 5, 3), created_by: created_by_user) }
let!(:lettings_log_2) { create(:lettings_log, :completed, startdate: Time.utc(2021, 5, 3), created_by: created_by_user) }
before do
Timecop.freeze(Time.utc(2022, 6, 3))
FactoryBot.create(:lettings_log, startdate: Time.utc(2022, 6, 3))
create(:lettings_log, startdate: Time.utc(2022, 6, 3))
end
after do
@ -2417,10 +2446,10 @@ RSpec.describe LettingsLog do
end
context "when searching logs" do
let!(:lettings_log_to_search) { FactoryBot.create(:lettings_log, :completed) }
let!(:lettings_log_to_search) { create(:lettings_log, :completed) }
before do
FactoryBot.create_list(:lettings_log, 5, :completed)
create_list(:lettings_log, 5, :completed)
end
describe "#filter_by_id" do
@ -2475,7 +2504,7 @@ RSpec.describe LettingsLog do
end
context "when lettings log is supported housing" do
let(:location) { FactoryBot.create(:location, postcode: "W6 0ST") }
let(:location) { create(:location, postcode: "W6 0ST") }
before do
lettings_log_to_search.update!(needstype: 2, location:)
@ -2515,7 +2544,7 @@ RSpec.describe LettingsLog do
end
context "when lettings log is supported housing" do
let(:location) { FactoryBot.create(:location, postcode: "W6 0ST") }
let(:location) { create(:location, postcode: "W6 0ST") }
before do
lettings_log_to_search.update!(needstype: 2, location:)
@ -2573,15 +2602,15 @@ RSpec.describe LettingsLog do
end
context "when filtering by organisation" do
let(:organisation_1) { FactoryBot.create(:organisation) }
let(:organisation_2) { FactoryBot.create(:organisation) }
let(:organisation_3) { FactoryBot.create(:organisation) }
let(:organisation_1) { create(:organisation) }
let(:organisation_2) { create(:organisation) }
let(:organisation_3) { create(:organisation) }
before do
FactoryBot.create(:lettings_log, :in_progress, owning_organisation: organisation_1, managing_organisation: organisation_1, created_by: nil)
FactoryBot.create(:lettings_log, :completed, owning_organisation: organisation_1, managing_organisation: organisation_2, created_by: nil)
FactoryBot.create(:lettings_log, :completed, owning_organisation: organisation_2, managing_organisation: organisation_1, created_by: nil)
FactoryBot.create(:lettings_log, :completed, owning_organisation: organisation_2, managing_organisation: organisation_2, created_by: nil)
create(:lettings_log, :in_progress, owning_organisation: organisation_1, managing_organisation: organisation_1, created_by: nil)
create(:lettings_log, :completed, owning_organisation: organisation_1, managing_organisation: organisation_2, created_by: nil)
create(:lettings_log, :completed, owning_organisation: organisation_2, managing_organisation: organisation_1, created_by: nil)
create(:lettings_log, :completed, owning_organisation: organisation_2, managing_organisation: organisation_2, created_by: nil)
end
it "filters by given organisation" do
@ -2623,7 +2652,7 @@ RSpec.describe LettingsLog do
describe "#retirement_age_for_person" do
context "when a person gender is Male" do
let(:lettings_log) { FactoryBot.build(:lettings_log, sex1: "M") }
let(:lettings_log) { build(:lettings_log, sex1: "M") }
it "returns the expected retirement age" do
expect(lettings_log.retirement_age_for_person_1).to eq(67)
@ -2635,7 +2664,7 @@ RSpec.describe LettingsLog do
end
context "when a person gender is Female" do
let(:lettings_log) { FactoryBot.build(:lettings_log, sex2: "F") }
let(:lettings_log) { build(:lettings_log, sex2: "F") }
it "returns the expected retirement age" do
expect(lettings_log.retirement_age_for_person_2).to eq(60)
@ -2647,7 +2676,7 @@ RSpec.describe LettingsLog do
end
context "when a person gender is Non-Binary" do
let(:lettings_log) { FactoryBot.build(:lettings_log, sex3: "X") }
let(:lettings_log) { build(:lettings_log, sex3: "X") }
it "returns the expected retirement age" do
expect(lettings_log.retirement_age_for_person_3).to eq(67)
@ -2659,7 +2688,7 @@ RSpec.describe LettingsLog do
end
context "when the person gender is not set" do
let(:lettings_log) { FactoryBot.build(:lettings_log) }
let(:lettings_log) { build(:lettings_log) }
it "returns nil" do
expect(lettings_log.retirement_age_for_person_3).to be_nil
@ -2671,7 +2700,7 @@ RSpec.describe LettingsLog do
end
context "when a postcode contains unicode characters" do
let(:lettings_log) { FactoryBot.build(:lettings_log, postcode_full: "SR81LS\u00A0") }
let(:lettings_log) { build(:lettings_log, postcode_full: "SR81LS\u00A0") }
it "triggers a validation error" do
expect { lettings_log.save! }.to raise_error(ActiveRecord::RecordInvalid, /Enter a postcode in the correct format/)
@ -2680,9 +2709,9 @@ RSpec.describe LettingsLog do
end
describe "csv download" do
let(:scheme) { FactoryBot.create(:scheme) }
let(:location) { FactoryBot.create(:location, :export, scheme:, type_of_unit: 6, postcode: "SE11TE", startdate: Time.zone.local(2021, 10, 1)) }
let(:user) { FactoryBot.create(:user, organisation: location.scheme.owning_organisation) }
let(:scheme) { create(:scheme) }
let(:location) { create(:location, :export, scheme:, type_of_unit: 6, postcode: "SE11TE", startdate: Time.zone.local(2021, 10, 1)) }
let(:user) { create(:user, organisation: location.scheme.owning_organisation) }
let(:expected_content) { csv_export_file.read }
after do

87
spec/models/sales_log_spec.rb

@ -1,6 +1,7 @@
require "rails_helper"
require "shared/shared_examples_for_derived_fields"
# rubocop:disable RSpec/AnyInstance
RSpec.describe SalesLog, type: :model do
let(:owning_organisation) { create(:organisation) }
let(:created_by_user) { create(:user) }
@ -36,7 +37,7 @@ RSpec.describe SalesLog, type: :model do
end
describe "#update" do
let(:sales_log) { FactoryBot.create(:sales_log, created_by: created_by_user) }
let(:sales_log) { create(:sales_log, created_by: created_by_user) }
let(:validator) { sales_log._validators[nil].first }
after do
@ -49,10 +50,34 @@ RSpec.describe SalesLog, type: :model do
end
describe "#optional_fields" do
let(:sales_log) { build(:sales_log) }
context "when saledate is before 2023" do
let(:sales_log) { build(:sales_log, saledate: Time.zone.parse("2022-07-01")) }
it "returns optional fields" do
expect(sales_log.optional_fields).to eq(%w[saledate_check purchid monthly_charges_value_check old_persons_shared_ownership_value_check])
expect(sales_log.optional_fields).to eq(%w[
saledate_check
purchid
monthly_charges_value_check
old_persons_shared_ownership_value_check
proplen
])
end
end
context "when saledate is after 2023" do
let(:sales_log) { build(:sales_log, saledate: Time.zone.parse("2023-07-01")) }
it "returns optional fields" do
expect(sales_log.optional_fields).to eq(%w[
saledate_check
purchid
monthly_charges_value_check
old_persons_shared_ownership_value_check
address_line2
county
postcode_full
])
end
end
end
@ -135,7 +160,7 @@ RSpec.describe SalesLog, type: :model do
end
describe "derived variables" do
let(:sales_log) { FactoryBot.create(:sales_log, :completed) }
let(:sales_log) { create(:sales_log, :completed) }
it "correctly derives and saves exday, exmonth and exyear" do
sales_log.update!(exdate: Time.gm(2022, 5, 4), saledate: Time.gm(2022, 7, 4), ownershipsch: 1, staircase: 2, resale: 2)
@ -192,7 +217,7 @@ RSpec.describe SalesLog, type: :model do
end
let!(:address_sales_log) do
FactoryBot.create(
create(
:sales_log,
:completed,
owning_organisation:,
@ -336,7 +361,7 @@ RSpec.describe SalesLog, type: :model do
context "when deriving household variables" do
let!(:sales_log) do
FactoryBot.create(
create(
:sales_log,
:completed,
jointpur: 1,
@ -463,7 +488,7 @@ RSpec.describe SalesLog, type: :model do
end
describe "#field_formatted_as_currency" do
let(:completed_sales_log) { FactoryBot.create(:sales_log, :completed) }
let(:completed_sales_log) { create(:sales_log, :completed) }
it "returns small numbers correctly formatted as currency" do
completed_sales_log.update!(savings: 4)
@ -483,4 +508,52 @@ RSpec.describe SalesLog, type: :model do
expect(completed_sales_log.field_formatted_as_currency("savings")).to eq("£400,000,000.00")
end
end
describe "#process_uprn_change!" do
context "when UPRN set to a value" do
let(:sales_log) { create(:sales_log, uprn: "123456789", uprn_confirmed: 1) }
it "updates sales log fields" do
sales_log.uprn = "1111111"
allow_any_instance_of(UprnClient).to receive(:call)
allow_any_instance_of(UprnClient).to receive(:result).and_return({
"UPRN" => "UPRN",
"UDPRN" => "UDPRN",
"ADDRESS" => "full address",
"SUB_BUILDING_NAME" => "0",
"BUILDING_NAME" => "building name",
"THOROUGHFARE_NAME" => "thoroughfare",
"POST_TOWN" => "posttown",
"POSTCODE" => "postcode",
})
expect { sales_log.process_uprn_change! }.to change(sales_log, :address_line1).from(nil).to("0, Building Name, Thoroughfare")
.and change(sales_log, :town_or_city).from(nil).to("Posttown")
.and change(sales_log, :postcode_full).from(nil).to("POSTCODE")
.and change(sales_log, :uprn_confirmed).from(1).to(nil)
end
end
context "when UPRN nil" do
let(:sales_log) { create(:sales_log, uprn: nil) }
it "does not update sales log" do
expect { sales_log.process_uprn_change! }.not_to change(sales_log, :attributes)
end
end
context "when service errors" do
let(:sales_log) { create(:sales_log, uprn: "123456789", uprn_confirmed: 1) }
let(:error_message) { "error" }
it "adds error to sales log" do
allow_any_instance_of(UprnClient).to receive(:call)
allow_any_instance_of(UprnClient).to receive(:error).and_return(error_message)
expect { sales_log.process_uprn_change! }.to change { sales_log.errors[:uprn] }.from([]).to([error_message])
end
end
end
end
# rubocop:enable RSpec/AnyInstance

29
spec/models/validations/property_validations_spec.rb

@ -290,4 +290,33 @@ RSpec.describe Validations::PropertyValidations do
end
end
end
describe "#validate_uprn" do
context "when within length limit but alphanumeric" do
let(:record) { build(:sales_log, uprn: "123abc") }
it "adds an error" do
property_validator.validate_uprn(record)
expect(record.errors.added?(:uprn, "UPRN must be 12 digits or less")).to be true
end
end
context "when over the length limit" do
let(:record) { build(:sales_log, uprn: "1234567890123") }
it "adds an error" do
property_validator.validate_uprn(record)
expect(record.errors.added?(:uprn, "UPRN must be 12 digits or less")).to be true
end
end
context "when within the limit and only numeric" do
let(:record) { build(:sales_log, uprn: "123456789012") }
it "does not add an error" do
property_validator.validate_uprn(record)
expect(record.errors).not_to be_present
end
end
end
end

39
spec/models/validations/sales/property_validations_spec.rb

@ -7,7 +7,7 @@ RSpec.describe Validations::Sales::PropertyValidations do
describe "#validate_postcodes_match_if_discounted_ownership" do
context "when ownership scheme is not discounted ownership" do
let(:record) { FactoryBot.build(:sales_log, ownershipsch: 1) }
let(:record) { build(:sales_log, ownershipsch: 1) }
it "when postcodes match no error is added" do
record.postcode_full = "SW1A 1AA"
@ -19,7 +19,7 @@ RSpec.describe Validations::Sales::PropertyValidations do
end
context "when ownership scheme is discounted ownership" do
let(:record) { FactoryBot.build(:sales_log, ownershipsch: 2) }
let(:record) { build(:sales_log, ownershipsch: 2) }
it "when ppostcode_full is not present no error is added" do
record.postcode_full = "SW1A 1AA"
@ -51,7 +51,7 @@ RSpec.describe Validations::Sales::PropertyValidations do
describe "#validate_property_unit_type" do
context "when number of bedrooms is 1" do
let(:record) { FactoryBot.build(:sales_log, beds: 1, proptype: 2) }
let(:record) { build(:sales_log, beds: 1, proptype: 2) }
it "does not add an error if it's a bedsit" do
property_validator.validate_bedsit_number_of_beds(record)
@ -60,7 +60,7 @@ RSpec.describe Validations::Sales::PropertyValidations do
end
context "when number of bedrooms is > 1" do
let(:record) { FactoryBot.build(:sales_log, beds: 2, proptype: 2) }
let(:record) { build(:sales_log, beds: 2, proptype: 2) }
it "does add an error if it's a bedsit" do
property_validator.validate_bedsit_number_of_beds(record)
@ -76,7 +76,7 @@ RSpec.describe Validations::Sales::PropertyValidations do
end
context "when number of bedrooms is undefined" do
let(:record) { FactoryBot.build(:sales_log, beds: nil, proptype: 2) }
let(:record) { build(:sales_log, beds: nil, proptype: 2) }
it "does not add an error if it's a bedsit" do
property_validator.validate_bedsit_number_of_beds(record)
@ -84,4 +84,33 @@ RSpec.describe Validations::Sales::PropertyValidations do
end
end
end
describe "#validate_uprn" do
context "when within length limit but alphanumeric" do
let(:record) { build(:sales_log, uprn: "123abc") }
it "adds an error" do
property_validator.validate_uprn(record)
expect(record.errors.added?(:uprn, "UPRN must be 12 digits or less")).to be true
end
end
context "when over the length limit" do
let(:record) { build(:sales_log, uprn: "1234567890123") }
it "adds an error" do
property_validator.validate_uprn(record)
expect(record.errors.added?(:uprn, "UPRN must be 12 digits or less")).to be true
end
end
context "when within the limit and only numeric" do
let(:record) { build(:sales_log, uprn: "123456789012") }
it "does not add an error" do
property_validator.validate_uprn(record)
expect(record.errors).not_to be_present
end
end
end
end

9
spec/services/csv/lettings_log_csv_service_spec.rb

@ -201,6 +201,13 @@ RSpec.describe Csv::LettingsLogCsvService do
vacdays
unresolved
updated_by_id
uprn
uprn_known
uprn_confirmed
address_line1
address_line2
town_or_city
county
unittype_sh
scheme_code
scheme_service_name
@ -222,7 +229,9 @@ RSpec.describe Csv::LettingsLogCsvService do
location_mobility_type
location_admin_district
location_startdate]
csv = CSV.parse(described_class.new(user, export_type: "labels").to_csv)
expect(csv.first).to eq(expected_csv_attributes)
end
end

68
spec/services/uprn_client_spec.rb

@ -0,0 +1,68 @@
require "rails_helper"
describe UprnClient do
let(:client) { described_class.new("123") }
let(:valid_response) do
{ results: [{ DPA: { postcode: "12345" } }] }.to_json
end
def stub_api_request(body:, status: 200)
stub_request(:get, "https://api.os.uk/search/places/v1/uprn?key=OS_DATA_KEY&uprn=123")
.to_return(status:, body:, headers: {})
end
describe "call" do
context "when json parse error" do
before do
stub_api_request(body: "{", status: 200)
client.call
end
it "returns error" do
expect(client.error).to eq("UPRN is not recognised. Check the number, or enter the address")
end
end
context "when http error" do
before do
stub_api_request(body: valid_response, status: 500)
client.call
end
it "returns error" do
expect(client.error).to eq("UPRN is not recognised. Check the number, or enter the address")
end
end
context "when results empty" do
before do
stub_api_request(body: {}.to_json)
client.call
end
it "returns error" do
expect(client.error).to eq("UPRN is not recognised. Check the number, or enter the address")
end
end
context "with results" do
before do
stub_api_request(body: valid_response)
client.call
end
it "returns result" do
expect(client.result).to eq({ "postcode" => "12345" })
end
it "returns no error" do
expect(client.error).to be_nil
end
end
end
end

66
spec/services/uprn_data_presenter_spec.rb

@ -0,0 +1,66 @@
require "rails_helper"
describe UprnDataPresenter do
let(:data) do
JSON.parse(
'{
"UPRN": "UPRN",
"UDPRN": "UDPRN",
"ADDRESS": "full address",
"SUB_BUILDING_NAME": "0",
"BUILDING_NAME": "building name",
"THOROUGHFARE_NAME": "thoroughfare",
"POST_TOWN": "posttown",
"POSTCODE": "postcode",
"STATUS": "APPROVED",
"DOUBLE_DEPENDENT_LOCALITY": "double dependent locality",
"DEPENDENT_LOCALITY": "dependent locality",
"CLASSIFICATION_CODE": "classification code",
"LOCAL_CUSTODIAN_CODE_DESCRIPTION": "LONDON BOROUGH OF HARINGEY",
"BLPU_STATE_CODE": "2",
"BLPU_STATE_CODE_DESCRIPTION": "In use",
"LAST_UPDATE_DATE": "31/07/2020",
"ENTRY_DATE": "30/01/2015",
"BLPU_STATE_DATE": "30/01/2015",
"LANGUAGE": "EN",
"MATCH_DESCRIPTION": "EXACT"
}',
)
end
let(:presenter) { described_class.new(data) }
describe "#postcode" do
it "returns postcode" do
expect(presenter.postcode).to eq("postcode")
end
end
describe "#address_line1" do
it "returns address_line1" do
expect(presenter.address_line1).to eq("0, Building Name, Thoroughfare")
end
end
describe "#address_line2" do
it "returns address_line2" do
expect(presenter.address_line2).to eq("Double Dependent Locality, Dependent Locality")
end
end
describe "#town_or_city" do
it "returns town_or_city" do
expect(presenter.town_or_city).to eq("Posttown")
end
end
context "when address_line2 fields are missing" do
let(:data) { {} }
describe "#address_line2" do
it "returns nil" do
expect(presenter.address_line2).to be_nil
end
end
end
end
Loading…
Cancel
Save