Class: Twstats::Runner

Inherits:
Object
  • Object
show all
Defined in:
lib/twstats/runner.rb

Instance Method Summary collapse

Constructor Details

#initialize(file = nil) ⇒ Runner

Returns a new instance of Runner.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/twstats/runner.rb', line 9

def initialize(file = nil)
  # Load interactive console
  @prompt = TTY::Prompt.new
  puts WELLCOME_MESSAGE.bright
  # Ask for the csv file
  file ||= @prompt.ask('Specify the CSV file from a Teamwork time log export', default: 'exportTimeLog.csv') do |input|
    input.modify :chomp
  end
  @csv = CSVReader.new(file)
  loop do
    option = @prompt.select("Choose an option", Twstats::MENU_CHOICES, cycle: true)
    case option
      when :stats
        show_stats_menu
      when :info
        show_info
      when :quit
        break
      else
        puts 'Option not recognized!'
    end
  end
end

Instance Method Details



80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/twstats/runner.rb', line 80

def print_table(log_list)
  167.times{print '-'}
  puts "\n|"+'Date'.center(12,' ').bright+'|'+'Time'.center(6,' ').bright+'|'+'Who'.center(20, ' ').bright+
           '|'+'Description'.center(78,' ').bright+'|'+'Tags'.center(24,' ').bright+'|'+'Task'.center(20, ' ').bright+'|'
  167.times{print '-'}
  puts ""
  log_list.each do |log|
    puts table_line(log)
  end
  167.times{print '-'}
  puts ""
end

#ranking_from_not_tagged(list) ⇒ Object



71
72
73
74
75
76
77
78
# File 'lib/twstats/runner.rb', line 71

def ranking_from_not_tagged(list)
  result = {}
  list[:list].each do |log|
    result[log.who] ||= 0
    result[log.who] += log.decimal_time
  end
  result.sort_by{|k,v| v}.reverse.to_h
end

#section(text) ⇒ Object



140
141
142
143
# File 'lib/twstats/runner.rb', line 140

def section(text)
  puts ""
  puts (" "+text+" ").center(70,"*").bright
end

#show_full_statsObject



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/twstats/runner.rb', line 102

def show_full_stats
  billable, non_billable = @csv.get_total_time(:all, nil, true)
  to_bill = @prompt.yes? 'Do you want to calculate the billed amount?'
  if to_bill
    amount_per_hour = @prompt.ask 'What is the hourly rate?', default: 46
  end
  section "Total time spent"
  puts " - Billable      ".bright.blue + " | " + billable.round(2).to_s
  puts " - Non-billable  ".bright.blue + " | " + non_billable.round(2).to_s
  if to_bill
    puts " - Billed amount ".bright.blue + " | " + (billable*amount_per_hour).round(2).to_s + " € "
  end
  section "People involved"
  show_stats :people, true
  section "Tags used"
  show_stats :tags, true
  show_not_tagged_section(true)
  section "Usefull metrics"
  show_metrics
end

#show_metricsObject



145
146
147
148
149
150
# File 'lib/twstats/runner.rb', line 145

def show_metrics
  mean = @csv.logs.inject(0) {|sum, log| sum + log.decimal_time }.to_f/@csv.logs.size
  mean_per_task = @csv.mean_time_per_task
  puts " - Mean time logged:   ".bright.blue + mean.round(2).to_s
  puts " - Mean time per task: ".bright.blue + mean_per_task.round(2).to_s
end

#show_not_tagged_section(table) ⇒ Object



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/twstats/runner.rb', line 123

def show_not_tagged_section(table)
  not_tagged = @csv.not_tagged_tasks
  unless not_tagged[:list].empty?
    section("Tasks not tagged in this report")
    puts "A total of #{not_tagged[:list].size} logs have not been tagged:"
    puts " - A total time of #{not_tagged[:total_time]} is not tagged properly."
    puts " - Impact by employee: "
    ranking_from_not_tagged(not_tagged).each do |user, time|
      puts "\t - #{user.ljust(30,' ').bright.blue} | #{time}"
    end
    table = @prompt.yes?('Do you want to see what tasks have not been tagged?', default: true) if table.nil?
    if table
      print_table not_tagged[:list]
    end
  end
end

#show_stats(obj, filter_billable = nil) ⇒ Object



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/twstats/runner.rb', line 51

def show_stats(obj, filter_billable = nil)
  puts "Time logged vs #{obj.to_s}:" if filter_billable.nil?
  toshow = {}
  max = 0
  filter_billable ||= @prompt.yes?('Do you want to filter billable and non-billable time?', default: true)
  @csv.send(obj).each do |element|
    toshow[element] = @csv.get_total_time(obj, element, filter_billable)
    max = element.size if max < element.size
  end
  toshow.sort_by{ |k,v| v}.reverse.to_h.each do |k,v|
    if filter_billable
      puts " - #{k.ljust(max,' ').bright.blue} | #{"Billable:".ljust(13," ").bright} #{v[0].round(2)} (#{((v[0]/(v[0]+v[1]))*100).round(2)} %)" unless v[0].zero?
      puts "   #{"".ljust(max,' ').bright.blue} | #{"Non-billable:".bright} #{v[1].round(2)}" unless v[1].zero?
    else
      puts " - #{k.ljust(max,' ').bright.blue} | #{v.round(2)}" unless v.zero?
    end
  end
  show_not_tagged_section false
end

#show_stats_menuObject



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/twstats/runner.rb', line 33

def show_stats_menu
  loop do
    option = @prompt.select("Select what time logging stats you want to see", Twstats::STATS_MENU_CHOICES, cycle: true)
    case option
      when :projects, :people, :tags
        show_stats option
      when :fullstats
        show_full_stats
      when :weekly
        show_weekly_report
      when :back
        return
      else
        puts 'Option not recognized'
    end
  end
end

#show_weekly_reportObject



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/twstats/runner.rb', line 152

def show_weekly_report
  unless @csv.is_weekly?
    puts 'The CSV file provided has logged times that differ more than a week.'
    unless @prompt.ask 'Are you sure you want to continue?', default: true
      return
    end
  end
  hours = @prompt.ask 'What is the weekly amount of hours worked?', default: 40, convert: :float
  info = {}
  @csv.people.each do |person|
    billable, non_billable = @csv.get_total_time(:people, person, true)
    info[person] = {rate: billable * 100 / hours,
                    not_billed: hours - billable - non_billable,
                    billable: billable,
                    non_billable: non_billable
    }
  end
  info.sort_by{|x,v| v[:rate] }.reverse.each do |person, data|
    puts " - " + person.bright.blue
    puts "\tBillable time: ".ljust(20, ' ').bright + data[:billable].round(2).to_s
    puts "\tBillable rate: ".ljust(20, ' ').bright + data[:rate].round(2).to_s + ' % '
    puts "\tNot logged time: ".ljust(20, ' ').bright + data[:not_billed].round(2).to_s
  end
end

#table_line(log) ⇒ Object



93
94
95
96
97
98
99
100
# File 'lib/twstats/runner.rb', line 93

def table_line(log)
  "|"+"#{log.date.strftime('%d/%m/%Y')}".truncate(10).center(12,' ')+
      '|'+"#{log.decimal_time.round(2)}".truncate(4).center(6,' ')+
      '|'+"#{log.who}".truncate(18).center(20, ' ')+
      '|'+"#{log.description}".truncate(76).ljust(78,' ')+
      '|'+"#{log.tags.join(', ')}".truncate(22).center(24,' ')+
      '|'+"#{log.task}".truncate(18).center(20, ' ')+'|'
end