Browse Source

Merge branch 'main' into CLDC-638-bulk_upload

pull/84/head
baarkerlounger 4 years ago
parent
commit
bc50087bb1
  1. 9
      app/constants/db_enums.rb
  2. 32
      app/helpers/check_answers_helper.rb
  3. 21
      app/helpers/tasklist_helper.rb
  4. 2
      app/models/case_log.rb
  5. 30
      app/models/form.rb
  6. 6
      app/validations/tenancy_validations.rb
  7. 4
      app/views/case_logs/_tasklist.html.erb
  8. 11
      config/forms/2021_2022.json
  9. 2
      docs/api/DLUHC-CORE-Data.v1.json
  10. 10
      lib/tasks/form_definition.rake
  11. 9
      spec/factories/case_log.rb
  12. 2
      spec/fixtures/complete_case_log.json
  13. 27
      spec/helpers/tasklist_helper_spec.rb
  14. 2
      spec/lib/tasks/form_definition_validator_spec.rb
  15. 18
      spec/models/case_log_spec.rb

9
app/constants/db_enums.rb

@ -166,11 +166,10 @@ module DbEnums
def self.tenancy def self.tenancy
{ {
"Fixed term – Secure" => 1, "Secure (including flexible)" => 1,
"Fixed term – Assured Shorthold Tenancy (AST)" => 4, "Assured" => 2,
"Lifetime – Secure" => 100, "Assured Shorthold" => 4,
"Lifetime – Assured" => 2, "Licence agreement (almshouses only)" => 5,
"License agreement" => 5,
"Other" => 3, "Other" => 3,
} }
end end

32
app/helpers/check_answers_helper.rb

@ -16,7 +16,7 @@ module CheckAnswersHelper
while page_name.to_s != "check_answers" && subsection_keys.include?(page_name) while page_name.to_s != "check_answers" && subsection_keys.include?(page_name)
questions = form.questions_for_page(page_name) questions = form.questions_for_page(page_name)
applicable_questions = filter_conditional_questions(questions, case_log) applicable_questions = form.filter_conditional_questions(questions, case_log)
total_questions = total_questions.merge(applicable_questions) total_questions = total_questions.merge(applicable_questions)
page_name = get_next_page_name(form, page_name, case_log) page_name = get_next_page_name(form, page_name, case_log)
@ -25,19 +25,6 @@ module CheckAnswersHelper
total_questions total_questions
end end
def filter_conditional_questions(questions, case_log)
applicable_questions = questions
questions.each do |k, question|
question.fetch("conditional_for", []).each do |conditional_question_key, condition|
if condition_not_met(case_log, k, question, condition)
applicable_questions = applicable_questions.reject { |z| z == conditional_question_key }
end
end
end
applicable_questions
end
def get_next_page_name(form, page_name, case_log) def get_next_page_name(form, page_name, case_log)
page = form.all_pages[page_name] page = form.all_pages[page_name]
if page.key?("conditional_route_to") if page.key?("conditional_route_to")
@ -50,23 +37,6 @@ module CheckAnswersHelper
form.next_page(page_name) form.next_page(page_name)
end end
def condition_not_met(case_log, question_key, question, condition)
case question["type"]
when "numeric"
operator = condition[/[<>=]+/].to_sym
operand = condition[/\d+/].to_i
case_log[question_key].blank? || !case_log[question_key].send(operator, operand)
when "text"
case_log[question_key].blank? || !condition.include?(case_log[question_key])
when "radio"
case_log[question_key].blank? || !condition.include?(case_log[question_key])
when "select"
case_log[question_key].blank? || !condition.include?(case_log[question_key])
else
raise "Not implemented yet"
end
end
def create_update_answer_link(case_log_answer, case_log_id, page) def create_update_answer_link(case_log_answer, case_log_id, page)
link_name = case_log_answer.blank? ? "Answer" : "Change" link_name = case_log_answer.blank? ? "Answer" : "Change"
link_to(link_name, "/case_logs/#{case_log_id}/#{page}", class: "govuk-link").html_safe link_to(link_name, "/case_logs/#{case_log_id}/#{page}", class: "govuk-link").html_safe

