Class: Period
- Inherits:
-
ActiveRecord::Base
- Object
- ActiveRecord::Base
- Period
show all
- Extended by:
- UserSystem
- Includes:
- Localization, UserSystem
- Defined in:
- app/models/period.rb
Constant Summary
Localization::LOCALIZED_STRINGS
Class Method Summary
collapse
Instance Method Summary
collapse
-
#active?(check_tasks = false) ⇒ Boolean
-
#active_or_future?(check_tasks = false) ⇒ Boolean
-
#active_tasks? ⇒ Boolean
-
#backlogs ⇒ Object
-
#burn_down_graph(size) ⇒ Object
-
#completed_tasks ⇒ Object
-
#dates ⇒ Object
-
#enable_subtasks? ⇒ Boolean
-
#estimate_data(date, actual = false) ⇒ Object
-
#estimates? ⇒ Boolean
-
#future? ⇒ Boolean
-
#get_todo_data(dates, actual = false) ⇒ Object
-
#get_work_data(dates) ⇒ Object
-
#invoice? ⇒ Boolean
-
#most_frequent_backlog ⇒ Object
-
#name ⇒ Object
-
#open_tasks ⇒ Object
-
#passed? ⇒ Boolean
-
#projection_data(observed_todo_data) ⇒ Object
-
#recorded_dates ⇒ Object
-
#required_speed ⇒ Object
-
#speed ⇒ Object
-
#to_s ⇒ Object
-
#track_times? ⇒ Boolean
-
#track_work? ⇒ Boolean
-
#validate ⇒ Object
-
#work_data(date) ⇒ Object
-
#works_for_week(week_no, with_empty_works = false, user_id = nil) ⇒ Object
Return an array with a work object per day: [ [<work>, <work>, <work>, <work>, <work>, nil, nil], [<work>, nil, <work>, <work>, <work>, nil, nil] ].
#l, load_localized_strings, #valid_language?
Class Method Details
.find_active_or_future(check_tasks = false) ⇒ Object
16
17
18
19
20
21
22
23
|
# File 'app/models/period.rb', line 16
def self.find_active_or_future(check_tasks = false)
periods = find(:all, :conditions => "end_on >= '#{Date.today.strftime '%Y-%m-%d'}'")
if (check_tasks)
ended_periods_with_open_tasks = Task.find(:all, :conditions => ['finished_at IS NULL AND period_id NOT IN (?)', periods.map{|p| p.id}]).map {|t| t.period}
periods + ended_periods_with_open_tasks
end
periods.select {|p| p.party.includes?(current_user)}
end
|
Instance Method Details
#active?(check_tasks = false) ⇒ Boolean
51
52
53
|
# File 'app/models/period.rb', line 51
def active?(check_tasks = false)
start_on <= Date.today && (end_on >= Date.today || (check_tasks && active_tasks?))
end
|
#active_or_future?(check_tasks = false) ⇒ Boolean
63
64
65
|
# File 'app/models/period.rb', line 63
def active_or_future?(check_tasks = false)
end_on >= Date.today || (check_tasks && active_tasks?)
end
|
#active_tasks? ⇒ Boolean
55
56
57
|
# File 'app/models/period.rb', line 55
def active_tasks?
not tasks.select {|task| task.active?}.empty?
end
|
#backlogs ⇒ Object
177
178
179
|
# File 'app/models/period.rb', line 177
def backlogs
tasks.map {|task| task.backlog}.uniq
end
|
#burn_down_graph(size) ⇒ Object
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
|
# File 'app/models/period.rb', line 181
def burn_down_graph(size)
begin
require 'gruff'
rescue MissingSourceFile => e
return File.read("public/images/rmagick_#{size}.gif") if File.exists? "public/images/rmagick_#{size}.gif"
return File.read("public/images/rmagick.gif")
end
g = Gruff::Line.new(size)
g.theme_37signals
g.title = l(:burn_down_chart) + " " + name
g.font = '/usr/share/fonts/bitstream-vera/Vera.ttf'
g.legend_font_size = 14
g.hide_dots = true
g.colors = %w{#0000ff #ff8800}
if track_work?
g.colors += %w{#00ff00}
end
if previous_period = higher_item
g.colors += %w{#cccccc #cccccc}
end
g.colors += %w{#8888ff #d7a790}
recorded_dates = self.recorded_dates
observed_todo_data = get_todo_data(recorded_dates)
g.data("#{l :todo} (#{l :obs})", observed_todo_data)
g.data(l(:projection), projection_data(observed_todo_data))
actual_todo_data = get_todo_data(recorded_dates, true)
g.data("#{l :todo}", actual_todo_data)
g.data(l(:projection), projection_data(actual_todo_data))
g.data(l(:done), get_work_data(recorded_dates)) if track_work?
if previous_period = higher_item
g.data("#{l :previous_abr} #{l :obs}", previous_period.get_todo_data(previous_period.dates))
g.data("#{l :previous_abr}", previous_period.get_todo_data(previous_period.dates, true))
end
g.minimum_value = 0
all_dates = dates
labels = {1 => all_dates[1].to_s, all_dates.length-1 => all_dates.last.to_s}
labels.merge({all_dates.index(Date.today) => Date.today.to_s}) if all_dates.index(Date.today) && (all_dates.index(Date.today) / all_dates.length) > 0.10
g.labels = labels
g.maximum_value = (g.maximum_value.to_s[0..0].to_i + 1) * (10**Math::log10(g.maximum_value.to_i).to_i) if g.maximum_value > 0
g.to_blob
end
|
#completed_tasks ⇒ Object
32
33
34
|
# File 'app/models/period.rb', line 32
def completed_tasks
tasks.select {|task| task.completed?}
end
|
#dates ⇒ Object
109
110
111
112
113
|
# File 'app/models/period.rb', line 109
def dates
all_dates = []
(start_on-1).upto(end_on) {|date| all_dates << date}
return all_dates
end
|
#enable_subtasks? ⇒ Boolean
169
170
171
|
# File 'app/models/period.rb', line 169
def enable_subtasks?
not backlogs.find {|backlog| backlog.enable_subtasks?}.nil?
end
|
#estimate_data(date, actual = false) ⇒ Object
71
72
73
74
75
76
77
|
# File 'app/models/period.rb', line 71
def estimate_data(date, actual=false)
total = BigDecimal('0')
tasks.each do |task|
total += task.estimate_data(date, actual)
end
total
end
|
#estimates? ⇒ Boolean
157
158
159
|
# File 'app/models/period.rb', line 157
def estimates?
not backlogs.find {|backlog| backlog.track_todo?}.nil?
end
|
#future? ⇒ Boolean
59
60
61
|
# File 'app/models/period.rb', line 59
def future?
start_on >= Date.today
end
|
#get_todo_data(dates, actual = false) ⇒ Object
233
234
235
|
# File 'app/models/period.rb', line 233
def get_todo_data(dates, actual=false)
dates.map { |date| estimate_data(date, actual) }
end
|
#get_work_data(dates) ⇒ Object
237
238
239
|
# File 'app/models/period.rb', line 237
def get_work_data(dates)
dates.map { |date| work_data(date) }
end
|
#invoice? ⇒ Boolean
173
174
175
|
# File 'app/models/period.rb', line 173
def invoice?
not backlogs.find {|backlog| backlog.enable_invoicing?}.nil?
end
|
#most_frequent_backlog ⇒ Object
40
41
42
43
44
45
46
47
48
49
|
# File 'app/models/period.rb', line 40
def most_frequent_backlog
all_backlogs = tasks.map {|t| t.backlog}.compact
return nil if all_backlogs.empty?
freq = {}
all_backlogs.each do |b|
freq[b.id] ||= 0
freq[b.id] += 1
end
freq.to_a.sort_by {|backlog, count| -count}.first[0]
end
|
#name ⇒ Object
105
106
107
|
# File 'app/models/period.rb', line 105
def name
"#{party.name}##{position}"
end
|
#open_tasks ⇒ Object
36
37
38
|
# File 'app/models/period.rb', line 36
def open_tasks
tasks.select {|task| task.active?}
end
|
#passed? ⇒ Boolean
67
68
69
|
# File 'app/models/period.rb', line 67
def passed?
end_on < Date.today
end
|
#projection_data(observed_todo_data) ⇒ Object
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
|
# File 'app/models/period.rb', line 241
def projection_data(observed_todo_data)
if observed_todo_data.length <= 1
velocity = party.current_speed
else
velocity = (observed_todo_data[0] - observed_todo_data[-1]).to_f / (observed_todo_data.length-1)
end
projection_data = dates.map do |date|
if date < Date.today
nil
else
value = observed_todo_data[0] - (date-start_on+1).to_f*velocity
value >= 0 ? value : 0
end
end
end
|
#recorded_dates ⇒ Object
115
116
117
118
119
120
121
122
123
124
125
|
# File 'app/models/period.rb', line 115
def recorded_dates
dates = []
if start_on > Date.today
dates << (start_on-1)
elsif end_on < Date.today
(start_on-1).upto(end_on) {|date| dates << date}
else
(start_on-1).upto(Date.today) {|date| dates << date}
end
return dates
end
|
#required_speed ⇒ Object
87
88
89
90
91
92
93
94
95
96
97
98
99
|
# File 'app/models/period.rb', line 87
def required_speed
todo = estimate_data(Date.today)
remaining_days = end_on - Date.today
if todo == 0
0
elsif remaining_days > 0
todo / remaining_days
elsif remaining_days == 0
todo
else
todo * (-remaining_days)
end
end
|
#speed ⇒ Object
25
26
27
28
29
30
|
# File 'app/models/period.rb', line 25
def speed
start_todo = estimate_data(start_on, true)
end_todo = estimate_data(end_on, true)
days = end_on - start_on
return (start_todo - end_todo).to_f / days
end
|
#to_s ⇒ Object
101
102
103
|
# File 'app/models/period.rb', line 101
def to_s
name
end
|
#track_times? ⇒ Boolean
165
166
167
|
# File 'app/models/period.rb', line 165
def track_times?
not backlogs.find {|backlog| backlog.track_times?}.nil?
end
|
#track_work? ⇒ Boolean
161
162
163
|
# File 'app/models/period.rb', line 161
def track_work?
not backlogs.find {|backlog| backlog.work_account}.nil?
end
|
#validate ⇒ Object
12
13
14
|
# File 'app/models/period.rb', line 12
def validate
errors.add "A period cannot end before it starts" unless end_on >= start_on
end
|
#work_data(date) ⇒ Object
79
80
81
82
83
84
85
|
# File 'app/models/period.rb', line 79
def work_data(date)
total = BigDecimal('0')
tasks.each do |task|
total += task.work_data(date)
end
total
end
|
#works_for_week(week_no, with_empty_works = false, user_id = nil) ⇒ Object
Return an array with a work object per day: [
[<work>, <work>, <work>, <work>, <work>, nil, nil],
[<work>, nil, <work>, <work>, <work>, nil, nil]
]
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
# File 'app/models/period.rb', line 132
def works_for_week(week_no, with_empty_works = false, user_id = nil)
first = Date.commercial(Date.today.year, week_no, 1)
last = first + 6
works = tasks.map {|t| t.works_with_children}.flatten
works.reject! {|work| work.hours == 0} unless with_empty_works
works.reject! {|work| work.user_id != user_id} if user_id && backlog.enable_users
by_day = (0..6).map do |i|
works.select {|w| w.completed_at && w.completed_at.to_date == first + i}.sort do |w1, w2|
if w1.completed_at != w2.completed_at
w1.completed_at <=> w2.completed_at
elsif w1.started_at && w2.started_at
w1.started_at <=> w2.started_at
elsif w1.started_at
1
else
-1
end
end
end
by_day.each {|d| d[works.size] = d[works.size]}
by_line = by_day.transpose
by_line = by_line.select {|l| l.compact.size > 0}
by_line
end
|