Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implements Backend of Case Movement for Blocked Cases #14957

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true

##
# Task to record on the appeal that the special case movement manually assigned the case outside of automatic
# case distribution and intentionally cancelled any tasks that were blocking distribution

class BlockedSpecialCaseMovementTask < SpecialCaseMovementTask
private

def distribute_to_judge
Task.transaction do
super
cancel_tasks_blocking_distribution
end
end

def cancel_tasks_blocking_distribution
parent.cancel_descendants
end

def verify_appeal_distributable
if DistributionTask.open.where(appeal: appeal).empty?
fail(Caseflow::Error::IneligibleForBlockedSpecialCaseMovement, appeal_id: appeal.id)
end
end
end
4 changes: 2 additions & 2 deletions app/models/tasks/special_case_movement_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ class SpecialCaseMovementTask < Task
before_create :verify_parent_task_type,
:verify_user_organization,
:verify_appeal_distributable
after_create :close_and_create_judge_task
after_create :distribute_to_judge

def self.label
COPY::CASE_MOVEMENT_TASK_LABEL
end

private

def close_and_create_judge_task
def distribute_to_judge
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renamed to better reflect the why of what's being done in both cases

Task.transaction do
JudgeAssignTask.create!(appeal: appeal,
parent: appeal.root_task,
Expand Down
36 changes: 35 additions & 1 deletion db/seeds/tasks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ def create_ama_appeals
)
)
end
# Create AMA tasks ready for distribution

# Create AMA appeals ready for distribution
(1..30).each do |num|
vet_file_number = format("3213213%<num>02d", num: num)
create(
Expand All @@ -95,6 +96,39 @@ def create_ama_appeals
)
end

# Create AMA appeals blocked for distribution due to Evidence Window
(1..30).each do |num|
vet_file_number = format("4324324%<num>02d", num: num)
create(
:appeal,
:with_post_intake_tasks,
number_of_claimants: 1,
active_task_assigned_at: Time.zone.now,
veteran_file_number: vet_file_number,
docket_type: Constants.AMA_DOCKETS.evidence_submission,
closest_regional_office: "RO17",
request_issues: create_list(
:request_issue, 2, :nonrating, notes: notes
)
)
end

# Create AMA appeals blocked for distribution due to blocking mail
(1..30).each do |num|
vet_file_number = format("4324334%<num>02d", num: num)
create(
:appeal,
:mail_blocking_distribution,
number_of_claimants: 1,
active_task_assigned_at: Time.zone.now,
veteran_file_number: vet_file_number,
docket_type: Constants.AMA_DOCKETS.direct_review,
closest_regional_office: "RO17",
request_issues: create_list(
:request_issue, 2, :nonrating, notes: notes
)
)
end
LegacyAppeal.create(vacols_id: "2096907", vbms_id: "228081153S")
LegacyAppeal.create(vacols_id: "2226048", vbms_id: "213912991S")
LegacyAppeal.create(vacols_id: "2249056", vbms_id: "608428712S")
Expand Down
11 changes: 11 additions & 0 deletions lib/caseflow/error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,17 @@ def initialize(args)
end
end

class IneligibleForBlockedSpecialCaseMovement < SerializableError
attr_accessor :appeal_id

def initialize(args)
@code = args[:code] || 500
@appeal_id = args[:appeal_id] || nil
@title = "This appeal cannot be advanced to a judge"
@message = args[:message] || "Appeal #{@appeal_id} must be in Case Storage to be eligible for Case Movement"
end
end

class IneligibleForSpecialCaseMovement < SerializableError
attr_accessor :appeal_id

Expand Down
16 changes: 16 additions & 0 deletions spec/factories/appeal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,22 @@
end
end

## Appeal with a realistic task tree
## The appeal would be ready for distribution by the ACD except there is a blocking mail task
## Leaves incorrectly open & incomplete Hearing / Evidence Window task branches
## for those dockets
trait :mail_blocking_distribution do
ready_for_distribution
after(:create) do |appeal, _evaluator|
distribution_task = appeal.tasks.active.detect { |task| task.is_a?(DistributionTask) }
create(
:extension_request_mail_task,
appeal: appeal,
parent: distribution_task
)
end
end

## Appeal with a realistic task tree
## The appeal is assigned to a Judge for a decision
## Leaves incorrectly open & incomplete Hearing / Evidence Window task branches
Expand Down
6 changes: 6 additions & 0 deletions spec/factories/task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,12 @@
assigned_by { nil }
end

factory :extension_request_mail_task, class: ExtensionRequestMailTask do
parent { create(:root_task, appeal: appeal) }
assigned_to { MailTeam.singleton }
assigned_by { nil }
end

Comment on lines +477 to +482
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I needed a MailTask type that should actually block distribution

factory :judge_address_motion_to_vacate_task, class: JudgeAddressMotionToVacateTask do
parent { create(:vacate_motion_mail_task, appeal: appeal) }
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# frozen_string_literal: true

require_relative "../special_case_movement_shared_examples"

describe BlockedSpecialCaseMovementTask do
describe ".create" do
context "with Case Movement Team user" do
let(:cm_user) { create(:user) }

subject do
BlockedSpecialCaseMovementTask.create!(appeal: appeal,
assigned_to: cm_user,
assigned_by: cm_user,
parent: dist_task)
end

before do
SpecialCaseMovementTeam.singleton.add_user(cm_user)
end

shared_examples "cancelled distribution children" do
it "cancel any open distribution descendants" do
dist_task = appeal.tasks.open.where(type: DistributionTask.name).first
open_tasks = dist_task.descendants.select(&:open?) - [dist_task]
expect { subject }.not_to raise_error
open_tasks.each do |task|
expect(task.reload.status).to eq(Constants.TASK_STATUSES.cancelled)
end
end
end

context "appeal ready for distribution" do
let(:appeal) do
create(:appeal,
:with_post_intake_tasks,
docket_type: Constants.AMA_DOCKETS.direct_review)
end
let(:dist_task) { appeal.tasks.active.where(type: DistributionTask.name).first }

context "with no blocking tasks" do
it_behaves_like "successful creation"
end

it_behaves_like "appeal has a nonblocking mail task"

context "with (dispatch) blocking mail task" do
before do
# TODO: this _should_ not cancel after we finish
# https://github.com/department-of-veterans-affairs/caseflow/issues/14057
# Distribution Blocking. Update this test to properly pass then!
Comment on lines +48 to +50
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO to be addressed in #14057

create(:congressional_interest_mail_task,
appeal: appeal,
parent: dist_task)
end
it_behaves_like "successful creation"
it_behaves_like "cancelled distribution children"
end

context "with a (distribution) blocking mail task" do
before do
create(:extension_request_mail_task,
appeal: appeal,
parent: dist_task)
end
it_behaves_like "successful creation"
it_behaves_like "cancelled distribution children"
end
end

context "appeal at the evidence window state" do
let(:appeal) do
create(:appeal,
:with_post_intake_tasks,
docket_type: Constants.AMA_DOCKETS.evidence_submission)
end
let(:dist_task) { appeal.tasks.open.where(type: DistributionTask.name).first }

context "with distribution task on_hold" do
it_behaves_like "successful creation"
it_behaves_like "cancelled distribution children"
end

it_behaves_like "wrong parent task type provided"
end

it_behaves_like "appeal past distribution" do
let(:expected_error) { Caseflow::Error::IneligibleForBlockedSpecialCaseMovement }
end
end

it_behaves_like "non Case Movement user provided"
end
end
90 changes: 90 additions & 0 deletions spec/models/tasks/special_case_movement_shared_examples.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# frozen_string_literal: true

# Shared examples for both SpecialCaseMovementTask and BlockedSpecialCaseMovementTask

shared_examples "successful creation" do
it "should create the SCM task and JudgeAssign task" do
expect { subject }.not_to raise_error
scm_task = appeal.tasks.where(type: described_class.name).first
expect(scm_task.status).to eq(Constants.TASK_STATUSES.completed)
judge_task = appeal.tasks.open.where(type: JudgeAssignTask.name).first
expect(judge_task.status).to eq(Constants.TASK_STATUSES.assigned)
end
end

shared_examples "appeal has a nonblocking mail task" do
before do
create(:aod_motion_mail_task,
appeal: appeal,
parent: appeal.root_task)
end
it_behaves_like "successful creation"
it "still has the open mail task" do
aod_mail_task = AodMotionMailTask.where(appeal: appeal).first
expect(aod_mail_task.open?).to eq(true)
expect { subject }.not_to raise_error
expect(aod_mail_task.reload.open?).to eq(true)
end
end

shared_examples "wrong parent task type provided" do
context "with the evidence window task as parent" do
let(:evidence_window_task) { appeal.tasks.open.where(type: EvidenceSubmissionWindowTask.name).first }

subject do
described_class.create!(appeal: appeal,
assigned_to: cm_user,
assigned_by: cm_user,
parent: evidence_window_task)
end

it "should error with wrong parent type" do
expect { subject }.to raise_error(Caseflow::Error::InvalidParentTask)
end
end
end

shared_examples "appeal past distribution" do
context "appeal at the judge already" do
let(:appeal) do
create(:appeal,
:assigned_to_judge,
docket_type: Constants.AMA_DOCKETS.direct_review)
end
let(:dist_task) { appeal.tasks.where(type: DistributionTask.name).first }

subject do
described_class.create!(appeal: appeal,
assigned_to: cm_user,
assigned_by: cm_user,
parent: dist_task)
end

it "should error with appeal not distributable" do
expect { subject }.to raise_error(expected_error)
end
end
end

shared_examples "non Case Movement user provided" do
context "with a non-CaseMovement user" do
let(:user) { create(:user) }
let(:appeal) do
create(:appeal,
:with_post_intake_tasks,
docket_type: Constants.AMA_DOCKETS.direct_review)
end
let(:dist_task) { appeal.tasks.active.where(type: DistributionTask.name).first }

subject do
described_class.create!(appeal: appeal,
assigned_to: user,
assigned_by: user,
parent: dist_task)
end

it "should error with user error" do
expect { subject }.to raise_error(Caseflow::Error::ActionForbiddenError)
end
end
end
Loading