21
app/helpers/tasklist_helper.rb

@ -13,31 +13,32 @@ module TasklistHelper
in_progress: "govuk-tag--blue", in_progress: "govuk-tag--blue",
}.freeze }.freeze
def get_subsection_status(subsection_name, case_log, questions) def get_subsection_status(subsection_name, case_log, form, questions)
applicable_questions = form.filter_conditional_questions(questions, case_log).keys
if subsection_name == "declaration" if subsection_name == "declaration"
return case_log.completed? ? :not_started : :cannot_start_yet return case_log.completed? ? :not_started : :cannot_start_yet
end end
return :not_started if questions.all? { |question| case_log[question].blank? } return :not_started if applicable_questions.all? { |question| case_log[question].blank? }
return :completed if questions.all? { |question| case_log[question].present? } return :completed if applicable_questions.all? { |question| case_log[question].present? }
:in_progress :in_progress
end end
def get_next_incomplete_section(form, case_log) def get_next_incomplete_section(form, case_log)
subsections = form.all_subsections.keys subsections = form.all_subsections.keys
subsections.find { |subsection| is_incomplete?(subsection, case_log, form.questions_for_subsection(subsection).keys) } subsections.find { |subsection| is_incomplete?(subsection, case_log, form, form.questions_for_subsection(subsection)) }
end end
def get_subsections_count(form, case_log, status = :all) def get_subsections_count(form, case_log, status = :all)
subsections = form.all_subsections.keys subsections = form.all_subsections.keys
return subsections.count if status == :all return subsections.count if status == :all
subsections.count { |subsection| get_subsection_status(subsection, case_log, form.questions_for_subsection(subsection).keys) == status } subsections.count { |subsection| get_subsection_status(subsection, case_log, form, form.questions_for_subsection(subsection)) == status }
end end
def get_first_page_or_check_answers(subsection, case_log, form, questions) def get_first_page_or_check_answers(subsection, case_log, form, questions)
path = if is_started?(subsection, case_log, questions) path = if is_started?(subsection, case_log, form, questions)
"case_log_#{subsection}_check_answers_path" "case_log_#{subsection}_check_answers_path"
else else
"case_log_#{form.first_page_for_subsection(subsection)}_path" "case_log_#{form.first_page_for_subsection(subsection)}_path"
@ -47,13 +48,13 @@ module TasklistHelper
private private
def is_incomplete?(subsection, case_log, questions) def is_incomplete?(subsection, case_log, form, questions)
status = get_subsection_status(subsection, case_log, questions) status = get_subsection_status(subsection, case_log, form, questions)
%i[not_started in_progress].include?(status) %i[not_started in_progress].include?(status)
end end
def is_started?(subsection, case_log, questions) def is_started?(subsection, case_log, form, questions)
status = get_subsection_status(subsection, case_log, questions) status = get_subsection_status(subsection, case_log, form, questions)
%i[in_progress completed].include?(status) %i[in_progress completed].include?(status)
end end
end end

2
app/models/case_log.rb

@ -231,7 +231,7 @@ private
dynamically_not_required << "incfreq" dynamically_not_required << "incfreq"
end end
if tenancy == "Fixed term – Secure" if tenancy == "Secure (including flexible)"
dynamically_not_required << "tenancylength" dynamically_not_required << "tenancylength"
end end

30
app/models/form.rb

