Class: TimeCop::Accountability

Inherits:
Object
  • Object
show all
Defined in:
lib/time_cop/accountability.rb

Constant Summary collapse

DAYS_PER_WEEK =
5.0
QUARTERLY_PERIODS =
{
  q1: [{month: 1, day: 1}, {month: 3, day: 31}],
  q2: [{month: 4, day: 1}, {month: 6, day: 30}],
  q3: [{month: 7, day: 1}, {month: 9, day: 30}],
  q4: [{month: 10, day: 1}, {month: 12, day: 31}]
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(harvest_client:, date: Date.today, today: Date.today, report_builder: nil, email: nil, hours_per_week: 34) ⇒ Accountability

Returns a new instance of Accountability.



18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/time_cop/accountability.rb', line 18

def initialize(harvest_client:, date: Date.today, today: Date.today, report_builder: nil, email: nil, hours_per_week: 34)
  @client = harvest_client
  @date = date
  @today = today
  @hours_per_week = hours_per_week
  @report_builder = report_builder ||
    ReportBuilder.new(
      client: client,
      user: (email ? fetch_user(email) : default_user),
      start_date: start_of_quarter_date,
      end_date: end_of_quarter_date
    )
end

Instance Attribute Details

#clientObject (readonly)

Returns the value of attribute client.



7
8
9
# File 'lib/time_cop/accountability.rb', line 7

def client
  @client
end

#dateObject (readonly)

Returns the value of attribute date.



7
8
9
# File 'lib/time_cop/accountability.rb', line 7

def date
  @date
end

#hours_per_weekObject (readonly)

Returns the value of attribute hours_per_week.



7
8
9
# File 'lib/time_cop/accountability.rb', line 7

def hours_per_week
  @hours_per_week
end

#report_builderObject (readonly)

Returns the value of attribute report_builder.



7
8
9
# File 'lib/time_cop/accountability.rb', line 7

def report_builder
  @report_builder
end

#todayObject (readonly)

Returns the value of attribute today.



7
8
9
# File 'lib/time_cop/accountability.rb', line 7

def today
  @today
end

Class Method Details

.paint_number(number) ⇒ Object



163
164
165
# File 'lib/time_cop/accountability.rb', line 163

def self.paint_number(number)
  Paint[number, (number >= 0 ? :green : :red)]
end

Instance Method Details

#accountObject



36
37
38
# File 'lib/time_cop/accountability.rb', line 36

def 
  client.
end

#active_quarter?Boolean

Returns:

  • (Boolean)


64
65
66
67
# File 'lib/time_cop/accountability.rb', line 64

def active_quarter?
  quarter_range = (date_from_period(get_quarter[0])...date_from_period(get_quarter[1]))
  quarter_range.include?(Date.today)
end

#average_quarter_hours_per_dayObject



127
128
129
130
131
132
133
# File 'lib/time_cop/accountability.rb', line 127

def average_quarter_hours_per_day
  if weekdays_so_far(false) > 0
    total_quarter_time_tracked(false) / weekdays_so_far(false)
  else
    0
  end
end

#current_hours_delta(include_future = true) ⇒ Object



147
148
149
# File 'lib/time_cop/accountability.rb', line 147

def current_hours_delta(include_future = true)
  total_quarter_time_tracked(include_future) - expected_quarter_hours_to_today
end

#date_from_period(period) ⇒ Object



48
49
50
# File 'lib/time_cop/accountability.rb', line 48

def date_from_period(period)
  Date.new(date.year, period[:month], period[:day])
end

#default_userObject



44
45
46
# File 'lib/time_cop/accountability.rb', line 44

def default_user
  .who_am_i
end

#end_of_quarter_dateObject



77
78
79
# File 'lib/time_cop/accountability.rb', line 77

def end_of_quarter_date
  date_from_period(get_quarter[1])
end

#expected_quarter_hoursObject



119
120
121
# File 'lib/time_cop/accountability.rb', line 119

def expected_quarter_hours
  total_week_days.to_f * hours_per_day
end

#expected_quarter_hours_to_todayObject



123
124
125
# File 'lib/time_cop/accountability.rb', line 123

def expected_quarter_hours_to_today
  weekdays_between(start_of_quarter_date, today < end_of_quarter_date ? Date.today : end_of_quarter_date) * hours_per_day
end

#fetch_user(email) ⇒ Object



40
41
42
# File 'lib/time_cop/accountability.rb', line 40

def fetch_user(email)
  client.users.find(email)
end

#future_days_with_workObject



143
144
145
# File 'lib/time_cop/accountability.rb', line 143

def future_days_with_work
  quarterly_tracked_time_by_user.select{ |t| t.spent_at > Date.today}.map(&:spent_at).uniq.length
end

#get_quarterObject



69
70
71
# File 'lib/time_cop/accountability.rb', line 69

def get_quarter
  select_quarter.first[1]
end

#hours_per_dayObject



32
33
34
# File 'lib/time_cop/accountability.rb', line 32

def hours_per_day
  @hours_per_week / DAYS_PER_WEEK
end


189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/time_cop/accountability.rb', line 189

def print_report
  puts "Quarter Period: #{start_of_quarter_date} - #{end_of_quarter_date}"
  puts "Hours Per Week: #{@hours_per_week}"
  puts "Weekdays So Far: #{weekdays_so_far(false)}"
  puts ""
  puts "Quarterly Hour Target: #{expected_quarter_hours.round(2)}"
  puts "Quarterly Hours Charged: #{total_quarter_time_tracked.round(2)}"
  if active_quarter?
    puts ""
    puts "Additional Hours Needed By End Of Quarter: #{quarterly_hours_delta.round(2)}"
    puts "Business Days Left In The Quarter (Excluding Today): #{weekdays_left(false)}"
    puts ""
    puts "Average Hours Per Business Day Worked: #{average_quarter_hours_per_day.round(2)}"
    puts "Hours Per Business Day Average Needed: #{quarterly_hours_per_business_day_needed.round(2)}"
  end
  puts ""
  puts "Current Surplus(+)/Deficit(-): #{Accountability.paint_number(current_hours_delta(false).round(2))}"
  puts "Projected Quarter Surplus(+)/Deficit(-): #{Accountability.paint_number(projected_quarter_hours.round(2))}" if active_quarter?
end

#projected_future_hoursObject



139
140
141
# File 'lib/time_cop/accountability.rb', line 139

def projected_future_hours
  (weekdays_left(false) - future_days_with_work)* average_quarter_hours_per_day
end

#projected_quarter_hoursObject



135
136
137
# File 'lib/time_cop/accountability.rb', line 135

def projected_quarter_hours
  (total_quarter_time_tracked + projected_future_hours) - expected_quarter_hours
end

#quarterly_hours_deltaObject



151
152
153
# File 'lib/time_cop/accountability.rb', line 151

def quarterly_hours_delta
  expected_quarter_hours - total_quarter_time_tracked
end

#quarterly_hours_per_business_day_neededObject



155
156
157
158
159
160
161
# File 'lib/time_cop/accountability.rb', line 155

def quarterly_hours_per_business_day_needed
  if weekdays_between(today, end_of_quarter_date) == 0
    quarterly_hours_delta
  else
    quarterly_hours_delta / weekdays_left(false).to_f
  end
end

#quarterly_tracked_time_by_userObject



81
82
83
# File 'lib/time_cop/accountability.rb', line 81

def quarterly_tracked_time_by_user
  @quarterly_tracked_time_by_user ||= report_builder.generate
end

#select_quarterObject



52
53
54
55
56
57
58
59
60
61
62
# File 'lib/time_cop/accountability.rb', line 52

def select_quarter
  QUARTERLY_PERIODS.select do |quarter, range|
    start_of_range = range[0]
    end_of_range = range[1]

    start_date_of_range = date_from_period(start_of_range)
    end_date_of_range = date_from_period(end_of_range)

    (date >= start_date_of_range) && (date <= end_date_of_range)
  end
end

#start_of_quarter_dateObject



73
74
75
# File 'lib/time_cop/accountability.rb', line 73

def start_of_quarter_date
  date_from_period(get_quarter[0])
end

#summary_hashObject



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/time_cop/accountability.rb', line 167

def summary_hash
  {
    quarter: {
      start: start_of_quarter_date,
      end: end_of_quarter_date,
      weekdays_in_quarter: weekdays_between(@report_builder.start_date, @report_builder.end_date),
      weekdays_so_far: weekdays_so_far,
      weekdays_left: weekdays_left
    },
    hours_per_week: @hours_per_week,
    hours: {
      charged: total_quarter_time_tracked,
      needed: expected_quarter_hours,
      left: quarterly_hours_delta,
      average_charged: average_quarter_hours_per_day,
      average_needed: quarterly_hours_per_business_day_needed,
      current_hours: current_hours_delta,
      total_projected: projected_quarter_hours
    }
  }
end

#total_quarter_daysObject



91
92
93
# File 'lib/time_cop/accountability.rb', line 91

def total_quarter_days
  (end_of_quarter_date - start_of_quarter_date).to_i
end

#total_quarter_time_tracked(include_future = true) ⇒ Object



85
86
87
88
89
# File 'lib/time_cop/accountability.rb', line 85

def total_quarter_time_tracked(include_future = true)
  quarterly_tracked_time_by_user.select do |t|
    include_future || t.spent_at <= Date.today
  end.map(&:hours).reduce(0, :+)
end

#total_week_daysObject



115
116
117
# File 'lib/time_cop/accountability.rb', line 115

def total_week_days
  weekdays_between(start_of_quarter_date, end_of_quarter_date)
end

#weekdays_between(start_date, end_date) ⇒ Object



111
112
113
# File 'lib/time_cop/accountability.rb', line 111

def weekdays_between(start_date, end_date)
  (start_date..end_date).select{|d| (1..5).include?(d.wday)}.size
end

#weekdays_left(include_today = false) ⇒ Object



95
96
97
98
99
100
101
# File 'lib/time_cop/accountability.rb', line 95

def weekdays_left(include_today = false)
  if include_today
    weekdays_between(Date.today, end_of_quarter_date)
  else
    weekdays_between(Date.today + 1, end_of_quarter_date)
  end
end

#weekdays_so_far(include_today = true) ⇒ Object



103
104
105
106
107
108
109
# File 'lib/time_cop/accountability.rb', line 103

def weekdays_so_far(include_today = true)
  if include_today
    weekdays_between(start_of_quarter_date, Date.today)
  else
    weekdays_between(start_of_quarter_date, Date.today - 1)
  end
end