Skip to content

Commit

Permalink
Display completed ChangeHearingRequestTypeTask info on timeline (#15395)
Browse files Browse the repository at this point in the history
Resolves #15193 

### Description
- return `timeline_title`, `converted_at`, and `converted_by` from `TaskSerializer`
- modify component `TaskRows` to include logic for displaying the relevant fields for `ChangeHearingRequstTypeTask`
- write storybook component for `TaskRows`
- refactor `Tasks.js`
- write a feature test in `spec/feature/hearings/convert_travel_board_hearing/edit_hearsched_spec.rb`
- bunch of refactors in legacy_appeal and appeal

### Testing Plan
#### Dev
1. Find a travel board appeal and visit the case details page `http://localhost:3000/queue/appeals/VACOLS_ID`

the following should find any vacols cases that are travel board and build them (ported from `FetchHearingLocationsForVeteransJob`
```
    VACOLS::Case
      .where(
        # Travle Board Hearing Request
        bfhr: VACOLS::Case::HEARING_PREFERENCE_TYPES_V2[:TRAVEL_BOARD][:vacols_value],
        # Current Location
        bfcurloc: LegacyAppeal::LOCATION_CODES[:schedule_hearing],
        # Video Hearing Request Indicator
        bfdocind: nil,
        # Datetime of Decision
        bfddec: nil
      )
      .map do |vacols_case|
        AppealRepository.build_appeal(vacols_case, true)
      end
```

if that does not work, you can update the fields (`bfhr: VACOLS::Case::HEARING_PREFERENCE_TYPES_V2[:TRAVEL_BOARD][:vacols_value]`, `bfcurloc: LegacyAppeal::LOCATION_CODES[:schedule_hearing]`, `1bfdocind: nil`, `bfddec: nil`) in `Generators::Vacols::Case`
and create a travel board vacols case 
```
v = Generators::Vacols::Case.create(attrs: Generators::Vacols::Case.case_attrs)
a = AppealRepository.build_appeal(v, true)
```
2. Complete the change hearing request type task
3. Scroll down to Case Timeline and see that the completed task displays as intended

#### Storybook
1. Go to storybook
2. look at `queue/CaseTimeline`
### User Facing Changes
 - [x] Screenshots of UI changes added to PR & Original Issue

 BEFORE|AFTER
 ---|---
<img width="605" alt="Screen Shot 2020-10-07 at 2 16 48 PM" src="https://user-images.githubusercontent.com/20735998/95371223-e33e3e80-08a7-11eb-9707-cca518fd5831.png">|<img width="601" alt="Screen Shot 2020-10-07 at 2 17 29 PM" src="https://user-images.githubusercontent.com/20735998/95371185-d91c4000-08a7-11eb-9bc3-c09461c5edbc.png">

### Storybook Story
*For Frontend (Presentationa) Components*
* [x] Add a [Storybook](https://github.com/department-of-veterans-affairs/caseflow/wiki/Documenting-React-Components-with-Storybook) file alongside the component file (e.g. create `MyComponent.stories.js` alongside `MyComponent.jsx`)
* [x] Give it a title that reflects the component's location within the overall Caseflow hierarchy
* [x] Write a separate story (within the same file) for each discrete variation of the component
  • Loading branch information
Rubaiyat Rashid authored Oct 14, 2020
1 parent 9251ed5 commit 0324c07
Show file tree
Hide file tree
Showing 26 changed files with 436 additions and 166 deletions.
2 changes: 1 addition & 1 deletion app/jobs/fetch_hearing_locations_for_veterans_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ def record_geomatched_appeal(appeal, status)
attrs: {
status: status,
appeal_external_id: appeal.external_id,
hearing_request_type: appeal.sanitized_hearing_request_type
hearing_request_type: appeal.current_hearing_request_type
}
)
end
Expand Down
2 changes: 1 addition & 1 deletion app/jobs/start_certification_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def update_certification_attributes
ssocs_required: @certification.calculate_ssocs_required,
ssocs_matching_at: @certification.calculcate_ssocs_matching_at,
form8_started_at: (@certification.certification_status == :started) ? @certification.now : nil,
vacols_hearing_preference: @certification.appeal.sanitized_hearing_request_type,
vacols_hearing_preference: @certification.appeal.current_hearing_request_type,
certifying_office: @certification.appeal.regional_office_name,
certifying_username: @certification.appeal.regional_office_key,
certifying_official_name: user ? user.full_name : nil
Expand Down
6 changes: 3 additions & 3 deletions app/jobs/update_cached_appeals_attributes_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def cache_ama_appeals
issue_count: request_issues_to_cache[appeal.id] || 0,
docket_type: appeal.docket_type,
docket_number: appeal.docket_number,
hearing_request_type: appeal.readable_hearing_request_type,
hearing_request_type: appeal.current_hearing_request_type(readable: true),
is_aod: appeal_aod_status.include?(appeal.id),
power_of_attorney_name: representative_names[appeal.id],
suggested_hearing_location: appeal.suggested_hearing_location&.formatted_location,
Expand Down Expand Up @@ -274,7 +274,7 @@ def case_fields_for_vacols_ids(vacols_ids)
{
location: vacols_case.bfcurloc,
status: VACOLS::Case::TYPES[vacols_case.bfac],
hearing_request_type: legacy_appeal.readable_hearing_request_type,
hearing_request_type: legacy_appeal.current_hearing_request_type(readable: true),
former_travel: former_travel?(legacy_appeal)
}
]
Expand Down Expand Up @@ -307,7 +307,7 @@ def veteran_names_for_file_numbers(veteran_file_numbers)
# 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.readable_hearing_request_type == LegacyAppeal::READABLE_HEARING_REQUEST_TYPES[:travel_board]
if legacy_appeal.current_hearing_request_type == :travel_board
return false
end

Expand Down
21 changes: 10 additions & 11 deletions app/models/appeal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -511,29 +511,28 @@ def ready_for_bva_dispatch?

# Returns the hearing request type.
#
# @note See `LegacyAppeal#sanitized_hearing_request_type` for more information.
# @note See `LegacyAppeal#current_hearing_request_type` for more information.
# This method is provided for compatibility.
def sanitized_hearing_request_type
def current_hearing_request_type(readable: false)
return nil if closest_regional_office.nil?

(closest_regional_office == "C") ? :central : :video
end
current_hearing_request_type = (closest_regional_office == "C") ? :central : :video

alias original_hearing_request_type sanitized_hearing_request_type
return current_hearing_request_type if !readable

# Determine type using cloesest_regional_office
# "Central" if closest_regional_office office is "C", "Video" otherwise
def readable_hearing_request_type
case sanitized_hearing_request_type
when nil
nil
# Determine type using closest_regional_office
# "Central" if closest_regional_office office is "C", "Video" otherwise
case current_hearing_request_type
when :central
Hearing::HEARING_TYPES[:C]
else
Hearing::HEARING_TYPES[:V]
end
end

alias original_hearing_request_type current_hearing_request_type
alias previous_hearing_request_type current_hearing_request_type

private

def business_lines_needing_assignment
Expand Down
2 changes: 1 addition & 1 deletion app/models/appeal_series.rb
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def fetch_details_for_status
location: hearing.request_type_location
}
when :pending_hearing_scheduling
{ type: latest_appeal.sanitized_hearing_request_type }
{ type: latest_appeal.current_hearing_request_type }
when :pending_form9, :pending_certification, :pending_certification_ssoc
{
last_soc_date: last_soc_date,
Expand Down
103 changes: 67 additions & 36 deletions app/models/legacy_appeal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -370,11 +370,21 @@ def power_of_attorney
end
end

## BEGIN Hearing specific attributes and methods

attr_writer :hearings
def hearings
@hearings ||= HearingRepository.hearings_for_appeal(vacols_id)
end

def hearing_pending?
hearing_requested && !hearing_held
end

def hearing_scheduled?
scheduled_hearings.any?
end

def completed_hearing_on_previous_appeal?
vacols_ids = VACOLS::Case.where(bfcorlid: vbms_id).pluck(:bfkey)
hearings = HearingRepository.hearings_for_appeals(vacols_ids)
Expand All @@ -391,41 +401,65 @@ def scheduled_hearings
hearings.select(&:scheduled_pending?)
end

def original_hearing_request_type
case hearing_request_type
when :central_office
:central_office
when :travel_board
video_hearing_requested ? :video : :travel_board
# Currently changed_request_type can only be stored as 'R' or 'V' because
# you can convert a hearing request type to Video or Virtual.
# This method returns the sanitized versions of those where 'R' => :virtual and 'V' => :video
def sanitized_changed_request_type(changed_request_type)
case changed_request_type
when HearingDay::REQUEST_TYPES[:video]
:video
when HearingDay::REQUEST_TYPES[:virtual]
:virtual
else
fail InvalidChangedRequestType, "\"#{changed_request_type}\" is not a valid request type."
end
end

# `hearing_request_type` is a direct mapping from VACOLS and has some unused
# 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.
#
# [Sept. 2020]:
# In response to COVID, the appellant has the option of changing their hearing
# preference if they were scheduled for a travel board hearing. This method captures
# if a travel board hearing request type was overridden in Caseflow.
def sanitized_hearing_request_type
if changed_request_type.present?
case changed_request_type
when HearingDay::REQUEST_TYPES[:video]
return :video
when HearingDay::REQUEST_TYPES[:virtual]
return :virtual
else
fail InvalidChangedRequestType, "\"#{changed_request_type}\" is not a valid request type."
end
end

original_hearing_request_type
# 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.
def original_hearing_request_type(readable: false)
original_hearing_request_type = case hearing_request_type
when :central_office
:central_office
when :travel_board
video_hearing_requested ? :video : :travel_board
end
readable ? READABLE_HEARING_REQUEST_TYPES[original_hearing_request_type] : original_hearing_request_type
end

def readable_hearing_request_type
READABLE_HEARING_REQUEST_TYPES[sanitized_hearing_request_type]
end
# [Sept. 2020]:
# In response to COVID, the appellant has the option of changing their hearing
# preference if they were scheduled for a travel board hearing.
# 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`
def current_hearing_request_type(readable: false)
current_hearing_request_type = if changed_request_type.present?
sanitized_changed_request_type(changed_request_type)
else
original_hearing_request_type
end
readable ? READABLE_HEARING_REQUEST_TYPES[current_hearing_request_type] : current_hearing_request_type
end

# if `change_hearing_request` is populated meaning the hearing request type was changed, then return what the
# previous hearing request type was. Use paper trail event to derive previous type in the case the type was changed
# multple times.
def previous_hearing_request_type(readable: false)
diff = latest_appeal_event&.diff || {} # Example of diff: {"changed_request_type"=>[nil, "R"]}
previous_unsanitized_type = diff["changed_request_type"]&.first

previous_hearing_request_type = if previous_unsanitized_type.present?
sanitized_changed_request_type(previous_unsanitized_type)
else
original_hearing_request_type
end
readable ? READABLE_HEARING_REQUEST_TYPES[previous_hearing_request_type] : previous_hearing_request_type
end

## END Hearing specific attributes and methods

def veteran_is_deceased
veteran_death_date.present?
Expand Down Expand Up @@ -501,14 +535,6 @@ def task_header
"&nbsp &#124; &nbsp ".html_safe + "#{veteran_name} (#{sanitized_vbms_id})"
end

def hearing_pending?
hearing_requested && !hearing_held
end

def hearing_scheduled?
!scheduled_hearings.empty?
end

def eligible_for_ramp?
!ramp_ineligibility_reason
end
Expand Down Expand Up @@ -935,6 +961,11 @@ def ready_for_bva_dispatch?
false
end

# uses the paper_trail version on LegacyAppeal
def latest_appeal_event
TaskEvent.new(version: versions.last) if versions.any?
end

private

def soc_eligible_for_opt_in?(receipt_date:, covid_flag: false)
Expand Down
8 changes: 6 additions & 2 deletions app/models/serializers/work_queue/appeal_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ class WorkQueue::AppealSerializer
).editable?
end

