From 348cb183ebea7fddb775ddd581f091ce39816239 Mon Sep 17 00:00:00 2001 From: baarkerlounger <5101747+baarkerlounger@users.noreply.github.com> Date: Fri, 7 Jan 2022 15:46:00 +0000 Subject: [PATCH] CLDC-825: Support suffixes and prefixes for numeric fields (#198) * Income frequency is derived rather than asked * Render prefix and suffix * Set header and suffix based on previous answer * Readme --- README.md | 2 + app/models/case_log.rb | 24 ++++--- app/models/form/question.rb | 4 +- app/views/form/_numeric_question.html.erb | 2 + config/forms/2021_2022.json | 78 ++++++++++++++++++----- spec/factories/case_log.rb | 1 - spec/fixtures/complete_case_log.json | 1 - spec/fixtures/forms/2021_2022.json | 4 +- spec/models/case_log_spec.rb | 11 ++++ spec/views/form/page_view_spec.rb | 39 ++++++++---- 10 files changed, 124 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 61956894b..26c2431fb 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,8 @@ The JSON should follow the structure: "max": Integer, // numeric only "step": Integer, // numeric only "width": 2 / 3 / 4 / 5 / 10 / 20, // text and numeric only + "prefix": String, // numeric only + "suffix": String, //numeric only "answer_options": { // checkbox and radio only "0": String, "1": String diff --git a/app/models/case_log.rb b/app/models/case_log.rb index 95ab75489..95afa77b5 100644 --- a/app/models/case_log.rb +++ b/app/models/case_log.rb @@ -132,7 +132,7 @@ class CaseLog < ApplicationRecord enum la_known: POLAR, _suffix: true enum net_income_known: NET_INCOME_KNOWN, _suffix: true - AUTOGENERATED_FIELDS = %w[id status created_at updated_at discarded_at renttype lettype is_la_inferred totchild totelder totadult].freeze + AUTOGENERATED_FIELDS = %w[id status created_at updated_at discarded_at renttype lettype is_la_inferred totchild totelder totadult incfreq].freeze OPTIONAL_FIELDS = %w[postcode_known la_known first_time_property_let_as_social_housing].freeze @@ -215,7 +215,16 @@ private self.month = startdate.month self.year = startdate.year end - self.incref = 1 if net_income_known == "Tenant prefers not to say" + case net_income_known + when "Yes – the household has a weekly income" + self.incfreq = "Weekly" + when "Yes – the household has a monthly income" + self.incfreq = "Monthly" + when "Yes – the household has a yearly income" + self.incfreq = "Yearly" + when "Tenant prefers not to say" + self.incref = 1 + end self.hhmemb = other_hhmemb + 1 if other_hhmemb.present? 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? @@ -316,12 +325,11 @@ private dynamically_not_required << "tenancyother" end - if net_income_known == "Tenant prefers not to say" - dynamically_not_required << "earnings" - dynamically_not_required << "incfreq" - else - dynamically_not_required << "incref" - end + dynamically_not_required << if net_income_known == "Tenant prefers not to say" + "earnings" + else + "incref" + end start_range = (other_hhmemb || 0) + 2 (start_range..8).each do |n| diff --git a/app/models/form/question.rb b/app/models/form/question.rb index e4e843c0e..6bf5039ca 100644 --- a/app/models/form/question.rb +++ b/app/models/form/question.rb @@ -3,7 +3,7 @@ class Form::Question :type, :min, :max, :step, :width, :fields_to_add, :result_field, :conditional_for, :readonly, :answer_options, :page, :check_answer_label, :inferred_answers, :hidden_in_check_answers, :inferred_check_answers_value, - :guidance_partial + :guidance_partial, :prefix, :suffix def initialize(id, hsh, page) @id = id @@ -24,6 +24,8 @@ class Form::Question @inferred_answers = hsh["inferred_answers"] @inferred_check_answers_value = hsh["inferred_check_answers_value"] @hidden_in_check_answers = hsh["hidden_in_check_answers"] + @prefix = hsh["prefix"] + @suffix = hsh["suffix"] @page = page end diff --git a/app/views/form/_numeric_question.html.erb b/app/views/form/_numeric_question.html.erb index 49872e8ee..a0cdcb625 100644 --- a/app/views/form/_numeric_question.html.erb +++ b/app/views/form/_numeric_question.html.erb @@ -6,5 +6,7 @@ hint: { text: question.hint_text&.html_safe }, min: question.min, max: question.max, step: question.step, width: question.width, :readonly => question.read_only?, + prefix_text: question.prefix.to_s, + suffix_text: question.suffix.to_s, **stimulus_html_attributes(question) %> diff --git a/config/forms/2021_2022.json b/config/forms/2021_2022.json index 054825ed9..da5a0bb0e 100644 --- a/config/forms/2021_2022.json +++ b/config/forms/2021_2022.json @@ -1804,7 +1804,7 @@ "label": "Income and benefits", "depends_on": { "about_this_log": "completed" }, "pages": { - "net_income": { + "net_income_known": { "header": "Household’s combined income", "description": "", "questions": { @@ -1820,31 +1820,77 @@ "2": "Yes – the household has a yearly income", "divider_a": true, "3": "Tenant prefers not to say" - }, - "conditional_for": { - "earnings": ["Yes"], - "incfreq": ["Yes"] } - }, + } + } + }, + "weekly_net_income": { + "depends_on": { "net_income_known": "Yes – the household has a weekly income" }, + "header": "", + "description": "", + "questions": { "earnings": { "check_answer_label": "Income", - "header": "What is the tenant’s /and partner’s combined income after tax?", + "header": "How much income does the household have in total every week?", "hint_text": "", "type": "numeric", "min": 0, - "step": "1" - }, - "incfreq": { - "check_answer_label": "Income Frequency", - "header": "How often do they receive this income?", + "step": "1", + "prefix": "£", + "suffix": "every week" + } + }, + "soft_validations": { + "override_net_income_validation": { + "check_answer_label": "Net income confirmed?", + "type": "validation_override", + "answer_options": { + "override_net_income_validation": "Yes" + } + } + } + }, + "monthly_net_income": { + "depends_on": { "net_income_known": "Yes – the household has a monthly income" }, + "header": "", + "description": "", + "questions": { + "earnings": { + "check_answer_label": "Income", + "header": "How much income does the household have in total every month?", "hint_text": "", - "type": "radio", + "type": "numeric", + "min": 0, + "step": "1", + "prefix": "£", + "suffix": "every month" + } + }, + "soft_validations": { + "override_net_income_validation": { + "check_answer_label": "Net income confirmed?", + "type": "validation_override", "answer_options": { - "0": "Weekly", - "1": "Monthly", - "2": "Yearly" + "override_net_income_validation": "Yes" } } + } + }, + "yearly_net_income": { + "depends_on": { "net_income_known": "Yes – the household has a yearly income" }, + "header": "", + "description": "", + "questions": { + "earnings": { + "check_answer_label": "Income", + "header": "How much income does the household have in total every year?", + "hint_text": "", + "type": "numeric", + "min": 0, + "step": "1", + "prefix": "£", + "suffix": "every year" + } }, "soft_validations": { "override_net_income_validation": { diff --git a/spec/factories/case_log.rb b/spec/factories/case_log.rb index 2c7d4ef0a..8a07b981c 100644 --- a/spec/factories/case_log.rb +++ b/spec/factories/case_log.rb @@ -71,7 +71,6 @@ FactoryBot.define do offered { 2 } wchair { "Yes" } earnings { 68 } - incfreq { "Weekly" } benefits { "Some" } period { "Fortnightly" } brent { 200 } diff --git a/spec/fixtures/complete_case_log.json b/spec/fixtures/complete_case_log.json index b55aadba9..1ed4d5206 100644 --- a/spec/fixtures/complete_case_log.json +++ b/spec/fixtures/complete_case_log.json @@ -76,7 +76,6 @@ "wchair": "Yes", "net_income_known": "Yes – the household has a weekly income", "earnings": 0, - "incfreq": null, "benefits": "Some", "hb": "Universal Credit with housing element, but not Housing Benefit", "period": "Fortnightly", diff --git a/spec/fixtures/forms/2021_2022.json b/spec/fixtures/forms/2021_2022.json index 645acdd1a..f07da547a 100644 --- a/spec/fixtures/forms/2021_2022.json +++ b/spec/fixtures/forms/2021_2022.json @@ -372,7 +372,9 @@ "type": "numeric", "min": 0, "step": 1, - "width": 5 + "width": 5, + "prefix": "£", + "suffix": "incfreq" }, "incfreq": { "check_answer_label": "Income Frequency", diff --git a/spec/models/case_log_spec.rb b/spec/models/case_log_spec.rb index 609c751b2..88715b3ae 100644 --- a/spec/models/case_log_spec.rb +++ b/spec/models/case_log_spec.rb @@ -1167,6 +1167,17 @@ RSpec.describe Form, type: :model do end end + context "net_income" do + it "infers the income frequency" do + case_log.update!(net_income_known: "Yes – the household has a weekly income") + expect(case_log.reload.incfreq).to eq("Weekly") + case_log.update!(net_income_known: "Yes – the household has a monthly income") + expect(case_log.reload.incfreq).to eq("Monthly") + case_log.update!(net_income_known: "Yes – the household has a yearly income") + expect(case_log.reload.incfreq).to eq("Yearly") + end + end + context "household members derived vars" do let!(:household_case_log) do CaseLog.create({ diff --git a/spec/views/form/page_view_spec.rb b/spec/views/form/page_view_spec.rb index 2666421b0..ac7c8c9b6 100644 --- a/spec/views/form/page_view_spec.rb +++ b/spec/views/form/page_view_spec.rb @@ -11,7 +11,7 @@ RSpec.describe "form/page" do let(:subsection) { form.get_subsection("income_and_benefits") } let(:page) { form.get_page("net_income") } let(:question) { page.questions.find { |q| q.id == "earnings" } } - let(:initial_attribs) { { type: "numeric", answer_options: nil } } + let(:initial_attribs) { { type: "numeric", answer_options: nil, prefix: nil, suffix: nil } } def assign_attributes(object, attrs) attrs.each_pair do |attr, value| @@ -19,22 +19,33 @@ RSpec.describe "form/page" do end end - context "given a question with extra guidance" do - let(:expected_guidance) { /What counts as income?/ } + before do + assign(:case_log, case_log) + assign(:page, page) + assign(:subsection, subsection) + assign_attributes(question, attribs) + render + end - before do - assign(:case_log, case_log) - assign(:page, page) - assign(:subsection, subsection) - assign_attributes(question, attribs) - render - end + after do + # Revert any changes we've made to avoid affecting other specs as the form, + # subsection, page, question objects being acted on are in memory + assign_attributes(question, initial_attribs) + end - after do - # Revert any changes we've made to avoid affecting other specs as the form, - # subsection, page, question objects being acted on are in memory - assign_attributes(question, initial_attribs) + context "given a numeric question with prefix and suffix" do + let(:attribs) { { type: "numeric", prefix: "£", suffix: "every week" } } + + it "renders prefix and suffix text" do + expect(rendered).to match(/govuk-input__prefix/) + expect(rendered).to match(/£/) + expect(rendered).to match(/govuk-input__suffix/) + expect(rendered).to match("every week") end + end + + context "given a question with extra guidance" do + let(:expected_guidance) { /What counts as income?/ } context "with radio type" do let(:attribs) { { type: "radio", answer_options: { "1": "A", "2": "B" } } }