kanbanworkflowstimelinescrumrubyroadmapproject-planningproject-managementopenprojectangularissue-trackerifcgantt-chartganttbug-trackerboardsbcf
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.
128 lines
5.3 KiB
128 lines
5.3 KiB
require 'date'
|
|
|
|
class Sprint < Version
|
|
unloadable
|
|
|
|
validate :start_and_end_dates
|
|
|
|
scope :open_sprints, lambda { |project|
|
|
{
|
|
:order => "COALESCE(start_date, CAST('4000-12-30' as date)) ASC, COALESCE(effective_date, CAST('4000-12-30' as date)) ASC",
|
|
:conditions => [ "versions.status = 'open' and versions.project_id = ?", project.id ]
|
|
}
|
|
}
|
|
|
|
#null last ordering
|
|
scope :order_by_date, :order => "COALESCE(start_date, CAST('4000-12-30' as date)) ASC, COALESCE(effective_date, CAST('4000-12-30' as date)) ASC"
|
|
scope :order_by_name, :order => "#{Version.table_name}.name ASC"
|
|
|
|
scope :apply_to, lambda { |project| {:include => :project,
|
|
:conditions => ["#{Version.table_name}.project_id = #{project.id}" +
|
|
" OR (#{Project.table_name}.status = #{Project::STATUS_ACTIVE} AND (" +
|
|
" #{Version.table_name}.sharing = 'system'" +
|
|
" OR (#{Project.table_name}.lft >= #{project.root.lft} AND #{Project.table_name}.rgt <= #{project.root.rgt} AND #{Version.table_name}.sharing = 'tree')" +
|
|
" OR (#{Project.table_name}.lft < #{project.lft} AND #{Project.table_name}.rgt > #{project.rgt} AND #{Version.table_name}.sharing IN ('hierarchy', 'descendants'))" +
|
|
" OR (#{Project.table_name}.lft > #{project.lft} AND #{Project.table_name}.rgt < #{project.rgt} AND #{Version.table_name}.sharing = 'hierarchy')" +
|
|
"))"]}}
|
|
|
|
scope :displayed_left, lambda { |project| { :joins => sanitize_sql_array(["LEFT OUTER JOIN (SELECT * from #{VersionSetting.table_name}" +
|
|
" WHERE project_id = ? ) version_settings" +
|
|
" ON version_settings.version_id = versions.id",
|
|
project.id]),
|
|
:conditions => ["(version_settings.project_id = ? AND version_settings.display = ?)" +
|
|
" OR (version_settings.project_id is NULL)",
|
|
project.id, VersionSetting::DISPLAY_LEFT] } }
|
|
|
|
scope :displayed_right, lambda { |project| {:include => :version_settings,
|
|
:conditions => ["version_settings.project_id = ? AND version_settings.display = ?",
|
|
project.id, VersionSetting::DISPLAY_RIGHT]} }
|
|
|
|
def stories(project, options = {} )
|
|
Story.sprint_backlog(project, self, options)
|
|
end
|
|
|
|
def points
|
|
stories.inject(0) { |sum, story| sum + story.story_points.to_i }
|
|
end
|
|
|
|
def has_wiki_page
|
|
return false if wiki_page_title.blank?
|
|
|
|
page = project.wiki.find_page(self.wiki_page_title)
|
|
return false if !page
|
|
|
|
template = project.wiki.find_page(Setting.plugin_openproject_backlogs["wiki_template"])
|
|
return false if template && page.text == template.text
|
|
|
|
true
|
|
end
|
|
|
|
def wiki_page
|
|
return '' unless project.wiki
|
|
|
|
self.update_attribute(:wiki_page_title, Wiki.titleize(self.name)) if wiki_page_title.blank?
|
|
|
|
page = project.wiki.find_page(self.wiki_page_title)
|
|
template = project.wiki.find_page(Setting.plugin_openproject_backlogs["wiki_template"])
|
|
|
|
if template and not page
|
|
page = project.wiki.pages.build(:title => self.wiki_page_title)
|
|
page.build_content(:text => "h1. #{self.name}\n\n#{template.text}")
|
|
page.save!
|
|
end
|
|
|
|
wiki_page_title
|
|
end
|
|
|
|
def days(cutoff = nil, alldays = false)
|
|
# assumes mon-fri are working days, sat-sun are not. this
|
|
# assumption is not globally right, we need to make this configurable.
|
|
cutoff = self.effective_date if cutoff.nil?
|
|
|
|
(self.start_date .. cutoff).select {|d| alldays || (d.wday > 0 and d.wday < 6) }
|
|
end
|
|
|
|
def has_burndown?
|
|
!!(self.effective_date and self.start_date)
|
|
end
|
|
|
|
def activity
|
|
bd = self.burndown('up')
|
|
return false if bd.blank?
|
|
|
|
# assume a sprint is active if it's only 2 days old
|
|
return true if bd.remaining_hours.size <= 2
|
|
|
|
Issue.exists?(['fixed_version_id = ? and ((updated_on between ? and ?) or (created_on between ? and ?))',
|
|
self.id, -2.days.from_now, Time.now, -2.days.from_now, Time.now])
|
|
end
|
|
|
|
def burndown(project, burn_direction = nil)
|
|
return nil unless self.has_burndown?
|
|
|
|
@cached_burndown ||= Burndown.new(self, project, burn_direction)
|
|
end
|
|
|
|
def self.generate_burndown(only_current = true)
|
|
if only_current
|
|
conditions = ["? BETWEEN start_date AND effective_date", Date.today]
|
|
else
|
|
conditions = "1 = 1"
|
|
end
|
|
|
|
Version.find(:all, :conditions => conditions).each { |sprint|
|
|
sprint.burndown
|
|
}
|
|
end
|
|
|
|
def impediments(project)
|
|
Impediment.find(:all, :conditions => {:fixed_version_id => self, :project_id => project})
|
|
end
|
|
|
|
private
|
|
def start_and_end_dates
|
|
if self.effective_date && self.start_date && self.start_date >= self.effective_date
|
|
errors.add(:base, :cannot_end_before_it_starts)
|
|
end
|
|
end
|
|
end
|
|
|