Browse Source

CLDC-933 update household income questions (#273)

* Change net income known question

* earnings and frequency on same page

* check answers changes and other fixes

* some fixes

* delete unnecessary test

* fix failing spec

* Refactor answer label

Co-authored-by: baarkerlounger  <baarkerlounger@users.noreply.github.com>

* test and lint fixes

* Method args

* Fix specs

* Rubocop

* Incfreq doesn't have it's own check answers display

* Add suffix to actual form

* JSON linting

* Conditional suffix only applies to check answers

* Validate that earnings and incfreq must be provided together

* Rubocop

* Fix spec

* Fix page view specs

* form fixes

* update error messages

Co-authored-by: baarkerlounger  <baarkerlounger@users.noreply.github.com>
Co-authored-by: baarkerlounger <db@slothlife.xyz>
pull/283/head
Dushan 3 years ago committed by GitHub
parent
commit
6360c56da5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      app/helpers/check_answers_helper.rb
  2. 17
      app/models/case_log.rb
  3. 9
      app/models/constants/case_log.rb
  4. 4
      app/models/form.rb
  5. 33
      app/models/form/question.rb
  6. 18
      app/models/validations/financial_validations.rb
  7. 2
      app/views/form/_check_answers_table.html.erb
  8. 2
      app/views/form/_numeric_question.html.erb
  9. 93
      config/forms/2021_2022.json
  10. 2
      config/locales/en.yml
  11. 3
      spec/factories/case_log.rb
  12. 3
      spec/fixtures/complete_case_log.json
  13. 6
      spec/fixtures/forms/2021_2022.json
  14. 11
      spec/models/case_log_spec.rb
  15. 28
      spec/models/form/question_spec.rb
  16. 24
      spec/models/validations/financial_validations_spec.rb
  17. 1
      spec/models/validations/property_validations_spec.rb
  18. 21
      spec/views/form/page_view_spec.rb

8
app/helpers/check_answers_helper.rb

@ -12,12 +12,6 @@ module CheckAnswersHelper
end end
def get_answer_label(question, case_log) def get_answer_label(question, case_log)
answer = question.prefix == "£" ? ActionController::Base.helpers.number_to_currency(question.answer_label(case_log), delimiter: ",", format: "%n") : question.answer_label(case_log) question.answer_label(case_log).presence || "<span class=\"app-!-colour-muted\">You didn’t answer this question</span>".html_safe
if answer.present?
[question.prefix, answer, question.suffix].join("")
else
"<span class=\"app-!-colour-muted\">You didn’t answer this question</span>".html_safe
end
end end
end end

17
app/models/case_log.rb

@ -243,22 +243,7 @@ private
self.month = startdate.month self.month = startdate.month
self.year = startdate.year self.year = startdate.year
end end
case net_income_known self.incref = 1 if net_income_known == "Tenant prefers not to say"
when "Weekly"
self.incfreq = "Weekly"
self.incref = nil
when "Monthly"
self.incfreq = "Monthly"
self.incref = nil
when "Annually"
self.incfreq = "Yearly"
self.incref = nil
when "Tenant prefers not to say"
self.incref = 1
self.incfreq = nil
when "Don’t know"
self.incfreq = nil
end
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[:provider_type]}" if renttype.present? && needstype.present? && owning_organisation[:provider_type].present? self.lettype = "#{renttype} #{needstype} #{owning_organisation[:provider_type]}" if renttype.present? && needstype.present? && owning_organisation[:provider_type].present?

9
app/models/constants/case_log.rb

