Skip to content

Commit

Permalink
Tag additional cancel/decline reasons with appropriate CE values for …
Browse files Browse the repository at this point in the history
…reporting (#838)

* Tag additional cancel/decline reasons with appropriate CE values for reporting

* WIP

* Make decision reasons into strings instead of STI classes

* Note future removal of classes

* Missed file save

* Update factories for decision reason changes

* Remove commented code
  • Loading branch information
eanders authored Aug 8, 2024
1 parent 2b27391 commit 4fa1f23
Show file tree
Hide file tree
Showing 19 changed files with 95 additions and 271 deletions.
3 changes: 2 additions & 1 deletion app/controllers/reports/agency_interactions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@ def index

def match_decision_reasons_collection
MatchDecisionReasons::Base.
active.
order(name: :asc).
map { |reason| [reason_text(reason), reason.id] }
end
helper_method :match_decision_reasons_collection

def reason_text(match_decision_reason)
text = match_decision_reason.name
text << " (#{match_decision_reason.title})" if match_decision_reason.title.present?
text << " (#{match_decision_reason.title})" if match_decision_reason.title.present? && match_decision_reason.title != match_decision_reason.name
text
end
helper_method :reason_text
Expand Down
264 changes: 49 additions & 215 deletions app/models/cas_seeds/match_decision_reasons.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,236 +9,70 @@ class MatchDecisionReasons
CLIENT_REJECTED = 2
PROVIDER_REJECTED = 3

DND_REASONS = [
["Client won't be eligible for services", nil],
["Client won't be eligible for housing type", nil],
["Client won't be eligible based on funding source", nil],
['Client has another housing option', nil],
].freeze

HSA_REASONS = [
['CORI', PROVIDER_REJECTED],
['SORI', PROVIDER_REJECTED],
['Immigration status', nil],
['Household did not respond after initial acceptance of match', CLIENT_REJECTED],
['Ineligible for Housing Program', nil],
['Client refused offer', CLIENT_REJECTED],
['Self-resolved', nil],
['Falsification of documents', nil],
# When adding new decline or cancel reasons to CAS, add them here, and indicate the rejection type for CE APR reporting.
# Then in the appropriate route or step, add to step_cancel_reasons or step_decline_reasons
ALL_REASONS = [
['Additional screening criteria imposed by third parties', PROVIDER_REJECTED],
['Health and Safety', nil],
].freeze

LIMITED_HSA_REASONS = [
['Barred from working with agency', PROVIDER_REJECTED],
['Client deceased', CLIENT_REJECTED],
['Client has another housing option', CLIENT_REJECTED],
['Client has declined match', CLIENT_REJECTED],
['Client has disappeared', CLIENT_REJECTED],
['Client has disengaged', CLIENT_REJECTED],
['Client needs higher level of care', PROVIDER_REJECTED],
['Unable to reach client after multiple attempts', nil],
].freeze

HSA_PROVIDER_ONLY_REASONS = [
['Household could not be located', nil],
['Ineligible for Housing Program', nil],
['Client no longer eligible for match', PROVIDER_REJECTED],
['Client received another housing opportunity', CLIENT_REJECTED],
['Client receiving navigation services', nil],
['Client refused offer', CLIENT_REJECTED],
['Health and Safety', nil],
].freeze

SHELTER_AGENCY_REASONS = [
['Does not agree to services', CLIENT_REJECTED],
['Unwilling to live in that neighborhood', CLIENT_REJECTED],
['Unwilling to live in SRO', CLIENT_REJECTED],
['Does not want housing at this time', CLIENT_REJECTED],
['Unsafe environment for this person', CLIENT_REJECTED],
['Client has another housing option', nil],
['Client refused unit (non-SRO)', CLIENT_REJECTED],
['Client refused voucher', CLIENT_REJECTED],
].freeze

MITIGATION_REASONS = [
['Mitigation failed', nil],
].freeze

SHELTER_AGENCY_NOT_WORKING_WITH_CLIENT_REASONS = [
['Barred from working with agency', PROVIDER_REJECTED],
['Hospitalized', nil],
['Client is already receiving navigation services', CLIENT_REJECTED],
["Client won't be eligible based on funding source", PROVIDER_REJECTED],
["Client won't be eligible for housing type", PROVIDER_REJECTED],
["Client won't be eligible for services", PROVIDER_REJECTED],
['CORI', PROVIDER_REJECTED],
['Does not agree to services', CLIENT_REJECTED],
['Does not want housing at this time', CLIENT_REJECTED],
['Don’t know / disappeared', nil],
['Incarcerated', nil],
].freeze

ADMINISTRATIVE_CANCEL_REASONS = [
['Falsification of documents', PROVIDER_REJECTED],
['Health and Safety', PROVIDER_REJECTED],
['Hospitalized', nil],
['Household became disengaged', nil],
['Household could not be located', PROVIDER_REJECTED],
['Household did not respond after initial acceptance of match', PROVIDER_REJECTED],
['Housing Case Manager has disengaged', PROVIDER_REJECTED],
['HSP CORI', PROVIDER_REJECTED],
['Immigration status', PROVIDER_REJECTED],
['In Treatment/Recovery Center', CLIENT_REJECTED],
['Incarcerated', CLIENT_REJECTED],
['Institutionalized', CLIENT_REJECTED],
['Ineligible for Housing Program', PROVIDER_REJECTED],
['Match expired – Agency interaction', nil],
['Match expired – No agency interaction', PROVIDER_REJECTED],
['Match expired – No Housing Case Manager interaction', PROVIDER_REJECTED],
['Match expired – No Shelter Agency interaction', PROVIDER_REJECTED],
['Match expired', nil],
['Client has declined match', CLIENT_REJECTED],
['Client has disengaged', CLIENT_REJECTED],
['Client has disappeared', CLIENT_REJECTED],
['Match stalled - Agency has disengaged', PROVIDER_REJECTED],
['Match stalled – Housing Case Manager has disengaged', PROVIDER_REJECTED],
['Mitigation failed', nil],
['Self-resolved', CLIENT_REJECTED],
['Shelter Agency has disengaged', PROVIDER_REJECTED],
['SORI', PROVIDER_REJECTED],
['SSP CORI', PROVIDER_REJECTED],
['HSP CORI', PROVIDER_REJECTED],
['Incarcerated', nil],
['Unable to reach client after multiple attempts', PROVIDER_REJECTED],
['Unsafe environment for this person', CLIENT_REJECTED],
['Unwilling to live in SRO', CLIENT_REJECTED],
['Unwilling to live in that neighborhood', CLIENT_REJECTED],
['Vacancy filled by other client', PROVIDER_REJECTED],
['Vacancy should not have been entered', nil],
['Client received another housing opportunity', nil],
['Client no longer eligible for match', nil],
['Client deceased', nil],
['Vacancy filled by other client', nil],
['Client receiving navigation services', nil],
].freeze

LIMITED_ADMINISTRATIVE_CANCEL_REASONS = [
['Match expired – No agency interaction', nil],
['Match expired – Agency interaction', nil],
['Match stalled - Agency has disengaged', nil],
['Match expired – No Housing Case Manager interaction', nil],
['Match expired – No Shelter Agency interaction', nil],
['Shelter Agency has disengaged', nil],
['Housing Case Manager has disengaged', nil],
['Match stalled – Housing Case Manager has disengaged', nil],
['Client needs higher level of care', nil],
['Unable to reach client after multiple attempts', nil],
].freeze

NINE_RECORD_VOUCHER_DATE_DECLINE_REASONS = [
[' Household became disengaged', nil],
].freeze

NINE_CASE_CONTACT_ASSIGNS_MANAGER_DECLINE_REASONS = [].freeze

CASE_CONTACT_ASSIGNS_MANAGER_DECLINE_REASONS = [].freeze

TEN_DECLINE_REASONS = [
['Immigration status', nil],
['Household did not respond after initial acceptance of match', nil],
['Ineligible for Housing Program', nil],
['Client refused offer', nil],
['Self-resolved', nil],
['Client needs higher level of care', nil],
['Unable to reach client after multiple attempts', nil],
].freeze

OTHER = [
['Other', nil],
].freeze

def run!
create_other_reason!
create_dnd_reasons!
create_hsa_reasons!
create_hsa_provider_only_reasons!
create_shelter_agency_reasons!
create_shelter_agency_not_working_with_client_reasons!
create_shelter_agency_not_working_with_client_other_reason!
create_admin_cancel_reasons!
create_mitigation_reasons!
create_record_voucher_decline_reasons!
create_case_contact_assigns_manager_decline_reasons!
create_nine_case_contact_assigns_manager_decline_reasons!
create_ten_decline_reasons!
create_base_reasons!
end

private def create_base_reasons!
reasons = DND_REASONS +
HSA_REASONS +
LIMITED_HSA_REASONS +
HSA_PROVIDER_ONLY_REASONS +
SHELTER_AGENCY_REASONS +
MITIGATION_REASONS +
SHELTER_AGENCY_NOT_WORKING_WITH_CLIENT_REASONS +
ADMINISTRATIVE_CANCEL_REASONS +
LIMITED_ADMINISTRATIVE_CANCEL_REASONS +
OTHER
reasons.each do |reason_name, referral_result|
reason = ::MatchDecisionReasons::All.where(name: reason_name).first_or_create!
reason.update(referral_result: referral_result)
end
end

private def create_other_reason!
reason = ::MatchDecisionReasons::Other.all.first_or_create! name: 'Other'
reason.update(referral_result: nil)
end

private def create_dnd_reasons!
DND_REASONS.each do |reason_name, referral_result|
reason = ::MatchDecisionReasons::DndStaffDecline.where(name: reason_name).first_or_create!
ALL_REASONS.each do |reason_name, referral_result|
reason = ::MatchDecisionReasons::Base.where(name: reason_name).first_or_create!
reason.update(referral_result: referral_result)
end
end

private def create_hsa_reasons!
HSA_REASONS.each do |reason_name, referral_result|
reason = ::MatchDecisionReasons::HousingSubsidyAdminDecline.where(name: reason_name).first_or_create!
reason.update(referral_result: referral_result)
end

LIMITED_HSA_REASONS.each do |reason_name, referral_result|
reason = ::MatchDecisionReasons::HousingSubsidyAdminDecline.where(name: reason_name, limited: true).first_or_create!
reason.update(referral_result: referral_result)
end
end

private def create_hsa_provider_only_reasons!
::MatchDecisionReasons::HousingSubsidyAdminPriorityDecline.update_all(active: false)
HSA_PROVIDER_ONLY_REASONS.each do |reason_name, referral_result|
reason = ::MatchDecisionReasons::HousingSubsidyAdminPriorityDecline.where(name: reason_name).first_or_create!
reason.update(active: true, referral_result: referral_result)
end
end

private def create_shelter_agency_reasons!
SHELTER_AGENCY_REASONS.each do |reason_name, referral_result|
reason = ::MatchDecisionReasons::ShelterAgencyDecline.where(name: reason_name).first_or_create!
reason.update(referral_result: referral_result)
end
end

private def create_shelter_agency_not_working_with_client_reasons!
SHELTER_AGENCY_NOT_WORKING_WITH_CLIENT_REASONS.each do |reason_name, referral_result|
reason = ::MatchDecisionReasons::ShelterAgencyNotWorkingWithClient.where(name: reason_name).first_or_create!
reason.update(referral_result: referral_result)
end
end

private def create_shelter_agency_not_working_with_client_other_reason!
reason = ::MatchDecisionReasons::ShelterAgencyNotWorkingWithClientOther.all.first_or_create! name: 'Other'
reason.update(referral_result: nil)
end

private def create_admin_cancel_reasons!
ADMINISTRATIVE_CANCEL_REASONS.each do |reason_name, referral_result|
reason = ::MatchDecisionReasons::AdministrativeCancel.where(name: reason_name).first_or_create!
reason.update(referral_result: referral_result)
end

LIMITED_ADMINISTRATIVE_CANCEL_REASONS.each do |reason_name, referral_result|
reason = ::MatchDecisionReasons::AdministrativeCancel.where(name: reason_name, limited: true).first_or_create!
reason.update(referral_result: referral_result)
end
end

private def create_mitigation_reasons!
MITIGATION_REASONS.each do |reason_name, _|
::MatchDecisionReasons::MitigationDecline.where(name: reason_name).first_or_create!
end
end

private def create_record_voucher_decline_reasons!
NINE_RECORD_VOUCHER_DATE_DECLINE_REASONS.each do |reason_name, _|
::MatchDecisionReasons::NineRecordVoucherDateDecline.where(name: reason_name).first_or_create!
end
end

private def create_case_contact_assigns_manager_decline_reasons!
CASE_CONTACT_ASSIGNS_MANAGER_DECLINE_REASONS.each do |reason_name, _|
::MatchDecisionReasons::CaseContactAssignsManagerDecline.where(name: reason_name).first_or_create!
end
end

private def create_nine_case_contact_assigns_manager_decline_reasons!
NINE_CASE_CONTACT_ASSIGNS_MANAGER_DECLINE_REASONS.each do |reason_name, _|
::MatchDecisionReasons::NineCaseContactAssignsManagerDecline.where(name: reason_name).first_or_create!
end
end

private def create_ten_decline_reasons!
TEN_DECLINE_REASONS.each do |reason_name, _|
::MatchDecisionReasons::RouteTenDeclineReasons.where(name: reason_name).first_or_create!
end
end
end
end
15 changes: 3 additions & 12 deletions app/models/concerns/match_decisions/accepts_decline_reason.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,10 @@ module AcceptsDeclineReason
validate :validate_decline_reason
end

# FIXME: remove 'include_other' after migration
def decline_reasons(include_other: true, contact:)
def decline_reasons(contact:)
@_decline_reasons ||= [].tap do |result| # rubocop:disable Naming/MemoizedInstanceVariableName
# FIXME: remove if/else after migration
if respond_to?(:step_decline_reasons)
MatchDecisionReasons::All.where(name: step_decline_reasons(contact)).find_each do |reason|
result << reason
end
else
decline_reason_scope(contact).each do |reason|
result << reason
end
result << MatchDecisionReasons::Other.first if include_other
MatchDecisionReasons::Base.active.where(name: step_decline_reasons(contact)).find_each do |reason|
result << reason
end
# Move other to the end of the list
result.sort_by! { |m| m.name.downcase == 'other' ? 1 : 0 }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ def step_cancel_reasons
reasons << 'Client deceased'
reasons << 'Vacancy filled by other client' unless pre_hsa_decision? || match_success_decision?
reasons << 'Health and Safety' unless match_success_decision?
reasons << 'Do not allow other matches for this vacancy' unless match_success_decision?
reasons << 'Other'
end
end
Expand Down
4 changes: 2 additions & 2 deletions app/models/match_decision_reasons/administrative_cancel.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
module MatchDecisionReasons
class AdministrativeCancel < Base
def self.available(include_other: true, route: nil) # rubocop:disable Lint/UnusedMethodArgument
other = MatchDecisionReasons::Other.first
other = MatchDecisionReasons::Base.other.first
# none = OpenStruct.new(name: 'None', id: nil)
av = active.to_a
# av << none
Expand All @@ -21,7 +21,7 @@ def self.available(include_other: true, route: nil) # rubocop:disable Lint/Unuse
end

def self.available_for_provider_only(include_other: true, route: nil) # rubocop:disable Lint/UnusedMethodArgument
other = MatchDecisionReasons::Other.first
other = MatchDecisionReasons::Base.other.first
# none = OpenStruct.new(name: 'None', id: nil)
av = active.where(name: provider_only_options).to_a
av << other if include_other
Expand Down
1 change: 1 addition & 0 deletions app/models/match_decision_reasons/all.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# License detail: https://github.com/greenriver/boston-cas/blob/production/LICENSE.md
###

# TODO: remove all non Base MatchDecisionReasons after release-63 is deployed to production
module MatchDecisionReasons
class All < Base
def title
Expand Down
16 changes: 2 additions & 14 deletions app/models/match_decision_reasons/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,8 @@

module MatchDecisionReasons
class Base < ApplicationRecord
# Pick-list reasons associated with a particular match decision
# Reasons are currently split up by actor type
# + special other option and shelter agency
# no longer working with the client
# Per requirements in https://www.pivotaltracker.com/story/show/118185729
# Feel free to change how available reasons are associated with decisions
# as the requirements evolve
# ~@rrosen, 5/24/2016

self.table_name = 'match_decision_reasons'
acts_as_paranoid

has_many :decisions, class_name: 'MatchDecisions::Base', foreign_key: :decline_reason_id

Expand All @@ -29,15 +21,11 @@ class Base < ApplicationRecord
validates :name, presence: true

def title
type.demodulize.underscore.humanize
name
end

def other?
name == 'Other'
end

def not_working_with_client?
false
end
end
end
Loading

0 comments on commit 4fa1f23

Please sign in to comment.