Skip to content

Commit

Permalink
APPEALS-23420
Browse files Browse the repository at this point in the history
  Add search query service for the api response for the `/search` page
  • Loading branch information
ryanpmessner committed Aug 7, 2024
1 parent 3367fbe commit e3a8da4
Show file tree
Hide file tree
Showing 27 changed files with 1,508 additions and 99 deletions.
4 changes: 2 additions & 2 deletions app/controllers/idt/api/v2/appeals_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ def details
result = if docket_number?(case_search)
CaseSearchResultsForDocketNumber.new(
docket_number: case_search, user: current_user
).call
).api_call
else
CaseSearchResultsForVeteranFileNumber.new(
file_number_or_ssn: case_search, user: current_user
).call
).api_call
end

render_search_results_as_json(result)
Expand Down
12 changes: 9 additions & 3 deletions app/decorators/appeal_status_api_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
# Extends the Appeal model with methods for the Appeals Status API

class AppealStatusApiDecorator < ApplicationDecorator
def initialize(appeal, scheduled_hearing = nil)
super(appeal)

@scheduled_hearing = scheduled_hearing
end

def appeal_status_id
"A#{id}"
end
Expand Down Expand Up @@ -162,19 +168,19 @@ def remanded_sc_decision_issues
end

def open_pre_docket_task?
tasks.open.any? { |task| task.is_a?(PreDocketTask) }
open_tasks.any? { |task| task.is_a?(PreDocketTask) }
end

def pending_schedule_hearing_task?
tasks.open.where(type: ScheduleHearingTask.name).any?
pending_schedule_hearing_tasks.any?
end

def hearing_pending?
scheduled_hearing.present?
end

def evidence_submission_hold_pending?
tasks.open.where(type: EvidenceSubmissionWindowTask.name).any?
evidence_submission_hold_pending_tasks.any?
end

def at_vso?
Expand Down
16 changes: 14 additions & 2 deletions app/models/appeal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,18 @@ def decorated_with_status
AppealStatusApiDecorator.new(self)
end

def open_tasks
tasks.open
end

def pending_schedule_hearing_tasks
tasks.open.where(type: ScheduleHearingTask.name)
end

def evidence_submission_hold_pending_tasks
tasks.open.where(type: EvidenceSubmissionWindowTask.name)
end

# :reek:RepeatedConditionals
def active_request_issues_or_decision_issues
decision_issues.empty? ? active_request_issues : fetch_all_decision_issues
Expand Down Expand Up @@ -629,7 +641,7 @@ def direct_review_docket?
end

def active?
tasks.open.of_type(:RootTask).any?
open_tasks.of_type(:RootTask).any?
end

def ready_for_distribution?
Expand Down Expand Up @@ -744,7 +756,7 @@ def substitutions
end

def status
@status ||= BVAAppealStatus.new(appeal: self)
@status ||= BVAAppealStatus.new(tasks: tasks)
end

def previously_selected_for_quality_review
Expand Down
6 changes: 5 additions & 1 deletion app/models/task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ class << self; undef_method :open; end
# Equivalent to .reject(&:hide_from_queue_table_view) but offloads that to the database.
scope :visible_in_queue_table_view, lambda {
where.not(
type: Task.descendants.select(&:hide_from_queue_table_view).map(&:name)
type: hidden_task_classes
)
}

Expand Down Expand Up @@ -138,6 +138,10 @@ class << self
# With taks that are likely to need Reader to complete
READER_PRIORITY_TASK_TYPES = [JudgeAssignTask.name, JudgeDecisionReviewTask.name].freeze

def hidden_task_classes
Task.descendants.select(&:hide_from_queue_table_view).map(&:name)
end

def reader_priority_task_types
READER_PRIORITY_TASK_TYPES
end
Expand Down
2 changes: 1 addition & 1 deletion app/models/tasks/evidence_submission_window_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class EvidenceSubmissionWindowTask < Task

before_validation :set_assignee

def initialize(args)
def initialize(args = {})
@end_date = args&.fetch(:end_date, nil)
super(args&.except(:end_date))
end
Expand Down
75 changes: 29 additions & 46 deletions app/services/bva_appeal_status.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Determine the BVA workflow status of an Appeal (symbol and string) based on its Tasks.

class BVAAppealStatus
attr_reader :status
attr_reader :status, :tasks

