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

Expand the only_open_task_of_type validation to AttorneyTask and JudgeDecisionReviewTask #16586

Merged
merged 29 commits into from
Aug 16, 2021
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
bb875f5
wrong start - need to change task factory
eileen-nava Jul 30, 2021
2e11eb4
test of invalid JudgeAssignTask status
eileen-nava Aug 2, 2021
a0e6eff
WIP - can't figure out how to select correct dropdown
eileen-nava Aug 3, 2021
2dfbe30
add validation for jdr task
eileen-nava Aug 3, 2021
947c08b
add validation to attorney appeal
eileen-nava Aug 3, 2021
90ca288
refactor task validation to remove thread local variables
eileen-nava Aug 3, 2021
bc92b17
spec fixed
yoomlam Aug 3, 2021
17976e1
remove ensure block from task reassign
eileen-nava Aug 3, 2021
fb33495
clean up tests
eileen-nava Aug 3, 2021
43fc305
continue test clean-up
eileen-nava Aug 9, 2021
ef27df7
update tests
eileen-nava Aug 9, 2021
5716194
update case details spec
eileen-nava Aug 9, 2021
0957ccc
override validation to maintain docket switch flow
eileen-nava Aug 9, 2021
1b4a087
Merge branch 'master' into 2075/limit-jdr-atty-tasks
eileen-nava Aug 9, 2021
c7a88d0
tweaks
eileen-nava Aug 9, 2021
3cb33e9
tweaks
eileen-nava Aug 9, 2021
3fc0fb9
debug spec to actually reassign judge task to a different judge
eileen-nava Aug 10, 2021
9c07fb9
refine tests in response to feedback
eileen-nava Aug 10, 2021
e7288b3
add wait statements
eileen-nava Aug 10, 2021
3561be1
Merge branch 'master' into eileen/2075-multiple-judge-tasks
eileen-nava Aug 10, 2021
d9f31c3
continue response to feedback
eileen-nava Aug 11, 2021
f2d9ea0
respond to feedback
eileen-nava Aug 11, 2021
f57d474
fix typo
eileen-nava Aug 11, 2021
642e963
respond to feedback
eileen-nava Aug 11, 2021
6859a0a
Merge branch 'eileen/2075-multiple-judge-tasks' into 2075/limit-jdr-a…
eileen-nava Aug 13, 2021
31ecbbf
update feature test to reflect changes from fix
eileen-nava Aug 13, 2021
b2f0763
remove breakpoints
eileen-nava Aug 13, 2021
8ee4a22
change assertions for feature test
eileen-nava Aug 16, 2021
2a0d120
Merge branch 'master' into 2075/limit-jdr-atty-tasks
Aug 16, 2021
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
12 changes: 4 additions & 8 deletions app/models/task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ class << self; undef_method :open; end

scope :with_cached_appeals, -> { joins(Task.joins_with_cached_appeals_clause) }

attr_accessor :skip_check_for_only_open_task_of_type

############################################################################################
## class methods
class << self
Expand Down Expand Up @@ -562,7 +564,7 @@ def verify_user_can_update!(user)
def reassign(reassign_params, current_user)
# We do not validate the number of tasks in this scenario because when a
# task is reassigned, more than one open task of the same type must exist during the reassignment.
Thread.current.thread_variable_set(:skip_check_for_only_open_task_of_type, true)
@skip_check_for_only_open_task_of_type = true
replacement = dup.tap do |task|
begin
ActiveRecord::Base.transaction do
Expand All @@ -573,10 +575,8 @@ def reassign(reassign_params, current_user)

task.save!
end
# The ensure block guarantees that the thread-local variable check_for_open_task_type
# does not leak outside of this method
yoomlam marked this conversation as resolved.
Show resolved Hide resolved
ensure
Thread.current.thread_variable_set(:skip_check_for_only_open_task_of_type, nil)
@skip_check_for_only_open_task_of_type = nil
end
end

Expand Down Expand Up @@ -834,10 +834,6 @@ def assignee_status_is_valid_on_create
true
end

def skip_check_for_only_open_task_of_type?
yoomlam marked this conversation as resolved.
Show resolved Hide resolved
Thread.current.thread_variable_get(:skip_check_for_only_open_task_of_type)
end

def only_open_task_of_type
if appeal.reload.tasks.open.of_type(type).any?
fail Caseflow::Error::MultipleOpenTasksOfSameTypeError, task_type: type
Expand Down
3 changes: 3 additions & 0 deletions app/models/tasks/attorney_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
# - adding admin actions (like translating documents)

class AttorneyTask < Task
validate :only_open_task_of_type, on: :create,
unless: :skip_check_for_only_open_task_of_type

