@@ -0,0 +1,15 | |||
|
1 | class ClearEstimatedHoursOnParentIssues < ActiveRecord::Migration | |
|
2 | def self.up | |
|
3 | # Clears estimated hours on parent issues | |
|
4 | Issue.where("rgt > lft + 1 AND estimated_hours > 0").update_all :estimated_hours => nil | |
|
5 | end | |
|
6 | ||
|
7 | def self.down | |
|
8 | table_name = Issue.table_name | |
|
9 | leaves_sum_select = "SELECT SUM(leaves.estimated_hours) FROM #{table_name} leaves" + | |
|
10 | " WHERE leaves.root_id = #{table_name}.root_id AND leaves.lft > #{table_name}.lft AND leaves.rgt < #{table_name}.rgt" + | |
|
11 | " AND leaves.rgt = leaves.lft + 1" | |
|
12 | ||
|
13 | Issue.where("rgt > lft + 1").update_all "estimated_hours = (#{leaves_sum_select})" | |
|
14 | end | |
|
15 | end |
@@ -113,6 +113,14 module IssuesHelper | |||
|
113 | 113 | s.html_safe |
|
114 | 114 | end |
|
115 | 115 | |
|
116 | def issue_estimated_hours_details(issue) | |
|
117 | s = issue.estimated_hours.present? ? l_hours(issue.estimated_hours) : "" | |
|
118 | unless issue.leaf? || issue.total_estimated_hours.nil? | |
|
119 | s << " (#{l(:label_total)}: #{l_hours(issue.total_estimated_hours)})" | |
|
120 | end | |
|
121 | s.html_safe | |
|
122 | end | |
|
123 | ||
|
116 | 124 | # Returns an array of error messages for bulk edited issues |
|
117 | 125 | def bulk_edit_error_messages(issues) |
|
118 | 126 | messages = {} |
@@ -206,6 +206,7 class Issue < ActiveRecord::Base | |||
|
206 | 206 | @assignable_versions = nil |
|
207 | 207 | @relations = nil |
|
208 | 208 | @spent_hours = nil |
|
209 | @total_estimated_hours = nil | |
|
209 | 210 | base_reload(*args) |
|
210 | 211 | end |
|
211 | 212 | |
@@ -435,9 +436,6 class Issue < ActiveRecord::Base | |||
|
435 | 436 | if done_ratio_derived? |
|
436 | 437 | names -= %w(done_ratio) |
|
437 | 438 | end |
|
438 | unless leaf? | |
|
439 | names -= %w(estimated_hours) | |
|
440 | end | |
|
441 | 439 | names |
|
442 | 440 | end |
|
443 | 441 | |
@@ -929,6 +927,14 class Issue < ActiveRecord::Base | |||
|
929 | 927 | sum("#{TimeEntry.table_name}.hours").to_f || 0.0 |
|
930 | 928 | end |
|
931 | 929 | |
|
930 | def total_estimated_hours | |
|
931 | if leaf? | |
|
932 | estimated_hours | |
|
933 | else | |
|
934 | @total_estimated_hours ||= self_and_descendants.sum(:estimated_hours) | |
|
935 | end | |
|
936 | end | |
|
937 | ||
|
932 | 938 | def relations |
|
933 | 939 | @relations ||= IssueRelation::Relations.new(self, (relations_from + relations_to).sort) |
|
934 | 940 | end |
@@ -1488,10 +1494,6 class Issue < ActiveRecord::Base | |||
|
1488 | 1494 | end |
|
1489 | 1495 | end |
|
1490 | 1496 | |
|
1491 | # estimate = sum of leaves estimates | |
|
1492 | p.estimated_hours = p.leaves.sum(:estimated_hours).to_f | |
|
1493 | p.estimated_hours = nil if p.estimated_hours == 0.0 | |
|
1494 | ||
|
1495 | 1497 | # ancestors will be recursively updated |
|
1496 | 1498 | p.save(:validate => false) |
|
1497 | 1499 | end |
@@ -83,7 +83,7 class Version < ActiveRecord::Base | |||
|
83 | 83 | # Returns the total estimated time for this version |
|
84 | 84 | # (sum of leaves estimated_hours) |
|
85 | 85 | def estimated_hours |
|
86 |
@estimated_hours ||= fixed_issues. |
|
|
86 | @estimated_hours ||= fixed_issues.sum(:estimated_hours).to_f | |
|
87 | 87 | end |
|
88 | 88 | |
|
89 | 89 | # Returns the total reported time for this version |
@@ -58,8 +58,8 | |||
|
58 | 58 | rows.right l(:field_done_ratio), progress_bar(@issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%"), :class => 'progress' |
|
59 | 59 | end |
|
60 | 60 | unless @issue.disabled_core_fields.include?('estimated_hours') |
|
61 | unless @issue.estimated_hours.nil? | |
|
62 |
rows.right l(:field_estimated_hours), |
|
|
61 | unless @issue.total_estimated_hours.nil? | |
|
62 | rows.right l(:field_estimated_hours), issue_estimated_hours_details(@issue), :class => 'estimated-hours' | |
|
63 | 63 | end |
|
64 | 64 | end |
|
65 | 65 | if User.current.allowed_to?(:view_time_entries, @project) |
@@ -287,26 +287,6 class IssueNestedSetTest < ActiveSupport::TestCase | |||
|
287 | 287 | end |
|
288 | 288 | end |
|
289 | 289 | |
|
290 | def test_parent_estimate_should_be_sum_of_leaves | |
|
291 | parent = Issue.generate! | |
|
292 | parent.generate_child!(:estimated_hours => nil) | |
|
293 | assert_equal nil, parent.reload.estimated_hours | |
|
294 | parent.generate_child!(:estimated_hours => 5) | |
|
295 | assert_equal 5, parent.reload.estimated_hours | |
|
296 | parent.generate_child!(:estimated_hours => 7) | |
|
297 | assert_equal 12, parent.reload.estimated_hours | |
|
298 | end | |
|
299 | ||
|
300 | def test_move_parent_updates_old_parent_attributes | |
|
301 | first_parent = Issue.generate! | |
|
302 | second_parent = Issue.generate! | |
|
303 | child = first_parent.generate_child!(:estimated_hours => 5) | |
|
304 | assert_equal 5, first_parent.reload.estimated_hours | |
|
305 | child.update_attributes(:estimated_hours => 7, :parent_issue_id => second_parent.id) | |
|
306 | assert_equal 7, second_parent.reload.estimated_hours | |
|
307 | assert_nil first_parent.reload.estimated_hours | |
|
308 | end | |
|
309 | ||
|
310 | 290 | def test_project_copy_should_copy_issue_tree |
|
311 | 291 | p = Project.create!(:name => 'Tree copy', :identifier => 'tree-copy', :tracker_ids => [1, 2]) |
|
312 | 292 | i1 = Issue.generate!(:project => p, :subject => 'i1') |
@@ -146,23 +146,41 class IssueSubtaskingTest < ActiveSupport::TestCase | |||
|
146 | 146 | end |
|
147 | 147 | |
|
148 | 148 | def test_done_ratio_of_parent_with_a_child_without_estimated_time_should_not_exceed_100 |
|
149 | parent = Issue.generate! | |
|
150 | parent.generate_child!(:estimated_hours => 40) | |
|
151 | parent.generate_child!(:estimated_hours => 40) | |
|
152 |
parent.generate_child!(:estimated_hours => |
|
|
153 | parent.generate_child! | |
|
154 | parent.reload.children.each(&:close!) | |
|
155 | assert_equal 100, parent.reload.done_ratio | |
|
149 | with_settings :parent_issue_done_ratio => 'derived' do | |
|
150 | parent = Issue.generate! | |
|
151 | parent.generate_child!(:estimated_hours => 40) | |
|
152 | parent.generate_child!(:estimated_hours => 40) | |
|
153 | parent.generate_child!(:estimated_hours => 20) | |
|
154 | parent.generate_child! | |
|
155 | parent.reload.children.each(&:close!) | |
|
156 | assert_equal 100, parent.reload.done_ratio | |
|
157 | end | |
|
156 | 158 | end |
|
157 | 159 | |
|
158 | 160 | def test_done_ratio_of_parent_with_a_child_with_estimated_time_at_0_should_not_exceed_100 |
|
159 | parent = Issue.generate! | |
|
160 | parent.generate_child!(:estimated_hours => 40) | |
|
161 | parent.generate_child!(:estimated_hours => 40) | |
|
162 |
parent.generate_child!(:estimated_hours => |
|
|
163 | parent.generate_child!(:estimated_hours => 0) | |
|
164 | parent.reload.children.each(&:close!) | |
|
165 | assert_equal 100, parent.reload.done_ratio | |
|
161 | with_settings :parent_issue_done_ratio => 'derived' do | |
|
162 | parent = Issue.generate! | |
|
163 | parent.generate_child!(:estimated_hours => 40) | |
|
164 | parent.generate_child!(:estimated_hours => 40) | |
|
165 | parent.generate_child!(:estimated_hours => 20) | |
|
166 | parent.generate_child!(:estimated_hours => 0) | |
|
167 | parent.reload.children.each(&:close!) | |
|
168 | assert_equal 100, parent.reload.done_ratio | |
|
169 | end | |
|
170 | end | |
|
171 | ||
|
172 | def test_changing_parent_should_update_previous_parent_done_ratio | |
|
173 | with_settings :parent_issue_done_ratio => 'derived' do | |
|
174 | first_parent = Issue.generate! | |
|
175 | second_parent = Issue.generate! | |
|
176 | first_parent.generate_child!(:done_ratio => 40) | |
|
177 | child = first_parent.generate_child!(:done_ratio => 20) | |
|
178 | assert_equal 30, first_parent.reload.done_ratio | |
|
179 | assert_equal 0, second_parent.reload.done_ratio | |
|
180 | child.update_attributes(:parent_issue_id => second_parent.id) | |
|
181 | assert_equal 40, first_parent.reload.done_ratio | |
|
182 | assert_equal 20, second_parent.reload.done_ratio | |
|
183 | end | |
|
166 | 184 | end |
|
167 | 185 | |
|
168 | 186 | def test_parent_dates_should_be_editable_with_parent_issue_dates_set_to_independent |
@@ -227,4 +245,14 class IssueSubtaskingTest < ActiveSupport::TestCase | |||
|
227 | 245 | assert_equal 0, parent.reload.done_ratio |
|
228 | 246 | end |
|
229 | 247 | end |
|
248 | ||
|
249 | def test_parent_total_estimated_hours_should_be_sum_of_descendants | |
|
250 | parent = Issue.generate! | |
|
251 | parent.generate_child!(:estimated_hours => nil) | |
|
252 | assert_equal 0, parent.reload.total_estimated_hours | |
|
253 | parent.generate_child!(:estimated_hours => 5) | |
|
254 | assert_equal 5, parent.reload.total_estimated_hours | |
|
255 | parent.generate_child!(:estimated_hours => 7) | |
|
256 | assert_equal 12, parent.reload.total_estimated_hours | |
|
257 | end | |
|
230 | 258 | end |
General Comments 0
You need to be logged in to leave comments.
Login now