@ -97,6 +97,36 @@ class Form
}.reduce(:merge) }.reduce(:merge)
end end
def filter_conditional_questions(questions, case_log)
applicable_questions = questions
questions.each do |k, question|
question.fetch("conditional_for", []).each do |conditional_question_key, condition|
if condition_not_met(case_log, k, question, condition)
applicable_questions = applicable_questions.reject { |z| z == conditional_question_key }
end
end
end
applicable_questions
end
def condition_not_met(case_log, question_key, question, condition)
case question["type"]
when "numeric"
operator = condition[/[<>=]+/].to_sym
operand = condition[/\d+/].to_i
case_log[question_key].blank? || !case_log[question_key].send(operator, operand)
when "text"
case_log[question_key].blank? || !condition.include?(case_log[question_key])
when "radio"
case_log[question_key].blank? || !condition.include?(case_log[question_key])
when "select"
case_log[question_key].blank? || !condition.include?(case_log[question_key])
else
raise "Not implemented yet"
end
end
def get_answer_label(case_log, question_title) def get_answer_label(case_log, question_title)
question = all_questions[question_title] question = all_questions[question_title]
if question["type"] == "checkbox" if question["type"] == "checkbox"

6
app/validations/tenancy_validations.rb

@ -4,12 +4,12 @@ module TenancyValidations
def validate_fixed_term_tenancy(record) def validate_fixed_term_tenancy(record)
is_present = record.tenancylength.present? is_present = record.tenancylength.present?
is_in_range = record.tenancylength.to_i.between?(2, 99) is_in_range = record.tenancylength.to_i.between?(2, 99)
is_secure = record.tenancy == "Fixed term – Secure" is_secure = record.tenancy == "Secure (including flexible)"
is_ast = record.tenancy == "Fixed term – Assured Shorthold Tenancy (AST)" is_ast = record.tenancy == "Assured Shorthold"
conditions = [ conditions = [
{ condition: !(is_secure || is_ast) && is_present, error: "You must only answer the fixed term tenancy length question if the tenancy type is fixed term" }, { condition: !(is_secure || is_ast) && is_present, error: "You must only answer the fixed term tenancy length question if the tenancy type is fixed term" },
{ condition: is_ast && !is_in_range, error: "Fixed term – Assured Shorthold Tenancy (AST) should be between 2 and 99 years" }, { condition: is_ast && !is_in_range, error: "Fixed term – Assured Shorthold Tenancy (AST) should be between 2 and 99 years" },
{ condition: is_secure && (!is_in_range && is_present), error: "Fixed term – Secure should be between 2 and 99 years or not specified" }, { condition: is_secure && (!is_in_range && is_present), error: "Secure (including flexible) should be between 2 and 99 years or not specified" },
] ]
conditions.each { |condition| condition[:condition] ? (record.errors.add :tenancylength, condition[:error]) : nil } conditions.each { |condition| condition[:condition] ? (record.errors.add :tenancylength, condition[:error]) : nil }

4
app/views/case_logs/_tasklist.html.erb

@ -9,10 +9,10 @@
<ul class="app-task-list__items"> <ul class="app-task-list__items">
<% section_value["subsections"].map do |subsection_key, subsection_value| %> <% section_value["subsections"].map do |subsection_key, subsection_value| %>
<li class="app-task-list__item" id=<%= subsection_key %>> <li class="app-task-list__item" id=<%= subsection_key %>>
<% questions_for_subsection = @form.questions_for_subsection(subsection_key).keys %> <% questions_for_subsection = @form.questions_for_subsection(subsection_key) %>
<% next_page_path = get_first_page_or_check_answers(subsection_key, @case_log, @form, questions_for_subsection) %> <% next_page_path = get_first_page_or_check_answers(subsection_key, @case_log, @form, questions_for_subsection) %>
<%= link_to subsection_value["label"], next_page_path, class: "task-name govuk-link" %> <%= link_to subsection_value["label"], next_page_path, class: "task-name govuk-link" %>
<% subsection_status = get_subsection_status(subsection_key, @case_log, questions_for_subsection) %> <% subsection_status = get_subsection_status(subsection_key, @case_log, @form, questions_for_subsection) %>
<strong class="govuk-tag app-task-list__tag <%= TasklistHelper::STYLES[subsection_status] %>"> <strong class="govuk-tag app-task-list__tag <%= TasklistHelper::STYLES[subsection_status] %>">
<%= TasklistHelper::STATUSES[subsection_status] %> <%= TasklistHelper::STATUSES[subsection_status] %>
</strong> </strong>

