From 3ecfe241396fb0d060d933d8ee4cfe76e7eac114 Mon Sep 17 00:00:00 2001 From: Mo Seedat Date: Thu, 3 Nov 2022 11:27:42 +0000 Subject: [PATCH] Update postcode handling Introduces new database fields and fixes rubocop issues --- .../form/sales/pages/property_postcode.rb | 2 +- .../form/sales/questions/postcode_full.rb | 15 ++++- .../form/sales/questions/property_postcode.rb | 22 ++++--- app/models/sales_log.rb | 60 ++++++++++++++++++- .../sales/property_information_validations.rb | 10 ++++ app/services/postcode_service.rb | 10 +++- ...0221018221143_add_postcode_to_sales_log.rb | 3 + db/schema.rb | 2 + 8 files changed, 111 insertions(+), 13 deletions(-) create mode 100644 app/models/validations/sales/property_information_validations.rb diff --git a/app/models/form/sales/pages/property_postcode.rb b/app/models/form/sales/pages/property_postcode.rb index 2c7e50e7d..0dd72931e 100644 --- a/app/models/form/sales/pages/property_postcode.rb +++ b/app/models/form/sales/pages/property_postcode.rb @@ -1,7 +1,7 @@ class Form::Sales::Pages::PropertyPostcode < ::Form::Page def initialize(id, hsh, subsection) super - @id = "property_postcode" + @id = "postcode_known" @header = "" @description = "" @subsection = subsection diff --git a/app/models/form/sales/questions/postcode_full.rb b/app/models/form/sales/questions/postcode_full.rb index 225d2bda5..eeecd95ac 100644 --- a/app/models/form/sales/questions/postcode_full.rb +++ b/app/models/form/sales/questions/postcode_full.rb @@ -2,10 +2,21 @@ class Form::Sales::Questions::PostcodeFull < ::Form::Question def initialize(id, hsh, page) super @id = "postcode_full" - @check_answer_label = "Property full postcode!!!" - @header = "The Full Postcode outer inner" + @check_answer_label = "Property postcode" + @header = "What is the property's postcode?" @type = "text" @page = page @width = 10 + @inferred_answers = { + "la" => { + "is_la_inferred" => true, + }, + } + @inferred_check_answers_value = { + "condition" => { + "postcode_known" => 0, + }, + "value" => "Not known", + } end end diff --git a/app/models/form/sales/questions/property_postcode.rb b/app/models/form/sales/questions/property_postcode.rb index 7d3b12ac7..9ce61c220 100644 --- a/app/models/form/sales/questions/property_postcode.rb +++ b/app/models/form/sales/questions/property_postcode.rb @@ -1,24 +1,32 @@ class Form::Sales::Questions::PropertyPostcode < ::Form::Question def initialize(id, hsh, page) super - @id = "pcodenk" - @check_answer_label = "Postcode" + @id = "postcode_known" + @check_answer_label = "Do you know the property's postcode?" @header = "Do you know the property's postcode?" @hint_text = "" @type = "radio" @answer_options = ANSWER_OPTIONS @width = 10 @page = page + @hidden_in_check_answers = { + "depends_on" => [ + { + "postcode_known" => 0, + }, + { + "postcode_known" => 1, + }, + ], + } @conditional_for = { - "postcode_full" => [0], + "postcode_full" => [1], } end ANSWER_OPTIONS = { - "0" => { "value" => "Yes" }, - "1" => { "value" => "No" }, + "1" => { "value" => "Yes" }, + "0" => { "value" => "No" }, }.freeze end - -#"sales-log-postcode-full-field" diff --git a/app/models/sales_log.rb b/app/models/sales_log.rb index e1458caa9..63a131c92 100644 --- a/app/models/sales_log.rb +++ b/app/models/sales_log.rb @@ -1,5 +1,10 @@ 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 class SalesLog < Log @@ -9,9 +14,12 @@ class SalesLog < Log has_paper_trail + ## Custom validations validates_with SalesLogValidator + before_validation :set_derived_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 :search_by, ->(param) { filter_by_id(param) } @@ -47,4 +55,54 @@ class SalesLog < Log def completed? status == "completed" 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 diff --git a/app/models/validations/sales/property_information_validations.rb b/app/models/validations/sales/property_information_validations.rb new file mode 100644 index 000000000..53815eb3d --- /dev/null +++ b/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 diff --git a/app/services/postcode_service.rb b/app/services/postcode_service.rb index 74c1f4895..a77887b89 100644 --- a/app/services/postcode_service.rb +++ b/app/services/postcode_service.rb @@ -8,18 +8,24 @@ class PostcodeService return unless postcode.match(POSTCODE_REGEXP) postcode_lookup = nil + begin # URI encoding only supports ASCII characters + # Example response for postcode SE27 0AL: ascii_postcode = self.class.clean(postcode) Timeout.timeout(5) { postcode_lookup = @pio.lookup(ascii_postcode) } rescue Timeout::Error Rails.logger.warn("Postcodes.io lookup timed out") end + if postcode_lookup && postcode_lookup.info.present? - { + OpenStruct.new({ location_code: postcode_lookup.codes["admin_district"], location_admin_district: postcode_lookup&.admin_district, - } + incode: postcode_lookup.incode, + outcode: postcode_lookup.outcode, + result?: postcode_lookup.outcode.present?, + }) end end diff --git a/db/migrate/20221018221143_add_postcode_to_sales_log.rb b/db/migrate/20221018221143_add_postcode_to_sales_log.rb index 047e51764..910da371e 100644 --- a/db/migrate/20221018221143_add_postcode_to_sales_log.rb +++ b/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 :pcode2, :string, default: nil # Incode e.g. 0HG t.column :pcodenk, :boolean, default: true # Not Known + + t.column :postcode_known, :integer + t.column :la_known, :integer end end end diff --git a/db/schema.rb b/db/schema.rb index 6866641fb..863dcbfc3 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -391,6 +391,8 @@ ActiveRecord::Schema[7.0].define(version: 2022_10_18_221143) do t.string "pcode1" t.string "pcode2" 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 ["managing_organisation_id"], name: "index_sales_logs_on_managing_organisation_id" t.index ["owning_organisation_id"], name: "index_sales_logs_on_owning_organisation_id"