diff --git a/app/controllers/api/docs/v3/decision_reviews.yaml b/app/controllers/api/docs/v3/decision_reviews.yaml
index abae92dba7f..7040bb12ac4 100644
--- a/app/controllers/api/docs/v3/decision_reviews.yaml
+++ b/app/controllers/api/docs/v3/decision_reviews.yaml
@@ -914,10 +914,14 @@ paths:
parameters:
- name: X-VA-SSN
in: header
- required: true
- description: The SSN of the veteran.
+ description: The SSN of the veteran. Either SSN or file number must be passed.
schema:
type : string
+ - name: X-VA-File-Number
+ in: header
+ description: The file number of the veteran. Either SSN or file number must be passed.
+ schema:
+ type: string
- name: X-VA-Receipt-Date
in: header
required: true
diff --git a/app/controllers/api/v3/base_controller.rb b/app/controllers/api/v3/base_controller.rb
index fc4216988dc..49b88fe6c6b 100644
--- a/app/controllers/api/v3/base_controller.rb
+++ b/app/controllers/api/v3/base_controller.rb
@@ -10,22 +10,6 @@ def status_from_errors(errors)
end
protect_from_forgery with: :null_session
- before_action :api_released?
-
- def api_released?
- return true if FeatureToggle.enabled?(:api_v3)
-
- render json: {
- errors: [
- {
- status: "501",
- title: "Not Implemented",
- detail: "This endpoint is not yet supported."
- }
- ]
- },
- status: :not_implemented
- end
def render_errors(errors)
errors = Array.wrap(errors)
diff --git a/app/controllers/api/v3/decision_reviews/appeals/contestable_issues_controller.rb b/app/controllers/api/v3/decision_reviews/appeals/contestable_issues_controller.rb
index f8ca2785544..b5c5193d38a 100644
--- a/app/controllers/api/v3/decision_reviews/appeals/contestable_issues_controller.rb
+++ b/app/controllers/api/v3/decision_reviews/appeals/contestable_issues_controller.rb
@@ -5,6 +5,12 @@ module V3
module DecisionReviews
module Appeals
class ContestableIssuesController < BaseContestableIssuesController
+ include ApiV3FeatureToggleConcern
+
+ before_action only: [:index] do
+ api_released?(:api_v3_appeals_contestable_issues)
+ end
+
private
def standin_decision_review
diff --git a/app/controllers/api/v3/decision_reviews/appeals_controller.rb b/app/controllers/api/v3/decision_reviews/appeals_controller.rb
index fb80236b4a6..51b48ee4efb 100644
--- a/app/controllers/api/v3/decision_reviews/appeals_controller.rb
+++ b/app/controllers/api/v3/decision_reviews/appeals_controller.rb
@@ -1,6 +1,12 @@
# frozen_string_literal: true
class Api::V3::DecisionReviews::AppealsController < Api::V3::BaseController
+ include ApiV3FeatureToggleConcern
+
+ before_action do
+ api_released?(:api_v3_appeals)
+ end
+
# stub
def create
render json: {}, status: :not_found
diff --git a/app/controllers/api/v3/decision_reviews/base_contestable_issues_controller.rb b/app/controllers/api/v3/decision_reviews/base_contestable_issues_controller.rb
index 37d3f0ef4be..f95f71b939b 100644
--- a/app/controllers/api/v3/decision_reviews/base_contestable_issues_controller.rb
+++ b/app/controllers/api/v3/decision_reviews/base_contestable_issues_controller.rb
@@ -41,17 +41,32 @@ def validate_params
end
def veteran_valid?
- unless veteran_ssn_is_formatted_correctly?
+ if veteran_ssn.present? && !veteran_ssn_is_formatted_correctly?
render_invalid_veteran_ssn
return false
end
- unless veteran
+ if veteran_identifier.nil?
+ render_missing_headers
+ return false
+ end
+ unless veteran.present? && veteran_matches
render_veteran_not_found
return false
end
true
end
+ def veteran_matches
+ if veteran_ssn.present? && veteran_ssn != veteran.ssn
+ return false
+ end
+ if veteran_file_number.present? && veteran_file_number != veteran.file_number
+ return false
+ end
+
+ true
+ end
+
def receipt_date_valid?
unless receipt_date.is_a? Date
render_invalid_receipt_date
@@ -69,11 +84,19 @@ def receipt_date_valid?
end
def veteran
- @veteran ||= VeteranFinder.find_best_match veteran_ssn
+ @veteran ||= VeteranFinder.find_best_match veteran_identifier
end
def veteran_ssn
- @veteran_ssn ||= request.headers["X-VA-SSN"].to_s.strip
+ @veteran_ssn ||= request.headers["X-VA-SSN"].presence&.strip
+ end
+
+ def veteran_file_number
+ @veteran_file_number ||= request.headers["X-VA-File-Number"].presence&.strip
+ end
+
+ def veteran_identifier
+ veteran_file_number || veteran_ssn
end
def veteran_ssn_is_formatted_correctly?
@@ -97,6 +120,14 @@ def render_veteran_not_found
)
end
+ def render_missing_headers
+ render_errors(
+ status: 422,
+ code: :missing_identifying_headers,
+ title: "Veteran file number or SSN header is required"
+ )
+ end
+
def receipt_date
@receipt_date ||= begin
Date.iso8601 receipt_date_header
diff --git a/app/controllers/api/v3/decision_reviews/higher_level_reviews/contestable_issues_controller.rb b/app/controllers/api/v3/decision_reviews/higher_level_reviews/contestable_issues_controller.rb
index bd8ec14fd7b..213fd515306 100644
--- a/app/controllers/api/v3/decision_reviews/higher_level_reviews/contestable_issues_controller.rb
+++ b/app/controllers/api/v3/decision_reviews/higher_level_reviews/contestable_issues_controller.rb
@@ -5,6 +5,12 @@ module V3
module DecisionReviews
module HigherLevelReviews
class ContestableIssuesController < BaseContestableIssuesController
+ include ApiV3FeatureToggleConcern
+
+ before_action only: [:index] do
+ api_released?(:api_v3_higher_level_reviews_contestable_issues)
+ end
+
private
def standin_decision_review
diff --git a/app/controllers/api/v3/decision_reviews/higher_level_reviews_controller.rb b/app/controllers/api/v3/decision_reviews/higher_level_reviews_controller.rb
index 0f6988f8eed..75c6d4db304 100644
--- a/app/controllers/api/v3/decision_reviews/higher_level_reviews_controller.rb
+++ b/app/controllers/api/v3/decision_reviews/higher_level_reviews_controller.rb
@@ -1,6 +1,12 @@
# frozen_string_literal: true
class Api::V3::DecisionReviews::HigherLevelReviewsController < Api::V3::BaseController
+ include ApiV3FeatureToggleConcern
+
+ before_action do
+ api_released?(:api_v3_higher_level_reviews)
+ end
+
SUCCESSFUL_CREATION_HTTP_STATUS = 202
def create
diff --git a/app/controllers/concerns/api_v3_feature_toggle_concern.rb b/app/controllers/concerns/api_v3_feature_toggle_concern.rb
new file mode 100644
index 00000000000..a8533d5b28a
--- /dev/null
+++ b/app/controllers/concerns/api_v3_feature_toggle_concern.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+module ApiV3FeatureToggleConcern
+ extend ActiveSupport::Concern
+
+ def api_released?(feature)
+ return true if FeatureToggle.enabled?(feature)
+
+ render json: {
+ errors: [
+ {
+ status: "501",
+ title: "Not Implemented",
+ detail: "This endpoint is not yet supported."
+ }
+ ]
+ },
+ status: :not_implemented
+ end
+end
diff --git a/app/controllers/organizations/users_controller.rb b/app/controllers/organizations/users_controller.rb
index acc0bad5e77..fe4d8d132f2 100644
--- a/app/controllers/organizations/users_controller.rb
+++ b/app/controllers/organizations/users_controller.rb
@@ -9,7 +9,7 @@ def index
render json: {
organization_name: organization.name,
- judge_team: FeatureToggle.enabled?(:judge_admin_scm) && organization.type == JudgeTeam.name,
+ judge_team: organization.type == JudgeTeam.name,
dvc_team: organization.type == DvcTeam.name,
organization_users: json_administered_users(organization_users)
}
diff --git a/app/controllers/tasks_controller.rb b/app/controllers/tasks_controller.rb
index f9a37b74511..41474e510a8 100644
--- a/app/controllers/tasks_controller.rb
+++ b/app/controllers/tasks_controller.rb
@@ -17,6 +17,8 @@ class TasksController < ApplicationController
BlockedSpecialCaseMovementTask: BlockedSpecialCaseMovementTask,
ChangeHearingDispositionTask: ChangeHearingDispositionTask,
ColocatedTask: ColocatedTask,
+ DocketSwitchDeniedTask: DocketSwitchDeniedTask,
+ DocketSwitchGrantedTask: DocketSwitchGrantedTask,
EvidenceSubmissionWindowTask: EvidenceSubmissionWindowTask,
FoiaTask: FoiaTask,
HearingAdminActionTask: HearingAdminActionTask,
@@ -109,12 +111,13 @@ def update
rescue ActiveRecord::RecordInvalid => error
invalid_record_error(error.record)
rescue AssignHearingDispositionTask::HearingAssociationMissing => error
- Raven.capture_exception(error)
+ Raven.capture_exception(error, extra: { application: "hearings" })
+
render json: {
"errors": ["title": "Missing Associated Hearing", "detail": error]
}, status: :bad_request
rescue Caseflow::Error::VirtualHearingConversionFailed => error
- Raven.capture_exception(error)
+ Raven.capture_exception(error, extra: { application: "hearings" })
render json: {
"errors": ["title": COPY::FAILED_HEARING_UPDATE, "message": error.message, "code": error.code]
diff --git a/app/jobs/update_cached_appeals_attributes_job.rb b/app/jobs/update_cached_appeals_attributes_job.rb
index b3332104108..31b07ac548f 100644
--- a/app/jobs/update_cached_appeals_attributes_job.rb
+++ b/app/jobs/update_cached_appeals_attributes_job.rb
@@ -286,20 +286,36 @@ def case_fields_for_vacols_ids(vacols_ids)
# ...
# }
VACOLS::Case.where(bfkey: vacols_ids).map do |vacols_case|
- legacy_appeal = AppealRepository.build_appeal(vacols_case) # build non-persisting legacy appeal object
+ original_request = original_hearing_request_type_for_vacols_case(vacols_case)
+ changed_request = changed_hearing_request_type_for_all_vacols_ids[vacols_case.bfkey]
+ # Replicates LegacyAppeal#current_hearing_request_type
+ current_request = HearingDay::REQUEST_TYPES.key(changed_request)&.to_sym || original_request
[
vacols_case.bfkey,
{
location: vacols_case.bfcurloc,
status: VACOLS::Case::TYPES[vacols_case.bfac],
- hearing_request_type: legacy_appeal.current_hearing_request_type(readable: true),
- former_travel: former_travel?(legacy_appeal)
+ hearing_request_type: LegacyAppeal::READABLE_HEARING_REQUEST_TYPES[current_request],
+ former_travel: original_request == :travel_board && current_request != :travel_board
}
]
end.to_h
end
+ # Gets the symbolic representation of the original type of hearing requested for a vacols case record
+ # Replicates logic in LegacyAppeal#original_hearing_request_type
+ def original_hearing_request_type_for_vacols_case(vacols_case)
+ request_type = VACOLS::Case::HEARING_REQUEST_TYPES[vacols_case.bfhr]
+
+ (request_type == :travel_board && vacols_case.bfdocind == "V") ? :video : request_type
+ end
+
+ # Maps vacols ids to their leagcy appeal's changed hearing request type
+ def changed_hearing_request_type_for_all_vacols_ids
+ @changed_hearing_request_type_for_all_vacols_ids ||= LegacyAppeal.pluck(:vacols_id, :changed_request_type).to_h
+ end
+
def issues_counts_for_vacols_folders(vacols_ids)
VACOLS::CaseIssue.where(isskey: vacols_ids).group(:isskey).count
end
@@ -322,15 +338,4 @@ def veteran_names_for_file_numbers(veteran_file_numbers)
[veteran.file_number, "#{veteran.last_name&.split(' ')&.last}, #{veteran.first_name}"]
end.to_h
end
-
- # checks to see if the hearing request type was former_travel
- def former_travel?(legacy_appeal)
- # the current request type is travel
- if legacy_appeal.current_hearing_request_type == :travel_board
- return false
- end
-
- # otherwise check if og request type was travel
- legacy_appeal.original_hearing_request_type == :travel_board
- end
end
diff --git a/app/models/cavc_remand.rb b/app/models/cavc_remand.rb
index 26bb1b25f37..0ae809a9da7 100644
--- a/app/models/cavc_remand.rb
+++ b/app/models/cavc_remand.rb
@@ -3,11 +3,12 @@
# Model to store information captured when processing a form for an appeal remanded by CAVC
class CavcRemand < CaseflowRecord
+ include UpdatedByUserConcern
+
belongs_to :created_by, class_name: "User"
- belongs_to :updated_by, class_name: "User"
belongs_to :appeal
- validates :created_by, :updated_by, :appeal, :cavc_docket_number, :represented_by_attorney, :cavc_judge_full_name,
+ validates :created_by, :appeal, :cavc_docket_number, :represented_by_attorney, :cavc_judge_full_name,
:cavc_decision_type, :decision_date, :decision_issue_ids, :instructions, presence: true
validates :remand_subtype, presence: true, if: :remand?
validates :judgement_date, :mandate_date, presence: true, unless: :mdr?
diff --git a/app/models/docket.rb b/app/models/docket.rb
index bfa2cc42ea6..de4cbfc0c80 100644
--- a/app/models/docket.rb
+++ b/app/models/docket.rb
@@ -44,7 +44,7 @@ def age_of_n_oldest_genpop_priority_appeals(num)
end
def age_of_oldest_priority_appeal
- @age_of_oldest_priority_appeal ||= appeals(priority: true, ready: true).limit(1).first.ready_for_distribution_at
+ @age_of_oldest_priority_appeal ||= appeals(priority: true, ready: true).limit(1).first&.ready_for_distribution_at
end
def oldest_priority_appeal_days_waiting
diff --git a/app/models/end_product_establishment.rb b/app/models/end_product_establishment.rb
index 4f4a71ae7a3..222e8e1f518 100644
--- a/app/models/end_product_establishment.rb
+++ b/app/models/end_product_establishment.rb
@@ -312,9 +312,10 @@ def on_decision_issue_sync_processed(processing_request_issue)
end
def status
+ ep_code = Constants::EP_CLAIM_TYPES[code]
if committed?
{
- ep_code: "#{modifier} #{Constants::EP_CLAIM_TYPES[code]['offical_label']}",
+ ep_code: "#{modifier} #{ep_code ? ep_code['offical_label'] : 'Unknown'}",
ep_status: [status_type, sync_status].compact.join(", ")
}
else
diff --git a/app/models/hearings/forms/base_hearing_update_form.rb b/app/models/hearings/forms/base_hearing_update_form.rb
index 48c27f4e1a6..6bb326a8a90 100644
--- a/app/models/hearings/forms/base_hearing_update_form.rb
+++ b/app/models/hearings/forms/base_hearing_update_form.rb
@@ -14,7 +14,7 @@ class BaseHearingUpdateForm
def update
virtual_hearing_changed = false
- ActiveRecord::Base.transaction do
+ ActiveRecord::Base.multi_transaction do
update_hearing
add_update_hearing_alert if show_update_alert?
if should_create_or_update_virtual_hearing?
diff --git a/app/models/legacy_appeal.rb b/app/models/legacy_appeal.rb
index ebc35a1ad09..32fa4554d68 100644
--- a/app/models/legacy_appeal.rb
+++ b/app/models/legacy_appeal.rb
@@ -419,6 +419,7 @@ def sanitized_changed_request_type(changed_request_type)
# values. Also, `hearing_request_type` alone can't disambiguate a video hearing
# from a travel board hearing
# This method cleans all of these issues up to return a sanitized version of the original type requested by Appellant.
+ # Replicated in UpdateCachedAppealAttributesJob#original_hearing_request_type_for_vacols_case
def original_hearing_request_type(readable: false)
original_hearing_request_type = case hearing_request_type
when :central_office
@@ -435,6 +436,7 @@ def original_hearing_request_type(readable: false)
# This method captures if a travel board hearing request type was overridden in Caseflow.
# In general, this method returns the current hearing request type which could be dervied
# from `change_request_type` or VACOLS `hearing_request_type`
+ # Replicated in UpdateCachedAppealAttributesJob#case_fields_for_vacols_ids
def current_hearing_request_type(readable: false)
current_hearing_request_type = if changed_request_type.present?
sanitized_changed_request_type(changed_request_type)
diff --git a/app/models/promulgated_rating.rb b/app/models/promulgated_rating.rb
index fcaaf7dbea5..cea50950a9b 100644
--- a/app/models/promulgated_rating.rb
+++ b/app/models/promulgated_rating.rb
@@ -82,6 +82,9 @@ def retry_fetching_rating_profile
)
matching_rating = ratings_at_issue.find { |rating| profile_date_matches(rating.profile_date) }
matching_rating.present? ? matching_rating.rating_profile : {}
+ rescue BGS::ShareError, Rating::NilRatingProfileListError => error
+ Raven.capture_exception(error)
+ {}
end
# The profile date is used as a key when fetching a rating by profile date.
diff --git a/app/models/tasks/assign_hearing_disposition_task.rb b/app/models/tasks/assign_hearing_disposition_task.rb
index 700bf74d49f..d905b99efec 100644
--- a/app/models/tasks/assign_hearing_disposition_task.rb
+++ b/app/models/tasks/assign_hearing_disposition_task.rb
@@ -69,9 +69,9 @@ def update_from_params(params, user)
payload_values = params.delete(:business_payloads)&.dig(:values)
if params[:status] == Constants.TASK_STATUSES.cancelled && payload_values[:disposition].present?
- update_hearing_and_self(params: params, payload_values: payload_values)
+ created_tasks = update_hearing_and_self(params: params, payload_values: payload_values)
- [self]
+ [self] + created_tasks
else
super(params, user)
end
@@ -82,15 +82,17 @@ def cancel!
fail HearingDispositionNotCanceled
end
- if appeal.is_a? Appeal
- EvidenceSubmissionWindowTask.find_or_create_by!(
- appeal: appeal,
- parent: hearing_task.parent,
- assigned_to: MailTeam.singleton
- )
- end
+ evidence_task = if appeal.is_a? Appeal
+ EvidenceSubmissionWindowTask.find_or_create_by!(
+ appeal: appeal,
+ parent: hearing_task.parent,
+ assigned_to: MailTeam.singleton
+ )
+ end
update!(status: Constants.TASK_STATUSES.cancelled, closed_at: Time.zone.now)
+
+ [evidence_task].compact
end
def postpone!
@@ -106,7 +108,7 @@ def no_show!
fail HearingDispositionNotNoShow
end
- NoShowHearingTask.create_with_hold(self)
+ [NoShowHearingTask.create_with_hold(self)]
end
def hold!
@@ -116,6 +118,8 @@ def hold!
if appeal.is_a?(LegacyAppeal)
update!(status: Constants.TASK_STATUSES.completed)
+
+ [] # Not creating any tasks, just updating self
else
create_transcription_and_maybe_evidence_submission_window_tasks
end
@@ -135,21 +139,25 @@ def cascade_closure_from_child_task?(_child_task)
end
def update_hearing_and_self(params:, payload_values:)
- case payload_values[:disposition]
- when Constants.HEARING_DISPOSITION_TYPES.cancelled
- mark_hearing_cancelled
- when Constants.HEARING_DISPOSITION_TYPES.held
- mark_hearing_held
- when Constants.HEARING_DISPOSITION_TYPES.no_show
- mark_hearing_no_show
- when Constants.HEARING_DISPOSITION_TYPES.postponed
- mark_hearing_postponed(
- instructions: params["instructions"],
- after_disposition_update: payload_values[:after_disposition_update]
- )
- end
+ created_tasks = case payload_values[:disposition]
+ when Constants.HEARING_DISPOSITION_TYPES.cancelled
+ mark_hearing_cancelled
+ when Constants.HEARING_DISPOSITION_TYPES.held
+ mark_hearing_held
+ when Constants.HEARING_DISPOSITION_TYPES.no_show
+ mark_hearing_no_show
+ when Constants.HEARING_DISPOSITION_TYPES.postponed
+ mark_hearing_postponed(
+ instructions: params["instructions"],
+ after_disposition_update: payload_values[:after_disposition_update]
+ )
+ else
+ fail ArgumentError, "unknown disposition"
+ end
update_with_instructions(instructions: params[:instructions]) if params[:instructions].present?
+
+ created_tasks
end
def update_hearing_disposition(disposition:)
@@ -186,7 +194,7 @@ def reschedule(hearing_day_id:, scheduled_time_string:, hearing_location: nil, v
.convert_hearing_to_virtual(new_hearing, virtual_hearing_attributes)
end
- self.class.create_assign_hearing_disposition_task!(appeal, new_hearing_task, new_hearing)
+ [new_hearing_task, self.class.create_assign_hearing_disposition_task!(appeal, new_hearing_task, new_hearing)]
end
end
@@ -234,6 +242,8 @@ def reschedule_or_schedule_later(instructions: nil, after_disposition_update:)
with_admin_action_klass: after_disposition_update[:with_admin_action_klass],
admin_action_instructions: after_disposition_update[:admin_action_instructions]
)
+ else
+ fail ArgumentError, "unknown disposition action"
end
end
@@ -245,20 +255,33 @@ def schedule_later(instructions: nil, with_admin_action_klass: nil, admin_action
instructions: instructions.present? ? [instructions] : nil,
parent: new_hearing_task
)
- if with_admin_action_klass.present?
- with_admin_action_klass.constantize.create!(
- appeal: appeal,
- assigned_to: HearingsManagement.singleton,
- instructions: admin_action_instructions.present? ? [admin_action_instructions] : nil,
- parent: schedule_task
- )
- end
+ admin_action_task = if with_admin_action_klass.present?
+ with_admin_action_klass.constantize.create!(
+ appeal: appeal,
+ assigned_to: HearingsManagement.singleton,
+ instructions: admin_action_instructions.present? ? [admin_action_instructions] : nil,
+ parent: schedule_task
+ )
+ end
+
+ [new_hearing_task, schedule_task, admin_action_task].compact
end
def create_transcription_and_maybe_evidence_submission_window_tasks
- TranscriptionTask.create!(appeal: appeal, parent: self, assigned_to: TranscriptionTeam.singleton)
- unless hearing&.evidence_window_waived
- EvidenceSubmissionWindowTask.create!(appeal: appeal, parent: self, assigned_to: MailTeam.singleton)
- end
+ transcription_task = TranscriptionTask.create!(
+ appeal: appeal,
+ parent: self,
+ assigned_to: TranscriptionTeam.singleton
+ )
+
+ evidence_task = unless hearing&.evidence_window_waived
+ EvidenceSubmissionWindowTask.create!(
+ appeal: appeal,
+ parent: self,
+ assigned_to: MailTeam.singleton
+ )
+ end
+
+ [transcription_task, evidence_task].compact
end
end
diff --git a/app/models/tasks/docket_switch/docket_switch_denied_task.rb b/app/models/tasks/docket_switch/docket_switch_denied_task.rb
new file mode 100644
index 00000000000..3a0273ddbb7
--- /dev/null
+++ b/app/models/tasks/docket_switch/docket_switch_denied_task.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class DocketSwitchDeniedTask < AttorneyTask
+ def available_actions(user)
+ actions = super(user)
+
+ if ClerkOfTheBoard.singleton.user_has_access?(user)
+ if assigned_to.is_a?(User) && FeatureToggle.enabled?(:docket_change, user: user)
+ actions.push(Constants.TASK_ACTIONS.DOCKET_SWITCH_DENIED.to_h)
+ end
+ end
+
+ actions
+ end
+
+ class << self
+ def label
+ COPY::DOCKET_SWITCH_DENIED_TASK_LABEL
+ end
+ end
+end
diff --git a/app/models/tasks/docket_switch/docket_switch_granted_task.rb b/app/models/tasks/docket_switch/docket_switch_granted_task.rb
new file mode 100644
index 00000000000..eedfa5c2a6c
--- /dev/null
+++ b/app/models/tasks/docket_switch/docket_switch_granted_task.rb
@@ -0,0 +1,21 @@
+# frozen_string_literal: true
+
+class DocketSwitchGrantedTask < AttorneyTask
+ def available_actions(user)
+ actions = super(user)
+
+ if ClerkOfTheBoard.singleton.user_has_access?(user)
+ if assigned_to.is_a?(User) && FeatureToggle.enabled?(:docket_change, user: user)
+ actions.push(Constants.TASK_ACTIONS.DOCKET_SWITCH_GRANTED.to_h)
+ end
+ end
+
+ actions
+ end
+
+ class << self
+ def label
+ COPY::DOCKET_SWITCH_GRANTED_TASK_LABEL
+ end
+ end
+end
diff --git a/app/models/tasks/docket_switch_mail_task.rb b/app/models/tasks/docket_switch/docket_switch_mail_task.rb
similarity index 100%
rename from app/models/tasks/docket_switch_mail_task.rb
rename to app/models/tasks/docket_switch/docket_switch_mail_task.rb
diff --git a/app/models/tasks/docket_switch_ruling_task.rb b/app/models/tasks/docket_switch/docket_switch_ruling_task.rb
similarity index 100%
rename from app/models/tasks/docket_switch_ruling_task.rb
rename to app/models/tasks/docket_switch/docket_switch_ruling_task.rb
diff --git a/app/models/tasks/schedule_hearing_task.rb b/app/models/tasks/schedule_hearing_task.rb
index ba2f2e42026..e8afde09797 100644
--- a/app/models/tasks/schedule_hearing_task.rb
+++ b/app/models/tasks/schedule_hearing_task.rb
@@ -44,24 +44,26 @@ def create_parent_hearing_task
def update_from_params(params, current_user)
multi_transaction do
verify_user_can_update!(current_user)
+
+ created_tasks = []
+
if params[:status] == Constants.TASK_STATUSES.completed
task_values = params.delete(:business_payloads)[:values]
- multi_transaction do
- hearing = create_hearing(task_values)
+ hearing = create_hearing(task_values)
- if task_values[:virtual_hearing_attributes].present?
- @alerts = VirtualHearings::ConvertToVirtualHearingService
- .convert_hearing_to_virtual(hearing, task_values[:virtual_hearing_attributes])
- end
-
- AssignHearingDispositionTask.create_assign_hearing_disposition_task!(appeal, parent, hearing)
+ if task_values[:virtual_hearing_attributes].present?
+ @alerts = VirtualHearings::ConvertToVirtualHearingService
+ .convert_hearing_to_virtual(hearing, task_values[:virtual_hearing_attributes])
end
+
+ created_tasks << AssignHearingDispositionTask.create_assign_hearing_disposition_task!(appeal, parent, hearing)
elsif params[:status] == Constants.TASK_STATUSES.cancelled
- withdraw_hearing
+ created_tasks << withdraw_hearing
end
- super(params, current_user) # returns [self]
+ # super returns [self]
+ super(params, current_user) + created_tasks.compact
end
end
@@ -155,6 +157,7 @@ def withdraw_hearing
AppealRepository.withdraw_hearing!(appeal)
AppealRepository.update_location!(appeal, location)
+ nil
else
EvidenceSubmissionWindowTask.create!(
appeal: appeal,
diff --git a/app/models/vacols/case_hearing.rb b/app/models/vacols/case_hearing.rb
index 26632555a15..46491819d11 100644
--- a/app/models/vacols/case_hearing.rb
+++ b/app/models/vacols/case_hearing.rb
@@ -3,7 +3,12 @@
class VACOLS::CaseHearing < VACOLS::Record
self.table_name = "hearsched"
self.primary_key = "hearing_pkseq"
- self.sequence_name = "hearsched_pkseq"
+
+ # :autogenerated allows a trigger to set the new sequence value for a primary key.
+ #
+ # COMPATIBILITY NOTE: Support for :autogenerated is dropped in Rails 6.
+ # See Issue: https://github.com/rsim/oracle-enhanced/issues/1643
+ self.sequence_name = :autogenerated
attribute :hearing_date, :datetime
attribute :notes1, :ascii_string
@@ -11,6 +16,8 @@ class VACOLS::CaseHearing < VACOLS::Record
has_one :staff, foreign_key: :sattyid, primary_key: :board_member
has_one :brieff, foreign_key: :bfkey, primary_key: :folder_nr, class_name: "Case"
+ has_one :folder, foreign_key: :ticknum, primary_key: :folder_nr
+ has_one :corres, foreign_key: :stafkey, primary_key: :bfcorkey, class_name: "Correspondent"
HEARING_TYPE_LOOKUP = {
central: "C",
@@ -46,6 +53,7 @@ class VACOLS::CaseHearing < VACOLS::Record
aod: :aod,
transcript_requested: :tranreq,
add_on: :addon,
+ add_time: :addtime,
representative_name: :repname,
staff_id: :mduser,
room: :room,
@@ -62,6 +70,9 @@ class VACOLS::CaseHearing < VACOLS::Record
after_update :create_or_update_diaries
class << self
+ # Finds all hearings for specific days.
+ #
+ # @deprecated Use {#where}
def hearings_for_hearing_days(hearing_day_ids)
select_hearings
.where(vdkey: hearing_day_ids)
@@ -69,6 +80,9 @@ def hearings_for_hearing_days(hearing_day_ids)
.where.not(folder_nr: nil)
end
+ # Finds all hearings for specific days that are assigned to a judge.
+ #
+ # @deprecated Use {#where}
def hearings_for_hearing_days_assigned_to_judge(hearing_day_ids, judge)
id = connection.quote(judge.css_id.upcase)
@@ -79,6 +93,9 @@ def hearings_for_hearing_days_assigned_to_judge(hearing_day_ids, judge)
.where.not(folder_nr: nil)
end
+ # Finds all hearings for an appeal.
+ #
+ # @deprecated Use {#where}
def for_appeal(appeal_vacols_id)
select_hearings.where(folder_nr: appeal_vacols_id)
end
@@ -93,6 +110,9 @@ def for_appeals(vacols_ids)
end
end
+ # Finds a hearing by ID.
+ #
+ # @deprecated Use {#find}.
def load_hearing(pkseq)
select_hearings.find_by(hearing_pkseq: pkseq)
end
@@ -108,6 +128,11 @@ def create_hearing!(hearing_info)
private
+ # Selects hearings and associated fields.
+ #
+ # @deprecated Use {#eager_load} when appropriate. This method creates attributes on the model that
+ # *don't* actually exist on the HEARSCHED table. It is better to load the associated data in a way
+ # that is idiomatic to Rails.
def select_hearings
# VACOLS overloads the HEARSCHED table with other types of hearings
# that work differently. Filter those out.
@@ -115,7 +140,7 @@ def select_hearings
:hearing_disp, :hearing_pkseq, :hearing_date, :hearing_type,
:notes1, :folder_nr, :vdkey, :aod,
:holddays, :tranreq, :transent,
- :repname, :addon, :board_member, :mduser,
+ :repname, :addon, :addtime, :board_member, :mduser,
:mdtime, :sattyid, :bfregoff, :bfso,
:bfcorkey, :bfddec, :bfdc, :room, :vdbvapoc,
"staff.sdomainid as css_id", "brieff.bfac", "staff.slogid",
diff --git a/app/repositories/hearing_repository.rb b/app/repositories/hearing_repository.rb
index 56f66bc1b09..0296e5c3b5a 100644
--- a/app/repositories/hearing_repository.rb
+++ b/app/repositories/hearing_repository.rb
@@ -37,7 +37,7 @@ def update_vacols_hearing!(vacols_record, hearing_hash)
end
def create_vacols_hearing(hearing_day, appeal, scheduled_for, hearing_location_attrs)
- VACOLS::CaseHearing.create_hearing!(
+ vacols_record = VACOLS::CaseHearing.create_hearing!(
folder_nr: appeal.vacols_id,
hearing_date: VacolsHelper.format_datetime_with_utc_timezone(scheduled_for),
vdkey: hearing_day.id,
@@ -47,12 +47,14 @@ def create_vacols_hearing(hearing_day, appeal, scheduled_for, hearing_location_a
vdbvapoc: hearing_day.bva_poc
)
- vacols_record = VACOLS::CaseHearing.for_appeal(appeal.vacols_id).where(vdkey: hearing_day.id)
- .order(addtime: :desc).last
- hearing = LegacyHearing.assign_or_create_from_vacols_record(vacols_record)
-
- hearing.update(hearing_location_attributes: hearing_location_attrs) unless hearing_location_attrs.nil?
+ # Reload the hearing to pull in associated data.
+ # Note: using `load_hearing` here is necessary to load in associated data that is not declared in
+ # the table (see `VACOLS::CaseHearing#select_hearings`).
+ vacols_record = VACOLS::CaseHearing.load_hearing(vacols_record.id)
+ hearing = LegacyHearing.assign_or_create_from_vacols_record(vacols_record)
+ hearing.hearing_location_attributes = hearing_location_attrs unless hearing_location_attrs.nil?
+ hearing.save!
hearing
end
diff --git a/app/repositories/task_action_repository.rb b/app/repositories/task_action_repository.rb
index 8053bb4f2db..c6c32b4f647 100644
--- a/app/repositories/task_action_repository.rb
+++ b/app/repositories/task_action_repository.rb
@@ -174,6 +174,18 @@ def sign_motion_to_vacate_data(_task, _user = nil)
{}
end
+ def docket_switch_denied_data(_task, _user = nil)
+ {
+ type: DocketSwitchDeniedTask.name
+ }
+ end
+
+ def docket_switch_granted_data(_task, _user = nil)
+ {
+ type: DocketSwitchGrantedTask.name
+ }
+ end
+
def assign_to_translation_team_data(_task, _user = nil)
org = Translation.singleton
diff --git a/app/services/external_api/bgs_service.rb b/app/services/external_api/bgs_service.rb
index 3a226fc4539..5eee0ee8c18 100644
--- a/app/services/external_api/bgs_service.rb
+++ b/app/services/external_api/bgs_service.rb
@@ -286,6 +286,8 @@ def bust_fetch_veteran_info_cache(vbms_id)
def fetch_ratings_in_range(participant_id:, start_date:, end_date:)
DBService.release_db_connections
+ start_date, end_date = formatted_start_and_end_dates(start_date, end_date)
+
MetricsService.record("BGS: fetch ratings in range: \
participant_id = #{participant_id}, \
start_date = #{start_date} \
@@ -315,6 +317,8 @@ def fetch_rating_profile(participant_id:, profile_date:)
def fetch_rating_profiles_in_range(participant_id:, start_date:, end_date:)
DBService.release_db_connections
+ start_date, end_date = formatted_start_and_end_dates(start_date, end_date)
+
MetricsService.record("BGS: fetch rating profile in range: \
participant_id = #{participant_id}, \
start_date = #{start_date}, \
@@ -462,5 +466,13 @@ def init_client
log: true
)
end
+
+ def formatted_start_and_end_dates(start_date, end_date)
+ # start_date and end_date should be Dates with different values
+ return_start_date = start_date&.to_date
+ return_end_date = end_date&.to_date
+ return_end_date += 1.day if return_end_date.present? && return_end_date == return_start_date
+ [return_start_date, return_end_date]
+ end
# :nocov:
end
diff --git a/app/services/hearing_task_tree_initializer.rb b/app/services/hearing_task_tree_initializer.rb
index 1b347eca35f..fbed859125d 100644
--- a/app/services/hearing_task_tree_initializer.rb
+++ b/app/services/hearing_task_tree_initializer.rb
@@ -29,9 +29,9 @@ def for_appeal_with_pending_travel_board_hearing(appeal)
create_args = { appeal: appeal, assigned_to: Bva.singleton }
root_task = RootTask.find_or_create_by!(**create_args)
- hearing_task = HearingTask.find_or_create_by!(**create_args, parent: root_task)
- schedule_hearing_task = ScheduleHearingTask.find_or_create_by!(**create_args, parent: hearing_task)
- ChangeHearingRequestTypeTask.find_or_create_by!(**create_args, parent: schedule_hearing_task)
+ hearing_task = HearingTask.create!(**create_args, parent: root_task)
+ schedule_hearing_task = ScheduleHearingTask.create!(**create_args, parent: hearing_task)
+ ChangeHearingRequestTypeTask.create!(**create_args, parent: schedule_hearing_task)
end
appeal.reload
diff --git a/app/services/virtual_hearings/convert_to_virtual_hearing_service.rb b/app/services/virtual_hearings/convert_to_virtual_hearing_service.rb
index f124589d35a..e15211022ac 100644
--- a/app/services/virtual_hearings/convert_to_virtual_hearing_service.rb
+++ b/app/services/virtual_hearings/convert_to_virtual_hearing_service.rb
@@ -21,12 +21,27 @@ def convert_hearing_to_virtual(hearing, virtual_hearing_attributes)
form.update
[{ hearing: form.hearing_alerts }, { virtual_hearing: form.virtual_hearing_alert }]
+ rescue ActiveRecord::RecordNotUnique => error
+ # :nocov:
+ raise wrap_error(error, 1003, COPY::VIRTUAL_HEARING_ALREADY_CREATED)
+ # :nocov:
+ rescue ActiveRecord::RecordInvalid => error
+ raise wrap_error(error, 1002, error.message)
rescue StandardError => error
- raise(
- Caseflow::Error::VirtualHearingConversionFailed,
+ # :nocov:
+ raise wrap_error(error, 1099, error.message)
+ # :nocov:
+ end
+
+ private
+
+ # Wraps an error in the class `Caseflow::Error::VirtualHearingConversionFailed`, allowing
+ # errors thrown by this class to be handled with specialized logic.
+ def wrap_error(error, code, message)
+ Caseflow::Error::VirtualHearingConversionFailed.new(
error_type: error.class,
- message: error.message,
- code: 1002
+ message: message,
+ code: code
)
end
end
diff --git a/client/.eslintrc.js b/client/.eslintrc.js
index 778f98ed00b..71f940b059a 100644
--- a/client/.eslintrc.js
+++ b/client/.eslintrc.js
@@ -41,6 +41,9 @@ module.exports = {
version: '16.12',
},
'import/resolver': {
+ webpack: {
+ config: './webpack.config.js'
+ },
node: {
extensions: ['.js', '.jsx', '.json'],
},
diff --git a/client/.storybook/main.js b/client/.storybook/main.js
index 13a918d073b..db368ec0f23 100644
--- a/client/.storybook/main.js
+++ b/client/.storybook/main.js
@@ -20,6 +20,13 @@ module.exports = {
return {
...config,
+ resolve: {
+ ...config.resolve,
+ alias: {
+ ...config.resolve.alias,
+ ...custom.resolve.alias
+ }
+ },
module: {
...config.module,
rules: [...config.module.rules, ...customRules],
diff --git a/client/COPY.json b/client/COPY.json
index 2b18a0ceb16..411fdc00d28 100644
--- a/client/COPY.json
+++ b/client/COPY.json
@@ -579,6 +579,8 @@
"CONTROLLED_CORRESPONDENCE_MAIL_TASK_LABEL": "Controlled correspondence",
"DEATH_CERTIFICATE_MAIL_TASK_LABEL": "Death certificate",
"DOCKET_SWITCH_MAIL_TASK_LABEL": "Docket Switch",
+ "DOCKET_SWITCH_DENIED_TASK_LABEL": "Denied Docket Switch",
+ "DOCKET_SWITCH_GRANTED_TASK_LABEL": "Granted Docket Switch",
"EVIDENCE_OR_ARGUMENT_MAIL_TASK_LABEL": "Evidence or argument",
"EXTENSION_REQUEST_MAIL_TASK_LABEL": "Extension request",
"FOIA_REQUEST_MAIL_TASK_LABEL": "FOIA request",
diff --git a/client/app/components/ReduxBase.jsx b/client/app/components/ReduxBase.jsx
index 5c6430b2a25..ab2865c9692 100644
--- a/client/app/components/ReduxBase.jsx
+++ b/client/app/components/ReduxBase.jsx
@@ -1,16 +1,15 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Provider } from 'react-redux';
-import { createStore, applyMiddleware, compose } from 'redux';
+import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
import perfLogger from 'redux-perf-middleware';
-import thunk from 'redux-thunk';
import { getReduxAnalyticsMiddleware } from '../util/ReduxUtil';
-const setupStore = ({ reducer, initialState, analyticsMiddlewareArgs, enhancers }) => {
- // eslint-disable-next-line no-underscore-dangle
- const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
-
- const middleware = [thunk, getReduxAnalyticsMiddleware(...analyticsMiddlewareArgs)];
+const setupStore = ({ reducer, initialState, analyticsMiddlewareArgs }) => {
+ const middleware = [
+ ...getDefaultMiddleware({ immutableCheck: false }),
+ getReduxAnalyticsMiddleware(...analyticsMiddlewareArgs),
+ ];
// Some middleware should be skipped in test scenarios. Normally I wouldn't leave a comment
// like this, but we had a bug where we accidentally added essential middleware here and it
@@ -20,17 +19,29 @@ const setupStore = ({ reducer, initialState, analyticsMiddlewareArgs, enhancers
middleware.push(perfLogger);
}
- const composedEnhancers = composeEnhancers(applyMiddleware(...middleware), ...enhancers);
-
- const store = createStore(reducer, initialState, composedEnhancers);
+ const store = configureStore({
+ reducer,
+ preloadedState: initialState,
+ middleware,
+ });
return store;
};
export default function ReduxBase(props) {
- const { children, reducer, initialState, enhancers, analyticsMiddlewareArgs, getStoreRef } = props;
+ const {
+ children,
+ reducer,
+ initialState,
+ analyticsMiddlewareArgs,
+ getStoreRef,
+ } = props;
- const store = setupStore({ reducer, initialState, enhancers, analyticsMiddlewareArgs });
+ const store = setupStore({
+ reducer,
+ initialState,
+ analyticsMiddlewareArgs,
+ });
// Dispatch relies on direct access to the store. It would be better to use connect(),
// but for now, we will expose this to grant that access.
@@ -42,17 +53,18 @@ export default function ReduxBase(props) {
}
ReduxBase.propTypes = {
- children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]).isRequired,
+ children: PropTypes.oneOfType([
+ PropTypes.arrayOf(PropTypes.node),
+ PropTypes.node,
+ ]).isRequired,
reducer: PropTypes.func,
initialState: PropTypes.object,
- enhancers: PropTypes.array,
analyticsMiddlewareArgs: PropTypes.array,
- getStoreRef: PropTypes.func
+ getStoreRef: PropTypes.func,
};
ReduxBase.defaultProps = {
analyticsMiddlewareArgs: [],
// eslint-disable-next-line no-empty-function
getStoreRef: () => {},
- enhancers: []
};
diff --git a/client/app/hearings/components/ScheduleVeteran.jsx b/client/app/hearings/components/ScheduleVeteran.jsx
index b7807b1a6c0..703824ce093 100644
--- a/client/app/hearings/components/ScheduleVeteran.jsx
+++ b/client/app/hearings/components/ScheduleVeteran.jsx
@@ -7,6 +7,7 @@ import { withRouter } from 'react-router-dom';
import AppSegment from '@department-of-veterans-affairs/caseflow-frontend-toolkit/components/AppSegment';
import Button from '../../components/Button';
import { sprintf } from 'sprintf-js';
+import { isNil, maxBy, omit, find, get } from 'lodash';
import TASK_STATUSES from '../../../constants/TASK_STATUSES';
import COPY from '../../../COPY';
@@ -17,7 +18,6 @@ import { onReceiveAppealDetails } from '../../queue/QueueActions';
import { formatDateStr } from '../../util/DateUtil';
import Alert from '../../components/Alert';
import { setMargin, marginTop, regionalOfficeSection, saveButton, cancelButton } from './details/style';
-import { find, get } from 'lodash';
import { getAppellantTitle, processAlerts, parseVirtualHearingErrors } from '../utils';
import {
onChangeFormData,
@@ -100,9 +100,6 @@ export const ScheduleVeteran = ({
// Reset the component state
const reset = () => {
- // Clear the loading state
- setLoading(false);
-
// Clear any lingering errors
setErrors({});
@@ -150,12 +147,19 @@ export const ScheduleVeteran = ({
// Format the payload for the API
const getPayload = () => {
+ // The API can't accept a payload if the field `status` is provided because it is a generated
+ // (not editable) field.
+ //
+ // `omit` returns an empty object if `null` is provided as an argument, so the `isNil` check here
+ // prevents `omit` from returning an empty object.`
+ const virtualHearing = isNil(hearing.virtualHearing) ? null : omit(hearing.virtualHearing, ['status']);
+
// Format the shared hearing values
const hearingValues = {
scheduled_time_string: hearing.scheduledTimeString,
hearing_day_id: hearing.hearingDay.hearingId,
hearing_location: hearing.hearingLocation ? ApiUtil.convertToSnakeCase(hearing.hearingLocation) : null,
- virtual_hearing_attributes: hearing.virtualHearing ? ApiUtil.convertToSnakeCase(hearing.virtualHearing) : null,
+ virtual_hearing_attributes: virtualHearing ? ApiUtil.convertToSnakeCase(virtualHearing) : null,
};
// Determine whether to send the reschedule payload
@@ -212,12 +216,17 @@ export const ScheduleVeteran = ({
// Patch the hearing task with the form data
const { body } = await ApiUtil.patch(`/tasks/${taskId}`, payload);
- const [task] = body?.tasks?.data?.filter((hearingTask) => hearingTask.id === taskId);
+ // Find the most recently created AssignHearingDispositionTask. This task will have the ID of the
+ // most recently created hearing.
+ const mostRecentTask = maxBy(
+ body?.tasks?.data?.filter((task) => task.attributes?.type === 'AssignHearingDispositionTask') ?? [],
+ (task) => task.id
+ );
const alerts = body?.tasks?.alerts;
if (alerts && hearing.virtualHearing) {
- processAlerts(alerts, props, () => props.startPollingHearing(task?.attributes?.external_hearing_id));
+ processAlerts(alerts, props, () => props.startPollingHearing(mostRecentTask?.attributes?.external_hearing_id));
} else {
props.showSuccessMessage(getSuccessMsg());
}
@@ -240,14 +249,11 @@ export const ScheduleVeteran = ({
setErrors(errList);
- // Remove the loading state on error
- setLoading(false);
-
// Handle errors in the standard format
} else if (msg?.title) {
props.showErrorMessage({
title: msg?.title,
- detail: msg?.detail
+ detail: msg?.detail ?? msg?.message
});
// Handle legacy appeals
@@ -266,6 +272,9 @@ export const ScheduleVeteran = ({
'Please contact the Caseflow Team for assistance.',
});
}
+ } finally {
+ // Clear the loading state
+ setLoading(false);
}
};
diff --git a/client/constants/DIAGNOSTIC_CODE_DESCRIPTIONS.json b/client/constants/DIAGNOSTIC_CODE_DESCRIPTIONS.json
index ad50681d8c6..8fb0adf3448 100644
--- a/client/constants/DIAGNOSTIC_CODE_DESCRIPTIONS.json
+++ b/client/constants/DIAGNOSTIC_CODE_DESCRIPTIONS.json
@@ -131,6 +131,22 @@
"staff_description": "Other musculoskeletal disease",
"status_description": "musculoskeletal disease"
},
+ "5100": {
+ "staff_description": "Anatomical loss of hands and feet",
+ "status_description": "Anatomical loss of hands and feet"
+ },
+ "5101": {
+ "staff_description": "Loss of Use of Hands and Feet",
+ "status_description": "Loss of Use of Hands and Feet"
+ },
+ "5102": {
+ "staff_description": "Anatomical loss of both hands and one foot",
+ "status_description": "Anatomical loss of both hands and one foot"
+ },
+ "5103": {
+ "staff_description": "Anatomical loss of both feet and one hand",
+ "status_description": "Anatomical loss of both feet and one hand"
+ },
"5104": {
"staff_description": "Anatomical loss of one hand and loss of use of one foot",
"status_description": "loss of hand and loss of use of foot"
@@ -359,6 +375,10 @@
"staff_description": "Toes, three or four, amputation of, without metatarsal involvement",
"status_description": "amputation of toes"
},
+ "5174": {
+ "staff_description": "Hip prosthesis",
+ "status_description": "Hip prosthesis"
+ },
"5199": {
"staff_description": "Other amputations",
"status_description": "amputation"
@@ -575,6 +595,10 @@
"staff_description": "Genu recurvatum",
"status_description": "knee hyperextension"
},
+ "5264": {
+ "staff_description": "Prosthesis for knee",
+ "status_description": "Prosthesis for knee"
+ },
"5270": {
"staff_description": "Ankle, ankylosis of",
"status_description": "ankylosis of ankle"
@@ -959,6 +983,70 @@
"staff_description": "Keratoconus",
"status_description": "keratoconus"
},
+ "6036": {
+ "staff_description": "Status Post Corneal Transplant",
+ "status_description": "Status Post Corneal Transplant"
+ },
+ "6037": {
+ "staff_description": "Pinguecula, Spot On White of Eye",
+ "status_description": "Pinguecula, Spot On White of Eye"
+ },
+ "6040": {
+ "staff_description": "Diabetic retinopathy",
+ "status_description": "Diabetic retinopathy"
+ },
+ "6042": {
+ "staff_description": "Retinal dystrophy",
+ "status_description": "Retinal dystrophy"
+ },
+ "6046": {
+ "staff_description": "Post-chiasmal disorders",
+ "status_description": "Post-chiasmal disorders"
+ },
+ "6050": {
+ "staff_description": "(Covered by SMC Codes)",
+ "status_description": "(Covered by SMC Codes)"
+ },
+ "6051": {
+ "staff_description": "(Covered by SMC Codes)",
+ "status_description": "(Covered by SMC Codes)"
+ },
+ "6052": {
+ "staff_description": "(Covered by SMC Codes)",
+ "status_description": "(Covered by SMC Codes)"
+ },
+ "6053": {
+ "staff_description": "(Covered by SMC Codes)",
+ "status_description": "(Covered by SMC Codes)"
+ },
+ "6054": {
+ "staff_description": "(Covered by SMC Codes)",
+ "status_description": "(Covered by SMC Codes)"
+ },
+ "6055": {
+ "staff_description": "(Covered by SMC Codes)",
+ "status_description": "(Covered by SMC Codes)"
+ },
+ "6056": {
+ "staff_description": "(Covered by SMC Codes)",
+ "status_description": "(Covered by SMC Codes)"
+ },
+ "6057": {
+ "staff_description": "(Covered by SMC Codes)",
+ "status_description": "(Covered by SMC Codes)"
+ },
+ "6058": {
+ "staff_description": "(Covered by SMC Codes)",
+ "status_description": "(Covered by SMC Codes)"
+ },
+ "6059": {
+ "staff_description": "(Covered by SMC Codes)",
+ "status_description": "(Covered by SMC Codes)"
+ },
+ "6060": {
+ "staff_description": "(Covered by SMC Codes)",
+ "status_description": "(Covered by SMC Codes)"
+ },
"6061": {
"staff_description": "Anatomical loss both eyes",
"status_description": "loss of both eyes"
@@ -1063,6 +1151,46 @@
"staff_description": "Hearing loss",
"status_description": "hearing loss"
},
+ "6101": {
+ "staff_description": "Hearing loss",
+ "status_description": "Hearing loss"
+ },
+ "6102": {
+ "staff_description": "Hearing loss",
+ "status_description": "Hearing loss"
+ },
+ "6103": {
+ "staff_description": "Hearing loss",
+ "status_description": "Hearing loss"
+ },
+ "6104": {
+ "staff_description": "Hearing loss",
+ "status_description": "Hearing loss"
+ },
+ "6105": {
+ "staff_description": "Hearing loss",
+ "status_description": "Hearing loss"
+ },
+ "6106": {
+ "staff_description": "Hearing loss",
+ "status_description": "Hearing loss"
+ },
+ "6107": {
+ "staff_description": "Hearing loss",
+ "status_description": "Hearing loss"
+ },
+ "6108": {
+ "staff_description": "Hearing loss",
+ "status_description": "Hearing loss"
+ },
+ "6109": {
+ "staff_description": "Hearing loss",
+ "status_description": "Hearing loss"
+ },
+ "6110": {
+ "staff_description": "Hearing loss",
+ "status_description": "Hearing loss"
+ },
"6199": {
"staff_description": "Other hearing loss",
"status_description": "hearing loss"
@@ -1079,13 +1207,21 @@
"staff_description": "Otosclerosis",
"status_description": "otosclerosis"
},
+ "6203": {
+ "staff_description": "Otitis interna",
+ "status_description": "Otitis interna"
+ },
"6204": {
"staff_description": "Peripheral vestibular disorders",
"status_description": "inner ear or vestibular nerve disorder"
},
"6205": {
"staff_description": "Meniere's syndrome",
- "status_description": "M\u00e9ni\u00e8re's disease"
+ "status_description": "Ménière's disease"
+ },
+ "6206": {
+ "staff_description": "Mastoiditis",
+ "status_description": "Mastoiditis"
},
"6207": {
"staff_description": "Auricle, loss or deformity",
@@ -1107,10 +1243,58 @@
"staff_description": "Tympanic membrane, perforation of",
"status_description": "perforation of tympanic membrane"
},
+ "6250": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6251": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6252": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6253": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6254": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6255": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6256": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6257": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6258": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
"6260": {
"staff_description": "Tinnitus, recurrent",
"status_description": "tinnitus"
},
+ "6261": {
+ "staff_description": "Ear condition",
+ "status_description": "Ear condition"
+ },
+ "6262": {
+ "staff_description": "Ear condition",
+ "status_description": "Ear condition"
+ },
+ "6263": {
+ "staff_description": "Ear condition",
+ "status_description": "Ear condition"
+ },
"6275": {
"staff_description": "Loss of sense of smell, complete",
"status_description": "loss of sense of smell"
@@ -1119,6 +1303,90 @@
"staff_description": "Loss of sense of taste, complete",
"status_description": "loss of sense of taste"
},
+ "6277": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6278": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6279": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6280": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6281": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6282": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6283": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6284": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6285": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6286": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6287": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6288": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6289": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6290": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6291": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6292": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6293": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6294": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6295": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6296": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
+ "6297": {
+ "staff_description": "Impaired hearing",
+ "status_description": "Impaired hearing"
+ },
"6299": {
"staff_description": "Other sense organ disability",
"status_description": "sense organ disability"
@@ -1167,6 +1435,10 @@
"staff_description": "Tuberculosis, miliary",
"status_description": "miliary tuberculosis"
},
+ "6312": {
+ "staff_description": "Nontuberculosis mycobacterium infection",
+ "status_description": "Nontuberculosis mycobacterium infection"
+ },
"6313": {
"staff_description": "Avitaminosis",
"status_description": "avitaminosis"
@@ -1199,6 +1471,38 @@
"staff_description": "Parasitic diseases otherwise not specified",
"status_description": "parasitic disease"
},
+ "6325": {
+ "staff_description": "Disseminated Strongyloidiasis",
+ "status_description": "Disseminated Strongyloidiasis"
+ },
+ "6326": {
+ "staff_description": "Schistosomiasis",
+ "status_description": "Schistosomiasis"
+ },
+ "6329": {
+ "staff_description": "Dengue",
+ "status_description": "Dengue"
+ },
+ "6330": {
+ "staff_description": "Campylobacter jejuni infection",
+ "status_description": "Campylobacter jejuni infection"
+ },
+ "6331": {
+ "staff_description": "Coxiella burnetii infection (Q fever)",
+ "status_description": "Coxiella burnetii infection (Q fever)"
+ },
+ "6333": {
+ "staff_description": "Nontyphoid Salmonella infections",
+ "status_description": "Nontyphoid Salmonella infections"
+ },
+ "6334": {
+ "staff_description": "Shigella infections",
+ "status_description": "Shigella infections"
+ },
+ "6335": {
+ "staff_description": "West Nile virus infection",
+ "status_description": "West Nile virus infection"
+ },
"6350": {
"staff_description": "Lupus erythematosus, systemic (disseminated)",
"status_description": "lupus"
@@ -1207,6 +1511,14 @@
"staff_description": "HIV-Related Illness",
"status_description": "HIV-related illness"
},
+ "6352": {
+ "staff_description": "Aids related complex",
+ "status_description": "Aids related complex"
+ },
+ "6353": {
+ "staff_description": "Positive blood test for AIDS antibody",
+ "status_description": "Positive blood test for AIDS antibody"
+ },
"6354": {
"staff_description": "Chronic Fatigue Syndrome (CFS)",
"status_description": "chronic fatigue syndrome"
@@ -1215,6 +1527,10 @@
"staff_description": "Other infectious disease, immune disorder, or nutritional deficiency",
"status_description": "infectious disease immune disorder or nutritional deficiency"
},
+ "6501": {
+ "staff_description": "Rhinitis",
+ "status_description": "Rhinitis"
+ },
"6502": {
"staff_description": "Septum, nasal, deviation of",
"status_description": "deviated septum"
@@ -1251,6 +1567,10 @@
"staff_description": "Laryngitis, chronic",
"status_description": "chronic laryngitis"
},
+ "6517": {
+ "staff_description": "Residuals of injured larynx",
+ "status_description": "Residuals of injured larynx"
+ },
"6518": {
"staff_description": "Laryngectomy, total",
"status_description": "laryngectomy"
@@ -1323,6 +1643,46 @@
"staff_description": "Tuberculosis, pulmonary, chronic, active, advancement unspecified [entitled 8/19/68]",
"status_description": "pulmonary tuberculosis"
},
+ "6705": {
+ "staff_description": "Lung Condition",
+ "status_description": "Lung Condition"
+ },
+ "6706": {
+ "staff_description": "Lung Condition",
+ "status_description": "Lung Condition"
+ },
+ "6707": {
+ "staff_description": "Active Pulmonary Tuberculosis",
+ "status_description": "Active Pulmonary Tuberculosis"
+ },
+ "6708": {
+ "staff_description": "Active Pulmonary Tuberculosis",
+ "status_description": "Active Pulmonary Tuberculosis"
+ },
+ "6709": {
+ "staff_description": "Active Pulmonary Tuberculosis",
+ "status_description": "Active Pulmonary Tuberculosis"
+ },
+ "6710": {
+ "staff_description": "Active Pulmonary Tuberculosis",
+ "status_description": "Active Pulmonary Tuberculosis"
+ },
+ "6711": {
+ "staff_description": "Lung condition",
+ "status_description": "Lung condition"
+ },
+ "6712": {
+ "staff_description": "Lung condition",
+ "status_description": "Lung condition"
+ },
+ "6713": {
+ "staff_description": "Lung condition",
+ "status_description": "Lung condition"
+ },
+ "6714": {
+ "staff_description": "Lung condition",
+ "status_description": "Lung condition"
+ },
"6721": {
"staff_description": "Tuberculosis, pulmonary, chronic, far advanced, inactive [entitled 8/19/68]",
"status_description": "pulmonary tuberculosis"
@@ -1339,6 +1699,22 @@
"staff_description": "Tuberculosis, pulmonary, chronic, inactive, advancement unspecified [entitled 8/19/68]",
"status_description": "pulmonary tuberculosis"
},
+ "6725": {
+ "staff_description": "Inactive Pulmonary Tuberculosis",
+ "status_description": "Inactive Pulmonary Tuberculosis"
+ },
+ "6726": {
+ "staff_description": "Inactive Pulmonary Tuberculosis",
+ "status_description": "Inactive Pulmonary Tuberculosis"
+ },
+ "6727": {
+ "staff_description": "Inactive Pulmonary Tuberculosis",
+ "status_description": "Inactive Pulmonary Tuberculosis"
+ },
+ "6728": {
+ "staff_description": "Inactive Pulmonary Tuberculosis",
+ "status_description": "Inactive Pulmonary Tuberculosis"
+ },
"6730": {
"staff_description": "Tuberculosis, pulmonary, chronic, active [after 8/19/68]",
"status_description": "pulmonary tuberculosis"
@@ -1355,10 +1731,82 @@
"staff_description": "Other tuberculous disease of lungs and/or pleura",
"status_description": "tuberculous disease"
},
+ "6800": {
+ "staff_description": "Anthracosis",
+ "status_description": "Anthracosis"
+ },
+ "6801": {
+ "staff_description": "Silicosis",
+ "status_description": "Silicosis"
+ },
+ "6802": {
+ "staff_description": "Pneumoconiosis, unspecified",
+ "status_description": "Pneumoconiosis, unspecified"
+ },
+ "6803": {
+ "staff_description": "Actinomycosis of Lung",
+ "status_description": "Actinomycosis of Lung"
+ },
+ "6804": {
+ "staff_description": "Streptotrichosis of Lung",
+ "status_description": "Streptotrichosis of Lung"
+ },
+ "6805": {
+ "staff_description": "Blastomycosis of Lung",
+ "status_description": "Blastomycosis of Lung"
+ },
+ "6806": {
+ "staff_description": "Sporotrichosis of Lung",
+ "status_description": "Sporotrichosis of Lung"
+ },
+ "6807": {
+ "staff_description": "Spergillosis of Lung",
+ "status_description": "Spergillosis of Lung"
+ },
+ "6808": {
+ "staff_description": "Mycosis of Lung",
+ "status_description": "Mycosis of Lung"
+ },
+ "6809": {
+ "staff_description": "Abcess of Lung",
+ "status_description": "Abcess of Lung"
+ },
+ "6810": {
+ "staff_description": "Pleurisy",
+ "status_description": "Pleurisy"
+ },
+ "6811": {
+ "staff_description": "Pleurisy",
+ "status_description": "Pleurisy"
+ },
+ "6812": {
+ "staff_description": "Fistula of Lung",
+ "status_description": "Fistula of Lung"
+ },
+ "6813": {
+ "staff_description": "Collapsed Lung",
+ "status_description": "Collapsed Lung"
+ },
+ "6814": {
+ "staff_description": "Spontaneous Collapsed Lung",
+ "status_description": "Spontaneous Collapsed Lung"
+ },
+ "6815": {
+ "staff_description": "Removal of Lung",
+ "status_description": "Removal of Lung"
+ },
+ "6816": {
+ "staff_description": "Partial Removal of Lung",
+ "status_description": "Partial Removal of Lung"
+ },
"6817": {
"staff_description": "Pulmonary Vascular Disease",
"status_description": "pulmonary vascular disease"
},
+ "6818": {
+ "staff_description": "Residuals of lung injury",
+ "status_description": "Residuals of lung injury"
+ },
"6819": {
"staff_description": "Neoplasms, malignant, any specified part of respiratory system exclusive of skin growths",
"status_description": "malignant neoplasm of the respiratory system"
@@ -1367,6 +1815,10 @@
"staff_description": "Neoplasms, benign, any specified part of respiratory system",
"status_description": "benign neoplasm of the respiratory system"
},
+ "6821": {
+ "staff_description": "Infection of the Lung",
+ "status_description": "Infection of the Lung"
+ },
"6822": {
"staff_description": "Actinomycosis",
"status_description": "actinomycosis"
@@ -1519,6 +1971,18 @@
"staff_description": "Ventricular arrhythmias (sustained)",
"status_description": "ventricular arrhythmias"
},
+ "7012": {
+ "staff_description": "Heart Condition",
+ "status_description": "Heart Condition"
+ },
+ "7013": {
+ "staff_description": "Heart Condition",
+ "status_description": "Heart Condition"
+ },
+ "7014": {
+ "staff_description": "Rapid pulse of the heart",
+ "status_description": "Rapid pulse of the heart"
+ },
"7015": {
"staff_description": "Atrioventricular block",
"status_description": "atrioventricular block"
@@ -1547,6 +2011,10 @@
"staff_description": "Other heart disease",
"status_description": "heart disease"
},
+ "7100": {
+ "staff_description": "Arteriosclerosis",
+ "status_description": "Arteriosclerosis"
+ },
"7101": {
"staff_description": "Hypertensive vascular disease (hypertension and isolated systolic hypertension)",
"status_description": "hypertensive vascular disease"
@@ -1575,6 +2043,10 @@
"staff_description": "Thrombo-angiitis obliterans (Buerger's Disease)",
"status_description": "Buerger's disease"
},
+ "7116": {
+ "staff_description": "Claudication",
+ "status_description": "Claudication"
+ },
"7117": {
"staff_description": "Raynaud's syndrome",
"status_description": "Raynaud's disease"
@@ -1639,6 +2111,10 @@
"staff_description": "Peritoneum, adhesions of",
"status_description": "peritoneal adhesions"
},
+ "7302": {
+ "staff_description": "Ulcer condition",
+ "status_description": "Ulcer condition"
+ },
"7304": {
"staff_description": "Ulcer, gastric",
"status_description": "ulcer"
@@ -1703,6 +2179,10 @@
"staff_description": "Irritable colon syndrome (spastic colitis, mucous colitis, etc.)",
"status_description": "irritable bowel syndrome"
},
+ "7320": {
+ "staff_description": "Intestinal condition",
+ "status_description": "Intestinal condition"
+ },
"7321": {
"staff_description": "Amebiasis",
"status_description": "amebiasis"
@@ -1783,6 +2263,10 @@
"staff_description": "Hernia, femoral",
"status_description": "femoral hernia"
},
+ "7341": {
+ "staff_description": "Residuals of abdominal wounds",
+ "status_description": "Residuals of abdominal wounds"
+ },
"7342": {
"staff_description": "Visceroptosis, symptomatic, marked",
"status_description": "visceroptosis"
@@ -1835,6 +2319,10 @@
"staff_description": "Nephritis, chronic",
"status_description": "chronic nephritis"
},
+ "7503": {
+ "staff_description": "Pyelitis",
+ "status_description": "Pyelitis"
+ },
"7504": {
"staff_description": "Pyelonephritis, chronic",
"status_description": "chronic pyelonephritis"
@@ -1843,6 +2331,10 @@
"staff_description": "Kidney, tuberculosis of",
"status_description": "tuberculosis of the kidney"
},
+ "7506": {
+ "staff_description": "Kidney condition",
+ "status_description": "Kidney condition"
+ },
"7507": {
"staff_description": "Nephrosclerosis, arteriolar",
"status_description": "arteriolar nephrosclerosis"
@@ -1867,6 +2359,14 @@
"staff_description": "Cystitis, chronic, includes interstitial and all etiologies, infectious and non-infectious",
"status_description": "chornic cystitis"
},
+ "7513": {
+ "staff_description": "Cystitis",
+ "status_description": "Cystitis"
+ },
+ "7514": {
+ "staff_description": "Tuberculosis of the bladder",
+ "status_description": "Tuberculosis of the bladder"
+ },
"7515": {
"staff_description": "Bladder, calculus in, with symptoms interfering with function",
"status_description": "bladder stone"
@@ -1911,6 +2411,10 @@
"staff_description": "Epididymo-orchitis, chronic only",
"status_description": "chronic epididymo-orchitis"
},
+ "7526": {
+ "staff_description": "Removal of the prostate gland",
+ "status_description": "Removal of the prostate gland"
+ },
"7527": {
"staff_description": "Prostate gland injuries, infections, hypertrophy, postoperative residuals",
"status_description": "prostate gland injury"
@@ -2055,6 +2559,14 @@
"staff_description": "Endometriosis",
"status_description": "endometriosis"
},
+ "7630": {
+ "staff_description": "Malignant neoplasms of the breast",
+ "status_description": "Malignant neoplasms of the breast"
+ },
+ "7631": {
+ "staff_description": "Benign neoplasms of the breast",
+ "status_description": "Benign neoplasms of the breast"
+ },
"7632": {
"staff_description": "Female Sexual Arousal Disorder (FSAD)",
"status_description": "female sexual arousal disorder"
@@ -2067,6 +2579,10 @@
"staff_description": "Anemia, hypochromic-microcytic and megaloblastic",
"status_description": "microcytic or megaloblastic anemia"
},
+ "7701": {
+ "staff_description": "Secondary Anemia",
+ "status_description": "Secondary Anemia"
+ },
"7702": {
"staff_description": "Agranulocytosis, acute",
"status_description": "agranulocytosis"
@@ -2099,10 +2615,18 @@
"staff_description": "Adenitis, tuberculous, active or inactive",
"status_description": "tuberculous lymphadenitis"
},
+ "7711": {
+ "staff_description": "Axillary adenitis",
+ "status_description": "Axillary adenitis"
+ },
"7712": {
"staff_description": "Inguinal adenitis",
"status_description": "multiple myeloma"
},
+ "7713": {
+ "staff_description": "Secondary adenitis",
+ "status_description": "Secondary adenitis"
+ },
"7714": {
"staff_description": "Sickle cell anemia",
"status_description": "sickle cell anemia"
@@ -2115,6 +2639,42 @@
"staff_description": "Aplastic anemia",
"status_description": "aplastic anemia"
},
+ "7717": {
+ "staff_description": "Primary (AL) amyloidosis",
+ "status_description": "Primary (AL) amyloidosis"
+ },
+ "7718": {
+ "staff_description": "Essential thrombocythemia/Primary myelofibrosis",
+ "status_description": "Essential thrombocythemia/Primary myelofibrosis"
+ },
+ "7719": {
+ "staff_description": "Chronic Myelogenous Leukemia (CML)",
+ "status_description": "Chronic Myelogenous Leukemia (CML)"
+ },
+ "7720": {
+ "staff_description": "Iron Deficiency Anemia",
+ "status_description": "Iron Deficiency Anemia"
+ },
+ "7721": {
+ "staff_description": "Folic Acid Deficiency",
+ "status_description": "Folic Acid Deficiency"
+ },
+ "7722": {
+ "staff_description": "Pernicious Anemia/Vitamin B12 Deficiency Anemia",
+ "status_description": "Pernicious Anemia/Vitamin B12 Deficiency Anemia"
+ },
+ "7723": {
+ "staff_description": "Acquired Hemolytic Anemia",
+ "status_description": "Acquired Hemolytic Anemia"
+ },
+ "7724": {
+ "staff_description": "Solitary Plasmacytoma",
+ "status_description": "Solitary Plasmacytoma"
+ },
+ "7725": {
+ "staff_description": "Myelodysplastic Syndromes",
+ "status_description": "Myelodysplastic Syndromes"
+ },
"7799": {
"staff_description": "Other hemic or lymphatic system disability",
"status_description": "hemic or lymphatic disability"
@@ -2283,6 +2843,10 @@
"staff_description": "Hypoparathyroidism",
"status_description": "hypoparathyroidism"
},
+ "7906": {
+ "staff_description": "Thyroiditis",
+ "status_description": "Thyroiditis"
+ },
"7907": {
"staff_description": "Cushing's syndrome",
"status_description": "Cushing's syndrome"
@@ -2295,6 +2859,10 @@
"staff_description": "Diabetes insipidus",
"status_description": "diabetes insipidus"
},
+ "7910": {
+ "staff_description": "Adrenal condition",
+ "status_description": "Adrenal condition"
+ },
"7911": {
"staff_description": "Addison's disease (Adrenal Cortical Hypofunction)",
"status_description": "Addison's disease"
@@ -2339,6 +2907,10 @@
"staff_description": "Encephalitis, epidemic, chronic",
"status_description": "chronic epidemic encephalitis"
},
+ "8001": {
+ "staff_description": "Condition of the brain",
+ "status_description": "Condition of the brain"
+ },
"8002": {
"staff_description": "Brain, new growth of, malignant",
"status_description": "malignant brain growth"
@@ -2427,6 +2999,10 @@
"staff_description": "Myasthenia gravis",
"status_description": "myasthenia gravis"
},
+ "8026": {
+ "staff_description": "Brain condition",
+ "status_description": "Brain condition"
+ },
"8045": {
"staff_description": "Brain disease due to trauma",
"status_description": "brain disease due to trauma"
@@ -2963,6 +3539,18 @@
"staff_description": "Undiagnosed condition, dental and oral",
"status_description": "undiagnosed dental or oral condition"
},
+ "8900": {
+ "staff_description": "Seizure disorder",
+ "status_description": "Seizure disorder"
+ },
+ "8901": {
+ "staff_description": "- Seizure disorder",
+ "status_description": "- Seizure disorder"
+ },
+ "8902": {
+ "staff_description": "- Seizure disorder",
+ "status_description": "- Seizure disorder"
+ },
"8910": {
"staff_description": "Epilepsy, grand mal",
"status_description": "epilepsy"
@@ -2987,6 +3575,282 @@
"staff_description": "Other epilepsy",
"status_description": "epilepsy"
},
+ "9000": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9001": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9002": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9003": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9004": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9005": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9006": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9007": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9008": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9009": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9010": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9011": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9012": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9013": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9014": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9015": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9016": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9017": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9018": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9019": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9020": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9021": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9022": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9023": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9024": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9025": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9026": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9027": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9028": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9029": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9030": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9031": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9032": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9033": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9034": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9035": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9036": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9037": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9038": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9039": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9040": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9041": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9042": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9043": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9044": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9045": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9046": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9047": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9048": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9049": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9050": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9051": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9052": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9053": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9054": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9055": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9099": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
+ "9100": {
+ "staff_description": "Neurosis",
+ "status_description": "Neurosis"
+ },
+ "9101": {
+ "staff_description": "Neurosis",
+ "status_description": "Neurosis"
+ },
+ "9102": {
+ "staff_description": "Neurosis",
+ "status_description": "Neurosis"
+ },
+ "9103": {
+ "staff_description": "Neurosis",
+ "status_description": "Neurosis"
+ },
+ "9104": {
+ "staff_description": "Neurosis",
+ "status_description": "Neurosis"
+ },
+ "9105": {
+ "staff_description": "Neurosis",
+ "status_description": "Neurosis"
+ },
+ "9106": {
+ "staff_description": "Neurosis",
+ "status_description": "Neurosis"
+ },
+ "9110": {
+ "staff_description": "Psychophysiologic heart disorder",
+ "status_description": "Psychophysiologic heart disorder"
+ },
+ "9111": {
+ "staff_description": "Psychophysiologic heart disorder",
+ "status_description": "Psychophysiologic heart disorder"
+ },
+ "9112": {
+ "staff_description": "Psychophysiologic stomach disorder",
+ "status_description": "Psychophysiologic stomach disorder"
+ },
+ "9199": {
+ "staff_description": "Nervous condition",
+ "status_description": "Nervous condition"
+ },
+ "9200": {
+ "staff_description": "Psychosis",
+ "status_description": "Psychosis"
+ },
"9201": {
"staff_description": "Schizophrenia, disorganized type",
"status_description": "schizophrenia"
@@ -3007,10 +3871,22 @@
"staff_description": "Schizophrenia, residual type; other and unspecified types",
"status_description": "schizophrenia"
},
+ "9206": {
+ "staff_description": "Bipolar disorder",
+ "status_description": "Bipolar disorder"
+ },
+ "9207": {
+ "staff_description": "Depression with psychotic features",
+ "status_description": "Depression with psychotic features"
+ },
"9208": {
"staff_description": "Delusional disorder",
"status_description": "delusional disorder"
},
+ "9209": {
+ "staff_description": "Depression with melancholia",
+ "status_description": "Depression with melancholia"
+ },
"9210": {
"staff_description": "Psychotic disorder, not otherwise specified (atypical psychosis)",
"status_description": "psychotic disorder"
@@ -3031,6 +3907,14 @@
"staff_description": "Dementia due to infection (see code for list)",
"status_description": "dementia"
},
+ "9302": {
+ "staff_description": "Dementia associated with intracranial infections",
+ "status_description": "Dementia associated with intracranial infections"
+ },
+ "9303": {
+ "staff_description": "Dementia associated with alcoholism",
+ "status_description": "Dementia associated with alcoholism"
+ },
"9304": {
"staff_description": "Dementia due to head trauma",
"status_description": "dementia"
@@ -3039,14 +3923,86 @@
"staff_description": "Vascular dementia",
"status_description": "vascular dementia"
},
+ "9306": {
+ "staff_description": "Multi-infarct dementia",
+ "status_description": "Multi-infarct dementia"
+ },
+ "9307": {
+ "staff_description": "Dementia associated with convulsive disorder",
+ "status_description": "Dementia associated with convulsive disorder"
+ },
+ "9308": {
+ "staff_description": "Dementia associated with metabolic disorder",
+ "status_description": "Dementia associated with metabolic disorder"
+ },
+ "9309": {
+ "staff_description": "Dementia associated with brain tumor",
+ "status_description": "Dementia associated with brain tumor"
+ },
"9310": {
"staff_description": "Dementia of unknown etiology",
"status_description": "dementia"
},
+ "9311": {
+ "staff_description": "Dementia due to undiagnosed cause",
+ "status_description": "Dementia due to undiagnosed cause"
+ },
"9312": {
"staff_description": "Dementia of the Alzheimer's type",
"status_description": "Alzheimer's disease"
},
+ "9313": {
+ "staff_description": "Brain syndrome",
+ "status_description": "Brain syndrome"
+ },
+ "9314": {
+ "staff_description": "Brain syndrome",
+ "status_description": "Brain syndrome"
+ },
+ "9315": {
+ "staff_description": "Dementia associated with epidemic encephalitis",
+ "status_description": "Dementia associated with epidemic encephalitis"
+ },
+ "9316": {
+ "staff_description": "Brain syndrome",
+ "status_description": "Brain syndrome"
+ },
+ "9317": {
+ "staff_description": "Brain syndrome",
+ "status_description": "Brain syndrome"
+ },
+ "9318": {
+ "staff_description": "Brain syndrome",
+ "status_description": "Brain syndrome"
+ },
+ "9319": {
+ "staff_description": "Brain syndrome",
+ "status_description": "Brain syndrome"
+ },
+ "9320": {
+ "staff_description": "Brain syndrome",
+ "status_description": "Brain syndrome"
+ },
+ "9321": {
+ "staff_description": "Brain syndrome",
+ "status_description": "Brain syndrome"
+ },
+ "9322": {
+ "staff_description": "Dementia associated with endocrine disorder",
+ "status_description": "Dementia associated with endocrine disorder"
+ },
+ "9323": {
+ "staff_description": "Brain syndrome",
+ "status_description": "Brain syndrome"
+ },
+ "9324": {
+ "staff_description": "Dementia associated with systemic infection",
+ "status_description": "Dementia associated with systemic infection"
+ },
+ "9325": {
+ "staff_description": "Brain Syndrome",
+ "status_description": "Brain Syndrome"
+ },
"9326": {
"staff_description": "Dementia due to other neurologic or general medical conditions, or substance- induced",
"status_description": "dementia"
@@ -3055,10 +4011,22 @@
"staff_description": "Organic mental disorder, other (inc. personality change due to a general medical condition)",
"status_description": "organic mental disorder"
},
+ "9399": {
+ "staff_description": "Cognitive disorders - general",
+ "status_description": "Cognitive disorders - general"
+ },
"9400": {
"staff_description": "Generalized anxiety disorder",
"status_description": "generalized anxiety disorder"
},
+ "9401": {
+ "staff_description": "Neurosis",
+ "status_description": "Neurosis"
+ },
+ "9402": {
+ "staff_description": "Neurosis",
+ "status_description": "Neurosis"
+ },
"9403": {
"staff_description": "Specific (simple) phobia; social phobia",
"status_description": "specific phobia"
@@ -3067,6 +4035,26 @@
"staff_description": "Obsessive compulsive disorder",
"status_description": "obsessive compulsive disorder"
},
+ "9405": {
+ "staff_description": "Depressive Reaction",
+ "status_description": "Depressive Reaction"
+ },
+ "9406": {
+ "staff_description": "Neurosis",
+ "status_description": "Neurosis"
+ },
+ "9407": {
+ "staff_description": "Neurosis",
+ "status_description": "Neurosis"
+ },
+ "9408": {
+ "staff_description": "Neurosis",
+ "status_description": "Neurosis"
+ },
+ "9409": {
+ "staff_description": "Neurosis",
+ "status_description": "Neurosis"
+ },
"9410": {
"staff_description": "Other and unspecified neurosis",
"status_description": "neurosis"
@@ -3139,6 +4127,54 @@
"staff_description": "Other nonpsychotic emotional illness",
"status_description": "nonpsychotic emotional illness"
},
+ "9500": {
+ "staff_description": "Psychological factors affecting skin",
+ "status_description": "Psychological factors affecting skin"
+ },
+ "9501": {
+ "staff_description": "Psychological factors affecting cardiovascular",
+ "status_description": "Psychological factors affecting cardiovascular"
+ },
+ "9502": {
+ "staff_description": "Psychological factors affecting gastrointestinal",
+ "status_description": "Psychological factors affecting gastrointestinal"
+ },
+ "9503": {
+ "staff_description": "Nervous Condition",
+ "status_description": "Nervous Condition"
+ },
+ "9504": {
+ "staff_description": "Nervous Condition",
+ "status_description": "Nervous Condition"
+ },
+ "9505": {
+ "staff_description": "Psychological factors affecting musculoskeletal",
+ "status_description": "Psychological factors affecting musculoskeletal"
+ },
+ "9506": {
+ "staff_description": "Psychological factors affecting respiratory",
+ "status_description": "Psychological factors affecting respiratory"
+ },
+ "9507": {
+ "staff_description": "Psychological factors affecting hemic/lymphatic",
+ "status_description": "Psychological factors affecting hemic/lymphatic"
+ },
+ "9508": {
+ "staff_description": "Psychological factors affecting genitourinary",
+ "status_description": "Psychological factors affecting genitourinary"
+ },
+ "9509": {
+ "staff_description": "Psychological factors affecting endocrine",
+ "status_description": "Psychological factors affecting endocrine"
+ },
+ "9510": {
+ "staff_description": "Psychological factors affecting organ of sense",
+ "status_description": "Psychological factors affecting organ of sense"
+ },
+ "9511": {
+ "staff_description": "Psychological factors affecting physical condition",
+ "status_description": "Psychological factors affecting physical condition"
+ },
"9520": {
"staff_description": "Anorexia nervosa",
"status_description": "anorexia"
@@ -3191,6 +4227,10 @@
"staff_description": "Coronoid process, loss of",
"status_description": "partial loss of lower jaw"
},
+ "9910": {
+ "staff_description": "Loss of maxilla",
+ "status_description": "Loss of maxilla"
+ },
"9911": {
"staff_description": "Hard palate, loss of half or more",
"status_description": "loss of hard palate"
diff --git a/client/constants/EP_CLAIM_TYPES.json b/client/constants/EP_CLAIM_TYPES.json
index 1ad87a55fad..0be858210ce 100644
--- a/client/constants/EP_CLAIM_TYPES.json
+++ b/client/constants/EP_CLAIM_TYPES.json
@@ -158,21 +158,6 @@
"offical_label": "PMC HLR DTA Error - Rating",
"disposition_type": "dta_error"
},
- "040SCNRPMC": {
- "review_type": "supplemental_claim",
- "issue_type": "nonrating",
- "benefit_type": "pension",
- "family": "040",
- "offical_label": "PMC Supplemental Claim nonrating",
- "disposition_type": "dta_error"
- },
- "040SCNR": {
- "review_type": "supplemental_claim",
- "issue_type": "nonrating",
- "benefit_type": "compensation",
- "family": "040",
- "offical_label": "Supplemental Claim nonrating"
- },
"040SCRPMC": {
"review_type": "supplemental_claim",
"issue_type": "rating",
@@ -212,34 +197,6 @@
"offical_label": "PMC Board Grant Rating",
"disposition_type": "allowed"
},
- "030HLRNR": {
- "review_type": "higher_level_review",
- "issue_type": "nonrating",
- "benefit_type": "compensation",
- "family": "030",
- "offical_label": "Higher-Level Review nonrating"
- },
- "030HLRNRPMC": {
- "review_type": "higher_level_review",
- "issue_type": "nonrating",
- "benefit_type": "pension",
- "family": "030",
- "offical_label": "PMC Higher-Level Review nonrating"
- },
- "030HLRR": {
- "review_type": "higher_level_review",
- "issue_type": "rating",
- "benefit_type": "compensation",
- "family": "030",
- "offical_label": "Higher-Level Review Rating"
- },
- "030HLRRPMC": {
- "review_type": "higher_level_review",
- "issue_type": "rating",
- "benefit_type": "pension",
- "family": "030",
- "offical_label": "PMC Higher-Level Review Rating"
- },
"930AHCNRLPMC": {
"review_type": "higher_level_review",
"issue_type": "nonrating",
diff --git a/client/constants/TASK_ACTIONS.json b/client/constants/TASK_ACTIONS.json
index 1b8d92d7ad7..06dcaccf096 100644
--- a/client/constants/TASK_ACTIONS.json
+++ b/client/constants/TASK_ACTIONS.json
@@ -90,7 +90,17 @@
},
"DOCKET_SWITCH_CHECKOUT": {
"label": "Send to Judge",
- "value": "docket_switch/checkout/review"
+ "value": "docket_switch/checkout/review",
+ "func": "docket_switch_granted_data"
+ },
+ "DOCKET_SWITCH_DENIED": {
+ "label": "Deny Docket Switch",
+ "value": "docket_switch/checkout/deny",
+ "func": "docket_switch_denied_data"
+ },
+ "DOCKET_SWITCH_GRANTED": {
+ "label": "Grant Docket Switch",
+ "value": "docket_switch/checkout/grant"
},
"CANCEL_FOREIGN_VETERANS_CASE_TASK": {
"label": "Cancel hearing request",
diff --git a/client/package.json b/client/package.json
index 270ff248806..741dfb72411 100644
--- a/client/package.json
+++ b/client/package.json
@@ -59,6 +59,7 @@
"@department-of-veterans-affairs/caseflow-frontend-toolkit": "https://github.com/department-of-veterans-affairs/caseflow-frontend-toolkit#71ee169",
"@fortawesome/fontawesome-free": "^5.3.1",
"@hookform/resolvers": "^0.1.1",
+ "@reduxjs/toolkit": "^1.4.0",
"@storybook/addon-a11y": "^6.0.7",
"@storybook/addon-actions": "^6.0.7",
"@storybook/addon-controls": "^6.0.7",
@@ -147,6 +148,7 @@
"enzyme-adapter-react-16": "^1.15.1",
"enzyme-to-json": "^3.5.0",
"eslint": "^7.0.0",
+ "eslint-import-resolver-webpack": "^0.13.0",
"eslint-plugin-babel": "^5.3.0",
"eslint-plugin-import": "^2.20.1",
"eslint-plugin-jest": "^23.19.0",
diff --git a/client/test/app/hearings/components/ScheduleVeteran.test.js b/client/test/app/hearings/components/ScheduleVeteran.test.js
index b067a6ee38c..c1f2f79cb01 100644
--- a/client/test/app/hearings/components/ScheduleVeteran.test.js
+++ b/client/test/app/hearings/components/ScheduleVeteran.test.js
@@ -1,6 +1,7 @@
import React from 'react';
import { mount } from 'enzyme';
import AppSegment from '@department-of-veterans-affairs/caseflow-frontend-toolkit/components/AppSegment';
+import { omit } from 'lodash';
import COPY from 'COPY';
import ScheduleVeteran from 'app/hearings/components/ScheduleVeteran';
@@ -378,7 +379,9 @@ describe('ScheduleVeteran', () => {
description: 'Update Task',
values: {
...scheduleHearingDetails.apiFormattedValues,
- virtual_hearing_attributes: ApiUtil.convertToSnakeCase(virtualHearing.virtualHearing),
+ virtual_hearing_attributes: ApiUtil.convertToSnakeCase(
+ omit(virtualHearing.virtualHearing, ['status'])
+ ),
override_full_hearing_day_validation: false,
},
},
diff --git a/client/test/app/hearings/components/__snapshots__/ScheduleVeteran.test.js.snap b/client/test/app/hearings/components/__snapshots__/ScheduleVeteran.test.js.snap
index d31059a245a..773b27629d9 100644
--- a/client/test/app/hearings/components/__snapshots__/ScheduleVeteran.test.js.snap
+++ b/client/test/app/hearings/components/__snapshots__/ScheduleVeteran.test.js.snap
@@ -49877,7 +49877,7 @@ SAN FRANCISCO, CA 94103
]
}
linkStyling={false}
- loading={true}
+ loading={false}
name="Schedule"
onClick={[Function]}
type="button"
@@ -49885,37 +49885,13 @@ SAN FRANCISCO, CA 94103
>
-
-
-
-
-
@@ -79318,7 +79294,7 @@ SAN FRANCISCO, CA 94103
]
}
linkStyling={false}
- loading={true}
+ loading={false}
name="Schedule"
onClick={[Function]}
type="button"
@@ -79326,37 +79302,13 @@ SAN FRANCISCO, CA 94103
>
-
-
-
-
-
@@ -168590,7 +168542,7 @@ SAN FRANCISCO, CA 94103
]
}
linkStyling={false}
- loading={true}
+ loading={false}
name="Schedule"
onClick={[Function]}
type="button"
@@ -168598,37 +168550,13 @@ SAN FRANCISCO, CA 94103
>
-
-
-
-
-
diff --git a/client/webpack.config.js b/client/webpack.config.js
index ff2eaa0b9e4..40da81f4835 100644
--- a/client/webpack.config.js
+++ b/client/webpack.config.js
@@ -20,7 +20,15 @@ const config = {
alias: {
// This does not actually appear to be necessary, but it does silence
// a warning from superagent-no-cache.
- ie: 'component-ie'
+ ie: 'component-ie',
+ app: path.resolve('app'),
+ constants: path.resolve('constants'),
+ layouts: path.resolve('app/2.0/layouts'),
+ routes: path.resolve('app/2.0/routes'),
+ store: path.resolve('app/2.0/store'),
+ screens: path.resolve('app/2.0/screens'),
+ components: path.resolve('app/2.0/components'),
+ test: path.resolve('test'),
}
},
module: {
diff --git a/client/yarn.lock b/client/yarn.lock
index ede3ec73071..4ea77176e08 100644
--- a/client/yarn.lock
+++ b/client/yarn.lock
@@ -2554,6 +2554,16 @@
prop-types "^15.6.1"
react-lifecycles-compat "^3.0.4"
+"@reduxjs/toolkit@^1.4.0":
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.4.0.tgz#ee2e2384cc3d1d76780d844b9c2da3580d32710d"
+ integrity sha512-hkxQwVx4BNVRsYdxjNF6cAseRmtrkpSlcgJRr3kLUcHPIAMZAmMJkXmHh/eUEGTMqPzsYpJLM7NN2w9fxQDuGw==
+ dependencies:
+ immer "^7.0.3"
+ redux "^4.0.0"
+ redux-thunk "^2.3.0"
+ reselect "^4.0.0"
+
"@sinonjs/commons@^1.7.0":
version "1.7.2"
resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.7.2.tgz#505f55c74e0272b43f6c52d81946bed7058fc0e2"
@@ -4277,6 +4287,11 @@ array-find-index@^1.0.1:
resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=
+array-find@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/array-find/-/array-find-1.0.0.tgz#6c8e286d11ed768327f8e62ecee87353ca3e78b8"
+ integrity sha1-bI4obRHtdoMn+OYuzuhzU8o+eLg=
+
array-flatten@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
@@ -7368,6 +7383,15 @@ enhanced-resolve@4.1.0:
memory-fs "^0.4.0"
tapable "^1.0.0"
+enhanced-resolve@^0.9.1:
+ version "0.9.1"
+ resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz#4d6e689b3725f86090927ccc86cd9f1635b89e2e"
+ integrity sha1-TW5omzcl+GCQknzMhs2fFjW4ni4=
+ dependencies:
+ graceful-fs "^4.1.2"
+ memory-fs "^0.2.0"
+ tapable "^0.1.8"
+
enhanced-resolve@^4.1.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz#3b806f3bfafc1ec7de69551ef93cca46c1704126"
@@ -7645,6 +7669,22 @@ eslint-import-resolver-node@^0.3.2:
debug "^2.6.9"
resolve "^1.13.1"
+eslint-import-resolver-webpack@^0.13.0:
+ version "0.13.0"
+ resolved "https://registry.yarnpkg.com/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.13.0.tgz#5cb19cf4b6996c8a2514aeb10f909e2c70488dc3"
+ integrity sha512-hZWGcmjaJZK/WSCYGI/y4+FMGQZT+cwW/1E/P4rDwFj2PbanlQHISViw4ccDJ+2wxAqjgwBfxwy3seABbVKDEw==
+ dependencies:
+ array-find "^1.0.0"
+ debug "^2.6.9"
+ enhanced-resolve "^0.9.1"
+ find-root "^1.1.0"
+ has "^1.0.3"
+ interpret "^1.2.0"
+ lodash "^4.17.15"
+ node-libs-browser "^1.0.0 || ^2.0.0"
+ resolve "^1.13.1"
+ semver "^5.7.1"
+
eslint-module-utils@^2.4.1:
version "2.5.2"
resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.5.2.tgz#7878f7504824e1b857dd2505b59a8e5eda26a708"
@@ -9590,6 +9630,11 @@ immer@1.10.0:
resolved "https://registry.yarnpkg.com/immer/-/immer-1.10.0.tgz#bad67605ba9c810275d91e1c2a47d4582e98286d"
integrity sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg==
+immer@^7.0.3:
+ version "7.0.7"
+ resolved "https://registry.yarnpkg.com/immer/-/immer-7.0.7.tgz#9dfe713d49bf871cc59aedfce59b1992fa37a977"
+ integrity sha512-Q8yYwVADJXrNfp1ZUAh4XDHkcoE3wpdpb4mC5abDSajs2EbW8+cGdPyAnglMyLnm7EF6ojD2xBFX7L5i4TIytw==
+
immutability-helper@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/immutability-helper/-/immutability-helper-3.0.1.tgz#4f609c5afbf8d78cb297970e8af2fba8b0eda1d6"
@@ -9835,7 +9880,7 @@ interpret@1.2.0:
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296"
integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==
-interpret@^1.0.0:
+interpret@^1.0.0, interpret@^1.2.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
@@ -11820,6 +11865,11 @@ memoizerific@^1.11.3:
dependencies:
map-or-similar "^1.5.0"
+memory-fs@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.2.0.tgz#f2bb25368bc121e391c2520de92969caee0a0290"
+ integrity sha1-8rslNovBIeORwlIN6Slpyu4KApA=
+
memory-fs@^0.4.0, memory-fs@^0.4.1, memory-fs@~0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
@@ -12427,7 +12477,7 @@ node-int64@^0.4.0:
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=
-node-libs-browser@^2.2.1:
+"node-libs-browser@^1.0.0 || ^2.0.0", node-libs-browser@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425"
integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==
@@ -14695,7 +14745,7 @@ redux@^3.7.2:
loose-envify "^1.1.0"
symbol-observable "^1.0.3"
-redux@^4.0.5:
+redux@^4.0.0, redux@^4.0.5:
version "4.0.5"
resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f"
integrity sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==
@@ -15372,7 +15422,7 @@ selfsigned@^1.10.7:
dependencies:
node-forge "0.9.0"
-"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0:
+"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0, semver@^5.7.1:
version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
@@ -16398,6 +16448,11 @@ table@^5.2.3:
slice-ansi "^2.1.0"
string-width "^3.0.0"
+tapable@^0.1.8:
+ version "0.1.10"
+ resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.1.10.tgz#29c35707c2b70e50d07482b5d202e8ed446dafd4"
+ integrity sha1-KcNXB8K3DlDQdIK10gLo7URtr9Q=
+
tapable@^1.0.0, tapable@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
diff --git a/db/migrate/20201020135542_cavc_remand_updated_by_nullable.rb b/db/migrate/20201020135542_cavc_remand_updated_by_nullable.rb
new file mode 100644
index 00000000000..f69c6e3fef7
--- /dev/null
+++ b/db/migrate/20201020135542_cavc_remand_updated_by_nullable.rb
@@ -0,0 +1,6 @@
+class CavcRemandUpdatedByNullable < Caseflow::Migration
+ def change
+ safety_assured { remove_column :cavc_remands, :updated_by_id, :bigint, null: false, comment: "User that updated this record. For MDR remands, judgement and mandate dates will be added after the record is first created." }
+ add_column :cavc_remands, :updated_by_id, :bigint, comment: "User that updated this record. For MDR remands, judgement and mandate dates will be added after the record is first created."
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 87456c5ee1f..4a7de6f9bec 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 2020_10_05_190456) do
+ActiveRecord::Schema.define(version: 2020_10_20_135542) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -280,7 +280,7 @@
t.string "remand_subtype", comment: "Type of remand. If the cavc_decision_type is 'remand', expecting one of 'jmp', 'jmpr', or 'mdr'. Otherwise, this can be null."
t.boolean "represented_by_attorney", null: false, comment: "Whether or not the appellant was represented by an attorney"
t.datetime "updated_at", null: false, comment: "Default timestamps"
- t.bigint "updated_by_id", null: false, comment: "User that updated this record. For MDR remands, judgement and mandate dates will be added after the record is first created."
+ t.bigint "updated_by_id", comment: "User that updated this record. For MDR remands, judgement and mandate dates will be added after the record is first created."
t.index ["appeal_id"], name: "index_cavc_remands_on_appeal_id"
end
diff --git a/docs/schema/caseflow.csv b/docs/schema/caseflow.csv
index 86e372985f8..8a16b68a493 100644
--- a/docs/schema/caseflow.csv
+++ b/docs/schema/caseflow.csv
@@ -194,7 +194,7 @@ cavc_remands,mandate_date,date ∗,x,,,,,Date that CAVC reported the mandate w
cavc_remands,remand_subtype,string ∗,x,,,,,"Type of remand. If the cavc_decision_type is 'remand', expecting one of 'jmp', 'jmpr', or 'mdr'. Otherwise, this can be null."
cavc_remands,represented_by_attorney,boolean ∗,x,,,,,Whether or not the appellant was represented by an attorney
cavc_remands,updated_at,datetime ∗,x,,,,,Default timestamps
-cavc_remands,updated_by_id,integer (8) ∗ FK,x,,x,,,"User that updated this record. For MDR remands, judgement and mandate dates will be added after the record is first created."
+cavc_remands,updated_by_id,integer (8) FK,,,x,,,"User that updated this record. For MDR remands, judgement and mandate dates will be added after the record is first created."
certifications,,,,,,,,
certifications,already_certified,boolean,,,,,,
certifications,bgs_rep_address_line_1,string,,,,,,
@@ -409,16 +409,6 @@ end_product_code_updates,created_at,datetime ∗,x,,,,,
end_product_code_updates,end_product_establishment_id,integer (8) ∗ FK,x,,x,,x,
end_product_code_updates,id,integer (8) PK,x,x,,,,
end_product_code_updates,updated_at,datetime ∗,x,,,,x,
-end_product_updates,,,,,,,, "Updates the claim label for end products established from Caseflow."
-end_product_updates,user_id,integer,"The ID of the user who makes an end product update."
-end_product_updates,end_product_establishment_id,bigint,"The end product establishment id used to track the end product being updated"
-end_product_updates,original_decision_review_id,bigint,"The original ID of the decision review that this end product update belongs to; has a non-nil value only if a new decision_review was created."
-end_product_updates,original_decision_review_type,string,"The original decision review type that this end product update belongs to"
-end_product_updates,status,string,"Status after an attempt to update the end product; expected values: 'success', 'error', ..."
-end_product_updates,error,string,"The error message captured from BGS if the end product update failed."
-end_product_updates,original_code,string,"The original end product code before the update was submitted"
-end_product_updates,new_code,string,"The new end product code the user wants to update to."
-end_product_updates,active_request_issue_ids,integer,"A list of active request issue IDs when a user has finished editing a decision review. Used to keep track of which request issues may have been impacted by the update."
end_product_establishments,,,,,,,,"Represents end products that have been, or need to be established by Caseflow. Used to track the status of those end products as they are processed in VBMS and/or SHARE."
end_product_establishments,benefit_type_code,string,,,,,,"1 if the Veteran is alive, and 2 if the Veteran is deceased. Not to be confused with benefit_type, which is unrelated."
end_product_establishments,claim_date,date,,,,,,The claim_date for end product established.
@@ -443,6 +433,19 @@ end_product_establishments,synced_status,string,,,,,,"The status of the end prod
end_product_establishments,updated_at,datetime,,,,,x,
end_product_establishments,user_id,integer FK,,,x,,x,The ID of the user who performed the decision review intake.
end_product_establishments,veteran_file_number,string ∗,x,,,,x,The file number of the Veteran submitted when establishing the end product.
+end_product_updates,,,,,,,,Updates the claim label for end products established from Caseflow
+end_product_updates,active_request_issue_ids,integer (8) ∗,x,,,,,A list of active request issue IDs when a user has finished editing a decision review. Used to keep track of which request issues may have been impacted by the update.
+end_product_updates,created_at,datetime ∗,x,,,,,
+end_product_updates,end_product_establishment_id,integer (8) ∗ FK,x,,x,,x,The end product establishment id used to track the end product being updated.
+end_product_updates,error,string,,,,,,The error message captured from BGS if the end product update failed.
+end_product_updates,id,integer (8) PK,x,x,,,,
+end_product_updates,new_code,string,,,,,,The new end product code the user wants to update to.
+end_product_updates,original_code,string,,,,,,The original end product code before the update was submitted.
+end_product_updates,original_decision_review_id,integer (8),,,,,x,The original decision review that this end product update belongs to; has a non-nil value only if a new decision_review was created.
+end_product_updates,original_decision_review_type,string,,,,,x,The original decision review type that this end product update belongs to
+end_product_updates,status,string,,,,,,"Status after an attempt to update the end product; expected values: 'success', 'error', ..."
+end_product_updates,updated_at,datetime ∗,x,,,,,
+end_product_updates,user_id,integer (8) ∗,x,,,,x,The ID of the user who makes an end product update.
form8s,,,,,,,,
form8s,_initial_appellant_name,string,,,,,,
form8s,_initial_appellant_relationship,string,,,,,,
diff --git a/lib/caseflow/error.rb b/lib/caseflow/error.rb
index 68785012755..4c2e7328c21 100644
--- a/lib/caseflow/error.rb
+++ b/lib/caseflow/error.rb
@@ -364,8 +364,8 @@ class VirtualHearingConversionFailed < SerializableError
def initialize(args = {})
@error_type = args[:error_type]
- @code = (@error_type == ActiveRecord::RecordNotUnique) ? :conflict : args[:code]
- @message = (@error_type == ActiveRecord::RecordNotUnique) ? COPY::VIRTUAL_HEARING_ALREADY_CREATED : args[:message]
+ @code = args[:code]
+ @message = args[:message]
end
end
end
diff --git a/spec/controllers/api/v3/base_controller_spec.rb b/spec/controllers/api/v3/base_controller_spec.rb
deleted file mode 100644
index 9329c490fdf..00000000000
--- a/spec/controllers/api/v3/base_controller_spec.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe Api::V3::BaseController, type: :controller do
- describe "#api_released used in before_action" do
- controller do
- def index
- render json: { meta: { text: "This is just a test action." } }
- end
- end
-
- before(:each) do
- allow(controller).to receive(:verify_authentication_token).and_return(true)
- end
-
- describe "when not enabled" do
- it "should return a 501 response" do
- get :index
- expect(response).to have_http_status(:not_implemented)
- end
- it "should have a jsonapi error response" do
- get :index
- expect { JSON.parse(response.body) }.to_not raise_error
- parsed_response = JSON.parse(response.body)
- expect(parsed_response["errors"]).to be_a Array
- expect(parsed_response["errors"].first).to include("status", "title", "detail")
- end
- end
-
- describe "when enabled" do
- before do
- FeatureToggle.enable!(:api_v3)
- end
- after do
- FeatureToggle.disable!(:api_v3)
- end
- it "should return a 200 response" do
- get :index
- expect(response).to have_http_status(:ok)
- end
- end
- end
-end
diff --git a/spec/controllers/tasks_controller_spec.rb b/spec/controllers/tasks_controller_spec.rb
index ab3e1683244..3862f22457d 100644
--- a/spec/controllers/tasks_controller_spec.rb
+++ b/spec/controllers/tasks_controller_spec.rb
@@ -860,6 +860,18 @@
include_examples "returns alerts"
it_behaves_like "request with invalid attributes"
+
+ # See https://github.com/department-of-veterans-affairs/caseflow/issues/15430
+ context "when virtual hearing payload includes virtual hearing status" do
+ let(:virtual_hearing_attributes) do
+ {
+ appellant_email: "valid@caseflow.va.gov",
+ status: "pending"
+ }
+ end
+
+ it_behaves_like "request with invalid attributes"
+ end
end
context "when task is ChangeHearingRequestTypeTask" do
diff --git a/spec/factories/vacols/case_hearing.rb b/spec/factories/vacols/case_hearing.rb
index 25d75e8e547..729bcf38e37 100644
--- a/spec/factories/vacols/case_hearing.rb
+++ b/spec/factories/vacols/case_hearing.rb
@@ -31,13 +31,6 @@
hearing_disp { "N" }
end
- after(:create) do |hearing, _evaluator|
- # For some reason the returned record's sequence is one less than what is actually saved.
- # We need to reload the correct record before trying to modify it.
- hearing.hearing_pkseq = hearing.hearing_pkseq + 1
- hearing.reload
- end
-
after(:build) do |hearing, evaluator|
# Build Caseflow hearing day and associate with legacy hearing.
if hearing.vdkey.nil?
diff --git a/spec/feature/hearings/change_hearing_disposition_spec.rb b/spec/feature/hearings/change_hearing_disposition_spec.rb
index 366a9bc86d3..4fa71cb5f14 100644
--- a/spec/feature/hearings/change_hearing_disposition_spec.rb
+++ b/spec/feature/hearings/change_hearing_disposition_spec.rb
@@ -125,7 +125,9 @@
step "change the hearing disposition to cancelled" do
expect(Raven).to receive(:capture_exception)
- .with(AssignHearingDispositionTask::HearingAssociationMissing) { @raven_called = true }
+ .with(AssignHearingDispositionTask::HearingAssociationMissing, any_args) do
+ @raven_called = true
+ end
click_dropdown(prompt: "Select an action", text: "Change hearing disposition")
click_dropdown({ prompt: "Select", text: "Cancelled" }, find(".cf-modal-body"))
diff --git a/spec/feature/hearings/postpone_hearing_spec.rb b/spec/feature/hearings/postpone_hearing_spec.rb
index 81f0b80cef5..94326b2f8ac 100644
--- a/spec/feature/hearings/postpone_hearing_spec.rb
+++ b/spec/feature/hearings/postpone_hearing_spec.rb
@@ -143,6 +143,8 @@
expect(Hearing.where(hearing_day: hearing_day_earlier).count).to eq 1
expect(Hearing.find_by(hearing_day: hearing_day_earlier).hearing_location.facility_id).to eq "vba_339"
expect(Hearing.first.disposition).to eq "postponed"
+ expect(Hearing.second.disposition).to be_nil
+ expect(Hearing.second.uuid).to_not eq Hearing.first.uuid
expect(HearingTask.count).to eq 2
end
end
@@ -166,6 +168,8 @@
expect(page).to have_content("You have successfully assigned")
expect(LegacyHearing.second.hearing_day.id).to eq hearing_day_earlier.id
expect(LegacyHearing.first.disposition).to eq "postponed"
+ expect(LegacyHearing.second.disposition).to be_nil
+ expect(LegacyHearing.second.vacols_id).to_not eq LegacyHearing.first.vacols_id
expect(HearingTask.first.hearing.id).to eq legacy_hearing.id
expect(HearingTask.second.hearing.id).to eq LegacyHearing.second.id
end
@@ -290,6 +294,8 @@
expect(page).to have_content("You have successfully assigned")
expect(LegacyHearing.second.hearing_day.id).to eq hearing_day_earlier.id
expect(LegacyHearing.first.disposition).to eq "postponed"
+ expect(LegacyHearing.second.disposition).to be_nil
+ expect(LegacyHearing.second.vacols_id).to_not eq LegacyHearing.first.vacols_id
expect(HearingTask.first.hearing.id).to eq legacy_hearing.id
expect(HearingTask.second.hearing.id).to eq LegacyHearing.second.id
end
diff --git a/spec/models/docket_spec.rb b/spec/models/docket_spec.rb
index 604bc658ef7..7ea1db538a0 100644
--- a/spec/models/docket_spec.rb
+++ b/spec/models/docket_spec.rb
@@ -207,11 +207,21 @@
end
context "age_of_oldest_priority_appeal" do
- subject { DirectReviewDocket.new.age_of_oldest_priority_appeal }
+ let(:docket) { DirectReviewDocket.new }
+
+ subject { docket.age_of_oldest_priority_appeal }
it "returns the 'ready at' field of the oldest priority appeal that is ready for distribution" do
expect(subject).to eq(aod_age_appeal.ready_for_distribution_at)
end
+
+ context "when there are no ready priority appeals" do
+ let(:docket) { EvidenceSubmissionDocket.new }
+
+ it "returns nil" do
+ expect(subject.nil?).to be true
+ end
+ end
end
context "distribute_appeals" do
diff --git a/spec/models/end_product_establishment_spec.rb b/spec/models/end_product_establishment_spec.rb
index c9c6720cf7c..52ece6036d4 100644
--- a/spec/models/end_product_establishment_spec.rb
+++ b/spec/models/end_product_establishment_spec.rb
@@ -1372,6 +1372,12 @@
context "if there is no modifier, shows unknown" do
it { is_expected.to eq(ep_code: " Higher-Level Review Rating", ep_status: "") }
end
+
+ context "if the epe code is not found" do
+ before { epe.update!(code: "NOTFOUND") }
+
+ it { is_expected.to eq(ep_code: " Unknown", ep_status: "") }
+ end
end
context "if there is not an end product" do
diff --git a/spec/models/promulgated_rating_spec.rb b/spec/models/promulgated_rating_spec.rb
index b7ff6ba11f5..7d0cb9d22b9 100644
--- a/spec/models/promulgated_rating_spec.rb
+++ b/spec/models/promulgated_rating_spec.rb
@@ -111,22 +111,59 @@
end
context "#rating_profile" do
- subject { rating.rating_profile }
+ let(:bgs) { Fakes::BGSService.new }
+
+ before do
+ allow(Fakes::BGSService).to receive(:new).and_return(bgs)
+ end
- context "when BGS throws a Share Error" do
- let(:bgs) { Fakes::BGSService.new }
+ subject { rating.rating_profile }
+ context "BGS throws a Share Error on fetch_rating_profile" do
before do
- allow(Fakes::BGSService).to receive(:new).and_return(bgs)
allow(bgs).to receive(:fetch_rating_profile)
.and_raise(BGS::ShareError, "Veteran does not meet the minimum disability requirements")
- allow(bgs).to receive(:fetch_rating_profiles_in_range).and_call_original
end
- it "Fetches the rating profile using RatingAtIssue" do
- expect(subject.present?)
- expect { rating.issues }.to_not raise_error
- expect(bgs).to have_received(:fetch_rating_profiles_in_range)
+ context "BGS returns a successful response on fetch_rating_profiles_in_range" do
+ before do
+ allow(bgs).to receive(:fetch_rating_profiles_in_range).and_call_original
+ end
+
+ it "Fetches the rating profile using RatingAtIssue" do
+ expect(subject.present?)
+ expect { rating.issues }.to_not raise_error
+ expect(bgs).to have_received(:fetch_rating_profiles_in_range)
+ end
+ end
+
+ context "an error is raised on fetch_rating_profiles_in_range" do
+ let(:error) { nil }
+ let(:message) { "" }
+
+ before do
+ allow(bgs).to receive(:fetch_rating_profiles_in_range)
+ .and_raise(error, message)
+ end
+
+ context "a share error is raised on fetch_rating_profiles_in_range" do
+ let(:error) { BGS::ShareError }
+ let(:message) { "Veteran does not meet the minimum disability requirements" }
+
+ it "captures the exception and returns an empty object" do
+ expect(Raven).to receive(:capture_exception).with error
+ expect(subject).to eq({})
+ end
+ end
+
+ context "a nil rating profile list error is raised on fetch_rating_profiles_in_range" do
+ let(:error) { Rating::NilRatingProfileListError }
+
+ it "captures the exception returns an empty object" do
+ expect(Raven).to receive(:capture_exception).with error
+ expect(subject).to eq({})
+ end
+ end
end
end
end
diff --git a/spec/models/tasks/assign_hearing_disposition_task_spec.rb b/spec/models/tasks/assign_hearing_disposition_task_spec.rb
index bba43cf1ccf..49114adae8c 100644
--- a/spec/models/tasks/assign_hearing_disposition_task_spec.rb
+++ b/spec/models/tasks/assign_hearing_disposition_task_spec.rb
@@ -57,10 +57,9 @@
end
it "sets the hearing disposition and calls hold!" do
- expect(disposition_task).to receive(:hold!).exactly(1).times
-
- subject
+ expect(disposition_task).to receive(:hold!).exactly(1).times.and_call_original
+ expect(subject.count).to eq 3
expect(Hearing.count).to eq 1
expect(hearing.disposition).to eq Constants.HEARING_DISPOSITION_TYPES.held
end
@@ -79,10 +78,9 @@
end
it "sets the hearing disposition and calls no_show!" do
- expect(disposition_task).to receive(:no_show!).exactly(1).times
-
- subject
+ expect(disposition_task).to receive(:no_show!).exactly(1).times.and_call_original
+ expect(subject.count).to eq(2)
expect(Hearing.count).to eq 1
expect(hearing.disposition).to eq Constants.HEARING_DISPOSITION_TYPES.no_show
end
diff --git a/spec/models/tasks/docket_switch_denied_task_spec.rb b/spec/models/tasks/docket_switch_denied_task_spec.rb
new file mode 100644
index 00000000000..83dfe09813b
--- /dev/null
+++ b/spec/models/tasks/docket_switch_denied_task_spec.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+describe DocketSwitchDeniedTask, :postgres do
+ let(:cotb_team) { ClerkOfTheBoard.singleton }
+ let(:root_task) { create(:root_task) }
+ let(:task_class) { DocketSwitchDeniedTask }
+ let(:judge) { create(:user, :with_vacols_judge_record, full_name: "Judge the First", css_id: "JUDGE_1") }
+
+ let(:attorney) { create(:user, :with_vacols_attorney_record) }
+
+ let(:task_actions) do
+ [Constants.TASK_ACTIONS.REVIEW_DECISION_DRAFT.to_h,
+ Constants.TASK_ACTIONS.ADD_ADMIN_ACTION.to_h,
+ Constants.TASK_ACTIONS.CANCEL_AND_RETURN_TASK.to_h]
+ end
+
+ before do
+ cotb_team.add_user(attorney)
+ end
+
+ describe ".available_actions" do
+ let(:attonery_task) do
+ task_class.create!(
+ appeal: root_task.appeal,
+ parent_id: root_task.id,
+ assigned_to: attorney,
+ assigned_by: judge
+ )
+ end
+
+ subject { attonery_task.available_actions(attorney) }
+
+ context "when the current user is not a member of the Clerk of the Board team" do
+ before { allow_any_instance_of(ClerkOfTheBoard).to receive(:user_has_access?).and_return(false) }
+ context "without docket_change feature toggle" do
+ it "returns the correct label" do
+ expect(DocketSwitchDeniedTask.new.label).to eq(
+ COPY::DOCKET_SWITCH_DENIED_TASK_LABEL
+ )
+ end
+ end
+
+ context "with docket_change feature toggle" do
+ before { FeatureToggle.enable!(:docket_change) }
+ after { FeatureToggle.disable!(:docket_change) }
+
+ it "returns the available_actions as defined by Task" do
+ expect(subject).to eq(task_actions)
+ end
+ end
+ end
+
+ context "when the current user is a member of the Clerk of the Board team" do
+ context "without docket_change feature toggle" do
+ it "returns the available_actions as defined by Task" do
+ expect(subject).to eq(task_actions)
+ end
+ end
+
+ context "with docket_change feature toggle" do
+ before { FeatureToggle.enable!(:docket_change) }
+ after { FeatureToggle.disable!(:docket_change) }
+
+ it "returns the available_actions as defined by Task" do
+ expect(subject).to eq(task_actions + [Constants.TASK_ACTIONS.DOCKET_SWITCH_DENIED.to_h])
+ end
+ end
+ end
+ end
+end
diff --git a/spec/models/tasks/docket_switch_granted_task_spec.rb b/spec/models/tasks/docket_switch_granted_task_spec.rb
new file mode 100644
index 00000000000..2fe28adfeac
--- /dev/null
+++ b/spec/models/tasks/docket_switch_granted_task_spec.rb
@@ -0,0 +1,70 @@
+# frozen_string_literal: true
+
+describe DocketSwitchGrantedTask, :postgres do
+ let(:cotb_team) { ClerkOfTheBoard.singleton }
+ let(:root_task) { create(:root_task) }
+ let(:task_class) { DocketSwitchGrantedTask }
+ let(:judge) { create(:user, :with_vacols_judge_record, full_name: "Judge the First", css_id: "JUDGE_1") }
+
+ let(:attorney) { create(:user, :with_vacols_attorney_record) }
+
+ let(:task_actions) do
+ [Constants.TASK_ACTIONS.REVIEW_DECISION_DRAFT.to_h,
+ Constants.TASK_ACTIONS.ADD_ADMIN_ACTION.to_h,
+ Constants.TASK_ACTIONS.CANCEL_AND_RETURN_TASK.to_h]
+ end
+
+ before do
+ cotb_team.add_user(attorney)
+ end
+
+ describe ".available_actions" do
+ let(:attonery_task) do
+ task_class.create!(
+ appeal: root_task.appeal,
+ parent_id: root_task.id,
+ assigned_to: attorney,
+ assigned_by: judge
+ )
+ end
+
+ subject { attonery_task.available_actions(attorney) }
+
+ context "when the current user is not a member of the Clerk of the Board team" do
+ before { allow_any_instance_of(ClerkOfTheBoard).to receive(:user_has_access?).and_return(false) }
+ context "without docket_change feature toggle" do
+ it "returns the correct label" do
+ expect(DocketSwitchGrantedTask.new.label).to eq(
+ COPY::DOCKET_SWITCH_GRANTED_TASK_LABEL
+ )
+ end
+ end
+
+ context "with docket_change feature toggle" do
+ before { FeatureToggle.enable!(:docket_change) }
+ after { FeatureToggle.disable!(:docket_change) }
+
+ it "returns the available_actions as defined by Task" do
+ expect(subject).to eq(task_actions)
+ end
+ end
+ end
+
+ context "when the current user is a member of the Clerk of the Board team" do
+ context "without docket_change feature toggle" do
+ it "returns the available_actions as defined by Task" do
+ expect(subject).to eq(task_actions)
+ end
+ end
+
+ context "with docket_change feature toggle" do
+ before { FeatureToggle.enable!(:docket_change) }
+ after { FeatureToggle.disable!(:docket_change) }
+
+ it "returns the available_actions as defined by Task" do
+ expect(subject).to eq(task_actions + [Constants.TASK_ACTIONS.DOCKET_SWITCH_GRANTED.to_h])
+ end
+ end
+ end
+ end
+end
diff --git a/spec/models/tasks/schedule_hearing_task_spec.rb b/spec/models/tasks/schedule_hearing_task_spec.rb
index 57e89fa5cd8..e42a3db8892 100644
--- a/spec/models/tasks/schedule_hearing_task_spec.rb
+++ b/spec/models/tasks/schedule_hearing_task_spec.rb
@@ -75,6 +75,8 @@
end
describe "#update_from_params" do
+ subject { schedule_hearing_task.update_from_params(update_params, hearings_management_user) }
+
context "AMA appeal" do
let(:hearing_day) do
create(:hearing_day,
@@ -95,19 +97,15 @@
}
end
- subject { schedule_hearing_task.update_from_params(update_params, hearings_management_user) }
-
it "associates a caseflow hearing with the hearing day" do
- subject
-
+ expect(subject.count).to eq(2)
expect(Hearing.count).to eq(1)
expect(Hearing.first.hearing_day).to eq(hearing_day)
expect(Hearing.first.appeal).to eq(schedule_hearing_task.appeal)
end
it "creates a AssignHearingDispositionTask and associated object" do
- subject
-
+ expect(subject.count).to eq(2)
expect(AssignHearingDispositionTask.count).to eq(1)
expect(AssignHearingDispositionTask.first.appeal).to eq(schedule_hearing_task.appeal)
expect(HearingTaskAssociation.count).to eq(1)
@@ -128,8 +126,7 @@
end
it "converts hearing to virtual hearing", :aggregate_failures do
- subject
-
+ expect(subject.count).to eq(2)
expect(Hearing.count).to eq(1)
expect(Hearing.first.virtual_hearing).not_to eq(nil)
expect(Hearing.first.virtual?).to eq(true)
@@ -169,8 +166,7 @@
context "with no VSO" do
it "completes the task and updates the location to case storage" do
- schedule_hearing_task.update_from_params(update_params, hearings_management_user)
-
+ expect(subject.count).to eq(1)
expect(schedule_hearing_task.status).to eq(Constants.TASK_STATUSES.cancelled)
expect(schedule_hearing_task.closed_at).to_not be_nil
expect(vacols_case.reload.bfcurloc).to eq(LegacyAppeal::LOCATION_CODES[:case_storage])
@@ -199,8 +195,7 @@
end
it "completes the task and updates the location to service organization" do
- schedule_hearing_task.update_from_params(update_params, hearings_management_user)
-
+ expect(subject.count).to eq(1)
expect(schedule_hearing_task.status).to eq(Constants.TASK_STATUSES.cancelled)
expect(vacols_case.reload.bfcurloc).to eq(LegacyAppeal::LOCATION_CODES[:service_organization])
expect(vacols_case.bfha).to eq("5")
@@ -216,8 +211,7 @@
end
it "completes the task and creates an EvidenceSubmissionWindowTask" do
- schedule_hearing_task.update_from_params(update_params, hearings_management_user)
-
+ expect(subject.count).to eq(2)
expect(schedule_hearing_task.status).to eq(Constants.TASK_STATUSES.cancelled)
expect(appeal.tasks.where(type: EvidenceSubmissionWindowTask.name).count).to eq(1)
end
diff --git a/spec/requests/api/v3/decision_reviews/appeals/contestable_issues_controller_spec.rb b/spec/requests/api/v3/decision_reviews/appeals/contestable_issues_controller_spec.rb
index 7cc61ac497a..3f1926f7823 100644
--- a/spec/requests/api/v3/decision_reviews/appeals/contestable_issues_controller_spec.rb
+++ b/spec/requests/api/v3/decision_reviews/appeals/contestable_issues_controller_spec.rb
@@ -1,6 +1,16 @@
# frozen_string_literal: true
describe Api::V3::DecisionReviews::Appeals::ContestableIssuesController, :postgres, type: :request do
+ include IntakeHelpers
+
+ before do
+ FeatureToggle.enable!(:api_v3_appeals_contestable_issues)
+
+ Timecop.freeze(post_ama_start_date)
+ end
+
+ after { FeatureToggle.disable!(:api_v3_appeals_contestable_issues) }
+
let(:decision_review_type) { :appeal }
let(:source) do
appeal = create(decision_review_type, veteran_file_number: veteran.file_number)
diff --git a/spec/requests/api/v3/decision_reviews/higher_level_reviews/contestable_issues_controller_spec.rb b/spec/requests/api/v3/decision_reviews/higher_level_reviews/contestable_issues_controller_spec.rb
index 814e69773e6..c643c2c50df 100644
--- a/spec/requests/api/v3/decision_reviews/higher_level_reviews/contestable_issues_controller_spec.rb
+++ b/spec/requests/api/v3/decision_reviews/higher_level_reviews/contestable_issues_controller_spec.rb
@@ -5,6 +5,16 @@
let(:source) { create(:higher_level_review, veteran_file_number: veteran.file_number, same_office: false) }
let(:benefit_type) { "compensation" }
+ include IntakeHelpers
+
+ before do
+ FeatureToggle.enable!(:api_v3_higher_level_reviews_contestable_issues)
+
+ Timecop.freeze(post_ama_start_date)
+ end
+
+ after { FeatureToggle.disable!(:api_v3_higher_level_reviews_contestable_issues) }
+
include_examples "contestable issues index requests"
describe "#index" do
@@ -34,5 +44,22 @@
expect(response).to have_http_status(:unprocessable_entity)
end
end
+
+ context "when feature toggle is not enabled" do
+ before { FeatureToggle.disable!(:api_v3_higher_level_reviews_contestable_issues) }
+
+ it "should return a 501 response" do
+ get_issues
+ expect(response).to have_http_status(:not_implemented)
+ end
+
+ it "should have a jsonapi error response" do
+ get_issues
+ expect { JSON.parse(response.body) }.to_not raise_error
+ parsed_response = JSON.parse(response.body)
+ expect(parsed_response["errors"]).to be_a Array
+ expect(parsed_response["errors"].first).to include("status", "title", "detail")
+ end
+ end
end
end
diff --git a/spec/requests/api/v3/decision_reviews/higher_level_reviews_controller_spec.rb b/spec/requests/api/v3/decision_reviews/higher_level_reviews_controller_spec.rb
index 4772a2ba409..58ba16ac9fe 100644
--- a/spec/requests/api/v3/decision_reviews/higher_level_reviews_controller_spec.rb
+++ b/spec/requests/api/v3/decision_reviews/higher_level_reviews_controller_spec.rb
@@ -6,12 +6,12 @@
include IntakeHelpers
before do
- FeatureToggle.enable!(:api_v3)
+ FeatureToggle.enable!(:api_v3_higher_level_reviews)
Timecop.freeze(post_ama_start_date)
end
- after { FeatureToggle.disable!(:api_v3) }
+ after { FeatureToggle.disable!(:api_v3_higher_level_reviews) }
let!(:rating) do
promulgation_date = receipt_date - 10.days
@@ -109,6 +109,25 @@ def post_create(parameters = params)
let(:expected_error_json) { expected_error_render_hash[:json].as_json }
let(:expected_error_status) { expected_error_render_hash[:status] }
+ context "when feature toggle is not enabled" do
+ before { FeatureToggle.disable!(:api_v3_higher_level_reviews) }
+
+ it "should return a 501 response" do
+ allow_any_instance_of(HigherLevelReview).to receive(:asyncable_status) { :submitted }
+ post_create
+ expect(response).to have_http_status(:not_implemented)
+ end
+
+ it "should have a jsonapi error response" do
+ allow_any_instance_of(HigherLevelReview).to receive(:asyncable_status) { :submitted }
+ post_create
+ expect { JSON.parse(response.body) }.to_not raise_error
+ parsed_response = JSON.parse(response.body)
+ expect(parsed_response["errors"]).to be_a Array
+ expect(parsed_response["errors"].first).to include("status", "title", "detail")
+ end
+ end
+
context "good request" do
it "should return a 202 on success" do
allow_any_instance_of(HigherLevelReview).to receive(:asyncable_status) { :submitted }
diff --git a/spec/services/external_api/bgs_service_spec.rb b/spec/services/external_api/bgs_service_spec.rb
index b445cbe0c9d..b048ad158b8 100644
--- a/spec/services/external_api/bgs_service_spec.rb
+++ b/spec/services/external_api/bgs_service_spec.rb
@@ -287,4 +287,45 @@
end
end
end
+
+ describe "fetch_ratings_in_range" do
+ let!(:veteran) { create(:veteran) }
+ let!(:rating) { double("rating") }
+ let(:start_date) { Time.zone.now - 5.years }
+ let(:start_date_formatted) { start_date.to_date.to_datetime.iso8601 }
+ let(:end_date) { start_date }
+
+ before do
+ allow(bgs_client).to receive(:rating).and_return rating
+ end
+
+ subject do
+ bgs.fetch_ratings_in_range(participant_id: veteran.participant_id, start_date: start_date, end_date: end_date)
+ end
+
+ context "the start and end dates are the same" do
+ let(:end_date_formatted) { (start_date + 1.day).to_date.to_datetime.iso8601 }
+
+ it "formats dates correctly" do
+ expect(rating)
+ .to receive(:find_by_participant_id_and_date_range)
+ .with(veteran.participant_id, start_date_formatted, end_date_formatted)
+
+ subject
+ end
+ end
+
+ context "the start and end dates are different" do
+ let(:end_date) { Time.zone.now }
+ let(:end_date_formatted) { end_date.to_date.to_datetime.iso8601 }
+
+ it "formats dates correctly" do
+ expect(rating)
+ .to receive(:find_by_participant_id_and_date_range)
+ .with(veteran.participant_id, start_date_formatted, end_date_formatted)
+
+ subject
+ end
+ end
+ end
end
diff --git a/spec/services/hearing_task_tree_initializer_spec.rb b/spec/services/hearing_task_tree_initializer_spec.rb
index f92e2a29e98..eb0663be1ad 100644
--- a/spec/services/hearing_task_tree_initializer_spec.rb
+++ b/spec/services/hearing_task_tree_initializer_spec.rb
@@ -13,7 +13,7 @@
subject { described_class.for_appeal_with_pending_travel_board_hearing(appeal) }
- context "if task tree does not already exist" do
+ context "the task tree does not already exist" do
it "it creates the expected tasks" do
expect(ChangeHearingRequestTypeTask.count).to eq(0)
expect(ScheduleHearingTask.count).to eq(0)
@@ -35,7 +35,7 @@
end
end
- context "if an open hearing task already exists" do
+ context "an open hearing task already exists" do
let(:root_task) { create(:root_task, appeal: appeal) }
let(:hearing_task) { create(:hearing_task, appeal: appeal, parent: root_task) }
let!(:schedule_hearing_task) { create(:schedule_hearing_task, appeal: appeal, parent: hearing_task) }
@@ -47,6 +47,25 @@
expect(HearingTask.count).to eq(1)
end
end
+
+ context "there's a closed hearing task on the appeal" do
+ let(:root_task) { create(:root_task, appeal: appeal) }
+ let!(:hearing_task) do
+ create(:hearing_task, appeal: appeal, parent: root_task)
+ end
+
+ before do
+ hearing_task.update!(status: Constants.TASK_STATUSES.completed)
+ end
+
+ it "creates a new hearing task parent" do
+ expect(HearingTask.count).to eq(1)
+ subject
+ expect(ChangeHearingRequestTypeTask.count).to eq(1)
+ expect(ScheduleHearingTask.count).to eq(1)
+ expect(HearingTask.count).to eq(2)
+ end
+ end
end
context "#create_schedule_hearing_tasks" do
diff --git a/spec/support/shared_context/requests/api/v3/decision_reviews/shared_context_contestable_issues.rb b/spec/support/shared_context/requests/api/v3/decision_reviews/shared_context_contestable_issues.rb
index fabdfad4bd1..0d6f7b9363e 100644
--- a/spec/support/shared_context/requests/api/v3/decision_reviews/shared_context_contestable_issues.rb
+++ b/spec/support/shared_context/requests/api/v3/decision_reviews/shared_context_contestable_issues.rb
@@ -14,18 +14,27 @@
let!(:api_key) { ApiKey.create!(consumer_name: "ApiV3 Test Consumer").key_string }
let(:veteran) { create(:veteran).unload_bgs_record }
let(:ssn) { veteran.ssn }
+ let(:file_number) { nil }
let(:response_data) { JSON.parse(response.body)["data"] }
let(:receipt_date) { Time.zone.today }
let(:get_issues) do
benefit_type_url_string = benefit_type ? "/#{benefit_type}" : ""
+
+ headers = {
+ "Authorization" => "Token #{api_key}",
+ "X-VA-Receipt-Date" => receipt_date.try(:strftime, "%F") || receipt_date
+ }
+
+ if file_number.present?
+ headers["X-VA-File-Number"] = file_number
+ elsif ssn.present?
+ headers["X-VA-SSN"] = ssn
+ end
+
get(
"/api/v3/decision_reviews/#{decision_review_type}s/contestable_issues#{benefit_type_url_string}",
- headers: {
- "Authorization" => "Token #{api_key}",
- "X-VA-SSN" => ssn,
- "X-VA-Receipt-Date" => receipt_date.try(:strftime, "%F") || receipt_date
- }
+ headers: headers
)
end
end
diff --git a/spec/support/shared_examples/requests/api/v3/decision_reviews/shared_examples_contestable_issues.rb b/spec/support/shared_examples/requests/api/v3/decision_reviews/shared_examples_contestable_issues.rb
index 55c543200f3..023e8312546 100644
--- a/spec/support/shared_examples/requests/api/v3/decision_reviews/shared_examples_contestable_issues.rb
+++ b/spec/support/shared_examples/requests/api/v3/decision_reviews/shared_examples_contestable_issues.rb
@@ -6,19 +6,45 @@
describe "#index" do
include_context "contestable issues request index context", include_shared: true
- it "should return a 200 OK" do
- get_issues
- expect(response).to have_http_status(:ok)
- end
-
- it "should return a list of issues in JSON:API format" do
+ let(:promulgated_ratings) do
Generators::PromulgatedRating.build(
participant_id: veteran.ptcpnt_id,
profile_date: Time.zone.today - 10.days # must be before receipt_date
)
- get_issues
- expect(response_data).to be_an Array
- expect(response_data).not_to be_empty
+ end
+
+ context "when SSN is used" do
+ let(:file_number) { nil }
+ let(:ssn) { veteran.ssn }
+
+ it "should return 200 OK" do
+ get_issues
+ expect(response).to have_http_status(:ok)
+ end
+
+ it "should return a list of issues in JSON:API format" do
+ promulgated_ratings
+ get_issues
+ expect(response_data).to be_an Array
+ expect(response_data).not_to be_empty
+ end
+ end
+
+ context "when file_number is used" do
+ let(:file_number) { veteran.file_number }
+ let(:ssn) { nil }
+
+ it "should return 200 OK" do
+ get_issues
+ expect(response).to have_http_status(:ok)
+ end
+
+ it "should return a list of issues in JSON:API format" do
+ promulgated_ratings
+ get_issues
+ expect(response_data).to be_an Array
+ expect(response_data).not_to be_empty
+ end
end
context "returned issues" do
@@ -276,5 +302,15 @@
expect(response).to have_http_status(:unprocessable_entity)
end
end
+
+ context "when no ssn or file_number is present" do
+ let(:ssn) { nil }
+ let(:file_number) { nil }
+
+ it "should return a 422" do
+ get_issues
+ expect(response).to have_http_status(:unprocessable_entity)
+ end
+ end
end
end