Feature #24277 » 01_add_remaining_hours_field_3.4.1.patch
app/helpers/issues_helper.rb | ||
---|---|---|
150 | 150 |
end |
151 | 151 |
end |
152 | 152 | |
153 |
def issue_remaining_hours_details(issue) |
|
154 |
if issue.total_remaining_hours.present? |
|
155 |
if issue.total_remaining_hours == issue.remaining_hours |
|
156 |
l_hours_short(issue.remaining_hours) |
|
157 |
else |
|
158 |
s = issue.remaining_hours.present? ? l_hours_short(issue.remaining_hours) : "" |
|
159 |
s << " (#{l(:label_total)}: #{l_hours_short(issue.total_remaining_hours)})" |
|
160 |
s.html_safe |
|
161 |
end |
|
162 |
end |
|
163 |
end |
|
164 | ||
153 | 165 |
def issue_spent_hours_details(issue) |
154 | 166 |
if issue.total_spent_hours > 0 |
155 | 167 |
path = project_time_entries_path(issue.project, :issue_id => "~#{issue.id}") |
... | ... | |
408 | 420 |
value = find_name_by_reflection(field, detail.value) |
409 | 421 |
old_value = find_name_by_reflection(field, detail.old_value) |
410 | 422 | |
411 |
when 'estimated_hours' |
|
423 |
when 'estimated_hours', 'remaining_hours'
|
|
412 | 424 |
value = l_hours_short(detail.value.to_f) unless detail.value.blank? |
413 | 425 |
old_value = l_hours_short(detail.old_value.to_f) unless detail.old_value.blank? |
414 | 426 |
app/models/issue.rb | ||
---|---|---|
66 | 66 |
validates_length_of :subject, :maximum => 255 |
67 | 67 |
validates_inclusion_of :done_ratio, :in => 0..100 |
68 | 68 |
validates :estimated_hours, :numericality => {:greater_than_or_equal_to => 0, :allow_nil => true, :message => :invalid} |
69 |
validates :remaining_hours, :numericality => {:greater_than_or_equal_to => 0, :allow_nil => true, :message => :invalid} |
|
69 | 70 |
validates :start_date, :date => true |
70 | 71 |
validates :due_date, :date => true |
71 | 72 |
validate :validate_issue, :validate_required_fields, :validate_permissions |
... | ... | |
107 | 108 | |
108 | 109 |
before_validation :default_assign, on: :create |
109 | 110 |
before_validation :clear_disabled_fields |
111 |
before_validation :update_remaining_hours_from_estimated_hours |
|
110 | 112 |
before_save :close_duplicates, :update_done_ratio_from_issue_status, |
111 |
:force_updated_on_change, :update_closed_on, :set_assigned_to_was |
|
113 |
:force_updated_on_change, :update_closed_on, :set_assigned_to_was, :update_remaining_hours
|
|
112 | 114 |
after_save {|issue| issue.send :after_project_change if !issue.id_changed? && issue.project_id_changed?} |
113 | 115 |
after_save :reschedule_following_issues, :update_nested_set_attributes, |
114 | 116 |
:update_parent_attributes, :delete_selected_attachments, :create_journal |
... | ... | |
245 | 247 |
@spent_hours = nil |
246 | 248 |
@total_spent_hours = nil |
247 | 249 |
@total_estimated_hours = nil |
250 |
@total_remaining_hours = nil |
|
248 | 251 |
@last_updated_by = nil |
249 | 252 |
@last_notes = nil |
250 | 253 |
base_reload(*args) |
... | ... | |
446 | 449 |
write_attribute :estimated_hours, (h.is_a?(String) ? h.to_hours : h) |
447 | 450 |
end |
448 | 451 | |
452 |
def remaining_hours=(h) |
|
453 |
h = h.is_a?(String) ? h.to_hours : h |
|
454 |
# remaining time cannot be less than zero |
|
455 |
h = 0 if !h.nil? && h < 0 |
|
456 |
write_attribute :remaining_hours, h |
|
457 |
end |
|
458 | ||
449 | 459 |
safe_attributes 'project_id', |
450 | 460 |
'tracker_id', |
451 | 461 |
'status_id', |
... | ... | |
459 | 469 |
'due_date', |
460 | 470 |
'done_ratio', |
461 | 471 |
'estimated_hours', |
472 |
'remaining_hours', |
|
462 | 473 |
'custom_field_values', |
463 | 474 |
'custom_fields', |
464 | 475 |
'lock_version', |
... | ... | |
1092 | 1103 |
end |
1093 | 1104 |
end |
1094 | 1105 | |
1106 |
def total_remaining_hours |
|
1107 |
if leaf? |
|
1108 |
remaining_hours |
|
1109 |
else |
|
1110 |
@total_remaining_hours ||= self_and_descendants.sum(:remaining_hours) |
|
1111 |
end |
|
1112 |
end |
|
1113 | ||
1095 | 1114 |
def relations |
1096 | 1115 |
@relations ||= IssueRelation::Relations.new(self, (relations_from + relations_to).sort) |
1097 | 1116 |
end |
... | ... | |
1834 | 1853 |
end |
1835 | 1854 |
end |
1836 | 1855 | |
1856 |
# Callback for setting remaining time to zero when the issue is closed. |
|
1857 |
def update_remaining_hours |
|
1858 |
if closing? && safe_attribute?('remaining_hours') && self.remaining_hours.to_f > 0 |
|
1859 |
self.remaining_hours = 0 |
|
1860 |
end |
|
1861 |
end |
|
1862 | ||
1837 | 1863 |
# Saves the changes in a Journal |
1838 | 1864 |
# Called after_save |
1839 | 1865 |
def create_journal |
... | ... | |
1868 | 1894 |
self.done_ratio ||= 0 |
1869 | 1895 |
end |
1870 | 1896 |
end |
1897 | ||
1898 |
def update_remaining_hours_from_estimated_hours |
|
1899 |
if self.remaining_hours.blank? && self.estimated_hours |
|
1900 |
self.remaining_hours = self.estimated_hours |
|
1901 |
end |
|
1902 |
end |
|
1871 | 1903 |
end |
app/models/issue_import.rb | ||
---|---|---|
162 | 162 |
if estimated_hours = row_value(row, 'estimated_hours') |
163 | 163 |
attributes['estimated_hours'] = estimated_hours |
164 | 164 |
end |
165 |
if remaining_hours = row_value(row, 'remaining_hours') |
|
166 |
attributes['remaining_hours'] = remaining_hours |
|
167 |
end |
|
165 | 168 |
if done_ratio = row_value(row, 'done_ratio') |
166 | 169 |
attributes['done_ratio'] = done_ratio |
167 | 170 |
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'), |
... | ... | |
134 | 139 |
add_available_filter "start_date", :type => :date |
135 | 140 |
add_available_filter "due_date", :type => :date |
136 | 141 |
add_available_filter "estimated_hours", :type => :float |
142 |
add_available_filter "remaining_hours", :type => :float |
|
137 | 143 |
add_available_filter "done_ratio", :type => :integer |
138 | 144 | |
139 | 145 |
if User.current.allowed_to?(:set_issues_private, nil, :global => true) || |
... | ... | |
249 | 255 |
map_total(scope.sum(:estimated_hours)) {|t| t.to_f.round(2)} |
250 | 256 |
end |
251 | 257 | |
258 |
# Returns sum of all the issue's remaining_hours |
|
259 |
def total_for_remaining_hours(scope) |
|
260 |
map_total(scope.sum(:remaining_hours)) {|t| t.to_f.round(2)} |
|
261 |
end |
|
262 | ||
252 | 263 |
# Returns sum of all the issue's time entries hours |
253 | 264 |
def total_for_spent_hours(scope) |
254 | 265 |
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 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 description).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 description).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.hours_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 %> |
74 | 78 |
</div> |
75 | 79 |
</div> |
app/views/issues/bulk_edit.html.erb | ||
---|---|---|
181 | 181 |
</p> |
182 | 182 |
<% end %> |
183 | 183 | |
184 |
<% if @safe_attributes.include?('remaining_hours') %> |
|
185 |
<p> |
|
186 |
<label for='issue_remaining_hours'><%= l(:field_remaining_hours) %></label> |
|
187 |
<%= text_field_tag 'issue[remaining_hours]', '', :value => @issue_params[:remaining_hours], :size => 10 %> |
|
188 |
<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> |
|
189 |
</p> |
|
190 |
<% end %> |
|
191 | ||
184 | 192 |
<% if @safe_attributes.include?('done_ratio') && Issue.use_field_for_done_ratio? %> |
185 | 193 |
<p> |
186 | 194 |
<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 | ||
---|---|---|
67 | 67 |
unless @issue.disabled_core_fields.include?('estimated_hours') |
68 | 68 |
rows.right l(:field_estimated_hours), issue_estimated_hours_details(@issue), :class => 'estimated-hours' |
69 | 69 |
end |
70 |
unless @issue.disabled_core_fields.include?('remaining_hours') |
|
71 |
rows.right l(:field_remaining_hours), issue_remaining_hours_details(@issue), :class => 'remaining-hours' |
|
72 |
end |
|
70 | 73 |
if User.current.allowed_to?(:view_time_entries, @project) && @issue.total_spent_hours > 0 |
71 | 74 |
rows.right l(:label_spent_time), issue_spent_hours_details(@issue), :class => 'spent-time' |
72 | 75 |
end |
config/locales/en.yml | ||
---|---|---|
375 | 375 |
field_full_width_layout: Full width layout |
376 | 376 |
field_digest: Checksum |
377 | 377 |
field_default_assigned_to: Default assignee |
378 |
field_remaining_hours: Remaining time |
|
379 |
field_total_remaining_hours: Total remaining time |
|
378 | 380 | |
379 | 381 |
setting_app_title: Application title |
380 | 382 |
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 | ||
---|---|---|
152 | 152 |
:f => ['tracker_id'], |
153 | 153 |
:op => { |
154 | 154 |
'tracker_id' => '=' |
155 |
},
|
|
155 |
}, |
|
156 | 156 |
:v => { |
157 | 157 |
'tracker_id' => ['1'] |
158 | 158 |
} |
... | ... | |
253 | 253 |
:f => [filter_name], |
254 | 254 |
:op => { |
255 | 255 |
filter_name => '=' |
256 |
},
|
|
256 |
}, |
|
257 | 257 |
:v => { |
258 | 258 |
filter_name => ['Foo'] |
259 |
},
|
|
259 |
}, |
|
260 | 260 |
:c => ['project'] |
261 | 261 |
} |
262 | 262 |
assert_response :success |
... | ... | |
970 | 970 |
assert_equal hours.sort.reverse, hours |
971 | 971 |
end |
972 | 972 | |
973 |
def test_index_sort_by_total_remaining_hours |
|
974 |
get :index, :sort => 'total_remaining_hours:desc' |
|
975 |
assert_response :success |
|
976 |
hours = assigns(:issues).collect(&:total_remaining_hours) |
|
977 |
assert_equal hours.sort.reverse, hours |
|
978 |
end |
|
979 | ||
973 | 980 |
def test_index_sort_by_user_custom_field |
974 | 981 |
cf = IssueCustomField.create!(:name => 'User', :is_for_all => true, :tracker_ids => [1,2,3], :field_format => 'user') |
975 | 982 |
CustomValue.create!(:custom_field => cf, :customized => Issue.find(1), :value => '2') |
... | ... | |
1146 | 1153 |
assert_select 'table.issues td.total_estimated_hours' |
1147 | 1154 |
end |
1148 | 1155 | |
1156 |
def test_index_with_total_remaining_hours_column |
|
1157 |
get :index, :set_filter => 1, :c => %w(subject total_remaining_hours) |
|
1158 |
assert_select 'table.issues td.total_remaining_hours' |
|
1159 |
end |
|
1160 | ||
1149 | 1161 |
def test_index_should_not_show_spent_hours_column_without_permission |
1150 | 1162 |
Role.anonymous.remove_permission! :view_time_entries |
1151 | 1163 |
get :index, :params => { |
... | ... | |
1352 | 1364 |
assert_select 'input[type=checkbox][name=?][value=estimated_hours][checked=checked]', 't[]' |
1353 | 1365 |
end |
1354 | 1366 | |
1367 |
def test_index_with_remaining_hours_total |
|
1368 |
Issue.delete_all |
|
1369 |
Issue.generate!(:remaining_hours => 5.4) |
|
1370 |
Issue.generate!(:remaining_hours => 1.1) |
|
1371 | ||
1372 |
get :index, :t => %w(remaining_hours) |
|
1373 |
assert_response :success |
|
1374 |
assert_select '.query-totals' |
|
1375 |
assert_select '.total-for-remaining-hours span.value', :text => '6.50' |
|
1376 |
assert_select 'input[type=checkbox][name=?][value=remaining_hours][checked=checked]', 't[]' |
|
1377 |
end |
|
1378 | ||
1355 | 1379 |
def test_index_with_grouped_query_and_estimated_hours_total |
1356 | 1380 |
Issue.delete_all |
1357 | 1381 |
Issue.generate!(:estimated_hours => 5.5, :category_id => 1) |
... | ... | |
1415 | 1439 |
:f => ['start_date'], |
1416 | 1440 |
:op => { |
1417 | 1441 |
:start_date => '=' |
1418 |
},
|
|
1442 |
}, |
|
1419 | 1443 |
:format => 'csv' |
1420 | 1444 |
} |
1421 | 1445 |
assert_equal 'text/csv', @response.content_type |
... | ... | |
2590 | 2614 |
:tracker_id => 3, |
2591 | 2615 |
:description => 'Prefilled', |
2592 | 2616 |
:custom_field_values => { |
2593 |
'2' => 'Custom field value'}
|
|
2617 |
'2' => 'Custom field value'} |
|
2594 | 2618 |
} |
2595 | 2619 |
} |
2596 | 2620 | |
... | ... | |
2714 | 2738 |
assert !t.disabled_core_fields.include?('parent_issue_id') |
2715 | 2739 | |
2716 | 2740 |
get :new, :params => { |
2717 |
:project_id => 1, issue: { parent_issue_id: 1
|
|
2741 |
:project_id => 1, issue: { parent_issue_id: 1 |
|
2718 | 2742 |
} |
2719 | 2743 |
} |
2720 | 2744 |
assert_response :success |
... | ... | |
2724 | 2748 |
t.save! |
2725 | 2749 |
assert t.disabled_core_fields.include?('parent_issue_id') |
2726 | 2750 |
get :new, :params => { |
2727 |
:project_id => 1, issue: { parent_issue_id: 1
|
|
2751 |
:project_id => 1, issue: { parent_issue_id: 1 |
|
2728 | 2752 |
} |
2729 | 2753 |
} |
2730 | 2754 |
assert_response :success |
... | ... | |
2782 | 2806 |
:issue => { |
2783 | 2807 |
:tracker_id => 2, |
2784 | 2808 |
:status_id => 1 |
2785 |
},
|
|
2809 |
}, |
|
2786 | 2810 |
:was_default_status => 1 |
2787 | 2811 |
} |
2788 | 2812 |
assert_response :success |
... | ... | |
2801 | 2825 |
:issue => { |
2802 | 2826 |
:project_id => 1, |
2803 | 2827 |
:fixed_version_id => '' |
2804 |
},
|
|
2828 |
}, |
|
2805 | 2829 |
:form_update_triggered_by => 'issue_project_id' |
2806 | 2830 |
} |
2807 | 2831 |
assert_response :success |
... | ... | |
2828 | 2852 |
:priority_id => 5, |
2829 | 2853 |
:start_date => '2010-11-07', |
2830 | 2854 |
:estimated_hours => '', |
2855 |
:remaining_hours => '', |
|
2831 | 2856 |
:custom_field_values => { |
2832 |
'2' => 'Value for field 2'}
|
|
2857 |
'2' => 'Value for field 2'} |
|
2833 | 2858 |
} |
2834 | 2859 |
} |
2835 | 2860 |
end |
... | ... | |
2843 | 2868 |
assert_equal 2, issue.status_id |
2844 | 2869 |
assert_equal Date.parse('2010-11-07'), issue.start_date |
2845 | 2870 |
assert_nil issue.estimated_hours |
2871 |
assert_nil issue.remaining_hours |
|
2846 | 2872 |
v = issue.custom_values.where(:custom_field_id => 2).first |
2847 | 2873 |
assert_not_nil v |
2848 | 2874 |
assert_equal 'Value for field 2', v.value |
... | ... | |
2888 | 2914 |
:priority_id => 5, |
2889 | 2915 |
:estimated_hours => '', |
2890 | 2916 |
:custom_field_values => { |
2891 |
'2' => 'Value for field 2'}
|
|
2917 |
'2' => 'Value for field 2'} |
|
2892 | 2918 |
} |
2893 | 2919 |
} |
2894 | 2920 |
end |
... | ... | |
2914 | 2940 |
:priority_id => 5, |
2915 | 2941 |
:estimated_hours => '', |
2916 | 2942 |
:custom_field_values => { |
2917 |
'2' => 'Value for field 2'}
|
|
2943 |
'2' => 'Value for field 2'} |
|
2918 | 2944 |
} |
2919 | 2945 |
} |
2920 | 2946 |
end |
... | ... | |
2935 | 2961 |
:tracker_id => 3, |
2936 | 2962 |
:subject => 'This is first issue', |
2937 | 2963 |
:priority_id => 5 |
2938 |
},
|
|
2964 |
}, |
|
2939 | 2965 |
:continue => '' |
2940 | 2966 |
} |
2941 | 2967 |
end |
... | ... | |
2977 | 3003 |
:description => 'This is the description', |
2978 | 3004 |
:priority_id => 5, |
2979 | 3005 |
:custom_field_values => { |
2980 |
'1' => ['', 'MySQL', 'Oracle']}
|
|
3006 |
'1' => ['', 'MySQL', 'Oracle']} |
|
2981 | 3007 |
} |
2982 | 3008 |
} |
2983 | 3009 |
end |
... | ... | |
3000 | 3026 |
:description => 'This is the description', |
3001 | 3027 |
:priority_id => 5, |
3002 | 3028 |
:custom_field_values => { |
3003 |
'1' => ['']}
|
|
3029 |
'1' => ['']} |
|
3004 | 3030 |
} |
3005 | 3031 |
} |
3006 | 3032 |
end |
... | ... | |
3023 | 3049 |
:description => 'This is the description', |
3024 | 3050 |
:priority_id => 5, |
3025 | 3051 |
:custom_field_values => { |
3026 |
field.id.to_s => ['', '2', '3']}
|
|
3052 |
field.id.to_s => ['', '2', '3']} |
|
3027 | 3053 |
} |
3028 | 3054 |
} |
3029 | 3055 |
end |
... | ... | |
3071 | 3097 |
:due_date => '', |
3072 | 3098 |
:custom_field_values => { |
3073 | 3099 |
cf1.id.to_s => '', cf2.id.to_s => '' |
3074 |
}
|
|
3075 |
|
|
3100 |
} |
|
3101 | ||
3076 | 3102 |
} |
3077 | 3103 |
} |
3078 | 3104 |
assert_response :success |
... | ... | |
3101 | 3127 |
:due_date => '', |
3102 | 3128 |
:custom_field_values => { |
3103 | 3129 |
cf1.id.to_s => '', cf2.id.to_s => [''] |
3104 |
}
|
|
3105 |
|
|
3130 |
} |
|
3131 | ||
3106 | 3132 |
} |
3107 | 3133 |
} |
3108 | 3134 |
assert_response :success |
... | ... | |
3131 | 3157 |
:due_date => '2012-07-16', |
3132 | 3158 |
:custom_field_values => { |
3133 | 3159 |
cf1.id.to_s => 'value1', cf2.id.to_s => 'value2' |
3134 |
}
|
|
3135 |
|
|
3160 |
} |
|
3161 | ||
3136 | 3162 |
} |
3137 | 3163 |
} |
3138 | 3164 |
assert_response 302 |
... | ... | |
3158 | 3184 |
:tracker_id => 1, |
3159 | 3185 |
:status_id => 1, |
3160 | 3186 |
:subject => 'Test' |
3161 |
|
|
3187 | ||
3162 | 3188 |
} |
3163 | 3189 |
} |
3164 | 3190 |
assert_response 302 |
... | ... | |
3336 | 3362 |
:project_id => 3, |
3337 | 3363 |
:tracker_id => 2, |
3338 | 3364 |
:subject => 'Foo' |
3339 |
},
|
|
3365 |
}, |
|
3340 | 3366 |
:continue => '1' |
3341 | 3367 |
} |
3342 | 3368 |
assert_redirected_to '/issues/new?issue%5Bproject_id%5D=3&issue%5Btracker_id%5D=2' |
... | ... | |
3389 | 3415 |
:priority_id => 5, |
3390 | 3416 |
:estimated_hours => '', |
3391 | 3417 |
:custom_field_values => { |
3392 |
'2' => 'Value for field 2'}
|
|
3418 |
'2' => 'Value for field 2'} |
|
3393 | 3419 |
} |
3394 | 3420 |
} |
3395 | 3421 |
end |
... | ... | |
3448 | 3474 |
post :create, :params => { |
3449 | 3475 |
:project_id => 1, |
3450 | 3476 |
:issue => { |
3451 |
:tracker => "A param can not be a Tracker"
|
|
3477 |
:tracker => "A param can not be a Tracker" |
|
3452 | 3478 |
} |
3453 | 3479 |
} |
3454 | 3480 |
end |
... | ... | |
3465 | 3491 |
:project_id => 1, |
3466 | 3492 |
:issue => { |
3467 | 3493 |
:tracker_id => '1', |
3468 |
:subject => 'With attachment'
|
|
3469 |
},
|
|
3494 |
:subject => 'With attachment' |
|
3495 |
}, |
|
3470 | 3496 |
:attachments => { |
3471 | 3497 |
'1' => { |
3472 |
'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}
|
|
3498 |
'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'} |
|
3473 | 3499 |
} |
3474 | 3500 |
} |
3475 | 3501 |
end |
... | ... | |
3500 | 3526 |
:project_id => 1, |
3501 | 3527 |
:issue => { |
3502 | 3528 |
:tracker_id => '1', |
3503 |
:subject => 'With attachment'
|
|
3504 |
},
|
|
3529 |
:subject => 'With attachment' |
|
3530 |
}, |
|
3505 | 3531 |
:attachments => { |
3506 | 3532 |
'1' => { |
3507 |
'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}
|
|
3533 |
'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'} |
|
3508 | 3534 |
} |
3509 | 3535 |
} |
3510 | 3536 |
end |
... | ... | |
3526 | 3552 |
:project_id => 1, |
3527 | 3553 |
:issue => { |
3528 | 3554 |
:tracker_id => '1', |
3529 |
:subject => ''
|
|
3530 |
},
|
|
3555 |
:subject => '' |
|
3556 |
}, |
|
3531 | 3557 |
:attachments => { |
3532 | 3558 |
'1' => { |
3533 |
'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}
|
|
3559 |
'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'} |
|
3534 | 3560 |
} |
3535 | 3561 |
} |
3536 | 3562 |
assert_response :success |
... | ... | |
3557 | 3583 |
:project_id => 1, |
3558 | 3584 |
:issue => { |
3559 | 3585 |
:tracker_id => '1', |
3560 |
:subject => ''
|
|
3561 |
},
|
|
3586 |
:subject => '' |
|
3587 |
}, |
|
3562 | 3588 |
:attachments => { |
3563 | 3589 |
'p0' => { |
3564 |
'token' => attachment.token}
|
|
3590 |
'token' => attachment.token} |
|
3565 | 3591 |
} |
3566 | 3592 |
} |
3567 | 3593 |
assert_response :success |
... | ... | |
3583 | 3609 |
:project_id => 1, |
3584 | 3610 |
:issue => { |
3585 | 3611 |
:tracker_id => '1', |
3586 |
:subject => 'Saved attachments'
|
|
3587 |
},
|
|
3612 |
:subject => 'Saved attachments' |
|
3613 |
}, |
|
3588 | 3614 |
:attachments => { |
3589 | 3615 |
'p0' => { |
3590 |
'token' => attachment.token}
|
|
3616 |
'token' => attachment.token} |
|
3591 | 3617 |
} |
3592 | 3618 |
} |
3593 | 3619 |
assert_response 302 |
... | ... | |
3885 | 3911 |
:project_id => '1', |
3886 | 3912 |
:tracker_id => '1', |
3887 | 3913 |
:status_id => '1' |
3888 |
},
|
|
3914 |
}, |
|
3889 | 3915 |
:was_default_status => '1' |
3890 | 3916 |
} |
3891 | 3917 |
end |
... | ... | |
3929 | 3955 |
:tracker_id => '3', |
3930 | 3956 |
:status_id => '1', |
3931 | 3957 |
:subject => 'Copy with attachments' |
3932 |
},
|
|
3958 |
}, |
|
3933 | 3959 |
:copy_attachments => '1' |
3934 | 3960 |
} |
3935 | 3961 |
end |
... | ... | |
3977 | 4003 |
:tracker_id => '3', |
3978 | 4004 |
:status_id => '1', |
3979 | 4005 |
:subject => 'Copy with attachments' |
3980 |
},
|
|
4006 |
}, |
|
3981 | 4007 |
:copy_attachments => '1', |
3982 | 4008 |
:attachments => { |
3983 | 4009 |
'1' => { |
... | ... | |
4076 | 4102 |
:tracker_id => '3', |
4077 | 4103 |
:status_id => '1', |
4078 | 4104 |
:subject => 'Copy with subtasks' |
4079 |
},
|
|
4105 |
}, |
|
4080 | 4106 |
:copy_subtasks => '1' |
4081 | 4107 |
} |
4082 | 4108 |
end |
... | ... | |
4100 | 4126 |
:status_id => '1', |
4101 | 4127 |
:subject => 'Copy with subtasks', |
4102 | 4128 |
:custom_field_values => { |
4103 |
'2' => 'Foo'}
|
|
4104 |
},
|
|
4129 |
'2' => 'Foo'} |
|
4130 |
}, |
|
4105 | 4131 |
:copy_subtasks => '1' |
4106 | 4132 |
} |
4107 | 4133 |
end |
... | ... | |
4242 | 4268 |
:id => 1, |
4243 | 4269 |
:issue => { |
4244 | 4270 |
:status_id => 5, |
4245 |
:priority_id => 7
|
|
4246 |
},
|
|
4271 |
:priority_id => 7 |
|
4272 |
}, |
|
4247 | 4273 |
:time_entry => { |
4248 | 4274 |
:hours => '2.5', |
4249 | 4275 |
:comments => 'test_get_edit_with_params', |
4250 |
:activity_id => 10
|
|
4276 |
:activity_id => 10 |
|
4251 | 4277 |
} |
4252 | 4278 |
} |
4253 | 4279 |
assert_response :success |
... | ... | |
4486 | 4512 |
:project_id => '1', |
4487 | 4513 |
:tracker_id => '2', |
4488 | 4514 |
:priority_id => '6' |
4489 |
|
|
4515 | ||
4490 | 4516 |
} |
4491 | 4517 |
} |
4492 | 4518 |
end |
... | ... | |
4549 | 4575 |
:issue => { |
4550 | 4576 |
:subject => 'Custom field change', |
4551 | 4577 |
:custom_field_values => { |
4552 |
'1' => ['', 'Oracle', 'PostgreSQL']
|
|
4553 |
}
|
|
4554 |
|
|
4578 |
'1' => ['', 'Oracle', 'PostgreSQL'] |
|
4579 |
} |
|
4580 | ||
4555 | 4581 |
} |
4556 | 4582 |
} |
4557 | 4583 |
end |
... | ... | |
4572 | 4598 |
:issue => { |
4573 | 4599 |
:status_id => 2, |
4574 | 4600 |
:assigned_to_id => 3, |
4575 |
:notes => 'Assigned to dlopper'
|
|
4576 |
},
|
|
4601 |
:notes => 'Assigned to dlopper' |
|
4602 |
}, |
|
4577 | 4603 |
:time_entry => { |
4578 | 4604 |
:hours => '', |
4579 | 4605 |
:comments => '', |
4580 |
:activity_id => TimeEntryActivity.first
|
|
4606 |
:activity_id => TimeEntryActivity.first |
|
4581 | 4607 |
} |
4582 | 4608 |
} |
4583 | 4609 |
end |
... | ... | |
4603 | 4629 |
put :update, :params => { |
4604 | 4630 |
:id => 1, |
4605 | 4631 |
:issue => { |
4606 |
:notes => notes
|
|
4632 |
:notes => notes |
|
4607 | 4633 |
} |
4608 | 4634 |
} |
4609 | 4635 |
end |
... | ... | |
4671 | 4697 |
put :update, :params => { |
4672 | 4698 |
:id => 1, |
4673 | 4699 |
:issue => { |
4674 |
:notes => '2.5 hours added'
|
|
4675 |
},
|
|
4700 |
:notes => '2.5 hours added' |
|
4701 |
}, |
|
4676 | 4702 |
:time_entry => { |
4677 | 4703 |
:hours => '2.5', |
4678 | 4704 |
:comments => 'test_put_update_with_note_and_spent_time', |
4679 |
:activity_id => TimeEntryActivity.first.id
|
|
4705 |
:activity_id => TimeEntryActivity.first.id |
|
4680 | 4706 |
} |
4681 | 4707 |
} |
4682 | 4708 |
end |
... | ... | |
4730 | 4756 |
:id => 1, |
4731 | 4757 |
:issue => { |
4732 | 4758 |
:notes => '' |
4733 |
},
|
|
4759 |
}, |
|
4734 | 4760 |
:attachments => { |
4735 | 4761 |
'1' => { |
4736 |
'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}
|
|
4762 |
'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'} |
|
4737 | 4763 |
} |
4738 | 4764 |
} |
4739 | 4765 |
end |
... | ... | |
4769 | 4795 |
put :update, :params => { |
4770 | 4796 |
:id => 1, |
4771 | 4797 |
:issue => { |
4772 |
:subject => ''
|
|
4773 |
},
|
|
4798 |
:subject => '' |
|
4799 |
}, |
|
4774 | 4800 |
:attachments => { |
4775 | 4801 |
'1' => { |
4776 |
'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'}
|
|
4802 |
'file' => uploaded_test_file('testfile.txt', 'text/plain'), 'description' => 'test file'} |
|
4777 | 4803 |
} |
4778 | 4804 |
} |
4779 | 4805 |
assert_response :success |
... | ... | |
4799 | 4825 |
put :update, :params => { |
4800 | 4826 |
:id => 1, |
4801 | 4827 |
:issue => { |
4802 |
:subject => ''
|
|
4803 |
},
|
|
4828 |
:subject => '' |
|
4829 |
}, |
|
4804 | 4830 |
:attachments => { |
4805 | 4831 |
'p0' => { |
4806 |
'token' => attachment.token}
|
|
4832 |
'token' => attachment.token} |
|
4807 | 4833 |
} |
4808 | 4834 |
} |
4809 | 4835 |
assert_response :success |
... | ... | |
4826 | 4852 |
:id => 1, |
4827 | 4853 |
:issue => { |
4828 | 4854 |
:notes => 'Attachment added' |
4829 |
},
|
|
4855 |
}, |
|
4830 | 4856 |
:attachments => { |
4831 | 4857 |
'p0' => { |
4832 |
'token' => attachment.token}
|
|
4858 |
'token' => attachment.token} |
|
4833 | 4859 |
} |
4834 | 4860 |
} |
4835 | 4861 |
assert_redirected_to '/issues/1' |
... | ... | |
4854 | 4880 |
:id => 1, |
4855 | 4881 |
:issue => { |
4856 | 4882 |
:notes => '' |
4857 |
},
|
|
4883 |
}, |
|
4858 | 4884 |
:attachments => { |
4859 | 4885 |
'1' => { |
4860 |
'file' => uploaded_test_file('testfile.txt', 'text/plain')}
|
|
4886 |
'file' => uploaded_test_file('testfile.txt', 'text/plain')} |
|
4861 | 4887 |
} |
4862 | 4888 |
} |
4863 | 4889 |
assert_redirected_to :action => 'show', :id => '1' |
... | ... | |
4877 | 4903 |
:issue => { |
4878 | 4904 |
:notes => 'Removing attachments', |
4879 | 4905 |
:deleted_attachment_ids => ['1', '5'] |
4880 |
|
|
4906 | ||
4881 | 4907 |
} |
4882 | 4908 |
} |
4883 | 4909 |
end |
... | ... | |
4904 | 4930 |
:subject => '', |
4905 | 4931 |
:notes => 'Removing attachments', |
4906 | 4932 |
:deleted_attachment_ids => ['1', '5'] |
4907 |
|
|
4933 | ||
4908 | 4934 |
} |
4909 | 4935 |
} |
4910 | 4936 |
end |
... | ... | |
4947 | 4973 |
:subject => new_subject, |
4948 | 4974 |
:priority_id => '6', |
4949 | 4975 |
:category_id => '1' # no change |
4950 |
|
|
4976 | ||
4951 | 4977 |
} |
4952 | 4978 |
} |
4953 | 4979 |
assert_equal 1, ActionMailer::Base.deliveries.size |
... | ... | |
4963 | 4989 |
:id => 1, |
4964 | 4990 |
:issue => { |
4965 | 4991 |
:notes => notes |
4966 |
},
|
|
4992 |
}, |
|
4967 | 4993 |
:time_entry => { |
4968 | 4994 |
"comments"=>"", "activity_id"=>"", "hours"=>"2z" |
4969 | 4995 |
} |
... | ... | |
4985 | 5011 |
:id => 1, |
4986 | 5012 |
:issue => { |
4987 | 5013 |
:notes => notes |
4988 |
},
|
|
5014 |
}, |
|
4989 | 5015 |
:time_entry => { |
4990 | 5016 |
"comments"=>"this is my comment", "activity_id"=>"", "hours"=>"" |
4991 | 5017 |
} |
... | ... | |
5007 | 5033 |
:id => issue.id, |
5008 | 5034 |
:issue => { |
5009 | 5035 |
:fixed_version_id => 4 |
5010 |
|
|
5036 | ||
5011 | 5037 |
} |
5012 | 5038 |
} |
5013 | 5039 | |
... | ... | |
5025 | 5051 |
:id => issue.id, |
5026 | 5052 |
:issue => { |
5027 | 5053 |
:fixed_version_id => 4 |
5028 |
|
|
5029 |
},
|
|
5054 | ||
5055 |
}, |
|
5030 | 5056 |
:back_url => '/issues' |
5031 | 5057 |
} |
5032 | 5058 | |
... | ... | |
5042 | 5068 |
:id => issue.id, |
5043 | 5069 |
:issue => { |
5044 | 5070 |
:fixed_version_id => 4 |
5045 |
|
|
5046 |
},
|
|
5071 | ||
5072 |
}, |
|
5047 | 5073 |
:back_url => 'http://google.com' |
5048 | 5074 |
} |
5049 | 5075 | |
... | ... | |
5059 | 5085 |
:issue => { |
5060 | 5086 |
:status_id => 6, |
5061 | 5087 |
:notes => 'Notes' |
5062 |
},
|
|
5088 |
}, |
|
5063 | 5089 |
:prev_issue_id => 8, |
5064 | 5090 |
:next_issue_id => 12, |
5065 | 5091 |
:issue_position => 2, |
... | ... | |
5348 | 5374 |
:priority_id => 7, |
5349 | 5375 |
:assigned_to_id => '', |
5350 | 5376 |
:custom_field_values => { |
5351 |
'2' => ''}
|
|
5377 |
'2' => ''} |
|
5352 | 5378 |
} |
5353 | 5379 |
} |
5354 | 5380 | |
... | ... | |
5378 | 5404 |
:priority_id => '', |
5379 | 5405 |
:assigned_to_id => group.id, |
5380 | 5406 |
:custom_field_values => { |
5381 |
'2' => ''}
|
|
5407 |
'2' => ''} |
|
5382 | 5408 |
} |
5383 | 5409 |
} |
5384 | 5410 | |
... | ... | |
5397 | 5423 |
:priority_id => 7, |
5398 | 5424 |
:assigned_to_id => '', |
5399 | 5425 |
:custom_field_values => { |
5400 |
'2' => ''}
|
|
5426 |
'2' => ''} |
|
5401 | 5427 |
} |
5402 | 5428 |
} |
5403 | 5429 | |
... | ... | |
5425 | 5451 |
:priority_id => 7, |
5426 | 5452 |
:assigned_to_id => '', |
5427 | 5453 |
:custom_field_values => { |
5428 |
'2' => ''}
|
|
5454 |
'2' => ''} |
|
5429 | 5455 |
} |
5430 | 5456 |
} |
5431 | 5457 |
assert_response 403 |
... | ... | |
5473 | 5499 |
:id => 1, |
5474 | 5500 |
:issue => { |
5475 | 5501 |
:project_id => '2' |
5476 |
},
|
|
5502 |
}, |
|
5477 | 5503 |
:follow => '1' |
5478 | 5504 |
} |
5479 | 5505 |
assert_redirected_to '/issues/1' |
... | ... | |
5485 | 5511 |
:id => [1, 2], |
5486 | 5512 |
:issue => { |
5487 | 5513 |
:project_id => '2' |
5488 |
},
|
|
5514 |
}, |
|
5489 | 5515 |
:follow => '1' |
5490 | 5516 |
} |
5491 | 5517 |
assert_redirected_to '/projects/onlinestore/issues' |
... | ... | |
5582 | 5608 |
assert_equal 4.25, Issue.find(2).estimated_hours |
5583 | 5609 |
end |
5584 | 5610 | |
5611 |
def test_bulk_update_remaining_hours |
|
5612 |
@request.session[:user_id] = 2 |
|
5613 |
post :bulk_update, :ids => [1, 2], :issue => {:remaining_hours => 4.15} |
|
5614 | ||
5615 |
assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook' |
|
5616 |
assert_equal 4.15, Issue.find(1).remaining_hours |
|
5617 |
assert_equal 4.15, Issue.find(2).remaining_hours |
|
5618 |
end |
|
5619 | ||
5585 | 5620 |
def test_bulk_update_custom_field |
5586 | 5621 |
@request.session[:user_id] = 2 |
5587 | 5622 |
# update issues priority |
... | ... | |
5592 | 5627 |
:priority_id => '', |
5593 | 5628 |
:assigned_to_id => '', |
5594 | 5629 |
:custom_field_values => { |
5595 |
'2' => '777'}
|
|
5630 |
'2' => '777'} |
|
5596 | 5631 |
} |
5597 | 5632 |
} |
5598 | 5633 | |
... | ... | |
5615 | 5650 |
:priority_id => '', |
5616 | 5651 |
:assigned_to_id => '', |
5617 | 5652 |
:custom_field_values => { |
5618 |
'1' => '__none__'}
|
|
5653 |
'1' => '__none__'} |
|
5619 | 5654 |
} |
5620 | 5655 |
} |
5621 | 5656 |
assert_response 302 |
... | ... | |
5635 | 5670 |
:priority_id => '', |
5636 | 5671 |
:assigned_to_id => '', |
5637 | 5672 |
:custom_field_values => { |
5638 |
'1' => ['MySQL', 'Oracle']}
|
|
5673 |
'1' => ['MySQL', 'Oracle']} |
|
5639 | 5674 |
} |
5640 | 5675 |
} |
5641 | 5676 | |
... | ... | |
5659 | 5694 |
:priority_id => '', |
5660 | 5695 |
:assigned_to_id => '', |
5661 | 5696 |
:custom_field_values => { |
5662 |
'1' => ['__none__']}
|
|
5697 |
'1' => ['__none__']} |
|
5663 | 5698 |
} |
5664 | 5699 |
} |
5665 | 5700 |
assert_response 302 |
... | ... | |
5815 | 5850 |
:ids => [1, 2], |
5816 | 5851 |
:issue => { |
5817 | 5852 |
:project_id => '2' |
5818 |
},
|
|
5853 |
}, |
|
5819 | 5854 |
:copy => '1' |
5820 | 5855 |
} |
5821 | 5856 |
end |
... | ... | |
5837 | 5872 |
:ids => [1, 2, 3], |
5838 | 5873 |
:issue => { |
5839 | 5874 |
:project_id => '2' |
5840 |
},
|
|
5875 |
}, |
|
5841 | 5876 |
:copy => '1' |
5842 | 5877 |
} |
5843 | 5878 |
assert_response 302 |
... | ... | |
5852 | 5887 |
:ids => [1, 2, 3], |
5853 | 5888 |
:issue => { |
5854 | 5889 |
:project_id => '' |
5855 |
},
|
|
5890 |
}, |
|
5856 | 5891 |
:copy => '1' |
5857 | 5892 |
} |
5858 | 5893 |
assert_response 403 |
... | ... | |
5866 | 5901 |
:ids => [1, 2, 3], |
5867 | 5902 |
:issue => { |
5868 | 5903 |
:project_id => '1' |
5869 |
},
|
|
5904 |
}, |
|
5870 | 5905 |
:copy => '1' |
5871 | 5906 |
} |
5872 | 5907 |
assert_response 403 |
... | ... | |
5893 | 5928 |
:status_id => '', |
5894 | 5929 |
:start_date => '', |
5895 | 5930 |
:due_date => '' |
5896 |
|
|
5931 | ||
5897 | 5932 |
} |
5898 | 5933 |
} |
5899 | 5934 |
end |
... | ... | |
5933 | 5968 |
:status_id => '1', |
5934 | 5969 |
:start_date => '2009-12-01', |
5935 | 5970 |
:due_date => '2009-12-31' |
5936 |
|
|
5971 | ||
5937 | 5972 |
} |
5938 | 5973 |
} |
5939 | 5974 |
end |
... | ... | |
5963 | 5998 |
:status_id => '3', |
5964 | 5999 |
:start_date => '2009-12-01', |
5965 | 6000 |
:due_date => '2009-12-31' |
5966 |
|
|
6001 | ||
5967 | 6002 |
} |
5968 | 6003 |
} |
5969 | 6004 |
end |
... | ... | |
5986 | 6021 |
:copy_attachments => '0', |
5987 | 6022 |
:issue => { |
5988 | 6023 |
:project_id => '' |
5989 |
|
|
6024 | ||
5990 | 6025 |
} |
5991 | 6026 |
} |
5992 | 6027 |
end |
... | ... | |
6006 | 6041 |
:copy_attachments => '1', |
6007 | 6042 |
:issue => { |
6008 | 6043 |
:project_id => '' |
6009 |
|
|
6044 | ||
6010 | 6045 |
} |
6011 | 6046 |
} |
6012 | 6047 |
end |
... | ... | |
6024 | 6059 |
:link_copy => '1', |
6025 | 6060 |
:issue => { |
6026 | 6061 |
:project_id => '1' |
6027 |
|
|
6062 | ||
6028 | 6063 |
} |
6029 | 6064 |
} |
6030 | 6065 |
end |
... | ... | |
6042 | 6077 |
:copy_subtasks => '0', |
6043 | 6078 |
:issue => { |
6044 | 6079 |
:project_id => '' |
6045 |
|
|
6080 | ||
6046 | 6081 |
} |
6047 | 6082 |
} |
6048 | 6083 |
end |
... | ... | |
6060 | 6095 |
:copy_subtasks => '1', |
6061 | 6096 |
:issue => { |
6062 | 6097 |
:project_id => '' |
6063 |
|
|
6098 | ||
6064 | 6099 |
} |
6065 | 6100 |
} |
6066 | 6101 |
end |
... | ... | |
6079 | 6114 |
:copy_watchers => '1', |
6080 | 6115 |
:issue => { |
6081 | 6116 |
:project_id => '' |
6082 |
|
|
6117 | ||
6083 | 6118 |
} |
6084 | 6119 |
} |
6085 | 6120 |
end |
... | ... | |
6099 | 6134 |
:copy_subtasks => '1', |
6100 | 6135 |
:issue => { |
6101 | 6136 |
:project_id => '' |
6102 |
|
|
6137 | ||
6103 | 6138 |
} |
6104 | 6139 |
} |
6105 | 6140 |
end |
... | ... | |
6114 | 6149 |
:copy => '1', |
6115 | 6150 |
:issue => { |
6116 | 6151 |
:project_id => 2 |
6117 |
},
|
|
6152 |
}, |
|
6118 | 6153 |
:follow => '1' |
6119 | 6154 |
} |
6120 | 6155 |
issue = Issue.order('id DESC').first |
test/integration/api_test/issues_test.rb | ||
---|---|---|
382 | 382 |
end |
383 | 383 |
end |
384 | 384 | |
385 |
test "GET /issues/:id.xml should contains total_estimated_hours and total_spent_hours" do |
|
385 |
test "GET /issues/:id.xml should contains total_estimated_hours, total_remaining_hours and total_spent_hours" do
|
|
386 | 386 |
parent = Issue.find(3) |
387 | 387 |
parent.update_columns :estimated_hours => 2.0 |
388 |
child = Issue.generate!(:parent_issue_id => parent.id, :estimated_hours => 3.0) |
|
388 |
child = Issue.generate!(:parent_issue_id => parent.id, :estimated_hours => 3.0, :remaining_hours => 1.0)
|
|
389 | 389 |
TimeEntry.create!(:project => child.project, :issue => child, :user => child.author, :spent_on => child.author.today, |
390 | 390 |
:hours => '2.5', :comments => '', :activity_id => TimeEntryActivity.first.id) |
391 | 391 |
get '/issues/3.xml' |
... | ... | |
394 | 394 |
assert_select 'issue' do |
395 | 395 |
assert_select 'estimated_hours', parent.estimated_hours.to_s |
396 | 396 |
assert_select 'total_estimated_hours', (parent.estimated_hours.to_f + 3.0).to_s |
397 |
assert_select 'remaining_hours', parent.remaining_hours.to_s |
|
398 |
assert_select 'total_remaining_hours', (parent.remaining_hours.to_f + 1.0).to_s |
|
397 | 399 |
assert_select 'spent_hours', parent.spent_hours.to_s |
398 | 400 |
assert_select 'total_spent_hours', (parent.spent_hours.to_f + 2.5).to_s |
399 | 401 |
end |
400 | 402 |
end |
401 | 403 | |
402 |
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 |
|
404 |
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
|
|
403 | 405 |
parent = Issue.find(3) |
404 | 406 |
parent.update_columns :estimated_hours => 2.0 |
405 |
child = Issue.generate!(:parent_issue_id => parent.id, :estimated_hours => 3.0) |
|
407 |
child = Issue.generate!(:parent_issue_id => parent.id, :estimated_hours => 3.0, :remaining_hours => 1.0)
|
|
406 | 408 |
# remove permission! |
407 | 409 |
Role.anonymous.remove_permission! :view_time_entries |
408 | 410 |
#Role.all.each { |role| role.remove_permission! :view_time_entries } |
... | ... | |
412 | 414 |
assert_select 'issue' do |
413 | 415 |
assert_select 'estimated_hours', parent.estimated_hours.to_s |
414 | 416 |
assert_select 'total_estimated_hours', (parent.estimated_hours.to_f + 3.0).to_s |
417 |
assert_select 'remaining_hours', parent.remaining_hours.to_s |
|
418 |
assert_select 'total_remaining_hours', (parent.remaining_hours.to_f + 1.0).to_s |
|
415 | 419 |
assert_select 'spent_hours', false |
416 | 420 |
assert_select 'total_spent_hours', false |
417 | 421 |
end |
... | ... | |
434 | 438 |
end |
435 | 439 |
end |
436 | 440 | |
437 |
test "GET /issues/:id.json should contains total_estimated_hours and total_spent_hours" do |
|
441 |
test "GET /issues/:id.json should contains total_estimated_hours, total_remaining_hours and total_spent_hours" do
|
|
438 | 442 |
parent = Issue.find(3) |
439 | 443 |
parent.update_columns :estimated_hours => 2.0 |
440 |
child = Issue.generate!(:parent_issue_id => parent.id, :estimated_hours => 3.0) |
|
444 |
child = Issue.generate!(:parent_issue_id => parent.id, :estimated_hours => 3.0, :remaining_hours => 1.0)
|
|
441 | 445 |
TimeEntry.create!(:project => child.project, :issue => child, :user => child.author, :spent_on => child.author.today, |
442 | 446 |
:hours => '2.5', :comments => '', :activity_id => TimeEntryActivity.first.id) |
443 | 447 |
get '/issues/3.json' |
... | ... | |
446 | 450 |
json = ActiveSupport::JSON.decode(response.body) |
447 | 451 |
assert_equal parent.estimated_hours, json['issue']['estimated_hours'] |
448 | 452 |
assert_equal (parent.estimated_hours.to_f + 3.0), json['issue']['total_estimated_hours'] |
453 |
assert_equal parent.remaining_hours, json['issue']['remaining_hours'] |
|
454 |
assert_equal (parent.remaining_hours.to_f + 1.0), json['issue']['total_remaining_hours'] |
|
449 | 455 |
assert_equal parent.spent_hours, json['issue']['spent_hours'] |
450 | 456 |
assert_equal (parent.spent_hours.to_f + 2.5), json['issue']['total_spent_hours'] |
451 | 457 |
end |
452 | 458 | |
453 |
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 |
|
459 |
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
|
|
454 | 460 |
parent = Issue.find(3) |
455 | 461 |
parent.update_columns :estimated_hours => 2.0 |
456 |
child = Issue.generate!(:parent_issue_id => parent.id, :estimated_hours => 3.0) |
|
462 |
child = Issue.generate!(:parent_issue_id => parent.id, :estimated_hours => 3.0, :remaining_hours => 1.0)
|
|
457 | 463 |
# remove permission! |
458 | 464 |
Role.anonymous.remove_permission! :view_time_entries |
459 | 465 |
#Role.all.each { |role| role.remove_permission! :view_time_entries } |
... | ... | |
463 | 469 |
json = ActiveSupport::JSON.decode(response.body) |
464 | 470 |
assert_equal parent.estimated_hours, json['issue']['estimated_hours'] |
465 | 471 |
assert_equal (parent.estimated_hours.to_f + 3.0), json['issue']['total_estimated_hours'] |
472 |
assert_equal parent.remaining_hours, json['issue']['remaining_hours'] |
|
473 |
assert_equal (parent.remaining_hours.to_f + 1.0), json['issue']['total_remaining_hours'] |
|
466 | 474 |
assert_nil json['issue']['spent_hours'] |
467 | 475 |
assert_nil json['issue']['total_spent_hours'] |
468 | 476 |
end |
test/unit/helpers/issues_helper_test.rb | ||
---|---|---|
196 | 196 |
assert_match '6.30', show_detail(detail, true) |
197 | 197 |
end |
198 | 198 | |
199 |
test 'show_detail should show old and new values with a remaining hours attribute' do |
|
200 |
detail = JournalDetail.new(:property => 'attr', :prop_key => 'remaining_hours', |
|
201 |
:old_value => '6.3', :value => '5') |
|
202 |
assert_match '5.00', show_detail(detail, true) |
|
203 |
assert_match '6.30', show_detail(detail, true) |
|
204 |
end |
|
205 | ||
199 | 206 |
test 'show_detail should not show values with a description attribute' do |
200 | 207 |
detail = JournalDetail.new(:property => 'attr', :prop_key => 'description', |
201 | 208 |
: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 |
... | ... | |
339 | 339 |
assert !child.save |
340 | 340 |
assert_include I18n.t("activerecord.errors.messages.open_issue_with_closed_parent"), child.errors.full_messages |
341 | 341 |
end |
342 | ||
343 |
def test_parent_total_remaining_hours_should_be_sum_of_descendants |
|
344 |
parent = Issue.generate! |
|
345 |
parent.generate_child!(:remaining_hours => nil) |
|
346 |
assert_equal 0, parent.reload.total_remaining_hours |
|
347 |
parent.generate_child!(:remaining_hours => 5) |
|
348 |
assert_equal 5, parent.reload.total_remaining_hours |
|
349 |
parent.generate_child!(:remaining_hours => 7) |
|
350 |
assert_equal 12, parent.reload.total_remaining_hours |
|
351 |
end |
|
342 | 352 |
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') |
... | ... | |
2460 | 2479 |
user = User.find(3) |
2461 | 2480 |
user.members.update_all ["mail_notification = ?", false] |
2462 | 2481 |
user.update! :mail_notification => 'only_assigned' |
2482 |
puts user.inspect |
|
2463 | 2483 | |
2464 | 2484 |
with_settings :notified_events => %w(issue_updated) do |
2465 | 2485 |
issue = Issue.find(2) |
... | ... | |
2952 | 2972 |
assert_equal false, issue.closing? |
2953 | 2973 |
end |
2954 | 2974 | |
2975 |
def test_closing_should_set_remaining_hours_to_zero |
|
2976 |
issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, |
|
2977 |
:status_id => 1, :priority => IssuePriority.all.first, |
|
2978 |
:subject => 'test_create', |
|
2979 |
:description => 'IssueTest#test_create', :estimated_hours => '1:30', :remaining_hours => '1') |
|
2980 |
assert_equal 1, issue.remaining_hours |
|
2981 |
issue.status_id = 5 |
|
2982 |
issue.save! |
|
2983 |
assert_equal 0, issue.remaining_hours |
|
2984 |
end |
|
2985 | ||
2955 | 2986 |
def test_reopening_should_return_true_when_reopening_an_issue |
2956 | 2987 |
issue = Issue.find(8) |
2957 | 2988 |
issue.status = IssueStatus.find(6) |
test/unit/mail_handler_test.rb | ||
---|---|---|
43 | 43 |
def test_add_issue_with_specific_overrides |
44 | 44 |
issue = submit_email('ticket_on_given_project.eml', |
45 | 45 |
:allow_override => ['status', 'start_date', 'due_date', 'assigned_to', |
46 |
'fixed_version', 'estimated_hours', 'done_ratio'] |
|
46 |
'fixed_version', 'estimated_hours', 'remaining_hours', 'done_ratio']
|
|
47 | 47 |
) |
48 | 48 |
assert issue.is_a?(Issue) |
49 | 49 |
assert !issue.new_record? |
... | ... | |
59 | 59 |
assert_equal User.find_by_login('jsmith'), issue.assigned_to |
60 | 60 |
assert_equal Version.find_by_name('Alpha'), issue.fixed_version |
61 | 61 |
assert_equal 2.5, issue.estimated_hours |
62 |
assert_equal 1, issue.remaining_hours |