SORT_KEYS = {
not_distributed: 1,
Expand Down Expand Up @@ -69,8 +69,18 @@ def attorney_task_names
end
end

def initialize(appeal:)
@appeal = appeal
Tasks = Struct.new(
:open,
:active,
:in_progress,
:cancelled,
:completed,
:assigned,
keyword_init: true
)

def initialize(tasks:)
@tasks = tasks
@status = compute
end

Expand All @@ -86,15 +96,12 @@ def to_i
SORT_KEYS[status]
end

def as_json(_args)
def as_json(_args = nil)
to_sym
end

private

attr_reader :appeal

delegate :tasks, to: :appeal
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength
def compute
if open_pre_docket_task?
Expand All @@ -113,7 +120,7 @@ def compute
:ready_for_signature
elsif active_sign_task?
:signed
elsif completed_dispatch_task? && open_tasks.empty?
elsif completed_dispatch_task? && tasks.open.empty?
:dispatched
elsif completed_dispatch_task?
:post_dispatch
Expand All @@ -133,84 +140,60 @@ def compute
end
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/MethodLength

def open_tasks
@open_tasks ||= tasks.open
end

def active_tasks
@active_tasks ||= tasks.active
end

def assigned_tasks
@assigned_tasks ||= tasks.assigned
end

def in_progress_tasks
@in_progress_tasks ||= tasks.in_progress
end

def cancelled_tasks
@cancelled_tasks ||= tasks.cancelled
end

def completed_tasks
@completed_tasks ||= tasks.completed
end

def open_pre_docket_task?
open_tasks.any? { |task| task.is_a?(PreDocketTask) }
tasks.open.any? { |task| task.type == "PreDocketTask" }
end

def open_distribution_task?
open_tasks.any? { |task| task.is_a?(DistributionTask) }
tasks.open.any? { |task| task.type == "DistributionTask" }
end

def open_timed_hold_task?
open_tasks.any? { |task| task.is_a?(TimedHoldTask) }
tasks.open.any? { |task| task.type == "TimedHoldTask" }
end

def active_judge_assign_task?
active_tasks.any? { |task| task.is_a?(JudgeAssignTask) }
tasks.active.any? { |task| task.type == "JudgeAssignTask" }
end

def assigned_attorney_task?
assigned_tasks.any? { |task| self.class.attorney_task_names.include?(task.type) }
tasks.assigned.any? { |task| self.class.attorney_task_names.include?(task.type) }
end

def active_colocated_task?
active_tasks.any? { |task| self.class.colocated_task_names.include?(task.type) }
tasks.active.any? { |task| self.class.colocated_task_names.include?(task.type) }
end

def attorney_task_in_progress?
in_progress_tasks.any? { |task| self.class.attorney_task_names.include?(task.type) }
tasks.in_progress.any? { |task| self.class.attorney_task_names.include?(task.type) }
end

def active_judge_decision_review_task?
active_tasks.any? { |task| task.is_a?(JudgeDecisionReviewTask) }
tasks.active.any? { |task| task.type == "JudgeDecisionReviewTask" }
end

def active_sign_task?
active_tasks.any? { |task| %w[BvaDispatchTask QualityReviewTask].include?(task.type) }
tasks.active.any? { |task| %w[BvaDispatchTask QualityReviewTask].include?(task.type) }
end

def completed_dispatch_task?
completed_tasks.any? { |task| task.is_a?(BvaDispatchTask) }
tasks.completed.any? { |task| task.type == "BvaDispatchTask" }
end

def docket_switched?
# TODO: this should be updated to check that there are no active tasks once the task handling is implemented
completed_tasks.any? { |task| task.is_a?(DocketSwitchGrantedTask) }
tasks.completed.any? { |task| task.type == "DocketSwitchGrantedTask" }
end

def cancelled_root_task?
cancelled_tasks.any? { |task| task.is_a?(RootTask) }
tasks.cancelled.any? { |task| task.type == "RootTask" }
end

def misc_task?
active_tasks.any? { |task| self.class.misc_task_names.include?(task.type) }
tasks.active.any? { |task| self.class.misc_task_names.include?(task.type) }
end

def active_specialty_case_team_assign_task?
active_tasks.any? { |task| task.is_a?(SpecialtyCaseTeamAssignTask) }
tasks.active.any? { |task| task.type == "SpecialtyCaseTeamAssignTask" }
end
end
69 changes: 69 additions & 0 deletions app/services/search_query_service.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# frozen_string_literal: true

class SearchQueryService
def initialize(file_number: nil, docket_number: nil)
@docket_number = docket_number
@file_number = file_number
@queries = SearchQueryService::Query.new
end

def search_by_veteran_file_number
search_results.map do |row|
if row["type"] != "legacy_appeal"
AppealRow.new(row).search_response
else
vacols_row = vacols_results.find { |result| result["vacols_id"] == row["external_id"] }
LegacyAppealRow.new(row, vacols_row).search_response
end
end
end

def search_by_docket_number
results = ActiveRecord::Base.connection.exec_query(
sanitize([queries.docket_number_query, docket_number])
)

results.map do |row|
AppealRow.new(row).search_response
end
end

private

attr_reader :docket_number, :file_number, :queries

def vacols_ids
legacy_results.map { |result| result["external_id"] }
end

def legacy_results
search_results.select { |result| result["type"] == "legacy_appeal" }
end

def search_results
@search_results = ActiveRecord::Base
.connection
.exec_query(file_number_or_ssn_query)
.uniq { |result| result["external_id"] }
end

def file_number_or_ssn_query
sanitize(
[
queries.veteran_file_number_query,
*[file_number].cycle(queries.veteran_file_number_num_params).to_a
]
)
end

def vacols_results
@vacols_results ||= begin
vacols_query = VACOLS::Record.sanitize_sql_array([queries.vacols_query, vacols_ids])
VACOLS::Record.connection.exec_query(vacols_query)
end
end

def sanitize(values)
ActiveRecord::Base.sanitize_sql_array(values)
end
end
3 changes: 3 additions & 0 deletions app/services/search_query_service/api_response.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# frozen_string_literal: true

SearchQueryService::ApiResponse = Struct.new(:id, :type, :attributes, keyword_init: true)
Loading

0 comments on commit e3a8da4

Please sign in to comment.