Browse Source

CDLC-504: Introduce regexp validation of property postcodes (#207)

Introduce regexp validation of property postcodes
Only changes the status after validation
Clean up logging and fix failing test on minimal earning
pull/211/head
Stéphane Meny 3 years ago committed by GitHub
parent
commit
e16fae8810
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 53
      app/models/case_log.rb
  2. 8
      app/models/validations/property_validations.rb
  3. 2
      config/forms/2021_2022.json
  4. 2
      spec/factories/case_log.rb
  5. 2
      spec/features/form/accessible_autocomplete_spec.rb
  6. 2
      spec/features/form/page_routing_spec.rb
  7. 2
      spec/features/form/saving_data_spec.rb
  8. 2
      spec/fixtures/complete_case_log.json
  9. 5
      spec/models/case_log_spec.rb
  10. 11
      spec/requests/case_log_controller_spec.rb

53
app/models/case_log.rb

@ -36,6 +36,9 @@ class CaseLog < ApplicationRecord
validates_with CaseLogValidator validates_with CaseLogValidator
before_save :update_status! before_save :update_status!
before_validation :process_postcode_changes!, if: :property_postcode_changed?
before_validation :reset_location_fields!, unless: :postcode_known?
before_validation :set_derived_fields!
belongs_to :owning_organisation, class_name: "Organisation" belongs_to :owning_organisation, class_name: "Organisation"
belongs_to :managing_organisation, class_name: "Organisation" belongs_to :managing_organisation, class_name: "Organisation"
@ -168,6 +171,10 @@ class CaseLog < ApplicationRecord
status == "in_progress" status == "in_progress"
end end
def postcode_known?
postcode_known == "Yes"
end
def weekly_net_income def weekly_net_income
return unless earnings && incfreq return unless earnings && incfreq
@ -203,10 +210,9 @@ private
else else
"in_progress" "in_progress"
end end
set_derived_fields
end end
def set_derived_fields def set_derived_fields!
if previous_postcode.present? if previous_postcode.present?
self.ppostc1 = UKPostcode.parse(previous_postcode).outcode self.ppostc1 = UKPostcode.parse(previous_postcode).outcode
self.ppostc2 = UKPostcode.parse(previous_postcode).incode self.ppostc2 = UKPostcode.parse(previous_postcode).incode
@ -234,26 +240,33 @@ private
self.hhmemb = other_hhmemb + 1 if other_hhmemb.present? self.hhmemb = other_hhmemb + 1 if other_hhmemb.present?
self.renttype = RENT_TYPE_MAPPING[rent_type] self.renttype = RENT_TYPE_MAPPING[rent_type]
self.lettype = "#{renttype} #{needstype} #{owning_organisation['Org type']}" if renttype.present? && needstype.present? && owning_organisation["Org type"].present? self.lettype = "#{renttype} #{needstype} #{owning_organisation['Org type']}" if renttype.present? && needstype.present? && owning_organisation["Org type"].present?
self.is_la_inferred = false if is_la_inferred.nil?
if property_postcode.blank? || postcode_known == "No"
reset_location_fields
else
inferred_la = get_inferred_la(property_postcode)
self.is_la_inferred = inferred_la.present?
self.la = inferred_la if inferred_la.present?
end
if property_postcode.present?
self.postcode = UKPostcode.parse(property_postcode).outcode
self.postcod2 = UKPostcode.parse(property_postcode).incode
else
self.postcode = self.postcod2 = nil
end
self.totchild = get_totchild self.totchild = get_totchild
self.totelder = get_totelder self.totelder = get_totelder
self.totadult = get_totadult self.totadult = get_totadult
self.tcharge = brent.to_i + scharge.to_i + pscharge.to_i + supcharg.to_i self.tcharge = brent.to_i + scharge.to_i + pscharge.to_i + supcharg.to_i
end end
def process_postcode_changes!
return if property_postcode.blank?
self.postcode_known = "Yes"
inferred_la = get_inferred_la(property_postcode)
self.is_la_inferred = inferred_la.present?
self.la = inferred_la if inferred_la.present?
self.postcode = UKPostcode.parse(property_postcode).outcode
self.postcod2 = UKPostcode.parse(property_postcode).incode
end
def reset_location_fields!
if is_la_inferred == true
self.la = nil
end
self.is_la_inferred = false
self.property_postcode = nil
self.postcode = nil
self.postcod2 = nil
end
def get_totelder def get_totelder
ages = [age1, age2, age3, age4, age5, age6, age7, age8] ages = [age1, age2, age3, age4, age5, age6, age7, age8]
ages.count { |x| !x.nil? && x >= 60 } ages.count { |x| !x.nil? && x >= 60 }
@ -281,14 +294,6 @@ private
end end
end end
def reset_location_fields
if is_la_inferred == true
self.la = nil
end
self.is_la_inferred = false
self.property_postcode = nil
end
def all_fields_completed? def all_fields_completed?
mandatory_fields.none? { |_key, val| val.nil? } mandatory_fields.none? { |_key, val| val.nil? }
end end

8
app/models/validations/property_validations.rb

@ -3,6 +3,8 @@ module Validations::PropertyValidations
# or 'validate_' to run on submit as well # or 'validate_' to run on submit as well
include Constants::CaseLog include Constants::CaseLog
POSTCODE_REGEXP = /^(([A-Z]{1,2}[0-9][A-Z0-9]?|ASCN|STHL|TDCU|BBND|[BFS]IQQ|PCRN|TKCA) ?[0-9][A-Z]{2}|BFPO ?[0-9]{1,4}|(KY[0-9]|MSR|VG|AI)[ -]?[0-9]{4}|[A-Z]{2} ?[0-9]{2}|GE ?CX|GIR ?0A{2}|SAN ?TA1)$/
def validate_property_number_of_times_relet(record) def validate_property_number_of_times_relet(record)
if record.offered && !/^[1-9]$|^0[1-9]$|^1[0-9]$|^20$/.match?(record.offered.to_s) if record.offered && !/^[1-9]$|^0[1-9]$|^1[0-9]$|^20$/.match?(record.offered.to_s)
record.errors.add :offered, "Property number of times relet must be between 0 and 20" record.errors.add :offered, "Property number of times relet must be between 0 and 20"
@ -35,8 +37,10 @@ module Validations::PropertyValidations
end end
def validate_property_postcode(record) def validate_property_postcode(record)
if record.postcode_known == "Yes" && record.property_postcode.blank? postcode = record.property_postcode
record.errors.add :property_postcode, "Enter a postcode in the correct format, for example AA1 1AA" if record.postcode_known == "Yes" && (postcode.blank? || !postcode.match(POSTCODE_REGEXP))
error_message = "Enter a postcode in the correct format, for example AA1 1AA"
record.errors.add :property_postcode, error_message
end end
end end
end end

2
config/forms/2021_2022.json

@ -2517,7 +2517,7 @@
"description": "", "description": "",
"questions": { "questions": {
"previous_postcode": { "previous_postcode": {
"check_answer_label": "Postcode of previous accomodation if the household has moved from settled accommodation", "check_answer_label": "Postcode of previous accommodation if the household has moved from settled accommodation",
"header": "Postcode for the previous accommodation", "header": "Postcode for the previous accommodation",
"hint_text": "If the household has moved from settled accommodation immediately prior to being re-housed", "hint_text": "If the household has moved from settled accommodation immediately prior to being re-housed",
"type": "text" "type": "text"

2
spec/factories/case_log.rb

@ -14,7 +14,7 @@ FactoryBot.define do
trait :in_progress do trait :in_progress do
status { 1 } status { 1 }
tenant_code { "TH356" } tenant_code { "TH356" }
property_postcode { "P0 5ST" } property_postcode { "PO5 3TE" }
previous_postcode { "SW2 6HI" } previous_postcode { "SW2 6HI" }
age1 { "17" } age1 { "17" }
end end

2
spec/features/form/accessible_autocomplete_spec.rb

@ -39,7 +39,7 @@ RSpec.describe "Accessible Automcomplete" do
end end
it "has the correct option selected if one has been saved" do it "has the correct option selected if one has been saved" do
case_log.update!(property_postcode: nil, la: "Oxford") case_log.update!(postcode_known: "No", la: "Oxford")
visit("/logs/#{case_log.id}/accessible-select") visit("/logs/#{case_log.id}/accessible-select")
expect(page).to have_select("case-log-la-field", selected: %w[Oxford]) expect(page).to have_select("case-log-la-field", selected: %w[Oxford])
end end

2
spec/features/form/page_routing_spec.rb

@ -51,7 +51,7 @@ RSpec.describe "Form Page Routing" do
context "inferred answers routing", js: true do context "inferred answers routing", js: true do
it "shows question if the answer could not be inferred" do it "shows question if the answer could not be inferred" do
visit("/logs/#{id}/property-postcode") visit("/logs/#{id}/property-postcode")
fill_in("case-log-property-postcode-field", with: "P0 5ST") fill_in("case-log-property-postcode-field", with: "PO5 3TE")
click_button("Save and continue") click_button("Save and continue")
expect(page).to have_current_path("/logs/#{id}/do-you-know-the-local-authority") expect(page).to have_current_path("/logs/#{id}/do-you-know-the-local-authority")
end end

2
spec/features/form/saving_data_spec.rb

@ -75,7 +75,7 @@ RSpec.describe "Form Saving Data" do
it "displays number answers in inputs if they are already saved" do it "displays number answers in inputs if they are already saved" do
visit("/logs/#{id}/property-postcode") visit("/logs/#{id}/property-postcode")
expect(page).to have_field("case-log-property-postcode-field", with: "P0 5ST") expect(page).to have_field("case-log-property-postcode-field", with: "PO5 3TE")
end end
it "displays text answers in inputs if they are already saved" do it "displays text answers in inputs if they are already saved" do

2
spec/fixtures/complete_case_log.json vendored

@ -75,7 +75,7 @@
"offered": 2, "offered": 2,
"wchair": "Yes", "wchair": "Yes",
"net_income_known": "Yes – the household has a weekly income", "net_income_known": "Yes – the household has a weekly income",
"earnings": 0, "earnings": 150,
"benefits": "Some", "benefits": "Some",
"hb": "Universal Credit with housing element, but not Housing Benefit", "hb": "Universal Credit with housing element, but not Housing Benefit",
"period": "Fortnightly", "period": "Fortnightly",

5
spec/models/case_log_spec.rb

@ -1121,6 +1121,11 @@ RSpec.describe Form, type: :model do
.to raise_error(ActiveRecord::RecordInvalid, /Enter a postcode in the correct format/) .to raise_error(ActiveRecord::RecordInvalid, /Enter a postcode in the correct format/)
end end
it "errors if the property postcode is not valid" do
expect { address_case_log.update!({ property_postcode: "invalid_postcode" }) }
.to raise_error(ActiveRecord::RecordInvalid, /Enter a postcode in the correct format/)
end
it "correctly resets all fields if property postcode not known" do it "correctly resets all fields if property postcode not known" do
address_case_log.update!({ postcode_known: "No" }) address_case_log.update!({ postcode_known: "No" })

11
spec/requests/case_log_controller_spec.rb

@ -99,6 +99,7 @@ RSpec.describe CaseLogsController, type: :request do
it "marks the record as completed" do it "marks the record as completed" do
json_response = JSON.parse(response.body) json_response = JSON.parse(response.body)
expect(json_response).not_to have_key("errors") expect(json_response).not_to have_key("errors")
expect(json_response["status"]).to eq(completed) expect(json_response["status"]).to eq(completed)
end end
@ -261,7 +262,7 @@ RSpec.describe CaseLogsController, type: :request do
owning_organisation: organisation, owning_organisation: organisation,
managing_organisation: organisation, managing_organisation: organisation,
postcode_known: "Yes", postcode_known: "Yes",
property_postcode: "P0 0ST") property_postcode: "PO5 3TE")
id = case_log.id id = case_log.id
get "/logs/#{id}/property-information/check-answers" get "/logs/#{id}/property-information/check-answers"
expected_inferred_answer = "<span class=\"govuk-!-font-weight-regular app-!-colour-muted\">Manchester</span>" expected_inferred_answer = "<span class=\"govuk-!-font-weight-regular app-!-colour-muted\">Manchester</span>"
@ -282,7 +283,7 @@ RSpec.describe CaseLogsController, type: :request do
describe "PATCH" do describe "PATCH" do
let(:case_log) do let(:case_log) do
FactoryBot.create(:case_log, :in_progress, tenant_code: "Old Value", property_postcode: "Old Value") FactoryBot.create(:case_log, :in_progress, tenant_code: "Old Value", property_postcode: "M1 1AE")
end end
let(:params) do let(:params) do
{ tenant_code: "New Value" } { tenant_code: "New Value" }
@ -300,7 +301,7 @@ RSpec.describe CaseLogsController, type: :request do
it "updates the case log with the given fields and keeps original values where none are passed" do it "updates the case log with the given fields and keeps original values where none are passed" do
case_log.reload case_log.reload
expect(case_log.tenant_code).to eq("New Value") expect(case_log.tenant_code).to eq("New Value")
expect(case_log.property_postcode).to eq("Old Value") expect(case_log.property_postcode).to eq("M1 1AE")
end end
context "invalid case log id" do context "invalid case log id" do
@ -340,7 +341,7 @@ RSpec.describe CaseLogsController, type: :request do
# what actually happens to an ActiveRecord object and what we're doing here, but either is allowed. # what actually happens to an ActiveRecord object and what we're doing here, but either is allowed.
describe "PUT" do describe "PUT" do
let(:case_log) do let(:case_log) do
FactoryBot.create(:case_log, :in_progress, tenant_code: "Old Value", property_postcode: "Old Value") FactoryBot.create(:case_log, :in_progress, tenant_code: "Old Value", property_postcode: "SW1A 2AA")
end end
let(:params) do let(:params) do
{ tenant_code: "New Value" } { tenant_code: "New Value" }
@ -358,7 +359,7 @@ RSpec.describe CaseLogsController, type: :request do
it "updates the case log with the given fields and keeps original values where none are passed" do it "updates the case log with the given fields and keeps original values where none are passed" do
case_log.reload case_log.reload
expect(case_log.tenant_code).to eq("New Value") expect(case_log.tenant_code).to eq("New Value")
expect(case_log.property_postcode).to eq("Old Value") expect(case_log.property_postcode).to eq("SW1A 2AA")
end end
context "invalid case log id" do context "invalid case log id" do

Loading…
Cancel
Save