Skip to content

Commit 9496faa

Browse files
committed
Fix court report topic output and ordering
1 parent 8e893b1 commit 9496faa

14 files changed

Lines changed: 150 additions & 35 deletions

app/controllers/casa_org_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def set_learning_hour_topics
9191
end
9292

9393
def set_contact_topics
94-
@contact_topics = @casa_org.contact_topics.where(soft_delete: false)
94+
@contact_topics = @casa_org.contact_topics.where(soft_delete: false).order(:question)
9595
end
9696

9797
def set_custom_org_links

app/controllers/case_court_reports_controller.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ def generate
6565
private
6666

6767
def date_range_params
68-
params.permit(:time_zone, case_court_report: %i[start_date end_date])
68+
params.permit(:time_zone, case_court_report: %i[start_date end_date include_empty_topics])
6969
end
7070

7171
def case_params
@@ -94,7 +94,8 @@ def generate_report_to_string(casa_case, time_range)
9494
path_to_template: template_docx_file.to_path,
9595
time_zone: time_range[:time_zone],
9696
start_date: time_range[:case_court_report][:start_date],
97-
end_date: time_range[:case_court_report][:end_date]
97+
end_date: time_range[:case_court_report][:end_date],
98+
include_empty_topics: time_range[:case_court_report][:include_empty_topics]
9899
}
99100
context = CaseCourtReportContext.new(args).context
100101
court_report = CaseCourtReport.new(path_to_template: template_docx_file.to_path, context: context)

app/models/case_court_report_context.rb

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ def initialize(args = {})
1212
@path_to_template = args[:path_to_template]
1313
@court_date = args[:court_date] || @casa_case.next_court_date
1414
@case_court_orders = args[:case_court_orders] || @casa_case.case_court_orders
15+
@include_empty_topics = ActiveModel::Type::Boolean.new.cast(args[:include_empty_topics])
1516
@date_range = calculate_date_range(args)
1617
end
1718

@@ -59,9 +60,11 @@ def case_orders(orders)
5960

6061
def filtered_interviewees
6162
CaseContactContactType
62-
.joins(:contact_type, case_contact: :casa_case)
63+
.joins(contact_type: :contact_type_group, case_contact: :casa_case)
64+
.includes(:case_contact, contact_type: :contact_type_group)
6365
.where("case_contacts.casa_case_id": @casa_case.id)
6466
.where("case_contacts.occurred_at": @date_range)
67+
.order("contact_type_groups.name ASC", "contact_types.name ASC", "case_contact_contact_types.id ASC")
6568
end
6669

6770
def case_details
@@ -92,15 +95,15 @@ def org_address(path_to_template)
9295
# Sample output
9396
#
9497
# expected_topics = {
95-
# "Question 1" => {topic: "Question 1", details: "Details 1", answers: [
98+
# "Question 1" => {topic: "Question 1", details: "", answers: [
9699
# {date: "12/02/20", medium: "Type A1, Type B1", value: "Answer 1"},
97100
# {date: "12/03/20", medium: "Type A2, Type B2", value: "Answer 3"}
98101
# ]},
99-
# "Question 2" => {topic: "Question 2", details: "Details 2", answers: [
102+
# "Question 2" => {topic: "Question 2", details: "", answers: [
100103
# {date: "12/02/20", medium: "Type A1, Type B1", value: "Answer 2"},
101104
# {date: "12/04/20", medium: "Type A3, Type B3", value: "Answer 5"}
102105
# ]},
103-
# "Question 3" => {topic: "Question 3", details: "Details 3", answers: [
106+
# "Question 3" => {topic: "Question 3", details: "", answers: [
104107
# {date: "12/03/20", medium: "Type A2, Type B2", value: "No Answer Provided"},
105108
# {date: "12/04/20", medium: "Type A3, Type B3", value: "No Answer Provided"}
106109
# ]}
@@ -112,18 +115,21 @@ def court_topics
112115
hash[topic.question] = {
113116
answers: answers_by_topic_id.fetch(topic.id, []),
114117
topic: topic.question,
115-
details: topic.details
118+
details: ""
116119
}
117120
end
118121
end
119122

