diff --git a/app/models/additional_expense.rb b/app/models/additional_expense.rb index 6ed7f2567e..3719dabff2 100644 --- a/app/models/additional_expense.rb +++ b/app/models/additional_expense.rb @@ -1,7 +1,9 @@ class AdditionalExpense < ApplicationRecord belongs_to :case_contact has_one :casa_case, through: :case_contact - has_one :casa_org, through: :casa_case + has_one :casa_org, through: :case_contact + # case_contact.casa_org may be nil for draft contacts, use for fallback: + has_one :contact_creator_casa_org, through: :case_contact, source: :creator_casa_org validates :other_expenses_describe, presence: true, if: :describe_required? diff --git a/app/models/case_contact.rb b/app/models/case_contact.rb index bd4fe7f415..8d23877ad4 100644 --- a/app/models/case_contact.rb +++ b/app/models/case_contact.rb @@ -32,9 +32,11 @@ class CaseContact < ApplicationRecord has_one :supervisor, through: :creator has_many :followups - # Draft support requires the casa_case to be nil if the contact is in_progress + # Draft casa_case_id is nil until active belongs_to :casa_case, optional: true has_one :casa_org, through: :casa_case + # Use creator_casa_org as fallback org relationship for drafts + has_one :creator_casa_org, through: :creator, source: :casa_org validates :casa_case_id, presence: true, if: :active? validates :draft_case_ids, presence: {message: :must_be_selected}, if: :active_or_details? diff --git a/app/models/contact_topic_answer.rb b/app/models/contact_topic_answer.rb index 2a1928040e..81c886f7d7 100644 --- a/app/models/contact_topic_answer.rb +++ b/app/models/contact_topic_answer.rb @@ -3,7 +3,9 @@ class ContactTopicAnswer < ApplicationRecord belongs_to :contact_topic has_one :casa_case, through: :case_contact - has_one :casa_org, through: :casa_case + has_one :casa_org, through: :case_contact + # case_contact.casa_org may be nil for draft contacts, use for fallback: + has_one :contact_creator_casa_org, through: :case_contact, source: :creator_casa_org validates :selected, inclusion: [true, false] diff --git a/app/policies/additional_expense_policy.rb b/app/policies/additional_expense_policy.rb index 921fa088c9..6476cb78ae 100644 --- a/app/policies/additional_expense_policy.rb +++ b/app/policies/additional_expense_policy.rb @@ -24,4 +24,11 @@ def create? end alias_method :destroy?, :create? + + private + + def same_org? + record_org = record.casa_org || record.contact_creator_casa_org + user&.casa_org == record_org + end end diff --git a/app/policies/case_contact_policy.rb b/app/policies/case_contact_policy.rb index 9df9ce29d3..c66c464abe 100644 --- a/app/policies/case_contact_policy.rb +++ b/app/policies/case_contact_policy.rb @@ -53,4 +53,9 @@ def is_draft? def is_creator? record.creator == user end + + def same_org? + record_org = record.casa_org || record.creator_casa_org + user&.casa_org == record_org + end end diff --git a/app/policies/contact_topic_answer_policy.rb b/app/policies/contact_topic_answer_policy.rb index 1c0ae4f444..dc35cd0b6d 100644 --- a/app/policies/contact_topic_answer_policy.rb +++ b/app/policies/contact_topic_answer_policy.rb @@ -3,7 +3,7 @@ class Scope < ApplicationPolicy::Scope def resolve case user when CasaAdmin, Supervisor - scope.joins([:case_contact, :casa_case]).where(casa_case: {casa_org_id: user.casa_org&.id}) + scope.unscoped.joins(:contact_topic).where(contact_topic: {casa_org: user&.casa_org}) when Volunteer scope.where(case_contact: user.case_contacts) else @@ -24,4 +24,11 @@ def create? end alias_method :destroy?, :create? + + private + + def same_org? + record_org = record.casa_org || record.contact_creator_casa_org + user&.casa_org == record_org + end end diff --git a/spec/lib/tasks/data_post_processors/case_contact_populator_spec.rb b/spec/lib/tasks/data_post_processors/case_contact_populator_spec.rb index f678c555cc..92dd6f62b8 100644 --- a/spec/lib/tasks/data_post_processors/case_contact_populator_spec.rb +++ b/spec/lib/tasks/data_post_processors/case_contact_populator_spec.rb @@ -15,7 +15,7 @@ end it "does nothing if there are no contact types" do - case_contact = create(:case_contact, contact_types: [], status: 'started') + case_contact = create(:case_contact, contact_types: [], status: "started") described_class.populate diff --git a/spec/models/additional_expense_spec.rb b/spec/models/additional_expense_spec.rb index a3e45a48e2..c259edc33e 100644 --- a/spec/models/additional_expense_spec.rb +++ b/spec/models/additional_expense_spec.rb @@ -3,7 +3,8 @@ RSpec.describe AdditionalExpense, type: :model do it { is_expected.to belong_to(:case_contact) } it { is_expected.to have_one(:casa_case).through(:case_contact) } - it { is_expected.to have_one(:casa_org).through(:casa_case) } + it { is_expected.to have_one(:casa_org).through(:case_contact) } + it { is_expected.to have_one(:contact_creator_casa_org).through(:case_contact) } describe "validations" do let(:case_contact) { build_stubbed :case_contact } diff --git a/spec/models/case_contact_spec.rb b/spec/models/case_contact_spec.rb index af43e8a7c8..f9c3d57578 100644 --- a/spec/models/case_contact_spec.rb +++ b/spec/models/case_contact_spec.rb @@ -4,6 +4,10 @@ it { is_expected.to have_many(:contact_topic_answers).dependent(:destroy) } 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 belong_to(:creator) } + it { is_expected.to have_one(:casa_org).through(:casa_case) } + it { is_expected.to have_one(:creator_casa_org).through(:creator) } + context "status is active" do it "belongs to a creator" do @@ -584,7 +588,7 @@ end it "returns false if creator's supervisor is inactive" do - supervisor.update(active: false) + supervisor.update!(active: false) expect(case_contact.should_send_reimbursement_email?).to be false end end diff --git a/spec/models/contact_topic_answer_spec.rb b/spec/models/contact_topic_answer_spec.rb index df65741ed7..49df9c822f 100644 --- a/spec/models/contact_topic_answer_spec.rb +++ b/spec/models/contact_topic_answer_spec.rb @@ -3,6 +3,7 @@ RSpec.describe ContactTopicAnswer, type: :model do it { should belong_to(:case_contact) } it { should belong_to(:contact_topic) } + it { is_expected.to have_one(:contact_creator_casa_org).through(:case_contact) } it "can hold more than 255 characters" do expect { diff --git a/spec/policies/contact_topic_answer_policy_spec.rb b/spec/policies/contact_topic_answer_policy_spec.rb index 7cd35d08ed..8fcf0864a1 100644 --- a/spec/policies/contact_topic_answer_policy_spec.rb +++ b/spec/policies/contact_topic_answer_policy_spec.rb @@ -9,7 +9,7 @@ let(:contact_topic) { create :contact_topic, casa_org: } let(:casa_case) { volunteer.casa_cases.first } - let(:case_contact) { create :case_contact, casa_case:, creator: volunteer } + let(:case_contact) { create :case_contact, :started_status, creator: volunteer } let!(:contact_topic_answer) { create :contact_topic_answer, contact_topic:, case_contact: } let(:same_org_volunteer) { create :volunteer, casa_org: } @@ -91,6 +91,7 @@ let(:user) { supervisor } it { is_expected.to include(contact_topic_answer) } + it { is_expected.to include(same_org_other_volunteer_contact_topic_answer) } it { is_expected.not_to include(other_org_contact_topic_answer) } end @@ -98,6 +99,7 @@ let(:user) { casa_admin } it { is_expected.to include(contact_topic_answer) } + it { is_expected.to include(same_org_other_volunteer_contact_topic_answer) } it { is_expected.not_to include(other_org_contact_topic_answer) } end @@ -105,6 +107,7 @@ let(:user) { all_casa_admin } it { is_expected.not_to include(contact_topic_answer) } + it { is_expected.not_to include(same_org_other_volunteer_contact_topic_answer) } it { is_expected.not_to include(other_org_contact_topic_answer) } end end diff --git a/spec/system/case_contacts/edit_spec.rb b/spec/system/case_contacts/edit_spec.rb index 1a17ae720a..e0c4a56af9 100644 --- a/spec/system/case_contacts/edit_spec.rb +++ b/spec/system/case_contacts/edit_spec.rb @@ -37,9 +37,6 @@ end it "admin successfully edits case contact with mileage reimbursement" do - casa_case = create(:casa_case, :with_one_case_assignment, casa_org: organization) - case_contact = create(:case_contact, duration_minutes: 105, casa_case: casa_case) - visit edit_case_contact_path(case_contact) complete_details_page(case_numbers: [], contact_types: [], contact_made: true, medium: "In Person", hours: 1, minutes: 45, occurred_on: "04/04/2020") @@ -49,7 +46,8 @@ click_on "Submit" case_contact.reload expect(page).to have_text "Case contact created at #{case_contact.created_at.strftime("%-I:%-M %p on %m-%e-%Y")}, was successfully updated." - expect(case_contact.casa_case.volunteers[0].address.content).to eq "123 str" + expect(case_contact.casa_case.volunteers[0]).to eq volunteer + expect(volunteer.address&.content).to eq "123 str" expect(case_contact.casa_case_id).to eq casa_case.id expect(case_contact.duration_minutes).to eq 105 expect(case_contact.medium_type).to eq "in-person" diff --git a/spec/system/case_contacts/new_spec.rb b/spec/system/case_contacts/new_spec.rb index fc2f2c4adb..75ac70dd27 100644 --- a/spec/system/case_contacts/new_spec.rb +++ b/spec/system/case_contacts/new_spec.rb @@ -399,20 +399,20 @@ submitted_case_contact = CaseContact.active.last next_case_contact = CaseContact.started.last - expect(page).to have_text "New Case Contact" - expect(submitted_case_contact.reload.metadata["create_another"]).to be true - # new contact uses draft_case_ids from the original & form selects them - expect(next_case_contact.draft_case_ids).to eq [casa_case.id] - expect(page).to have_text case_number - # default values for other attributes (not from the last contact) - expect(next_case_contact.status).to eq "started" - expect(next_case_contact.miles_driven).to be_zero - %i[casa_case_id duration_minutes occurred_at medium_type - want_driving_reimbursement notes].each do |attribute| - expect(next_case_contact.send(attribute)).to be_blank - end - expect(next_case_contact.contact_made).to be true + expect(page).to have_text "New Case Contact" + expect(submitted_case_contact.reload.metadata["create_another"]).to be true + # new contact uses draft_case_ids from the original & form selects them + expect(next_case_contact.draft_case_ids).to eq [casa_case.id] + expect(page).to have_text case_number + # default values for other attributes (not from the last contact) + expect(next_case_contact.status).to eq "started" + expect(next_case_contact.miles_driven).to be_zero + %i[casa_case_id duration_minutes occurred_at medium_type + want_driving_reimbursement notes].each do |attribute| + expect(next_case_contact.send(attribute)).to be_blank end + expect(next_case_contact.contact_made).to be true + end it "does not reset referring location" do visit casa_case_path casa_case