Skip to content

Commit

Permalink
Merge branch 'master' into feature/APPEALS-50887
Browse files Browse the repository at this point in the history
  • Loading branch information
msteele96 committed Aug 13, 2024
2 parents 6c30a90 + e5563b2 commit ce63551
Show file tree
Hide file tree
Showing 45 changed files with 950 additions and 465 deletions.
4 changes: 2 additions & 2 deletions app/controllers/test/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ class Test::UsersController < ApplicationController
name: "Queue",
links: {
your_queue: "/queue",
assignment_queue: "/queue/USER_CSS_ID/assign" # USER_CSS_ID is then updated in TestUsers file
assignment_queue: "/queue/USER_CSS_ID/assign", # USER_CSS_ID is then updated in TestUsers file
case_distribution_dashboard: "/acd-controls/test"
}
},
{
Expand Down Expand Up @@ -65,7 +66,6 @@ class Test::UsersController < ApplicationController
admin: "/admin",
test_veterans: "/test/data",
metrics_dashboard: "/metrics/dashboard",
case_distribution_dashboard: "/acd-controls/test",
swagger: "/api-docs"
}
}
Expand Down
126 changes: 76 additions & 50 deletions app/jobs/push_priority_appeals_to_judges_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def perform

perform_later_or_now(UpdateAppealAffinityDatesJob)

send_job_report
slack_service.send_notification(generate_report.join("\n"), self.class.name)
rescue StandardError => error
start_time ||= Time.zone.now # temporary fix to get this job to succeed
duration = time_ago_in_words(start_time)
Expand All @@ -32,55 +32,6 @@ def perform
metrics_service_report_runtime(metric_group_name: "priority_appeal_push_job")
end

def send_job_report
slack_service.send_notification(slack_report.join("\n"), self.class.name)
end

def slack_report # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
report = []
if use_by_docket_date?
total_cases = @genpop_distributions.map(&:distributed_cases_count).sum
report << "*Number of cases distributed*: " \
"#{total_cases}"
else
tied_distributions_sum = @tied_distributions.map(&:distributed_cases_count).sum
genpop_distributions_sum = @genpop_distributions.map(&:distributed_cases_count).sum
report << "*Number of cases tied to judges distributed*: " \
"#{tied_distributions_sum}"
report << "*Number of general population cases distributed*: " \
"#{genpop_distributions_sum}"
end

appeals_not_distributed = docket_coordinator.dockets.map do |docket_type, docket|
report << "*Age of oldest #{docket_type} case*: #{docket.oldest_priority_appeal_days_waiting} days"
[docket_type, docket.ready_priority_appeal_ids]
end.to_h

report << "*Total Number of appeals _not_ distributed*: #{appeals_not_distributed.values.flatten.count}"
docket_coordinator.dockets.each_pair do |sym, docket|
report << "*Number of #{sym} appeals _not_ distributed*: #{docket.count(priority: true, ready: true)}"
end
report << "*Number of Legacy Hearing Non Genpop appeals _not_ distributed*: #{legacy_not_genpop_count}"

report << ""
report << "*Debugging information*"
report << "Priority Target: #{priority_target}"
report << "Previous monthly distributions {judge_id=>count}: #{priority_distributions_this_month_for_eligible_judges}" # rubocop:disable Layout/LineLength

if appeals_not_distributed.values.flatten.any?
add_stuck_appeals_to_report(report, appeals_not_distributed)
end

report
end

def add_stuck_appeals_to_report(report, appeals)
report.unshift("[WARN]")
report << COPY::PRIORITY_PUSH_WARNING_MESSAGE
report << "AMA appeals not distributed: `Appeal.where(uuid: #{appeals.values.drop(1).flatten})`"
report << "Legacy appeals not distributed: `LegacyAppeal.where(vacols_id: #{appeals[:legacy]})`"
end

