diff --git a/app/controllers/all_casa_admins/casa_orgs_controller.rb b/app/controllers/all_casa_admins/casa_orgs_controller.rb index 7cd7510afe..8bd740c3d6 100644 --- a/app/controllers/all_casa_admins/casa_orgs_controller.rb +++ b/app/controllers/all_casa_admins/casa_orgs_controller.rb @@ -12,7 +12,7 @@ def create @casa_org = CasaOrg.new(casa_org_params) if @casa_org.save - @casa_org.generate_contact_types_and_hearing_types + @casa_org.generate_defaults respond_to do |format| format.html do redirect_to all_casa_admins_casa_org_path(@casa_org), diff --git a/app/controllers/case_contacts/form_controller.rb b/app/controllers/case_contacts/form_controller.rb index 3afead4f64..785d07bfb1 100644 --- a/app/controllers/case_contacts/form_controller.rb +++ b/app/controllers/case_contacts/form_controller.rb @@ -113,6 +113,10 @@ def create_additional_case_contacts(case_contact) other_expenses_describe: ae.other_expenses_describe ) end + case_contact.case_contact_topics.each do |cct| + new_case_contact.case_contact_topics << cct.dup + end + new_case_contact.save! end end diff --git a/app/controllers/case_contacts_controller.rb b/app/controllers/case_contacts_controller.rb index b741ab5a72..a5c7f03b41 100644 --- a/app/controllers/case_contacts_controller.rb +++ b/app/controllers/case_contacts_controller.rb @@ -49,6 +49,7 @@ def new end @case_contact = CaseContact.create(creator: current_user, draft_case_ids: draft_case_ids) + @case_contact.create_court_topics(current_organization) redirect_to case_contact_form_path(CaseContact::FORM_STEPS.first, case_contact_id: @case_contact.id) end diff --git a/app/models/casa_org.rb b/app/models/casa_org.rb index c1d22664fb..384fc65279 100644 --- a/app/models/casa_org.rb +++ b/app/models/casa_org.rb @@ -26,6 +26,7 @@ class CasaOrg < ApplicationRecord has_many :case_groups, dependent: :destroy has_one_attached :logo has_one_attached :court_report_template + has_many :case_contact_topics encrypts :twilio_account_sid encrypts :twilio_api_key_sid @@ -85,10 +86,12 @@ def set_slug self.slug = name.parameterize end - def generate_contact_types_and_hearing_types + # generates default: contact types, hearing types, contact topics + def generate_defaults ActiveRecord::Base.transaction do ContactTypeGroup.generate_for_org!(self) HearingType.generate_for_org!(self) + CaseContactTopic.generate_for_org!(self) end end diff --git a/app/models/case_contact.rb b/app/models/case_contact.rb index da624e1777..fd982f5b53 100644 --- a/app/models/case_contact.rb +++ b/app/models/case_contact.rb @@ -20,6 +20,7 @@ class CaseContact < ApplicationRecord }, primary_key: :creator_id, foreign_key: :volunteer_id has_one :supervisor, through: :creator has_many :followups + has_many :case_contact_topics, dependent: :destroy # Draft support requires the casa_case to be nil if the contact is in_progress belongs_to :casa_case, optional: true @@ -49,6 +50,7 @@ def active_or_expenses? accepts_nested_attributes_for :case_contact_contact_type accepts_nested_attributes_for :casa_case + accepts_nested_attributes_for :case_contact_topics, update_only: true, reject_if: :all_blank scope :supervisors, ->(supervisor_ids = nil) { joins(:supervisor_volunteer).where(supervisor_volunteers: {supervisor_id: supervisor_ids}) if supervisor_ids.present? @@ -282,6 +284,14 @@ def self.case_hash_from_cases(cases) contact_made_desc: "Contact made ('yes' first)" } end + + def create_court_topics(casa_org) + casa_org.case_contact_topics.each do |topic| + case_contact_topics << topic.dup + end + + save! + end end # == Schema Information diff --git a/app/models/case_contact_topic.rb b/app/models/case_contact_topic.rb new file mode 100644 index 0000000000..d28342b068 --- /dev/null +++ b/app/models/case_contact_topic.rb @@ -0,0 +1,44 @@ +class CaseContactTopic < ApplicationRecord + CASA_DEFAULT_COURT_TOPICS = Rails.root.join("data", "default_contact_topics.yml") + REQUIRED_ATTRS = %w[title details].freeze + + belongs_to :casa_org + belongs_to :case_contact, optional: true + + validates :title, :details, presence: true + + class << self + def generate_for_org!(casa_org) + default_contact_topics.each do |topic| + filtered_topic = topic.select { |k, _| REQUIRED_ATTRS.include?(k) } + find_or_create_by!(casa_org:, **filtered_topic) + end + end + + private + + def default_contact_topics + YAML.load_file(CASA_DEFAULT_COURT_TOPICS) + end + end +end + +# == Schema Information +# +# Table name: case_contact_topics +# +# id :bigint not null, primary key +# active :boolean default(FALSE) +# answer :string +# details :string +# title :string +# created_at :datetime not null +# updated_at :datetime not null +# casa_org_id :bigint not null +# case_contact_id :bigint +# +# Indexes +# +# index_case_contact_topics_on_casa_org_id (casa_org_id) +# index_case_contact_topics_on_case_contact_id (case_contact_id) +# diff --git a/app/values/case_contact_parameters.rb b/app/values/case_contact_parameters.rb index ed3cdc5e6a..f18a2f5eda 100644 --- a/app/values/case_contact_parameters.rb +++ b/app/values/case_contact_parameters.rb @@ -14,7 +14,8 @@ def initialize(params) :volunteer_address, draft_case_ids: [], case_contact_contact_type_attributes: [:contact_type_id], - additional_expenses_attributes: [:id, :other_expense_amount, :other_expenses_describe] + case_contact_topics_attributes: %i[case_contact_topic_id id answer active], + additional_expenses_attributes: %i[id other_expense_amount other_expenses_describe] ) if params.dig(:case_contact, :duration_minutes) new_params[:duration_minutes] = convert_duration_minutes(params) diff --git a/data/default_contact_topics.yml b/data/default_contact_topics.yml new file mode 100644 index 0000000000..a33bc1e76c --- /dev/null +++ b/data/default_contact_topics.yml @@ -0,0 +1,36 @@ +- title: "Background information" + details: + "a) When did the family first come into contact with the Department of Social Services or Department of Juvenile Justice – how many times? + b) Tell the history of their involvement with the department and any facts about their life that could help determine the need for placement and/or services. + c) Discuss the child’s history – behavior problems, educational history, medical history, psychological history (any hospitalizations, previous counseling, etc.) + d) If child has been placed previously give a history of the child’s placements (placed with different parents, relatives, DSS, etc)." +- title: "Current situation" + details: + "a) When did the family first come into contact with the Department of Social Services or Department of Juvenile Justice – how many times? + b) Tell the history of their involvement with the department and any facts about their life that could help determine the need for placement and/or services. + c) Discuss the child’s history – behavior problems, educational history, medical history, psychological history (any hospitalizations, previous counseling, etc.) + d) If child has been placed previously give a history of the child’s placements (placed with different parents, relatives, DSS, etc)." +- title: "Education, vocation, or daycare" + details: + "a) When did the family first come into contact with the Department of Social Services or Department of Juvenile Justice – how many times? + b) Tell the history of their involvement with the department and any facts about their life that could help determine the need for placement and/or services. + c) Discuss the child’s history – behavior problems, educational history, medical history, psychological history (any hospitalizations, previous counseling, etc.) + d) If child has been placed previously give a history of the child’s placements (placed with different parents, relatives, DSS, etc)." +- title: "Health and mental health" + details: + "a) When did the family first come into contact with the Department of Social Services or Department of Juvenile Justice – how many times? + b) Tell the history of their involvement with the department and any facts about their life that could help determine the need for placement and/or services. + c) Discuss the child’s history – behavior problems, educational history, medical history, psychological history (any hospitalizations, previous counseling, etc.) + d) If child has been placed previously give a history of the child’s placements (placed with different parents, relatives, DSS, etc)." +- title: "Family and community connections" + details: + "a) When did the family first come into contact with the Department of Social Services or Department of Juvenile Justice – how many times? + b) Tell the history of their involvement with the department and any facts about their life that could help determine the need for placement and/or services. + c) Discuss the child’s history – behavior problems, educational history, medical history, psychological history (any hospitalizations, previous counseling, etc.) + d) If child has been placed previously give a history of the child’s placements (placed with different parents, relatives, DSS, etc)." +- title: "Child’s strengths" + details: + "a) When did the family first come into contact with the Department of Social Services or Department of Juvenile Justice – how many times? + b) Tell the history of their involvement with the department and any facts about their life that could help determine the need for placement and/or services. + c) Discuss the child’s history – behavior problems, educational history, medical history, psychological history (any hospitalizations, previous counseling, etc.) + d) If child has been placed previously give a history of the child’s placements (placed with different parents, relatives, DSS, etc)." diff --git a/db/migrate/20240128015203_create_case_contact_topics.rb b/db/migrate/20240128015203_create_case_contact_topics.rb new file mode 100644 index 0000000000..a7c55d6b07 --- /dev/null +++ b/db/migrate/20240128015203_create_case_contact_topics.rb @@ -0,0 +1,14 @@ +class CreateCaseContactTopics < ActiveRecord::Migration[7.0] + def change + create_table :case_contact_topics do |t| + t.string :title + t.string :details + t.string :answer + t.boolean :active, default: false + t.references :casa_org, null: false + t.references :case_contact, null: true + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 6f959d77a4..e30253c951 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_11_25_150721) do +ActiveRecord::Schema[7.1].define(version: 2024_01_28_015203) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -184,6 +184,19 @@ t.index ["contact_type_id"], name: "index_case_contact_contact_types_on_contact_type_id" end + create_table "case_contact_topics", force: :cascade do |t| + t.string "title" + t.string "details" + t.string "answer" + t.boolean "active", default: false + t.bigint "casa_org_id", null: false + t.bigint "case_contact_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["casa_org_id"], name: "index_case_contact_topics_on_casa_org_id" + t.index ["case_contact_id"], name: "index_case_contact_topics_on_case_contact_id" + end + create_table "case_contacts", force: :cascade do |t| t.bigint "creator_id", null: false t.bigint "casa_case_id" @@ -395,6 +408,7 @@ create_table "learning_hours", force: :cascade do |t| t.bigint "user_id", null: false + t.integer "learning_type", default: 5 t.string "name", null: false t.integer "duration_minutes", null: false t.integer "duration_hours", null: false diff --git a/db/seeds.rb b/db/seeds.rb index 1751534412..f42b48ad84 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -12,6 +12,7 @@ require_relative "../lib/tasks/data_post_processors/case_contact_populator" require_relative "../lib/tasks/data_post_processors/contact_type_populator" require_relative "../lib/tasks/data_post_processors/sms_notification_event_populator" +require_relative "../lib/tasks/data_post_processors/contact_topic_populator" class SeederMain attr_reader :db_populator, :rng @@ -76,6 +77,7 @@ def active_record_classes def post_process_data ContactTypePopulator.populate CaseContactPopulator.populate + ContactTopicPopulator.populate end def get_seed_specification @@ -97,7 +99,7 @@ def get_seed_specification def report_object_counts log "\nRecords written to the DB:\n\nCount Class Name\n----- ----------\n\n" active_record_classes.each do |klass| - log "%5d %s" % [klass.count, klass.name] + log format("%5d %s", klass.count, klass.name) end log "\n\nVolunteers, Supervisors and CasaAdmins are types of Users" end diff --git a/lib/tasks/data_post_processors/contact_topic_populator.rb b/lib/tasks/data_post_processors/contact_topic_populator.rb new file mode 100644 index 0000000000..17dcc9c9a9 --- /dev/null +++ b/lib/tasks/data_post_processors/contact_topic_populator.rb @@ -0,0 +1,7 @@ +module ContactTopicPopulator + def self.populate + CasaOrg.all.each do |casa_org| + CaseContactTopic.generate_for_org!(casa_org) + end + end +end diff --git a/spec/factories/case_contact_topics.rb b/spec/factories/case_contact_topics.rb new file mode 100644 index 0000000000..fee7ed96db --- /dev/null +++ b/spec/factories/case_contact_topics.rb @@ -0,0 +1,8 @@ +FactoryBot.define do + factory :case_contact_topic do + title { Faker::Lorem.sentence } + details { Faker::Lorem.paragraph } + casa_org + case_contact + end +end diff --git a/spec/models/casa_org_spec.rb b/spec/models/casa_org_spec.rb index fce9d87da2..c388d21d35 100644 --- a/spec/models/casa_org_spec.rb +++ b/spec/models/casa_org_spec.rb @@ -10,6 +10,7 @@ it { is_expected.to have_many(:case_assignments).through(:users) } it { is_expected.to have_one_attached(:logo) } it { is_expected.to have_one_attached(:court_report_template) } + it { is_expected.to have_many(:case_contact_topics) } it "has unique name" do org = create(:casa_org) @@ -86,10 +87,15 @@ it { is_expected.to eq 15 } end - describe "generate_contact_types_and_hearing_types" do + describe "generate_defaults" do let(:org) { create(:casa_org) } + let(:fake_topics) { [{"title" => "Test Title", "details" => "Test Details"}] } - before { org.generate_contact_types_and_hearing_types } + before do + default_topics_file = Rails.root.join("data", "default_contact_topics.yml") + allow(YAML).to receive(:load_file).with(default_topics_file).and_return(fake_topics) + org.generate_defaults + end describe "generates default contact type groups" do let(:groups) { ContactTypeGroup.where(casa_org: org).joins(:contact_types).pluck(:name, "contact_types.name").sort } @@ -128,52 +134,61 @@ end end - describe "mileage rate for a given date" do - let(:casa_org) { build(:casa_org) } + describe "generates default contact types" do + let(:contact_topics) { CaseContactTopic.where(casa_org: org).pluck(:title) } - describe "with a casa org with no rates" do - it "is nil" do - expect(casa_org.mileage_rate_for_given_date(Date.today)).to be_nil - end + it "matches default contact topics" do + expected = fake_topics.map { |topic| topic["title"] } + expect(contact_topics).to include(*expected) end + end + end - describe "with a casa org with inactive dates" do - let!(:mileage_rates) do - [ - create(:mileage_rate, casa_org: casa_org, effective_date: 10.days.ago, is_active: false), - create(:mileage_rate, casa_org: casa_org, effective_date: 3.days.ago, is_active: false) - ] - end - - it "is nil" do - expect(casa_org.mileage_rates.count).to eq 2 - expect(casa_org.mileage_rate_for_given_date(Date.today)).to be_nil - end + describe "mileage rate for a given date" do + let(:casa_org) { build(:casa_org) } + + describe "with a casa org with no rates" do + it "is nil" do + expect(casa_org.mileage_rate_for_given_date(Date.today)).to be_nil end + end - describe "with active dates in the future" do - let!(:mileage_rate) { create(:mileage_rate, casa_org: casa_org, effective_date: 3.days.from_now) } + describe "with a casa org with inactive dates" do + let!(:mileage_rates) do + [ + create(:mileage_rate, casa_org:, effective_date: 10.days.ago, is_active: false), + create(:mileage_rate, casa_org:, effective_date: 3.days.ago, is_active: false) + ] + end + + it "is nil" do + expect(casa_org.mileage_rates.count).to eq 2 + expect(casa_org.mileage_rate_for_given_date(Date.today)).to be_nil + end + end + + describe "with active dates in the future" do + let!(:mileage_rate) { create(:mileage_rate, casa_org:, effective_date: 3.days.from_now) } + + it "is nil" do + expect(casa_org.mileage_rates.count).to eq 1 + expect(casa_org.mileage_rate_for_given_date(Date.today)).to be_nil + end + end - it "is nil" do - expect(casa_org.mileage_rates.count).to eq 1 - expect(casa_org.mileage_rate_for_given_date(Date.today)).to be_nil - end + describe "with active dates in the past" do + let!(:mileage_rates) do + [ + create(:mileage_rate, casa_org:, amount: 4.50, effective_date: 20.days.ago), + create(:mileage_rate, casa_org:, amount: 5.50, effective_date: 10.days.ago), + create(:mileage_rate, casa_org:, amount: 6.50, effective_date: 3.days.ago) + ] end - describe "with active dates in the past" do - let!(:mileage_rates) do - [ - create(:mileage_rate, casa_org: casa_org, amount: 4.50, effective_date: 20.days.ago), - create(:mileage_rate, casa_org: casa_org, amount: 5.50, effective_date: 10.days.ago), - create(:mileage_rate, casa_org: casa_org, amount: 6.50, effective_date: 3.days.ago) - ] - end - - it "uses the most recent date" do - expect(casa_org.mileage_rate_for_given_date(12.days.ago.to_date)).to eq 4.50 - expect(casa_org.mileage_rate_for_given_date(5.days.ago.to_date)).to eq 5.50 - expect(casa_org.mileage_rate_for_given_date(Date.today)).to eq 6.50 - end + it "uses the most recent date" do + expect(casa_org.mileage_rate_for_given_date(12.days.ago.to_date)).to eq 4.50 + expect(casa_org.mileage_rate_for_given_date(5.days.ago.to_date)).to eq 5.50 + expect(casa_org.mileage_rate_for_given_date(Date.today)).to eq 6.50 end end end diff --git a/spec/models/case_contact_spec.rb b/spec/models/case_contact_spec.rb index 8e1508ce8b..1cb5f79973 100644 --- a/spec/models/case_contact_spec.rb +++ b/spec/models/case_contact_spec.rb @@ -3,6 +3,7 @@ RSpec.describe CaseContact, type: :model do it { is_expected.to validate_numericality_of(:miles_driven).is_less_than 10_000 } it { is_expected.to validate_numericality_of(:miles_driven).is_greater_than_or_equal_to 0 } + it { is_expected.to have_many(:case_contact_topics).dependent(:destroy) } context "status is active" do it "belongs to a creator" do @@ -73,6 +74,21 @@ end end + describe "#create_court_topics" do + let(:case_contact_topics) { create_list(:case_contact_topic, 2) } + let(:org) { create(:casa_org, case_contact_topics:) } + let(:casa_case) { create(:casa_case, casa_org: org) } + let(:case_contact) { create(:case_contact, casa_case:) } + + it "creates case contact topics after creation" do + org + + expect { + case_contact.create_court_topics(org) + }.to change(CaseContactTopic, :count).from(2).to(4) + end + end + context "status is started" do it "ignores some validations" do case_contact = build_stubbed(:case_contact, :started_status, want_driving_reimbursement: true) diff --git a/spec/models/case_contact_topic_spec.rb b/spec/models/case_contact_topic_spec.rb new file mode 100644 index 0000000000..fd4bc04200 --- /dev/null +++ b/spec/models/case_contact_topic_spec.rb @@ -0,0 +1,58 @@ +require "rails_helper" + +RSpec.describe CaseContactTopic, type: :model do + subject { build_stubbed(:case_contact_topic) } + let(:case_contact) { build_stubbed(:case_contact) } + + describe "validations" do + it { is_expected.to belong_to(:casa_org) } + it { is_expected.to belong_to(:case_contact).optional } + it { is_expected.to validate_presence_of(:title) } + it { is_expected.to validate_presence_of(:details) } + end + + describe "generate for org" do + let(:org) { create(:casa_org) } + let(:fake_topics) { [{"title" => "Test Title", "details" => "Test Details"}] } + + describe "generate_contact_topics" do + before do + default_topics_file = Rails.root.join("data", "default_contact_topics.yml") + allow(YAML).to receive(:load_file).with(default_topics_file).and_return(fake_topics) + end + + it "creates contact topics from a YAML file" do + expect { CaseContactTopic.generate_for_org!(org) }.to change { org.case_contact_topics.count }.by(1) + + created_topic = org.case_contact_topics.first + expect(created_topic.title).to eq(fake_topics.first["title"]) + expect(created_topic.details).to eq(fake_topics.first["details"]) + end + + it "does not create if there are no topics in the YAML file" do + allow(YAML).to receive(:load_file).and_return([]) + expect { CaseContactTopic.generate_for_org!(org) }.not_to(change { org.case_contact_topics.count }) + end + + it "generates from parameter" do + topics = fake_topics.push({"title" => "a", "details" => "a"}) + expect { CaseContactTopic.generate_for_org!(org) }.to change { org.case_contact_topics.count }.by(2) + + created_topic = org.case_contact_topics.first + expect(created_topic.title).to eq(topics.first["title"]) + expect(created_topic.details).to eq(topics.first["details"]) + end + + context "when defaults are invalid" do + it "fails if not all required attrs are present " do + fake_topics.first["title"] = nil + expect { CaseContactTopic.generate_for_org!(org) }.to raise_error(ActiveRecord::RecordInvalid) + end + it "creates if needed fields all persent" do + fake_topics.first["invalid_field"] = "invalid" + expect { CaseContactTopic.generate_for_org!(org) }.to change { org.case_contact_topics.count }.by(1) + end + end + end + end +end diff --git a/spec/requests/all_casa_admins/casa_orgs_spec.rb b/spec/requests/all_casa_admins/casa_orgs_spec.rb index b5fbca00d5..b840856555 100644 --- a/spec/requests/all_casa_admins/casa_orgs_spec.rb +++ b/spec/requests/all_casa_admins/casa_orgs_spec.rb @@ -47,11 +47,26 @@ {casa_org: {name: "New Org", display_name: "New org display", address: "29207 Weimann Canyon, New Andrew, PA 40510-7416"}} end + let(:contact_topics) { build_list(:case_contact_topic, 3).map(&:as_json) } + + before do + allow(CaseContactTopic).to receive(:default_contact_topics).and_return(contact_topics) + end it "creates a new CASA org" do expect { post_create }.to change(CasaOrg, :count).by(1) end + it "generates correct defaults during creation" do + expect { post_create }.to change(CaseContactTopic, :count).by(3) + + casa_org = CasaOrg.last + expect(casa_org.case_contact_topics.pluck(:title)).to eq contact_topics.map {|t| t["title"]} + expect(casa_org.case_contact_topics.pluck(:details)).to eq contact_topics.map {|t| t["details"]} + expect(casa_org.case_contact_topics.pluck(:active)).to be_all false + expect(casa_org.case_contact_topics.pluck(:answer)).to be_all nil + end + it "redirects to CASA org show page, with notice flash", :aggregate_failures do post_create diff --git a/spec/requests/case_contacts/form_spec.rb b/spec/requests/case_contacts/form_spec.rb index c3d0d99065..38de488332 100644 --- a/spec/requests/case_contacts/form_spec.rb +++ b/spec/requests/case_contacts/form_spec.rb @@ -57,11 +57,14 @@ expect(page).not_to include(*contact_types_b.pluck(:name)) end end + + # TODO: Test that contact topics are shown end end describe "PATCH /update" do let!(:casa_case) { create(:casa_case, casa_org: organization) } + let!(:case_contact) { create(:case_contact, :details_status, casa_case:) } let(:advance_form) { true } let(:params) { {case_contact: attributes} } @@ -72,7 +75,8 @@ end context "submitting details step" do - let!(:case_contact) { create(:case_contact, :started_status, creator: creator) } + let!(:case_contact) { create(:case_contact, :started_status, creator: creator, case_contact_topics:) } + let(:case_contact_topics) { build_list(:case_contact_topic, 3, active: false) } let(:step) { :details } let!(:contact_type_group_b) { create(:contact_type_group, casa_org: organization, name: "B") } let!(:contact_types_b) do @@ -98,7 +102,8 @@ duration_minutes: 50, contact_made: true, medium_type: CaseContact::CONTACT_MEDIUMS.second, - case_contact_contact_type_attributes: contact_type_attributes + case_contact_contact_type_attributes: contact_type_attributes, + case_contact_topics_attributes: contact_topic_attributes } end let(:contact_type_attributes) do @@ -108,6 +113,12 @@ } end + let(:contact_topic_attributes) do + case_contact_topics.map.with_index do |t, i| + [i.to_s, t.attributes.merge("active" => true, "answer" => "test")] + end.to_h + end + it "with valid attributes updates the requested case_contact" do request case_contact.reload @@ -117,6 +128,19 @@ expect(case_contact.medium_type).to eq(CaseContact::CONTACT_MEDIUMS.second) end + it "updates only active and details field for contact topics" do + expected_titles = case_contact_topics.pluck(:title) + expected_details = case_contact_topics.pluck(:details) + + request + case_contact.reload + + expect(case_contact.case_contact_topics.pluck(:title)).to eq expected_titles + expect(case_contact.case_contact_topics.pluck(:details)).to eq expected_details + expect(case_contact.case_contact_topics.pluck(:answer)).to be_all "test" + expect(case_contact.case_contact_topics.pluck(:active)).to be_all true + end + context "contact types" do it "attaches contact types" do request @@ -163,6 +187,51 @@ end end + context "submitting notes step: contact topics" do + let!(:case_contact) { create(:case_contact, :details_status, creator: creator, case_contact_topics:) } + # let!(:case_contact) { create(:case_contact, :details_status, casa_case:, case_contact_topics:) } + let(:case_contact_topics) { create_list(:case_contact_topic, 3, active: false) } + let(:contact_topic_attributes) do + case_contact_topics.map.with_index do |t, i| + [i.to_s, t.attributes.merge("active" => true, "answer" => "test")] + end.to_h + end + let(:step) { :notes } + let(:attributes) do + {case_contact_topics_attributes: contact_topic_attributes} + end + + context "with valid contact topic answers" do + context "when submitting via button" do + it "updates the requested case_contact" do + request + case_contact.reload + + expect(case_contact.case_contact_topics.pluck(:answer)).to be_all "test" + expect(case_contact.case_contact_topics.pluck(:active)).to be_all true + end + end + + context "when autosaving" do + subject(:request) do + patch "/case_contacts/#{case_contact.id}/form/#{step}", params:, as: :json + + response + end + + it "updates the requested case_contact" do + request + case_contact.reload + + expect(case_contact.case_contact_topics.pluck(:answer)).to be_all "test" + expect(case_contact.case_contact_topics.pluck(:active)).to be_all true + end + + it { is_expected.to have_http_status(:success) } + end + end + end + context "submitting notes step" do let!(:case_contact) { create(:case_contact, :details_status, creator: creator) } let(:step) { :notes } @@ -215,7 +284,13 @@ end context "submitting expenses step" do - let!(:case_contact) { create(:case_contact, :notes_status, draft_case_ids: [casa_case.id], creator: creator) } + let!(:case_contact) { create(:case_contact, :notes_status, draft_case_ids: [casa_case.id], creator: creator, case_contact_topics:) } + let(:case_contact_topics) { build_list(:case_contact_topic, 3, active: false) } + let(:contact_topic_attributes) do + case_contact_topics.map.with_index do |t, i| + [i.to_s, t.attributes.merge("active" => true, "answer" => "test")] + end.to_h + end let(:additional_expenses) do { "0" => {other_expense_amount: 50, other_expenses_describe: "meal"}, @@ -230,7 +305,8 @@ want_driving_reimbursement: true, miles_driven: 60, volunteer_address: "123 str", - additional_expenses_attributes: additional_expenses + additional_expenses_attributes: additional_expenses, + case_contact_topics_attributes: contact_topic_attributes } end @@ -245,6 +321,9 @@ expect(case_contact.additional_expenses.first.other_expenses_describe).to eq "meal" expect(case_contact.additional_expenses.last.other_expense_amount).to eq 100 expect(case_contact.additional_expenses.last.other_expenses_describe).to eq "hotel" + + expect(case_contact.case_contact_topics.pluck(:active)).to be_all true + expect(case_contact.case_contact_topics.pluck(:answer)).to be_all "test" end it "sets the case_contact's status to active" do @@ -288,7 +367,7 @@ context "with multiple cases selected" do let!(:other_casa_case) { create(:casa_case, casa_org: organization) } - let!(:case_contact) { create(:case_contact, :notes_status, draft_case_ids: [casa_case.id, other_casa_case.id], creator: admin) } + let!(:case_contact) { create(:case_contact, :notes_status, draft_case_ids: [casa_case.id, other_casa_case.id], creator: admin, case_contact_topics:) } it "creates a copy of the draft for each case" do expect { @@ -299,6 +378,17 @@ expect(CaseContact.last.status).to eq "active" end + it "sets contact_topics for all cases" do + expected_titles = case_contact_topics.pluck(:title) + expected_details = case_contact_topics.pluck(:details) + initial_ids = case_contact_topics.pluck(:id) + + expect { request }.to change(CaseContactTopic, :count).by(3) + expect(CaseContact.last.case_contact_topics.pluck(:title)).to eq expected_titles + expect(CaseContact.last.case_contact_topics.pluck(:details)).to eq expected_details + expect(CaseContact.last.case_contact_topics.pluck(:id)).to_not eq initial_ids + end + it "sets the draft_case_ids of the draft to only the first case" do expect(case_contact.draft_case_ids.count).to eq 2 request diff --git a/spec/requests/case_contacts_spec.rb b/spec/requests/case_contacts_spec.rb index e72425a6e0..d7f1def230 100644 --- a/spec/requests/case_contacts_spec.rb +++ b/spec/requests/case_contacts_spec.rb @@ -51,6 +51,20 @@ request }.to change(CaseContact, :count).by(1) end + + context "when current org has contact topics" do + let(:case_contact_topics) { build_list(:case_contact_topic, 3) } + let(:organization) { create(:casa_org, case_contact_topics:) } + + it "should set contact topics for new case contact to org topics" do + expect { request }.to change(CaseContactTopic, :count).by(3) + + want_topics = case_contact_topics.map(&:title) + got_topics = CaseContact.last.case_contact_topics.pluck(:title) + + expect(got_topics).to eq(want_topics) + end + end end describe "GET /edit" do diff --git a/spec/values/case_contact_parameters_spec.rb b/spec/values/case_contact_parameters_spec.rb index 9a25c59520..7e69a5dd7f 100644 --- a/spec/values/case_contact_parameters_spec.rb +++ b/spec/values/case_contact_parameters_spec.rb @@ -2,6 +2,7 @@ RSpec.describe CaseContactParameters do subject { described_class.new(params) } + let(:params) { ActionController::Parameters.new( case_contact: ActionController::Parameters.new( @@ -13,10 +14,14 @@ miles_driven: "123", want_driving_reimbursement: "want_driving_reimbursement", notes: "notes", - case_contact_contact_type_attributes: [:contact_type_id] + case_contact_contact_type_attributes: [:contact_type_id], + case_contact_topics_attributes: contact_topics_attributes ) ) } + let(:contact_topics_attributes) do + {"0" => {"case_contact_topic_id" => 1, "id" => 3, "active" => true, "answer" => "test", "title" => "false"}} + end it "returns data" do expect(subject["duration_minutes"]).to eq(62) @@ -27,5 +32,8 @@ expect(subject["want_driving_reimbursement"]).to eq("want_driving_reimbursement") expect(subject["notes"]).to eq("notes") expect(subject["case_contact_contact_type_attributes"]).to eq([]) + + expected_attrs = contact_topics_attributes["0"].except("title") + expect(subject["case_contact_topics_attributes"]["0"].to_h).to eq(expected_attrs) end end