Chris@1494: # Redmine - project management software Chris@1494: # Copyright (C) 2006-2014 Jean-Philippe Lang Chris@1494: # Chris@1494: # This program is free software; you can redistribute it and/or Chris@1494: # modify it under the terms of the GNU General Public License Chris@1494: # as published by the Free Software Foundation; either version 2 Chris@1494: # of the License, or (at your option) any later version. Chris@1494: # Chris@1494: # This program is distributed in the hope that it will be useful, Chris@1494: # but WITHOUT ANY WARRANTY; without even the implied warranty of Chris@1494: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Chris@1494: # GNU General Public License for more details. Chris@1494: # Chris@1494: # You should have received a copy of the GNU General Public License Chris@1494: # along with this program; if not, write to the Free Software Chris@1494: # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Chris@1494: Chris@1494: class TimeEntryQuery < Query Chris@1494: Chris@1494: self.queried_class = TimeEntry Chris@1494: Chris@1494: self.available_columns = [ Chris@1494: QueryColumn.new(:project, :sortable => "#{Project.table_name}.name", :groupable => true), Chris@1494: QueryColumn.new(:spent_on, :sortable => ["#{TimeEntry.table_name}.spent_on", "#{TimeEntry.table_name}.created_on"], :default_order => 'desc', :groupable => true), Chris@1494: QueryColumn.new(:user, :sortable => lambda {User.fields_for_order_statement}, :groupable => true), Chris@1494: QueryColumn.new(:activity, :sortable => "#{TimeEntryActivity.table_name}.position", :groupable => true), Chris@1494: QueryColumn.new(:issue, :sortable => "#{Issue.table_name}.id"), Chris@1494: QueryColumn.new(:comments), Chris@1494: QueryColumn.new(:hours, :sortable => "#{TimeEntry.table_name}.hours"), Chris@1494: ] Chris@1494: Chris@1494: def initialize(attributes=nil, *args) Chris@1494: super attributes Chris@1494: self.filters ||= {} Chris@1494: add_filter('spent_on', '*') unless filters.present? Chris@1494: end Chris@1494: Chris@1494: def initialize_available_filters Chris@1494: add_available_filter "spent_on", :type => :date_past Chris@1494: Chris@1494: principals = [] Chris@1494: if project Chris@1494: principals += project.principals.sort Chris@1494: unless project.leaf? Chris@1494: subprojects = project.descendants.visible.all Chris@1494: if subprojects.any? Chris@1494: add_available_filter "subproject_id", Chris@1494: :type => :list_subprojects, Chris@1494: :values => subprojects.collect{|s| [s.name, s.id.to_s] } Chris@1494: principals += Principal.member_of(subprojects) Chris@1494: end Chris@1494: end Chris@1494: else Chris@1494: if all_projects.any? Chris@1494: # members of visible projects Chris@1494: principals += Principal.member_of(all_projects) Chris@1494: # project filter Chris@1494: project_values = [] Chris@1494: if User.current.logged? && User.current.memberships.any? Chris@1494: project_values << ["<< #{l(:label_my_projects).downcase} >>", "mine"] Chris@1494: end Chris@1494: project_values += all_projects_values Chris@1494: add_available_filter("project_id", Chris@1494: :type => :list, :values => project_values Chris@1494: ) unless project_values.empty? Chris@1494: end Chris@1494: end Chris@1494: principals.uniq! Chris@1494: principals.sort! Chris@1494: users = principals.select {|p| p.is_a?(User)} Chris@1494: Chris@1494: users_values = [] Chris@1494: users_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged? Chris@1494: users_values += users.collect{|s| [s.name, s.id.to_s] } Chris@1494: add_available_filter("user_id", Chris@1494: :type => :list_optional, :values => users_values Chris@1494: ) unless users_values.empty? Chris@1494: Chris@1494: activities = (project ? project.activities : TimeEntryActivity.shared.active) Chris@1494: add_available_filter("activity_id", Chris@1494: :type => :list, :values => activities.map {|a| [a.name, a.id.to_s]} Chris@1494: ) unless activities.empty? Chris@1494: Chris@1494: add_available_filter "comments", :type => :text Chris@1494: add_available_filter "hours", :type => :float Chris@1494: Chris@1494: add_custom_fields_filters(TimeEntryCustomField) Chris@1494: add_associations_custom_fields_filters :project, :issue, :user Chris@1494: end Chris@1494: Chris@1494: def available_columns Chris@1494: return @available_columns if @available_columns Chris@1494: @available_columns = self.class.available_columns.dup Chris@1494: @available_columns += TimeEntryCustomField.visible.all.map {|cf| QueryCustomFieldColumn.new(cf) } Chris@1494: @available_columns += IssueCustomField.visible.all.map {|cf| QueryAssociationCustomFieldColumn.new(:issue, cf) } Chris@1494: @available_columns Chris@1494: end Chris@1494: Chris@1494: def default_columns_names Chris@1494: @default_columns_names ||= [:project, :spent_on, :user, :activity, :issue, :comments, :hours] Chris@1494: end Chris@1494: Chris@1494: def results_scope(options={}) Chris@1494: order_option = [group_by_sort_order, options[:order]].flatten.reject(&:blank?) Chris@1494: Chris@1494: TimeEntry.visible. Chris@1494: where(statement). Chris@1494: order(order_option). Chris@1494: joins(joins_for_order_statement(order_option.join(','))). Chris@1494: includes(:activity) Chris@1494: end Chris@1494: Chris@1494: def sql_for_activity_id_field(field, operator, value) Chris@1494: condition_on_id = sql_for_field(field, operator, value, Enumeration.table_name, 'id') Chris@1494: condition_on_parent_id = sql_for_field(field, operator, value, Enumeration.table_name, 'parent_id') Chris@1494: ids = value.map(&:to_i).join(',') Chris@1494: table_name = Enumeration.table_name Chris@1494: if operator == '=' Chris@1494: "(#{table_name}.id IN (#{ids}) OR #{table_name}.parent_id IN (#{ids}))" Chris@1494: else Chris@1494: "(#{table_name}.id NOT IN (#{ids}) AND (#{table_name}.parent_id IS NULL OR #{table_name}.parent_id NOT IN (#{ids})))" Chris@1494: end Chris@1494: end Chris@1494: Chris@1494: # Accepts :from/:to params as shortcut filters Chris@1494: def build_from_params(params) Chris@1494: super Chris@1494: if params[:from].present? && params[:to].present? Chris@1494: add_filter('spent_on', '><', [params[:from], params[:to]]) Chris@1494: elsif params[:from].present? Chris@1494: add_filter('spent_on', '>=', [params[:from]]) Chris@1494: elsif params[:to].present? Chris@1494: add_filter('spent_on', '<=', [params[:to]]) Chris@1494: end Chris@1494: self Chris@1494: end Chris@1494: end