Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/controllers/casa_org_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def set_learning_hour_topics
end

def set_contact_topics
@contact_topics = @casa_org.contact_topics.where(soft_delete: false)
@contact_topics = @casa_org.contact_topics.where(soft_delete: false).order(:question)
end

def set_custom_org_links
Expand Down
5 changes: 3 additions & 2 deletions app/controllers/case_court_reports_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def generate
private

def date_range_params
params.permit(:time_zone, case_court_report: %i[start_date end_date])
params.permit(:time_zone, case_court_report: %i[start_date end_date include_empty_topics])
end

def case_params
Expand Down Expand Up @@ -94,7 +94,8 @@ def generate_report_to_string(casa_case, time_range)
path_to_template: template_docx_file.to_path,
time_zone: time_range[:time_zone],
start_date: time_range[:case_court_report][:start_date],
end_date: time_range[:case_court_report][:end_date]
end_date: time_range[:case_court_report][:end_date],
include_empty_topics: time_range[:case_court_report][:include_empty_topics]
}
context = CaseCourtReportContext.new(args).context
court_report = CaseCourtReport.new(path_to_template: template_docx_file.to_path, context: context)
Expand Down
22 changes: 14 additions & 8 deletions app/models/case_court_report_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ def initialize(args = {})
@path_to_template = args[:path_to_template]
@court_date = args[:court_date] || @casa_case.next_court_date
@case_court_orders = args[:case_court_orders] || @casa_case.case_court_orders
@include_empty_topics = ActiveModel::Type::Boolean.new.cast(args[:include_empty_topics])
@date_range = calculate_date_range(args)
end

Expand Down Expand Up @@ -59,9 +60,11 @@ def case_orders(orders)

def filtered_interviewees
CaseContactContactType
.joins(:contact_type, case_contact: :casa_case)
.joins(contact_type: :contact_type_group, case_contact: :casa_case)
.includes(:case_contact, contact_type: :contact_type_group)
.where("case_contacts.casa_case_id": @casa_case.id)
.where("case_contacts.occurred_at": @date_range)
.order("contact_type_groups.name ASC", "contact_types.name ASC", "case_contact_contact_types.id ASC")
end

def case_details
Expand Down Expand Up @@ -92,15 +95,15 @@ def org_address(path_to_template)
# Sample output
#
# expected_topics = {
# "Question 1" => {topic: "Question 1", details: "Details 1", answers: [
# "Question 1" => {topic: "Question 1", details: "", 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: [
# "Question 2" => {topic: "Question 2", details: "", 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: [
# "Question 3" => {topic: "Question 3", details: "", 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"}
# ]}
Expand All @@ -112,18 +115,21 @@ def court_topics
hash[topic.question] = {
answers: answers_by_topic_id.fetch(topic.id, []),
topic: topic.question,
details: topic.details
details: ""
}
end
end

private

def report_topics(answered_topic_ids)
ContactTopic
topics = ContactTopic
.where(casa_org: @casa_case.casa_org, exclude_from_court_report: false)
.merge(ContactTopic.active.or(ContactTopic.where(id: answered_topic_ids)))
.order(:id)
.order(:question)

return topics.where(id: answered_topic_ids) unless @include_empty_topics

topics.merge(ContactTopic.active.or(ContactTopic.where(id: answered_topic_ids)))
end

def court_topic_answers
Expand Down
16 changes: 10 additions & 6 deletions app/services/case_contacts_contact_dates.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ def initialize(case_contact_contact_types)
end

def contact_dates_details
contact_type_names = @case_contact_contact_types.map(&:contact_type).map(&:name).uniq # .sort # TODO sort after refactor
contact_type_names.map do |contact_type_name|
case_contacts = case_contacts_for_type(contact_type_name)
contact_types = @case_contact_contact_types
.map(&:contact_type)
.uniq
.sort_by { |contact_type| [contact_type.contact_type_group.name, contact_type.name] }

contact_types.map do |contact_type|
case_contacts = case_contacts_for_type(contact_type)

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

private

def case_contacts_for_type(contact_type_name)
def case_contacts_for_type(contact_type)
@case_contact_contact_types
.select { |ccct| ccct.contact_type.name == contact_type_name }
.select { |ccct| ccct.contact_type_id == contact_type.id }
.map(&:case_contact)
end

