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/lib/issue_patch.rb

152 lines
5.3 KiB

require_dependency 'issue'
module IssuePatch
def self.included(base) # :nodoc:
base.extend(ClassMethods)
base.send(:include, InstanceMethods)
base.class_eval do
unloadable
alias_method_chain :move_to_project_without_transaction, :autolink
alias_method_chain :update_parent_attributes, :remaining_hours
before_save :store_parent
after_save :task_follows_story
after_save :fix_old_parent
end
end
module ClassMethods
end
module InstanceMethods
def move_to_project_without_transaction_with_autolink(new_project, new_tracker = nil, options = {})
newissue = move_to_project_without_transaction_without_autolink(new_project, new_tracker, options)
if self.project_id == newissue.project_id and self.is_story? and newissue.is_story? and self.id != newissue.id
relation = IssueRelation.new :relation_type => IssueRelation::TYPE_DUPLICATES
relation.issue_from = self
relation.issue_to = newissue
relation.save
end
return newissue
end
def journalized_update_attributes!(attribs)
self.init_journal(User.current)
return self.update_attributes! attribs
end
def journalized_update_attributes(attribs)
self.init_journal(User.current)
return self.update_attributes attribs
end
def journalized_update_attribute(attrib, v)
self.init_journal(User.current)
self.update_attribute(attrib, v)
end
def is_story?
return (Story.trackers.include?(self.tracker_id) and self.root?)
end
def is_task?
return (self.parent_id && self.tracker_id == Task.tracker)
end
def story
return Issue.find(:first,
:conditions => [ "id = ? and tracker_id in (?)", self.root_id, Story.trackers ])
end
def blocks
# return issues that I block that aren't closed
return [] if closed?
relations_from.collect {|ir| ir.relation_type == 'blocks' && !ir.issue_to.closed? ? ir.issue_to : nil}.compact
end
def blockers
# return issues that block me
return [] if closed?
relations_to.collect {|ir| ir.relation_type == 'blocks' && !ir.issue_from.closed? ? ir.issue_from : nil}.compact
end
def velocity_based_estimate
return nil if !self.is_story? || ! self.story_points || self.story_points <= 0
v = self.project.velocity
return nil if ! v or ! v[:velocity] or v[:velocity] <= 0
return self.story_points * (v[:days] / v[:velocity])
end
def update_parent_attributes_with_remaining_hours
update_parent_attributes_without_remaining_hours
if parent_id && p = Issue.find_by_id(parent_id)
p.remaining_hours = p.leaves.sum(:remaining_hours).to_f
p.save
end
end
def store_parent
if self.parent_id_was && !(self.parent_id_was == self.parent_issue_id)
@old_parent = self.parent_id_was
else
@old_parent = nil
end
end
def fix_old_parent
if @old_parent
p = Issue.find_by_id(@old_parent)
c = p.children
if c.length == 0
p.update_attribute(:estimated_hours, nil)
p.update_attribute(:remaining_hours, nil)
else
c[0].instance_eval{ update_parent_attributes }
end
end
end
def task_follows_story
## automatically sets the tracker to the task tracker for
## any descendant of story, and follow the version_id
## Normally one of the _before_save hooks ought to take
## care of this, but appearantly neither root_id nor
## parent_id are set at that point
renamed start_date, burndown generation, parameter quotation * start_date was added to the core Issue model, overriding our start_date. The core start_date is just an alias for the effective_date, so it's not useful to us. * burndown generation. Sprint.generate_burndown will generate the burndown for all current sprints by calling +generate+ on each of them. +generate+ picks what it can from the cache and interpolates the rest. The cache can be primed by just calling +generate+ at least once a day. Calling it multiple times will have no effect _unless_ you've changed a story or task, which will cause today's cache entry to be discarded. This way you will always have the latest data. The charts being generated: - points committed: the total of points included in the sprint. This would typically always be the same from the start, but will change if stories are added or removed mid-sprint - points resolved: when a story goes to 100% completed (typically by setting its tasks to closed), the story is deemed resolved. - points accepted: when a story is closed, it is deemed to be accepted by the PO - remaining hours: total of hours remaining on all tasks - required burn rate in points/hours: the number of points/hours the team will have to burn down each day to complete all the work at the end of the sprint. A flat line is perfect, if the line starts dropping it means the team is ahead of the curve, if the line starts climbing it means the team is running behind * parameter quotation added to raw sql
15 years ago
touched_sprint = nil
if self.is_story?
# raw sql here because it's efficient and not
# doing so causes an update loop when Issue calls
# update_parent
if not Task.tracker.nil?
renamed start_date, burndown generation, parameter quotation * start_date was added to the core Issue model, overriding our start_date. The core start_date is just an alias for the effective_date, so it's not useful to us. * burndown generation. Sprint.generate_burndown will generate the burndown for all current sprints by calling +generate+ on each of them. +generate+ picks what it can from the cache and interpolates the rest. The cache can be primed by just calling +generate+ at least once a day. Calling it multiple times will have no effect _unless_ you've changed a story or task, which will cause today's cache entry to be discarded. This way you will always have the latest data. The charts being generated: - points committed: the total of points included in the sprint. This would typically always be the same from the start, but will change if stories are added or removed mid-sprint - points resolved: when a story goes to 100% completed (typically by setting its tasks to closed), the story is deemed resolved. - points accepted: when a story is closed, it is deemed to be accepted by the PO - remaining hours: total of hours remaining on all tasks - required burn rate in points/hours: the number of points/hours the team will have to burn down each day to complete all the work at the end of the sprint. A flat line is perfect, if the line starts dropping it means the team is ahead of the curve, if the line starts climbing it means the team is running behind * parameter quotation added to raw sql
15 years ago
tasks = self.descendants.collect{|t| connection.quote(t.id)}.join(",")
if tasks != ""
connection.execute("update issues set tracker_id=#{connection.quote(Task.tracker)}, fixed_version_id=#{connection.quote(self.fixed_version_id)} where id in (#{tasks})")
end
end
renamed start_date, burndown generation, parameter quotation * start_date was added to the core Issue model, overriding our start_date. The core start_date is just an alias for the effective_date, so it's not useful to us. * burndown generation. Sprint.generate_burndown will generate the burndown for all current sprints by calling +generate+ on each of them. +generate+ picks what it can from the cache and interpolates the rest. The cache can be primed by just calling +generate+ at least once a day. Calling it multiple times will have no effect _unless_ you've changed a story or task, which will cause today's cache entry to be discarded. This way you will always have the latest data. The charts being generated: - points committed: the total of points included in the sprint. This would typically always be the same from the start, but will change if stories are added or removed mid-sprint - points resolved: when a story goes to 100% completed (typically by setting its tasks to closed), the story is deemed resolved. - points accepted: when a story is closed, it is deemed to be accepted by the PO - remaining hours: total of hours remaining on all tasks - required burn rate in points/hours: the number of points/hours the team will have to burn down each day to complete all the work at the end of the sprint. A flat line is perfect, if the line starts dropping it means the team is ahead of the curve, if the line starts climbing it means the team is running behind * parameter quotation added to raw sql
15 years ago
touched_sprint = self.fixed_version
elsif not Task.tracker.nil?
begin
story = self.story
if not story.nil?
renamed start_date, burndown generation, parameter quotation * start_date was added to the core Issue model, overriding our start_date. The core start_date is just an alias for the effective_date, so it's not useful to us. * burndown generation. Sprint.generate_burndown will generate the burndown for all current sprints by calling +generate+ on each of them. +generate+ picks what it can from the cache and interpolates the rest. The cache can be primed by just calling +generate+ at least once a day. Calling it multiple times will have no effect _unless_ you've changed a story or task, which will cause today's cache entry to be discarded. This way you will always have the latest data. The charts being generated: - points committed: the total of points included in the sprint. This would typically always be the same from the start, but will change if stories are added or removed mid-sprint - points resolved: when a story goes to 100% completed (typically by setting its tasks to closed), the story is deemed resolved. - points accepted: when a story is closed, it is deemed to be accepted by the PO - remaining hours: total of hours remaining on all tasks - required burn rate in points/hours: the number of points/hours the team will have to burn down each day to complete all the work at the end of the sprint. A flat line is perfect, if the line starts dropping it means the team is ahead of the curve, if the line starts climbing it means the team is running behind * parameter quotation added to raw sql
15 years ago
connection.execute "update issues set tracker_id = #{connection.quote(Task.tracker)}, fixed_version_id = #{connection.quote(story.fixed_version_id)} where id = #{connection.quote(self.id)}"
touched_sprint = story.fixed_version
end
end
end
renamed start_date, burndown generation, parameter quotation * start_date was added to the core Issue model, overriding our start_date. The core start_date is just an alias for the effective_date, so it's not useful to us. * burndown generation. Sprint.generate_burndown will generate the burndown for all current sprints by calling +generate+ on each of them. +generate+ picks what it can from the cache and interpolates the rest. The cache can be primed by just calling +generate+ at least once a day. Calling it multiple times will have no effect _unless_ you've changed a story or task, which will cause today's cache entry to be discarded. This way you will always have the latest data. The charts being generated: - points committed: the total of points included in the sprint. This would typically always be the same from the start, but will change if stories are added or removed mid-sprint - points resolved: when a story goes to 100% completed (typically by setting its tasks to closed), the story is deemed resolved. - points accepted: when a story is closed, it is deemed to be accepted by the PO - remaining hours: total of hours remaining on all tasks - required burn rate in points/hours: the number of points/hours the team will have to burn down each day to complete all the work at the end of the sprint. A flat line is perfect, if the line starts dropping it means the team is ahead of the curve, if the line starts climbing it means the team is running behind * parameter quotation added to raw sql
15 years ago
if not touched_sprint.nil?
touched_sprint.touch_burndown
end
end
end
end