diff options
author | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2017-07-19 14:13:10 +0000 |
---|---|---|
committer | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2017-07-19 14:13:10 +0000 |
commit | 7bd8280a83290e144b19c7ac614952d430e3e4b1 (patch) | |
tree | 14a9c754c93613a2c61f99a1a04f726325822401 | |
parent | a9d7f32da347a382d2f130cbc13187505f370fc7 (diff) | |
download | redmine-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.rb | 28 | ||||
-rw-r--r-- | app/views/settings/_timelog.html.erb | 3 | ||||
-rw-r--r-- | config/locales/en.yml | 3 | ||||
-rw-r--r-- | config/locales/fr.yml | 4 | ||||
-rw-r--r-- | config/settings.yml | 5 | ||||
-rw-r--r-- | test/object_helpers.rb | 7 | ||||
-rw-r--r-- | test/unit/time_entry_test.rb | 28 |
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 = '' |