Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parked client download #816

Merged
merged 11 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
4 changes: 0 additions & 4 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,6 @@ Layout/SpaceAroundOperators:
# SupportedStylesForEmptyBraces: space, no_space
Layout/SpaceBeforeBlockBraces:
Exclude:
- 'spec/models/client_opportunity_match_spec.rb'
- 'spec/models/imported_clients_csv_spec.rb'
- 'spec/tasks/update_project_clients_from_deidentified_clients_spec.rb'

Expand Down Expand Up @@ -724,7 +723,6 @@ Style/BlockComments:
Style/BlockDelimiters:
Exclude:
- 'spec/controllers/client_notes_controller_spec.rb'
- 'spec/models/client_opportunity_match_spec.rb'
- 'spec/models/prioritization/rank_spec.rb'
- 'spec/models/rules/assessment_scores_spec.rb'
- 'spec/models/rules/assessment_scores_specified_spec.rb'
Expand Down Expand Up @@ -813,7 +811,6 @@ Style/InverseMethods:
# Configuration parameters: IgnoredMethods.
Style/MethodCallWithoutArgsParentheses:
Exclude:
- 'spec/models/decisions_spec.rb'

# Offense count: 2
# Cop supports --auto-correct.
Expand Down Expand Up @@ -999,7 +996,6 @@ Style/StringLiterals:
- 'spec/factories/housing_media_links.rb'
- 'spec/factories/roles.rb'
- 'spec/models/client_notes_spec.rb'
- 'spec/models/client_opportunity_match_spec.rb'
- 'spec/models/prioritization/rank_spec.rb'
- 'spec/requests/express_neighborhood_interests_spec.rb'
- 'spec/support/tasks.rb'
Expand Down
4 changes: 2 additions & 2 deletions app/controllers/clients_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def update
prevent_matching_until = params[:client].try(:[], :prevent_matching_until)
should_prevent_matching = prevent_matching_until.present? && prevent_matching_until.to_date > Date.current

@client.unavailable(permanent: false, contact_id: current_contact.id, cancel_all: true, expires_at: prevent_matching_until.to_date) if should_prevent_matching
@client.unavailable(permanent: false, contact_id: current_contact.id, cancel_all: true, expires_at: prevent_matching_until.to_date, user: current_user) if should_prevent_matching

if request.xhr?
head :ok
Expand All @@ -105,7 +105,7 @@ def update
# Remove the client from any other proposed matches
# Mark the Client as available = false
def unavailable
@client.unavailable(permanent: true)
@client.unavailable(permanent: true, user: current_user)
redirect_to action: :show
end

Expand Down
27 changes: 11 additions & 16 deletions app/controllers/match_decision_acknowledgments_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,27 @@ class MatchDecisionAcknowledgmentsController < ApplicationController
before_action :find_decision!
before_action :authorize_decision!

delegate :current_contact,
:match_scope,
to: :access_context
delegate :current_contact, :match_scope, to: :access_context

def create
if @decision.update status: 'acknowledged'
@decision.record_action_event! contact: current_contact
@decision.run_status_callback!
@decision.run_status_callback!(user: current_user)
head :ok
else
head :bad_request
end
end

private

def find_match!
@match = match_scope.find params[:match_id]
end

def find_decision!
@decision = @match.decision_from_param params[:decision_id]
end
private def find_match!
@match = match_scope.find params[:match_id]
end

def authorize_decision!
# TODO ensure that the current contact can authorize this decision
end
private def find_decision!
@decision = @match.decision_from_param params[:decision_id]
end

private def authorize_decision!
# TODO ensure that the current contact can authorize this decision
end
end
13 changes: 10 additions & 3 deletions app/controllers/match_decisions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def show
render 'matches/show'
end

def update
def update # rubocop:disable Metrics/AbcSize
@program = @match.program
@sub_program = @match.sub_program
@types = MatchRoutes::Base.match_steps
Expand Down Expand Up @@ -114,9 +114,16 @@ def update
# re-enable the client for matching
prevent_matching_until = decision_params[:prevent_matching_until]&.to_date
if can_reject_matches? && prevent_matching_until.present? && prevent_matching_until > Date.current
@match.client.unavailable(permanent: false, contact_id: current_contact.id, cancel_specific: @match, expires_at: prevent_matching_until)
@match.client.unavailable(
permanent: false,
contact_id: current_contact.id,
cancel_specific: @match,
expires_at: prevent_matching_until,
user: current_user,
match: @match,
)
else
@decision.run_status_callback!
@decision.run_status_callback!(user: current_user)
end

if decision_params[:disable_opportunity] == '1'
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/matches_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def history

def reopen
@match = match_scope.find(params[:match_id])
@match.reopen!(current_contact)
@match.reopen!(current_contact, user: current_user)
redirect_to match_path(@match)
end

