summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean-Philippe Lang <jp_lang@yahoo.fr>2017-07-19 14:13:10 +0000
committerJean-Philippe Lang <jp_lang@yahoo.fr>2017-07-19 14:13:10 +0000
commit7bd8280a83290e144b19c7ac614952d430e3e4b1 (patch)
tree14a9c754c93613a2c61f99a1a04f726325822401
parenta9d7f32da347a382d2f130cbc13187505f370fc7 (diff)
downloadredmine-7bd8280a83290e144b19c7ac614952d430e3e4b1.tar.gz
redmine-7bd8280a83290e144b19c7ac614952d430e3e4b1.zip
Adds settings for time entry hours validation (#24005).
git-svn-id: http://svn.redmine.org/redmine/trunk@16832 e93f8b46-1217-0410-a6f0-8f06a7374b81
-rw-r--r--app/models/time_entry.rb28
-rw-r--r--app/views/settings/_timelog.html.erb3
-rw-r--r--config/locales/en.yml3
-rw-r--r--config/locales/fr.yml4
-rw-r--r--config/settings.yml5
-rw-r--r--test/object_helpers.rb7
-rw-r--r--test/unit/time_entry_test.rb28
7 files changed, 75 insertions, 3 deletions
diff --git a/app/models/time_entry.rb b/app/models/time_entry.rb
index 1e0f5bc95..80d14ad15 100644
--- a/app/models/time_entry.rb
+++ b/app/models/time_entry.rb
@@ -122,7 +122,19 @@ class TimeEntry < ActiveRecord::Base
end
def validate_time_entry
- errors.add :hours, :invalid if hours && (hours < 0 || hours >= 1000)
+ if hours
+ errors.add :hours, :invalid if hours < 0
+ errors.add :hours, :invalid if hours == 0.0 && hours_changed? && !Setting.timelog_accept_0_hours?
+
+ max_hours = Setting.timelog_max_hours_per_day.to_f
+ if hours_changed? && max_hours > 0.0
+ logged_hours = other_hours_with_same_user_and_day
+ if logged_hours + hours > max_hours
+ errors.add :base, I18n.t(:error_exceeds_maximum_hours_per_day,
+ :logged_hours => format_hours(logged_hours), :max_hours => format_hours(max_hours))
+ end
+ end
+ end
errors.add :project_id, :invalid if project.nil?
errors.add :issue_id, :invalid if (issue_id && !issue) || (issue && project!=issue.project) || @invalid_issue_id
errors.add :activity_id, :inclusion if activity_id_changed? && project && !project.activities.include?(activity)
@@ -166,4 +178,18 @@ class TimeEntry < ActiveRecord::Base
def editable_custom_fields(user=nil)
editable_custom_field_values(user).map(&:custom_field).uniq
end
+
+ private
+
+ # Returns the hours that were logged in other time entries for the same user and the same day
+ def other_hours_with_same_user_and_day
+ if user_id && spent_on
+ TimeEntry.
+ where(:user_id => user_id, :spent_on => spent_on).
+ where.not(:id => id).
+ sum(:hours).to_f
+ else
+ 0.0
+ end
+ end
end
diff --git a/app/views/settings/_timelog.html.erb b/app/views/settings/_timelog.html.erb
index c4453a616..e3c0a5657 100644
--- a/app/views/settings/_timelog.html.erb
+++ b/app/views/settings/_timelog.html.erb
@@ -4,6 +4,9 @@
<p><%= setting_multiselect(:timelog_required_fields,
[[l(:field_issue), 'issue_id'], [l(:field_comments), 'comments'] ]) %></p>
+<p><%= setting_text_field :timelog_max_hours_per_day, :size => 6 %></p>
+
+<p><%= setting_check_box :timelog_accept_0_hours %></p>
</div>
<fieldset class="box">
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 281872711..0dac83a06 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -220,6 +220,7 @@ en:
error_move_of_child_not_possible: "Subtask %{child} could not be moved to the new project: %{errors}"
error_cannot_reassign_time_entries_to_an_issue_about_to_be_deleted: "Spent time cannot be reassigned to an issue that is about to be deleted"
warning_fields_cleared_on_bulk_edit: "Changes will result in the automatic deletion of values from one or more fields on the selected objects"
+ error_exceeds_maximum_hours_per_day: "Cannot log more than %{max_hours} hours on the same day (%{logged_hours} hours have already been logged)"
mail_subject_lost_password: "Your %{value} password"
mail_body_lost_password: 'To change your password, click on the following link:'
@@ -464,6 +465,8 @@ en:
setting_timelog_required_fields: Required fields for time logs
setting_close_duplicate_issues: Close duplicate issues automatically
setting_time_entry_list_defaults: Timelog list defaults
+ setting_timelog_accept_0_hours: Accept time logs with 0 hours
+ setting_timelog_max_hours_per_day: Maximum hours that can be logged per day and user
permission_add_project: Create project
permission_add_subprojects: Create subprojects
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index 02d4570f0..e029b5e04 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -240,6 +240,7 @@ fr:
error_move_of_child_not_possible: "La sous-tâche %{child} n'a pas pu être déplacée dans le nouveau projet : %{errors}"
error_cannot_reassign_time_entries_to_an_issue_about_to_be_deleted: "Le temps passé ne peut pas être réaffecté à une demande qui va être supprimée"
warning_fields_cleared_on_bulk_edit: "Les changements apportés entraîneront la suppression automatique des valeurs d'un ou plusieurs champs sur les objets sélectionnés"
+ error_exceeds_maximum_hours_per_day: "Impossible de saisir plus de %{max_hours} heures pour le même jour (%{logged_hours} heures ont déjà été saisies)"
mail_subject_lost_password: "Votre mot de passe %{value}"
mail_body_lost_password: 'Pour changer votre mot de passe, cliquez sur le lien suivant :'
@@ -476,7 +477,8 @@ fr:
setting_timelog_required_fields: Champs obligatoire pour les temps passés
setting_close_duplicate_issues: Fermer les doublons automatiquement
setting_time_entry_list_defaults: Affichage par défaut de la liste des temps passés
-
+ setting_timelog_accept_0_hours: Autoriser la saisie de temps avec 0 heure
+ setting_timelog_max_hours_per_day: Maximum d'heures pouvant être saisies par un utilisateur sur un jour
permission_add_project: Créer un projet
permission_add_subprojects: Créer des sous-projets
diff --git a/config/settings.yml b/config/settings.yml
index 556014a6a..03581a235 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -302,3 +302,8 @@ new_item_menu_tab:
timelog_required_fields:
serialized: true
default: []
+timelog_accept_0_hours:
+ default: 1
+timelog_max_hours_per_day:
+ format: int
+ default: 999
diff --git a/test/object_helpers.rb b/test/object_helpers.rb
index f827cd150..ce38356a9 100644
--- a/test/object_helpers.rb
+++ b/test/object_helpers.rb
@@ -139,7 +139,7 @@ module ObjectHelpers
version
end
- def TimeEntry.generate!(attributes={})
+ def TimeEntry.generate(attributes={})
entry = TimeEntry.new(attributes)
entry.user ||= User.find(2)
entry.issue ||= Issue.find(1) unless entry.project
@@ -147,6 +147,11 @@ module ObjectHelpers
entry.activity ||= TimeEntryActivity.first
entry.spent_on ||= Date.today
entry.hours ||= 1.0
+ entry
+ end
+
+ def TimeEntry.generate!(attributes={}, &block)
+ entry = TimeEntry.generate(attributes, &block)
entry.save!
entry
end
diff --git a/test/unit/time_entry_test.rb b/test/unit/time_entry_test.rb
index 6476dc523..9b3fbf78b 100644
--- a/test/unit/time_entry_test.rb
+++ b/test/unit/time_entry_test.rb
@@ -91,6 +91,34 @@ class TimeEntryTest < ActiveSupport::TestCase
assert_nil TimeEntry.new.hours
end
+ def test_should_accept_0_hours
+ entry = TimeEntry.generate
+ entry.hours = 0
+ assert entry.save
+ end
+
+ def test_should_not_accept_0_hours_if_disabled
+ with_settings :timelog_accept_0_hours => '0' do
+ entry = TimeEntry.generate
+ entry.hours = 0
+ assert !entry.save
+ assert entry.errors[:hours].present?
+ end
+ end
+
+ def test_should_not_accept_more_than_maximum_hours_per_day_and_user
+ with_settings :timelog_max_hours_per_day => '8' do
+ entry = TimeEntry.generate(:spent_on => '2017-07-16', :hours => 6.0, :user_id => 2)
+ assert entry.save
+
+ entry = TimeEntry.generate(:spent_on => '2017-07-16', :hours => 1.5, :user_id => 2)
+ assert entry.save
+
+ entry = TimeEntry.generate(:spent_on => '2017-07-16', :hours => 3.0, :user_id => 2)
+ assert !entry.save
+ end
+ end
+
def test_spent_on_with_blank
c = TimeEntry.new
c.spent_on = ''