validates :assigned_by, presence: true
validates :parent, presence: true, if: :ama?

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,12 @@ def default_actions
]
end
end

private

def only_open_task_of_type
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This felt odd even as I typed it, but it was necessary to maintain the docket switch flow. Maybe we should check with the board that we want to allow multiple DocketSwitchDeniedTask and DocketSwitchGrantedTask instances for one appeal?

Copy link
Contributor

Choose a reason for hiding this comment

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

@eileen-nava Yes, check with Foxtrot and @araposo-tistatech first.

Copy link
Contributor Author

@eileen-nava eileen-nava Aug 10, 2021

Choose a reason for hiding this comment

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

Ann-Marie directed me to Foxtrot. Slack response from Yang:

I believe there should only ever be two open DocketSwitchAbstractAttorneyTasks on an appeal, parent assigned to COTB and child assigned to a user.

Yang also noted that @jcq created this task tree structure. I'll check with JC about this when he is back from PTO.

For now, overriding the validation seems fine.

# This overrides the validation inherited from the parent class, AttorneyTask.
# Docket switch requires an appeal to have two DocketSwitchAbstractAttorneyTasks,
# with the parent assigned to COTB and the child assigned to a user.
end
end
2 changes: 1 addition & 1 deletion app/models/tasks/judge_assign_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

class JudgeAssignTask < JudgeTask
validate :only_open_task_of_type, on: :create,
unless: :skip_check_for_only_open_task_of_type?
unless: :skip_check_for_only_open_task_of_type

def additional_available_actions(_user)
[Constants.TASK_ACTIONS.ASSIGN_TO_ATTORNEY.to_h]
Expand Down
21 changes: 2 additions & 19 deletions app/models/tasks/judge_decision_review_task.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
# and create a new JudgeAssignTask, because another assignment by a judge is needed.

class JudgeDecisionReviewTask < JudgeTask
before_create :verify_user_task_unique
validate :only_open_task_of_type, on: :create,
yoomlam marked this conversation as resolved.
Show resolved Hide resolved
unless: :skip_check_for_only_open_task_of_type

def additional_available_actions(user)
return [] unless assigned_to == user
Expand All @@ -31,24 +32,6 @@ def self.label
COPY::JUDGE_DECISION_REVIEW_TASK_LABEL
end

# Use the existence of another open JudgeDecisionReviewTask to prevent duplicates since there should only
# ever be one open JudgeDecisionReviewTask at a time for an appeal.
def verify_user_task_unique
yoomlam marked this conversation as resolved.
Show resolved Hide resolved
return if !open?

if appeal.tasks.open.where(
type: type,
assigned_to: assigned_to,
parent: parent
).any? && assigned_to.is_a?(User)
fail(
Caseflow::Error::DuplicateUserTask,
docket_number: appeal.docket_number,
task_type: self.class.name
)
end
end

private

def ama_judge_actions(user)
Expand Down
8 changes: 2 additions & 6 deletions spec/feature/queue/case_details_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1219,15 +1219,13 @@ def wait_for_page_render
)
end
let!(:attorney_task) { create(:ama_attorney_task, parent: judge_task, assigned_to: user) }
let!(:attorney_task2) { create(:ama_attorney_task, parent: root_task, assigned_to: user) }

before do
FeatureToggle.enable!(:view_nod_date_updates)
# The status attribute needs to be set here due to update_parent_status hook in the task model
# the updated_at attribute needs to be set here due to the set_timestamps hook in the task model
assign_task.update!(status: Constants.TASK_STATUSES.completed, closed_at: "2019-01-01")
attorney_task.update!(status: Constants.TASK_STATUSES.completed, closed_at: "2019-02-01")
attorney_task2.update!(status: Constants.TASK_STATUSES.completed, closed_at: "2019-03-01")
judge_task.update!(status: Constants.TASK_STATUSES.completed, closed_at: Time.zone.now)
nod_date_update.update!(updated_at: "2019-01-05")
end
Expand All @@ -1246,11 +1244,9 @@ def wait_for_page_render
first_row_with_date = case_timeline_rows[1]
second_row_with_date = case_timeline_rows[2]
third_row_with_date = case_timeline_rows[3]
fourth_row_with_date = case_timeline_rows[4]
expect(first_row_with_date).to have_content("01/01/2020")
expect(second_row_with_date).to have_content("03/01/2019")
expect(third_row_with_date).to have_content("02/01/2019")
expect(fourth_row_with_date).to have_content("01/05/2019")
expect(second_row_with_date).to have_content("02/01/2019")
expect(third_row_with_date).to have_content("01/05/2019")
end