# Distribute all priority cases tied to a judge without limit
def distribute_non_genpop_priority_appeals
eligible_judges.map do |judge|
Expand Down Expand Up @@ -182,7 +133,82 @@ def use_by_docket_date?
FeatureToggle.enabled?(:acd_distribute_by_docket_date, user: RequestStore.store[:current_user])
end

#
# Reporting methods
#

def generate_report
report = []

num_of_cases_distributed(report)

report << "Priority Target: #{priority_target}"

appeals_not_distributed = age_of_oldest_by_docket(report)
num_of_appeals_not_distributed(report, appeals_not_distributed)
num_of_appeals_not_distributed_by_affinity_date(report)

report << ""
report << "*Debugging information*"

excluded_judges_reporting(report)

report << "Previous monthly distributions {judge_id=>count}: #{priority_distributions_this_month_for_eligible_judges}" # rubocop:disable Layout/LineLength
report
end

def num_of_cases_distributed(report)
if use_by_docket_date?
total_cases = @genpop_distributions.map(&:distributed_cases_count).sum
report << "*Number of cases distributed*: " \
"#{total_cases}"
else
tied_distributions_sum = @tied_distributions.map(&:distributed_cases_count).sum
genpop_distributions_sum = @genpop_distributions.map(&:distributed_cases_count).sum
report << "*Number of cases tied to judges distributed*: " \
"#{tied_distributions_sum}"
report << "*Number of general population cases distributed*: " \
"#{genpop_distributions_sum}"
end
end

# :reek:FeatureEnvy
def age_of_oldest_by_docket(report)
docket_coordinator.dockets.map do |docket_type, docket|
report << "*Age of oldest #{docket_type} case*: #{docket.oldest_priority_appeal_days_waiting} days"
[docket_type, docket.ready_priority_appeal_ids]
end.to_h
end

# :reek:FeatureEnvy
def num_of_appeals_not_distributed(report, appeals_not_distributed)
report << ""
report << "*Total Number of appeals _not_ distributed*: #{appeals_not_distributed.values.flatten.count}"

docket_coordinator.dockets.each_pair do |sym, docket|
report << "*Number of #{sym} appeals _not_ distributed*: #{docket.count(priority: true, ready: true)}"
end

report << "*Number of Legacy Hearing Non Genpop appeals _not_ distributed*: #{legacy_not_genpop_count}"
end

def legacy_not_genpop_count
docket_coordinator.dockets[:legacy].not_genpop_priority_count
end

# :reek:FeatureEnvy
def num_of_appeals_not_distributed_by_affinity_date(report)
report << ""
docket_coordinator.dockets.each_pair do |sym, docket|
report << "*Number of #{sym} appeals in affinity date window*: " \
"#{docket.affinity_date_count(true, true)}"
report << "*Number of #{sym} appeals out of affinity date window*: " \
"#{docket.affinity_date_count(false, true)}"
end
end

def excluded_judges_reporting(report)
excluded_judges = JudgeTeam.judges_with_exclude_appeals_from_affinity.pluck(:css_id)
report << "*Excluded Judges*: #{excluded_judges}"
end
end
10 changes: 7 additions & 3 deletions app/models/appeal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -251,11 +251,15 @@ def contested_claim?

category_substrings = %w[Contested Apportionment]

request_issues.active.any? do |request_issue|
category_substrings.any? do |substring|
request_issues.active.include?(request_issue) && request_issue.nonrating_issue_category&.include?(substring)
request_issues.each do |request_issue|
category_substrings.each do |substring|
if request_issue.active? && request_issue.nonrating_issue_category&.include?(substring)
return true
end
end
end

false
end