Expand Down
4 changes: 4 additions & 0 deletions app/views/casa_cases/_court_report_modal.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
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" %>
</div>
</div>
<label class="flex items-center gap-2 text-sm font-medium text-slate-700">
<%= form.check_box :include_empty_topics, class: "h-4 w-4 shrink-0 rounded border-slate-300 text-brand-600 focus:ring-brand-500" %>
<span>Include sections with no entries</span>
</label>
<% end %>
<%= render Dialog::FooterComponent.new do %>
<button type="button" data-action="modal#close" class="<%= button_classes(:secondary) %>">Cancel</button>
Expand Down
4 changes: 4 additions & 0 deletions app/views/case_court_reports/_generate_docx.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@
data: {court_report_target: "endDate"}, class: input_class %>
</div>
</div>
<label class="flex items-center gap-2 text-sm font-medium text-slate-700">
<%= form.check_box :include_empty_topics, class: "h-4 w-4 shrink-0 rounded border-slate-300 text-brand-600 focus:ring-brand-500" %>
<span>Include sections with no entries</span>
</label>
<% end %>
<%= render Dialog::FooterComponent.new do %>
<button type="button" data-action="modal#close" class="<%= button_classes(:secondary) %>">Cancel</button>
Expand Down
4 changes: 3 additions & 1 deletion spec/factories/case_court_report_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
start_date { nil }
end_date { nil }
time_zone { nil }
include_empty_topics { false }
end