it "should NOT display judge & attorney tasks" do
Expand Down
5 changes: 3 additions & 2 deletions spec/feature/queue/judge_assignment_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,9 @@
click_on "Assign 2 cases"
expect(page).to have_content("#{attorney_one.full_name} (0)")
expect(page).to have_content("Error assigning tasks")
expect(page).to have_content("Docket (#{appeal_two.docket_number}) already "\
"has an open task type of #{JudgeDecisionReviewTask.name}")

expect(page).to have_content("Looks like this appeal already has an open JudgeDecisionReviewTask "\
"and this action cannot be completed.")
Comment on lines +236 to +237
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's change this error message to:

Suggested change
expect(page).to have_content("Looks like this appeal already has an open JudgeDecisionReviewTask "\
"and this action cannot be completed.")
expect(page).to have_content("This appeal already has an open JudgeDecisionReviewTask "\
"and this action cannot be completed.")

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The current error message was suggested by design in a slack conversation with @mbaenatan and @rutvigupta-design. I'd appreciate their thoughts on any changes.


visit "/queue/#{judge_one.user.css_id}/assign"
expect(page).to have_content("#{attorney_one.full_name} (0)")
Expand Down
10 changes: 0 additions & 10 deletions spec/feature/queue/task_queue_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,6 @@
)
end

let!(:attorney_task_new_docs) do
create(
:ama_attorney_task,
:on_hold,
assigned_to: attorney_user,
placed_on_hold_at: 4.days.ago,
appeal: attorney_task.appeal
)
end

