Project

General

Profile

« Previous | Next » 

Revision 2349

Use estimated hours to weight issues in version completion calculation (#2182).

View differences:

trunk/app/models/version.rb
51 51
  end
52 52
  
53 53
  def completed_pourcent
54
    if fixed_issues.count == 0
54
    if issues_count == 0
55 55
      0
56 56
    elsif open_issues_count == 0
57 57
      100
58 58
    else
59
      (closed_issues_count * 100 + Issue.sum('done_ratio', :include => 'status', :conditions => ["fixed_version_id = ? AND is_closed = ?", id, false]).to_f) / fixed_issues.count
59
      issues_progress(false) + issues_progress(true)
60 60
    end
61 61
  end
62 62
  
63 63
  def closed_pourcent
64
    if fixed_issues.count == 0
64
    if issues_count == 0
65 65
      0
66 66
    else
67
      closed_issues_count * 100.0 / fixed_issues.count
67
      issues_progress(false)
68 68
    end
69 69
  end
70 70
  
......
73 73
    effective_date && (effective_date < Date.today) && (open_issues_count > 0)
74 74
  end
75 75
  
76
  # Returns assigned issues count
77
  def issues_count
78
    @issue_count ||= fixed_issues.count
79
  end
80
  
76 81
  def open_issues_count
77 82
    @open_issues_count ||= Issue.count(:all, :conditions => ["fixed_version_id = ? AND is_closed = ?", self.id, false], :include => :status)
78 83
  end
......
104 109
  def check_integrity
105 110
    raise "Can't delete version" if self.fixed_issues.find(:first)
106 111
  end
112
  
113
  # Returns the average estimated time of assigned issues
114
  # or 1 if no issue has an estimated time
115
  # Used to weigth unestimated issues in progress calculation
116
  def estimated_average
117
    if @estimated_average.nil?
118
      average = fixed_issues.average(:estimated_hours).to_f
119
      if average == 0
120
        average = 1
121
      end
122
      @estimated_average = average
123
    end
124
    @estimated_average
125
  end
126
  
127
  # Returns the total progress of open or closed issues
128
  def issues_progress(open)
129
    @issues_progress ||= {}
130
    @issues_progress[open] ||= begin
131
      progress = 0
132
      if issues_count > 0
133
        ratio = open ? 'done_ratio' : 100
134
        done = fixed_issues.sum("COALESCE(estimated_hours, #{estimated_average}) * #{ratio}",
135
                                  :include => :status,
136
                                  :conditions => ["is_closed = ?", !open]).to_f
137
                                  
138
        progress = done / (estimated_average * issues_count)
139
      end
140
      progress
141
    end
142
  end
107 143
end
trunk/test/unit/version_test.rb
18 18
require File.dirname(__FILE__) + '/../test_helper'
19 19

  
20 20
class VersionTest < Test::Unit::TestCase
21
  fixtures :projects, :issues, :issue_statuses, :versions
21
  fixtures :projects, :users, :issues, :issue_statuses, :trackers, :enumerations, :versions
22 22

  
23 23
  def setup
24 24
  end
......
33 33
    assert !v.save
34 34
    assert_equal 'activerecord_error_not_a_date', v.errors.on(:effective_date)
35 35
  end
36
  
37
  def test_progress_should_be_0_with_no_assigned_issues
38
    project = Project.find(1)
39
    v = Version.create!(:project => project, :name => 'Progress')
40
    assert_equal 0, v.completed_pourcent
41
    assert_equal 0, v.closed_pourcent
42
  end
43
  
44
  def test_progress_should_be_0_with_unbegun_assigned_issues
45
    project = Project.find(1)
46
    v = Version.create!(:project => project, :name => 'Progress')
47
    add_issue(v)
48
    add_issue(v, :done_ratio => 0)
49
    assert_progress_equal 0, v.completed_pourcent
50
    assert_progress_equal 0, v.closed_pourcent
51
  end
52
  
53
  def test_progress_should_be_100_with_closed_assigned_issues
54
    project = Project.find(1)
55
    status = IssueStatus.find(:first, :conditions => {:is_closed => true})
56
    v = Version.create!(:project => project, :name => 'Progress')
57
    add_issue(v, :status => status)
58
    add_issue(v, :status => status, :done_ratio => 20)
59
    add_issue(v, :status => status, :done_ratio => 70, :estimated_hours => 25)
60
    add_issue(v, :status => status, :estimated_hours => 15)
61
    assert_progress_equal 100.0, v.completed_pourcent
62
    assert_progress_equal 100.0, v.closed_pourcent
63
  end
64
  
65
  def test_progress_should_consider_done_ratio_of_open_assigned_issues
66
    project = Project.find(1)
67
    v = Version.create!(:project => project, :name => 'Progress')
68
    add_issue(v)
69
    add_issue(v, :done_ratio => 20)
70
    add_issue(v, :done_ratio => 70)
71
    assert_progress_equal (0.0 + 20.0 + 70.0)/3, v.completed_pourcent
72
    assert_progress_equal 0, v.closed_pourcent
73
  end
74
  
75
  def test_progress_should_consider_closed_issues_as_completed
76
    project = Project.find(1)
77
    v = Version.create!(:project => project, :name => 'Progress')
78
    add_issue(v)
79
    add_issue(v, :done_ratio => 20)
80
    add_issue(v, :status => IssueStatus.find(:first, :conditions => {:is_closed => true}))
81
    assert_progress_equal (0.0 + 20.0 + 100.0)/3, v.completed_pourcent
82
    assert_progress_equal (100.0)/3, v.closed_pourcent
83
  end
84
  
85
  def test_progress_should_consider_estimated_hours_to_weigth_issues
86
    project = Project.find(1)
87
    v = Version.create!(:project => project, :name => 'Progress')
88
    add_issue(v, :estimated_hours => 10)
89
    add_issue(v, :estimated_hours => 20, :done_ratio => 30)
90
    add_issue(v, :estimated_hours => 40, :done_ratio => 10)
91
    add_issue(v, :estimated_hours => 25, :status => IssueStatus.find(:first, :conditions => {:is_closed => true}))
92
    assert_progress_equal (10.0*0 + 20.0*0.3 + 40*0.1 + 25.0*1)/95.0*100, v.completed_pourcent
93
    assert_progress_equal 25.0/95.0*100, v.closed_pourcent
94
  end
95
  
96
  def test_progress_should_consider_average_estimated_hours_to_weigth_unestimated_issues
97
    project = Project.find(1)
98
    v = Version.create!(:project => project, :name => 'Progress')
99
    add_issue(v, :done_ratio => 20)
100
    add_issue(v, :status => IssueStatus.find(:first, :conditions => {:is_closed => true}))
101
    add_issue(v, :estimated_hours => 10, :done_ratio => 30)
102
    add_issue(v, :estimated_hours => 40, :done_ratio => 10)
103
    assert_progress_equal (25.0*0.2 + 25.0*1 + 10.0*0.3 + 40.0*0.1)/100.0*100, v.completed_pourcent
104
    assert_progress_equal 25.0/100.0*100, v.closed_pourcent
105
  end
106
  
107
  private
108
  
109
  def add_issue(version, attributes={})
110
    Issue.create!({:project => version.project,
111
                   :fixed_version => version,
112
                   :subject => 'Test',
113
                   :author => User.find(:first),
114
                   :tracker => version.project.trackers.find(:first)}.merge(attributes))
115
  end
116
  
117
  def assert_progress_equal(expected_float, actual_float, message="")
118
    assert_in_delta(expected_float, actual_float, 0.000001, message="")
119
  end
36 120
end

Also available in: Unified diff