##// END OF EJS Templates
Handle time entries on subtasks and prevent from reassigning an issue that is going to be deleted (#24718, #24693)....
Jean-Philippe Lang -
r15736:987ca8cc2af0
parent child
Show More
@@ -343,21 +343,28 class IssuesController < ApplicationController
343
343
344 def destroy
344 def destroy
345 raise Unauthorized unless @issues.all?(&:deletable?)
345 raise Unauthorized unless @issues.all?(&:deletable?)
346 @hours = TimeEntry.where(:issue_id => @issues.map(&:id)).sum(:hours).to_f
346
347 # all issues and their descendants are about to be deleted
348 issues_and_descendants_ids = Issue.self_and_descendants(@issues).pluck(:id)
349 time_entries = TimeEntry.where(:issue_id => issues_and_descendants_ids)
350 @hours = time_entries.sum(:hours).to_f
351
347 if @hours > 0
352 if @hours > 0
348 case params[:todo]
353 case params[:todo]
349 when 'destroy'
354 when 'destroy'
350 # nothing to do
355 # nothing to do
351 when 'nullify'
356 when 'nullify'
352 TimeEntry.where(['issue_id IN (?)', @issues]).update_all('issue_id = NULL')
357 time_entries.update_all(:issue_id => nil)
353 when 'reassign'
358 when 'reassign'
354 reassign_to = @project.issues.find_by_id(params[:reassign_to_id])
359 reassign_to = @project.issues.find_by_id(params[:reassign_to_id])
355 if reassign_to.nil?
360 if reassign_to.nil?
356 flash.now[:error] = l(:error_issue_not_found_in_project)
361 flash.now[:error] = l(:error_issue_not_found_in_project)
357 return
362 return
363 elsif issues_and_descendants_ids.include?(reassign_to.id)
364 flash.now[:error] = l(:error_cannot_reassign_time_entries_to_an_issue_about_to_be_deleted)
365 return
358 else
366 else
359 TimeEntry.where(['issue_id IN (?)', @issues]).
367 time_entries.update_all(:issue_id => reassign_to.id)
360 update_all("issue_id = #{reassign_to.id}")
361 end
368 end
362 else
369 else
363 # display the destroy form if it's a user request
370 # display the destroy form if it's a user request
@@ -1102,6 +1102,15 class Issue < ActiveRecord::Base
1102 end
1102 end
1103 end
1103 end
1104
1104
1105 # Returns a scope of the given issues and their descendants
1106 def self.self_and_descendants(issues)
1107 issue_ids = Issue.joins("JOIN #{Issue.table_name} ancestors" +
1108 " ON ancestors.root_id = #{Issue.table_name}.root_id" +
1109 " AND ancestors.lft <= #{Issue.table_name}.lft AND ancestors.rgt >= #{Issue.table_name}.rgt"
1110 ).
1111 where(:ancestors => {:id => issues.map(&:id)})
1112 end
1113
1105 # Finds an issue relation given its id.
1114 # Finds an issue relation given its id.
1106 def find_relation(relation_id)
1115 def find_relation(relation_id)
1107 IssueRelation.where("issue_to_id = ? OR issue_from_id = ?", id, id).find(relation_id)
1116 IssueRelation.where("issue_to_id = ? OR issue_from_id = ?", id, id).find(relation_id)
@@ -218,6 +218,7 en:
218 error_no_tracker_allowed_for_new_issue_in_project: "The project doesn't have any trackers for which you can create an issue"
218 error_no_tracker_allowed_for_new_issue_in_project: "The project doesn't have any trackers for which you can create an issue"
219 error_no_projects_with_tracker_allowed_for_new_issue: "There are no projects with trackers for which you can create an issue"
219 error_no_projects_with_tracker_allowed_for_new_issue: "There are no projects with trackers for which you can create an issue"
220 error_move_of_child_not_possible: "Subtask %{child} could not be moved to the new project: %{errors}"
220 error_move_of_child_not_possible: "Subtask %{child} could not be moved to the new project: %{errors}"
221 error_cannot_reassign_time_entries_to_an_issue_about_to_be_deleted: "Spent time cannot be reassigned to an issue that is about to be deleted"
221
222
222 mail_subject_lost_password: "Your %{value} password"
223 mail_subject_lost_password: "Your %{value} password"
223 mail_body_lost_password: 'To change your password, click on the following link:'
224 mail_body_lost_password: 'To change your password, click on the following link:'
@@ -238,6 +238,7 fr:
238 error_no_tracker_allowed_for_new_issue_in_project: "Le projet ne dispose d'aucun tracker sur lequel vous pouvez crΓ©er une demande"
238 error_no_tracker_allowed_for_new_issue_in_project: "Le projet ne dispose d'aucun tracker sur lequel vous pouvez crΓ©er une demande"
239 error_no_projects_with_tracker_allowed_for_new_issue: "Aucun projet ne dispose d'un tracker sur lequel vous pouvez crΓ©er une demande"
239 error_no_projects_with_tracker_allowed_for_new_issue: "Aucun projet ne dispose d'un tracker sur lequel vous pouvez crΓ©er une demande"
240 error_move_of_child_not_possible: "La sous-tΓ’che %{child} n'a pas pu Γͺtre dΓ©placΓ©e dans le nouveau projet : %{errors}"
240 error_move_of_child_not_possible: "La sous-tΓ’che %{child} n'a pas pu Γͺtre dΓ©placΓ©e dans le nouveau projet : %{errors}"
241 error_cannot_reassign_time_entries_to_an_issue_about_to_be_deleted: "Le temps passΓ© ne peut pas Γͺtre rΓ©affectΓ© Γ  une demande qui va Γͺtre supprimΓ©e"
241
242
242 mail_subject_lost_password: "Votre mot de passe %{value}"
243 mail_subject_lost_password: "Votre mot de passe %{value}"
243 mail_body_lost_password: 'Pour changer votre mot de passe, cliquez sur le lien suivant :'
244 mail_body_lost_password: 'Pour changer votre mot de passe, cliquez sur le lien suivant :'
@@ -4609,7 +4609,7 class IssuesControllerTest < Redmine::ControllerTest
4609 assert_response :success
4609 assert_response :success
4610 end
4610 end
4611
4611
4612 def test_destroy_issue_with_no_time_entries
4612 def test_destroy_issue_with_no_time_entries_should_delete_the_issues
4613 assert_nil TimeEntry.find_by_issue_id(2)
4613 assert_nil TimeEntry.find_by_issue_id(2)
4614 @request.session[:user_id] = 2
4614 @request.session[:user_id] = 2
4615
4615
@@ -4620,7 +4620,7 class IssuesControllerTest < Redmine::ControllerTest
4620 assert_nil Issue.find_by_id(2)
4620 assert_nil Issue.find_by_id(2)
4621 end
4621 end
4622
4622
4623 def test_destroy_issues_with_time_entries
4623 def test_destroy_issues_with_time_entries_should_show_the_reassign_form
4624 @request.session[:user_id] = 2
4624 @request.session[:user_id] = 2
4625
4625
4626 assert_no_difference 'Issue.count' do
4626 assert_no_difference 'Issue.count' do
@@ -4633,6 +4633,20 class IssuesControllerTest < Redmine::ControllerTest
4633 end
4633 end
4634 end
4634 end
4635
4635
4636 def test_destroy_issues_with_time_entries_should_show_hours_on_issues_and_descendants
4637 parent = Issue.generate_with_child!
4638 TimeEntry.generate!(:issue => parent)
4639 TimeEntry.generate!(:issue => parent.children.first)
4640 leaf = Issue.generate!
4641 TimeEntry.generate!(:issue => leaf)
4642 @request.session[:user_id] = 2
4643
4644 delete :destroy, :ids => [parent.id, leaf.id]
4645 assert_response :success
4646
4647 assert_select 'p', :text => /3\.00 hours were reported/
4648 end
4649
4636 def test_destroy_issues_and_destroy_time_entries
4650 def test_destroy_issues_and_destroy_time_entries
4637 @request.session[:user_id] = 2
4651 @request.session[:user_id] = 2
4638
4652
@@ -4674,6 +4688,24 class IssuesControllerTest < Redmine::ControllerTest
4674 assert_equal 2, TimeEntry.find(2).issue_id
4688 assert_equal 2, TimeEntry.find(2).issue_id
4675 end
4689 end
4676
4690
4691 def test_destroy_issues_with_time_entries_should_reassign_time_entries_of_issues_and_descendants
4692 parent = Issue.generate_with_child!
4693 TimeEntry.generate!(:issue => parent)
4694 TimeEntry.generate!(:issue => parent.children.first)
4695 leaf = Issue.generate!
4696 TimeEntry.generate!(:issue => leaf)
4697 target = Issue.generate!
4698 @request.session[:user_id] = 2
4699
4700 assert_difference 'Issue.count', -3 do
4701 assert_no_difference 'TimeEntry.count' do
4702 delete :destroy, :ids => [parent.id, leaf.id], :todo => 'reassign', :reassign_to_id => target.id
4703 assert_response 302
4704 end
4705 end
4706 assert_equal 3, target.time_entries.count
4707 end
4708
4677 def test_destroy_issues_and_reassign_time_entries_to_an_invalid_issue_should_fail
4709 def test_destroy_issues_and_reassign_time_entries_to_an_invalid_issue_should_fail
4678 @request.session[:user_id] = 2
4710 @request.session[:user_id] = 2
4679
4711
@@ -4686,6 +4718,18 class IssuesControllerTest < Redmine::ControllerTest
4686 assert_response :success
4718 assert_response :success
4687 end
4719 end
4688
4720
4721 def test_destroy_issues_and_reassign_time_entries_to_an_issue_to_delete_should_fail
4722 @request.session[:user_id] = 2
4723
4724 assert_no_difference 'Issue.count' do
4725 assert_no_difference 'TimeEntry.count' do
4726 delete :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 3
4727 end
4728 end
4729 assert_response :success
4730 assert_select '#flash_error', :text => I18n.t(:error_cannot_reassign_time_entries_to_an_issue_about_to_be_deleted)
4731 end
4732
4689 def test_destroy_issues_from_different_projects
4733 def test_destroy_issues_from_different_projects
4690 @request.session[:user_id] = 2
4734 @request.session[:user_id] = 2
4691
4735
General Comments 0
You need to be logged in to leave comments. Login now