Expand Down
6 changes: 3 additions & 3 deletions app/controllers/opportunity_matches_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ def create
client_ids_to_activate.each do |client_id|
match = ClientOpportunityMatch.where(client_id: client_id, opportunity_id: @opportunity, closed: false).
first_or_create(create_match_attributes(client_id))
match.activate!(touch_referral_event: @opportunity.match_route.auto_initialize_event?)
match.activate!(touch_referral_event: @opportunity.match_route.auto_initialize_event?, user: current_user)
end
redirect_to opportunity_matches_path(@opportunity)
end

def update
client_id = params[:id].to_i
client_id = params[:id].to_i

unless @opportunity.match_route.allow_multiple_active_matches
@opportunity.active_matches.each do |active_match|
Expand All @@ -53,7 +53,7 @@ def update

match = ClientOpportunityMatch.create(create_match_attributes(client_id))

match.activate!(touch_referral_event: @opportunity.match_route.auto_initialize_event?)
match.activate!(touch_referral_event: @opportunity.match_route.auto_initialize_event?, user: current_user)
redirect_to match_path match
end

Expand Down
2 changes: 1 addition & 1 deletion app/controllers/qualified_opportunities_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def update
match_route: @opportunity.match_route,
universe_state: universe_state,
)
match.activate!(touch_referral_event: @opportunity.match_route.auto_initialize_event?)
match.activate!(touch_referral_event: @opportunity.match_route.auto_initialize_event?, user: current_user)
redirect_to match_path match
end

Expand Down
29 changes: 22 additions & 7 deletions app/controllers/reports/parked_clients_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,30 @@ def index
@active_tab = params[:tab] || route_to_html_id(@routes.first)
clients = parked_scope
clients = clients.non_confidential.full_release unless can_view_all_clients?

@clients = clients.
joins(:unavailable_as_candidate_fors).
order(uacf_t[:expires_at].asc).
page(params[:page].to_i).per(25)
respond_to do |format|
format.html do
@clients = clients.
joins(:unavailable_as_candidate_fors).
order(uacf_t[:expires_at].asc).
page(params[:page].to_i).per(25)
end
format.xlsx do
@parked = UnavailableAsCandidateFor.joins(:client).
merge(client_scope).
where(match_route_type: MatchRoutes::Base.active.select(:type)).
preload(:user, client: { project_client: :data_source })
filename = "Parked Clients #{Time.current.to_fs(:db)}.xlsx"
render xlsx: 'index', filename: filename
end
end
end

def parked_scope
Client.accessible_by_user(current_user).unavailable_in(@route)
client_scope.unavailable_in(@route)
end

private def client_scope
Client.accessible_by_user(current_user)
end

private def set_routes
Expand All @@ -38,7 +53,7 @@ def route_to_html_id(route)
end
helper_method :route_to_html_id

private def route_from_tab(tab_label=nil)
private def route_from_tab(tab_label = nil)
return @routes.first unless tab_label.present?

@routes.detect do |route|
Expand Down
81 changes: 1 addition & 80 deletions app/models/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -368,85 +368,6 @@ def active_in_match?
active_matches.any?
end

def available_as_candidate_for_any_route?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was moved into the Availability concern, where similar methods already existed.

(
MatchRoutes::Base.available.pluck(:type) -
UnavailableAsCandidateFor.where(client_id: id).distinct.pluck(:match_route_type)
).any?
end

def make_available_in match_route:
route_name = MatchRoutes::Base.route_name_from_route(match_route)
UnavailableAsCandidateFor.where(client_id: id, match_route_type: route_name).destroy_all
end

def make_available_in_all_routes
UnavailableAsCandidateFor.where(client_id: id).destroy_all
end

private def default_unavailable_expiration_date
days = Config.get(:unavailable_for_length)
return nil unless days.present? && days.positive?

Date.current + days.days
end

def make_unavailable_in(match_route:, expires_at: default_unavailable_expiration_date)
route_name = MatchRoutes::Base.route_name_from_route(match_route)

un = unavailable_as_candidate_fors.where(match_route_type: route_name).first_or_create
un.update(expires_at: expires_at)
end

def make_unavailable_in_all_routes(expires_at: default_unavailable_expiration_date)
MatchRoutes::Base.all_routes.each do |route|
make_unavailable_in(match_route: route, expires_at: expires_at)
end
end

# cancel_specific must be a match object
def unavailable(permanent: false, contact_id: nil, cancel_all: false, cancel_specific: false, expires_at: default_unavailable_expiration_date)
Client.transaction do
update(available: false) if permanent

if cancel_all
# Cancel any active matches
client_opportunity_matches.active.each do |active_match|
opportunity = active_match.opportunity
active_match.canceled!
MatchEvents::Parked.create!(
match_id: active_match.id,
contact_id: contact_id,
)
opportunity.update(available_candidate: true)
end
# Delete any non-active open matches
client_opportunity_matches.open.each(&:delete)
# Prevent any new matches for this client
# This will re-queue the client once the date is passed
make_unavailable_in_all_routes(expires_at: expires_at)
end

