Feature #6687 » keep_original_dates_and_estimations_on_parent_issue.diff
app/models/issue.rb (copia de trabajo) | ||
---|---|---|
27 | 27 |
belongs_to :fixed_version, :class_name => 'Version', :foreign_key => 'fixed_version_id' |
28 | 28 |
belongs_to :priority, :class_name => 'IssuePriority', :foreign_key => 'priority_id' |
29 | 29 |
belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id' |
30 |
belongs_to :priority_on_children, :class_name => 'IssuePriority', :foreign_key => 'priority_id_on_children' |
|
30 | 31 | |
31 | 32 |
has_many :journals, :as => :journalized, :dependent => :destroy |
32 | 33 |
has_many :visible_journals, |
... | ... | |
64 | 65 |
delegate :notes, :notes=, :private_notes, :private_notes=, :to => :current_journal, :allow_nil => true |
65 | 66 | |
66 | 67 |
validates_presence_of :subject, :priority, :project, :tracker, :author, :status |
68 |
validates_presence_of :priority_on_children, :if => Proc.new{|i| !i.leaf?} |
|
67 | 69 | |
68 | 70 |
validates_length_of :subject, :maximum => 255 |
69 | 71 |
validates_inclusion_of :done_ratio, :in => 0..100 |
... | ... | |
413 | 415 |
return if attrs.empty? |
414 | 416 | |
415 | 417 |
unless leaf? |
416 |
attrs.reject! {|k,v| %w(priority_id done_ratio start_date due_date estimated_hours).include?(k)}
|
|
418 |
attrs.reject! {|k,v| %w(done_ratio).include?(k)}
|
|
417 | 419 |
end |
418 | 420 | |
419 | 421 |
if attrs['parent_issue_id'].present? |
... | ... | |
556 | 558 |
errors.add :tracker_id, :inclusion |
557 | 559 |
end |
558 | 560 |
end |
559 | ||
561 |
|
|
562 |
if estimated_hours && estimated_hours_on_children && estimated_hours < estimated_hours_on_children |
|
563 |
errors.add :estimated_hours, :less_than_children_estimations |
|
564 |
end |
|
565 |
|
|
560 | 566 |
# Checks parent issue assignment |
561 | 567 |
if @invalid_parent_issue_id.present? |
562 | 568 |
errors.add :parent_issue_id, :invalid |
... | ... | |
573 | 579 |
errors.add :parent_issue_id, :invalid |
574 | 580 |
end |
575 | 581 |
end |
582 |
if errors[:parent_issue_id].empty? |
|
583 |
# Parent valid, avoid estimated hours on children overflow estimated hours on parent |
|
584 |
ests_on_parent = @parent_issue.estimated_hours_on_children || 0 |
|
585 |
ests_on_parent -= estimated_hours_was unless estimated_hours_was.nil? || (parent_id != @parent_issue.id) |
|
586 |
if @parent_issue.estimated_hours.nil? && !estimated_hours.nil? |
|
587 |
errors.add :estimated_hours, :no_parent_estimations |
|
588 |
elsif !estimated_hours.nil? && @parent_issue.estimated_hours < ests_on_parent + estimated_hours |
|
589 |
errors.add :estimated_hours, :greater_than_parent_estimations |
|
590 |
end |
|
591 |
end |
|
576 | 592 |
end |
577 | 593 |
end |
578 | 594 | |
... | ... | |
1200 | 1216 | |
1201 | 1217 |
def recalculate_attributes_for(issue_id) |
1202 | 1218 |
if issue_id && p = Issue.find_by_id(issue_id) |
1203 |
# priority = highest priority of children |
|
1219 |
# priority in children = highest priority of children
|
|
1204 | 1220 |
if priority_position = p.children.maximum("#{IssuePriority.table_name}.position", :joins => :priority) |
1205 |
p.priority = IssuePriority.find_by_position(priority_position) |
|
1221 |
p.priority_on_children = IssuePriority.find_by_position(priority_position)
|
|
1206 | 1222 |
end |
1207 | 1223 | |
1208 |
# start/due dates = lowest/highest dates of children |
|
1209 |
p.start_date = p.children.minimum(:start_date) |
|
1210 |
p.due_date = p.children.maximum(:due_date) |
|
1211 |
if p.start_date && p.due_date && p.due_date < p.start_date
|
|
1212 |
p.start_date, p.due_date = p.due_date, p.start_date
|
|
1224 |
# start/due dates on children = lowest/highest dates of children
|
|
1225 |
p.start_date_on_children = p.children.minimum(:start_date)
|
|
1226 |
p.due_date_on_children = p.children.maximum(:due_date)
|
|
1227 |
if p.start_date_on_children && p.due_date_on_children && p.due_date_on_children < p.start_date_on_children
|
|
1228 |
p.start_date_on_children, p.due_date_on_children = p.due_date_on_children, p.start_date_on_children
|
|
1213 | 1229 |
end |
1214 | ||
1230 |
|
|
1231 |
p_children = Issue.where(:parent_id => p.id) |
|
1232 |
|
|
1215 | 1233 |
# done ratio = weighted average ratio of leaves |
1216 | 1234 |
unless Issue.use_status_for_done_ratio? && p.status && p.status.default_done_ratio |
1217 |
leaves_count = p.leaves.count
|
|
1235 |
leaves_count = p_children.count # 1
|
|
1218 | 1236 |
if leaves_count > 0 |
1219 |
average = p.leaves.average(:estimated_hours).to_f
|
|
1237 |
average = p_children.average(:estimated_hours).to_f # 5
|
|
1220 | 1238 |
if average == 0 |
1221 | 1239 |
average = 1 |
1222 | 1240 |
end |
1223 |
done = p.leaves.sum("COALESCE(estimated_hours, #{average}) * (CASE WHEN is_closed = #{connection.quoted_true} THEN 100 ELSE COALESCE(done_ratio, 0) END)", :joins => :status).to_f
|
|
1224 |
progress = done / (average * leaves_count) |
|
1241 |
done = p_children.sum("COALESCE(estimated_hours, #{average}) * (CASE WHEN is_closed = #{connection.quoted_true} THEN 100 ELSE COALESCE(done_ratio, 0) END)", :joins => :status).to_f
|
|
1242 |
progress = done / p.estimated_hours#(average * leaves_count)
|
|
1225 | 1243 |
p.done_ratio = progress.round |
1226 | 1244 |
end |
1227 | 1245 |
end |
1228 | 1246 | |
1229 |
# estimate = sum of leaves estimates |
|
1230 |
p.estimated_hours = p.leaves.sum(:estimated_hours).to_f
|
|
1231 |
p.estimated_hours = nil if p.estimated_hours == 0.0 |
|
1247 |
# estimate on children = sum of leaves estimates
|
|
1248 |
p.estimated_hours_on_children = p_children.sum(:estimated_hours).to_f
|
|
1249 |
p.estimated_hours_on_children = nil if p.estimated_hours == 0.0
|
|
1232 | 1250 | |
1233 | 1251 |
# ancestors will be recursively updated |
1234 | 1252 |
p.save(:validate => false) |
app/views/issues/show.html.erb (copia de trabajo) | ||
---|---|---|
35 | 35 |
<%= issue_fields_rows do |rows| |
36 | 36 |
rows.left l(:field_status), h(@issue.status.name), :class => 'status' |
37 | 37 |
rows.left l(:field_priority), h(@issue.priority.name), :class => 'priority' |
38 |
rows.left l(:field_priority_on_children), h(@issue.priority_on_children.name), :class => 'priority-on-children' unless @issue.leaf? |
|
38 | 39 | |
39 | 40 |
unless @issue.disabled_core_fields.include?('assigned_to_id') |
40 | 41 |
rows.left l(:field_assigned_to), avatar(@issue.assigned_to, :size => "14").to_s.html_safe + (@issue.assigned_to ? link_to_user(@issue.assigned_to) : "-"), :class => 'assigned-to' |
... | ... | |
48 | 49 | |
49 | 50 |
unless @issue.disabled_core_fields.include?('start_date') |
50 | 51 |
rows.right l(:field_start_date), format_date(@issue.start_date), :class => 'start-date' |
52 |
rows.right l(:field_start_date_on_children), format_date(@issue.start_date_on_children), :class => 'start-date-on-children' unless @issue.leaf? |
|
51 | 53 |
end |
52 | 54 |
unless @issue.disabled_core_fields.include?('due_date') |
53 | 55 |
rows.right l(:field_due_date), format_date(@issue.due_date), :class => 'due-date' |
56 |
rows.right l(:field_due_date_on_children), format_date(@issue.due_date_on_children), :class => 'due-date-on-children' unless @issue.leaf? |
|
54 | 57 |
end |
55 | 58 |
unless @issue.disabled_core_fields.include?('done_ratio') |
56 | 59 |
rows.right l(:field_done_ratio), progress_bar(@issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%"), :class => 'progress' |
... | ... | |
59 | 62 |
unless @issue.estimated_hours.nil? |
60 | 63 |
rows.right l(:field_estimated_hours), l_hours(@issue.estimated_hours), :class => 'estimated-hours' |
61 | 64 |
end |
65 |
unless @issue.estimated_hours_on_children.nil? |
|
66 |
rows.right l(:field_estimated_hours_on_children), l_hours(@issue.estimated_hours_on_children), :class => 'estimated-hours_on_children' unless @issue.leaf? |
|
67 |
end |
|
62 | 68 |
end |
63 | 69 |
if User.current.allowed_to?(:view_time_entries, @project) |
64 | 70 |
rows.right l(:label_spent_time), (@issue.total_spent_hours > 0 ? (link_to l_hours(@issue.total_spent_hours), {:controller => 'timelog', :action => 'index', :project_id => @project, :issue_id => @issue}) : "-"), :class => 'spent-time' |
app/views/issues/_attributes.html.erb (copia de trabajo) | ||
---|---|---|
11 | 11 |
<% end %> |
12 | 12 | |
13 | 13 |
<% if @issue.safe_attribute? 'priority_id' %> |
14 |
<p><%= f.select :priority_id, (@priorities.collect {|p| [p.name, p.id]}), {:required => true}, :disabled => !@issue.leaf? %></p>
|
|
14 |
<p><%= f.select :priority_id, (@priorities.collect {|p| [p.name, p.id]}), {:required => true} %></p> |
|
15 | 15 |
<% end %> |
16 | 16 | |
17 | 17 |
<% if @issue.safe_attribute? 'assigned_to_id' %> |
... | ... | |
47 | 47 |
<% end %> |
48 | 48 | |
49 | 49 |
<% if @issue.safe_attribute? 'start_date' %> |
50 |
<p><%= f.text_field :start_date, :size => 10, :disabled => !@issue.leaf?, :required => @issue.required_attribute?('start_date') %><%= calendar_for('issue_start_date') if @issue.leaf? %></p>
|
|
50 |
<p><%= f.text_field :start_date, :size => 10, :required => @issue.required_attribute?('start_date') %><%= calendar_for('issue_start_date') if @issue.leaf? %></p> |
|
51 | 51 |
<% end %> |
52 | 52 | |
53 | 53 |
<% if @issue.safe_attribute? 'due_date' %> |
54 |
<p><%= f.text_field :due_date, :size => 10, :disabled => !@issue.leaf?, :required => @issue.required_attribute?('due_date') %><%= calendar_for('issue_due_date') if @issue.leaf? %></p>
|
|
54 |
<p><%= f.text_field :due_date, :size => 10, :required => @issue.required_attribute?('due_date') %><%= calendar_for('issue_due_date') if @issue.leaf? %></p> |
|
55 | 55 |
<% end %> |
56 | 56 | |
57 | 57 |
<% if @issue.safe_attribute? 'estimated_hours' %> |
58 |
<p><%= f.text_field :estimated_hours, :size => 3, :disabled => !@issue.leaf?, :required => @issue.required_attribute?('estimated_hours') %> <%= l(:field_hours) %></p>
|
|
58 |
<p><%= f.text_field :estimated_hours, :size => 3, :required => @issue.required_attribute?('estimated_hours') %> <%= l(:field_hours) %></p> |
|
59 | 59 |
<% end %> |
60 | 60 | |
61 | 61 |
<% if @issue.safe_attribute?('done_ratio') && @issue.leaf? && Issue.use_field_for_done_ratio? %> |
config/locales/en.yml (copia de trabajo) | ||
---|---|---|
129 | 129 |
not_same_project: "doesn't belong to the same project" |
130 | 130 |
circular_dependency: "This relation would create a circular dependency" |
131 | 131 |
cant_link_an_issue_with_a_descendant: "An issue cannot be linked to one of its subtasks" |
132 |
|
|
133 |
models: |
|
134 |
# Overrides default messages |
|
135 |
issue: |
|
136 |
attributes: |
|
137 |
estimated_hours: |
|
138 |
greater_than_parent_estimations: "is over the parent issue's estimation" |
|
139 |
less_than_children_estimations: "is under the estimations of subtasks" |
|
140 |
no_parent_estimations: "can't be present if parent issue's estimation is undefined" |
|
132 | 141 | |
133 | 142 |
actionview_instancetag_blank_option: Please select |
134 | 143 | |
... | ... | |
332 | 341 |
field_timeout: "Timeout (in seconds)" |
333 | 342 |
field_board_parent: Parent forum |
334 | 343 |
field_private_notes: Private notes |
344 |
field_due_date_on_children: Due date on subtasks |
|
345 |
field_start_date_on_children: Start date on subtasks |
|
346 |
field_priority_on_children: Highest priority on subtasks |
|
347 |
field_estimated_hours_on_children: Estimated hours on subtasks |
|
335 | 348 | |
336 | 349 |
setting_app_title: Application title |
337 | 350 |
setting_app_subtitle: Application subtitle |
config/locales/es.yml (copia de trabajo) | ||
---|---|---|
141 | 141 | |
142 | 142 |
models: |
143 | 143 |
# Overrides default messages |
144 | ||
144 |
issue: |
|
145 |
attributes: |
|
146 |
estimated_hours: |
|
147 |
greater_than_parent_estimations: "sobrepasa estimaciones de la tarea padre" |
|
148 |
less_than_children_estimations: "bajo estimaciones de subtareas" |
|
149 |
no_parent_estimations: "no puede estar presente si tarea padre no lo tiene definido" |
|
145 | 150 |
attributes: |
146 | 151 |
# Overrides model and default messages. |
147 | ||
152 |
|
|
148 | 153 |
direction: ltr |
149 | 154 |
date: |
150 | 155 |
formats: |
... | ... | |
275 | 280 |
field_done_ratio: "% Realizado" |
276 | 281 |
field_downloads: Descargas |
277 | 282 |
field_due_date: Fecha fin |
283 |
field_due_date_on_children: Fecha fin en subtareas |
|
278 | 284 |
field_effective_date: Fecha |
279 | 285 |
field_estimated_hours: Tiempo estimado |
286 |
field_estimated_hours_on_children: Tiempo estimado en subtareas |
|
280 | 287 |
field_field_format: Formato |
281 | 288 |
field_filename: Fichero |
282 | 289 |
field_filesize: Tamaño |
... | ... | |
315 | 322 |
field_port: Puerto |
316 | 323 |
field_possible_values: Valores posibles |
317 | 324 |
field_priority: Prioridad |
325 |
field_priority_on_children: Prioridad más alta en subtareas |
|
318 | 326 |
field_project: Proyecto |
319 | 327 |
field_redirect_existing_links: Redireccionar enlaces existentes |
320 | 328 |
field_regexp: Expresión regular |
... | ... | |
322 | 330 |
field_searchable: Incluir en las búsquedas |
323 | 331 |
field_spent_on: Fecha |
324 | 332 |
field_start_date: Fecha de inicio |
333 |
field_start_date_on_children: Fecha de inicio de subtareas |
|
325 | 334 |
field_start_page: Página principal |
326 | 335 |
field_status: Estado |
327 | 336 |
field_subject: Asunto |
db/migrate/20130222154546_add_due_date_on_children_and_priority_id_on_children_and_start_date_on_children_and_estimated_hours_on_children_to_issue.rb (revisión: 0) | ||
---|---|---|
1 |
class AddDueDateOnChildrenAndPriorityIdOnChildrenAndStartDateOnChildrenAndEstimatedHoursOnChildrenToIssue < ActiveRecord::Migration |
|
2 |
def change |
|
3 |
add_column :issues, :due_date_on_children, :date |
|
4 |
add_column :issues, :start_date_on_children, :date |
|
5 |
add_column :issues, :priority_id_on_children, :integer, :default => 0, :null => false |
|
6 |
add_column :issues, :estimated_hours_on_children, :float |
|
7 |
add_index :issues, :priority_id_on_children |
|
8 |
Issue.all.each do |i| |
|
9 |
# Trigger update_parent_attributes |
|
10 |
i.update_attributes(:parent_id => i.parent_id) |
|
11 |
end |
|
12 |
end |
|
13 |
end |