diff --git a/app/documents/templates/default_report_template.docx b/app/documents/templates/default_report_template.docx old mode 100755 new mode 100644 index 6cdb2dfeaf..dbfd0c6ca1 Binary files a/app/documents/templates/default_report_template.docx and b/app/documents/templates/default_report_template.docx differ diff --git a/app/documents/templates/howard_county_report_template.docx b/app/documents/templates/howard_county_report_template.docx index 03c2e2e024..f25b1181ad 100644 Binary files a/app/documents/templates/howard_county_report_template.docx and b/app/documents/templates/howard_county_report_template.docx differ diff --git a/app/documents/templates/prince_george_report_template.docx b/app/documents/templates/prince_george_report_template.docx old mode 100755 new mode 100644 index b74deb58a1..6685bc74a4 Binary files a/app/documents/templates/prince_george_report_template.docx and b/app/documents/templates/prince_george_report_template.docx differ diff --git a/app/models/case_court_report_context.rb b/app/models/case_court_report_context.rb index 122ccabb23..d91735d94a 100644 --- a/app/models/case_court_report_context.rb +++ b/app/models/case_court_report_context.rb @@ -25,7 +25,8 @@ def context 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" + hearing_type_name: @court_date&.hearing_type&.name || "None", + case_topics: court_topics.values } end @@ -88,6 +89,51 @@ def org_address(path_to_template) @volunteer.casa_org.address if @volunteer && is_default_template end + # Sample output + # + # expected_topics = { + # "Question 1" => {topic: "Question 1", details: "Details 1", answers: [ + # {date: "12/02/20", medium: "Type A1, Type B1", value: "Answer 1"}, + # {date: "12/03/20", medium: "Type A2, Type B2", value: "Answer 3"} + # ]}, + # "Question 2" => {topic: "Question 2", details: "Details 2", answers: [ + # {date: "12/02/20", medium: "Type A1, Type B1", value: "Answer 2"}, + # {date: "12/04/20", medium: "Type A3, Type B3", value: "Answer 5"} + # ]}, + # "Question 3" => {topic: "Question 3", details: "Details 3", answers: [ + # {date: "12/03/20", medium: "Type A2, Type B2", value: "No Answer Provided"}, + # {date: "12/04/20", medium: "Type A3, Type B3", value: "No Answer Provided"} + # ]} + # } + def court_topics + topics = ContactTopic + .joins(contact_topic_answers: {case_contact: [:casa_case, :contact_types]}).distinct + .where("casa_cases.id": @casa_case.id) + .where("case_contacts.occurred_at": @date_range) + .order(:occurred_at, :value) + .select(:details, :question, :occurred_at, :value, :contact_made, + "STRING_AGG(contact_types.name, ', ' ORDER BY contact_types.name) AS medium_types") + .group(:details, :question, :occurred_at, :value, :contact_made) + + topics.each_with_object({}) do |topic, hash| + hash[topic.question] ||= { + answers: [], + topic: topic.question, + details: topic.details + } + + formatted_date = CourtReportFormatContactDate.new(topic).format_long + answer_value = topic.value.blank? ? "No Answer Provided" : topic.value + answer = { + date: formatted_date, + medium: topic.medium_types, + value: answer_value + } + + hash[topic.question][:answers].push(answer) + end + end + private def calculate_date_range(args) diff --git a/app/services/court_report_format_contact_date.rb b/app/services/court_report_format_contact_date.rb index 6376ba29fd..db20bfbd66 100644 --- a/app/services/court_report_format_contact_date.rb +++ b/app/services/court_report_format_contact_date.rb @@ -8,4 +8,8 @@ def initialize(case_contact) def format I18n.l(@case_contact.occurred_at, format: :short_date, default: nil).concat(@case_contact.contact_made ? "" : CONTACT_UNSUCCESSFUL_PREFIX) end + + def format_long + I18n.l(@case_contact.occurred_at, format: :long_date, default: nil) + end end diff --git a/config/locales/en.yml b/config/locales/en.yml index 5e21875536..49422fd827 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -38,6 +38,7 @@ en: full: "%B %-d, %Y" youth_date_of_birth: "%B %Y" short_date: "%-m/%d" + long_date: "%m/%d/%y" edit_profile: "%B %d, %Y at %I:%M %p %Z" time_on_date: "%-I:%-M %p on %m-%e-%Y" date: diff --git a/spec/models/case_court_report_context_spec.rb b/spec/models/case_court_report_context_spec.rb index 45ee767d1f..043191517b 100644 --- a/spec/models/case_court_report_context_spec.rb +++ b/spec/models/case_court_report_context_spec.rb @@ -26,6 +26,7 @@ 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("") + allow(context).to receive(:court_topics).and_return({}) expected_shape = { created_date: "January 1, 2021", @@ -36,7 +37,8 @@ latest_hearing_date: "", org_address: nil, volunteer: {}, - hearing_type_name: court_date.hearing_type.name + hearing_type_name: court_date.hearing_type.name, + case_topics: [] } expect(context.context).to eq(expected_shape) @@ -176,6 +178,82 @@ end end + describe "#court_topics" do + let(:org) { create(:casa_org) } + let(:casa_case) { create(:casa_case, casa_org: org) } + let(:topics) { [1, 2, 3].map { |i| create(:contact_topic, casa_org: org, question: "Question #{i}", details: "Details #{i}") } } + let(:contacts) do + [1, 2, 3, 4].map do |i| + create(:case_contact, + casa_case: casa_case, + occurred_at: 1.month.ago + i.days, + contact_types: [ + create(:contact_type, name: "Type A#{i}"), + create(:contact_type, name: "Type B#{i}") + ]) + end + end + # let(:contacts) { create_list(:case_contact, 4, casa_case: casa_case, occurred_at: 1.month.ago) } + + context "when given data" do + # Add some values that should get filtered out + before do + contact_one = create(:case_contact, casa_case: casa_case, medium_type: "in-person", occurred_at: 1.day.ago) + create_list(:contact_topic_answer, 2, case_contact: contact_one, contact_topic: topics[0], value: "Not included") + + contact_two = create(:case_contact, casa_case: casa_case, medium_type: "in-person", occurred_at: 50.day.ago) + create_list(:contact_topic_answer, 2, case_contact: contact_two, contact_topic: topics[0], value: "Not included") + + other_case = create(:casa_case, casa_org: org) + contact_three = create(:case_contact, casa_case: other_case, medium_type: "in-person", occurred_at: 50.day.ago) + create_list(:contact_topic_answer, 2, case_contact: contact_three, contact_topic: topics[0], value: "Not included") + end + + it "generates correctly shaped data" do + # Contact 1 Answers + create(:contact_topic_answer, case_contact: contacts[0], contact_topic: topics[0], value: "Answer 1") + create(:contact_topic_answer, case_contact: contacts[0], contact_topic: topics[1], value: "Answer 2") + + # Contact 2 Answers + create(:contact_topic_answer, case_contact: contacts[1], contact_topic: topics[0], value: "Answer 3") + create(:contact_topic_answer, case_contact: contacts[1], contact_topic: topics[2], value: nil) + + # Contact 3 Answers + create(:contact_topic_answer, case_contact: contacts[2], contact_topic: topics[1], value: "Answer 5") + create(:contact_topic_answer, case_contact: contacts[2], contact_topic: topics[2], value: "") + + # Contact 4 Answers + # No Answers + + expected_topics = { + "Question 1" => {topic: "Question 1", details: "Details 1", answers: [ + {date: "12/02/20", medium: "Type A1, Type B1", value: "Answer 1"}, + {date: "12/03/20", medium: "Type A2, Type B2", value: "Answer 3"} + ]}, + "Question 2" => {topic: "Question 2", details: "Details 2", answers: [ + {date: "12/02/20", medium: "Type A1, Type B1", value: "Answer 2"}, + {date: "12/04/20", medium: "Type A3, Type B3", value: "Answer 5"} + ]}, + "Question 3" => {topic: "Question 3", details: "Details 3", answers: [ + {date: "12/03/20", medium: "Type A2, Type B2", value: "No Answer Provided"}, + {date: "12/04/20", medium: "Type A3, Type B3", value: "No Answer Provided"} + ]} + } + + court_report_context = build(:case_court_report_context, start_date: 45.day.ago.to_s, end_date: 5.day.ago.to_s, casa_case: casa_case) + + expect(court_report_context.court_topics).to eq(expected_topics) + end + end + + context "when there are no contact topics" do + it "returns an empty hash" do + court_report_context = build(:case_court_report_context, start_date: 45.day.ago.to_s, end_date: 5.day.ago.to_s, casa_case: casa_case) + expect(court_report_context.court_topics).to eq({}) + end + end + end + describe "#filtered_interviewees" do it "filters based on date range" do casa_case = create(:casa_case) diff --git a/spec/models/case_court_report_spec.rb b/spec/models/case_court_report_spec.rb index 17783455dd..2473cc7952 100644 --- a/spec/models/case_court_report_spec.rb +++ b/spec/models/case_court_report_spec.rb @@ -9,6 +9,83 @@ let(:path_to_report) { Rails.root.join("tmp", "test_report.docx").to_s } context "#generate_to_string" do + let(:full_context) do + { + created_date: "April 9, 2024", + casa_case: { + court_date: "April 23, 2024", + case_number: "A-CASA-CASE-NUMBER-12345", + dob: "April 2012", + is_transitioning: false, + judge_name: "Judge Judy" + }, + case_contacts: [ + {name: "Some Name", type: "Type 1", dates: "4/09*", dates_by_medium_type: {"in-person" => "4/09*"}}, + {name: "Some Other Name", type: "Type 4", dates: "4/09*", dates_by_medium_type: {"in-person" => "4/09*"}} + ], + case_court_orders: [ + {order: "case_court_order_text", status: "Partially implemented"} + ], + case_mandates: [ + {order: "case_mandates_text", status: "Partially implemented"} + ], + latest_hearing_date: "_______", + org_address: "596 Unique Avenue Seattle, Washington", + volunteer: { + name: "name_of_volunteer", + supervisor_name: "name_of_supervisor", + assignment_date: "February 9, 2024" + }, + hearing_type_name: "None", + case_topics: [ + {topic: "Question 1", details: "Details 1", answers: [ + {date: "12/01/20", medium: "Type A1, Type B1", value: "Answer 1"}, + {date: "12/02/20", medium: "Type A2, Type B2", value: "Answer 3"} + ]}, + {topic: "Question 2", details: "Details 2", answers: [ + {date: "12/01/20", medium: "Type A1, Type B1", value: "Answer 2"}, + {date: "12/02/20", medium: "Type A3, Type B3", value: "Answer 5"} + ]}, + {topic: "Question 3", details: "Details 3", answers: [ + {date: "12/01/20", medium: "Type A3, Type B3", value: "No Answer Provided"}, + {date: "12/02/20", medium: "Type A2, Type B2", value: "No Answer Provided"} + ]} + ] + } + end + describe "contact_topics" do + it "all contact topics are present in the report" do + docx_response = generate_doc(full_context, path_to_template) + expect(docx_response.paragraphs.map(&:to_s)).to include(/Question 1.*/) + expect(docx_response.paragraphs.map(&:to_s)).to include(/Question 2.*/) + expect(docx_response.paragraphs.map(&:to_s)).to include(/Question 3.*/) + end + + it "all topic details are present in the report" do + docx_response = generate_doc(full_context, path_to_template) + expect(docx_response.paragraphs.map(&:to_s)).to include(/Details 1.*/) + expect(docx_response.paragraphs.map(&:to_s)).to include(/Details 2.*/) + expect(docx_response.paragraphs.map(&:to_s)).to include(/Details 3.*/) + end + + it "all answers are present with correct format" do + docx_response = generate_doc(full_context, path_to_template) + expect(docx_response.paragraphs.map(&:to_s)).to include(/Type A1, Type B1 \(12\/01\/20\): Answer 1.*/) + expect(docx_response.paragraphs.map(&:to_s)).to include(/Type A2, Type B2 \(12\/02\/20\): Answer 3.*/) + expect(docx_response.paragraphs.map(&:to_s)).to include(/Type A1, Type B1 \(12\/01\/20\): Answer 2.*/) + expect(docx_response.paragraphs.map(&:to_s)).to include(/Type A3, Type B3 \(12\/02\/20\): Answer 5.*/) + expect(docx_response.paragraphs.map(&:to_s)).to include(/Type A3, Type B3 \(12\/01\/20\): No Answer Provided.*/) + expect(docx_response.paragraphs.map(&:to_s)).to include(/Type A2, Type B2 \(12\/02\/20\): No Answer Provided.*/) + end + + context "when there are no answers" do + it "report does not error" do + full_context[:case_topics] = [] + expect { generate_doc(full_context, path_to_template) }.not_to raise_error + end + end + end + describe "when receiving valid case, volunteer, and path_to_template" do let(:volunteer) { create(:volunteer, :with_cases_and_contacts, :with_assigned_supervisor) } let(:casa_case_with_contacts) { volunteer.casa_cases.first } @@ -367,3 +444,8 @@ end end end + +def generate_doc(context, path_to_template) + report = CaseCourtReport.new(path_to_template: path_to_template, context: context) + Docx::Document.open(StringIO.new(report.generate_to_string)) +end