Browse Source

CLDC-1116: Don't route to ecstat if age is under 16 (#446)

* Ecstat dependent on age

* Derive ecstat if age is under 16

* Test value label derivation

* Ensure derived option is still shown in check answers
pull/447/head
baarkerlounger 3 years ago committed by GitHub
parent
commit
9dc7e574bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      app/models/case_log.rb
  2. 14
      app/models/form/page.rb
  3. 14
      app/models/form/question.rb
  4. 2
      app/views/form/_checkbox_question.html.erb
  5. 2
      app/views/form/_radio_question.html.erb
  6. 2
      app/views/form/_select_question.html.erb
  7. 42
      config/forms/2021_2022.json
  8. 1
      spec/factories/case_log.rb
  9. 22
      spec/fixtures/forms/2021_2022.json
  10. 3
      spec/helpers/check_answers_helper_spec.rb
  11. 21
      spec/models/case_log_spec.rb
  12. 18
      spec/models/form/page_spec.rb
  13. 38
      spec/models/form/question_spec.rb
  14. 8
      spec/models/form/subsection_spec.rb
  15. 2
      spec/models/form_handler_spec.rb
  16. 7
      spec/models/form_spec.rb

7
app/models/case_log.rb

@ -409,6 +409,13 @@ private
self.prevten = 30 if managing_organisation.provider_type == "LA" self.prevten = 30 if managing_organisation.provider_type == "LA"
end end
end end
(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)
self["ecstat#{idx}"] = nil
end
end
end end
def process_postcode_changes! def process_postcode_changes!

14
app/models/form/page.rb

@ -46,10 +46,16 @@ private
depends_on.any? do |conditions_set| depends_on.any? do |conditions_set|
conditions_set.all? do |question, value| conditions_set.all? do |question, value|
parts = question.split(".") if value.is_a?(Hash) && value.key?("operator")
case_log_value = send_chain(parts, case_log) operator = value["operator"]
operand = value["operand"]
value.nil? ? case_log_value == value : !case_log_value.nil? && case_log_value == value 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
end end

14
app/models/form/question.rb

@ -60,7 +60,7 @@ class Form::Question
def enabled?(case_log) def enabled?(case_log)
return true if conditional_on.blank? return true if conditional_on.blank?
conditional_on.map { |condition| evaluate_condition(condition, case_log) }.all? conditional_on.all? { |condition| evaluate_condition(condition, case_log) }
end end
def hidden_in_check_answers? def hidden_in_check_answers?
@ -68,11 +68,18 @@ class Form::Question
end end
def has_inferred_check_answers_value?(case_log) def has_inferred_check_answers_value?(case_log)
return true if selected_answer_option_is_derived?(case_log)
return inferred_check_answers_value["condition"].values[0] == case_log[inferred_check_answers_value["condition"].keys[0]] if inferred_check_answers_value.present? return inferred_check_answers_value["condition"].values[0] == case_log[inferred_check_answers_value["condition"].keys[0]] if inferred_check_answers_value.present?
false false
end end
def displayed_answer_options
answer_options.select do |_key, val|
!val.is_a?(Hash) || !val["derived"]
end
end
def update_answer_link_name(case_log) def update_answer_link_name(case_log)
link_type = if has_inferred_check_answers_value?(case_log) link_type = if has_inferred_check_answers_value?(case_log)
"Change" "Change"
@ -150,6 +157,11 @@ class Form::Question
private 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"]
end
def has_inferred_display_value?(case_log) def has_inferred_display_value?(case_log)
inferred_check_answers_value.present? && case_log[inferred_check_answers_value["condition"].keys.first] == inferred_check_answers_value["condition"].values.first inferred_check_answers_value.present? && case_log[inferred_check_answers_value["condition"].keys.first] == inferred_check_answers_value["condition"].values.first
end end

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

