Feature #24277 » 01_add_remaining_hours_field_15945.patch
app/helpers/issues_helper.rb | ||
---|---|---|
118 | 118 |
end |
119 | 119 |
end |
120 | 120 | |
121 |
def issue_remaining_hours_details(issue) |
|
122 |
if issue.total_remaining_hours.present? |
|
123 |
if issue.total_remaining_hours == issue.remaining_hours |
|
124 |
l_hours_short(issue.remaining_hours) |
|
125 |
else |
|
126 |
s = issue.remaining_hours.present? ? l_hours_short(issue.remaining_hours) : "" |
|
127 |
s << " (#{l(:label_total)}: #{l_hours_short(issue.total_remaining_hours)})" |
|
128 |
s.html_safe |
|
129 |
end |
|
130 |
end |
|
131 |
end |
|
132 | ||
121 | 133 |
def issue_spent_hours_details(issue) |
122 | 134 |
if issue.total_spent_hours > 0 |
123 | 135 |
path = project_time_entries_path(issue.project, :issue_id => "~#{issue.id}") |
... | ... | |
345 | 357 |
value = find_name_by_reflection(field, detail.value) |
346 | 358 |
old_value = find_name_by_reflection(field, detail.old_value) |
347 | 359 | |
348 |
when 'estimated_hours' |
|
360 |
when 'estimated_hours', 'remaining_hours'
|
|
349 | 361 |
value = l_hours_short(detail.value.to_f) unless detail.value.blank? |
350 | 362 |
old_value = l_hours_short(detail.old_value.to_f) unless detail.old_value.blank? |
351 | 363 |
app/models/issue.rb | ||
---|---|---|
71 | 71 |
validates_length_of :subject, :maximum => 255 |
72 | 72 |
validates_inclusion_of :done_ratio, :in => 0..100 |
73 | 73 |
validates :estimated_hours, :numericality => {:greater_than_or_equal_to => 0, :allow_nil => true, :message => :invalid} |
74 |
validates :remaining_hours, :numericality => {:greater_than_or_equal_to => 0, :allow_nil => true, :message => :invalid} |
|
74 | 75 |
validates :start_date, :date => true |
75 | 76 |
validates :due_date, :date => true |
76 | 77 |
validate :validate_issue, :validate_required_fields |
... | ... | |
107 | 108 |
before_validation :clear_disabled_fields |
108 | 109 |
before_create :default_assign |
109 | 110 |
before_save :close_duplicates, :update_done_ratio_from_issue_status, |
110 |
:force_updated_on_change, :update_closed_on, :set_assigned_to_was |
|
111 |
:force_updated_on_change, :update_closed_on, :set_assigned_to_was, :update_remaining_hours
|
|
111 | 112 |
after_save {|issue| issue.send :after_project_change if !issue.id_changed? && issue.project_id_changed?} |
112 | 113 |
after_save :reschedule_following_issues, :update_nested_set_attributes, |
113 | 114 |
:update_parent_attributes, :delete_selected_attachments, :create_journal |
... | ... | |
244 | 245 |
@spent_hours = nil |
245 | 246 |
@total_spent_hours = nil |
246 | 247 |
@total_estimated_hours = nil |
248 |
@total_remaining_hours = nil |
|
247 | 249 |
base_reload(*args) |
248 | 250 |
end |
249 | 251 | |
... | ... | |
430 | 432 |
write_attribute :estimated_hours, (h.is_a?(String) ? h.to_hours : h) |
431 | 433 |
end |
432 | 434 | |
435 |
def remaining_hours=(h) |
|
436 |
h = h.is_a?(String) ? h.to_hours : h |
|
437 |
# remaining time cannot be less than zero |
|
438 |
h = 0 if !h.nil? && h < 0 |
|
439 |
write_attribute :remaining_hours, h |
|
440 |
end |
|
441 | ||
433 | 442 |
safe_attributes 'project_id', |
434 | 443 |
'tracker_id', |
435 | 444 |
'status_id', |
... | ... | |
443 | 452 |
'due_date', |
444 | 453 |
'done_ratio', |
445 | 454 |
'estimated_hours', |
455 |
'remaining_hours', |
|
446 | 456 |
'custom_field_values', |
447 | 457 |
'custom_fields', |
448 | 458 |
'lock_version', |
... | ... | |
1030 | 1040 |
end |
1031 | 1041 |
end |
1032 | 1042 | |
1043 |
def remaining_hours |
|
1044 |
@remaining_hours = read_attribute(:remaining_hours) |
|
1045 |
if @remaining_hours.nil? && estimated_hours |
|
1046 |
@remaining_hours = estimated_hours |
|
1047 |
else |
|
1048 |
@remaining_hours |
|
1049 |
end |
|
1050 |
end |
|
1051 | ||
1052 |
def total_remaining_hours |
|
1053 |
if leaf? |
|
1054 |
remaining_hours |
|
1055 |
else |
|
1056 |
@total_remaining_hours ||= self_and_descendants.sum(:remaining_hours) |
|
1057 |
end |
|
1058 |
end |
|
1059 | ||
1033 | 1060 |
def relations |
1034 | 1061 |
@relations ||= IssueRelation::Relations.new(self, (relations_from + relations_to).sort) |
1035 | 1062 |
end |
... | ... | |
1703 | 1730 |
end |
1704 | 1731 |
end |
1705 | 1732 | |
1733 |
# Callback for setting remaining time to zero when the issue is closed. |
|
1734 |
def update_remaining_hours |
|
1735 |
if closing? && safe_attribute?('remaining_hours') && self.remaining_hours.to_f > 0 |
|
1736 |
self.remaining_hours = 0 |
|
1737 |
end |
|
1738 |
end |
|
1739 | ||
1706 | 1740 |
# Saves the changes in a Journal |
1707 | 1741 |
# Called after_save |
1708 | 1742 |
def create_journal |
app/models/issue_import.rb | ||
---|---|---|
158 | 158 |
if estimated_hours = row_value(row, 'estimated_hours') |
159 | 159 |
attributes['estimated_hours'] = estimated_hours |
160 | 160 |
end |
161 |
if remaining_hours = row_value(row, 'remaining_hours') |
|
162 |
attributes['remaining_hours'] = remaining_hours |
|
163 |
end |
|
161 | 164 |
if done_ratio = row_value(row, 'done_ratio') |
162 | 165 |
attributes['done_ratio'] = done_ratio |
163 | 166 |
end |
app/models/issue_query.rb | ||
---|---|---|
36 | 36 |
QueryColumn.new(:start_date, :sortable => "#{Issue.table_name}.start_date"), |
37 | 37 |
QueryColumn.new(:due_date, :sortable => "#{Issue.table_name}.due_date"), |
38 | 38 |
QueryColumn.new(:estimated_hours, :sortable => "#{Issue.table_name}.estimated_hours", :totalable => true), |
39 |
QueryColumn.new(:remaining_hours, :sortable => "#{Issue.table_name}.remaining_hours", :totalable => true), |
|
39 | 40 |
QueryColumn.new(:total_estimated_hours, |
40 | 41 |
:sortable => "COALESCE((SELECT SUM(estimated_hours) FROM #{Issue.table_name} subtasks" + |
41 | 42 |
" WHERE subtasks.root_id = #{Issue.table_name}.root_id AND subtasks.lft >= #{Issue.table_name}.lft AND subtasks.rgt <= #{Issue.table_name}.rgt), 0)", |
42 | 43 |
:default_order => 'desc'), |
44 |
QueryColumn.new(:total_remaining_hours, |
|
45 |
:sortable => "COALESCE((SELECT SUM(remaining_hours) FROM #{Issue.table_name} subtasks" + |
|
46 |
" WHERE subtasks.root_id = #{Issue.table_name}.root_id AND subtasks.lft >= #{Issue.table_name}.lft AND subtasks.rgt <= #{Issue.table_name}.rgt), 0)", |
|
47 |
:default_order => 'desc'), |
|
43 | 48 |
QueryColumn.new(:done_ratio, :sortable => "#{Issue.table_name}.done_ratio", :groupable => true), |
44 | 49 |
QueryColumn.new(:created_on, :sortable => "#{Issue.table_name}.created_on", :default_order => 'desc'), |
45 | 50 |
QueryColumn.new(:closed_on, :sortable => "#{Issue.table_name}.closed_on", :default_order => 'desc'), |
... | ... | |
174 | 179 |
add_available_filter "start_date", :type => :date |
175 | 180 |
add_available_filter "due_date", :type => :date |
176 | 181 |
add_available_filter "estimated_hours", :type => :float |
182 |
add_available_filter "remaining_hours", :type => :float |
|
177 | 183 |
add_available_filter "done_ratio", :type => :integer |
178 | 184 | |
179 | 185 |
if User.current.allowed_to?(:set_issues_private, nil, :global => true) || |
... | ... | |
285 | 291 |
map_total(scope.sum(:estimated_hours)) {|t| t.to_f.round(2)} |
286 | 292 |
end |
287 | 293 | |
294 |
# Returns sum of all the issue's remaining_hours |
|
295 |
def total_for_remaining_hours(scope) |
|
296 |
map_total(scope.sum(:remaining_hours)) {|t| t.to_f.round(2)} |
|
297 |
end |
|
298 | ||
288 | 299 |
# Returns sum of all the issue's time entries hours |
289 | 300 |
def total_for_spent_hours(scope) |
290 | 301 |
total = if group_by_column.try(:name) == :project |
app/models/mail_handler.rb | ||
---|---|---|
424 | 424 |
'start_date' => get_keyword(:start_date, :format => '\d{4}-\d{2}-\d{2}'), |
425 | 425 |
'due_date' => get_keyword(:due_date, :format => '\d{4}-\d{2}-\d{2}'), |
426 | 426 |
'estimated_hours' => get_keyword(:estimated_hours), |
427 |
'remaining_hours' => get_keyword(:remaining_hours), |
|
427 | 428 |
'done_ratio' => get_keyword(:done_ratio, :format => '(\d|10)?0') |
428 | 429 |
}.delete_if {|k, v| v.blank? } |
429 | 430 |
app/models/tracker.rb | ||
---|---|---|
21 | 21 |
CORE_FIELDS_UNDISABLABLE = %w(project_id tracker_id subject description priority_id is_private).freeze |
22 | 22 |
# Fields that can be disabled |
23 | 23 |
# Other (future) fields should be appended, not inserted! |
24 |
CORE_FIELDS = %w(assigned_to_id category_id fixed_version_id parent_issue_id start_date due_date estimated_hours done_ratio).freeze |
|
24 |
CORE_FIELDS = %w(assigned_to_id category_id fixed_version_id parent_issue_id start_date due_date estimated_hours remaining_hours done_ratio).freeze
|
|
25 | 25 |
CORE_FIELDS_ALL = (CORE_FIELDS_UNDISABLABLE + CORE_FIELDS).freeze |
26 | 26 | |
27 | 27 |
before_destroy :check_integrity |
app/views/imports/_fields_mapping.html.erb | ||
---|---|---|
82 | 82 |
<%= mapping_select_tag @import, 'estimated_hours' %> |
83 | 83 |
</p> |
84 | 84 |
<p> |
85 |
<label><%= l(:field_remaining_hours) %></label> |
|
86 |
<%= mapping_select_tag @import, 'remaining_hours' %> |
|
87 |
</p> |
|
88 |
<p> |
|
85 | 89 |
<label><%= l(:field_done_ratio) %></label> |
86 | 90 |
<%= mapping_select_tag @import, 'done_ratio' %> |
87 | 91 |
</p> |
app/views/issues/_attributes.html.erb | ||
---|---|---|
64 | 64 |
</p> |
65 | 65 |
<% end %> |
66 | 66 | |
67 |
<% if @issue.safe_attribute?('done_ratio') && Issue.use_field_for_done_ratio? %> |
|
68 |
<p><%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }), :required => @issue.required_attribute?('done_ratio') %></p> |
|
69 |
<% end %> |
|
70 | ||
67 | 71 |
<% if @issue.safe_attribute? 'estimated_hours' %> |
68 | 72 |
<p><%= f.text_field :estimated_hours, :size => 3, :required => @issue.required_attribute?('estimated_hours') %> <%= l(:field_hours) %></p> |
69 | 73 |
<% end %> |
70 | 74 | |
71 |
<% if @issue.safe_attribute?('done_ratio') && Issue.use_field_for_done_ratio? %>
|
|
72 |
<p><%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }), :required => @issue.required_attribute?('done_ratio') %></p>
|
|
75 |
<% if @issue.safe_attribute? 'remaining_hours' %>
|
|
76 |
<p><%= f.text_field :remaining_hours, :size => 3, :required => @issue.required_attribute?('remaining_hours') %> <%= l(:field_hours) %></p>
|
|
73 | 77 |
<% end %> |
78 | ||
74 | 79 |
</div> |
75 | 80 |
</div> |
76 | 81 |
app/views/issues/_edit.html.erb | ||
---|---|---|
31 | 31 |
<fieldset><legend><%= l(:field_notes) %></legend> |
32 | 32 |
<%= f.text_area :notes, :cols => 60, :rows => 10, :class => 'wiki-edit', :no_label => true %> |
33 | 33 |
<%= wikitoolbar_for 'issue_notes' %> |
34 |
|
|
34 | ||
35 | 35 |
<% if @issue.safe_attribute? 'private_notes' %> |
36 | 36 |
<%= f.check_box :private_notes, :no_label => true %> <label for="issue_private_notes"><%= l(:field_private_notes) %></label> |
37 | 37 |
<% end %> |
38 |
|
|
38 | ||
39 | 39 |
<%= call_hook(:view_issues_edit_notes_bottom, { :issue => @issue, :notes => @notes, :form => f }) %> |
40 | 40 |
</fieldset> |
41 | 41 |
app/views/issues/bulk_edit.html.erb | ||
---|---|---|
170 | 170 |
</p> |
171 | 171 |
<% end %> |
172 | 172 | |
173 |
<% if @safe_attributes.include?('remaining_hours') %> |
|
174 |
<p> |
|
175 |
<label for='issue_remaining_hours'><%= l(:field_remaining_hours) %></label> |
|
176 |
<%= text_field_tag 'issue[remaining_hours]', '', :value => @issue_params[:remaining_hours], :size => 10 %> |
|
177 |
<label class="inline"><%= check_box_tag 'issue[remaining_hours]', 'none', (@issue_params[:remaining_hours] == 'none'), :id => nil, :data => {:disables => '#issue_remaining_hours'} %><%= l(:button_clear) %></label> |
|
178 |
</p> |
|
179 |
<% end %> |
|
180 | ||
173 | 181 |
<% if @safe_attributes.include?('done_ratio') && Issue.use_field_for_done_ratio? %> |
174 | 182 |
<p> |
175 | 183 |
<label for='issue_done_ratio'><%= l(:field_done_ratio) %></label> |
app/views/issues/index.api.rsb | ||
---|---|---|
19 | 19 |
api.done_ratio issue.done_ratio |
20 | 20 |
api.is_private issue.is_private |
21 | 21 |
api.estimated_hours issue.estimated_hours |
22 |
api.remaining_hours issue.remaining_hours |
|
22 | 23 | |
23 | 24 |
render_api_custom_values issue.visible_custom_field_values, api |
24 | 25 |
app/views/issues/show.api.rsb | ||
---|---|---|
17 | 17 |
api.done_ratio @issue.done_ratio |
18 | 18 |
api.is_private @issue.is_private |
19 | 19 |
api.estimated_hours @issue.estimated_hours |
20 |
api.remaining_hours @issue.remaining_hours |
|
20 | 21 |
api.total_estimated_hours @issue.total_estimated_hours |
22 |
api.total_remaining_hours @issue.total_remaining_hours |
|
21 | 23 |
if User.current.allowed_to?(:view_time_entries, @project) |
22 | 24 |
api.spent_hours(@issue.spent_hours) |
23 | 25 |
api.total_spent_hours(@issue.total_spent_hours) |
app/views/issues/show.html.erb | ||
---|---|---|
60 | 60 |
unless @issue.disabled_core_fields.include?('estimated_hours') |
61 | 61 |
rows.right l(:field_estimated_hours), issue_estimated_hours_details(@issue), :class => 'estimated-hours' |
62 | 62 |
end |
63 |
unless @issue.disabled_core_fields.include?('remaining_hours') |
|
64 |
rows.right l(:field_remaining_hours), issue_remaining_hours_details(@issue), :class => 'remaining-hours' |
|
65 |
end |
|
63 | 66 |
if User.current.allowed_to_view_all_time_entries?(@project) |
64 | 67 |
if @issue.total_spent_hours > 0 |
65 | 68 |
rows.right l(:label_spent_time), issue_spent_hours_details(@issue), :class => 'spent-time' |
config/locales/en.yml | ||
---|---|---|
365 | 365 |
field_default_version: Default version |
366 | 366 |
field_remote_ip: IP address |
367 | 367 |
field_textarea_font: Font used for text areas |
368 |
field_remaining_hours: Remaining time |
|
369 |
field_total_remaining_hours: Total remaining time |
|
368 | 370 | |
369 | 371 |
setting_app_title: Application title |
370 | 372 |
setting_app_subtitle: Application subtitle |
db/migrate/20160920184857_add_remaining_hours_to_issues.rb | ||
---|---|---|
1 |
class AddRemainingHoursToIssues < ActiveRecord::Migration |
|
2 |
def self.up |
|
3 |
add_column :issues, :remaining_hours, :float |
|
4 |
Issue.where("estimated_hours > ?", 0).update_all("remaining_hours = estimated_hours") |
|
5 |
end |
|
6 | ||
7 |
def self.down |
|
8 |
remove_column :issues, :remaining_hours |
|
9 |
end |
|
10 |
end |
test/fixtures/mail_handler/ticket_on_given_project.eml | ||
---|---|---|
18 | 18 |
X-Mailer: Microsoft Outlook Express 6.00.2900.2869 |
19 | 19 |
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2869 |
20 | 20 | |
21 |
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas imperdiet
|
|
22 |
turpis et odio. Integer eget pede vel dolor euismod varius. Phasellus
|
|
23 |
blandit eleifend augue. Nulla facilisi. Duis id diam. Class aptent taciti
|
|
24 |
sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In
|
|
25 |
in urna sed tellus aliquet lobortis. Morbi scelerisque tortor in dolor. Cras
|
|
26 |
sagittis odio eu lacus. Aliquam sem tortor, consequat sit amet, vestibulum
|
|
27 |
id, iaculis at, lectus. Fusce tortor libero, congue ut, euismod nec, luctus
|
|
28 |
eget, eros. Pellentesque tortor enim, feugiat in, dignissim eget, tristique
|
|
29 |
sed, mauris --- Pellentesque habitant morbi tristique senectus et netus et
|
|
30 |
malesuada fames ac turpis egestas. Quisque sit amet libero. In hac habitasse
|
|
21 |
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas imperdiet |
|
22 |
turpis et odio. Integer eget pede vel dolor euismod varius. Phasellus |
|
23 |
blandit eleifend augue. Nulla facilisi. Duis id diam. Class aptent taciti |
|
24 |
sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In |
|
25 |
in urna sed tellus aliquet lobortis. Morbi scelerisque tortor in dolor. Cras |
|
26 |
sagittis odio eu lacus. Aliquam sem tortor, consequat sit amet, vestibulum |
|
27 |
id, iaculis at, lectus. Fusce tortor libero, congue ut, euismod nec, luctus |
|
28 |
eget, eros. Pellentesque tortor enim, feugiat in, dignissim eget, tristique |
|
29 |
sed, mauris --- Pellentesque habitant morbi tristique senectus et netus et |
|
30 |
malesuada fames ac turpis egestas. Quisque sit amet libero. In hac habitasse |
|
31 | 31 |
platea dictumst. |
32 | 32 | |
33 | 33 |
Project: onlinestore |
... | ... | |
37 | 37 |
Assigned to: John Smith |
38 | 38 |
fixed version: alpha |
39 | 39 |
estimated hours: 2.5 |
40 |
remaining hours: 1 |
|
40 | 41 |
done ratio: 30 |
41 | 42 | |
42 | 43 |
--- This line starts with a delimiter and should not be stripped |
... | ... | |
51 | 52 | |
52 | 53 |
This paragraph is after the delimiter so it shouldn't appear. |
53 | 54 | |
54 |
Nulla et nunc. Duis pede. Donec et ipsum. Nam ut dui tincidunt neque
|
|
55 |
sollicitudin iaculis. Duis vitae dolor. Vestibulum eget massa. Sed lorem.
|
|
56 |
Nullam volutpat cursus erat. Cras felis dolor, lacinia quis, rutrum et,
|
|
57 |
dictum et, ligula. Sed erat nibh, gravida in, accumsan non, placerat sed,
|
|
58 |
massa. Sed sodales, ante fermentum ultricies sollicitudin, massa leo
|
|
55 |
Nulla et nunc. Duis pede. Donec et ipsum. Nam ut dui tincidunt neque |
|
56 |
sollicitudin iaculis. Duis vitae dolor. Vestibulum eget massa. Sed lorem. |
|
57 |
Nullam volutpat cursus erat. Cras felis dolor, lacinia quis, rutrum et, |
|
58 |
dictum et, ligula. Sed erat nibh, gravida in, accumsan non, placerat sed, |
|
59 |
massa. Sed sodales, ante fermentum ultricies sollicitudin, massa leo |
|
59 | 60 |
pulvinar dui, a gravida orci mi eget odio. Nunc a lacus. |
60 | 61 |
test/functional/issues_controller_test.rb | ||
---|---|---|
561 | 561 |
str_big5 = "\xa4@\xa4\xeb".force_encoding('Big5') |
562 | 562 |
issue = Issue.generate!(:subject => str_utf8) |
563 | 563 | |
564 |
get :index, :project_id => 1,
|
|
565 |
:f => ['subject'],
|
|
564 |
get :index, :project_id => 1, |
|
565 |
:f => ['subject'], |
|
566 | 566 |
:op => '=', :values => [str_utf8], |
567 | 567 |
:format => 'csv' |
568 | 568 |
assert_equal 'text/csv; header=present', @response.content_type |
... | ... | |
580 | 580 |
str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85".force_encoding('UTF-8') |
581 | 581 |
issue = Issue.generate!(:subject => str_utf8) |
582 | 582 | |
583 |
get :index, :project_id => 1,
|
|
584 |
:f => ['subject'],
|
|
583 |
get :index, :project_id => 1, |
|
584 |
:f => ['subject'], |
|
585 | 585 |
:op => '=', :values => [str_utf8], |
586 | 586 |
:c => ['status', 'subject'], |
587 | 587 |
:format => 'csv', |
... | ... | |
603 | 603 |
str1 = "test_index_csv_tw" |
604 | 604 |
issue = Issue.generate!(:subject => str1, :estimated_hours => '1234.5') |
605 | 605 | |
606 |
get :index, :project_id => 1,
|
|
607 |
:f => ['subject'],
|
|
606 |
get :index, :project_id => 1, |
|
607 |
:f => ['subject'], |
|
608 | 608 |
:op => '=', :values => [str1], |
609 | 609 |
:c => ['estimated_hours', 'subject'], |
610 | 610 |
:format => 'csv', |
... | ... | |
620 | 620 |
str1 = "test_index_csv_fr" |
621 | 621 |
issue = Issue.generate!(:subject => str1, :estimated_hours => '1234.5') |
622 | 622 | |
623 |
get :index, :project_id => 1,
|
|
624 |
:f => ['subject'],
|
|
623 |
get :index, :project_id => 1, |
|
624 |
:f => ['subject'], |
|
625 | 625 |
:op => '=', :values => [str1], |
626 | 626 |
:c => ['estimated_hours', 'subject'], |
627 | 627 |
:format => 'csv', |
... | ... | |
696 | 696 |
assert_response :success |
697 | 697 |
end |
698 | 698 |
end |
699 |
|
|
699 | ||
700 | 700 |
def test_index_sort_by_assigned_to |
701 | 701 |
get :index, :sort => 'assigned_to' |
702 | 702 |
assert_response :success |
... | ... | |
705 | 705 |
assert_equal assignees.sort, assignees |
706 | 706 |
assert_select 'table.issues.sort-by-assigned-to.sort-asc' |
707 | 707 |
end |
708 |
|
|
708 | ||
709 | 709 |
def test_index_sort_by_assigned_to_desc |
710 | 710 |
get :index, :sort => 'assigned_to:desc' |
711 | 711 |
assert_response :success |
... | ... | |
762 | 762 |
assert_equal hours.sort.reverse, hours |
763 | 763 |
end |
764 | 764 | |
765 |
def test_index_sort_by_total_remaining_hours |
|
766 |
get :index, :sort => 'total_remaining_hours:desc' |
|
767 |
assert_response :success |
|
768 |
hours = assigns(:issues).collect(&:total_remaining_hours) |
|
769 |
assert_equal hours.sort.reverse, hours |
|
770 |
end |
|
771 | ||
765 | 772 |
def test_index_sort_by_user_custom_field |
766 | 773 |
cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'user') |
767 | 774 |
CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '2') |
... | ... | |
899 | 906 |
assert_select 'table.issues td.total_estimated_hours' |
900 | 907 |
end |
901 | 908 | |
909 |
def test_index_with_total_remaining_hours_column |
|
910 |
get :index, :set_filter => 1, :c => %w(subject total_remaining_hours) |
|
911 |
assert_select 'table.issues td.total_remaining_hours' |
|
912 |
end |
|
913 | ||
902 | 914 |
def test_index_should_not_show_spent_hours_column_without_permission |
903 | 915 |
Role.anonymous.remove_permission! :view_time_entries |
904 | 916 |
get :index, :set_filter => 1, :c => %w(subject spent_hours) |
... | ... | |
982 | 994 |
assert_select 'input[type=checkbox][name=?][value=estimated_hours][checked=checked]', 't[]' |
983 | 995 |
end |
984 | 996 | |
997 |
def test_index_with_remaining_hours_total |
|
998 |
Issue.delete_all |
|
999 |
Issue.generate!(:remaining_hours => 5.4) |
|
1000 |
Issue.generate!(:remaining_hours => 1.1) |
|
1001 | ||
1002 |
get :index, :t => %w(remaining_hours) |
|
1003 |
assert_response :success |
|
1004 |
assert_select '.query-totals' |
|
1005 |
assert_select '.total-for-remaining-hours span.value', :text => '6.50' |
|
1006 |
assert_select 'input[type=checkbox][name=?][value=remaining_hours][checked=checked]', 't[]' |
|
1007 |
end |
|
1008 | ||
985 | 1009 |
def test_index_with_grouped_query_and_estimated_hours_total |
986 | 1010 |
Issue.delete_all |
987 | 1011 |
Issue.generate!(:estimated_hours => 5.5, :category_id => 1) |
... | ... | |
1093 | 1117 |
def test_index_should_not_include_new_issue_tab_for_project_without_trackers |
1094 | 1118 |
with_settings :new_item_menu_tab => '1' do |
1095 | 1119 |
Project.find(1).trackers.clear |
1096 |
|
|
1120 | ||
1097 | 1121 |
@request.session[:user_id] = 2 |
1098 | 1122 |
get :index, :project_id => 1 |
1099 | 1123 |
assert_select '#main-menu a.new-issue', 0 |
... | ... | |
1105 | 1129 |
role = Role.find(1) |
1106 | 1130 |
role.remove_permission! :add_issues |
1107 | 1131 |
role.add_permission! :copy_issues |
1108 |
|
|
1132 | ||
1109 | 1133 |
@request.session[:user_id] = 2 |
1110 | 1134 |
get :index, :project_id => 1 |
1111 | 1135 |
assert_select '#main-menu a.new-issue', 0 |
... | ... | |
1614 | 1638 |
end |
1615 | 1639 | |
1616 | 1640 |
def test_show_export_to_pdf |
1617 |
issue = Issue.find(3)
|
|
1641 |
issue = Issue.find(3) |
|
1618 | 1642 |
assert issue.relations.select{|r| r.other_issue(issue).visible?}.present? |
1619 | 1643 |
get :show, :id => 3, :format => 'pdf' |
1620 | 1644 |
assert_response :success |
... | ... | |
2062 | 2086 |
get :new, :project_id => 'invalid' |
2063 | 2087 |
assert_response 404 |
2064 | 2088 |
end |
2065 |
|
|
2089 | ||
2066 | 2090 |
def test_new_with_parent_id_should_only_propose_valid_trackers |
2067 | 2091 |
@request.session[:user_id] = 2 |
2068 | 2092 |
t = Tracker.find(3) |
... | ... | |
2158 | 2182 |
:priority_id => 5, |
2159 | 2183 |
:start_date => '2010-11-07', |
2160 | 2184 |
:estimated_hours => '', |
2185 |
:remaining_hours => '', |
|
2161 | 2186 |
:custom_field_values => {'2' => 'Value for field 2'}} |
2162 | 2187 |
end |
2163 | 2188 |
end |
... | ... | |
2170 | 2195 |
assert_equal 2, issue.status_id |
2171 | 2196 |
assert_equal Date.parse('2010-11-07'), issue.start_date |
2172 | 2197 |
assert_nil issue.estimated_hours |
2198 |
assert_nil issue.remaining_hours |
|
2173 | 2199 |
v = issue.custom_values.where(:custom_field_id => 2).first |
2174 | 2200 |
assert_not_nil v |
2175 | 2201 |
assert_equal 'Value for field 2', v.value |
... | ... | |
2611 | 2637 |
:custom_field_values => {'2' => 'Value for field 2'}} |
2612 | 2638 |
end |
2613 | 2639 |
assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id |
2614 |
|
|
2640 | ||
2615 | 2641 |
assert_equal 1, ActionMailer::Base.deliveries.size |
2616 | 2642 |
end |
2617 | 2643 |
end |
... | ... | |
3160 | 3186 |
def test_get_edit_should_display_the_time_entry_form_with_log_time_permission |
3161 | 3187 |
@request.session[:user_id] = 2 |
3162 | 3188 |
Role.find_by_name('Manager').update_attribute :permissions, [:view_issues, :edit_issues, :log_time] |
3163 |
|
|
3189 | ||
3164 | 3190 |
get :edit, :id => 1 |
3165 | 3191 |
assert_select 'input[name=?]', 'time_entry[hours]' |
3166 | 3192 |
end |
... | ... | |
3168 | 3194 |
def test_get_edit_should_not_display_the_time_entry_form_without_log_time_permission |
3169 | 3195 |
@request.session[:user_id] = 2 |
3170 | 3196 |
Role.find_by_name('Manager').remove_permission! :log_time |
3171 |
|
|
3197 | ||
3172 | 3198 |
get :edit, :id => 1 |
3173 | 3199 |
assert_select 'input[name=?]', 'time_entry[hours]', 0 |
3174 | 3200 |
end |
... | ... | |
3813 | 3839 |
assert_response :redirect |
3814 | 3840 |
assert_redirected_to :controller => 'issues', :action => 'show', :id => issue.id |
3815 | 3841 |
end |
3816 |
|
|
3842 | ||
3817 | 3843 |
def test_put_update_should_redirect_with_previous_and_next_issue_ids_params |
3818 | 3844 |
@request.session[:user_id] = 2 |
3819 | 3845 | |
... | ... | |
3867 | 3893 | |
3868 | 3894 |
assert_select 'select[name=?]', 'issue[project_id]' |
3869 | 3895 |
assert_select 'input[name=?]', 'issue[parent_issue_id]' |
3870 |
|
|
3896 | ||
3871 | 3897 |
# Project specific custom field, date type |
3872 | 3898 |
field = CustomField.find(9) |
3873 | 3899 |
assert !field.is_for_all? |
3874 | 3900 |
assert_equal 'date', field.field_format |
3875 | 3901 |
assert_select 'input[name=?]', 'issue[custom_field_values][9]' |
3876 |
|
|
3902 | ||
3877 | 3903 |
# System wide custom field |
3878 | 3904 |
assert CustomField.find(1).is_for_all? |
3879 | 3905 |
assert_select 'select[name=?]', 'issue[custom_field_values][1]' |
3880 |
|
|
3906 | ||
3881 | 3907 |
# Be sure we don't display inactive IssuePriorities |
3882 | 3908 |
assert ! IssuePriority.find(15).active? |
3883 | 3909 |
assert_select 'select[name=?]', 'issue[priority_id]' do |
... | ... | |
4064 | 4090 |
:issue => {:priority_id => '', |
4065 | 4091 |
:assigned_to_id => group.id, |
4066 | 4092 |
:custom_field_values => {'2' => ''}} |
4067 |
|
|
4093 | ||
4068 | 4094 |
assert_response 302 |
4069 | 4095 |
assert_equal [group, group], Issue.where(:id => [1, 2]).collect {|i| i.assigned_to} |
4070 | 4096 |
end |
... | ... | |
4208 | 4234 |
assert_equal 4.25, Issue.find(2).estimated_hours |
4209 | 4235 |
end |
4210 | 4236 | |
4237 |
def test_bulk_update_remaining_hours |
|
4238 |
@request.session[:user_id] = 2 |
|
4239 |
post :bulk_update, :ids => [1, 2], :issue => {:remaining_hours => 4.15} |
|
4240 | ||
4241 |
assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook' |
|
4242 |
assert_equal 4.15, Issue.find(1).remaining_hours |
|
4243 |
assert_equal 4.15, Issue.find(2).remaining_hours |
|
4244 |
end |
|
4245 | ||
4211 | 4246 |
def test_bulk_update_custom_field |
4212 | 4247 |
@request.session[:user_id] = 2 |
4213 | 4248 |
# update issues priority |
... | ... | |
4370 | 4405 |
assert_select 'option[value="2"]' |
4371 | 4406 |
end |
4372 | 4407 |
end |
4373 |
|
|
4408 | ||
4374 | 4409 |
def test_bulk_copy_to_another_project |
4375 | 4410 |
@request.session[:user_id] = 2 |
4376 | 4411 |
assert_difference 'Issue.count', 2 do |
... | ... | |
4423 | 4458 |
:assigned_to_id => 3) |
4424 | 4459 |
] |
4425 | 4460 |
assert_difference 'Issue.count', issues.size do |
4426 |
post :bulk_update, :ids => issues.map(&:id), :copy => '1',
|
|
4461 |
post :bulk_update, :ids => issues.map(&:id), :copy => '1', |
|
4427 | 4462 |
:issue => { |
4428 | 4463 |
:project_id => '', :tracker_id => '', :assigned_to_id => '', |
4429 | 4464 |
:status_id => '', :start_date => '', :due_date => '' |
... | ... | |
4451 | 4486 |
@request.session[:user_id] = 2 |
4452 | 4487 |
assert_difference 'Issue.count', 2 do |
4453 | 4488 |
assert_no_difference 'Project.find(1).issues.count' do |
4454 |
post :bulk_update, :ids => [1, 2], :copy => '1',
|
|
4489 |
post :bulk_update, :ids => [1, 2], :copy => '1', |
|
4455 | 4490 |
:issue => { |
4456 | 4491 |
:project_id => '2', :tracker_id => '', :assigned_to_id => '2', |
4457 | 4492 |
:status_id => '1', :start_date => '2009-12-01', :due_date => '2009-12-31' |
test/integration/api_test/issues_test.rb | ||
---|---|---|
354 | 354 |
end |
355 | 355 |
end |
356 | 356 | |
357 |
test "GET /issues/:id.xml should contains total_estimated_hours and total_spent_hours" do |
|
357 |
test "GET /issues/:id.xml should contains total_estimated_hours, total_remaining_hours and total_spent_hours" do
|
|
358 | 358 |
parent = Issue.find(3) |
359 |
child = Issue.generate!(:parent_issue_id => parent.id, :estimated_hours => 3.0) |
|
359 |
child = Issue.generate!(:parent_issue_id => parent.id, :estimated_hours => 3.0, :remaining_hours => 1.0)
|
|
360 | 360 |
TimeEntry.create!(:project => child.project, :issue => child, :user => child.author, :spent_on => child.author.today, |
361 | 361 |
:hours => '2.5', :comments => '', :activity_id => TimeEntryActivity.first.id) |
362 | 362 |
get '/issues/3.xml' |
... | ... | |
365 | 365 |
assert_select 'issue' do |
366 | 366 |
assert_select 'estimated_hours', parent.estimated_hours.to_s |
367 | 367 |
assert_select 'total_estimated_hours', (parent.estimated_hours.to_f + 3.0).to_s |
368 |
assert_select 'remaining_hours', parent.remaining_hours.to_s |
|
369 |
assert_select 'total_remaining_hours', (parent.remaining_hours.to_f + 1.0).to_s |
|
368 | 370 |
assert_select 'spent_hours', parent.spent_hours.to_s |
369 | 371 |
assert_select 'total_spent_hours', (parent.spent_hours.to_f + 2.5).to_s |
370 | 372 |
end |
371 | 373 |
end |
372 | 374 | |
373 |
test "GET /issues/:id.xml should contains total_estimated_hours, and should not contains spent_hours and total_spent_hours when permission does not exists" do |
|
375 |
test "GET /issues/:id.xml should contains total_estimated_hours and total_remaining_hours, and should not contains spent_hours and total_spent_hours when permission does not exists" do
|
|
374 | 376 |
parent = Issue.find(3) |
375 |
child = Issue.generate!(:parent_issue_id => parent.id, :estimated_hours => 3.0) |
|
377 |
child = Issue.generate!(:parent_issue_id => parent.id, :estimated_hours => 3.0, :remaining_hours => 1.0)
|
|
376 | 378 |
# remove permission! |
377 | 379 |
Role.anonymous.remove_permission! :view_time_entries |
378 | 380 |
#Role.all.each { |role| role.remove_permission! :view_time_entries } |
... | ... | |
382 | 384 |
assert_select 'issue' do |
383 | 385 |
assert_select 'estimated_hours', parent.estimated_hours.to_s |
384 | 386 |
assert_select 'total_estimated_hours', (parent.estimated_hours.to_f + 3.0).to_s |
387 |
assert_select 'remaining_hours', parent.remaining_hours.to_s |
|
388 |
assert_select 'total_remaining_hours', (parent.remaining_hours.to_f + 1.0).to_s |
|
385 | 389 |
assert_select 'spent_hours', false |
386 | 390 |
assert_select 'total_spent_hours', false |
387 | 391 |
end |
388 | 392 |
end |
389 | 393 | |
390 |
test "GET /issues/:id.json should contains total_estimated_hours and total_spent_hours" do |
|
394 |
test "GET /issues/:id.json should contains total_estimated_hours, total_remaining_hours and total_spent_hours" do
|
|
391 | 395 |
parent = Issue.find(3) |
392 |
child = Issue.generate!(:parent_issue_id => parent.id, :estimated_hours => 3.0) |
|
396 |
child = Issue.generate!(:parent_issue_id => parent.id, :estimated_hours => 3.0, :remaining_hours => 1.0)
|
|
393 | 397 |
TimeEntry.create!(:project => child.project, :issue => child, :user => child.author, :spent_on => child.author.today, |
394 | 398 |
:hours => '2.5', :comments => '', :activity_id => TimeEntryActivity.first.id) |
395 | 399 |
get '/issues/3.json' |
... | ... | |
398 | 402 |
json = ActiveSupport::JSON.decode(response.body) |
399 | 403 |
assert_equal parent.estimated_hours, json['issue']['estimated_hours'] |
400 | 404 |
assert_equal (parent.estimated_hours.to_f + 3.0), json['issue']['total_estimated_hours'] |
405 |
assert_equal parent.remaining_hours, json['issue']['remaining_hours'] |
|
406 |
assert_equal (parent.remaining_hours.to_f + 1.0), json['issue']['total_remaining_hours'] |
|
401 | 407 |
assert_equal parent.spent_hours, json['issue']['spent_hours'] |
402 | 408 |
assert_equal (parent.spent_hours.to_f + 2.5), json['issue']['total_spent_hours'] |
403 | 409 |
end |
404 | 410 | |
405 |
test "GET /issues/:id.json should contains total_estimated_hours, and should not contains spent_hours and total_spent_hours when permission does not exists" do |
|
411 |
test "GET /issues/:id.json should contains total_estimated_hours and total_remaining_hours, and should not contains spent_hours and total_spent_hours when permission does not exists" do
|
|
406 | 412 |
parent = Issue.find(3) |
407 |
child = Issue.generate!(:parent_issue_id => parent.id, :estimated_hours => 3.0) |
|
413 |
child = Issue.generate!(:parent_issue_id => parent.id, :estimated_hours => 3.0, :remaining_hours => 1.0)
|
|
408 | 414 |
# remove permission! |
409 | 415 |
Role.anonymous.remove_permission! :view_time_entries |
410 | 416 |
#Role.all.each { |role| role.remove_permission! :view_time_entries } |
... | ... | |
414 | 420 |
json = ActiveSupport::JSON.decode(response.body) |
415 | 421 |
assert_equal parent.estimated_hours, json['issue']['estimated_hours'] |
416 | 422 |
assert_equal (parent.estimated_hours.to_f + 3.0), json['issue']['total_estimated_hours'] |
423 |
assert_equal parent.remaining_hours, json['issue']['remaining_hours'] |
|
424 |
assert_equal (parent.remaining_hours.to_f + 1.0), json['issue']['total_remaining_hours'] |
|
417 | 425 |
assert_equal nil, json['issue']['spent_hours'] |
418 | 426 |
assert_equal nil, json['issue']['total_spent_hours'] |
419 | 427 |
end |
test/unit/helpers/issues_helper_test.rb | ||
---|---|---|
203 | 203 |
assert_match '6.30', show_detail(detail, true) |
204 | 204 |
end |
205 | 205 | |
206 |
test 'show_detail should show old and new values with a remaining hours attribute' do |
|
207 |
detail = JournalDetail.new(:property => 'attr', :prop_key => 'remaining_hours', |
|
208 |
:old_value => '6.3', :value => '5') |
|
209 |
assert_match '5.00', show_detail(detail, true) |
|
210 |
assert_match '6.30', show_detail(detail, true) |
|
211 |
end |
|
212 | ||
206 | 213 |
test 'show_detail should not show values with a description attribute' do |
207 | 214 |
detail = JournalDetail.new(:property => 'attr', :prop_key => 'description', |
208 | 215 |
:old_value => 'Foo', :value => 'Bar') |
test/unit/issue_subtasking_test.rb | ||
---|---|---|
28 | 28 |
def test_leaf_planning_fields_should_be_editable |
29 | 29 |
issue = Issue.generate! |
30 | 30 |
user = User.find(1) |
31 |
%w(priority_id done_ratio start_date due_date estimated_hours).each do |attribute| |
|
31 |
%w(priority_id done_ratio start_date due_date estimated_hours remaining_hours).each do |attribute|
|
|
32 | 32 |
assert issue.safe_attribute?(attribute, user) |
33 | 33 |
end |
34 | 34 |
end |
... | ... | |
147 | 147 |
assert_equal 20, parent.reload.done_ratio |
148 | 148 |
parent.generate_child!(:done_ratio => 70) |
149 | 149 |
assert_equal 45, parent.reload.done_ratio |
150 |
|
|
150 | ||
151 | 151 |
child = parent.generate_child!(:done_ratio => 0) |
152 | 152 |
assert_equal 30, parent.reload.done_ratio |
153 |
|
|
153 | ||
154 | 154 |
child.generate_child!(:done_ratio => 30) |
155 | 155 |
assert_equal 30, child.reload.done_ratio |
156 | 156 |
assert_equal 40, parent.reload.done_ratio |
... | ... | |
330 | 330 |
parent.generate_child!(:estimated_hours => 7) |
331 | 331 |
assert_equal 12, parent.reload.total_estimated_hours |
332 | 332 |
end |
333 | ||
334 |
def test_parent_total_remaining_hours_should_be_sum_of_descendants |
|
335 |
parent = Issue.generate! |
|
336 |
parent.generate_child!(:remaining_hours => nil) |
|
337 |
assert_equal 0, parent.reload.total_remaining_hours |
|
338 |
parent.generate_child!(:remaining_hours => 5) |
|
339 |
assert_equal 5, parent.reload.total_remaining_hours |
|
340 |
parent.generate_child!(:remaining_hours => 7) |
|
341 |
assert_equal 12, parent.reload.total_remaining_hours |
|
342 |
end |
|
333 | 343 |
end |
test/unit/issue_test.rb | ||
---|---|---|
56 | 56 |
issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, |
57 | 57 |
:status_id => 1, :priority => IssuePriority.all.first, |
58 | 58 |
:subject => 'test_create', |
59 |
:description => 'IssueTest#test_create', :estimated_hours => '1:30') |
|
59 |
:description => 'IssueTest#test_create', :estimated_hours => '1:30', :remaining_hours => '1')
|
|
60 | 60 |
assert issue.save |
61 | 61 |
issue.reload |
62 | 62 |
assert_equal 1.5, issue.estimated_hours |
63 |
assert_equal 1, issue.remaining_hours |
|
63 | 64 |
end |
64 | 65 | |
65 | 66 |
def test_create_minimal |
... | ... | |
68 | 69 |
assert_equal issue.tracker.default_status, issue.status |
69 | 70 |
assert issue.description.nil? |
70 | 71 |
assert_nil issue.estimated_hours |
72 |
assert_nil issue.remaining_hours |
|
71 | 73 |
end |
72 | 74 | |
73 | 75 |
def test_create_with_all_fields_disabled |
... | ... | |
134 | 136 |
end |
135 | 137 |
end |
136 | 138 | |
139 |
def test_remaining_hours_update_with_negative_value_should_set_to_zero |
|
140 |
set_language_if_valid 'en' |
|
141 |
['-4'].each do |invalid| |
|
142 |
issue = Issue.new(:remaining_hours => invalid) |
|
143 |
assert_equal 0, issue.remaining_hours |
|
144 |
end |
|
145 |
end |
|
146 | ||
147 |
def test_remaining_hours_should_be_set_from_estimated_hours_when_is_empty |
|
148 |
issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, |
|
149 |
:status_id => 1, :priority => IssuePriority.all.first, |
|
150 |
:subject => 'test_create', |
|
151 |
:description => 'IssueTest#test_create', :estimated_hours => '1:30') |
|
152 |
assert issue.save |
|
153 |
assert_equal 1.5, issue.remaining_hours |
|
154 |
end |
|
155 | ||
137 | 156 |
def test_create_with_required_custom_field |
138 | 157 |
set_language_if_valid 'en' |
139 | 158 |
field = IssueCustomField.find_by_name('Database') |
... | ... | |
2885 | 2904 |
assert_equal false, issue.closing? |
2886 | 2905 |
end |
2887 | 2906 | |
2907 |
def test_closing_should_set_remaining_hours_to_zero |
|
2908 |
issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, |
|
2909 |
:status_id => 1, :priority => IssuePriority.all.first, |
|
2910 |
:subject => 'test_create', |
|
2911 |
:description => 'IssueTest#test_create', :estimated_hours => '1:30', :remaining_hours => '1') |
|
2912 |
assert_equal 1, issue.remaining_hours |
|
2913 |
issue.status_id = 5 |
|
2914 |
issue.save! |
|
2915 |
assert_equal 0, issue.remaining_hours |
|
2916 |
end |
|
2917 | ||
2888 | 2918 |
def test_reopening_should_return_true_when_reopening_an_issue |
2889 | 2919 |
issue = Issue.find(8) |
2890 | 2920 |
issue.status = IssueStatus.find(6) |
test/unit/mail_handler_test.rb | ||
---|---|---|
42 | 42 | |
43 | 43 |
def test_add_issue_with_specific_overrides |
44 | 44 |
issue = submit_email('ticket_on_given_project.eml', |
45 |
:allow_override => ['status', 'start_date', 'due_date', 'assigned_to', 'fixed_version', 'estimated_hours', 'done_ratio'] |
|
45 |
:allow_override => ['status', 'start_date', 'due_date', 'assigned_to', 'fixed_version', 'estimated_hours', 'remaining_hours', 'done_ratio']
|
|
46 | 46 |
) |
47 | 47 |
assert issue.is_a?(Issue) |
48 | 48 |
assert !issue.new_record? |
... | ... | |
58 | 58 |
assert_equal User.find_by_login('jsmith'), issue.assigned_to |
59 | 59 |
assert_equal Version.find_by_name('Alpha'), issue.fixed_version |
60 | 60 |
assert_equal 2.5, issue.estimated_hours |
61 |
assert_equal 1, issue.remaining_hours |
|
61 | 62 |
assert_equal 30, issue.done_ratio |
62 | 63 |
# keywords should be removed from the email body |
63 | 64 |
assert !issue.description.match(/^Project:/i) |
64 | 65 |
assert !issue.description.match(/^Status:/i) |
65 | 66 |
assert !issue.description.match(/^Start Date:/i) |
67 |
assert !issue.description.match(/^remaining hours:/i) |
|
66 | 68 |
end |
67 | 69 | |
68 | 70 |
def test_add_issue_with_all_overrides |
... | ... | |
79 | 81 |
assert_equal User.find_by_login('jsmith'), issue.assigned_to |
80 | 82 |
assert_equal Version.find_by_name('Alpha'), issue.fixed_version |
81 | 83 |
assert_equal 2.5, issue.estimated_hours |
84 |
assert_equal 1, issue.remaining_hours |
|
82 | 85 |
assert_equal 30, issue.done_ratio |
83 | 86 |
end |
84 | 87 | |
... | ... | |
100 | 103 |
assert_nil issue.assigned_to |
101 | 104 |
assert_nil issue.fixed_version |
102 | 105 |
assert_nil issue.estimated_hours |
106 |
assert_nil issue.remaining_hours |
|
103 | 107 |
assert_equal 0, issue.done_ratio |
104 | 108 |
end |
105 | 109 |
test/unit/query_test.rb | ||
---|---|---|
1256 | 1256 | |
1257 | 1257 |
def test_set_totalable_names |
1258 | 1258 |
q = IssueQuery.new |
1259 |
q.totalable_names = ['estimated_hours', :spent_hours, ''] |
|
1260 |
assert_equal [:estimated_hours, :spent_hours], q.totalable_columns.map(&:name) |
|
1259 |
q.totalable_names = ['estimated_hours', 'remaining_hours', :spent_hours, '']
|
|
1260 |
assert_equal [:estimated_hours, :remaining_hours, :spent_hours], q.totalable_columns.map(&:name)
|
|
1261 | 1261 |
end |
1262 | 1262 | |
1263 | 1263 |
def test_totalable_columns_should_default_to_settings |
... | ... | |
1272 | 1272 |
assert_include :estimated_hours, q.available_totalable_columns.map(&:name) |
1273 | 1273 |
end |
1274 | 1274 | |
1275 |
def test_available_totalable_columns_should_include_remaining_hours |
|
1276 |
q = IssueQuery.new |
|
1277 |
assert_include :remaining_hours, q.available_totalable_columns.map(&:name) |
|
1278 |
end |
|
1279 | ||
1275 | 1280 |
def test_available_totalable_columns_should_include_spent_hours |
1276 | 1281 |
User.current = User.find(1) |
1277 | 1282 | |
... | ... | |
1314 | 1319 |
) |
1315 | 1320 |
end |
1316 | 1321 | |
1322 |
def test_total_for_remaining_hours |
|
1323 |
Issue.delete_all |
|
1324 |
Issue.generate!(:remaining_hours => 5.5) |
|
1325 |
Issue.generate!(:remaining_hours => 1.1) |
|
1326 |
Issue.generate! |
|
1327 | ||
1328 |
q = IssueQuery.new |
|
1329 |
assert_equal 6.6, q.total_for(:remaining_hours) |
|
1330 |
end |
|
1331 | ||
1332 |
def test_total_by_group_for_remaining_hours |
|
1333 |
Issue.delete_all |
|
1334 |
Issue.generate!(:remaining_hours => 5.5, :assigned_to_id => 2) |
|
1335 |
Issue.generate!(:remaining_hours => 1.1, :assigned_to_id => 3) |
|
1336 |
Issue.generate!(:remaining_hours => 3.5) |
|
1337 | ||
1338 |
q = IssueQuery.new(:group_by => 'assigned_to') |
|
1339 |
assert_equal( |
|
1340 |
{nil => 3.5, User.find(2) => 5.5, User.find(3) => 1.1}, |
|
1341 |
q.total_by_group_for(:remaining_hours) |
|
1342 |
) |
|
1343 |
end |
|
1344 | ||
1317 | 1345 |
def test_total_for_spent_hours |
1318 | 1346 |
TimeEntry.delete_all |
1319 | 1347 |
TimeEntry.generate!(:hours => 5.5) |