120123
private
121124

122125
def report_topics(answered_topic_ids)
123-
ContactTopic
126+
topics = ContactTopic
124127
.where(casa_org: @casa_case.casa_org, exclude_from_court_report: false)
125-
.merge(ContactTopic.active.or(ContactTopic.where(id: answered_topic_ids)))
126-
.order(:id)
128+
.order(:question)
129+
130+
return topics.where(id: answered_topic_ids) unless @include_empty_topics
131+
132+
topics.merge(ContactTopic.active.or(ContactTopic.where(id: answered_topic_ids)))
127133
end
128134

129135
def court_topic_answers

app/services/case_contacts_contact_dates.rb

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@ def initialize(case_contact_contact_types)
44
end
55

66
def contact_dates_details
7-
contact_type_names = @case_contact_contact_types.map(&:contact_type).map(&:name).uniq # .sort # TODO sort after refactor
8-
contact_type_names.map do |contact_type_name|
9-
case_contacts = case_contacts_for_type(contact_type_name)
7+
contact_types = @case_contact_contact_types
8+
.map(&:contact_type)
9+
.uniq
10+
.sort_by { |contact_type| [contact_type.contact_type_group.name, contact_type.name] }
11+
12+
contact_types.map do |contact_type|
13+
case_contacts = case_contacts_for_type(contact_type)
1014

1115
{
1216
name: "Names of persons involved, starting with the child's name",
13-
type: contact_type_name,
17+
type: contact_type.name,
1418
dates: order_and_format(case_contacts),
1519
dates_by_medium_type: case_contacts.group_by(&:medium_type).transform_values { |vals| order_and_format(vals) }
1620
}
@@ -19,9 +23,9 @@ def contact_dates_details
1923

2024
private
2125

22-
def case_contacts_for_type(contact_type_name)
26+
def case_contacts_for_type(contact_type)
2327
@case_contact_contact_types
24-
.select { |ccct| ccct.contact_type.name == contact_type_name }
28+
.select { |ccct| ccct.contact_type_id == contact_type.id }
2529
.map(&:case_contact)
2630
end
2731

app/views/casa_cases/_court_report_modal.html.erb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@
3232
class: "block w-full rounded-lg border border-slate-300 px-3.5 py-2.5 text-sm text-slate-900 shadow-sm focus:border-brand-500 focus:ring-2 focus:ring-brand-500/30 focus:outline-none" %>
3333
</div>
3434
</div>
35+
<label class="flex items-center gap-2 text-sm font-medium text-slate-700">
36+
<%= form.check_box :include_empty_topics, class: "h-4 w-4 shrink-0 rounded border-slate-300 text-brand-600 focus:ring-brand-500" %>
37+
<span>Include sections with no entries</span>
38+
</label>
3539
<% end %>
3640
<%= render Dialog::FooterComponent.new do %>
3741
<button type="button" data-action="modal#close" class="<%= button_classes(:secondary) %>">Cancel</button>

app/views/case_court_reports/_generate_docx.html.erb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@
5757
data: {court_report_target: "endDate"}, class: input_class %>
5858
</div>
5959
</div>
60+
<label class="flex items-center gap-2 text-sm font-medium text-slate-700">
61+
<%= form.check_box :include_empty_topics, class: "h-4 w-4 shrink-0 rounded border-slate-300 text-brand-600 focus:ring-brand-500" %>
62+
<span>Include sections with no entries</span>
63+
</label>
6064
<% end %>
6165
<%= render Dialog::FooterComponent.new do %>
6266
<button type="button" data-action="modal#close" class="<%= button_classes(:secondary) %>">Cancel</button>

spec/factories/case_court_report_context.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
start_date { nil }
1313
end_date { nil }
1414
time_zone { nil }
15+
include_empty_topics { false }
1516
end
1617

1718
initialize_with {
@@ -31,7 +32,8 @@
3132
case_court_orders: case_court_orders,
3233
start_date: start_date,
3334
end_date: end_date,
34-
time_zone: time_zone
35+
time_zone: time_zone,
36+
include_empty_topics: include_empty_topics
3537
)
3638
}
3739
end

