Project

General

Profile

Feature #41053 » 41053-v2.patch

Go MAEDA, 2024-08-13 10:29

View differences:

app/models/time_entry_query.rb
91 91
      "user_id",
92 92
      :type => :list_optional, :values => lambda {author_values}
93 93
    )
94
    add_available_filter(
95
      "user.group",
96
      :type => :list_optional,
97
      :name => l("label_attribute_of_user", :name => l(:label_group)),
98
      :values => lambda {Group.givable.visible.pluck(:name, :id).map {|name, id| [name, id.to_s]}}
99
    )
100
    add_available_filter(
101
      "user.role",
102
      :type => :list_optional,
103
      :name => l("label_attribute_of_user", :name => l(:field_role)),
104
      :values => lambda {Role.givable.pluck(:name, :id).map {|name, id| [name, id.to_s]}}
105
    )
94 106
    add_available_filter(
95 107
      "author_id",
96 108
      :type => :list_optional, :values => lambda {author_values}
......
264 276
    sql_for_field(field, operator, value, Project.table_name, "status")
265 277
  end
266 278

  
279
  def sql_for_user_group_field(field, operator, value)
280
    if operator == '*' # Any group
281
      groups = Group.givable
282
      operator = '='
283
    elsif operator == '!*'
284
      groups = Group.givable
285
      operator = '!'
286
    else
287
      groups = Group.where(:id => value).to_a
288
    end
289
    groups ||= []
290

  
291
    members_of_groups = groups.inject([]) do |user_ids, group|
292
      user_ids + group.user_ids
293
    end.uniq.compact.sort.collect(&:to_s)
294

  
295
    '(' + sql_for_field('user_id', operator, members_of_groups, TimeEntry.table_name, "user_id", false) + ')'
296
  end
297

  
298
  def sql_for_user_role_field(field, operator, value)
299
    case operator
300
    when "*", "!*"
301
      sw = operator == "!*" ? "NOT" : ""
302
      nl = operator == "!*" ? "#{TimeEntry.table_name}.user_id IS NULL OR" : ""
303

  
304
      subquery =
305
        "SELECT 1" +
306
        " FROM #{Member.table_name}" +
307
        " WHERE #{TimeEntry.table_name}.project_id = #{Member.table_name}.project_id AND #{Member.table_name}.user_id = #{TimeEntry.table_name}.user_id"
308
      "(#{nl} #{sw} EXISTS (#{subquery}))"
309
    when "=", "!"
310
      role_cond =
311
        if value.any?
312
          "#{MemberRole.table_name}.role_id IN (" + value.collect{|val| "'#{self.class.connection.quote_string(val)}'"}.join(",") + ")"
313
        else
314
          "1=0"
315
        end
316
      sw = operator == "!" ? 'NOT' : ''
317
      nl = operator == "!" ? "#{TimeEntry.table_name}.user_id IS NULL OR" : ''
318
      subquery =
319
        "SELECT 1" +
320
        " FROM #{Member.table_name} inner join #{MemberRole.table_name} on members.id = member_roles.member_id" +
321
        " WHERE #{TimeEntry.table_name}.project_id = #{Member.table_name}.project_id AND #{Member.table_name}.user_id = #{TimeEntry.table_name}.user_id AND #{role_cond}"
322
      "(#{nl} #{sw} EXISTS (#{subquery}))"
323
    end
324
  end
325

  
267 326
  # Accepts :from/:to params as shortcut filters
268 327
  def build_from_params(params, defaults={})
269 328
    super
test/unit/time_entry_query_test.rb
136 136
    assert !query.available_filters.has_key?('project.status')
137 137
  end
138 138

  
139
  def test_user_group_filter_should_consider_spacified_groups_time_entries
140
    Group.find(10).users << User.find(2)
141
    Group.find(11).users << User.find(3)
142

  
143
    TimeEntry.delete_all
144
    t1 = TimeEntry.generate!(:hours => 1.0, :user_id => 2)
145
    t2 = TimeEntry.generate!(:hours => 2.0, :user_id => 2)
146
    t3 = TimeEntry.generate!(:hours => 4.0, :user_id => 3)
147

  
148
    query = TimeEntryQuery.new(:name => '_')
149
    result = query.base_scope.to_a
150
    assert result.include?(t1)
151
    assert result.include?(t2)
152
    assert result.include?(t3)
153
    assert_equal 7.0, query.results_scope.sum(:hours)
154

  
155
    query.add_filter('user.group', '=', ['10'])
156
    result = query.base_scope.to_a
157
    assert result.include?(t1)
158
    assert result.include?(t2)
159
    assert_not result.include?(t3)
160
    assert_equal 3.0, query.results_scope.sum(:hours)
161

  
162
    query.add_filter('user.group', '=', ['10', '11'])
163
    result = query.base_scope.to_a
164
    assert result.include?(t1)
165
    assert result.include?(t2)
166
    assert result.include?(t3)
167
    assert_equal 7.0, query.results_scope.sum(:hours)
168
  end
169

  
170
  def test_user_role_filter_should_consider_spacified_roles_time_entries
171
    project = Project.find(1)
172
    project.members << Member.new(:user_id => 2, :roles => [Role.find(1)])
173
    project.members << Member.new(:user_id => 3, :roles => [Role.find(2)])
174

  
175
    TimeEntry.delete_all
176
    t1 = TimeEntry.generate!(:project => project, :hours => 1.0, :user_id => 2)
177
    t2 = TimeEntry.generate!(:project => project, :hours => 2.0, :user_id => 2)
178
    t3 = TimeEntry.generate!(:project => project, :hours => 4.0, :user_id => 3)
179

  
180
    query = TimeEntryQuery.new(:project => project, :name => '_')
181
    result = query.base_scope.to_a
182
    assert result.include?(t1)
183
    assert result.include?(t2)
184
    assert result.include?(t3)
185
    assert_equal 7.0, query.results_scope.sum(:hours)
186

  
187
    query.add_filter('user.role', '=', ['1'])
188
    result = query.base_scope.to_a
189
    assert result.include?(t1)
190
    assert result.include?(t2)
191
    assert_not result.include?(t3)
192
    assert_equal 3.0, query.results_scope.sum(:hours)
193

  
194
    query.add_filter('user.role', '=', ['1', '2'])
195
    result = query.base_scope.to_a
196
    assert result.include?(t1)
197
    assert result.include?(t2)
198
    assert result.include?(t3)
199
    assert_equal 7.0, query.results_scope.sum(:hours)
200
  end
201

  
139 202
  def test_results_scope_should_be_in_the_same_order_when_paginating
140 203
    4.times {TimeEntry.generate!}
141 204
    q = TimeEntryQuery.new
(3-3/3)