@@ -149,6 +149,15 module SettingsHelper | |||||
149 | options.map {|label, value| [l(label), value.to_s]} |
|
149 | options.map {|label, value| [l(label), value.to_s]} | |
150 | end |
|
150 | end | |
151 |
|
151 | |||
|
152 | def parent_issue_done_ratio_options | |||
|
153 | options = [ | |||
|
154 | [:label_parent_task_attributes_derived, 'derived'], | |||
|
155 | [:label_parent_task_attributes_independent, 'independent'] | |||
|
156 | ] | |||
|
157 | ||||
|
158 | options.map {|label, value| [l(label), value.to_s]} | |||
|
159 | end | |||
|
160 | ||||
152 | # Returns the options for the date_format setting |
|
161 | # Returns the options for the date_format setting | |
153 | def date_format_setting_options(locale) |
|
162 | def date_format_setting_options(locale) | |
154 | Setting::DATE_FORMATS.map do |f| |
|
163 | Setting::DATE_FORMATS.map do |f| |
@@ -432,8 +432,11 class Issue < ActiveRecord::Base | |||||
432 | if priority_derived? |
|
432 | if priority_derived? | |
433 | names -= %w(priority_id) |
|
433 | names -= %w(priority_id) | |
434 | end |
|
434 | end | |
|
435 | if done_ratio_derived? | |||
|
436 | names -= %w(done_ratio) | |||
|
437 | end | |||
435 | unless leaf? |
|
438 | unless leaf? | |
436 |
names -= %w( |
|
439 | names -= %w(estimated_hours) | |
437 | end |
|
440 | end | |
438 | names |
|
441 | names | |
439 | end |
|
442 | end | |
@@ -1161,6 +1164,10 class Issue < ActiveRecord::Base | |||||
1161 | !leaf? && Setting.parent_issue_priority == 'derived' |
|
1164 | !leaf? && Setting.parent_issue_priority == 'derived' | |
1162 | end |
|
1165 | end | |
1163 |
|
1166 | |||
|
1167 | def done_ratio_derived? | |||
|
1168 | !leaf? && Setting.parent_issue_done_ratio == 'derived' | |||
|
1169 | end | |||
|
1170 | ||||
1164 | def <=>(issue) |
|
1171 | def <=>(issue) | |
1165 | if issue.nil? |
|
1172 | if issue.nil? | |
1166 | -1 |
|
1173 | -1 | |
@@ -1463,19 +1470,21 class Issue < ActiveRecord::Base | |||||
1463 | end |
|
1470 | end | |
1464 | end |
|
1471 | end | |
1465 |
|
1472 | |||
1466 | # done ratio = weighted average ratio of leaves |
|
1473 | if p.done_ratio_derived? | |
1467 | unless Issue.use_status_for_done_ratio? && p.status && p.status.default_done_ratio |
|
1474 | # done ratio = weighted average ratio of leaves | |
1468 | leaves_count = p.leaves.count |
|
1475 | unless Issue.use_status_for_done_ratio? && p.status && p.status.default_done_ratio | |
1469 |
|
|
1476 | leaves_count = p.leaves.count | |
1470 | average = p.leaves.where("estimated_hours > 0").average(:estimated_hours).to_f |
|
1477 | if leaves_count > 0 | |
1471 | if average == 0 |
|
1478 | average = p.leaves.where("estimated_hours > 0").average(:estimated_hours).to_f | |
1472 |
average = |
|
1479 | if average == 0 | |
|
1480 | average = 1 | |||
|
1481 | end | |||
|
1482 | done = p.leaves.joins(:status). | |||
|
1483 | sum("COALESCE(CASE WHEN estimated_hours > 0 THEN estimated_hours ELSE NULL END, #{average}) " + | |||
|
1484 | "* (CASE WHEN is_closed = #{self.class.connection.quoted_true} THEN 100 ELSE COALESCE(done_ratio, 0) END)").to_f | |||
|
1485 | progress = done / (average * leaves_count) | |||
|
1486 | p.done_ratio = progress.round | |||
1473 | end |
|
1487 | end | |
1474 | done = p.leaves.joins(:status). |
|
|||
1475 | sum("COALESCE(CASE WHEN estimated_hours > 0 THEN estimated_hours ELSE NULL END, #{average}) " + |
|
|||
1476 | "* (CASE WHEN is_closed = #{self.class.connection.quoted_true} THEN 100 ELSE COALESCE(done_ratio, 0) END)").to_f |
|
|||
1477 | progress = done / (average * leaves_count) |
|
|||
1478 | p.done_ratio = progress.round |
|
|||
1479 | end |
|
1488 | end | |
1480 | end |
|
1489 | end | |
1481 |
|
1490 |
@@ -28,6 +28,8 | |||||
28 | <p><%= setting_select :parent_issue_dates, parent_issue_dates_options, :label => "#{l(:field_start_date)} / #{l(:field_due_date)}" %></p> |
|
28 | <p><%= setting_select :parent_issue_dates, parent_issue_dates_options, :label => "#{l(:field_start_date)} / #{l(:field_due_date)}" %></p> | |
29 |
|
29 | |||
30 | <p><%= setting_select :parent_issue_priority, parent_issue_priority_options, :label => :field_priority %></p> |
|
30 | <p><%= setting_select :parent_issue_priority, parent_issue_priority_options, :label => :field_priority %></p> | |
|
31 | ||||
|
32 | <p><%= setting_select :parent_issue_done_ratio, parent_issue_done_ratio_options, :label => :field_done_ratio %></p> | |||
31 | </div> |
|
33 | </div> | |
32 | </fieldset> |
|
34 | </fieldset> | |
33 |
|
35 |
@@ -150,6 +150,8 parent_issue_dates: | |||||
150 | default: 'derived' |
|
150 | default: 'derived' | |
151 | parent_issue_priority: |
|
151 | parent_issue_priority: | |
152 | default: 'derived' |
|
152 | default: 'derived' | |
|
153 | parent_issue_done_ratio: | |||
|
154 | default: 'derived' | |||
153 | link_copied_issue: |
|
155 | link_copied_issue: | |
154 | default: 'ask' |
|
156 | default: 'ask' | |
155 | issue_group_assignment: |
|
157 | issue_group_assignment: |
@@ -287,40 +287,6 class IssueNestedSetTest < ActiveSupport::TestCase | |||||
287 | end |
|
287 | end | |
288 | end |
|
288 | end | |
289 |
|
289 | |||
290 | def test_parent_done_ratio_should_be_average_done_ratio_of_leaves |
|
|||
291 | parent = Issue.generate! |
|
|||
292 | parent.generate_child!(:done_ratio => 20) |
|
|||
293 | assert_equal 20, parent.reload.done_ratio |
|
|||
294 | parent.generate_child!(:done_ratio => 70) |
|
|||
295 | assert_equal 45, parent.reload.done_ratio |
|
|||
296 |
|
||||
297 | child = parent.generate_child!(:done_ratio => 0) |
|
|||
298 | assert_equal 30, parent.reload.done_ratio |
|
|||
299 |
|
||||
300 | child.generate_child!(:done_ratio => 30) |
|
|||
301 | assert_equal 30, child.reload.done_ratio |
|
|||
302 | assert_equal 40, parent.reload.done_ratio |
|
|||
303 | end |
|
|||
304 |
|
||||
305 | def test_parent_done_ratio_should_be_weighted_by_estimated_times_if_any |
|
|||
306 | parent = Issue.generate! |
|
|||
307 | parent.generate_child!(:estimated_hours => 10, :done_ratio => 20) |
|
|||
308 | assert_equal 20, parent.reload.done_ratio |
|
|||
309 | parent.generate_child!(:estimated_hours => 20, :done_ratio => 50) |
|
|||
310 | assert_equal (50 * 20 + 20 * 10) / 30, parent.reload.done_ratio |
|
|||
311 | end |
|
|||
312 |
|
||||
313 | def test_parent_done_ratio_with_child_estimate_to_0_should_reach_100 |
|
|||
314 | parent = Issue.generate! |
|
|||
315 | issue1 = parent.generate_child! |
|
|||
316 | issue2 = parent.generate_child!(:estimated_hours => 0) |
|
|||
317 | assert_equal 0, parent.reload.done_ratio |
|
|||
318 | issue1.reload.close! |
|
|||
319 | assert_equal 50, parent.reload.done_ratio |
|
|||
320 | issue2.reload.close! |
|
|||
321 | assert_equal 100, parent.reload.done_ratio |
|
|||
322 | end |
|
|||
323 |
|
||||
324 | def test_parent_estimate_should_be_sum_of_leaves |
|
290 | def test_parent_estimate_should_be_sum_of_leaves | |
325 | parent = Issue.generate! |
|
291 | parent = Issue.generate! | |
326 | parent.generate_child!(:estimated_hours => nil) |
|
292 | parent.generate_child!(:estimated_hours => nil) |
@@ -97,6 +97,54 class IssueSubtaskingTest < ActiveSupport::TestCase | |||||
97 | end |
|
97 | end | |
98 | end |
|
98 | end | |
99 |
|
99 | |||
|
100 | def test_parent_done_ratio_should_be_read_only_with_parent_issue_done_ratio_set_to_derived | |||
|
101 | with_settings :parent_issue_done_ratio => 'derived' do | |||
|
102 | issue = Issue.generate_with_child! | |||
|
103 | user = User.find(1) | |||
|
104 | assert !issue.safe_attribute?('done_ratio', user) | |||
|
105 | end | |||
|
106 | end | |||
|
107 | ||||
|
108 | def test_parent_done_ratio_should_be_average_done_ratio_of_leaves | |||
|
109 | with_settings :parent_issue_done_ratio => 'derived' do | |||
|
110 | parent = Issue.generate! | |||
|
111 | parent.generate_child!(:done_ratio => 20) | |||
|
112 | assert_equal 20, parent.reload.done_ratio | |||
|
113 | parent.generate_child!(:done_ratio => 70) | |||
|
114 | assert_equal 45, parent.reload.done_ratio | |||
|
115 | ||||
|
116 | child = parent.generate_child!(:done_ratio => 0) | |||
|
117 | assert_equal 30, parent.reload.done_ratio | |||
|
118 | ||||
|
119 | child.generate_child!(:done_ratio => 30) | |||
|
120 | assert_equal 30, child.reload.done_ratio | |||
|
121 | assert_equal 40, parent.reload.done_ratio | |||
|
122 | end | |||
|
123 | end | |||
|
124 | ||||
|
125 | def test_parent_done_ratio_should_be_weighted_by_estimated_times_if_any | |||
|
126 | with_settings :parent_issue_done_ratio => 'derived' do | |||
|
127 | parent = Issue.generate! | |||
|
128 | parent.generate_child!(:estimated_hours => 10, :done_ratio => 20) | |||
|
129 | assert_equal 20, parent.reload.done_ratio | |||
|
130 | parent.generate_child!(:estimated_hours => 20, :done_ratio => 50) | |||
|
131 | assert_equal (50 * 20 + 20 * 10) / 30, parent.reload.done_ratio | |||
|
132 | end | |||
|
133 | end | |||
|
134 | ||||
|
135 | def test_parent_done_ratio_with_child_estimate_to_0_should_reach_100 | |||
|
136 | with_settings :parent_issue_done_ratio => 'derived' do | |||
|
137 | parent = Issue.generate! | |||
|
138 | issue1 = parent.generate_child! | |||
|
139 | issue2 = parent.generate_child!(:estimated_hours => 0) | |||
|
140 | assert_equal 0, parent.reload.done_ratio | |||
|
141 | issue1.reload.close! | |||
|
142 | assert_equal 50, parent.reload.done_ratio | |||
|
143 | issue2.reload.close! | |||
|
144 | assert_equal 100, parent.reload.done_ratio | |||
|
145 | end | |||
|
146 | end | |||
|
147 | ||||
100 | def test_parent_dates_should_be_editable_with_parent_issue_dates_set_to_independent |
|
148 | def test_parent_dates_should_be_editable_with_parent_issue_dates_set_to_independent | |
101 | with_settings :parent_issue_dates => 'independent' do |
|
149 | with_settings :parent_issue_dates => 'independent' do | |
102 | issue = Issue.generate_with_child! |
|
150 | issue = Issue.generate_with_child! | |
@@ -143,4 +191,20 class IssueSubtaskingTest < ActiveSupport::TestCase | |||||
143 | assert_equal 'Normal', parent.reload.priority.name |
|
191 | assert_equal 'Normal', parent.reload.priority.name | |
144 | end |
|
192 | end | |
145 | end |
|
193 | end | |
|
194 | ||||
|
195 | def test_parent_done_ratio_should_be_editable_with_parent_issue_done_ratio_set_to_independent | |||
|
196 | with_settings :parent_issue_done_ratio => 'independent' do | |||
|
197 | issue = Issue.generate_with_child! | |||
|
198 | user = User.find(1) | |||
|
199 | assert issue.safe_attribute?('done_ratio', user) | |||
|
200 | end | |||
|
201 | end | |||
|
202 | ||||
|
203 | def test_parent_done_ratio_should_not_be_updated_with_parent_issue_done_ratio_set_to_independent | |||
|
204 | with_settings :parent_issue_done_ratio => 'independent' do | |||
|
205 | parent = Issue.generate!(:done_ratio => 0) | |||
|
206 | child1 = parent.generate_child!(:done_ratio => 10) | |||
|
207 | assert_equal 0, parent.reload.done_ratio | |||
|
208 | end | |||
|
209 | end | |||
146 | end |
|
210 | end |
General Comments 0
You need to be logged in to leave comments.
Login now