Browse Source

Update postcode handling

Introduces new database fields and fixes rubocop issues
CLDC-1468-add-postcode-to-sales-property-info-journey
Mo Seedat 2 years ago
parent
commit
3ecfe24139
  1. 2
      app/models/form/sales/pages/property_postcode.rb
  2. 15
      app/models/form/sales/questions/postcode_full.rb
  3. 22
      app/models/form/sales/questions/property_postcode.rb
  4. 60
      app/models/sales_log.rb
  5. 10
      app/models/validations/sales/property_information_validations.rb
  6. 10
      app/services/postcode_service.rb
  7. 3
      db/migrate/20221018221143_add_postcode_to_sales_log.rb
  8. 2
      db/schema.rb

2
app/models/form/sales/pages/property_postcode.rb

@ -1,7 +1,7 @@
class Form::Sales::Pages::PropertyPostcode < ::Form::Page class Form::Sales::Pages::PropertyPostcode < ::Form::Page
def initialize(id, hsh, subsection) def initialize(id, hsh, subsection)
super super
@id = "property_postcode" @id = "postcode_known"
@header = "" @header = ""
@description = "" @description = ""
@subsection = subsection @subsection = subsection

15
app/models/form/sales/questions/postcode_full.rb

@ -2,10 +2,21 @@ class Form::Sales::Questions::PostcodeFull < ::Form::Question
def initialize(id, hsh, page) def initialize(id, hsh, page)
super super
@id = "postcode_full" @id = "postcode_full"
@check_answer_label = "Property full postcode!!!" @check_answer_label = "Property postcode"
@header = "The Full Postcode outer inner" @header = "What is the property's postcode?"
@type = "text" @type = "text"
@page = page @page = page
@width = 10 @width = 10
@inferred_answers = {
"la" => {
"is_la_inferred" => true,
},
}
@inferred_check_answers_value = {
"condition" => {
"postcode_known" => 0,
},
"value" => "Not known",
}
end end
end end

22
app/models/form/sales/questions/property_postcode.rb

@ -1,24 +1,32 @@
class Form::Sales::Questions::PropertyPostcode < ::Form::Question class Form::Sales::Questions::PropertyPostcode < ::Form::Question
def initialize(id, hsh, page) def initialize(id, hsh, page)
super super
@id = "pcodenk" @id = "postcode_known"
@check_answer_label = "Postcode" @check_answer_label = "Do you know the property's postcode?"
@header = "Do you know the property's postcode?" @header = "Do you know the property's postcode?"
@hint_text = "" @hint_text = ""
@type = "radio" @type = "radio"
@answer_options = ANSWER_OPTIONS @answer_options = ANSWER_OPTIONS
@width = 10 @width = 10
@page = page @page = page
@hidden_in_check_answers = {
"depends_on" => [
{
"postcode_known" => 0,
},
{
"postcode_known" => 1,
},
],
}
@conditional_for = { @conditional_for = {
"postcode_full" => [0], "postcode_full" => [1],
} }
end end
ANSWER_OPTIONS = { ANSWER_OPTIONS = {
"0" => { "value" => "Yes" }, "1" => { "value" => "Yes" },
"1" => { "value" => "No" }, "0" => { "value" => "No" },
}.freeze }.freeze
end end
#"sales-log-postcode-full-field"

60
app/models/sales_log.rb

@ -1,5 +1,10 @@
class SalesLogValidator < ActiveModel::Validator class SalesLogValidator < ActiveModel::Validator
def validate(record); end include Validations::Sales::PropertyInformationValidations
def validate(record)
validation_methods = public_methods.select { |method| method.starts_with?("validate_") }
validation_methods.each { |meth| public_send(meth, record) }
end
end end
class SalesLog < Log class SalesLog < Log
@ -9,9 +14,12 @@ class SalesLog < Log
has_paper_trail has_paper_trail
## Custom validations
validates_with SalesLogValidator validates_with SalesLogValidator
before_validation :set_derived_fields! before_validation :set_derived_fields!
before_validation :reset_invalidated_dependent_fields! before_validation :reset_invalidated_dependent_fields!
before_validation :process_postcode_changes!, if: :postcode_full_changed?
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_year, ->(year) { where(saledate: Time.zone.local(year.to_i, 4, 1)...Time.zone.local(year.to_i + 1, 4, 1)) }
scope :search_by, ->(param) { filter_by_id(param) } scope :search_by, ->(param) { filter_by_id(param) }
@ -47,4 +55,54 @@ class SalesLog < Log
def completed? def completed?
status == "completed" status == "completed"
end end
# NOTE: Assume if the postcode is not found by the
# Postcode service, entered value is still valid. E.g.
# if the Postcode service timesout/unavailable then still
# need to proceed
def process_postcode_changes!
return if postcode_full.blank?
self.pcodenk = nil
self.postcode_known = 1
if postcode_lookup&.result?
self.pcode1 = postcode_lookup.outcode
self.pcode2 = postcode_lookup.incode
self.la = postcode_lookup.location_admin_district
self.la_known = 1
else
self.pcode1 = nil
self.pcode2 = nil
self.la = nil
self.la_known = 0
end
end
def postcode_lookup
@postcode_lookup ||= PostcodeService.new.lookup(postcode_full)
end
# 1: Yes
def postcode_known?
postcode_known == 1
end
# 1: Yes
def la_known?
la_known == 1
end
def postcode_full=(postcode)
if postcode.present?
super UKPostcode.parse(upcase_and_remove_whitespace(postcode)).to_s
self.postcode_known = 1
else
super nil
end
end
def upcase_and_remove_whitespace(string)
string.present? ? string.upcase.gsub(/\s+/, "") : string
end
end end