yoomlam marked this conversation as resolved.
Show resolved Hide resolved
let!(:colocated_task) do
create(
:ama_colocated_task,
Expand Down
25 changes: 19 additions & 6 deletions spec/models/appeal_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -250,10 +250,16 @@

context "#latest_attorney_case_review" do
let(:appeal) { create(:appeal) }
let(:task1) { create(:ama_attorney_task, appeal: appeal) }
let(:task2) { create(:ama_attorney_task, appeal: appeal) }
let!(:task1) { create(:ama_attorney_task, appeal: appeal) }
let!(:attorney_case_review1) { create(:attorney_case_review, task: task1, created_at: 2.days.ago) }
let!(:attorney_case_review2) { create(:attorney_case_review, task: task2, created_at: 1.day.ago) }
let!(:attorney_case_review2) do
task1.update!(status: Constants.TASK_STATUSES.completed)
if appeal.tasks.open.of_type("JudgeDecisionReviewTask").any?
appeal.tasks.open.find_by(type: "JudgeDecisionReviewTask").completed!
end
task2 = create(:ama_attorney_task, appeal: appeal)
create(:attorney_case_review, task: task2, created_at: 1.day.ago)
end

subject { appeal.latest_attorney_case_review }

Expand Down Expand Up @@ -909,8 +915,15 @@
let!(:attorney) { create(:user) }
let!(:attorney2) { create(:user) }
let!(:appeal) { create(:appeal) }
let!(:task) { create(:ama_attorney_task, assigned_to: attorney, appeal: appeal, created_at: 1.day.ago) }
let!(:task2) { create(:ama_attorney_task, assigned_to: attorney2, appeal: appeal) }
let(:judge_decision_review_task) { create(:ama_judge_decision_review_task, appeal: appeal) }
let!(:task) do
create(:ama_attorney_task, parent: judge_decision_review_task, assigned_to: attorney,
appeal: appeal, created_at: 1.day.ago)
end
let!(:task2) do
task.completed!
create(:ama_attorney_task, parent: judge_decision_review_task, assigned_to: attorney2, appeal: appeal)
end

subject { appeal.assigned_attorney }

Expand All @@ -919,7 +932,7 @@
end

it "should know the right assigned attorney with a cancelled task" do
task2.update(status: "cancelled")
task2.cancelled!
expect(subject).to eq attorney
end
end
Expand Down
4 changes: 2 additions & 2 deletions spec/models/concerns/task_tree_render_module_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
let(:root_task) { appeal.root_task }
let!(:ama_judge_assign_task) { create(:ama_judge_assign_task, parent: root_task, created_at: 1.day.ago.round) }
let!(:ama_attorney_task) { create(:ama_attorney_task, parent: root_task) }
let!(:ama_attorney_task_no_parent) { create(:ama_attorney_task, appeal: appeal) }
let!(:task_no_parent) { create(:track_veteran_task, appeal: appeal) }

context "#tree is called on an appeal" do
it "returns all tasks for the appeal" do
Expand Down Expand Up @@ -131,7 +131,7 @@ def tree2(obj, *atts, **kwargs)
initial_count = appeal.tasks.count + 3
expect(appeal.tree.lines.count).to eq initial_count

ama_attorney_task_no_parent.delete
task_no_parent.delete
appeal.reload
expect(appeal.tree.lines.count).to eq initial_count - 1
end
Expand Down
9 changes: 9 additions & 0 deletions spec/models/tasks/attorney_task_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,15 @@
expect(subject.errors.messages[:assigned_to].first).to eq "has to be an attorney"
end
end

context "when an AttorneyTask is already open for the appeal" do
let!(:attorney_task) { create(:ama_attorney_task, appeal: appeal, parent: parent) }
it "throws an error when a second task is created" do
expect { subject }.to raise_error do |error|
expect(error).to be_a(Caseflow::Error::MultipleOpenTasksOfSameTypeError)
end
end
end
end

context ".update" do
Expand Down
5 changes: 2 additions & 3 deletions spec/models/tasks/colocated_task_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -611,8 +611,7 @@
create(:judge_address_motion_to_vacate_task,
appeal: appeal,
assigned_to: judge,
parent: vacate_motion_mail_task
)
parent: vacate_motion_mail_task)
end
let(:post_decision_motion_params) do
{
Expand All @@ -629,7 +628,7 @@
Appeal.find_by(stream_docket_number: appeal.docket_number, stream_type: Constants.AMA_STREAM_TYPES.vacate)
end
let(:attorney_task) { AttorneyTask.find_by(assigned_to: attorney) }
let(:parent) { create(:ama_judge_decision_review_task, assigned_to: judge, appeal: vacate_stream ) }
let(:parent) { attorney_task.parent }

let(:params_list) do
[{
Expand Down
42 changes: 24 additions & 18 deletions spec/models/tasks/judge_task_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
let!(:first_assign_task) do
create(:ama_judge_assign_task, assigned_to: judge, appeal: appeal)
end
let!(:first_review_task) do
create(:ama_judge_decision_review_task, assigned_to: judge, appeal: appeal)
end

context "when one judge assign task is open for an appeal" do
it "throws an error when a second task is created" do
Expand All @@ -24,11 +27,18 @@
end
end
end

context "when one judge decision review task is open for an appeal" do
it "throws an error when a second task is created" do
expect { create(:ama_judge_decision_review_task, assigned_to: judge2, appeal: appeal) }.to raise_error do |err|
expect(err).to be_a(Caseflow::Error::MultipleOpenTasksOfSameTypeError)
end
end
end
end

describe "reassign" do
let(:root_task) { create(:root_task) }
let(:task) { create(:ama_judge_assign_task, parent: root_task) }
let(:old_assignee) { task.assigned_to }
let(:new_assignee) { create(:user) }
let(:params) do
Expand All @@ -40,25 +50,21 @@
end
subject { task.reassign(params, old_assignee) }

context "when a judge task is reassigned successfully" do
it "should not violate the only_open_task_of_type validation" do
expect { subject }.to_not raise_error
expect(Thread.current.thread_variable_get(:skip_check_for_only_open_task_of_type)).to be_nil
context "when the task is a judge decision review task" do
let(:task) { create(:ama_judge_decision_review_task, parent: root_task) }
context "when the judge decision review task is reassigned successfully" do
it "does not violate the only_open_task_of_type validation" do
expect { subject }.to_not raise_error
end
end
end

context "when a judge task throws an error during attempted reassignment" do
let(:params) do
{
assigned_to_id: nil,
assigned_to_type: new_assignee.class.name,
instructions: "instructions"
}
end

it "sets the thread local variable of skip_only_open_task_of_type to nil" do
expect { subject }.to raise_error ActiveRecord::RecordNotFound
expect(Thread.current.thread_variable_get(:skip_check_for_only_open_task_of_type)).to be_nil
context "when the task is a judge assign task" do
let(:task) { create(:ama_judge_assign_task, parent: root_task) }
context "when the judge assign task is reassigned successfully" do
it "should not violate the only_open_task_of_type validation" do
expect { subject }.to_not raise_error
end
end
end
end
Expand Down Expand Up @@ -246,7 +252,7 @@
it "should fail creation of second JudgeDecisionReviewTask" do
expect(root_task.appeal.tasks.count).to eq(2), root_task.appeal.tasks.to_a.to_s
jdrt.update(status: o_status)
expect { subject }.to raise_error(Caseflow::Error::DuplicateUserTask)
expect { subject }.to raise_error(Caseflow::Error::MultipleOpenTasksOfSameTypeError)
expect(root_task.appeal.tasks.count).to eq(2), root_task.appeal.tasks.to_a.to_s
end
end
Expand Down