diff --git a/lib/redmine/helpers/time_report.rb b/lib/redmine/helpers/time_report.rb index 89b94ec3c4..7b1c0a1a6c 100644 --- a/lib/redmine/helpers/time_report.rb +++ b/lib/redmine/helpers/time_report.rb @@ -47,7 +47,7 @@ module Redmine time_columns = %w(tyear tmonth tweek spent_on) @hours = [] @scope.includes(:activity). - reorder(nil). + reorder(@criteria.collect{|criteria| @available_criteria[criteria][:order]}.compact). group(@criteria.collect{|criteria| @available_criteria[criteria][:sql]} + time_columns). joins(@criteria.collect{|criteria| @available_criteria[criteria][:joins]}.compact). sum(:hours).each do |hash, hours| @@ -105,27 +105,39 @@ module Redmine def load_available_criteria @available_criteria = { 'project' => {:sql => "#{TimeEntry.table_name}.project_id", + :order => {Arel.sql("LOWER(#{Project.table_name}.name)") => :asc, "#{TimeEntry.table_name}.project_id" => :asc}, :klass => Project, :label => :label_project}, 'status' => {:sql => "#{Issue.table_name}.status_id", + :joins => "LEFT OUTER JOIN #{IssueStatus.table_name} ON #{IssueStatus.table_name}.id = #{Issue.table_name}.status_id", + :order => {"#{IssueStatus.table_name}.position" => :asc, "#{Issue.table_name}.status_id" => :asc}, :klass => IssueStatus, :label => :field_status}, 'version' => {:sql => "#{Issue.table_name}.fixed_version_id", + :joins => "LEFT OUTER JOIN #{Version.table_name} ON #{Version.table_name}.id = #{Issue.table_name}.fixed_version_id", + :order => {"#{Version.table_name}.name" => :asc, "#{Issue.table_name}.fixed_version_id" => :asc}, :klass => ::Version, :label => :label_version}, 'category' => {:sql => "#{Issue.table_name}.category_id", + :joins => "LEFT OUTER JOIN #{IssueCategory.table_name} ON #{IssueCategory.table_name}.id = #{Issue.table_name}.category_id", + :order => {"#{IssueCategory.table_name}.name" => :asc, "#{Issue.table_name}.category_id" => :asc}, :klass => IssueCategory, :label => :field_category}, 'user' => {:sql => "#{TimeEntry.table_name}.user_id", + :order => User.fields_for_order_statement.index_with{|_| :asc}, :klass => User, :label => :label_user}, 'tracker' => {:sql => "#{Issue.table_name}.tracker_id", + :joins => "LEFT OUTER JOIN #{Tracker.table_name} ON #{Tracker.table_name}.id = #{Issue.table_name}.tracker_id", + :order => {"#{Tracker.table_name}.position" => :asc, "#{Issue.table_name}.tracker_id" => :asc}, :klass => Tracker, :label => :label_tracker}, 'activity' => {:sql => "#{TimeEntry.table_name}.activity_id", + :order => {"#{TimeEntryActivity.table_name}.position" => :asc, "#{TimeEntry.table_name}.activity_id" => :asc}, :klass => TimeEntryActivity, :label => :field_activity}, 'issue' => {:sql => "#{TimeEntry.table_name}.issue_id", + :order => {"#{TimeEntry.table_name}.issue_id" => :asc}, :klass => Issue, :label => :label_issue} } @@ -141,8 +153,17 @@ module Redmine # Add list and boolean custom fields as available criteria custom_fields.select {|cf| %w(list bool).include?(cf.field_format) && !cf.multiple?}.each do |cf| + subquery_name = "#{cf.format.__send__(:join_alias, cf)}_options" + subquery = + cf.format.possible_values_options(cf).collect.with_index(1) do |option, idx| + value = option.is_a?(Array) ? option.last : option + cf.class.sanitize_sql_array(["SELECT %d AS id, '%s' AS value", idx, value]) + end.join(' UNION ') + joins = cf.join_for_order_statement + joins << " LEFT OUTER JOIN (#{subquery}) AS #{subquery_name} ON #{subquery_name}.value = #{cf.group_statement}" @available_criteria["cf_#{cf.id}"] = {:sql => cf.group_statement, - :joins => cf.join_for_order_statement, + :joins => joins, + :order => {"#{subquery_name}.id" => :asc}, :format => cf.field_format, :custom_field => cf, :label => cf.name}