Project

General

Profile

Defect #23511

Updated by Toshi MARUYAMA over 7 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>

Back