10
app/models/validations/sales/property_information_validations.rb

@ -0,0 +1,10 @@
module Validations::Sales::PropertyInformationValidations
def validate_property_postcode(record)
postcode = record.postcode_full
if record.postcode_known? && (postcode.blank? || !postcode.match(POSTCODE_REGEXP))
error_message = I18n.t("validations.postcode")
record.errors.add :postcode_full, error_message
end
end
end

10
app/services/postcode_service.rb

@ -8,18 +8,24 @@ class PostcodeService
return unless postcode.match(POSTCODE_REGEXP) return unless postcode.match(POSTCODE_REGEXP)
postcode_lookup = nil postcode_lookup = nil
begin begin
# URI encoding only supports ASCII characters # URI encoding only supports ASCII characters
# Example response for postcode SE27 0AL:
ascii_postcode = self.class.clean(postcode) ascii_postcode = self.class.clean(postcode)
Timeout.timeout(5) { postcode_lookup = @pio.lookup(ascii_postcode) } Timeout.timeout(5) { postcode_lookup = @pio.lookup(ascii_postcode) }
rescue Timeout::Error rescue Timeout::Error
Rails.logger.warn("Postcodes.io lookup timed out") Rails.logger.warn("Postcodes.io lookup timed out")
end end
if postcode_lookup && postcode_lookup.info.present? if postcode_lookup && postcode_lookup.info.present?
{ OpenStruct.new({
location_code: postcode_lookup.codes["admin_district"], location_code: postcode_lookup.codes["admin_district"],
location_admin_district: postcode_lookup&.admin_district, location_admin_district: postcode_lookup&.admin_district,
} incode: postcode_lookup.incode,
outcode: postcode_lookup.outcode,
result?: postcode_lookup.outcode.present?,
})
end end
end end

3
db/migrate/20221018221143_add_postcode_to_sales_log.rb

@ -5,6 +5,9 @@ class AddPostcodeToSalesLog < ActiveRecord::Migration[7.0]
t.column :pcode1, :string, default: nil # Outcode e.g. SE27 t.column :pcode1, :string, default: nil # Outcode e.g. SE27
t.column :pcode2, :string, default: nil # Incode e.g. 0HG t.column :pcode2, :string, default: nil # Incode e.g. 0HG
t.column :pcodenk, :boolean, default: true # Not Known t.column :pcodenk, :boolean, default: true # Not Known
t.column :postcode_known, :integer
t.column :la_known, :integer
end end
end end
end end

2
db/schema.rb

@ -391,6 +391,8 @@ ActiveRecord::Schema[7.0].define(version: 2022_10_18_221143) do
t.string "pcode1" t.string "pcode1"
t.string "pcode2" t.string "pcode2"
t.boolean "pcodenk", default: true t.boolean "pcodenk", default: true
t.integer "postcode_known"
t.integer "la_known"
t.index ["created_by_id"], name: "index_sales_logs_on_created_by_id" t.index ["created_by_id"], name: "index_sales_logs_on_created_by_id"
t.index ["managing_organisation_id"], name: "index_sales_logs_on_managing_organisation_id" t.index ["managing_organisation_id"], name: "index_sales_logs_on_managing_organisation_id"
t.index ["owning_organisation_id"], name: "index_sales_logs_on_owning_organisation_id" t.index ["owning_organisation_id"], name: "index_sales_logs_on_owning_organisation_id"

Loading…
Cancel
Save