# :reek:RepeatedConditionals
Expand Down
25 changes: 13 additions & 12 deletions app/models/concerns/automatic_case_distribution.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,18 +90,19 @@ def distribute_limited_priority_appeals_from_all_dockets(limit, style: "push")
def ama_statistics
sct_appeals_counts = @appeals.count { |appeal| appeal.try(:sct_appeal) }
{
batch_size: @appeals.count,
total_batch_size: total_batch_size,
priority_count: priority_count,
direct_review_due_count: direct_review_due_count,
legacy_hearing_backlog_count: VACOLS::CaseDocket.nonpriority_hearing_cases_for_judge_count(judge),
legacy_proportion: docket_proportions[:legacy],
direct_review_proportion: docket_proportions[:direct_review],
evidence_submission_proportion: docket_proportions[:evidence_submission],
hearing_proportion: docket_proportions[:hearing],
nonpriority_iterations: @nonpriority_iterations,
algorithm: "proportions",
sct_appeals: sct_appeals_counts
statistics: {
batch_size: @appeals.count,
total_batch_size: total_batch_size,
priority_count: priority_count,
direct_review_due_count: direct_review_due_count,
legacy_hearing_backlog_count: VACOLS::CaseDocket.nonpriority_hearing_cases_for_judge_count(judge),
legacy_proportion: docket_proportions[:legacy],
direct_review_proportion: docket_proportions[:direct_review],
evidence_submission_proportion: docket_proportions[:evidence_submission],
hearing_proportion: docket_proportions[:hearing],
nonpriority_iterations: @nonpriority_iterations,
sct_appeals: sct_appeals_counts
}
}
end

