mirror of
https://github.com/redmine/redmine.git
synced 2025-11-09 14:56:01 +01:00
Fix that spent_time total on the issue list can be wrong (#26471).
git-svn-id: http://svn.redmine.org/redmine/trunk@16839 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
@@ -187,18 +187,29 @@ class IssueQuery < Query
|
|||||||
@available_columns += issue_custom_fields.visible.collect {|cf| QueryCustomFieldColumn.new(cf) }
|
@available_columns += issue_custom_fields.visible.collect {|cf| QueryCustomFieldColumn.new(cf) }
|
||||||
|
|
||||||
if User.current.allowed_to?(:view_time_entries, project, :global => true)
|
if User.current.allowed_to?(:view_time_entries, project, :global => true)
|
||||||
|
# insert the columns after total_estimated_hours or at the end
|
||||||
index = @available_columns.find_index {|column| column.name == :total_estimated_hours}
|
index = @available_columns.find_index {|column| column.name == :total_estimated_hours}
|
||||||
index = (index ? index + 1 : -1)
|
index = (index ? index + 1 : -1)
|
||||||
# insert the column after total_estimated_hours or at the end
|
|
||||||
|
subselect = "SELECT SUM(hours) FROM #{TimeEntry.table_name}" +
|
||||||
|
" JOIN #{Project.table_name} ON #{Project.table_name}.id = #{TimeEntry.table_name}.project_id" +
|
||||||
|
" WHERE (#{TimeEntry.visible_condition(User.current)}) AND #{TimeEntry.table_name}.issue_id = #{Issue.table_name}.id"
|
||||||
|
|
||||||
@available_columns.insert index, QueryColumn.new(:spent_hours,
|
@available_columns.insert index, QueryColumn.new(:spent_hours,
|
||||||
:sortable => "COALESCE((SELECT SUM(hours) FROM #{TimeEntry.table_name} WHERE #{TimeEntry.table_name}.issue_id = #{Issue.table_name}.id), 0)",
|
:sortable => "COALESCE((#{subselect}), 0)",
|
||||||
:default_order => 'desc',
|
:default_order => 'desc',
|
||||||
:caption => :label_spent_time,
|
:caption => :label_spent_time,
|
||||||
:totalable => true
|
:totalable => true
|
||||||
)
|
)
|
||||||
|
|
||||||
|
subselect = "SELECT SUM(hours) FROM #{TimeEntry.table_name}" +
|
||||||
|
" JOIN #{Project.table_name} ON #{Project.table_name}.id = #{TimeEntry.table_name}.project_id" +
|
||||||
|
" JOIN #{Issue.table_name} subtasks ON subtasks.id = #{TimeEntry.table_name}.issue_id" +
|
||||||
|
" WHERE (#{TimeEntry.visible_condition(User.current)})" +
|
||||||
|
" AND subtasks.root_id = #{Issue.table_name}.root_id AND subtasks.lft >= #{Issue.table_name}.lft AND subtasks.rgt <= #{Issue.table_name}.rgt"
|
||||||
|
|
||||||
@available_columns.insert index+1, QueryColumn.new(:total_spent_hours,
|
@available_columns.insert index+1, QueryColumn.new(:total_spent_hours,
|
||||||
:sortable => "COALESCE((SELECT SUM(hours) FROM #{TimeEntry.table_name} JOIN #{Issue.table_name} subtasks ON subtasks.id = #{TimeEntry.table_name}.issue_id" +
|
:sortable => "COALESCE((#{subselect}), 0)",
|
||||||
" WHERE subtasks.root_id = #{Issue.table_name}.root_id AND subtasks.lft >= #{Issue.table_name}.lft AND subtasks.rgt <= #{Issue.table_name}.rgt), 0)",
|
|
||||||
:default_order => 'desc',
|
:default_order => 'desc',
|
||||||
:caption => :label_total_spent_time
|
:caption => :label_total_spent_time
|
||||||
)
|
)
|
||||||
@@ -251,15 +262,10 @@ class IssueQuery < Query
|
|||||||
|
|
||||||
# Returns sum of all the issue's time entries hours
|
# Returns sum of all the issue's time entries hours
|
||||||
def total_for_spent_hours(scope)
|
def total_for_spent_hours(scope)
|
||||||
total = if group_by_column.try(:name) == :project
|
total = scope.joins(:time_entries).
|
||||||
# TODO: remove this when https://github.com/rails/rails/issues/21922 is fixed
|
where(TimeEntry.visible_condition(User.current)).
|
||||||
# We have to do a custom join without the time_entries.project_id column
|
sum("#{TimeEntry.table_name}.hours")
|
||||||
# that would trigger a ambiguous column name error
|
|
||||||
scope.joins("JOIN (SELECT issue_id, hours FROM #{TimeEntry.table_name}) AS joined_time_entries ON joined_time_entries.issue_id = #{Issue.table_name}.id").
|
|
||||||
sum("joined_time_entries.hours")
|
|
||||||
else
|
|
||||||
scope.joins(:time_entries).sum("#{TimeEntry.table_name}.hours")
|
|
||||||
end
|
|
||||||
map_total(total) {|t| t.to_f.round(2)}
|
map_total(total) {|t| t.to_f.round(2)}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -952,6 +952,22 @@ class IssuesControllerTest < Redmine::ControllerTest
|
|||||||
assert_equal hours.sort.reverse, hours
|
assert_equal hours.sort.reverse, hours
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_index_sort_by_spent_hours_should_sort_by_visible_spent_hours
|
||||||
|
TimeEntry.delete_all
|
||||||
|
TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1), :hours => 3)
|
||||||
|
TimeEntry.generate!(:issue => Issue.generate!(:project_id => 3), :hours => 4)
|
||||||
|
|
||||||
|
get :index, :params => {:sort => "spent_hours:desc", :c => ['subject','spent_hours']}
|
||||||
|
assert_response :success
|
||||||
|
assert_equal [4.0, 3.0, 0.0], issues_in_list.map(&:spent_hours)[0..2]
|
||||||
|
|
||||||
|
Project.find(3).disable_module!(:time_tracking)
|
||||||
|
|
||||||
|
get :index, :params => {:sort => "spent_hours:desc", :c => ['subject','spent_hours']}
|
||||||
|
assert_response :success
|
||||||
|
assert_equal [3.0, 0.0, 0.0], issues_in_list.map(&:spent_hours)[0..2]
|
||||||
|
end
|
||||||
|
|
||||||
def test_index_sort_by_total_spent_hours
|
def test_index_sort_by_total_spent_hours
|
||||||
get :index, :params => {
|
get :index, :params => {
|
||||||
:sort => 'total_spent_hours:desc'
|
:sort => 'total_spent_hours:desc'
|
||||||
@@ -1390,6 +1406,22 @@ class IssuesControllerTest < Redmine::ControllerTest
|
|||||||
assert_select ".total-for-cf-#{field.id} span.value", :text => '9'
|
assert_select ".total-for-cf-#{field.id} span.value", :text => '9'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_index_with_spent_time_total_should_sum_visible_spent_time_only
|
||||||
|
TimeEntry.delete_all
|
||||||
|
TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1), :hours => 3)
|
||||||
|
TimeEntry.generate!(:issue => Issue.generate!(:project_id => 3), :hours => 4)
|
||||||
|
|
||||||
|
get :index, :params => {:t => ["spent_hours"]}
|
||||||
|
assert_response :success
|
||||||
|
assert_select ".total-for-spent-hours span.value", :text => '7.00'
|
||||||
|
|
||||||
|
Project.find(3).disable_module!(:time_tracking)
|
||||||
|
|
||||||
|
get :index, :params => {:t => ["spent_hours"]}
|
||||||
|
assert_response :success
|
||||||
|
assert_select ".total-for-spent-hours span.value", :text => '3.00'
|
||||||
|
end
|
||||||
|
|
||||||
def test_index_totals_should_default_to_settings
|
def test_index_totals_should_default_to_settings
|
||||||
with_settings :issue_list_default_totals => ['estimated_hours'] do
|
with_settings :issue_list_default_totals => ['estimated_hours'] do
|
||||||
get :index
|
get :index
|
||||||
|
|||||||
Reference in New Issue
Block a user