class TheFox::Timr::Model::Task

Attributes

current_track[R]
description[R]
foreign_id[R]
has_flat_rate[R]
hourly_rate[R]

Public Class Methods

create_task_from_hash(options) click to toggle source

Create a new Task using a Hash.

Options:

  • `:name` (String)

  • `:description` (String)

  • `:estimation` (String|Integer|Duration)

  • `:hourly_rate` (Integer)

# File lib/timr/model/task.rb, line 1017
def create_task_from_hash(options)
        task = Task.new
        task.name = options.fetch(:name, nil)
        task.description = options.fetch(:description, nil)
        task.estimation = options.fetch(:estimation, nil)
        task.hourly_rate = options.fetch(:hourly_rate, nil)
        task.has_flat_rate = options.fetch(:has_flat_rate, false)
        task
end
load_task_from_file(path) click to toggle source

Load a Task from a file into a Task instance.

# File lib/timr/model/task.rb, line 994
def load_task_from_file(path)
        task = Task.new
        task.load_from_file(path)
        task
end
load_task_from_file_with_id(base_path, task_id) click to toggle source

Search a Task in a base path for a Track by ID. If found a file load it into a Task instance.

# File lib/timr/model/task.rb, line 1002
def load_task_from_file_with_id(base_path, task_id)
        task_file_path = BasicModel.find_file_by_id(base_path, task_id)
        if task_file_path
                load_task_from_file(task_file_path)
        end
end
new() click to toggle source
Calls superclass method TheFox::Timr::Model::BasicModel::new
# File lib/timr/model/task.rb, line 16
def initialize
        super()
        
        # Meta
        @foreign_id = nil # --id
        @name = nil
        @description = nil
        @current_track = nil
        @estimation = nil
        @hourly_rate = nil
        @has_flat_rate = false
        
        # Data
        @tracks = Hash.new
end

Public Instance Methods

add_track(track, set_as_current_track = false) click to toggle source

Add a Track.

# File lib/timr/model/task.rb, line 80
def add_track(track, set_as_current_track = false)
        track.task = self
        
        @tracks[track.id] = track
        
        if set_as_current_track
                @current_track = track
        end
        
        # Mark Task as changed.
        changed
end
begin_datetime(options = Hash.new) click to toggle source

Uses `tracks()` with `options` to filter.

Options:

  • `:from`

# File lib/timr/model/task.rb, line 317
def begin_datetime(options = Hash.new)
        from_opt = options.fetch(:from, nil)
        
        # Cache
        # if @begin_datetime
        #  return @begin_datetime
        # end
        # Cannot use this cache because of :from :to range limitation.
        # It needs always to be direct from child Tracks, because the
        # cache does not know when the begin and end datetimes of the
        # child Tracks change.
        
        # Do not sort. We only need to sort the tracks
        # by begin_datetime and take the first.
        options[:sort] = false
        
        first_track = tracks(options)
                .select{ |track_id, track| track.begin_datetime } # filter nil
                .sort_by{ |track_id, track| track.begin_datetime }
                .to_h # sort_by makes [[]]
                .values # no keys to take the first
                .first
        
        if first_track
                bdt = first_track.begin_datetime(options)
        end
        
        if from_opt && bdt && from_opt > bdt
                bdt = from_opt
        end
        
        bdt
end
begin_datetime_s(options = Hash.new) click to toggle source

Options:

  • `:format`

# File lib/timr/model/task.rb, line 354
def begin_datetime_s(options = Hash.new)
        format_opt = options.fetch(:format, HUMAN_DATETIME_FOMRAT)
        
        bdt = begin_datetime(options)
        if bdt
                bdt.strftime(format_opt)
        else
                '---'
        end
end
billed_duration(options = Hash.new) click to toggle source

Alias for `duration` method.

Options:

  • `:billed` (Boolean)

# File lib/timr/model/task.rb, line 660
def billed_duration(options = Hash.new)
        duration(options.merge({:billed => true}))
end
consumed_budge() click to toggle source

Get the actual consumed budge.

# File lib/timr/model/task.rb, line 503
def consumed_budge
        if @hourly_rate
                duration.to_i.to_f / 3600.0 * @hourly_rate
        else
                0.0
        end
end
continue(options = Hash.new) click to toggle source

Continues the current Track. Only if it isn't already running.

