Defect #23511
Updated by Toshi MARUYAMA over 8 years ago
Problem of calculating the percentage of completion of a Issue(see the attached file). When "child" has "sub-child": estimated_hours is nil, therefore is not accounted in "average" (line 1534). Issue.total_estimated_hours has to be accounted in this estimate. app/model/issue.rb: <pre><code class="ruby"> 1511 def recalculate_attributes_for(issue_id) 1512 if issue_id && p = Issue.find_by_id(issue_id) 1513 if p.priority_derived? 1514 # priority = highest priority of children 1515 if priority_position = p.children.joins(:priority).maximum("#{IssuePriority.table_name}.position") 1516 p.priority = IssuePriority.find_by_position(priority_position) 1517 end 1518 end 1519 1520 if p.dates_derived? 1521 # start/due dates = lowest/highest dates of children 1522 p.start_date = p.children.minimum(:start_date) 1523 p.due_date = p.children.maximum(:due_date) 1524 if p.start_date && p.due_date && p.due_date < p.start_date 1525 p.start_date, p.due_date = p.due_date, p.start_date 1526 end 1527 end 1528 1529 if p.done_ratio_derived? 1530 # done ratio = weighted average ratio of leaves 1531 unless Issue.use_status_for_done_ratio? && p.status && p.status.default_done_ratio 1532 child_count = p.children.count 1533 if child_count > 0 1534 average = p.children.where("estimated_hours > 0").average(:estimated_hours).to_f 1535 if average == 0 1536 average = 1 1537 end 1538 done = p.children.joins(:status). 1539 sum("COALESCE(CASE WHEN estimated_hours > 0 THEN estimated_hours ELSE NULL END, #{average}) " + 1540 "* (CASE WHEN is_closed = #{self.class.connection.quoted_true} THEN 100 ELSE COALESCE(done_ratio, 0) END)").to_f 1541 progress = done / (average * child_count) 1542 p.done_ratio = progress.round 1543 end 1544 end 1545 end 1546 1547 # ancestors will be recursively updated 1548 p.save(:validate => false) 1549 end 1550 end </code></pre> Possible Fix: <pre><code class="diff"> --- issue.rb.ori 2016-08-01 11:44:53.220332666 -0400 +++ issue.rb 2016-08-01 11:45:07.395332666 -0400 @@ -1531,13 +1531,12 @@ unless Issue.use_status_for_done_ratio? && p.status && p.status.default_done_ratio child_count = p.children.count if child_count > 0 - average = p.children.where("estimated_hours > 0").average(:estimated_hours).to_f + average = p.total_estimated_hours / child_count if average == 0 average = 1 end - done = p.children.joins(:status). - sum("COALESCE(CASE WHEN estimated_hours > 0 THEN estimated_hours ELSE NULL END, #{average}) " + - "* (CASE WHEN is_closed = #{self.class.connection.quoted_true} THEN 100 ELSE COALESCE(done_ratio, 0) END)").to_f + done = 0 + p.children.each { |c| done += (c.total_estimated_hours * c.done_ratio) } progress = done / (average * child_count) p.done_ratio = progress.round end </code></pre> ************** When one manually enter the estimated time. In the original program, based on the average of other tasks to calculate progress. I keep the same approach in the patch : <pre><code class="diff"> --- issue.rb.ori 2016-08-01 11:44:53.220332666 -0400 +++ issue.rb 2016-08-01 13:42:18.138330460 -0400 @@ -1531,13 +1531,19 @@ unless Issue.use_status_for_done_ratio? && p.status && p.status.default_done_ratio child_count = p.children.count if child_count > 0 - average = p.children.where("estimated_hours > 0").average(:estimated_hours).to_f + average = (p.total_estimated_hours||=0) / child_count if average == 0 average = 1 end - done = p.children.joins(:status). - sum("COALESCE(CASE WHEN estimated_hours > 0 THEN estimated_hours ELSE NULL END, #{average}) " + - "* (CASE WHEN is_closed = #{self.class.connection.quoted_true} THEN 100 ELSE COALESCE(done_ratio, 0) END)").to_f + done = 0 + p.children.each do |c| + dr = c.closed_on.nil? ? (c.done_ratio||=0) : 100 + unless c.total_estimated_hours.nil? || c.total_estimated_hours == 0 + done += (c.total_estimated_hours * c.done_ratio) + else + done += average * c.done_ratio + end + end progress = done / (average * child_count) p.done_ratio = progress.round end </code></pre>