@ -6,7 +6,7 @@
hint: { text: question.hint_text&.html_safe } do %> hint: { text: question.hint_text&.html_safe } do %>
<% after_divider = false %> <% after_divider = false %>
<% question.answer_options.map do |key, options| %> <% question.displayed_answer_options.map do |key, options| %>
<% if key.starts_with?("divider") %> <% if key.starts_with?("divider") %>
<% after_divider = true %> <% after_divider = true %>
<%= f.govuk_check_box_divider %> <%= f.govuk_check_box_divider %>

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

@ -5,7 +5,7 @@
legend: legend(question, page_header, conditional), legend: legend(question, page_header, conditional),
hint: { text: question.hint_text&.html_safe } do %> hint: { text: question.hint_text&.html_safe } do %>
<% question.answer_options.map do |key, options| %> <% question.displayed_answer_options.map do |key, options| %>
<% if key.starts_with?("divider") %> <% if key.starts_with?("divider") %>
<%= f.govuk_radio_divider %> <%= f.govuk_radio_divider %>
<% else %> <% else %>

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

@ -1,7 +1,7 @@
<%= render partial: "form/guidance/#{question.guidance_partial}" if question.guidance_partial %> <%= render partial: "form/guidance/#{question.guidance_partial}" if question.guidance_partial %>
<% selected = @case_log.public_send(question.id) || "" %> <% selected = @case_log.public_send(question.id) || "" %>
<%= answers = question.answer_options.map { |key, value| OpenStruct.new(id: key, name: value) } <%= answers = question.displayed_answer_options.map { |key, value| OpenStruct.new(id: key, name: value) }
f.govuk_collection_select question.id.to_sym, f.govuk_collection_select question.id.to_sym,
answers, answers,
:id, :id,

42
config/forms/2021_2022.json

@ -1731,7 +1731,8 @@
"value": "Retired" "value": "Retired"
}, },
"9": { "9": {
"value": "Child under 16" "value": "Child under 16",
"derived": true
}, },
"0": { "0": {
"value": "Other" "value": "Other"
@ -1747,7 +1748,8 @@
}, },
"depends_on": [ "depends_on": [
{ {
"details_known_2": 0 "details_known_2": 0,
"age2": { "operator": ">", "operand": 15 }
} }
] ]
}, },
@ -1939,7 +1941,8 @@
"value": "Retired" "value": "Retired"
}, },
"9": { "9": {
"value": "Child under 16" "value": "Child under 16",
"derived": true
}, },
"0": { "0": {
"value": "Other" "value": "Other"
@ -1955,7 +1958,8 @@
}, },
"depends_on": [ "depends_on": [
{ {
"details_known_3": 0 "details_known_3": 0,
"age3": { "operator": ">", "operand": 15 }
} }
] ]
}, },
@ -2144,7 +2148,8 @@
"value": "Retired" "value": "Retired"
}, },
"9": { "9": {
"value": "Child under 16" "value": "Child under 16",
"derived": true
}, },
"0": { "0": {
"value": "Other" "value": "Other"
@ -2160,7 +2165,8 @@
}, },
"depends_on": [ "depends_on": [
{ {
"details_known_4": 0 "details_known_4": 0,
"age4": { "operator": ">", "operand": 15 }
} }
] ]
}, },
@ -2346,7 +2352,8 @@
"value": "Retired" "value": "Retired"
}, },
"9": { "9": {
"value": "Child under 16" "value": "Child under 16",
"derived": true
}, },
"0": { "0": {
"value": "Other" "value": "Other"
@ -2362,7 +2369,8 @@
}, },
"depends_on": [ "depends_on": [
{ {
"details_known_5": 0 "details_known_5": 0,
"age5": { "operator": ">", "operand": 15 }
} }
] ]
}, },
@ -2545,7 +2553,8 @@
"value": "Retired" "value": "Retired"
}, },
"9": { "9": {
"value": "Child under 16" "value": "Child under 16",
"derived": true
}, },
"0": { "0": {
"value": "Other" "value": "Other"
@ -2561,7 +2570,8 @@
}, },
"depends_on": [ "depends_on": [
{ {
"details_known_6": 0 "details_known_6": 0,
"age6": { "operator": ">", "operand": 15 }
} }
] ]
}, },
@ -2741,7 +2751,8 @@
"value": "Retired" "value": "Retired"
}, },
"9": { "9": {
"value": "Child under 16" "value": "Child under 16",
"derived": true
}, },
"0": { "0": {
"value": "Other" "value": "Other"
@ -2757,7 +2768,8 @@
}, },
"depends_on": [ "depends_on": [
{ {
"details_known_7": 0 "details_known_7": 0,
"age7": { "operator": ">", "operand": 15 }
} }
] ]
}, },
@ -2934,7 +2946,8 @@
"value": "Retired" "value": "Retired"
}, },
"9": { "9": {
"value": "Child under 16" "value": "Child under 16",
"derived": true
}, },
"0": { "0": {
"value": "Other" "value": "Other"
@ -2950,7 +2963,8 @@
}, },
"depends_on": [ "depends_on": [
{ {
"details_known_8": 0 "details_known_8": 0,
"age8": { "operator": ">", "operand": 15 }
} }
] ]
} }