if cancel_specific
# remove from specific match and proposed on same route
match = cancel_specific
opportunity = match.opportunity
route = match.match_route
match.canceled! # note canceled! makes the client available in the route
Notifications::MatchCanceled.create_for_match! match
MatchEvents::Parked.create!(
match_id: match.id,
contact_id: contact_id,
)
opportunity.update(available_candidate: true)
# Delete any non-active open matches
client_opportunity_matches.on_route(route).proposed.each(&:delete)
make_unavailable_in(match_route: route, expires_at: expires_at)
end
end
Matching::RunEngineJob.perform_later
end

def remote_id
@remote_id ||= project_client&.id_in_data_source.presence
end
Expand All @@ -456,7 +377,7 @@ def remote_data_source_id
end

def remote_data_source
@remote_data_source ||= DataSource.find(remote_data_source_id) rescue false # rubocop:disable Style/RescueModifier
@remote_data_source ||= project_client&.data_source || false
end

def remote_client_visible_to?(user)
Expand Down
34 changes: 19 additions & 15 deletions app/models/client_opportunity_match.rb
Original file line number Diff line number Diff line change
Expand Up @@ -644,9 +644,9 @@ def restrictions_on_reopening
restrictions
end

def reopen!(contact)
def reopen!(contact, user: nil)
self.class.transaction do
client.make_unavailable_in(match_route: match_route, expires_at: nil)
client.make_unavailable_in(match_route: match_route, expires_at: nil, user: user, match: self, reason: 'Active Match')
update(closed: false, active: true, closed_reason: nil)
current_decision.update(status: :pending)
MatchEvents::Reopened.create(match_id: id, contact_id: contact.id)
Expand All @@ -658,11 +658,11 @@ def reopen!(contact)
end
end

def activate!(touch_referral_event: true)
def activate!(touch_referral_event: true, user: nil)
self.class.transaction do
update! active: true
client.make_unavailable_in(match_route: match_route, expires_at: nil) if match_route.should_prevent_multiple_matches_per_client
opportunity.update available_candidate: false
update!(active: true)
client.make_unavailable_in(match_route: match_route, expires_at: nil, user: user, match: self, reason: 'Active Match') if match_route.should_prevent_multiple_matches_per_client
opportunity.update(available_candidate: false)
add_default_contacts!
requirements_with_inherited.each { |req| req.apply_to_match(self) }
send(match_route.initial_decision).initialize_decision!
Expand Down Expand Up @@ -727,7 +727,7 @@ def poached!(touch_referral_event: true)
end
end

def succeeded!(touch_referral_event: true)
def succeeded!(touch_referral_event: true, user: nil)
self.class.transaction do
route = opportunity.match_route
update! active: false, closed: true, closed_reason: 'success'
Expand All @@ -736,9 +736,11 @@ def succeeded!(touch_referral_event: true)
if route.should_cancel_other_matches
client_related_matches.each do |match|
if match.current_decision.present?
MatchEvents::DecisionAction.create(match_id: match.id,
decision_id: match.current_decision.id,
action: :canceled)
MatchEvents::DecisionAction.create(
match_id: match.id,
decision_id: match.current_decision.id,
action: :canceled,
)
reason = MatchDecisionReasons::AdministrativeCancel.find_by(name: 'Client received another housing opportunity')
match.current_decision.update! status: 'canceled', administrative_cancel_reason_id: reason.id
match.poached!
Expand All @@ -748,10 +750,10 @@ def succeeded!(touch_referral_event: true)
end
client.update available: false
# Prevent matching on any route
client.make_unavailable_in_all_routes
client.make_unavailable_in_all_routes(user: user, match: self, reason: 'Successful Match')
else
# Prevent matching on this route again
client.make_unavailable_in(match_route: route)
client.make_unavailable_in(match_route: route, user: user, match: self, reason: 'Successful Match')
end

# Cleanup other matches on the same opportunity
Expand All @@ -761,9 +763,11 @@ def succeeded!(touch_referral_event: true)
else
opportunity_related_matches.each do |match|
if match.active
MatchEvents::DecisionAction.create(match_id: match.id,
decision_id: match.current_decision.id,
action: :canceled)
MatchEvents::DecisionAction.create(
match_id: match.id,
decision_id: match.current_decision.id,
action: :canceled,
)
opportunity.notify_contacts_opportunity_taken(match)
reason = MatchDecisionReasons::AdministrativeCancel.find_by(name: 'Vacancy filled by other client')
match.current_decision.update! status: 'canceled', administrative_cancel_reason_id: reason.id
Expand Down
Loading
Loading