Mercurial > hg > soundsoftware-site
comparison app/models/version.rb @ 1338:25603efa57b5
Merge from live branch
author | Chris Cannam |
---|---|
date | Thu, 20 Jun 2013 13:14:14 +0100 |
parents | 433d4f72a19b |
children | 622f24f53b42 261b3d9a4903 |
comparison
equal
deleted
inserted
replaced
1209:1b1138f6f55e | 1338:25603efa57b5 |
---|---|
1 # Redmine - project management software | 1 # Redmine - project management software |
2 # Copyright (C) 2006-2011 Jean-Philippe Lang | 2 # Copyright (C) 2006-2012 Jean-Philippe Lang |
3 # | 3 # |
4 # This program is free software; you can redistribute it and/or | 4 # This program is free software; you can redistribute it and/or |
5 # modify it under the terms of the GNU General Public License | 5 # modify it under the terms of the GNU General Public License |
6 # as published by the Free Software Foundation; either version 2 | 6 # as published by the Free Software Foundation; either version 2 |
7 # of the License, or (at your option) any later version. | 7 # of the License, or (at your option) any later version. |
31 validates_uniqueness_of :name, :scope => [:project_id] | 31 validates_uniqueness_of :name, :scope => [:project_id] |
32 validates_length_of :name, :maximum => 60 | 32 validates_length_of :name, :maximum => 60 |
33 validates_format_of :effective_date, :with => /^\d{4}-\d{2}-\d{2}$/, :message => :not_a_date, :allow_nil => true | 33 validates_format_of :effective_date, :with => /^\d{4}-\d{2}-\d{2}$/, :message => :not_a_date, :allow_nil => true |
34 validates_inclusion_of :status, :in => VERSION_STATUSES | 34 validates_inclusion_of :status, :in => VERSION_STATUSES |
35 validates_inclusion_of :sharing, :in => VERSION_SHARINGS | 35 validates_inclusion_of :sharing, :in => VERSION_SHARINGS |
36 | 36 validate :validate_version |
37 named_scope :named, lambda {|arg| { :conditions => ["LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip]}} | 37 |
38 named_scope :open, :conditions => {:status => 'open'} | 38 scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)} |
39 named_scope :visible, lambda {|*args| { :include => :project, | 39 scope :open, where(:status => 'open') |
40 :conditions => Project.allowed_to_condition(args.first || User.current, :view_issues) } } | 40 scope :visible, lambda {|*args| |
41 includes(:project).where(Project.allowed_to_condition(args.first || User.current, :view_issues)) | |
42 } | |
41 | 43 |
42 safe_attributes 'name', | 44 safe_attributes 'name', |
43 'description', | 45 'description', |
44 'effective_date', | 46 'effective_date', |
45 'due_date', | 47 'due_date', |
76 @estimated_hours ||= fixed_issues.leaves.sum(:estimated_hours).to_f | 78 @estimated_hours ||= fixed_issues.leaves.sum(:estimated_hours).to_f |
77 end | 79 end |
78 | 80 |
79 # Returns the total reported time for this version | 81 # Returns the total reported time for this version |
80 def spent_hours | 82 def spent_hours |
81 @spent_hours ||= TimeEntry.sum(:hours, :include => :issue, :conditions => ["#{Issue.table_name}.fixed_version_id = ?", id]).to_f | 83 @spent_hours ||= TimeEntry.joins(:issue).where("#{Issue.table_name}.fixed_version_id = ?", id).sum(:hours).to_f |
82 end | 84 end |
83 | 85 |
84 def closed? | 86 def closed? |
85 status == 'closed' | 87 status == 'closed' |
86 end | 88 end |
89 status == 'open' | 91 status == 'open' |
90 end | 92 end |
91 | 93 |
92 # Returns true if the version is completed: due date reached and no open issues | 94 # Returns true if the version is completed: due date reached and no open issues |
93 def completed? | 95 def completed? |
94 effective_date && (effective_date <= Date.today) && (open_issues_count == 0) | 96 effective_date && (effective_date < Date.today) && (open_issues_count == 0) |
95 end | 97 end |
96 | 98 |
97 def behind_schedule? | 99 def behind_schedule? |
98 if completed_pourcent == 100 | 100 if completed_pourcent == 100 |
99 return false | 101 return false |
131 effective_date && (effective_date < Date.today) && (open_issues_count > 0) | 133 effective_date && (effective_date < Date.today) && (open_issues_count > 0) |
132 end | 134 end |
133 | 135 |
134 # Returns assigned issues count | 136 # Returns assigned issues count |
135 def issues_count | 137 def issues_count |
136 @issue_count ||= fixed_issues.count | 138 load_issue_counts |
139 @issue_count | |
137 end | 140 end |
138 | 141 |
139 # Returns the total amount of open issues for this version. | 142 # Returns the total amount of open issues for this version. |
140 def open_issues_count | 143 def open_issues_count |
141 @open_issues_count ||= Issue.count(:all, :conditions => ["fixed_version_id = ? AND is_closed = ?", self.id, false], :include => :status) | 144 load_issue_counts |
145 @open_issues_count | |
142 end | 146 end |
143 | 147 |
144 # Returns the total amount of closed issues for this version. | 148 # Returns the total amount of closed issues for this version. |
145 def closed_issues_count | 149 def closed_issues_count |
146 @closed_issues_count ||= Issue.count(:all, :conditions => ["fixed_version_id = ? AND is_closed = ?", self.id, true], :include => :status) | 150 load_issue_counts |
151 @closed_issues_count | |
147 end | 152 end |
148 | 153 |
149 def wiki_page | 154 def wiki_page |
150 if project.wiki && !wiki_page_title.blank? | 155 if project.wiki && !wiki_page_title.blank? |
151 @wiki_page ||= project.wiki.find_page(wiki_page_title) | 156 @wiki_page ||= project.wiki.find_page(wiki_page_title) |
157 | 162 |
158 def to_s_with_project | 163 def to_s_with_project |
159 "#{project} - #{name}" | 164 "#{project} - #{name}" |
160 end | 165 end |
161 | 166 |
162 # Versions are sorted by effective_date and "Project Name - Version name" | 167 # Versions are sorted by effective_date and name |
163 # Those with no effective_date are at the end, sorted by "Project Name - Version name" | 168 # Those with no effective_date are at the end, sorted by name |
164 def <=>(version) | 169 def <=>(version) |
165 if self.effective_date | 170 if self.effective_date |
166 if version.effective_date | 171 if version.effective_date |
167 if self.effective_date == version.effective_date | 172 if self.effective_date == version.effective_date |
168 "#{self.project.name} - #{self.name}" <=> "#{version.project.name} - #{version.name}" | 173 name == version.name ? id <=> version.id : name <=> version.name |
169 else | 174 else |
170 self.effective_date <=> version.effective_date | 175 self.effective_date <=> version.effective_date |
171 end | 176 end |
172 else | 177 else |
173 -1 | 178 -1 |
174 end | 179 end |
175 else | 180 else |
176 if version.effective_date | 181 if version.effective_date |
177 1 | 182 1 |
178 else | 183 else |
179 "#{self.project.name} - #{self.name}" <=> "#{version.project.name} - #{version.name}" | 184 name == version.name ? id <=> version.id : name <=> version.name |
180 end | 185 end |
181 end | 186 end |
182 end | 187 end |
188 | |
189 def self.fields_for_order_statement(table=nil) | |
190 table ||= table_name | |
191 ["(CASE WHEN #{table}.effective_date IS NULL THEN 1 ELSE 0 END)", "#{table}.effective_date", "#{table}.name", "#{table}.id"] | |
192 end | |
193 | |
194 scope :sorted, order(fields_for_order_statement) | |
183 | 195 |
184 # Returns the sharings that +user+ can set the version to | 196 # Returns the sharings that +user+ can set the version to |
185 def allowed_sharings(user = User.current) | 197 def allowed_sharings(user = User.current) |
186 VERSION_SHARINGS.select do |s| | 198 VERSION_SHARINGS.select do |s| |
187 if sharing == s | 199 if sharing == s |
202 end | 214 end |
203 end | 215 end |
204 | 216 |
205 private | 217 private |
206 | 218 |
219 def load_issue_counts | |
220 unless @issue_count | |
221 @open_issues_count = 0 | |
222 @closed_issues_count = 0 | |
223 fixed_issues.count(:all, :group => :status).each do |status, count| | |
224 if status.is_closed? | |
225 @closed_issues_count += count | |
226 else | |
227 @open_issues_count += count | |
228 end | |
229 end | |
230 @issue_count = @open_issues_count + @closed_issues_count | |
231 end | |
232 end | |
233 | |
207 # Update the issue's fixed versions. Used if a version's sharing changes. | 234 # Update the issue's fixed versions. Used if a version's sharing changes. |
208 def update_issues_from_sharing_change | 235 def update_issues_from_sharing_change |
209 if sharing_changed? | 236 if sharing_changed? |
210 if VERSION_SHARINGS.index(sharing_was).nil? || | 237 if VERSION_SHARINGS.index(sharing_was).nil? || |
211 VERSION_SHARINGS.index(sharing).nil? || | 238 VERSION_SHARINGS.index(sharing).nil? || |
240 @issues_progress[open] ||= begin | 267 @issues_progress[open] ||= begin |
241 progress = 0 | 268 progress = 0 |
242 if issues_count > 0 | 269 if issues_count > 0 |
243 ratio = open ? 'done_ratio' : 100 | 270 ratio = open ? 'done_ratio' : 100 |
244 | 271 |
245 done = fixed_issues.sum("COALESCE(estimated_hours, #{estimated_average}) * #{ratio}", | 272 done = fixed_issues.open(open).sum("COALESCE(estimated_hours, #{estimated_average}) * #{ratio}").to_f |
246 :include => :status, | |
247 :conditions => ["is_closed = ?", !open]).to_f | |
248 progress = done / (estimated_average * issues_count) | 273 progress = done / (estimated_average * issues_count) |
249 end | 274 end |
250 progress | 275 progress |
251 end | 276 end |
252 end | 277 end |
278 | |
279 def validate_version | |
280 if effective_date.nil? && @attributes['effective_date'].present? | |
281 errors.add :effective_date, :not_a_date | |
282 end | |
283 end | |
253 end | 284 end |