Class: TimeEntry

Inherits:
ActiveRecord::Base
  • Object
show all
Includes:
Redmine::SafeAttributes
Defined in:
app/models/time_entry.rb

Overview

Redmine - project management software Copyright © 2006-2022 Jean-Philippe Lang

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Redmine::SafeAttributes

#delete_unsafe_attributes, included, #safe_attribute?, #safe_attribute_names

Constructor Details

#initialize(attributes = nil, *args) ⇒ TimeEntry

Returns a new instance of TimeEntry.



103
104
105
106
107
108
109
110
111
# File 'app/models/time_entry.rb', line 103

def initialize(attributes=nil, *args)
  super
  if new_record? && self.activity.nil?
    if default_activity = TimeEntryActivity.default
      self.activity_id = default_activity.id
    end
    self.hours = nil if hours == 0
  end
end

Class Method Details

.visible_condition(user, options = {}) ⇒ Object

Returns a SQL conditions string used to find all time entries visible by the specified user



78
79
80
81
82
83
84
85
86
87
88
# File 'app/models/time_entry.rb', line 78

def self.visible_condition(user, options={})
  Project.allowed_to_condition(user, :view_time_entries, options) do |role, user|
    if role.time_entries_visibility == 'all'
      nil
    elsif role.time_entries_visibility == 'own' && user.id && user.logged?
      "#{table_name}.user_id = #{user.id}"
    else
      '1=0'
    end
  end
end

Instance Method Details

#assignable_usersObject



231
232
233
234
235
236
237
238
239
# File 'app/models/time_entry.rb', line 231

def assignable_users
  users = []
  if project
    users = project.members.active.preload(:user)
    users = users.map(&:user).select{|u| u.allowed_to?(:log_time, project)}
  end
  users << User.current if User.current.logged? && !users.include?(User.current)
  users
end

#editable_by?(usr) ⇒ Boolean

Returns true if the time entry can be edited by usr, otherwise false

Returns:

  • (Boolean)


208
209
210
211
212
# File 'app/models/time_entry.rb', line 208

def editable_by?(usr)
  visible?(usr) && (
    (usr == user && usr.allowed_to?(:edit_own_time_entries, project)) || usr.allowed_to?(:edit_time_entries, project)
  )
end

#editable_custom_field_values(user = nil) ⇒ Object

Returns the custom_field_values that can be edited by the given user



215
216
217
# File 'app/models/time_entry.rb', line 215

def editable_custom_field_values(user=nil)
  visible_custom_field_values(user)
end

#editable_custom_fields(user = nil) ⇒ Object

Returns the custom fields that can be edited by the given user



220
221
222
# File 'app/models/time_entry.rb', line 220

def editable_custom_fields(user=nil)
  editable_custom_field_values(user).map(&:custom_field).uniq
end

#hoursObject



189
190
191
192
193
194
195
196
# File 'app/models/time_entry.rb', line 189

def hours
  h = read_attribute(:hours)
  if h.is_a?(Float)
    h.round(2)
  else
    h
  end
end

#hours=(h) ⇒ Object



185
186
187
# File 'app/models/time_entry.rb', line 185

def hours=(h)
  write_attribute :hours, (h.is_a?(String) ? (h.to_hours || h) : h)
end

#safe_attributes=(attrs, user = User.current) ⇒ Object



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'app/models/time_entry.rb', line 113

def safe_attributes=(attrs, user=User.current)
  if attrs
    attrs = super(attrs)
    if issue_id_changed? && issue
      if issue.visible?(user) && user.allowed_to?(:log_time, issue.project)
        if attrs[:project_id].blank? && issue.project_id != project_id
          self.project_id = issue.project_id
        end
        @invalid_issue_id = nil
      elsif user.allowed_to?(:log_time, issue.project) && issue.assigned_to_id_changed? && issue.previous_assignee == User.current
        current_assignee = issue.assigned_to
        issue.assigned_to = issue.previous_assignee
        unless issue.visible?(user)
          @invalid_issue_id = issue_id
        end
        issue.assigned_to = current_assignee
      else
        @invalid_issue_id = issue_id
      end
    end
    if user_id_changed? && user_id != author_id && !user.allowed_to?(:log_time_for_other_users, project)
      @invalid_user_id = user_id
    else
      @invalid_user_id = nil
    end

    # Delete assigned custom fields not visible by the user
    editable_custom_field_ids = editable_custom_field_values(user).map {|v| v.custom_field_id.to_s}
    self.custom_field_values.delete_if do |c|
      !editable_custom_field_ids.include?(c.custom_field.id.to_s)
    end
  end

  attrs
end

#set_author_if_nilObject



153
154
155
# File 'app/models/time_entry.rb', line 153

def set_author_if_nil
  self.author = User.current if author.nil?
end

#set_project_if_nilObject



149
150
151
# File 'app/models/time_entry.rb', line 149

def set_project_if_nil
  self.project = issue.project if issue && project.nil?
end

#spent_on=(date) ⇒ Object

tyear, tmonth, tweek assigned where setting spent_on attributes these attributes make time aggregations easier



200
201
202
203
204
205
# File 'app/models/time_entry.rb', line 200

def spent_on=(date)
  super
  self.tyear = spent_on ? spent_on.year : nil
  self.tmonth = spent_on ? spent_on.month : nil
  self.tweek = spent_on ? Date.civil(spent_on.year, spent_on.month, spent_on.day).cweek : nil
end

#validate_time_entryObject



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'app/models/time_entry.rb', line 157

def validate_time_entry
  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?
  if @invalid_user_id || (user_id_changed? && user_id != author_id && !self.assignable_users.map(&:id).include?(user_id))
    errors.add :user_id, :invalid
  end
  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)
  if spent_on_changed? && user
    errors.add :base, I18n.t(:error_spent_on_future_date) if !Setting.timelog_accept_future_dates? && (spent_on > user.today)
  end
end

#visible?(user = nil) ⇒ Boolean

Returns true if user or current user is allowed to view the time entry

Returns:

  • (Boolean)


91
92
93
94
95
96
97
98
99
100
101
# File 'app/models/time_entry.rb', line 91

def visible?(user=nil)
  (user || User.current).allowed_to?(:view_time_entries, self.project) do |role, user|
    if role.time_entries_visibility == 'all'
      true
    elsif role.time_entries_visibility == 'own'
      self.user == user
    else
      false
    end
  end
end

#visible_custom_field_values(user = nil) ⇒ Object



224
225
226
227
228
229
# File 'app/models/time_entry.rb', line 224

def visible_custom_field_values(user = nil)
  user ||= User.current
  custom_field_values.select do |value|
    value.custom_field.visible_by?(project, user)
  end
end