Mercurial > hg > soundsoftware-site
comparison app/models/.svn/text-base/version.rb.svn-base @ 0:513646585e45
* Import Redmine trunk SVN rev 3859
author | Chris Cannam |
---|---|
date | Fri, 23 Jul 2010 15:52:44 +0100 |
parents | |
children | 40f7cfd4df19 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:513646585e45 |
---|---|
1 # Redmine - project management software | |
2 # Copyright (C) 2006-2010 Jean-Philippe Lang | |
3 # | |
4 # This program is free software; you can redistribute it and/or | |
5 # modify it under the terms of the GNU General Public License | |
6 # as published by the Free Software Foundation; either version 2 | |
7 # of the License, or (at your option) any later version. | |
8 # | |
9 # This program is distributed in the hope that it will be useful, | |
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 # GNU General Public License for more details. | |
13 # | |
14 # You should have received a copy of the GNU General Public License | |
15 # along with this program; if not, write to the Free Software | |
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 | |
18 class Version < ActiveRecord::Base | |
19 after_update :update_issues_from_sharing_change | |
20 belongs_to :project | |
21 has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id', :dependent => :nullify | |
22 acts_as_customizable | |
23 acts_as_attachable :view_permission => :view_files, | |
24 :delete_permission => :manage_files | |
25 | |
26 VERSION_STATUSES = %w(open locked closed) | |
27 VERSION_SHARINGS = %w(none descendants hierarchy tree system) | |
28 | |
29 validates_presence_of :name | |
30 validates_uniqueness_of :name, :scope => [:project_id] | |
31 validates_length_of :name, :maximum => 60 | |
32 validates_format_of :effective_date, :with => /^\d{4}-\d{2}-\d{2}$/, :message => :not_a_date, :allow_nil => true | |
33 validates_inclusion_of :status, :in => VERSION_STATUSES | |
34 validates_inclusion_of :sharing, :in => VERSION_SHARINGS | |
35 | |
36 named_scope :open, :conditions => {:status => 'open'} | |
37 named_scope :visible, lambda {|*args| { :include => :project, | |
38 :conditions => Project.allowed_to_condition(args.first || User.current, :view_issues) } } | |
39 | |
40 # Returns true if +user+ or current user is allowed to view the version | |
41 def visible?(user=User.current) | |
42 user.allowed_to?(:view_issues, self.project) | |
43 end | |
44 | |
45 def start_date | |
46 effective_date | |
47 end | |
48 | |
49 def due_date | |
50 effective_date | |
51 end | |
52 | |
53 # Returns the total estimated time for this version | |
54 # (sum of leaves estimated_hours) | |
55 def estimated_hours | |
56 @estimated_hours ||= fixed_issues.leaves.sum(:estimated_hours).to_f | |
57 end | |
58 | |
59 # Returns the total reported time for this version | |
60 def spent_hours | |
61 @spent_hours ||= TimeEntry.sum(:hours, :include => :issue, :conditions => ["#{Issue.table_name}.fixed_version_id = ?", id]).to_f | |
62 end | |
63 | |
64 def closed? | |
65 status == 'closed' | |
66 end | |
67 | |
68 def open? | |
69 status == 'open' | |
70 end | |
71 | |
72 # Returns true if the version is completed: due date reached and no open issues | |
73 def completed? | |
74 effective_date && (effective_date <= Date.today) && (open_issues_count == 0) | |
75 end | |
76 | |
77 # Returns the completion percentage of this version based on the amount of open/closed issues | |
78 # and the time spent on the open issues. | |
79 def completed_pourcent | |
80 if issues_count == 0 | |
81 0 | |
82 elsif open_issues_count == 0 | |
83 100 | |
84 else | |
85 issues_progress(false) + issues_progress(true) | |
86 end | |
87 end | |
88 | |
89 # Returns the percentage of issues that have been marked as 'closed'. | |
90 def closed_pourcent | |
91 if issues_count == 0 | |
92 0 | |
93 else | |
94 issues_progress(false) | |
95 end | |
96 end | |
97 | |
98 # Returns true if the version is overdue: due date reached and some open issues | |
99 def overdue? | |
100 effective_date && (effective_date < Date.today) && (open_issues_count > 0) | |
101 end | |
102 | |
103 # Returns assigned issues count | |
104 def issues_count | |
105 @issue_count ||= fixed_issues.count | |
106 end | |
107 | |
108 # Returns the total amount of open issues for this version. | |
109 def open_issues_count | |
110 @open_issues_count ||= Issue.count(:all, :conditions => ["fixed_version_id = ? AND is_closed = ?", self.id, false], :include => :status) | |
111 end | |
112 | |
113 # Returns the total amount of closed issues for this version. | |
114 def closed_issues_count | |
115 @closed_issues_count ||= Issue.count(:all, :conditions => ["fixed_version_id = ? AND is_closed = ?", self.id, true], :include => :status) | |
116 end | |
117 | |
118 def wiki_page | |
119 if project.wiki && !wiki_page_title.blank? | |
120 @wiki_page ||= project.wiki.find_page(wiki_page_title) | |
121 end | |
122 @wiki_page | |
123 end | |
124 | |
125 def to_s; name end | |
126 | |
127 # Versions are sorted by effective_date and "Project Name - Version name" | |
128 # Those with no effective_date are at the end, sorted by "Project Name - Version name" | |
129 def <=>(version) | |
130 if self.effective_date | |
131 if version.effective_date | |
132 if self.effective_date == version.effective_date | |
133 "#{self.project.name} - #{self.name}" <=> "#{version.project.name} - #{version.name}" | |
134 else | |
135 self.effective_date <=> version.effective_date | |
136 end | |
137 else | |
138 -1 | |
139 end | |
140 else | |
141 if version.effective_date | |
142 1 | |
143 else | |
144 "#{self.project.name} - #{self.name}" <=> "#{version.project.name} - #{version.name}" | |
145 end | |
146 end | |
147 end | |
148 | |
149 # Returns the sharings that +user+ can set the version to | |
150 def allowed_sharings(user = User.current) | |
151 VERSION_SHARINGS.select do |s| | |
152 if sharing == s | |
153 true | |
154 else | |
155 case s | |
156 when 'system' | |
157 # Only admin users can set a systemwide sharing | |
158 user.admin? | |
159 when 'hierarchy', 'tree' | |
160 # Only users allowed to manage versions of the root project can | |
161 # set sharing to hierarchy or tree | |
162 project.nil? || user.allowed_to?(:manage_versions, project.root) | |
163 else | |
164 true | |
165 end | |
166 end | |
167 end | |
168 end | |
169 | |
170 private | |
171 | |
172 # Update the issue's fixed versions. Used if a version's sharing changes. | |
173 def update_issues_from_sharing_change | |
174 if sharing_changed? | |
175 if VERSION_SHARINGS.index(sharing_was).nil? || | |
176 VERSION_SHARINGS.index(sharing).nil? || | |
177 VERSION_SHARINGS.index(sharing_was) > VERSION_SHARINGS.index(sharing) | |
178 Issue.update_versions_from_sharing_change self | |
179 end | |
180 end | |
181 end | |
182 | |
183 # Returns the average estimated time of assigned issues | |
184 # or 1 if no issue has an estimated time | |
185 # Used to weigth unestimated issues in progress calculation | |
186 def estimated_average | |
187 if @estimated_average.nil? | |
188 average = fixed_issues.average(:estimated_hours).to_f | |
189 if average == 0 | |
190 average = 1 | |
191 end | |
192 @estimated_average = average | |
193 end | |
194 @estimated_average | |
195 end | |
196 | |
197 # Returns the total progress of open or closed issues. The returned percentage takes into account | |
198 # the amount of estimated time set for this version. | |
199 # | |
200 # Examples: | |
201 # issues_progress(true) => returns the progress percentage for open issues. | |
202 # issues_progress(false) => returns the progress percentage for closed issues. | |
203 def issues_progress(open) | |
204 @issues_progress ||= {} | |
205 @issues_progress[open] ||= begin | |
206 progress = 0 | |
207 if issues_count > 0 | |
208 ratio = open ? 'done_ratio' : 100 | |
209 | |
210 done = fixed_issues.sum("COALESCE(estimated_hours, #{estimated_average}) * #{ratio}", | |
211 :include => :status, | |
212 :conditions => ["is_closed = ?", !open]).to_f | |
213 progress = done / (estimated_average * issues_count) | |
214 end | |
215 progress | |
216 end | |
217 end | |
218 end |