# File lib/timr/model/task.rb, line 608
def continue(options = Hash.new)
        track_opt = options.fetch(:track, nil)
        
        if @current_track
                if @current_track.stopped?
                        
                        # Duplicate and start.
                        @current_track = @current_track.dup
                        @current_track.start(options)
                        
                        
                        add_track(@current_track)
                else
                        raise TrackError, "Cannot continue Track #{@current_track.short_id}, is already running."
                end
        else
                unless track_opt
                        raise TaskError, 'No Track given.'
                end
                
                # Duplicate and start.
                @current_track = track_opt.dup
                @current_track.start(options)
                
                add_track(@current_track)
        end
        
        @current_track
end
description=(description) click to toggle source

Set description.

# File lib/timr/model/task.rb, line 72
def description=(description)
        @description = description
        
        # Mark Task as changed.
        changed
end
duration(options = Hash.new) click to toggle source

Consumed duration.

Options:

  • `:billed` (Boolean)

# File lib/timr/model/task.rb, line 643
def duration(options = Hash.new)
        billed_opt = options.fetch(:billed, nil)
        
        duration = Duration.new
        @tracks.each do |track_id, track|
                if billed_opt.nil? || (billed_opt && track.is_billed) || (!billed_opt && !track.is_billed)
                        duration += track.duration(options)
                end
        end
        duration
end
end_datetime(options = Hash.new) click to toggle source

Uses `tracks()` with `options` to filter.

Options:

  • `:to`

# File lib/timr/model/task.rb, line 370
def end_datetime(options = Hash.new)
        to_opt = options.fetch(:to, nil)
        
        # Cache
        # if @end_datetime
        #  return @end_datetime
        # end
        # Cannot use this cache because of :from :to range limitation.
        # It needs always to be direct from child Tracks, because the
        # cache does not know when the begin and end datetimes of the
        # child Tracks change.
        
        # Do not sort. We only need to sort the tracks
        # by end_datetime and take the last.
        options[:sort] = false
        
        last_track = tracks(options)
                .select{ |track_id, track| track.end_datetime } # filter nil
                .sort_by{ |track_id, track| track.end_datetime }
                .to_h # sort_by makes [[]]
                .values # no keys to take the last
                .last
        
        if last_track
                edt = last_track.end_datetime(options)
        end
        
        if to_opt && edt && to_opt < edt
                edt = to_opt
        end
        
        edt
end
end_datetime_s(options = Hash.new) click to toggle source

Options:

  • `:format`

# File lib/timr/model/task.rb, line 407
def end_datetime_s(options = Hash.new)
        format_opt = options.fetch(:format, HUMAN_DATETIME_FOMRAT)
        
        edt = end_datetime(options)
        if edt
                edt.strftime(format_opt)
        else
                '---'
        end
end
eql?(task) click to toggle source

Are two Tasks equal?

Uses ID for comparision.

# File lib/timr/model/task.rb, line 767
def eql?(task)
        unless task.is_a?(Task)
                raise TaskError, "task variable must be a Task instance. #{task.class} given."
        end
        
        self.id == task.id
end
estimated_budge() click to toggle source

Calculate the budge based on estimation.

# File lib/timr/model/task.rb, line 512
def estimated_budge
        if @hourly_rate
                estimation.to_i.to_f / 3600.0 * @hourly_rate
        else
                0.0
        end
end
estimation() click to toggle source

Get estimation.

# File lib/timr/model/task.rb, line 469
def estimation
        @estimation
end
estimation=(estimation) click to toggle source

Set estimation.

Either using a Duration instance, Integer or a String like `2h 30m`. Estimation is parsed by [chronic_duration](github.com/henrypoydar/chronic_duration).

Examples:

  • `-e 2:10:5`

    Sets Estimation to 2h 10m 5s.

  • `-e '2h 10m 5s'`

    Sets Estimation to 2h 10m 5s.

Use `+` or `-` to calculate with Estimation Times:

  • `-e '-45m'`

    Subtracts 45 minutes from the original Estimation.

  • `-e '+1h 30m'`

    Adds 1 hour 30 minutes to the original Estimation.

See [chronic_duration](github.com/henrypoydar/chronic_duration) for more examples.

# File lib/timr/model/task.rb, line 439
def estimation=(estimation)
        case estimation
        when String
                # Cannot use estimation.strip! because frozen.
                estimation = estimation.strip
                
                if estimation[0] == '+'
                        estimation = estimation[1..-1]
                        @estimation += Duration.parse(estimation)
                elsif estimation[0] == '-'
                        estimation = estimation[1..-1]
                        @estimation -= Duration.parse(estimation)
                else
                        @estimation = Duration.parse(estimation)
                end
        when Integer
                @estimation = Duration.new(estimation)
        when Duration
                @estimation = estimation
        when nil
                @estimation = estimation
        else
                raise TaskError, "estimation needs to be an instance of String, Integer, Duration or nil, #{estimation.class} given."
        end
        
        # Mark Task as changed.
        changed
end
estimation_s() click to toggle source

Get estimation as String.

# File lib/timr/model/task.rb, line 474
def estimation_s
        if @estimation
                @estimation.to_human_s
        else
                '---'
        end
end
find_track_by_id(track_id) click to toggle source

Find a Track by ID even if the ID is not 40 characters long. When the ID is 40 characters long `@tracks` is faster. ;)

# File lib/timr/model/task.rb, line 739
def find_track_by_id(track_id)
        track_id_len = track_id.length
        
        # puts "search track id '#{track_id}'"
        
        if track_id_len < 40
                found_track_id = nil
                @tracks.keys.each do |key|
                        if track_id == key[0, track_id_len]
                                if found_track_id
                                        raise TrackError, "Track ID '#{track_id}' is not a unique identifier."
                                else
                                        found_track_id = key
                                        
                                        # Do not break the loop here.
                                        # Iterate all keys to make sure the ID is unique.
                                end
                        end
                end
                track_id = found_track_id
        end
        
        @tracks[track_id]
end
foreign_id=(foreign_id) click to toggle source
# File lib/timr/model/task.rb, line 37
def foreign_id=(foreign_id)
        @foreign_id = foreign_id
        
        # Mark Task as changed.
        changed
end
formatted(options = Hash.new) click to toggle source

Return formatted String.

Options:

  • `:format`

  • `:prefix` - Default: `%`

Format:

  • `%id` - ID

  • `%sid` - Short ID

  • `%fid` - Foreign ID

  • `%n` - Name

  • `%d` - Description

  • `%ds` - Duration Seconds

  • `%dh` - Duration Human Format

# File lib/timr/model/task.rb, line 962
def formatted(options = Hash.new)
        format = options.fetch(:format, '')
        prefix = options.fetch(:prefix, '%')
        
        formatted_s = format
                .gsub("#{prefix}id", self.id)
                .gsub("#{prefix}sid", self.short_id ? self.short_id : '')
                .gsub("#{prefix}fid", self.foreign_id ? self.foreign_id : '')
                .gsub("#{prefix}n", self.name ? self.name : '')
                .gsub("#{prefix}ds", self.duration(options).to_s)
        
        duration_human = self.duration(options).to_human
        if duration_human
                formatted_s.gsub!('%dh', duration_human)
        else
                formatted_s.gsub!('%dh', '')
        end
        
        # Must not before %dh and %ds.
        formatted_s.gsub!("#{prefix}d", self.description ? self.description : '')
        
        formatted_s
end
has_flat_rate=(has_flat_rate) click to toggle source

Set has_flat_rate.

# File lib/timr/model/task.rb, line 495
def has_flat_rate=(has_flat_rate)
        @has_flat_rate = has_flat_rate
        
        # Mark Task as changed.
        changed
end
hourly_rate=(new_hourly_rate) click to toggle source

Set hourly_rate.

# File lib/timr/model/task.rb, line 483
def hourly_rate=(new_hourly_rate)
        if new_hourly_rate.nil?
                @hourly_rate = nil
        else
                @hourly_rate = new_hourly_rate.to_f
        end
        
        # Mark Task as changed.
        changed
end
id_foreign_or_short() click to toggle source

Get Foreign ID or Short ID.

# File lib/timr/model/task.rb, line 33
def id_foreign_or_short
        @foreign_id ? @foreign_id : short_id
end
inspect() click to toggle source
# File lib/timr/model/task.rb, line 986
def inspect
        "#<Task_#{short_id} tracks=#{@tracks.count}>"
end
is_billed=(is_billed) click to toggle source

Set is_billed.

# File lib/timr/model/task.rb, line 731
def is_billed=(is_billed)
        @tracks.each do |track_id, track|
                track.is_billed = is_billed
        end
end
loss_budge() click to toggle source

Calculates the budge loss when a Flat Rate is used and the consumed duration is greater than the estimation.

# File lib/timr/model/task.rb, line 521
def loss_budge
        if @has_flat_rate && @hourly_rate
                if duration > estimation
                        (duration - estimation).to_i.to_f / 3600.0 * @hourly_rate
                else
                        0.0
                end
        else
                0.0
        end
end
move_track(track, target_task) click to toggle source

Move a Track to another Task.

# File lib/timr/model/task.rb, line 107
def move_track(track, target_task)
        if eql?(target_task)
                return false
        end
        
        unless remove_track(track)
                return false
        end
        
        set_as_current_track = false
        if @current_track && @current_track.eql?(track)
                @current_track = nil
                set_as_current_track = true
        end
        
        target_task.add_track(track, set_as_current_track)
        
        true
end
name(max_length = nil) click to toggle source

Get name.

# File lib/timr/model/task.rb, line 53
def name(max_length = nil)
        name = @name
        if name && max_length && name.length > max_length + 2
                name = name[0, max_length] << '...'
        end
        name
end
name=(name) click to toggle source

Set name.

# File lib/timr/model/task.rb, line 45
def name=(name)
        @name = name
        
        # Mark Task as changed.
        changed
end
name_s(max_length = nil) click to toggle source

Get name or `—` if name is not set.

# File lib/timr/model/task.rb, line 62
def name_s(max_length = nil)
        s = name(max_length)
        if s.nil?
                '---'
        else
                s
        end
end
pause(options = Hash.new) click to toggle source

Pauses a current running Track.

# File lib/timr/model/task.rb, line 595
def pause(options = Hash.new)
        if @current_track
                @current_track.stop(options)
                
                # Mark Task as changed.
                changed
                
                @current_track
        end
end
remaining_time() click to toggle source

Get the remaining Time of estimation.

Returns a Duration instance.

# File lib/timr/model/task.rb, line 676
def remaining_time
        if @estimation
                estimation - duration
        end
end
remaining_time_percent() click to toggle source

Get the remaining Time as percent.

# File lib/timr/model/task.rb, line 696
def remaining_time_percent
        rmt = remaining_time
        if rmt && @estimation
                (rmt.to_i.to_f / @estimation.to_i.to_f) * 100.0
        end
end
remaining_time_percent_s() click to toggle source

Get the remaining Time Percent as String.

# File lib/timr/model/task.rb, line 704
def remaining_time_percent_s
        rmtp = remaining_time_percent
        if rmtp
                '%.1f %%' % [rmtp]
        else
                '---'
        end
end
remaining_time_s() click to toggle source

Get the remaining Time as Human String.

  • Like `2h 30m`.

  • Or `—` when `@estimation` is `nil`.

# File lib/timr/model/task.rb, line 686
def remaining_time_s
        rmt = remaining_time
        if rmt
                rmt.to_human_s
        else
                '---'
        end
end
remove_track(track) click to toggle source

Remove a Track.

# File lib/timr/model/task.rb, line 94
def remove_track(track)
        track.task = nil
        
        if @tracks.delete(track.id)
                # Mark Task as changed.
                changed
        else
                # Track is not assiged to this Task.
                false
        end
end
reset() click to toggle source
# File lib/timr/model/task.rb, line 127
def reset
        if @current_track
                @current_track = nil
                
                # Mark Task as changed.
                changed
        end
end
start(options = Hash.new) click to toggle source

Start a new Track by given `options`.

Options:

  • `:foreign_id` (String)

  • `:track_id` (String)

  • `:no_stop` (Boolean)

# File lib/timr/model/task.rb, line 540
def start(options = Hash.new)
        foreign_id_opt = options.fetch(:foreign_id, nil)
        track_id_opt = options.fetch(:track_id, nil)
        
        # Used by Push.
        no_stop_opt = options.fetch(:no_stop, false)
        
        unless no_stop_opt
                # End current Track before starting a new one.
                # Leave options empty here for stop().
                stop
        end
        
        if foreign_id_opt && @foreign_id.nil?
                @foreign_id = foreign_id_opt
        end
        
        if track_id_opt
                found_track = find_track_by_id(track_id_opt)
                if found_track
                        
                        @current_track = found_track.dup
                else
                        raise TrackError, "No Track found for Track ID '#{track_id_opt}'."
                end
        else
                @current_track = Track.new
                @current_track.task = self
        end
        
        @tracks[@current_track.id] = @current_track
        
        # Mark Task as changed.
        changed
        
        @current_track.start(options)
        @current_track
end
status() click to toggle source

Get Task status as Status instance.

# File lib/timr/model/task.rb, line 714
def status
        stati = @tracks.map{ |track_id, track| track.status.short_status }.to_set
        
        if @tracks.count == 0
                status = ?-
        elsif stati.include?(?R)
                status = ?R
        elsif stati.include?(?S)
                status = ?S
        else
                status = ?U
        end
        
        Status.new(status)
end
stop(options = Hash.new) click to toggle source

Stops a current running Track.

# File lib/timr/model/task.rb, line 580
def stop(options = Hash.new)
        if @current_track
                @current_track.stop(options)
                
                # Reset current Track variable.
                @current_track = nil
                
                # Mark Task as changed.
                changed
        end
        
        nil
end
to_compact_array() click to toggle source

Used to print informations to STDOUT.

# File lib/timr/model/task.rb, line 806
def to_compact_array
        full_id = self.foreign_id ? self.foreign_id : self.short_id
        
        to_ax = Array.new
        to_ax << 'Task: %s %s' % [full_id, self.name]
        if self.description
                to_ax << 'Description: %s' % [self.description]
        end
        if self.estimation
                to_ax << 'Estimation: %s' % [self.estimation.to_human_s]
        end
        to_ax
end
to_compact_str() click to toggle source

Used to print informations to STDOUT.

# File lib/timr/model/task.rb, line 801
def to_compact_str
        to_compact_array.join("\n")
end
to_detailed_array(options = Hash.new) click to toggle source

Used to print informations to STDOUT.

Options:

  • `:full_id` (Boolean) Show full Task ID.

# File lib/timr/model/task.rb, line 830
def to_detailed_array(options = Hash.new)
        full_id_opt = options.fetch(:full_id, false)
        
        full_id = full_id_opt ? self.id : self.short_id
        
        to_ax = Array.new
        
        to_ax << 'Task: %s' % [full_id]
        
        if self.foreign_id
                to_ax << 'Foreign ID: %s' % [self.foreign_id]
        end
        
        to_ax << 'Name: %s' % [self.name]
        
        if self.description
                to_ax << 'Description: %s' % [self.description]
        end
        
        # Duration
        duration_human = self.duration.to_human_s
        to_ax << 'Duration: %s' % [duration_human]
        
        duration_man_days = self.duration.to_man_days
        if duration_human != duration_man_days
                to_ax << 'Man Unit: %s' % [duration_man_days]
        end
        
        # Billed Duration
        billed_duration_human = self.billed_duration.to_human
        to_ax << 'Billed   Duration: %s' % [billed_duration_human]
        
        # Unbilled Duration
        unbilled_duration_human = self.unbilled_duration.to_human
        to_ax << 'Unbilled Duration: %s' % [unbilled_duration_human]
        
        if self.estimation
                to_ax << 'Estimation:     %s' % [self.estimation.to_human]
                
                to_ax << 'Time Remaining: %s (%s)' % [self.remaining_time_s, self.remaining_time_percent_s]
                
                bar_options = {
                        :total => self.estimation.to_i,
                        :progress => self.duration.to_i,
                        :length => 50,
                        :progress_mark => '#',
                        :remainder_mark => '-',
                }
                bar = ProgressBar.new(bar_options)
                
                to_ax << '                |%s|' % [bar.render]
        end
        
        if self.hourly_rate
                to_ax << 'Hourly Rate:     %.2f' % [self.hourly_rate]
                to_ax << 'Flat Rate:       %s' % [@has_flat_rate ? 'Yes' : 'No']
                
                to_ax << 'Consumed Budge:  %.2f' % [self.consumed_budge]
                
                if self.estimation
                        to_ax << 'Estimated Budge: %.2f' % [self.estimated_budge]
                end
                
                if @has_flat_rate
                        to_ax << 'Loss Budge:      %.2f' % [self.loss_budge]
                end
        end
        
        tracks = self.tracks
        first_track = tracks
                .select{ |track_id, track| track.begin_datetime }
                .sort_by{ |track_id, track| track.begin_datetime }
                .to_h
                .values
                .first
        if first_track
                to_ax << 'Begin Track: %s  %s' % [first_track.short_id, first_track.begin_datetime_s]
        end
        
        last_track = tracks
                .select{ |track_id, track| track.end_datetime }
                .sort_by{ |track_id, track| track.end_datetime }
                .to_h
                .values
                .last
        if last_track
                to_ax << 'End   Track: %s  %s' % [last_track.short_id, last_track.end_datetime_s]
        end
        
        status = self.status.colorized
        to_ax << 'Status: %s' % [status]
        
        if @current_track
                to_ax << 'Current Track: %s %s' % [@current_track.short_id, @current_track.title]
        end
        
        tracks_count = tracks.count
        to_ax << 'Tracks:          %d' % [tracks_count]
        
        billed_tracks_count = tracks({:billed => true}).count
        to_ax << 'Billed Tracks:   %d' % [billed_tracks_count]
        
        unbilled_tracks_count = tracks({:billed => false}).count
        to_ax << 'Unbilled Tracks: %d' % [unbilled_tracks_count]
        
        if tracks_count > 0 && @tracks_opt # --tracks
                to_ax << 'Track IDs: %s' % [tracks.map{ |track_id, track| track.short_id }.join(' ')]
        end
        
        if self.file_path
                to_ax << 'File path: %s' % [self.file_path]
        end
        
        to_ax
end
to_detailed_str() click to toggle source

Used to print informations to STDOUT.

# File lib/timr/model/task.rb, line 821
def to_detailed_str
        to_detailed_array.join("\n")
end
to_s() click to toggle source

To String

# File lib/timr/model/task.rb, line 776
def to_s
        "Task_#{short_id}"
end
to_track_array(options = Hash.new) click to toggle source

Use to print informations for Track.

Options:

  • `:full_id` (Boolean) Show full Task ID.

# File lib/timr/model/task.rb, line 785
def to_track_array(options = Hash.new)
        full_id_opt = options.fetch(:full_id, false) # @TODO full_id unit test
        
        full_id = full_id_opt ? self.id : ( self.foreign_id ? self.foreign_id : self.short_id )
        
        name_a = ['Task:', full_id]
        if self.name
                name_a << self.name
        end
        
        to_ax = Array.new
        to_ax << name_a.join(' ')
        to_ax
end
tracks(options = Hash.new) click to toggle source

Select Track by Time Range and/or Status.

Options:

  • `:from`, `:to` limit the begin and end datetimes to a specific range.

  • `:status` filter Tracks by Short Status.

  • `:billed` filter Tracks by is_billed flag.

    • `true` filter billed Tracks.

    • `false` filter unbilled Tracks.

    • `nil` filter off.

Fixed Start and End (`from != nil && to != nil`)

“` Selected Range |———-| Track A ----------------- Track B ------ Track C ------------ Track D ---- Track E --- Track F --- “`

  • Track A is bigger then the Options range. Take it.

  • Track B ends in the Options range. Take it.

  • Track C starts in the Options range. Take it.

  • Track D starts and ends within the Options range. Definitely take this.

  • Track E is out-of-score. Ignore it.

  • Track F is out-of-score. Ignore it.


Open End (`to == nil`)

Take all except Track E.

“` Selected Range |———-> Track A ----------------- Track B ------ Track C ------------ Track D ---- Track E --- Track F --- “`


Open Start (`from == nil`)

Take all except Track F.

“` Selected Range <———-| Track A ----------------- Track B ------ Track C ------------ Track D ---- Track E --- Track F --- “`

# File lib/timr/model/task.rb, line 195
def tracks(options = Hash.new)
        from_opt = options.fetch(:from, nil)
        to_opt = options.fetch(:to, nil)
        status_opt = options.fetch(:status, nil)
        sort_opt = options.fetch(:sort, true)
        billed_opt = options.fetch(:billed, nil)
        
        if status_opt
                case status_opt
                when String
                        status_opt = [status_opt]
                when Array
                        # OK
                else
                        raise TaskError, ":status needs to be an instance of String or Array, #{status_opt.class} given."
                end
        end
        
        if from_opt && to_opt && from_opt > to_opt
                raise TaskError, 'From cannot be bigger than To.'
        end
        
        filtered_tracks = Hash.new
        if from_opt.nil? && to_opt.nil?
                # Take all Tracks.
                filtered_tracks = @tracks.select{ |track_id, track|
                        # Filter Tracks with no Begin DateTime.
                        # This can happen when 'timr track add' without any DateTime.
                        !track.begin_datetime.nil?
                }
        elsif !from_opt.nil? && to_opt.nil?
                # Open End (to_opt == nil)
                filtered_tracks = @tracks.select{ |track_id, track|
                        bdt = track.begin_datetime
                        edt = track.end_datetime || Time.now
                        
                        bdt && ( \
                                # Track A, B
                                bdt <  from_opt && edt >  from_opt || \
                                
                                # Track C, D, F
                                bdt >= from_opt && edt >= from_opt
                        )
                }
        elsif from_opt.nil? && !to_opt.nil?
                # Open Start (from_opt == nil)
                filtered_tracks = @tracks.select{ |track_id, track|
                        bdt = track.begin_datetime
                        edt = track.end_datetime || Time.now
                        
                        bdt && ( \
                                # Track B, D, E
                                bdt <  to_opt && edt <= to_opt || \
                                
                                # Track A, C
                                bdt <  to_opt && edt >  to_opt
                        )
                }
        elsif !from_opt.nil? && !to_opt.nil?
                # Fixed Start and End (from_opt != nil && to_opt != nil)
                filtered_tracks = @tracks.select{ |track_id, track|
                        bdt = track.begin_datetime
                        edt = track.end_datetime || Time.now
                        
                        bdt && ( \
                                # Track D
                                bdt >= from_opt && edt <= to_opt || \
                                
                                # Track A
                                bdt <  from_opt && edt >  to_opt || \
                                
                                # Track B
                                bdt <  from_opt && edt <= to_opt && edt > from_opt || \
                                
                                # Track C
                                bdt >= from_opt && edt >  to_opt && bdt < to_opt
                        )
                }
        else
                raise ThisShouldNeverHappenError, 'Should never happen, bug shit happens.'
        end
        
        if status_opt
                filtered_tracks.select!{ |track_id, track|
                        status_opt.include?(track.status.short_status)
                }
        end
        
        unless billed_opt.nil?
                if billed_opt
                        filtered_tracks.select!{ |track_id, track|
                                track.is_billed
                        }
                else
                        filtered_tracks.select!{ |track_id, track|
                                !track.is_billed
                        }
                end
        end
        
        if sort_opt
                filtered_tracks.sort{ |t1, t2|
                        t1 = t1.last
                        t2 = t2.last
                        
                        cmp1 = t1.begin_datetime <=> t2.begin_datetime
                        if cmp1.nil? || cmp1 == 0
                                t1.end_datetime <=> t2.end_datetime
                        else
                                cmp1
                        end
                }.to_h
        else
                filtered_tracks
        end
end
unbilled_duration(options = Hash.new) click to toggle source

Alias for `duration` method.

Options:

  • `:billed` (Boolean)

# File lib/timr/model/task.rb, line 669
def unbilled_duration(options = Hash.new)
        duration(options.merge({:billed => false}))
end

Private Instance Methods

post_load_from_file() click to toggle source

BasicModel Hook

# File lib/timr/model/task.rb, line 1068
def post_load_from_file
        @tracks = @data.map{ |track_id, track_h|
                track = Track.create_track_from_hash(track_h)
                track.task = self
                [track_id, track]
        }.to_h
        
        current_track_id = @meta['current_track_id']
        if current_track_id
                @current_track = @tracks[current_track_id]
        end
        
        @foreign_id = @meta['foreign_id']
        @name = @meta['name']
        @description = @meta['description']
        
        if @meta['estimation']
                @estimation = Duration.new(@meta['estimation'])
        end
        if @meta['hourly_rate']
                @hourly_rate = @meta['hourly_rate'].to_f
        end
        if @meta['has_flat_rate']
                @has_flat_rate = @meta['has_flat_rate']
        end
end
pre_save_to_file() click to toggle source

BasicModel Hook

# File lib/timr/model/task.rb, line 1032
def pre_save_to_file
        # Meta
        @meta['foreign_id'] = @foreign_id
        @meta['name'] = @name
        @meta['description'] = @description
        
        @meta['current_track_id'] = nil
        if @current_track
                @meta['current_track_id'] = @current_track.id
        end
        
        if @estimation
                @meta['estimation'] = @estimation.to_i
        else
                @meta['estimation'] = nil
        end
        if @hourly_rate
                @meta['hourly_rate'] = @hourly_rate.to_f
        else
                @meta['hourly_rate'] = nil
        end
        if @has_flat_rate
                @meta['has_flat_rate'] = @has_flat_rate
        else
                @meta['has_flat_rate'] = false
        end
        
        # Tracks
        @data = @tracks.map{ |track_id, track|
                [track_id, track.to_h]
        }.to_h
        
        super()
end