initialize_with {
Expand All @@ -31,7 +32,8 @@
case_court_orders: case_court_orders,
start_date: start_date,
end_date: end_date,
time_zone: time_zone
time_zone: time_zone,
include_empty_topics: include_empty_topics
)
}
end
Expand Down
43 changes: 34 additions & 9 deletions spec/models/case_court_report_context_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@
expect(court_topics.values).to all(
a_hash_including(
topic: a_kind_of(String),
details: a_kind_of(String),
details: "",
answers: all(
a_hash_including(
date: a_string_matching(/\d{2}\/\d{2}\/\d{2}/),
Expand Down Expand Up @@ -270,29 +270,37 @@
end

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

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

expect(court_topics.keys).to eq(["Question 1", "Question 2", "Question 3"])
expect(court_topics.keys).to eq(["Question 1"])
expect(court_topics["Question 1"][:answers].pluck(:value)).to eq(["Answer 1"])
end

it "includes unanswered topics when requested" do
create(:contact_topic_answer, case_contact: contacts[0], contact_topic: topics[0], value: "Answer 1")

court_topics = build(:case_court_report_context, casa_case: casa_case, include_empty_topics: true).court_topics

expect(court_topics.keys).to eq(["Question 1", "Question 2", "Question 3"])
expect(court_topics["Question 2"][:answers]).to eq([])
expect(court_topics["Question 3"][:answers]).to eq([])
end

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

court_topics = build(:case_court_report_context, casa_case: casa_case).court_topics
court_topics = build(:case_court_report_context, casa_case: casa_case, include_empty_topics: true).court_topics

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

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

court_topics = build(:case_court_report_context, casa_case: casa_case).court_topics
court_topics = build(:case_court_report_context, casa_case: casa_case, include_empty_topics: true).court_topics

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

court_topics = build(:case_court_report_context, casa_case: casa_case).court_topics
court_topics = build(:case_court_report_context, casa_case: casa_case, include_empty_topics: true).court_topics

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

context "when answers occur in a different order than the topics were created" do
it "orders topics by creation order, not by answer date" do
it "orders topics alphabetically" do
topics[0].update!(question: "Zulu")
topics[1].update!(question: "Alpha")
topics[2].update!(question: "Middle")
create(:contact_topic_answer, case_contact: contacts[0], contact_topic: topics[2], value: "Earliest answer")
create(:contact_topic_answer, case_contact: contacts[1], contact_topic: topics[1], value: "Middle answer")
create(:contact_topic_answer, case_contact: contacts[2], contact_topic: topics[0], value: "Latest answer")

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

expect(court_topics.keys).to eq(["Question 1", "Question 2", "Question 3"])
expect(court_topics.keys).to eq(["Alpha", "Middle", "Zulu"])
end
end

Expand All @@ -326,7 +337,7 @@

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

expect(court_topics.keys).to eq(["Question 1", "Question 2", "Question 3"])
expect(court_topics.keys).to eq(["Question 2"])
expect(court_topics["Question 2"][:answers].pluck(:value)).to eq(["Answer before deactivation"])
end
end
Expand Down Expand Up @@ -400,6 +411,20 @@

expect(result).to be_empty
end

it "orders interviewees by contact type group and name" do
casa_case = create(:casa_case)
family_group = create(:contact_type_group, casa_org: casa_case.casa_org, name: "Family")
health_group = create(:contact_type_group, casa_org: casa_case.casa_org, name: "Health")
therapist = create(:contact_type, contact_type_group: health_group, name: "Therapist")
aunt = create(:contact_type, contact_type_group: family_group, name: "Aunt")
counselor = create(:contact_type, contact_type_group: health_group, name: "Counselor")
create(:case_contact, casa_case: casa_case, contact_types: [therapist, aunt, counselor])

result = build(:case_court_report_context, casa_case: casa_case).filtered_interviewees

expect(result.map { |interviewee| interviewee.contact_type.name }).to eq(["Aunt", "Counselor", "Therapist"])
end
end

describe "#context" do
Expand Down
42 changes: 42 additions & 0 deletions spec/models/case_court_report_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,48 @@
expect(docx_response.paragraphs.map(&:to_s)).to include(/Type A2, Type B2 \(12\/02\/20\): No Answer Provided.*/)
end

it "omits guidance and unanswered topics from real report templates" do
casa_case = create(:casa_case)
answered_topic = create(
:contact_topic,
casa_org: casa_case.casa_org,
question: "Included topic heading",
details: "Included topic guidance"
)
create(
:contact_topic,
casa_org: casa_case.casa_org,
question: "Omitted topic heading",
details: "Omitted topic guidance"
)
case_contact = create(:case_contact, casa_case: casa_case)
create(
:contact_topic_answer,
case_contact: case_contact,
contact_topic: answered_topic,
value: "Included topic answer"
)
template_paths = %w[
default_report_template.docx
montgomery_report_template.docx
prince_george_report_template.docx
].map { |filename| Rails.root.join("app/documents/templates", filename).to_s }

template_paths.each do |template_path|
topics = CaseCourtReportContext.new(case_id: casa_case.id, path_to_template: template_path).court_topics.values
docx_response = generate_doc(full_context.merge(case_topics: topics), template_path)
document_text = (docx_response.paragraphs.map(&:to_s) + table_text(docx_response)).join(" ")

aggregate_failures(File.basename(template_path)) do
expect(document_text).to include("Included topic heading")
expect(document_text).to include("Included topic answer")
expect(document_text).not_to include("Included topic guidance")
expect(document_text).not_to include("Omitted topic heading")
expect(document_text).not_to include("Omitted topic guidance")
end
end
end

context "when there are topics but no answers" do
let(:curr_context) do
full_context[:case_topics] = [
Expand Down
9 changes: 9 additions & 0 deletions spec/requests/casa_org_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@
end

it { is_expected.to be_successful }

it "orders contact topics alphabetically" do
create(:contact_topic, casa_org: casa_org, question: "Zulu")
create(:contact_topic, casa_org: casa_org, question: "Alpha")

request

expect(assigns(:contact_topics).pluck(:question)).to eq(["Alpha", "Zulu"])
end
end

describe "PATCH /update" do
Expand Down
13 changes: 13 additions & 0 deletions spec/requests/case_court_reports_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,19 @@
request
end

it "passes the empty-topic option to the report context" do
params[:case_court_report][:include_empty_topics] = "1"
context_builder = instance_double(CaseCourtReportContext, context: {})
report = instance_double(CaseCourtReport, generate_to_string: "report")
allow(CaseCourtReport).to receive(:new).and_return(report)
allow_any_instance_of(CaseCourtReportsController).to receive(:save_report)
expect(CaseCourtReportContext).to receive(:new)
.with(hash_including(include_empty_topics: "1"))
.and_return(context_builder)

expect(request).to have_http_status(:ok)
end

context "when no custom template is set" do
it "sends response as a JSON string", :aggregate_failures do
expect(request.content_type).to eq("application/json; charset=utf-8")
Expand Down
Loading
Loading