attribute :readable_hearing_request_type
attribute :readable_original_hearing_request_type, &:readable_hearing_request_type
attribute :readable_hearing_request_type do |object|
object.current_hearing_request_type(readable: true)
end
attribute :readable_original_hearing_request_type do |object|
object.original_hearing_request_type(readable: true)
end
end
7 changes: 4 additions & 3 deletions app/models/serializers/work_queue/legacy_appeal_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ class WorkQueue::LegacyAppealSerializer

attribute :assigned_attorney
attribute :assigned_judge
attribute :readable_hearing_request_type
attribute :readable_hearing_request_type do |object|
object.current_hearing_request_type(readable: true)
end
attribute :readable_original_hearing_request_type do |object|
LegacyAppeal::READABLE_HEARING_REQUEST_TYPES[object.original_hearing_request_type]
object.original_hearing_request_type(readable: true)
end

attribute :issues do |object|
object.issues.map do |issue|
WorkQueue::LegacyIssueSerializer.new(issue).serializable_hash[:data][:attributes]
Expand Down
8 changes: 8 additions & 0 deletions app/models/serializers/work_queue/task_column_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -325,4 +325,12 @@ def self.serialize_attribute?(params, columns)
css_id: nil
}
end
attribute :converted_by do
{
css_id: nil
}
end
attribute :converted_on do
nil
end
end
14 changes: 14 additions & 0 deletions app/models/serializers/work_queue/task_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,20 @@ class WorkQueue::TaskSerializer
}
end

# only ChangeHearingRequestType defines a convertedBy deriving the data from paper_trail
# refers to the conversion of hearing request type
attribute :converted_by do |object|
{
css_id: object.try(:converted_by).try(:css_id)
}
end

# ChangeHearingRequestType defines a converted_on
# refers to when the hearing request type was converted and is equivalent to closed_at
attribute :converted_on do |object|
object.try(:converted_on)
end

attribute :assignee_name do |object|
object.assigned_to.is_a?(Organization) ? object.assigned_to.name : object.assigned_to.css_id
end
Expand Down
21 changes: 21 additions & 0 deletions app/models/tasks/change_hearing_request_type_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,31 @@ def self.label
"Change hearing request type"
end

# if task is completed, show this on timeline
# conditioned to reduce a call to vacols in the absence of a value in `changed_hearing_type` field
def timeline_title
if completed?
"Hearing type converted from #{appeal.previous_hearing_request_type(readable: true)}"\
" to #{appeal.current_hearing_request_type(readable: true)}"
end
end

def self.hide_from_queue_table_view
true
end

def converted_on
if completed?
closed_at
end
end

def converted_by
if completed?
appeal.latest_appeal_event.who
end
end

def default_instructions
[COPY::CHANGE_HEARING_REQUEST_TYPE_TASK_DEFAULT_INSTRUCTIONS]
end
Expand Down
2 changes: 1 addition & 1 deletion app/services/va_dot_gov_address_validator/validations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ def closest_regional_office_facility_id_is_san_antonio?
end