@ -1071,11 +1071,10 @@ module Constants::CaseLog
}.freeze }.freeze
NET_INCOME_KNOWN = { NET_INCOME_KNOWN = {
"Weekly" => 0, "Yes" => 0,
"Monthly" => 1, "No" => 1,
"Annually" => 2, "Tenant prefers not to say" => 2,
"Tenant prefers not to say" => 3, "Don’t know" => 3,
"Don’t know" => 4,
}.freeze }.freeze
HAS_BENEFITS_OPTIONS = ["Housing benefit", HAS_BENEFITS_OPTIONS = ["Housing benefit",

4
app/models/form.rb

@ -24,6 +24,10 @@ class Form
pages.find { |p| p.id == id.to_s.underscore } pages.find { |p| p.id == id.to_s.underscore }
end end
def get_question(id)
questions.find { |q| q.id == id.to_s.underscore }
end
def subsection_for_page(page) def subsection_for_page(page)
subsections.find { |s| s.pages.find { |p| p.id == page.id } } subsections.find { |s| s.pages.find { |p| p.id == page.id } }
end end

33
app/models/form/question.rb

@ -38,7 +38,10 @@ class Form::Question
return checkbox_answer_label(case_log) if type == "checkbox" return checkbox_answer_label(case_log) if type == "checkbox"
return case_log[id]&.to_formatted_s(:govuk_date).to_s if type == "date" return case_log[id]&.to_formatted_s(:govuk_date).to_s if type == "date"
return case_log[id].to_s if case_log[id].present? answer = case_log[id].to_s if case_log[id].present?
answer_label = [prefix, format_value(answer), suffix_label(case_log)].join("") if answer
return answer_label if answer_label
has_inferred_check_answers_value?(case_log) ? inferred_check_answers_value["value"] : "" has_inferred_check_answers_value?(case_log) ? inferred_check_answers_value["value"] : ""
end end
@ -96,6 +99,28 @@ private
answer.join(", ") answer.join(", ")
end end
def format_value(answer_label)
prefix == "£" ? ActionController::Base.helpers.number_to_currency(answer_label, delimiter: ",", format: "%n") : answer_label
end
def suffix_label(case_log)
return "" unless suffix
return suffix if suffix.is_a?(String)
label = ""
suffix.each do |s|
condition = s["depends_on"]
next unless condition
answer = case_log.send(condition.keys.first)
if answer == condition.values.first
label = ANSWER_SUFFIX_LABELS.key?(answer.to_sym) ? ANSWER_SUFFIX_LABELS[answer.to_sym] : answer
end
end
label
end
def conditional_on def conditional_on
@conditional_on ||= form.conditional_question_conditions.select do |condition| @conditional_on ||= form.conditional_question_conditions.select do |condition|
condition[:to] == id condition[:to] == id
@ -118,4 +143,10 @@ private
def enabled_inferred_answers(inferred_answers, case_log) def enabled_inferred_answers(inferred_answers, case_log)
inferred_answers.filter { |_key, value| value.all? { |condition_key, condition_value| case_log[condition_key] == condition_value } } inferred_answers.filter { |_key, value| value.all? { |condition_key, condition_value| case_log[condition_key] == condition_value } }
end end
ANSWER_SUFFIX_LABELS = {
"Weekly": " every week",
"Monthly": " every month",
"Yearly": " every year",
}.freeze
end end

18
app/models/validations/financial_validations.rb

@ -21,14 +21,22 @@ module Validations::FinancialValidations
end end
def validate_net_income(record) def validate_net_income(record)
return unless record.ecstat1 && record.weekly_net_income if record.ecstat1 && record.weekly_net_income
if record.weekly_net_income > record.applicable_income_range.hard_max
record.errors.add :earnings, I18n.t("validations.financial.earnings.under_hard_max", hard_max: record.applicable_income_range.hard_max)
end
if record.weekly_net_income < record.applicable_income_range.hard_min
record.errors.add :earnings, I18n.t("validations.financial.earnings.over_hard_min", hard_min: record.applicable_income_range.hard_min)
end
end
if record.weekly_net_income > record.applicable_income_range.hard_max if record.earnings.present? && record.incfreq.blank?
record.errors.add :earnings, I18n.t("validations.financial.earnings.under_hard_max", hard_max: record.applicable_income_range.hard_max) record.errors.add :incfreq, I18n.t("validations.financial.earnings.freq_missing")
end end
if record.weekly_net_income < record.applicable_income_range.hard_min if record.incfreq.present? && record.earnings.blank?
record.errors.add :earnings, I18n.t("validations.financial.earnings.over_hard_min", hard_min: record.applicable_income_range.hard_min) record.errors.add :earnings, I18n.t("validations.financial.earnings.earnings_missing")
end end
end end

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

@ -1,6 +1,6 @@
<div class="govuk-summary-list__row"> <div class="govuk-summary-list__row">
<dt class="govuk-summary-list__key"> <dt class="govuk-summary-list__key">
<%= question.check_answer_label.to_s.present? ? question.check_answer_label.to_s : question.header.to_s %> <%= question.check_answer_label.to_s.present? ? question.check_answer_label.to_s : question.header.to_s %>
</dt> </dt>
<dd class="govuk-summary-list__value"> <dd class="govuk-summary-list__value">
<%= get_answer_label(question, @case_log) %><br/> <%= get_answer_label(question, @case_log) %><br/>

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

@ -7,6 +7,6 @@
min: question.min, max: question.max, step: question.step, min: question.min, max: question.max, step: question.step,
width: question.width, :readonly => question.read_only?, width: question.width, :readonly => question.read_only?,
prefix_text: question.prefix.to_s, prefix_text: question.prefix.to_s,
suffix_text: question.suffix.to_s, suffix_text: question.suffix.is_a?(String) ? question.suffix : nil,
**stimulus_html_attributes(question) **stimulus_html_attributes(question)
%> %>

93
config/forms/2021_2022.json

@ -2292,95 +2292,56 @@
"depends_on": [{ "setup": "completed" }], "depends_on": [{ "setup": "completed" }],
"pages": { "pages": {
"net_income_known": { "net_income_known": {
"header": "Household’s combined income", "header": "",
"description": "", "description": "",
"questions": { "questions": {
"net_income_known": { "net_income_known": {
"check_answer_label": "How often household receives income", "check_answer_label": "Do you know the household’s combined income?",
"header": "How often does the household receive income?", "header": "Do you know the household’s combined income?",
"guidance_partial": "what_counts_as_income",
"hint_text": "", "hint_text": "",
"type": "radio", "type": "radio",
"answer_options": { "answer_options": {
"0": "Weekly", "0": "Yes",
"1": "Monthly", "1": "No",
"2": "Annually",
"divider_a": true, "divider_a": true,
"3": "Don’t know", "2": "Don’t know",
"4": "Tenant prefers not to say" "3": "Tenant prefers not to say"
} }
} }
} }
}, },
"weekly_net_income": { "net_income": {
"depends_on": [{ "net_income_known": "Weekly" }], "depends_on": [{ "net_income_known": "Yes" }],
"header": "", "header": "Household’s combined income after tax",
"description": "", "description": "",
"questions": { "questions": {
"earnings": { "earnings": {
"check_answer_label": "Total household income", "check_answer_label": "Total household income",
"header": "How much income does the household have in total every week?", "header": "How much income does the household have in total?",
"guidance_partial": "what_counts_as_income",
"hint_text": "", "hint_text": "",
"type": "numeric", "type": "numeric",
"min": 0, "min": 0,
"step": "1", "step": "1",
"width": 5, "width": 5,
"prefix": "£", "prefix": "£",
"suffix": " every week" "suffix": [
} { "label": "every week", "depends_on" : { "incfreq": "Weekly" } },
}, { "label": "every month", "depends_on" : { "incfreq": "Monthly" } },
"soft_validations": { { "label": "every month", "depends_on" : { "incfreq": "Yearly" } }
"override_net_income_validation": { ]
"check_answer_label": "Net income confirmed?", },
"type": "validation_override", "incfreq": {
"answer_options": { "check_answer_label": "How often does the household receive this amount?",
"override_net_income_validation": "Yes" "header": "How often does the household receive this amount?",
}
}
}
},
"monthly_net_income": {
"depends_on": [{ "net_income_known": "Monthly" }],
"header": "",
"description": "",
"questions": {
"earnings": {
"check_answer_label": "Total household income",
"header": "How much income does the household have in total every month?",
"hint_text": "", "hint_text": "",
"type": "numeric", "type": "radio",
"min": 0,
"step": "1",
"width": 5,
"prefix": "£",
"suffix": " every month"
}
},
"soft_validations": {
"override_net_income_validation": {
"check_answer_label": "Net income confirmed?",
"type": "validation_override",
"answer_options": { "answer_options": {
"override_net_income_validation": "Yes" "0": "Weekly",
} "1": "Monthly",
} "2": "Yearly"
} },
}, "hidden_in_check_answers": true
"yearly_net_income": {
"depends_on": [{ "net_income_known": "Annually" }],
"header": "",
"description": "",
"questions": {
"earnings": {
"check_answer_label": "Total household income",
"header": "How much income does the household have in total every year?",
"hint_text": "",
"type": "numeric",
"min": 0,
"step": "1",
"width": 5,
"prefix": "£",
"suffix": " every year"
} }
}, },
"soft_validations": { "soft_validations": {

2
config/locales/en.yml

@ -68,6 +68,8 @@ en:
earnings: earnings:
under_hard_max: "Net income cannot be greater than %{hard_max} given the tenant’s working situation" under_hard_max: "Net income cannot be greater than %{hard_max} given the tenant’s working situation"
over_hard_min: "Net income cannot be less than %{hard_min} given the tenant’s working situation" over_hard_min: "Net income cannot be less than %{hard_min} given the tenant’s working situation"
freq_missing: "Select how often the household receives income"
earnings_missing: "Enter how much income the household has in total"
household: household:
reasonpref: reasonpref:

3
spec/factories/case_log.rb

@ -69,6 +69,7 @@ FactoryBot.define do
offered { 2 } offered { 2 }
wchair { "Yes" } wchair { "Yes" }
earnings { 68 } earnings { 68 }
incfreq { "Weekly" }
benefits { "Some" } benefits { "Some" }
period { "Every 2 weeks" } period { "Every 2 weeks" }
brent { 200 } brent { 200 }
@ -110,7 +111,7 @@ FactoryBot.define do
discarded_at { nil } discarded_at { nil }
tenancyother { nil } tenancyother { nil }
override_net_income_validation { nil } override_net_income_validation { nil }
net_income_known { "Weekly" } net_income_known { "Yes" }
property_owner_organisation { "Test" } property_owner_organisation { "Test" }
property_manager_organisation { "Test" } property_manager_organisation { "Test" }
renewal { 1 } renewal { 1 }

3
spec/fixtures/complete_case_log.json vendored

@ -74,8 +74,9 @@
"mrcyear": 2020, "mrcyear": 2020,
"offered": 2, "offered": 2,
"wchair": "Yes", "wchair": "Yes",
"net_income_known": "Weekly", "net_income_known": "Yes",
"earnings": 150, "earnings": 150,
"incfreq": "Weekly",
"benefits": "Some", "benefits": "Some",
"hb": "Universal Credit with housing element (excluding housing benefit)", "hb": "Universal Credit with housing element (excluding housing benefit)",
"period": "Every 2 weeks", "period": "Every 2 weeks",

6
spec/fixtures/forms/2021_2022.json vendored

@ -358,7 +358,11 @@
"step": 1, "step": 1,
"width": 5, "width": 5,
"prefix": "£", "prefix": "£",
"suffix": "incfreq" "suffix": [
{ "label": "every week", "depends_on" : { "incfreq": "Weekly" } },
{ "label": "every month", "depends_on" : { "incfreq": "Monthly" } },
{ "label": "every month", "depends_on" : { "incfreq": "Yearly" } }
]
}, },
"incfreq": { "incfreq": {
"check_answer_label": "Income Frequency", "check_answer_label": "Income Frequency",

11
spec/models/case_log_spec.rb

@ -1092,17 +1092,6 @@ RSpec.describe CaseLog do
end end
end end
context "when saving net_income" do
it "infers the income frequency" do
case_log.update!(net_income_known: "Weekly")
expect(case_log.reload.incfreq).to eq("Weekly")
case_log.update!(net_income_known: "Monthly")
expect(case_log.reload.incfreq).to eq("Monthly")
case_log.update!(net_income_known: "Annually")
expect(case_log.reload.incfreq).to eq("Yearly")
end
end
context "when saving rent and charges" do context "when saving rent and charges" do
let!(:case_log) do let!(:case_log) do
described_class.create({ described_class.create({

28
spec/models/form/question_spec.rb

@ -99,16 +99,17 @@ RSpec.describe Form::Question, type: :model do
context "with a case log" do context "with a case log" do
let(:case_log) { FactoryBot.build(:case_log, :in_progress) } let(:case_log) { FactoryBot.build(:case_log, :in_progress) }
let(:question_id) { "incfreq" }
it "has an answer label" do it "has an answer label" do
case_log.earnings = 100 case_log.incfreq = "Weekly"
expect(question.answer_label(case_log)).to eq("100") expect(question.answer_label(case_log)).to eq("Weekly")
end end
it "has an update answer link text helper" do it "has an update answer link text helper" do
expect(question.update_answer_link_name(case_log)).to eq("Answer<span class=\"govuk-visually-hidden\"> income</span>") expect(question.update_answer_link_name(case_log)).to match(/Answer/)
case_log[question_id] = 5 case_log["incfreq"] = "Weekly"
expect(question.update_answer_link_name(case_log)).to eq("Change<span class=\"govuk-visually-hidden\"> income</span>") expect(question.update_answer_link_name(case_log)).to match(/Change/)
end end
context "when type is date" do context "when type is date" do
@ -155,6 +156,23 @@ RSpec.describe Form::Question, type: :model do
expect(question.enabled?(case_log)).to be true expect(question.enabled?(case_log)).to be true
end end
end end
context "when answers have a suffix dependent on another answer" do
let(:section_id) { "rent_and_charges" }
let(:subsection_id) { "income_and_benefits" }
let(:page_id) { "net_income" }
let(:question_id) { "earnings" }
it "displays the correct label for given suffix and answer the suffix depends on" do
case_log.incfreq = "Weekly"
case_log.earnings = 500
expect(question.answer_label(case_log)).to eq("£500.00 every week")
case_log.incfreq = "Monthly"
expect(question.answer_label(case_log)).to eq("£500.00 every month")
case_log.incfreq = "Yearly"
expect(question.answer_label(case_log)).to eq("£500.00 every year")
end
end
end end
describe ".completed?" do describe ".completed?" do

24
spec/models/validations/financial_validations_spec.rb

@ -0,0 +1,24 @@
require "rails_helper"
RSpec.describe Validations::FinancialValidations do
subject(:financial_validator) { validator_class.new }
let(:validator_class) { Class.new { include Validations::FinancialValidations } }
let(:record) { FactoryBot.create(:case_log) }
describe "earnings and income frequency" do
it "when earnings are provided it validates that income frequency must be provided" do
record.earnings = 500
record.incfreq = nil
financial_validator.validate_net_income(record)
expect(record.errors["incfreq"]).to include(match I18n.t("validations.financial.earnings.freq_missing"))
end
it "when income frequency is provided it validates that earnings must be provided" do
record.earnings = nil
record.incfreq = "Weekly"
financial_validator.validate_net_income(record)
expect(record.errors["earnings"]).to include(match I18n.t("validations.financial.earnings.earnings_missing"))
end
end
end

1
spec/models/validations/property_validations_spec.rb

@ -1,5 +1,4 @@
require "rails_helper" require "rails_helper"
require_relative "../../request_helper"
RSpec.describe Validations::PropertyValidations do RSpec.describe Validations::PropertyValidations do
subject(:property_validator) { property_validator_class.new } subject(:property_validator) { property_validator_class.new }

21
spec/views/form/page_view_spec.rb

@ -70,6 +70,27 @@ RSpec.describe "form/page" do
expect(rendered).to match(/govuk-input__suffix/) expect(rendered).to match(/govuk-input__suffix/)
expect(rendered).to match("every week") expect(rendered).to match("every week")
end end
context "when the suffix is conditional and not a string" do
let(:question_attributes) do
{
type: "numeric",
prefix: "£",
suffix: [
{ "label": "every week", "depends_on": { "incfreq": "Weekly" } },
{ "label": "every month", "depends_on": { "incfreq": "Monthly" } },
{ "label": "every month", "depends_on": { "incfreq": "Yearly" } },
],
}
end
it "does not render the suffix" do
expect(rendered).not_to match(/govuk-input__suffix/)
expect(rendered).not_to match("every week")
expect(rendered).not_to match("every month")
expect(rendered).not_to match("every year")
end
end
end end
context "with a question containing extra guidance" do context "with a question containing extra guidance" do

Loading…
Cancel
Save