Expand Down
88 changes: 61 additions & 27 deletions app/models/concerns/by_docket_date_distribution.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,23 +57,47 @@ def distribute_nonpriority_appeals_from_all_dockets_by_age_to_limit(limit, style
end
end

# rubocop:disable Metrics/MethodLength
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
def ama_statistics
priority_counts = { count: priority_count }
nonpriority_counts = { count: nonpriority_count }
docket_counts = {
direct_review_priority_stats: {},
direct_review_stats: {},
evidence_submission_priority_stats: {},
evidence_submission_stats: {},
hearing_priority_stats: {},
hearing_stats: {},
legacy_priority_stats: {},
legacy_stats: {}
}

dockets.each_pair do |sym, docket|
priority_counts[sym] = docket.count(priority: true, ready: true)
nonpriority_counts[sym] = docket.count(priority: false, ready: true)
docket_counts["#{sym}_priority_stats".to_sym] = {
count: docket.count(priority: true, ready: true),
affinity_date: {
in_window: docket.affinity_date_count(true, true),
out_of_window: docket.affinity_date_count(false, true)
}
}

docket_counts["#{sym}_stats".to_sym] = {
count: docket.count(priority: false, ready: true),
affinity_date: {
in_window: docket.affinity_date_count(true, false),
out_of_window: docket.affinity_date_count(false, false)
}
}
end

priority_counts[:legacy_hearing_tied_to] = legacy_hearing_priority_count(judge)
nonpriority_counts[:legacy_hearing_tied_to] = legacy_hearing_nonpriority_count(judge)

nonpriority_counts[:iterations] = @nonpriority_iterations
docket_counts[:legacy_priority_stats][:legacy_hearing_tied_to] = legacy_hearing_priority_count(judge)
docket_counts[:legacy_stats][:legacy_hearing_tied_to] = legacy_hearing_nonpriority_count(judge)

sct_appeals_counts = @appeals.count { |appeal| appeal.try(:sct_appeal) }

cases_tied_to_ineligible_judges = {
ama: ama_distributed_cases_tied_to_ineligible_judges,
legacy: distributed_cases_tied_to_ineligible_judges
}

settings = {}
feature_toggles = [
:specialty_case_team_distribution
Expand All @@ -82,29 +106,39 @@ def ama_statistics
settings[sym] = FeatureToggle.enabled?(sym, user: RequestStore.store[:current_user])
end

{
batch_size: @appeals.count,
total_batch_size: total_batch_size,
priority_target: @push_priority_target || @request_priority_count,
priority: priority_counts,
nonpriority: nonpriority_counts,
sct_appeals: sct_appeals_counts,
distributed_cases_tied_to_ineligible_judges: {
ama: ama_distributed_cases_tied_to_ineligible_judges,
legacy: distributed_cases_tied_to_ineligible_judges
},
algorithm: "by_docket_date",
settings: settings
}
docket_counts.merge(
{
ineligible_judge_stats: {
distributed_cases_tied_to_ineligible_judges: cases_tied_to_ineligible_judges
},
judge_stats: {
team_size: team_size,
ama_judge_assigned_tasks: judge_tasks.length,
legacy_assigned_tasks: judge_legacy_tasks.length,
settings: settings
},
statistics: {
batch_size: @appeals.count,
total_batch_size: total_batch_size,
priority_target: @push_priority_target || @request_priority_count,
priority_count: priority_count,
nonpriority_count: nonpriority_count,
nonpriority_iterations: @nonpriority_iterations,
sct_appeals: sct_appeals_counts
}
}
)
rescue StandardError => error
# There always needs to be a batch_size value for a completed distribution, else the priority push job will error
{
batch_size: @appeals.count,
message: "Distribution successful, but there was an error generating statistics: \
#{error.class}: #{error.message}, #{error.backtrace.first}"
statistics: {
batch_size: @appeals.count,
message: "Distribution successful, but there was an error generating statistics: \
#{error.class}: #{error.message}, #{error.backtrace.first}"
}
}
end
# rubocop:enable Metrics/MethodLength
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize

def ama_distributed_cases_tied_to_ineligible_judges
@appeals.filter_map do |appeal|
Expand Down
21 changes: 19 additions & 2 deletions app/models/concerns/distribution_scopes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,16 @@ def genpop
OR original_judge_task.assigned_to_id in (?)",
Constants.AMA_STREAM_TYPES.court_remand,
CaseDistributionLever.cavc_affinity_days.days.ago,
JudgeTeam.judges_with_exclude_appeals_from_affinity
JudgeTeam.judge_ids_with_exclude_appeals_from_affinity
)
end

def genpop_by_affinity_start_date
with_appeal_affinities
.with_original_appeal_and_judge_task
.where(
"appeal_affinities.affinity_start_date <= ?",
CaseDistributionLever.cavc_affinity_days.days.ago
)
end

Expand Down Expand Up @@ -89,6 +98,14 @@ def non_genpop_for_judge(judge)
.where(original_judge_task: { assigned_to_id: judge&.id })
end

def non_genpop_by_affinity_start_date
with_appeal_affinities
.with_original_appeal_and_judge_task
.where("appeal_affinities.affinity_start_date > ? or appeal_affinities.affinity_start_date is null",
CaseDistributionLever.cavc_affinity_days.days.ago)
.where.not(original_judge_task: { assigned_to_id: nil })
end

def ordered_by_distribution_ready_date
joins(:tasks)
.group("appeals.id")
Expand Down Expand Up @@ -134,7 +151,7 @@ def tied_to_ineligible_judge

def tied_to_judges_with_exclude_appeals_from_affinity
with_appeal_affinities
.where(hearings: { disposition: "held", judge_id: JudgeTeam.judges_with_exclude_appeals_from_affinity })
.where(hearings: { disposition: "held", judge_id: JudgeTeam.judge_ids_with_exclude_appeals_from_affinity })
end

# If an appeal has exceeded the affinity, it should be returned to genpop.
Expand Down
6 changes: 5 additions & 1 deletion app/models/decision_review.rb
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,11 @@ def veteran_full_name
end

def number_of_issues
request_issues.active.count
request_issues.count(&:active?)
end

def issue_categories
request_issues.select(&:active?).map(&:nonrating_issue_category)
end

def external_id
Expand Down
Loading

0 comments on commit ce63551

Please sign in to comment.