Class: TimeEntry

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

Overview

Redmine - project management software Copyright (C) 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.


107
108
109
110
111
112
113
114
115
# File 'app/models/time_entry.rb', line 107

def initialize(attributes=nil, *args)
  super
  if new_record? && self.activity.nil?
    if default_activity = TimeEntryActivity.default(self.project)
      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


82
83
84
85
86
87
88
89
90
91
92
# File 'app/models/time_entry.rb', line 82

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


235
236
237
238
239
240
241
242
243
# File 'app/models/time_entry.rb', line 235

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)

212
213
214
215
216
# File 'app/models/time_entry.rb', line 212

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


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

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


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

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

#hoursObject


193
194
195
196
197
198
199
200
# File 'app/models/time_entry.rb', line 193

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

#hours=(h) ⇒ Object


189
190
191
# File 'app/models/time_entry.rb', line 189

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

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


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
148
149
150
151
# File 'app/models/time_entry.rb', line 117

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


157
158
159
# File 'app/models/time_entry.rb', line 157

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

#set_project_if_nilObject


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

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


204
205
206
207
208
209
# File 'app/models/time_entry.rb', line 204

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


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

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)

95
96
97
98
99
100
101
102
103
104
105
# File 'app/models/time_entry.rb', line 95

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


228
229
230
231
232
233
# File 'app/models/time_entry.rb', line 228

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