1
spec/factories/case_log.rb

@ -15,6 +15,7 @@ FactoryBot.define do
postcode_full { "PO5 3TE" } postcode_full { "PO5 3TE" }
ppostcode_full { "SW2 6HI" } ppostcode_full { "SW2 6HI" }
age1 { 17 } age1 { 17 }
age2 { 19 }
end end
trait :soft_validations_triggered do trait :soft_validations_triggered do
status { 1 } status { 1 }

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

@ -128,8 +128,7 @@
"conditional_for": { "conditional_for": {
"relat2": ">0", "relat2": ">0",
"age2": ">0", "age2": ">0",
"sex2": ">0", "sex2": ">0"
"ecstat2": ">0"
} }
}, },
"relat2": { "relat2": {
@ -172,7 +171,13 @@
"value": "Prefer not to say" "value": "Prefer not to say"
} }
} }
}, }
}
},
"person_2_working_situation": {
"header": "",
"description": "",
"questions": {
"ecstat2": { "ecstat2": {
"check_answer_label": "Person 2’s Work", "check_answer_label": "Person 2’s Work",
"header": "Which of these best describes person 2’s working situation?", "header": "Which of these best describes person 2’s working situation?",
@ -181,12 +186,21 @@
"0": { "0": {
"value": "Other" "value": "Other"
}, },
"9": {
"value": "Child under 16",
"derived": true
},
"1": { "1": {
"value": "Prefer not to say" "value": "Prefer not to say"
} }
} }
} }
} },
"depends_on": [
{
"age2": { "operator": ">", "operand": 15 }
}
]
}, },
"propcode": { "propcode": {
"questions": { "questions": {

3
spec/helpers/check_answers_helper_spec.rb

@ -9,7 +9,7 @@ RSpec.describe CheckAnswersHelper do
context "when a section hasn't been completed yet" do context "when a section hasn't been completed yet" do
it "returns that you have unanswered questions" do it "returns that you have unanswered questions" do
expect(display_answered_questions_summary(subsection, case_log)) expect(display_answered_questions_summary(subsection, case_log))
.to match(/You have answered 2 of 6 questions./) .to match(/You have answered 2 of 7 questions./)
end end
end end
@ -19,6 +19,7 @@ RSpec.describe CheckAnswersHelper do
case_log.other_hhmemb = 0 case_log.other_hhmemb = 0
case_log.propcode = "123" case_log.propcode = "123"
case_log.ecstat1 = 200 case_log.ecstat1 = 200
case_log.ecstat2 = 9
expect(display_answered_questions_summary(subsection, case_log)) expect(display_answered_questions_summary(subsection, case_log))
.to match(/You answered all the questions./) .to match(/You answered all the questions./)
expect(display_answered_questions_summary(subsection, case_log)) expect(display_answered_questions_summary(subsection, case_log))

21
spec/models/case_log_spec.rb

@ -1339,21 +1339,21 @@ RSpec.describe CaseLog do
context "when validating household members derived vars" do context "when validating household members derived vars" do
let!(:household_case_log) do let!(:household_case_log) do
described_class.create({ described_class.create!({
managing_organisation: organisation, managing_organisation: organisation,
owning_organisation: organisation, owning_organisation: organisation,
other_hhmemb: 4, other_hhmemb: 4,
relat2: "C", relat2: "X",
relat3: "C", relat3: "C",
relat4: "X", relat4: "X",
relat5: "C", relat5: "C",
relat7: "X", relat7: "C",
relat8: "X", relat8: "X",
age1: 22, age1: 22,
age2: 14, age2: 16,
age4: 60, age4: 60,
age6: 88, age6: 88,
age7: 16, age7: 14,
age8: 42, age8: 42,
}) })
end end
@ -1372,6 +1372,17 @@ RSpec.describe CaseLog do
record_from_db = ActiveRecord::Base.connection.execute("select totadult from case_logs where id=#{household_case_log.id}").to_a[0] record_from_db = ActiveRecord::Base.connection.execute("select totadult from case_logs where id=#{household_case_log.id}").to_a[0]
expect(record_from_db["totadult"]).to eq(3) expect(record_from_db["totadult"]).to eq(3)
end end
it "correctly derives economic status for tenants under 16" do
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(9)
end
it "correctly resets economic status when age changes from under 16" do
household_case_log.update!(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
end end
it "correctly derives and saves has_benefits" do it "correctly derives and saves has_benefits" do

18
spec/models/form/page_spec.rb

@ -55,12 +55,28 @@ RSpec.describe Form::Page, type: :model do
expect(page.routed_to?(case_log)).to be false expect(page.routed_to?(case_log)).to be false
end end
it "evaluates not conditions correctly" do it "evaluates met conditions correctly" do
case_log.incfreq = "Weekly" case_log.incfreq = "Weekly"
expect(page.routed_to?(case_log)).to be true expect(page.routed_to?(case_log)).to be true
end end
end end
context "with expression routing conditions" do
let(:section_id) { "household" }
let(:subsection_id) { "household_characteristics" }
let(:page_id) { "person_2_working_situation" }
it "evaluates not met conditions correctly" do
case_log.age2 = 12
expect(page.routed_to?(case_log)).to be false
end
it "evaluates met conditions correctly" do
case_log.age2 = 17
expect(page.routed_to?(case_log)).to be true
end
end
context "when the page's subsection has routing conditions" do context "when the page's subsection has routing conditions" do
let(:section_id) { "submission" } let(:section_id) { "submission" }
let(:subsection_id) { "declaration" } let(:subsection_id) { "declaration" }

38
spec/models/form/question_spec.rb

@ -116,6 +116,30 @@ RSpec.describe Form::Question, type: :model do
end end
end end
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)
end
end
context "when answer options include derived options" do
let(:section_id) { "household" }
let(:subsection_id) { "household_characteristics" }
let(:page_id) { "person_2_working_situation" }
let(:question_id) { "ecstat2" }
let(:expected_answer_options) do
{ "0" => { "value" => "Other" }, "1" => { "value" => "Prefer not to say" } }
end
it "does not include those options in the displayed options" do
expect(question.displayed_answer_options).to match(expected_answer_options)
end
it "can still map the value label" do
expect(question.label_from_value(9)).to eq("Child under 16")
end
end
context "when the saved answer is not in the value map" do context "when the saved answer is not in the value map" do
it "displays the saved answer umapped" do it "displays the saved answer umapped" do
expect(question.label_from_value(9999)).to eq("9999") expect(question.label_from_value(9999)).to eq("9999")
@ -219,6 +243,20 @@ RSpec.describe Form::Question, type: :model do
end end
end end
context "when the answer option is a derived answer option" do
let(:section_id) { "household" }
let(:subsection_id) { "household_characteristics" }
let(:page_id) { "person_2_working_situation" }
let(:question_id) { "ecstat2" }
let(:case_log) do
FactoryBot.create(:case_log, :in_progress, hhmemb: 2, details_known_2: 0, age2_known: 0, age2: 12)
end
it "knows it has an inferred value for check answers" do
expect(question.has_inferred_check_answers_value?(case_log)).to be true
end
end
context "when type is date" do context "when type is date" do
let(:section_id) { "local_authority" } let(:section_id) { "local_authority" }
let(:subsection_id) { "local_authority" } let(:subsection_id) { "local_authority" }

8
spec/models/form/subsection_spec.rb

@ -25,7 +25,7 @@ RSpec.describe Form::Subsection, type: :model do
end end
it "has pages" do it "has pages" do
expected_pages = %w[tenant_code person_1_age person_1_gender person_1_working_situation household_number_of_other_members propcode] expected_pages = %w[tenant_code person_1_age person_1_gender person_1_working_situation household_number_of_other_members person_2_working_situation propcode]
expect(subsection.pages.map(&:id)).to eq(expected_pages) expect(subsection.pages.map(&:id)).to eq(expected_pages)
end end
@ -58,9 +58,9 @@ RSpec.describe Form::Subsection, type: :model do
end end
it "has question helpers for the number of applicable questions" do it "has question helpers for the number of applicable questions" do
expected_questions = %w[tenant_code age1 sex1 ecstat1 other_hhmemb propcode] expected_questions = %w[tenant_code age1 sex1 ecstat1 other_hhmemb ecstat2 propcode]
expect(subsection.applicable_questions(case_log).map(&:id)).to eq(expected_questions) expect(subsection.applicable_questions(case_log).map(&:id)).to eq(expected_questions)
expect(subsection.applicable_questions_count(case_log)).to eq(6) expect(subsection.applicable_questions_count(case_log)).to eq(7)
end end
it "has question helpers for the number of answered questions" do it "has question helpers for the number of answered questions" do
@ -79,7 +79,7 @@ RSpec.describe Form::Subsection, type: :model do
end end
it "has a question helpers for the unanswered questions" do it "has a question helpers for the unanswered questions" do
expected_questions = %w[sex1 ecstat1 other_hhmemb propcode] expected_questions = %w[sex1 ecstat1 other_hhmemb ecstat2 propcode]
expect(subsection.unanswered_questions(case_log).map(&:id)).to eq(expected_questions) expect(subsection.unanswered_questions(case_log).map(&:id)).to eq(expected_questions)
end end
end end

2
spec/models/form_handler_spec.rb

@ -17,7 +17,7 @@ RSpec.describe FormHandler do
form_handler = described_class.instance form_handler = described_class.instance
form = form_handler.get_form(test_form_name) form = form_handler.get_form(test_form_name)
expect(form).to be_a(Form) expect(form).to be_a(Form)
expect(form.pages.count).to eq(33) expect(form.pages.count).to eq(34)
end end
end end

7
spec/models/form_spec.rb

@ -128,9 +128,12 @@ RSpec.describe Form, type: :model do
before do before do
case_log.tenant_code = "123" case_log.tenant_code = "123"
case_log.age1 = 35 case_log.age1 = 35
case_log.sex1 = "Male" case_log.sex1 = "M"
case_log.ecstat1 = 0 case_log.ecstat1 = 0
case_log.other_hhmemb = 0 case_log.other_hhmemb = 1
case_log.relat2 = "P"
case_log.sex2 = "F"
case_log.ecstat2 = 1
end end
it "returns the first page of the next incomplete subsection if the subsection is not in progress" do it "returns the first page of the next incomplete subsection if the subsection is not in progress" do

Loading…
Cancel
Save