diff --git a/app/models/case_court_report_context.rb b/app/models/case_court_report_context.rb index 5bb295fcc8..9d10bb1637 100644 --- a/app/models/case_court_report_context.rb +++ b/app/models/case_court_report_context.rb @@ -15,28 +15,26 @@ def initialize(args = {}) end def context - prepare_context(@path_to_template.end_with?("default_report_template.docx")) - end - - private - - def prepare_context(is_default_template) - latest_hearing_date = @casa_case.most_recent_past_court_date - { created_date: I18n.l(Time.current.in_time_zone(@time_zone).to_date, format: :full, default: nil), - casa_case: prepare_case_details, - case_contacts: prepare_case_contacts, - case_court_orders: prepare_case_orders, - case_mandates: prepare_case_orders, # backwards compatible with old Montgomery template - keep this! TODO test full generation - latest_hearing_date: latest_hearing_date.nil? ? "_______" : I18n.l(latest_hearing_date.date, format: :full, default: nil), - org_address: org_address(is_default_template), + casa_case: case_details, + case_contacts: case_contacts, + case_court_orders: case_orders(@case_court_orders), + case_mandates: case_orders(@case_court_orders), # backwards compatible with old Montgomery template - keep this! TODO test full generation + latest_hearing_date: latest_hearing_date, + org_address: org_address(@path_to_template), volunteer: volunteer_info, hearing_type_name: @court_date&.hearing_type&.name || "None" } end - def prepare_case_contacts + # @return [Array] + # Each hash includes: + # - :name [String] + # - :type [String] + # - :dates [Array] + # - :dates_by_medium_type [Array] + def case_contacts cccts = CaseContactContactType.includes(:case_contact, :contact_type).where("case_contacts.casa_case_id": @casa_case.id) interviewees = filter_out_old_case_contacts(cccts) return [] unless interviewees.size.positive? @@ -44,8 +42,13 @@ def prepare_case_contacts CaseContactsContactDates.new(interviewees).contact_dates_details end - def prepare_case_orders - @case_court_orders.map do |case_order| + def latest_hearing_date + latest_hearing_date = @casa_case.most_recent_past_court_date + latest_hearing_date.nil? ? "_______" : I18n.l(latest_hearing_date.date, format: :full, default: nil) + end + + def case_orders(orders) + orders.map do |case_order| { order: case_order.text, status: case_order.implementation_status&.humanize @@ -62,7 +65,7 @@ def filter_out_old_case_contacts(interviewees) end end - def prepare_case_details + def case_details { court_date: I18n.l(@court_date&.date, format: :full, default: nil), case_number: @casa_case.case_number, @@ -82,7 +85,8 @@ def volunteer_info end end - def org_address(is_default_template) + def org_address(path_to_template) + is_default_template = path_to_template.end_with?("default_report_template.docx") @volunteer.casa_org.address if @volunteer && is_default_template end end diff --git a/spec/factories/case_court_report_context.rb b/spec/factories/case_court_report_context.rb index f3402cf5e1..1d0301a5f5 100644 --- a/spec/factories/case_court_report_context.rb +++ b/spec/factories/case_court_report_context.rb @@ -15,13 +15,13 @@ volunteer_for_context = volunteer.nil? ? create(:volunteer) : volunteer casa_case_for_context = casa_case.nil? ? create(:casa_case) : casa_case - unless volunteer_for_context.casa_cases.where(id: casa_case_for_context.id).exists? + if volunteer_for_context && volunteer_for_context.casa_cases.where(id: casa_case_for_context.id).none? volunteer_for_context.casa_cases << casa_case_for_context end new( case_id: casa_case_for_context.id, - volunteer_id: volunteer_for_context.id, + volunteer_id: volunteer_for_context.try(:id), path_to_report: path_to_report, path_to_template: path_to_template, court_date: court_date, diff --git a/spec/models/case_court_report_context_spec.rb b/spec/models/case_court_report_context_spec.rb index e57dd2cdf7..301f424e78 100644 --- a/spec/models/case_court_report_context_spec.rb +++ b/spec/models/case_court_report_context_spec.rb @@ -13,274 +13,152 @@ end describe "#context" do - let(:court_report_context) { build(:case_court_report_context) } - - describe ":created_date" do - it "has a created date equal to the current date" do - expect(court_report_context.context[:created_date]).to eq("January 1, 2021") - end - end - - describe ":casa_case" do - let(:case_number) { "Sample-Case-12345" } - let(:casa_case) { - create(:casa_case, - birth_month_year_youth: 121.months.ago, # 10 Years 1 month ago - case_number: case_number) + it "has the right shape" do + date = 1.day.ago + court_date = build(:court_date, :with_hearing_type, date: date) + context = create(:case_court_report_context, court_date: court_date) + + allow(context).to receive(:case_details).and_return({}) + allow(context).to receive(:case_contacts).and_return([]) + allow(context).to receive(:case_orders).and_return([]) + allow(context).to receive(:org_address).and_return(nil) + allow(context).to receive(:volunteer_info).and_return({}) + allow(context).to receive(:latest_hearing_date).and_return("") + + expected_shape = { + created_date: "January 1, 2021", + casa_case: {}, + case_contacts: [], + case_court_orders: [], + case_mandates: [], + latest_hearing_date: "", + org_address: nil, + volunteer: {}, + hearing_type_name: court_date.hearing_type.name } - let(:court_report_context) { build(:case_court_report_context, casa_case: casa_case) } - - describe ":court_date" do - context "when there are future court dates" do - let(:court_date_1) { create(:court_date, date: 2.months.since) } - let(:court_date_2) { create(:court_date, date: 5.months.since) } - - before(:each) do - casa_case.court_dates << court_date_1 - casa_case.court_dates << court_date_2 - end - - it "contains the soonest future court date in a human readable format" do - expect(court_report_context.context[:casa_case][:court_date]).to eq("March 1, 2021") - end - end - - context "when they specify a specific court date they are interested in looking at" do - it "contains the selected court date in a human readable format" do - court_date_1 = create(:court_date, date: 2.months.since) - court_date_2 = create(:court_date, date: 5.months.since) - - casa_case.court_dates << court_date_1 - casa_case.court_dates << court_date_2 - court_report_context = build(:case_court_report_context, casa_case: casa_case, court_date: court_date_2) - expect(court_report_context.context[:casa_case][:court_date]).to eq("June 1, 2021") - end - end + expect(context.context).to eq(expected_shape) + end + end - context "when there are no future court dates" do - let(:past_court_date) { create(:court_date, date: 2.months.ago) } + describe "case_orders" do + it "returns the correct shape" do + court_orders = [ + build(:case_court_order, text: "Court order 1", implementation_status: :unimplemented), + build(:case_court_order, text: "Court order 2", implementation_status: :implemented) + ] + expected = [ + {order: "Court order 1", status: "Unimplemented"}, + {order: "Court order 2", status: "Implemented"} + ] + context = build_stubbed(:case_court_report_context) + + expect(context.case_orders(court_orders)).to match_array(expected) + end + end - before(:each) do - casa_case.court_dates << past_court_date - end + describe "org_address" do + let(:volunteer) { create(:volunteer) } + let(:context) { build(:case_court_report_context, volunteer: volunteer) } - it "contains the soonest future court date in a human readable format" do - expect(court_report_context.context[:casa_case][:court_date]).to be_nil - end - end - end + context "when volunteer and default template are provided" do + it "returns the CASA org address" do + path_to_template = "default_report_template.docx" + expected_address = volunteer.casa_org.address - describe ":case_number" do - it "contains the case number of the casa case" do - expect(court_report_context.context[:casa_case][:case_number]).to eq(case_number) - end + expect(context.org_address(path_to_template)).to eq(expected_address) end + end - describe ":dob" do - it "contains the month and year of birth" do - expect(court_report_context.context[:casa_case][:dob]).to eq("December 2010") - end - end - - describe ":is_transitioning" do - context "when the case birth month and year is less than 14 years ago" do - before(:each) do - casa_case.update_attribute(:birth_month_year_youth, 167.months.ago) - end - - it "contains false" do - expect(court_report_context.context[:casa_case][:is_transitioning]).to eq(false) - end - end - - context "when the case birth month and year is greater or equal to 14 years ago" do - before(:each) do - casa_case.update_attribute(:birth_month_year_youth, 14.years.ago) - end + context "when volunteer is provided but not default template" do + it "returns nil" do + path_to_template = "some_other_template.docx" - it "contains true" do - expect(court_report_context.context[:casa_case][:is_transitioning]).to eq(true) - end - end + expect(context.org_address(path_to_template)).to be_nil end + end - describe ":judge_name" do - context "when there are future court dates" do - let(:next_court_date_judge_name) { "Judge A" } - let(:court_date_1) { create(:court_date, :with_judge, date: 2.months.since) } - let(:court_date_2) { create(:court_date, :with_judge, date: 5.months.since) } - - before(:each) do - court_date_1.judge.update_attribute(:name, next_court_date_judge_name) - court_date_2.judge.update_attribute(:name, "Judge B") - - casa_case.court_dates << court_date_1 - casa_case.court_dates << court_date_2 - end + context "when volunteer is not provided" do + let(:context) { build(:case_court_report_context, volunteer: false) } - it "contains the soonest future court date in a human readable format" do - expect(court_report_context.context[:casa_case][:judge_name]).to eq(next_court_date_judge_name) - end - end + it "returns nil" do + path_to_template = "default_report_template.docx" + expect(context.org_address(path_to_template)).to be_nil end end + end - describe ":case_contacts" do - let(:casa_case) { create(:casa_case) } - let(:case_contact_1_date) { 30.days.ago } - let(:case_contact_2_date) { 45.days.ago } - let(:case_contact_3_date) { 60.days.ago } - let(:case_contact_4_date) { 75.days.ago } - let(:case_contact_1) { build(:case_contact, occurred_at: case_contact_1_date) } - let(:case_contact_2) { build(:case_contact, occurred_at: case_contact_2_date) } - let(:case_contact_3) { build(:case_contact, occurred_at: case_contact_3_date) } - let(:case_contact_4) { build(:case_contact, occurred_at: case_contact_4_date) } - let(:contact_type_1) { build(:contact_type, name: "XM_L!_g=Ko\\-'A!") } - let(:contact_type_2) { build(:contact_type, name: "uHp$O2;oq!C3{]l") } - let(:contact_type_3) { build(:contact_type, name: "\"PlqEsCP[JktjTS") } - let(:contact_type_4) { build(:contact_type, name: "K3BbzNCni4mVC5@") } - let(:contact_type_5) { build(:contact_type, name: "lf7CA&n8BQ*qJ?E") } - let(:court_report_context) { build(:case_court_report_context, casa_case: casa_case).context } - - before(:each) do - case_contact_1.contact_types << contact_type_1 - case_contact_2.contact_types << contact_type_2 - case_contact_3.contact_types << contact_type_3 - case_contact_4.contact_types << contact_type_4 - case_contact_1.contact_types << contact_type_5 - - casa_case.case_contacts << case_contact_1 - casa_case.case_contacts << case_contact_2 - casa_case.case_contacts << case_contact_3 - casa_case.case_contacts << case_contact_4 - end + describe "#latest_hearing_date" do + context "when casa_case has court_dates" do + let(:court_date) { build(:court_date, date: 2.day.ago) } + let(:casa_case) { create(:casa_case, court_dates: [court_date]) } + let(:instance) { build(:case_court_report_context, casa_case: casa_case) } - it "for each contact type in a case contact, contains the name of the type and the occurred at date" do - expect(court_report_context[:case_contacts]).to include(include(dates: case_contact_1_date.strftime("%m/%d*"), type: contact_type_1.name)) - expect(court_report_context[:case_contacts]).to include(include(dates: case_contact_2_date.strftime("%m/%d*"), type: contact_type_2.name)) - expect(court_report_context[:case_contacts]).to include(include(dates: case_contact_3_date.strftime("%m/%d*"), type: contact_type_3.name)) - expect(court_report_context[:case_contacts]).to include(include(dates: case_contact_4_date.strftime("%m/%d*"), type: contact_type_4.name)) - expect(court_report_context[:case_contacts]).to include(include(dates: case_contact_1_date.strftime("%m/%d*"), type: contact_type_5.name)) + it "returns the formatted date" do + expect(instance.latest_hearing_date).to eq("December 30, 2020") # 2 days before spec default date end + end - it "for each contact type in a case contact, contains a placeholder value for the name(s) of the people involved" do - case_contact_report_data = court_report_context[:case_contacts] - expect(case_contact_report_data.length).to be > 0 + context "when most recent past court date is nil" do + let(:instance) { build(:case_court_report_context) } - case_contact_report_data.each { |contact_type_and_dates| - expect(contact_type_and_dates[:name]).to eq("Names of persons involved, starting with the child's name") - } + it "returns the placeholder string" do + expect(instance.latest_hearing_date).to eq("_______") end + end + end - context "when a contact type is included in multiple case contacts" do - before(:each) do - case_contact_2.contact_types << contact_type_1 - case_contact_4.contact_types << contact_type_1 - end - - it "includes an object with the contact type name and the dates of all case contacts" do - contact_type_and_dates = court_report_context[:case_contacts].find { |case_contact_type_and_dates| - case_contact_type_and_dates[:type] == contact_type_1.name - } - - expect(contact_type_and_dates).to_not be_nil - expect(contact_type_and_dates[:dates]).to include(case_contact_1_date.strftime("%m/%d")) - expect(contact_type_and_dates[:dates]).to include(case_contact_2_date.strftime("%m/%d")) - expect(contact_type_and_dates[:dates]).to include(case_contact_4_date.strftime("%m/%d")) - expect(contact_type_and_dates[:dates]).to_not include(case_contact_3_date.strftime("%m/%d")) - end - - it "contains a string with the dates of the case contacts with the contact type sorted by oldest date first" do - contact_type_and_dates = court_report_context[:case_contacts].find { |case_contact_type_and_dates| - case_contact_type_and_dates[:type] == contact_type_1.name - } - - expect(contact_type_and_dates).to_not be_nil - - dates = contact_type_and_dates[:dates] - case_contact_1_date_index = dates.index(case_contact_1_date.strftime("%m/%d")) - case_contact_2_date_index = dates.index(case_contact_2_date.strftime("%m/%d")) - case_contact_4_date_index = dates.index(case_contact_4_date.strftime("%m/%d")) - - expect(case_contact_1_date_index).to be > case_contact_2_date_index - expect(case_contact_2_date_index).to be > case_contact_4_date_index - end - - context "when there are multiple medium types" do - before(:each) do - case_contact_4.update_attribute(:medium_type, "voice-only") - end - - describe ":dates_by_medium_type" do - it "contains a key for each medium type and the dates of the case contacts with the medium type the values" do - case_contact_object_containing_complex_dates_by_medium_type = court_report_context[:case_contacts].find { |case_contact_type_and_dates| - case_contact_type_and_dates[:type] == contact_type_1.name - } - - dates_by_medium_type = case_contact_object_containing_complex_dates_by_medium_type[:dates_by_medium_type] + describe "#case_contacts" do + let(:casa_case) { create(:casa_case) } + let(:context) { build(:case_court_report_context, casa_case: casa_case) } - expect(dates_by_medium_type).to have_key(case_contact_1.medium_type) - expect(dates_by_medium_type).to have_key(case_contact_4.medium_type) + it "returns an empty array if there are no interviewees" do + expect(context.case_contacts).to eq([]) + end - expect(dates_by_medium_type[case_contact_1.medium_type]).to include(case_contact_1_date.strftime("%m/%d")) - expect(dates_by_medium_type[case_contact_2.medium_type]).to include(case_contact_2_date.strftime("%m/%d")) - expect(dates_by_medium_type[case_contact_4.medium_type]).to include(case_contact_4_date.strftime("%m/%d")) - end - end - end - end + # not sure how to test this without just restating the code + # context 'when there are interviewees' do + # it 'it calls CaseContactsContactDates with filtered values' do + # create_list(:case_contact_contact_type, 3, case_contact: create(:case_contact, casa_case: casa_case)) + # context.case_contacts + # end + # end + end - context "when there are past court dates" do - let!(:past_court_date) { create(:court_date, date: 50.days.ago, casa_case: casa_case) } + describe "#filter_out_old_case_contacts" do + let(:casa_case) { create(:casa_case) } + let(:court_date) { nil } + let(:court_report_context) { build(:case_court_report_context, casa_case: casa_case, court_date: court_date) } - it "contains only case contacts information after the latest past court date" do - expect(court_report_context[:case_contacts]).to include(include(type: contact_type_1.name)) - expect(court_report_context[:case_contacts]).to include(include(type: contact_type_5.name)) - expect(court_report_context[:case_contacts]).to include(include(type: contact_type_2.name)) - expect(court_report_context[:case_contacts]).to_not include(include(type: contact_type_3.name)) - expect(court_report_context[:case_contacts]).to_not include(include(type: contact_type_4.name)) - end + context "when there is no most recent court date" do + it "returns all interviewees" do + interviewees = build_list(:case_contact, 3) + expect(court_report_context.filter_out_old_case_contacts(interviewees)).to match_array(interviewees) end end - describe ":case_court_orders and :case_mandates" do - let(:casa_case) { create(:casa_case, case_number: "Sample-Case-12345") } - let!(:court_order_implemented) { build(:case_court_order, text: "K6N-ce8|NuXnht(", implementation_status: :implemented) } - let!(:court_order_unimplemented) { build(:case_court_order, text: "'q\"tE1LP-9W>,2)", implementation_status: :unimplemented) } - let!(:court_order_partially_implemented) { build(:case_court_order, text: "ZmCw@w@\d`&roct", implementation_status: :partially_implemented) } - let!(:court_order_not_specified) { build(:case_court_order, text: "(4WqOL7e'FRYd@%", implementation_status: nil) } - let(:court_report_context) { build(:case_court_report_context, casa_case: casa_case).context } + context "when there is a most recent court date" do + let(:date) { 5.day.ago } + let(:court_date) { build(:court_date, date: date) } + let(:casa_case) { create(:casa_case, court_dates: [court_date]) } - before(:each) do - casa_case.case_court_orders << court_order_implemented - casa_case.case_court_orders << court_order_not_specified - casa_case.case_court_orders << court_order_partially_implemented - - casa_case.case_court_orders << court_order_unimplemented - end + it "filters out case contacts before the court date" do + create_list(:case_contact, 3, occurred_at: date - 1.day, casa_case: casa_case) + included_interviewee = create(:case_contact, occurred_at: date + 1.day, casa_case: casa_case) - context "when using specified orders to a specific casa date" do - it "does not lean on orders of the casa case if specified directly" do - court_order = build(:case_court_order, text: "Some Court Text", implementation_status: :implemented) - court_report_context = build(:case_court_report_context, casa_case: casa_case, case_court_orders: [court_order]).context - expect(court_report_context[:case_court_orders]).to eq([{order: "Some Court Text", status: "Implemented"}]) - end - end + result = court_report_context.filter_out_old_case_contacts(CaseContact.all) - it "has a list of court orders the same length as all the court orders in the case" do - expect(court_report_context[:case_court_orders].length).to eq(casa_case.case_court_orders.length) + expect(result).to contain_exactly(included_interviewee) end + end + end - it "includes the implementation status and text of each court order" do - expect(court_report_context[:case_court_orders]).to include({order: court_order_implemented.text, status: court_order_implemented.implementation_status&.humanize}) - expect(court_report_context[:case_court_orders]).to include({order: court_order_not_specified.text, status: court_order_not_specified.implementation_status&.humanize}) - expect(court_report_context[:case_court_orders]).to include({order: court_order_partially_implemented.text, status: court_order_partially_implemented.implementation_status&.humanize}) - expect(court_report_context[:case_court_orders]).to include({order: court_order_unimplemented.text, status: court_order_unimplemented.implementation_status&.humanize}) - end + describe "#context" do + let(:court_report_context) { build(:case_court_report_context) } - it "has identical values for :case_court_orders and :case_mandates" do - expect(court_report_context[:case_mandates]).to eq(court_report_context[:case_court_orders]) # backwards compatibility for old names in old montgomery template - TODO track it down and update prod templates + describe ":created_date" do + it "has a created date equal to the current date" do + expect(court_report_context.context[:created_date]).to eq("January 1, 2021") end end @@ -309,47 +187,20 @@ end end end + end - describe ":org_address" do - let(:casa_org_address) { "-m}~2ccy%F7v;\\].-g$", supervisor: build(:supervisor, display_name: "Mm^ED;`zg(gcy%F7v;\\].-g$", + supervisor_name: "Mm^ED;`zg(gcy%F7v;\\].-g$", supervisor: build(:supervisor, display_name: "Mm^ED;`zg(g