Skip to content

Commit

Permalink
Merge branch 'master' into hschallhorn/14604-priority-only-distribution
Browse files Browse the repository at this point in the history
  • Loading branch information
hschallhorn committed Jul 21, 2020
2 parents 78e9e7a + 8189189 commit 463d33c
Show file tree
Hide file tree
Showing 142 changed files with 174,982 additions and 7,363 deletions.
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ gem "aasm", "4.11.0"
gem "activerecord-import"
gem "acts_as_tree"
# BGS
gem "bgs", git: "https://github.com/department-of-veterans-affairs/ruby-bgs.git", ref: "eb402ebd17eb39cd13df3c21d749e1b598676324"
gem "bgs", git: "https://github.com/department-of-veterans-affairs/ruby-bgs.git", ref: "21e2c4ac87be8a340073ceea403a685154df2f8f"
# Bootsnap speeds up app boot (and started to be a default gem in 5.2).
gem "bootsnap", require: false
gem "business_time", "~> 0.9.3"
Expand Down
6 changes: 3 additions & 3 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ GIT

GIT
remote: https://github.com/department-of-veterans-affairs/ruby-bgs.git
revision: eb402ebd17eb39cd13df3c21d749e1b598676324
ref: eb402ebd17eb39cd13df3c21d749e1b598676324
revision: 21e2c4ac87be8a340073ceea403a685154df2f8f
ref: 21e2c4ac87be8a340073ceea403a685154df2f8f
specs:
bgs (0.2)
httpclient
Expand Down Expand Up @@ -552,7 +552,7 @@ GEM
sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3)
savon (2.12.0)
savon (2.12.1)
akami (~> 1.2)
builder (>= 2.1.2)
gyoku (~> 1.2)
Expand Down
3 changes: 3 additions & 0 deletions app/controllers/legacy_tasks_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ def update

return invalid_record_error(task) unless task.valid?

# Remove overtime status of an appeal when reassigning to another attorney
appeal.overtime = false if appeal.overtime?

