Commit e2ac5a91 authored by jplang's avatar jplang

Better handling of update failures when bulk editing time entries.

git-svn-id: https://svn.redmine.org/redmine/trunk@16477 e93f8b46-1217-0410-a6f0-8f06a7374b81
parent 3e6d2f67
......@@ -172,19 +172,33 @@ class TimelogController < ApplicationController
def bulk_update
attributes = parse_params_for_bulk_update(params[:time_entry])
unsaved_time_entry_ids = []
unsaved_time_entries = []
saved_time_entries = []
@time_entries.each do |time_entry|
time_entry.reload
time_entry.safe_attributes = attributes
call_hook(:controller_time_entries_bulk_edit_before_save, { :params => params, :time_entry => time_entry })
unless time_entry.save
logger.info "time entry could not be updated: #{time_entry.errors.full_messages}" if logger && logger.info?
# Keep unsaved time_entry ids to display them in flash error
unsaved_time_entry_ids << time_entry.id
if time_entry.save
saved_time_entries << time_entry
else
unsaved_time_entries << time_entry
end
end
set_flash_from_bulk_time_entry_save(@time_entries, unsaved_time_entry_ids)
redirect_back_or_default project_time_entries_path(@projects.first)
if unsaved_time_entries.empty?
flash[:notice] = l(:notice_successful_update) unless saved_time_entries.empty?
redirect_back_or_default project_time_entries_path(@projects.first)
else
@saved_time_entries = @time_entries
@unsaved_time_entries = unsaved_time_entries
@time_entries = TimeEntry.where(:id => unsaved_time_entries.map(&:id)).
preload(:project => :time_entry_activities).
preload(:user).to_a
bulk_edit
render :action => 'bulk_edit'
end
end
def destroy
......@@ -243,17 +257,6 @@ private
render_404
end
def set_flash_from_bulk_time_entry_save(time_entries, unsaved_time_entry_ids)
if unsaved_time_entry_ids.empty?
flash[:notice] = l(:notice_successful_update) unless time_entries.empty?
else
flash[:error] = l(:notice_failed_to_save_time_entries,
:count => unsaved_time_entry_ids.size,
:total => time_entries.size,
:ids => '#' + unsaved_time_entry_ids.join(', #'))
end
end
def find_optional_issue
if params[:issue_id].present?
@issue = Issue.find(params[:issue_id])
......
<h2><%= l(:label_bulk_edit_selected_time_entries) %></h2>
<% if @unsaved_time_entries.present? %>
<div id="errorExplanation">
<span>
<%= l(:notice_failed_to_save_time_entries,
:count => @unsaved_time_entries.size,
:total => @saved_time_entries.size,
:ids => @unsaved_time_entries.map {|i| "##{i.id}"}.join(', ')) %>
</span>
<ul>
<% bulk_edit_error_messages(@unsaved_time_entries).each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<ul id="bulk-selection">
<% @time_entries.each do |entry| %>
<%= content_tag 'li',
......@@ -12,29 +28,29 @@
<div class="box tabular">
<div>
<p>
<label><%= l(:field_issue) %></label>
<label for="time_entry_issue_id"><%= l(:field_issue) %></label>
<%= text_field :time_entry, :issue_id, :size => 6 %>
</p>
<p>
<label><%= l(:field_spent_on) %></label>
<label for="time_entry_spent_on"><%= l(:field_spent_on) %></label>
<%= date_field :time_entry, :spent_on, :size => 10 %><%= calendar_for('time_entry_spent_on') %>
</p>
<p>
<label><%= l(:field_hours) %></label>
<label for="time_entry_hours"><%= l(:field_hours) %></label>
<%= text_field :time_entry, :hours, :size => 6 %>
</p>
<% if @available_activities.any? %>
<p>
<label><%= l(:field_activity) %></label>
<label for="time_entry_activity_id"><%= l(:field_activity) %></label>
<%= select_tag('time_entry[activity_id]', content_tag('option', l(:label_no_change_option), :value => '') + options_from_collection_for_select(@available_activities, :id, :name)) %>
</p>
<% end %>
<p>
<label><%= l(:field_comments) %></label>
<label for="time_entry_comments"><%= l(:field_comments) %></label>
<%= text_field(:time_entry, :comments, :size => 100) %>
</p>
......
......@@ -582,8 +582,8 @@ class TimelogControllerTest < Redmine::ControllerTest
@request.session[:user_id] = 2
post :bulk_update, :params => {:ids => [1, 2], :time_entry => { :hours => 'A'}}
assert_response 302
assert_match /Failed to save 2 time entrie/, flash[:error]
assert_response :success
assert_select_error /Failed to save 2 time entrie/
end
def test_bulk_update_on_different_projects
......
......@@ -20,7 +20,8 @@ require File.expand_path('../base', __FILE__)
class Redmine::UiTest::TimelogTest < Redmine::UiTest::Base
fixtures :projects, :users, :email_addresses, :roles, :members, :member_roles,
:trackers, :projects_trackers, :enabled_modules, :issue_statuses, :issues,
:enumerations, :custom_fields, :custom_values, :custom_fields_trackers
:enumerations, :custom_fields, :custom_values, :custom_fields_trackers,
:time_entries
def test_changing_project_should_update_activities
project = Project.find(1)
......@@ -41,4 +42,31 @@ class Redmine::UiTest::TimelogTest < Redmine::UiTest::Base
assert !has_content?('Design')
end
end
def test_bulk_edit
log_user 'jsmith', 'jsmith'
visit '/time_entries/bulk_edit?ids[]=1&ids[]=2&ids[]=3'
fill_in 'Hours', :with => '8.5'
select 'QA', :from => 'Activity'
page.first(:button, 'Submit').click
entries = TimeEntry.where(:id => [1,2,3]).to_a
assert entries.all? {|entry| entry.hours == 8.5}
assert entries.all? {|entry| entry.activity.name == 'QA'}
end
def test_bulk_edit_with_failure
log_user 'jsmith', 'jsmith'
visit '/time_entries/bulk_edit?ids[]=1&ids[]=2&ids[]=3'
fill_in 'Hours', :with => 'A'
page.first(:button, 'Submit').click
assert page.has_css?('#errorExplanation')
fill_in 'Hours', :with => '7'
page.first(:button, 'Submit').click
assert_equal "/projects/ecookbook/time_entries", current_path
entries = TimeEntry.where(:id => [1,2,3]).to_a
assert entries.all? {|entry| entry.hours == 7.0}
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment