1# frozen_string_literal: true 2 3# == TimeTrackable concern 4# 5# Contains functionality related to objects that support time tracking. 6# 7# Used by Issue and MergeRequest. 8# 9 10module TimeTrackable 11 extend ActiveSupport::Concern 12 13 included do 14 attr_reader :time_spent, :time_spent_user, :spent_at, :summary 15 16 alias_method :time_spent?, :time_spent 17 18 default_value_for :time_estimate, value: 0, allows_nil: false 19 20 validates :time_estimate, numericality: { message: 'has an invalid format' }, allow_nil: false 21 validate :check_negative_time_spent 22 23 has_many :timelogs, dependent: :destroy, autosave: true # rubocop:disable Cop/ActiveRecordDependent 24 end 25 26 # rubocop:disable Gitlab/ModuleWithInstanceVariables 27 def spend_time(options) 28 @time_spent = options[:duration] 29 @time_spent_note_id = options[:note_id] 30 @time_spent_user = User.find(options[:user_id]) 31 @spent_at = options[:spent_at] 32 @summary = options[:summary] 33 @original_total_time_spent = nil 34 35 return if @time_spent == 0 36 37 @timelog = if @time_spent == :reset 38 reset_spent_time 39 else 40 add_or_subtract_spent_time 41 end 42 end 43 alias_method :spend_time=, :spend_time 44 # rubocop:enable Gitlab/ModuleWithInstanceVariables 45 46 def total_time_spent 47 timelogs.sum(:time_spent) 48 end 49 50 def human_total_time_spent 51 Gitlab::TimeTrackingFormatter.output(total_time_spent) 52 end 53 54 def time_change 55 @timelog&.time_spent.to_i # rubocop:disable Gitlab/ModuleWithInstanceVariables 56 end 57 58 def human_time_change 59 Gitlab::TimeTrackingFormatter.output(time_change) 60 end 61 62 def human_time_estimate 63 Gitlab::TimeTrackingFormatter.output(time_estimate) 64 end 65 66 def time_estimate=(val) 67 val.is_a?(Integer) ? super([val, Gitlab::Database::MAX_INT_VALUE].min) : super(val) 68 end 69 70 private 71 72 def reset_spent_time 73 timelogs.new(time_spent: total_time_spent * -1, user: @time_spent_user) # rubocop:disable Gitlab/ModuleWithInstanceVariables 74 end 75 76 # rubocop:disable Gitlab/ModuleWithInstanceVariables 77 def add_or_subtract_spent_time 78 timelogs.new( 79 time_spent: time_spent, 80 note_id: @time_spent_note_id, 81 user: @time_spent_user, 82 spent_at: @spent_at, 83 summary: @summary 84 ) 85 end 86 # rubocop:enable Gitlab/ModuleWithInstanceVariables 87 88 def check_negative_time_spent 89 return if time_spent.nil? || time_spent == :reset 90 91 if time_spent < 0 && (time_spent.abs > original_total_time_spent) 92 errors.add(:base, _('Time to subtract exceeds the total time spent')) 93 end 94 end 95 96 # we need to cache the total time spent so multiple calls to #valid? 97 # doesn't give a false error 98 def original_total_time_spent 99 @original_total_time_spent ||= total_time_spent 100 end 101end 102