render json: {
task: json_task(AttorneyLegacyTask.from_vacols(
task.last_case_assignment,
Expand Down
2 changes: 1 addition & 1 deletion app/jobs/fetch_hearing_locations_for_veterans_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class FetchHearingLocationsForVeteransJob < ApplicationJob
queue_with_priority :low_priority
application_attr :hearing_schedule

QUERY_LIMIT = 500
QUERY_LIMIT = 750
def create_schedule_hearing_tasks
AppealRepository.create_schedule_hearing_tasks
end
Expand Down
6 changes: 3 additions & 3 deletions app/jobs/virtual_hearings/create_conference_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,16 @@ class VirtualHearingNotCreatedError < StandardError; end
)
end

retry_on(IncompleteError, attempts: 5) do |job, exception|
retry_on(IncompleteError, attempts: 10, wait: :exponentially_longer) do |job, exception|
Rails.logger.error("#{job.class.name} (#{job.job_id}) failed with error: #{exception}")
end

retry_on(VirtualHearingNotCreatedError, attempts: 5) do |job, exception|
retry_on(VirtualHearingNotCreatedError, attempts: 10, wait: :exponentially_longer) do |job, exception|
Rails.logger.error("#{job.class.name} (#{job.job_id}) failed with error: #{exception}")
end

# Retry if Pexip returns an invalid response.
retry_on Caseflow::Error::PexipApiError, attempts: 5 do |job, exception|
retry_on(Caseflow::Error::PexipApiError, attempts: 10, wait: :exponentially_longer) do |job, exception|
Rails.logger.error("#{job.class.name} (#{job.job_id}) failed with error: #{exception}")

kwargs = job.arguments.first
Expand Down
7 changes: 6 additions & 1 deletion app/jobs/virtual_hearings/delete_conferences_job.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# frozen_string_literal: true

##
# Job that deletes the pexip conference resource if the hearing was held or
# if the hearing type is switched from virtual to original hearing type.
# It also sends cancellation emails to hearing participants if latter is case.

class VirtualHearings::DeleteConferencesJob < VirtualHearings::ConferenceJob
queue_with_priority :low_priority
application_attr :hearing_schedule
Expand All @@ -15,7 +20,7 @@ class EmailsFailedToSend < StandardError; end
)
end

retry_on(DeleteConferencesJobFailure, attempts: 5) do |job, exception|
retry_on(DeleteConferencesJobFailure, attempts: 5, wait: :exponentially_longer) do |job, exception|
Rails.logger.error("#{job.class.name} (#{job.job_id}) failed with error: #{exception}")

extra = {
Expand Down
2 changes: 1 addition & 1 deletion app/mappers/hearing_mapper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def notes_to_vacols_format(value)
return if value.nil?
fail(InvalidNotesError) if !value.is_a?(String)

value[0, 100]
value[0, 1000]
end

def disposition_to_vacols_format(value, keys)
Expand Down
36 changes: 30 additions & 6 deletions app/models/appeal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,9 @@ def assigned_to_location
decorated_with_status.fetch_status.to_s.titleize
end

def program
decorated_with_status.program
end
delegate :program, to: :decorated_with_status

def distributed_to_a_judge?
decorated_with_status.distributed_to_a_judge?
end
delegate :distributed_to_a_judge?, to: :decorated_with_status

def decorated_with_status
AppealStatusApiDecorator.new(self)
Expand Down Expand Up @@ -296,6 +292,34 @@ def advanced_on_docket?
:state,
:email_address, to: :appellant, prefix: true, allow_nil: true

def appellant_tz
return if address.blank?

# Use an address object if this is a hash
appellant_address = address.is_a?(Hash) ? Address.new(address) : address

begin
TimezoneService.address_to_timezone(appellant_address).identifier
rescue StandardError => error
log_error(error)
nil
end
end

def representative_tz
return if representative_address.blank?

# Use an address object if this is a hash
rep_address = representative_address.is_a?(Hash) ? Address.new(representative_address) : representative_address

begin
TimezoneService.address_to_timezone(rep_address).identifier
rescue StandardError => error
log_error(error)
nil
end
end

def appellant_middle_initial
appellant_middle_name&.first
end
Expand Down
13 changes: 13 additions & 0 deletions app/models/attorney_claimant.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,17 @@
# An attorney can be a claimant when contesting attorney fees.

class AttorneyClaimant < Claimant
delegate :name, to: :bgs_attorney

private

def find_power_of_attorney
find_power_of_attorney_by_pid
end

def bgs_attorney
@bgs_attorney ||= begin
BgsAttorney.find_by_participant_id(participant_id)
end
end
end
22 changes: 22 additions & 0 deletions app/models/bgs_related_claimant.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

class BgsRelatedClaimant < Claimant
include AssociatedBgsRecord

def fetch_bgs_record
general_info = bgs.fetch_claimant_info_by_participant_id(participant_id)
name_info = bgs.fetch_person_info(participant_id)

general_info.merge(name_info)
end

def bgs_payee_code
return unless bgs_record

bgs_record[:payee_code]
end

def bgs_record
@bgs_record ||= try_and_retry_bgs_record
end
end
20 changes: 0 additions & 20 deletions app/models/claimant.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,11 @@
# The Claimant model associates a claimant to a decision review.

class Claimant < CaseflowRecord
include AssociatedBgsRecord
include HasDecisionReviewUpdatedSince

belongs_to :decision_review, polymorphic: true
belongs_to :person, primary_key: :participant_id, foreign_key: :participant_id

bgs_attr_accessor :relationship

validate { |claimant| ClaimantValidator.new(claimant).validate }
validates :participant_id,
uniqueness: { scope: [:decision_review_id, :decision_review_type],
Expand Down Expand Up @@ -63,23 +60,6 @@ def person
:zip,
to: :bgs_address_service

def fetch_bgs_record
general_info = bgs.fetch_claimant_info_by_participant_id(participant_id)
name_info = bgs.fetch_person_info(participant_id)

general_info.merge(name_info)
end

def bgs_payee_code
return unless bgs_record

bgs_record[:payee_code]
end

def bgs_record
@bgs_record ||= try_and_retry_bgs_record
end

private

def find_power_of_attorney
Expand Down
3 changes: 2 additions & 1 deletion app/models/dependent_claimant.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
##
# Dependent claimants are when the veteran's child, spouse, or parent are listed as a decision review's claimant.

class DependentClaimant < Claimant
class DependentClaimant < BgsRelatedClaimant
bgs_attr_accessor :relationship
end
29 changes: 26 additions & 3 deletions app/models/hearing.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# frozen_string_literal: true

##
# The Veteran/Appellant, often with a representative, has a hearing with a Veterans Law Judge(VLJ) to
# provide additional details for their appeal. In this case the appeal is an AMA Appeal meaning it was filed
# after Appeals Improvement and Modernization Act (AMA) was passed.
#
# If the veterans/appellants opt in to have a hearing for their appeal process, an open ScheduleHearingTask is
# created to track the the status of hearings. Hearings are created when a hearing coordinator
# schedules the veteran/apellant for a hearing by completing the open ScheduleHearingTask.
#
# There are four types of hearings: travel board, in-person (also known as Central), video and virtual. Unlike the
# other types, virtual type has VirtualHearing model which tracks additional details about virtual conference
# and emails. Travel board hearings are only worked on in VACOLS.
#
# Hearings have a nil disposition unless the hearing is held, cancelled, postponed or the veteran/appellant
# does not show up for their hearing. AssignHearingDispositionTask is created after hearing has passed
# and allows users to set the disposition.
#
# A HearingDay organizes hearings by regional office and a room. Hearing has a HearingLocation where the
# hearing will place as well as a Trascription which is the trascribed record of the hearing if hearing was held.
# If a hearing is virtual then it has EmailEvents which is a record of virtual hearing emails sent to
# different recipients.

class Hearing < CaseflowRecord
include HasHearingTask
include HasVirtualHearing
Expand Down Expand Up @@ -28,9 +50,10 @@ class HearingDayFull < StandardError; end

UUID_REGEX = /^\h{8}-\h{4}-\h{4}-\h{4}-\h{12}$/.freeze

delegate :appellant_first_name, :appellant_last_name, :appellant_address_line_1,
:appellant_city, :appellant_state, :appellant_zip, :appellant_email_address,
:veteran_age, :veteran_gender, :veteran_first_name, :veteran_last_name, :veteran_file_number,
delegate :appellant_first_name, :appellant_last_name, :representative_address,
:appellant_city, :appellant_state, :appellant_zip, :appellant_address_line_1,
:appellant_email_address, :appellant_tz, :representative_tz, :veteran_age,
:veteran_gender, :veteran_first_name, :veteran_last_name, :veteran_file_number,
:veteran_email_address, :docket_number, :docket_name, :request_issues, :decision_issues,
:available_hearing_locations, :closest_regional_office, :advanced_on_docket?,
to: :appeal
Expand Down
27 changes: 23 additions & 4 deletions app/models/hearing_day.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,28 @@
# frozen_string_literal: true

# Class to coordinate interactions between controller
# and repository class. Eventually may persist data to
# Caseflow DB. For now all schedule data is sent to the
# VACOLS DB (Aug 2018 implementation).
##
# HearingDay groups hearings, both AMA and legacy, by a regional office and a room at the BVA.
# Hearing Admin can create a HearingDay either individually or in bulk at the begining of
# each year by uploading bunch of spreadsheets.
#
# Each HearingDay has a request type which applies to all hearings associated for that day.
# Request types:
# 'V' (also known as video hearing):
# The veteran/appellant travels to a regional office to have a hearing through video conference
# with a VLJ (Veterans Law Judge) who joins from the board at Washington D.C.
# 'C' (also known as Central):
# The veteran/appellant travels to the board in D.C to have a in-person hearing with the VLJ.
# 'T' (also known as travel board)
# The VLJ travels to the the Veteran/Appellant's closest regional office to conduct the hearing.
#
# If the request type is video('V'), then the HearingDay has a regional office associated.
# Currently, a video hearing can be switched to a virtual hearing represented by VirtualHearing.
#
# Each HearingDay has a maximum number of hearings that can be held which is either based on the
# timezone of associated regional office or 12 if the request type is central('C).
#
# A HearingDay can be assigned to a judge.

class HearingDay < CaseflowRecord
include UpdatedByUserConcern

Expand Down
4 changes: 4 additions & 0 deletions app/models/hearing_location.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# frozen_string_literal: true

##
# HearingLocation is created for a Hearing/LegacyHearing when the coordinator schedules
# the veteran/appellant for hearing for a location from a list of AvailableHearingLocations.

class HearingLocation < CaseflowRecord
belongs_to :hearing, polymorphic: true

Expand Down
6 changes: 6 additions & 0 deletions app/models/hearings/available_hearing_locations.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# frozen_string_literal: true

##
# FetchHearingLocationsForVeteransJob creates a list of hearing locations based on the
# proximity to veteran/appellant's physical location and stores them as
# AvailableHearingLocations for an appeal. From this list, a hearing coordinator chooses
# a location to schedule the veteran/appellant for.

class AvailableHearingLocations < CaseflowRecord
include HasAppealUpdatedSince

Expand Down
15 changes: 11 additions & 4 deletions app/models/hearings/forms/base_hearing_update_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,15 @@ def should_create_or_update_virtual_hearing?
)
end

def only_time_updated?
!virtual_hearing_created? && scheduled_time_string.present?
def only_time_updated_or_timezone_updated?
(!virtual_hearing_created? &&
scheduled_time_string.present? ||
# Also send virtual hearing time updates if the representative timezone is changed
(virtual_hearing_attributes&.dig(:representative_tz).present? &&
virtual_hearing_attributes&.dig(:representative_email).blank?) ||
(virtual_hearing_attributes&.dig(:appellant_tz).present? &&
virtual_hearing_attributes&.dig(:appellant_email).blank?)
)
end

def start_async_job?
Expand Down Expand Up @@ -123,7 +130,7 @@ def start_activate_job
hearing_type: hearing.class.name,
# TODO: Ideally, this would use symbols, but symbols can't be serialized for ActiveJob.
# Rails 6 supports passing symbols to a job.
email_type: only_time_updated? ? "updated_time_confirmation" : "confirmation"
email_type: only_time_updated_or_timezone_updated? ? "updated_time_confirmation" : "confirmation"
}

if run_async?
Expand Down Expand Up @@ -247,7 +254,7 @@ def change_type
"CHANGED_TO_VIRTUAL"
elsif virtual_hearing_cancelled?
"CHANGED_FROM_VIRTUAL"
elsif only_time_updated?
elsif only_time_updated_or_timezone_updated?
"CHANGED_HEARING_TIME"
elsif only_emails_updated?
email_change_type
Expand Down
4 changes: 4 additions & 0 deletions app/models/hearings/sent_hearing_email_event.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# frozen_string_literal: true

##
# Model to track the history of virtual hearing emails sent out hearing
# recipients (judge, representative, appellant).

class SentHearingEmailEvent < CaseflowRecord
belongs_to :hearing, polymorphic: true
belongs_to :sent_by, class_name: "User"
Expand Down
Loading

0 comments on commit 463d33c

Please sign in to comment.