83 |
83 |
after_update :update_versions_from_hierarchy_change, :if => Proc.new {|project| project.saved_change_to_parent_id?}
|
84 |
84 |
before_destroy :delete_all_members
|
85 |
85 |
|
|
86 |
attr_accessor :cached_start_date
|
|
87 |
|
|
88 |
attr_accessor :cached_due_date
|
|
89 |
|
86 |
90 |
scope :has_module, lambda {|mod|
|
87 |
91 |
where("#{Project.table_name}.id IN (SELECT em.project_id FROM #{EnabledModule.table_name} em WHERE em.name=?)", mod.to_s)
|
88 |
92 |
}
|
... | ... | |
641 |
645 |
# The earliest start date of a project, based on it's issues and versions
|
642 |
646 |
def start_date
|
643 |
647 |
@start_date ||= [
|
644 |
|
issues.minimum('start_date'),
|
|
648 |
cached_start_date || issues.minimum('start_date'),
|
645 |
649 |
shared_versions.minimum('effective_date'),
|
646 |
650 |
Issue.fixed_version(shared_versions).minimum('start_date')
|
647 |
651 |
].compact.min
|
... | ... | |
650 |
654 |
# The latest due date of an issue or version
|
651 |
655 |
def due_date
|
652 |
656 |
@due_date ||= [
|
653 |
|
issues.maximum('due_date'),
|
|
657 |
cached_due_date || issues.maximum('due_date'),
|
654 |
658 |
shared_versions.maximum('effective_date'),
|
655 |
659 |
Issue.fixed_version(shared_versions).maximum('due_date')
|
656 |
660 |
].compact.max
|
... | ... | |
853 |
857 |
|
854 |
858 |
# Yields the given block for each project with its level in the tree
|
855 |
859 |
def self.project_tree(projects, options={}, &block)
|
|
860 |
|
|
861 |
start_dates = Issue.where(project_id: projects).group(:project_id).minimum(:start_date)
|
|
862 |
due_dates = Issue.where(project_id: projects).group(:project_id).maximum(:due_date)
|
|
863 |
projects.each do |project|
|
|
864 |
project.cached_start_date = start_dates[project.id]
|
|
865 |
project.cached_due_date = due_dates[project.id]
|
|
866 |
end
|
856 |
867 |
ancestors = []
|
857 |
868 |
if options[:init_level] && projects.first
|
858 |
869 |
ancestors = projects.first.ancestors.to_a
|