def appeal_is_legacy_and_veteran_requested_central_office?
appeal.is_a?(LegacyAppeal) && appeal.sanitized_hearing_request_type == :central_office
appeal.is_a?(LegacyAppeal) && appeal.current_hearing_request_type == :central_office
end

def veteran_lives_in_texas?
Expand Down
2 changes: 1 addition & 1 deletion app/workflows/tasks_for_appeal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def user_is_judge_or_attorney?

def initialize_hearing_tasks_for_travel_board?
appeal.is_a?(LegacyAppeal) &&
appeal.sanitized_hearing_request_type == :travel_board &&
appeal.current_hearing_request_type == :travel_board &&
user.can_change_hearing_request_type?
end

Expand Down
2 changes: 2 additions & 0 deletions client/COPY.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@
"TASK_SNAPSHOT_TASK_COMPLETED_DATE_LABEL": "Completed on",
"TASK_SNAPSHOT_TASK_CANCELLED_DATE_LABEL": "Cancelled on",
"TASK_SNAPSHOT_TASK_WITHDRAWAL_DATE_LABEL": "withdrawn on",
"TASK_SNAPSHOT_HEARING_REQUEST_CONVERTED_ON_LABEL": "Converted on",
"TASK_SNAPSHOT_HEARING_REQUEST_CONVERTER_LABEL": "Converted by",
"TASK_SNAPSHOT_ASSIGNED_JUDGE_LABEL": "VLJ",
"TASK_SNAPSHOT_ASSIGNED_ATTORNEY_LABEL": "Attorney",
"TASK_SNAPSHOT_DECISION_DOCUMENT_ID_LABEL": "Decision Document ID",
Expand Down
2 changes: 1 addition & 1 deletion client/app/queue/CaseTimeline.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { caseTimelineTasksForAppeal } from './selectors';
import COPY from '../../COPY';
import TaskRows from './components/TaskRows';

class CaseTimeline extends React.PureComponent {
export class CaseTimeline extends React.PureComponent {
render = () => {
const {
appeal,
Expand Down
Loading

0 comments on commit 0324c07

Please sign in to comment.