18 |
18 |
class Issue < ActiveRecord::Base
|
19 |
19 |
include Redmine::SafeAttributes
|
20 |
20 |
include Redmine::Utils::DateCalculation
|
|
21 |
|
|
22 |
cattr_accessor :skip_callbacks
|
21 |
23 |
|
22 |
24 |
belongs_to :project
|
23 |
25 |
belongs_to :tracker
|
... | ... | |
91 |
93 |
}
|
92 |
94 |
|
93 |
95 |
before_create :default_assign
|
94 |
|
before_save :close_duplicates, :update_done_ratio_from_issue_status, :force_updated_on_change, :update_closed_on
|
|
96 |
before_save :close_duplicates, :update_mirrors, :update_mirrored, :update_done_ratio_from_issue_status, :force_updated_on_change, :update_closed_on, :unless => :skip_callbacks
|
95 |
97 |
after_save {|issue| issue.send :after_project_change if !issue.id_changed? && issue.project_id_changed?}
|
96 |
98 |
after_save :reschedule_following_issues, :update_nested_set_attributes, :update_parent_attributes, :create_journal
|
97 |
99 |
# Should be after_create but would be called before previous after_save callbacks
|
... | ... | |
870 |
872 |
relations_to.select {|r| r.relation_type == IssueRelation::TYPE_DUPLICATES}.collect {|r| r.issue_from}
|
871 |
873 |
end
|
872 |
874 |
|
|
875 |
# Returns an array of issues that mirror this one
|
|
876 |
def mirrors
|
|
877 |
relations_to.select {|r| r.relation_type == IssueRelation::TYPE_MIRRORED}.collect {|r| r.issue_from}
|
|
878 |
end
|
|
879 |
|
|
880 |
# Returns an array of issues that mirror this one
|
|
881 |
def mirrored
|
|
882 |
relations_from.select {|r| r.relation_type == IssueRelation::TYPE_MIRRORED}.collect {|r| r.issue_to}
|
|
883 |
end
|
|
884 |
|
873 |
885 |
# Returns the due date or the target due date if any
|
874 |
886 |
# Used on gantt chart
|
875 |
887 |
def due_before
|
... | ... | |
1330 |
1342 |
end
|
1331 |
1343 |
end
|
1332 |
1344 |
end
|
|
1345 |
|
|
1346 |
# Update mirrors
|
|
1347 |
def update_mirrors
|
|
1348 |
if status_id_changed?
|
|
1349 |
logger.error "## #{id} UPDATE MIRROR ## #{relations_to}"
|
|
1350 |
logger.error "# #{id} - Relation mirror : #{mirrors}"
|
|
1351 |
mirrors.each do |mirror|
|
|
1352 |
# Reload is need in case the duplicate was updated by a previous duplicate
|
|
1353 |
mirror.reload
|
|
1354 |
# Don't re-close it if it's already closed
|
|
1355 |
logger.error "## status : #{self.status} mirror : #{mirror.status}"
|
|
1356 |
next if mirror.closed? || mirror.status == self.status
|
|
1357 |
# Same user and notes
|
|
1358 |
if @current_journal
|
|
1359 |
mirror.init_journal(@current_journal.user, @current_journal.notes)
|
|
1360 |
end
|
|
1361 |
Issue.skip_callbacks = true
|
|
1362 |
mirror.update_attribute :status, self.status
|
|
1363 |
Issue.skip_callbacks = false
|
|
1364 |
end
|
|
1365 |
end
|
|
1366 |
end
|
|
1367 |
|
|
1368 |
# Update mirrored
|
|
1369 |
def update_mirrored
|
|
1370 |
if status_id_changed?
|
|
1371 |
logger.error "## #{id} UPDATE MIRRORED ## #{relations_from}"
|
|
1372 |
logger.error "# #{id} - Relations mirrored : #{mirrored}"
|
|
1373 |
mirrored.each do |mirrored|
|
|
1374 |
# Reload is need in case the duplicate was updated by a previous duplicate
|
|
1375 |
mirrored.reload
|
|
1376 |
# Don't re-close it if it's already closed
|
|
1377 |
logger.error "## status : #{self.status} mirrored : #{mirrored.status}"
|
|
1378 |
next if mirrored.closed? || mirrored.status == self.status
|
|
1379 |
# Same user and notes
|
|
1380 |
if @current_journal
|
|
1381 |
mirrored.init_journal(@current_journal.user, @current_journal.notes)
|
|
1382 |
end
|
|
1383 |
Issue.skip_callbacks = true
|
|
1384 |
mirrored.update_attribute :status, self.status
|
|
1385 |
Issue.skip_callbacks = false
|
|
1386 |
end
|
|
1387 |
end
|
|
1388 |
end
|
1333 |
1389 |
|
1334 |
1390 |
# Make sure updated_on is updated when adding a note and set updated_on now
|
1335 |
1391 |
# so we can set closed_on with the same value on closing
|