spec/models/case_court_report_context_spec.rb

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@
229229
expect(court_topics.values).to all(
230230
a_hash_including(
231231
topic: a_kind_of(String),
232-
details: a_kind_of(String),
232+
details: "",
233233
answers: all(
234234
a_hash_including(
235235
date: a_string_matching(/\d{2}\/\d{2}\/\d{2}/),
@@ -270,29 +270,37 @@
270270
end
271271

272272
context "when some topics have no answers" do
273-
it "includes every topic, with an empty answer list for unanswered ones" do
273+
it "omits unanswered topics by default" do
274274
create(:contact_topic_answer, case_contact: contacts[0], contact_topic: topics[0], value: "Answer 1")
275275

276276
court_topics = build(:case_court_report_context, casa_case: casa_case).court_topics
277277

278-
expect(court_topics.keys).to eq(["Question 1", "Question 2", "Question 3"])
278+
expect(court_topics.keys).to eq(["Question 1"])
279279
expect(court_topics["Question 1"][:answers].pluck(:value)).to eq(["Answer 1"])
280+
end
281+
282+
it "includes unanswered topics when requested" do
283+
create(:contact_topic_answer, case_contact: contacts[0], contact_topic: topics[0], value: "Answer 1")
284+
285+
court_topics = build(:case_court_report_context, casa_case: casa_case, include_empty_topics: true).court_topics
286+
287+
expect(court_topics.keys).to eq(["Question 1", "Question 2", "Question 3"])
280288
expect(court_topics["Question 2"][:answers]).to eq([])
281289
expect(court_topics["Question 3"][:answers]).to eq([])
282290
end
283291

284292
it "does not include unanswered topics that are inactive" do
285293
topics[1].update!(active: false)
286294

287-
court_topics = build(:case_court_report_context, casa_case: casa_case).court_topics
295+
court_topics = build(:case_court_report_context, casa_case: casa_case, include_empty_topics: true).court_topics
288296

289297
expect(court_topics.keys).to eq(["Question 1", "Question 3"])
290298
end
291299

292300
it "does not include unanswered topics excluded from the court report" do
293301
topics[1].update!(exclude_from_court_report: true)
294302

295-
court_topics = build(:case_court_report_context, casa_case: casa_case).court_topics
303+
court_topics = build(:case_court_report_context, casa_case: casa_case, include_empty_topics: true).court_topics
296304

297305
expect(court_topics.keys).to eq(["Question 1", "Question 3"])
298306
end
@@ -301,21 +309,24 @@
301309
topics
302310
create(:contact_topic, question: "Other Org Question")
303311

304-
court_topics = build(:case_court_report_context, casa_case: casa_case).court_topics
312+
court_topics = build(:case_court_report_context, casa_case: casa_case, include_empty_topics: true).court_topics
305313

306314
expect(court_topics.keys).to eq(["Question 1", "Question 2", "Question 3"])
307315
end
308316
end
309317

310318
context "when answers occur in a different order than the topics were created" do
311-
it "orders topics by creation order, not by answer date" do
319+
it "orders topics alphabetically" do
320+
topics[0].update!(question: "Zulu")
321+
topics[1].update!(question: "Alpha")
322+
topics[2].update!(question: "Middle")
312323
create(:contact_topic_answer, case_contact: contacts[0], contact_topic: topics[2], value: "Earliest answer")
313324
create(:contact_topic_answer, case_contact: contacts[1], contact_topic: topics[1], value: "Middle answer")
314325
create(:contact_topic_answer, case_contact: contacts[2], contact_topic: topics[0], value: "Latest answer")
315326

316327
court_topics = build(:case_court_report_context, casa_case: casa_case).court_topics
317328

318-
expect(court_topics.keys).to eq(["Question 1", "Question 2", "Question 3"])
329+
expect(court_topics.keys).to eq(["Alpha", "Middle", "Zulu"])
319330
end
320331
end
321332

@@ -326,7 +337,7 @@
326337

327338
court_topics = build(:case_court_report_context, casa_case: casa_case).court_topics
328339

329-
expect(court_topics.keys).to eq(["Question 1", "Question 2", "Question 3"])
340+
expect(court_topics.keys).to eq(["Question 2"])
330341
expect(court_topics["Question 2"][:answers].pluck(:value)).to eq(["Answer before deactivation"])
331342
end
332343
end
@@ -400,6 +411,20 @@
400411

401412
expect(result).to be_empty
402413
end
414+
415+
it "orders interviewees by contact type group and name" do
416+
casa_case = create(:casa_case)
417+
family_group = create(:contact_type_group, casa_org: casa_case.casa_org, name: "Family")
418+
health_group = create(:contact_type_group, casa_org: casa_case.casa_org, name: "Health")
419+
therapist = create(:contact_type, contact_type_group: health_group, name: "Therapist")
420+
aunt = create(:contact_type, contact_type_group: family_group, name: "Aunt")
421+
counselor = create(:contact_type, contact_type_group: health_group, name: "Counselor")
422+
create(:case_contact, casa_case: casa_case, contact_types: [therapist, aunt, counselor])
423+
424+
result = build(:case_court_report_context, casa_case: casa_case).filtered_interviewees
425+
426+
expect(result.map { |interviewee| interviewee.contact_type.name }).to eq(["Aunt", "Counselor", "Therapist"])
427+
end
403428
end
404429

405430
describe "#context" do

spec/models/case_court_report_spec.rb

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,48 @@
104104
expect(docx_response.paragraphs.map(&:to_s)).to include(/Type A2, Type B2 \(12\/02\/20\): No Answer Provided.*/)
105105
end
106106

107+
it "omits guidance and unanswered topics from real report templates" do
108+
casa_case = create(:casa_case)
109+
answered_topic = create(
110+
:contact_topic,
111+
casa_org: casa_case.casa_org,
112+
question: "Included topic heading",
113+
details: "Included topic guidance"
114+
)
115+
create(
116+
:contact_topic,
117+
casa_org: casa_case.casa_org,
118+
question: "Omitted topic heading",
119+
details: "Omitted topic guidance"
120+
)
121+
case_contact = create(:case_contact, casa_case: casa_case)
122+
create(
123+
:contact_topic_answer,
124+
case_contact: case_contact,
125+
contact_topic: answered_topic,
126+
value: "Included topic answer"
127+
)
128+
template_paths = %w[
129+
default_report_template.docx
130+
montgomery_report_template.docx
131+
prince_george_report_template.docx
132+
].map { |filename| Rails.root.join("app/documents/templates", filename).to_s }
133+
134+
template_paths.each do |template_path|
135+
topics = CaseCourtReportContext.new(case_id: casa_case.id, path_to_template: template_path).court_topics.values
136+
docx_response = generate_doc(full_context.merge(case_topics: topics), template_path)
137+
document_text = (docx_response.paragraphs.map(&:to_s) + table_text(docx_response)).join(" ")
138+
139+
aggregate_failures(File.basename(template_path)) do
140+
expect(document_text).to include("Included topic heading")
141+
expect(document_text).to include("Included topic answer")
142+
expect(document_text).not_to include("Included topic guidance")
143+
expect(document_text).not_to include("Omitted topic heading")
144+
expect(document_text).not_to include("Omitted topic guidance")
145+
end
146+
end
147+
end
148+
107149
context "when there are topics but no answers" do
108150
let(:curr_context) do
109151
full_context[:case_topics] = [

spec/requests/casa_org_spec.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@
1717
end
1818

1919
it { is_expected.to be_successful }
20+
21+
it "orders contact topics alphabetically" do
22+
create(:contact_topic, casa_org: casa_org, question: "Zulu")
23+
create(:contact_topic, casa_org: casa_org, question: "Alpha")
24+
25+
request
26+
27+
expect(assigns(:contact_topics).pluck(:question)).to eq(["Alpha", "Zulu"])
28+
end
2029
end
2130

2231
describe "PATCH /update" do

0 commit comments

Comments
 (0)