diff --git a/app/models/case_log.rb b/app/models/case_log.rb index fd977e11e..b8bbfd0b0 100644 --- a/app/models/case_log.rb +++ b/app/models/case_log.rb @@ -477,12 +477,16 @@ private (2..8).each do |idx| if public_send("age#{idx}") && public_send("age#{idx}") < 16 self["ecstat#{idx}"] = 9 - elsif public_send("ecstat#{idx}") == 9 && (public_send("age#{idx}").nil? || public_send("age#{idx}") >= 16) + elsif public_send("ecstat#{idx}") == 9 && (public_send("age#{idx}").nil? || public_send("age#{idx}") >= 16) && age_known?(idx) self["ecstat#{idx}"] = nil end end end + def age_known?(person_num) + !!public_send("age#{person_num}_known")&.zero? + end + def process_postcode_changes! self.postcode_full = postcode_full.present? ? postcode_full.upcase.gsub(/\s+/, "") : postcode_full process_postcode(postcode_full, "postcode_known", "is_la_inferred", "la") diff --git a/app/models/form.rb b/app/models/form.rb index c885db64d..e339f6fdc 100644 --- a/app/models/form.rb +++ b/app/models/form.rb @@ -146,4 +146,27 @@ class Form previous_page(page_ids, page_index - 1, case_log) end + + def send_chain(arr, case_log) + Array(arr).inject(case_log) { |o, a| o.public_send(*a) } + end + + def depends_on_met(depends_on, case_log) + return true unless depends_on + + depends_on.any? do |conditions_set| + conditions_set.all? do |question, value| + if value.is_a?(Hash) && value.key?("operator") + operator = value["operator"] + operand = value["operand"] + case_log[question]&.send(operator, operand) + else + parts = question.split(".") + case_log_value = send_chain(parts, case_log) + + value.nil? ? case_log_value == value : !case_log_value.nil? && case_log_value == value + end + end + end + end end diff --git a/app/models/form/page.rb b/app/models/form/page.rb index a2bac3bf2..155f85d20 100644 --- a/app/models/form/page.rb +++ b/app/models/form/page.rb @@ -14,10 +14,12 @@ class Form::Page @subsection = subsection end + delegate :form, to: :subsection + def routed_to?(case_log) return true unless depends_on || subsection.depends_on - subsection.enabled?(case_log) && depends_on_met(case_log) + subsection.enabled?(case_log) && form.depends_on_met(depends_on, case_log) end def non_conditional_questions @@ -36,27 +38,4 @@ private q.conditional_for.keys if q.type == "radio" }.compact end - - def send_chain(arr, case_log) - Array(arr).inject(case_log) { |o, a| o.public_send(*a) } - end - - def depends_on_met(case_log) - return true unless depends_on - - depends_on.any? do |conditions_set| - conditions_set.all? do |question, value| - if value.is_a?(Hash) && value.key?("operator") - operator = value["operator"] - operand = value["operand"] - case_log[question]&.send(operator, operand) - else - parts = question.split(".") - case_log_value = send_chain(parts, case_log) - - value.nil? ? case_log_value == value : !case_log_value.nil? && case_log_value == value - end - end - end - end end diff --git a/app/models/form/question.rb b/app/models/form/question.rb index 66d54e277..96276f48a 100644 --- a/app/models/form/question.rb +++ b/app/models/form/question.rb @@ -80,9 +80,9 @@ class Form::Question false end - def displayed_answer_options + def displayed_answer_options(case_log) answer_options.select do |_key, val| - !val.is_a?(Hash) || !val["derived"] + !val.is_a?(Hash) || !val["depends_on"] || form.depends_on_met(val["depends_on"], case_log) end end @@ -168,7 +168,7 @@ private def selected_answer_option_is_derived?(case_log) selected_option = answer_options&.dig(case_log[id].to_s.presence) - selected_option.is_a?(Hash) && selected_option["derived"] + selected_option.is_a?(Hash) && selected_option["depends_on"] && form.depends_on_met(selected_option["depends_on"], case_log) end def has_inferred_display_value?(case_log) diff --git a/app/views/form/_checkbox_question.html.erb b/app/views/form/_checkbox_question.html.erb index 99551bac1..eb6cd8d40 100644 --- a/app/views/form/_checkbox_question.html.erb +++ b/app/views/form/_checkbox_question.html.erb @@ -6,7 +6,7 @@ hint: { text: question.hint_text&.html_safe } do %> <% after_divider = false %> - <% question.displayed_answer_options.map do |key, options| %> + <% question.displayed_answer_options(@case_log).map do |key, options| %> <% if key.starts_with?("divider") %> <% after_divider = true %> <%= f.govuk_check_box_divider %> diff --git a/app/views/form/_radio_question.html.erb b/app/views/form/_radio_question.html.erb index a79e9422d..a6cd165f9 100644 --- a/app/views/form/_radio_question.html.erb +++ b/app/views/form/_radio_question.html.erb @@ -5,7 +5,7 @@ legend: legend(question, page_header, conditional), hint: { text: question.hint_text&.html_safe } do %> - <% question.displayed_answer_options.map do |key, options| %> + <% question.displayed_answer_options(@case_log).map do |key, options| %> <% if key.starts_with?("divider") %> <%= f.govuk_radio_divider %> <% else %> diff --git a/app/views/form/_select_question.html.erb b/app/views/form/_select_question.html.erb index b5c6d94a9..52c47d66d 100644 --- a/app/views/form/_select_question.html.erb +++ b/app/views/form/_select_question.html.erb @@ -1,7 +1,7 @@ <%= render partial: "form/guidance/#{question.guidance_partial}" if question.guidance_partial %> <% selected = @case_log.public_send(question.id) || "" %> -<% answers = question.displayed_answer_options.map { |key, value| OpenStruct.new(id: key, name: value) } %> +<% answers = question.displayed_answer_options(@case_log).map { |key, value| OpenStruct.new(id: key, name: value) } %> <%= f.govuk_collection_select question.id.to_sym, answers, :id, diff --git a/config/forms/2021_2022.json b/config/forms/2021_2022.json index 0810e6121..af47ff1aa 100644 --- a/config/forms/2021_2022.json +++ b/config/forms/2021_2022.json @@ -1771,7 +1771,10 @@ }, "9": { "value": "Child under 16", - "derived": true + "depends_on": [ + { "age2_known": 1 }, + { "age2": { "operator": "<", "operand": 16 } } + ] }, "0": { "value": "Other" @@ -1990,7 +1993,10 @@ }, "9": { "value": "Child under 16", - "derived": true + "depends_on": [ + { "age3_known": 1 }, + { "age3": { "operator": "<", "operand": 16 } } + ] }, "0": { "value": "Other" @@ -2206,7 +2212,10 @@ }, "9": { "value": "Child under 16", - "derived": true + "depends_on": [ + { "age4_known": 1 }, + { "age4": { "operator": "<", "operand": 16 } } + ] }, "0": { "value": "Other" @@ -2419,7 +2428,10 @@ }, "9": { "value": "Child under 16", - "derived": true + "depends_on": [ + { "age5_known": 1 }, + { "age5": { "operator": "<", "operand": 16 } } + ] }, "0": { "value": "Other" @@ -2629,7 +2641,10 @@ }, "9": { "value": "Child under 16", - "derived": true + "depends_on": [ + { "age6_known": 1 }, + { "age6": { "operator": "<", "operand": 16 } } + ] }, "0": { "value": "Other" @@ -2836,7 +2851,10 @@ }, "9": { "value": "Child under 16", - "derived": true + "depends_on": [ + { "age7_known": 1 }, + { "age7": { "operator": "<", "operand": 16 } } + ] }, "0": { "value": "Other" @@ -3040,7 +3058,10 @@ }, "9": { "value": "Child under 16", - "derived": true + "depends_on": [ + { "age8_known": 1 }, + { "age8": { "operator": "<", "operand": 16 } } + ] }, "0": { "value": "Other" diff --git a/config/forms/2022_2023.json b/config/forms/2022_2023.json index b03afc78b..c6b8018ce 100644 --- a/config/forms/2022_2023.json +++ b/config/forms/2022_2023.json @@ -1769,7 +1769,10 @@ }, "9": { "value": "Child under 16", - "derived": true + "depends_on": [ + { "age2_known": 1 }, + { "age2": { "operator": "<", "operand": 16 } } + ] }, "0": { "value": "Other" @@ -1995,7 +1998,10 @@ }, "9": { "value": "Child under 16", - "derived": true + "depends_on": [ + { "age3_known": 1 }, + { "age3": { "operator": "<", "operand": 16 } } + ] }, "0": { "value": "Other" @@ -2218,7 +2224,10 @@ }, "9": { "value": "Child under 16", - "derived": true + "depends_on": [ + { "age4_known": 1 }, + { "age4": { "operator": "<", "operand": 16 } } + ] }, "0": { "value": "Other" @@ -2438,7 +2447,10 @@ }, "9": { "value": "Child under 16", - "derived": true + "depends_on": [ + { "age5_known": 1 }, + { "age5": { "operator": "<", "operand": 16 } } + ] }, "0": { "value": "Other" @@ -2655,7 +2667,10 @@ }, "9": { "value": "Child under 16", - "derived": true + "depends_on": [ + { "age6_known": 1 }, + { "age6": { "operator": "<", "operand": 16 } } + ] }, "0": { "value": "Other" @@ -2869,7 +2884,10 @@ }, "9": { "value": "Child under 16", - "derived": true + "depends_on": [ + { "age7_known": 1 }, + { "age7": { "operator": "<", "operand": 16 } } + ] }, "0": { "value": "Other" @@ -3080,7 +3098,10 @@ }, "9": { "value": "Child under 16", - "derived": true + "depends_on": [ + { "age8_known": 1 }, + { "age8": { "operator": "<", "operand": 16 } } + ] }, "0": { "value": "Other" diff --git a/spec/fixtures/forms/2021_2022.json b/spec/fixtures/forms/2021_2022.json index 1aa37557b..c2582b6e8 100644 --- a/spec/fixtures/forms/2021_2022.json +++ b/spec/fixtures/forms/2021_2022.json @@ -188,7 +188,10 @@ }, "9": { "value": "Child under 16", - "derived": true + "depends_on": [ + { "age2_known": 1 }, + { "age2": { "operator": "<", "operand": 16 } } + ] }, "1": { "value": "Prefer not to say" diff --git a/spec/fixtures/softwire_imports/case_logs/0ead17cb-1668-442d-898c-0d52879ff592.xml b/spec/fixtures/softwire_imports/case_logs/0ead17cb-1668-442d-898c-0d52879ff592.xml index ac7ef6d5a..30f1a2289 100644 --- a/spec/fixtures/softwire_imports/case_logs/0ead17cb-1668-442d-898c-0d52879ff592.xml +++ b/spec/fixtures/softwire_imports/case_logs/0ead17cb-1668-442d-898c-0d52879ff592.xml @@ -54,8 +54,8 @@ 6) Not Seeking Work 17 Refused 1 UK national resident in UK - 2 - + + Age_Refused Male Child 9) Child under 16 diff --git a/spec/models/case_log_spec.rb b/spec/models/case_log_spec.rb index 8c483774c..7fdbd6381 100644 --- a/spec/models/case_log_spec.rb +++ b/spec/models/case_log_spec.rb @@ -1367,7 +1367,7 @@ RSpec.describe CaseLog do end it "correctly resets economic status when age changes from under 16" do - household_case_log.update!(age7: 17) + household_case_log.update!(age7_known: 0, age7: 17) record_from_db = ActiveRecord::Base.connection.execute("select ecstat7 from case_logs where id=#{household_case_log.id}").to_a[0] expect(record_from_db["ecstat7"]).to eq(nil) end diff --git a/spec/models/form/question_spec.rb b/spec/models/form/question_spec.rb index 094d521e3..4057e4687 100644 --- a/spec/models/form/question_spec.rb +++ b/spec/models/form/question_spec.rb @@ -118,7 +118,7 @@ RSpec.describe Form::Question, type: :model do context "when answer options do not include derived options" do it "displays all answer options" do - expect(question.displayed_answer_options).to match(question.answer_options) + expect(question.displayed_answer_options(case_log)).to match(question.answer_options) end end @@ -132,7 +132,7 @@ RSpec.describe Form::Question, type: :model do end it "does not include those options in the displayed options" do - expect(question.displayed_answer_options).to match(expected_answer_options) + expect(question.displayed_answer_options(case_log)).to match(expected_answer_options) end it "can still map the value label" do