require 'tty-prompt' require 'rainbow/refinement' using Rainbow require_relative 'csv_reader' module Twstats class Runner 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 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 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 end def show_info end 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 section "Usefull metrics" show_metrics end def section(text) puts "" puts (" "+text+" ").center(70,"*").bright end 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 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 end end