OpenProject is the leading open source project management software.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
openproject/app/models/backlog_chart_data.rb

85 lines
2.9 KiB

class BacklogChartData < ActiveRecord::Base
unloadable
set_table_name 'backlog_chart_data'
belongs_to :backlog
def self.generate(backlog)
# do not generate if end_date or start_date are not defined
# or if the start date is still in the future
# or if the backlog is already closed
return nil if backlog.end_date.nil? || backlog.start_date.nil? ||
backlog.start_date > Date.today ||
backlog.is_closed?
data_today = BacklogChartData.find :first, :conditions => ["backlog_id=? AND created_at=?", backlog.id, Date.today.to_formatted_s(:db)]
scope = Item.sum('points', :conditions => ["items.backlog_id=? AND items.parent_id=0", backlog.id])
done = Item.sum('points', :include => {:issue => :status}, :conditions => ["items.parent_id=0 AND items.backlog_id=? AND issue_statuses.is_closed=?", backlog.id, true])
wip = 0
if data_today.nil?
create :scope => scope, :done => done, :backlog_id => backlog.id, :created_at => Date.today.to_formatted_s(:db)
else
data_today.scope = scope
data_today.done = done
data_today.wip = wip
data_today.save!
end
data_today
end
def self.fetch(options = {})
backlog = Backlog.find(options[:backlog_id])
if generate(backlog).nil?
return nil
end
end_date = backlog.end_date
data = find_all_by_backlog_id backlog.id, :conditions => ["created_at>=? AND created_at<=?", backlog.start_date.to_formatted_s(:db), end_date.to_formatted_s(:db)], :order => "created_at ASC"
return nil if data.nil? || data.length==0
data_points = (end_date - data.first.created_at.to_date).to_i + 1
scope = []
done = []
days = []
data.each do |d|
scope << d.scope
done << d.done
days << d.created_at
end
(1..(data_points-days.length)).to_a.each do |i|
days << days.last + 1.day
end
scope = scope.fill(scope.last, scope.length, data_points - scope.length)
speed = (done.last - done.first).to_f / done.length
best = [done.last]
worst = [done.last]
if done.length > 1
while best.last < scope.last && best.last > 0 && (best.length+done.length <= scope.length)
best << (best.last + speed*1.5).round(2)
end
best[best.length-1] = best.last > scope.last ? scope.last : best.last
while worst.last < scope.last && worst.last > 0 && (worst.length+done.length <= scope.length)
worst << (worst.last + speed*0.5).round(2)
end
worst[worst.length-1] = worst.last > scope.last ? scope.last : worst.last
end
{
:days => days,
:scope => scope,
:scope_x => (0...scope.length).to_a,
:done => done,
:done_x => (0...done.length).to_a,
:best => best,
:best_x => (0...best.length).to_a.map{|n| n+done.length-1},
:worst => worst,
:worst_x => (0...worst.length).to_a.map{|n| n+done.length-1}
}
end
end