11
config/forms/2021_2022.json

@ -1068,12 +1068,11 @@
"hint_text": "", "hint_text": "",
"type": "radio", "type": "radio",
"answer_options": { "answer_options": {
"0": "Fixed term – Secure", "0": "Secure (including flexible)",
"1": "Fixed term – Assured Shorthold Tenancy (AST)", "1": "Assured",
"2": "Lifetime – Secure", "2": "Assured Shorthold",
"3": "Lifetime – Assured", "3": "Licence agreement (almshouses only)",
"4": "License agreement", "4": "Other"
"5": "Other"
}, },
"conditional_for": { "conditional_for": {
"other_tenancy_type": ["Other"] "other_tenancy_type": ["Other"]

2
docs/api/DLUHC-CORE-Data.v1.json

@ -306,7 +306,7 @@
"startdate": "12/03/2019", "startdate": "12/03/2019",
"startertenancy": "No", "startertenancy": "No",
"tenancylength": "No", "tenancylength": "No",
"tenancy": "Fixed term – Secure", "tenancy": "Secure (including flexible)",
"lettype": "Affordable Rent - General Needs", "lettype": "Affordable Rent - General Needs",
"landlord": "This landlord", "landlord": "This landlord",
"la": "Barnet", "la": "Barnet",

10
lib/tasks/form_definition.rake

@ -32,12 +32,12 @@ namespace :form_definition do
schema = JSON.parse(file.read) schema = JSON.parse(file.read)
meta_schema = JSON::Validator.validator_for_name("draft4").metaschema meta_schema = JSON::Validator.validator_for_name("draft4").metaschema
puts path puts path unless Rails.env.test?
if JSON::Validator.validate(meta_schema, schema) if JSON::Validator.validate(meta_schema, schema)
puts "Schema Definition is Valid" puts "Schema Definition is Valid" unless Rails.env.test?
else else
puts "Schema Definition in #{path} is not valid against draft4 json schema." puts "Schema Definition in #{path} is not valid against draft4 json schema." unless Rails.env.test?
next next
end end
@ -45,8 +45,8 @@ namespace :form_definition do
file = File.open(path) file = File.open(path)
form_definition = JSON.parse(file.read) form_definition = JSON.parse(file.read)
puts path puts path unless Rails.env.test?
puts JSON::Validator.fully_validate(schema, form_definition, strict: true) puts JSON::Validator.fully_validate(schema, form_definition, strict: true) unless Rails.env.test?
begin begin
JSON::Validator.validate!(schema, form_definition) JSON::Validator.validate!(schema, form_definition)

9
spec/factories/case_log.rb

@ -19,6 +19,15 @@ FactoryBot.define do
earnings { 750 } earnings { 750 }
incfreq { "Weekly" } incfreq { "Weekly" }
end end
trait :conditional_section_complete do
tenant_code { "TH356" }
age1 { 34 }
sex1 { "M" }
ethnic { 2 }
national { 4 }
ecstat1 { 2 }
other_hhmemb { 0 }
end
created_at { Time.zone.now } created_at { Time.zone.now }
updated_at { Time.zone.now } updated_at { Time.zone.now }
end end

2
spec/fixtures/complete_case_log.json vendored

@ -52,7 +52,7 @@
"startdate": "12/03/2019", "startdate": "12/03/2019",
"startertenancy": "No", "startertenancy": "No",
"tenancylength": "5", "tenancylength": "5",
"tenancy": "Fixed term – Secure", "tenancy": "Secure (including flexible)",
"lettype": "Affordable Rent - General Needs", "lettype": "Affordable Rent - General Needs",
"landlord": "This landlord", "landlord": "This landlord",
"la": "Barnet", "la": "Barnet",

27
spec/helpers/tasklist_helper_spec.rb

@ -6,26 +6,27 @@ RSpec.describe TasklistHelper do
let(:completed_case_log) { FactoryBot.build(:case_log, :completed) } let(:completed_case_log) { FactoryBot.build(:case_log, :completed) }
form_handler = FormHandler.instance form_handler = FormHandler.instance
let(:form) { form_handler.get_form("test_form") } let(:form) { form_handler.get_form("test_form") }
let(:household_characteristics_questions) { form.questions_for_subsection("household_characteristics") }
describe "get subsection status" do describe "get subsection status" do
let(:section) { "income_and_benefits" } let(:section) { "income_and_benefits" }
let(:income_and_benefits_questions) { form.questions_for_subsection("income_and_benefits").keys } let(:income_and_benefits_questions) { form.questions_for_subsection("income_and_benefits") }
let(:declaration_questions) { form.questions_for_subsection("declaration").keys } let(:declaration_questions) { form.questions_for_subsection("declaration") }
let(:local_authority_questions) { form.questions_for_subsection("local_authority").keys } let(:local_authority_questions) { form.questions_for_subsection("local_authority") }
it "returns not started if none of the questions in the subsection are answered" do it "returns not started if none of the questions in the subsection are answered" do
status = get_subsection_status("income_and_benefits", case_log, income_and_benefits_questions) status = get_subsection_status("income_and_benefits", case_log, form, income_and_benefits_questions)
expect(status).to eq(:not_started) expect(status).to eq(:not_started)
end end
it "returns cannot start yet if the subsection is declaration" do it "returns cannot start yet if the subsection is declaration" do
status = get_subsection_status("declaration", case_log, declaration_questions) status = get_subsection_status("declaration", case_log, form, declaration_questions)
expect(status).to eq(:cannot_start_yet) expect(status).to eq(:cannot_start_yet)
end end
it "returns in progress if some of the questions have been answered" do it "returns in progress if some of the questions have been answered" do
case_log["previous_postcode"] = "P0 5TT" case_log["previous_postcode"] = "P0 5TT"
status = get_subsection_status("local_authority", case_log, local_authority_questions) status = get_subsection_status("local_authority", case_log, form, local_authority_questions)
expect(status).to eq(:in_progress) expect(status).to eq(:in_progress)
end end
@ -35,14 +36,22 @@ RSpec.describe TasklistHelper do
case_log["benefits"] = "All" case_log["benefits"] = "All"
case_log["hb"] = "Do not know" case_log["hb"] = "Do not know"
status = get_subsection_status("income_and_benefits", case_log, income_and_benefits_questions) status = get_subsection_status("income_and_benefits", case_log, form, income_and_benefits_questions)
expect(status).to eq(:completed) expect(status).to eq(:completed)
end end
it "returns not started if the subsection is declaration and all the questions are completed" do it "returns not started if the subsection is declaration and all the questions are completed" do
status = get_subsection_status("declaration", completed_case_log, declaration_questions) status = get_subsection_status("declaration", completed_case_log, form, declaration_questions)
expect(status).to eq(:not_started) expect(status).to eq(:not_started)
end end
let(:conditional_section_complete_case_log) { FactoryBot.build(:case_log, :conditional_section_complete) }
it "sets the correct status for sections with conditional questions" do
status = get_subsection_status(
"household_characteristics", conditional_section_complete_case_log, form, household_characteristics_questions
)
expect(status).to eq(:completed)
end
end end
describe "get next incomplete section" do describe "get next incomplete section" do
@ -79,8 +88,6 @@ RSpec.describe TasklistHelper do
end end
describe "get_first_page_or_check_answers" do describe "get_first_page_or_check_answers" do
let(:household_characteristics_questions) { form.questions_for_subsection("household_characteristics").keys }
it "returns the check answers page path if the section has been started already" do it "returns the check answers page path if the section has been started already" do
expect(get_first_page_or_check_answers("household_characteristics", case_log, form, household_characteristics_questions)).to match(/check_answers/) expect(get_first_page_or_check_answers("household_characteristics", case_log, form, household_characteristics_questions)).to match(/check_answers/)
end end

2
spec/lib/tasks/form_definition_validator_spec.rb

@ -27,7 +27,7 @@ describe "rake form_definition:validate", type: :task do
end end
it "runs the validate task for the given form definition" do it "runs the validate task for the given form definition" do
expect(JSON::Validator).to receive(:validate!).at_least(2).times expect(JSON::Validator).to receive(:validate!).at_least(1).time
task.invoke("config/forms/2021_2022.json") task.invoke("config/forms/2021_2022.json")
end end
end end

18
spec/models/case_log_spec.rb

@ -182,39 +182,39 @@ RSpec.describe Form, type: :model do
it "Must be completed and between 2 and 99 if type of tenancy is Assured shorthold" do it "Must be completed and between 2 and 99 if type of tenancy is Assured shorthold" do
expect { expect {
CaseLog.create!(tenancy: "Fixed term – Assured Shorthold Tenancy (AST)", CaseLog.create!(tenancy: "Assured Shorthold",
tenancylength: 1) tenancylength: 1)
}.to raise_error(ActiveRecord::RecordInvalid) }.to raise_error(ActiveRecord::RecordInvalid)
expect { expect {
CaseLog.create!(tenancy: "Fixed term – Assured Shorthold Tenancy (AST)", CaseLog.create!(tenancy: "Assured Shorthold",
tenancylength: nil) tenancylength: nil)
}.to raise_error(ActiveRecord::RecordInvalid) }.to raise_error(ActiveRecord::RecordInvalid)
expect { expect {
CaseLog.create!(tenancy: "Fixed term – Assured Shorthold Tenancy (AST)", CaseLog.create!(tenancy: "Assured Shorthold",
tenancylength: 2) tenancylength: 2)
}.not_to raise_error }.not_to raise_error
end end
it "Must be empty or between 2 and 99 if type of tenancy is Secure" do it "Must be empty or between 2 and 99 if type of tenancy is Secure" do
expect { expect {
CaseLog.create!(tenancy: "Fixed term – Secure", CaseLog.create!(tenancy: "Secure (including flexible)",
tenancylength: 1) tenancylength: 1)
}.to raise_error(ActiveRecord::RecordInvalid) }.to raise_error(ActiveRecord::RecordInvalid)
expect { expect {
CaseLog.create!(tenancy: "Fixed term – Secure", CaseLog.create!(tenancy: "Secure (including flexible)",
tenancylength: 100) tenancylength: 100)
}.to raise_error(ActiveRecord::RecordInvalid) }.to raise_error(ActiveRecord::RecordInvalid)
expect { expect {
CaseLog.create!(tenancy: "Fixed term – Secure", CaseLog.create!(tenancy: "Secure (including flexible)",
tenancylength: nil) tenancylength: nil)
}.not_to raise_error }.not_to raise_error
expect { expect {
CaseLog.create!(tenancy: "Fixed term – Secure", CaseLog.create!(tenancy: "Secure (including flexible)",
tenancylength: 2) tenancylength: 2)
}.not_to raise_error }.not_to raise_error
end end
@ -294,12 +294,12 @@ RSpec.describe Form, type: :model do
it "must not be provided if tenancy type is not other" do it "must not be provided if tenancy type is not other" do
expect { expect {
CaseLog.create!(tenancy: "Fixed term – Secure", CaseLog.create!(tenancy: "Secure (including flexible)",
tenancyother: "the other reason provided") tenancyother: "the other reason provided")
}.to raise_error(ActiveRecord::RecordInvalid) }.to raise_error(ActiveRecord::RecordInvalid)
expect { expect {
CaseLog.create!(tenancy: "Fixed term – Secure", CaseLog.create!(tenancy: "Secure (including flexible)",
tenancyother: nil) tenancyother: nil)
}.not_to raise_error }.not_to raise_error
end end

Loading…
Cancel
Save