Project

General

Profile

Patch #27676 » 0001-Moves-issue-calculations-into-the-fixed_issues-relat.patch

Jan from Planio www.plan.io, 2017-11-29 17:24

View differences:

app/models/version.rb
23 23
  before_destroy :nullify_projects_default_version
24 24

  
25 25
  belongs_to :project
26
  has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id', :dependent => :nullify
26
  has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id', :dependent => :nullify do
27
    # Returns the total estimated time for this version
28
    # (sum of leaves estimated_hours)
29
    def estimated_hours
30
      @estimated_hours ||= sum(:estimated_hours).to_f
31
    end
32
    #
33
    # Returns the total amount of open issues for this version.
34
    def open_count
35
      load_counts
36
      @open_count
37
    end
38

  
39
    # Returns the total amount of closed issues for this version.
40
    def closed_count
41
      load_counts
42
      @closed_count
43
    end
44

  
45
    # Returns the completion percentage of this version based on the amount of open/closed issues
46
    # and the time spent on the open issues.
47
    def completed_percent
48
      if count == 0
49
        0
50
      elsif open_count == 0
51
        100
52
      else
53
        issues_progress(false) + issues_progress(true)
54
      end
55
    end
56

  
57
    # Returns the percentage of issues that have been marked as 'closed'.
58
    def closed_percent
59
      if count == 0
60
        0
61
      else
62
        issues_progress(false)
63
      end
64
    end
65

  
66
    private
67

  
68
    def load_counts
69
      unless @open_count
70
        @open_count = 0
71
        @closed_count = 0
72
        self.group(:status).count.each do |status, count|
73
          if status.is_closed?
74
            @closed_count += count
75
          else
76
            @open_count += count
77
          end
78
        end
79
      end
80
    end
81

  
82
    # Returns the average estimated time of assigned issues
83
    # or 1 if no issue has an estimated time
84
    # Used to weight unestimated issues in progress calculation
85
    def estimated_average
86
      if @estimated_average.nil?
87
        average = average(:estimated_hours).to_f
88
        if average == 0
89
          average = 1
90
        end
91
        @estimated_average = average
92
      end
93
      @estimated_average
94
    end
95

  
96
    # Returns the total progress of open or closed issues.  The returned percentage takes into account
97
    # the amount of estimated time set for this version.
98
    #
99
    # Examples:
100
    # issues_progress(true)   => returns the progress percentage for open issues.
101
    # issues_progress(false)  => returns the progress percentage for closed issues.
102
    def issues_progress(open)
103
      @issues_progress ||= {}
104
      @issues_progress[open] ||= begin
105
        progress = 0
106
        if count > 0
107
          ratio = open ? 'done_ratio' : 100
108

  
109
          done = open(open).sum("COALESCE(estimated_hours, #{estimated_average}) * #{ratio}").to_f
110
          progress = done / (estimated_average * count)
111
        end
112
        progress
113
      end
114
    end
115
  end
116

  
27 117
  acts_as_customizable
28 118
  acts_as_attachable :view_permission => :view_files,
29 119
                     :edit_permission => :manage_files,
......
104 194
  # Returns the total estimated time for this version
105 195
  # (sum of leaves estimated_hours)
106 196
  def estimated_hours
107
    @estimated_hours ||= fixed_issues.sum(:estimated_hours).to_f
197
    fixed_issues.estimated_hours
108 198
  end
109 199

  
110 200
  # Returns the total reported time for this version
......
139 229
  # Returns the completion percentage of this version based on the amount of open/closed issues
140 230
  # and the time spent on the open issues.
141 231
  def completed_percent
142
    if issues_count == 0
143
      0
144
    elsif open_issues_count == 0
145
      100
146
    else
147
      issues_progress(false) + issues_progress(true)
148
    end
232
    fixed_issues.completed_percent
149 233
  end
150 234

  
151 235
  # Returns the percentage of issues that have been marked as 'closed'.
152 236
  def closed_percent
153
    if issues_count == 0
154
      0
155
    else
156
      issues_progress(false)
157
    end
237
    fixed_issues.closed_percent
158 238
  end
159 239

  
160 240
  # Returns true if the version is overdue: due date reached and some open issues
......
164 244

  
165 245
  # Returns assigned issues count
166 246
  def issues_count
167
    load_issue_counts
168
    @issue_count
247
    fixed_issues.count
169 248
  end
170 249

  
171 250
  # Returns the total amount of open issues for this version.
172 251
  def open_issues_count
173
    load_issue_counts
174
    @open_issues_count
252
    fixed_issues.open_count
175 253
  end
176 254

  
177 255
  # Returns the total amount of closed issues for this version.
178 256
  def closed_issues_count
179
    load_issue_counts
180
    @closed_issues_count
257
    fixed_issues.closed_count
181 258
  end
182 259

  
183 260
  def wiki_page
......
284 361

  
285 362
  private
286 363

  
287
  def load_issue_counts
288
    unless @issue_count
289
      @open_issues_count = 0
290
      @closed_issues_count = 0
291
      fixed_issues.group(:status).count.each do |status, count|
292
        if status.is_closed?
293
          @closed_issues_count += count
294
        else
295
          @open_issues_count += count
296
        end
297
      end
298
      @issue_count = @open_issues_count + @closed_issues_count
299
    end
300
  end
301

  
302 364
  # Update the issue's fixed versions. Used if a version's sharing changes.
303 365
  def update_issues_from_sharing_change
304 366
    if saved_change_to_sharing?
......
316 378
    end
317 379
  end
318 380

  
319
  # Returns the average estimated time of assigned issues
320
  # or 1 if no issue has an estimated time
321
  # Used to weight unestimated issues in progress calculation
322
  def estimated_average
323
    if @estimated_average.nil?
324
      average = fixed_issues.average(:estimated_hours).to_f
325
      if average == 0
326
        average = 1
327
      end
328
      @estimated_average = average
329
    end
330
    @estimated_average
331
  end
332

  
333
  # Returns the total progress of open or closed issues.  The returned percentage takes into account
334
  # the amount of estimated time set for this version.
335
  #
336
  # Examples:
337
  # issues_progress(true)   => returns the progress percentage for open issues.
338
  # issues_progress(false)  => returns the progress percentage for closed issues.
339
  def issues_progress(open)
340
    @issues_progress ||= {}
341
    @issues_progress[open] ||= begin
342
      progress = 0
343
      if issues_count > 0
344
        ratio = open ? 'done_ratio' : 100
345

  
346
        done = fixed_issues.open(open).sum("COALESCE(estimated_hours, #{estimated_average}) * #{ratio}").to_f
347
        progress = done / (estimated_average * issues_count)
348
      end
349
      progress
350
    end
351
  end
352

  
353 381
  def referenced_by_a_custom_field?
354 382
    CustomValue.joins(:custom_field).
355 383
      where(:value => id.to_s, :custom_fields => {:field_format => 'version'}).any?
(4-4/4)