time_cop 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/time_cop/accountability.rb +24 -45
- data/lib/time_cop/runner.rb +63 -18
- data/lib/time_cop/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5386380ae098f3a9daa1a1e7861a44fb346db8e8
|
4
|
+
data.tar.gz: 6aa3386caa796aca933336607980e764aced49f3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9a4c4d9e71d174573580c90dc35f2f90f48de1059369d084d93411972a44b60c669af0cf9e59b807ccbc2128f3b015e48e01587d8e09a0f75570b4741010f6cd
|
7
|
+
data.tar.gz: 05f65255b494f94b81891a522a94e0635b17712cfbc60a3df8e49c8ed4ad18fdd4fa5e067c3df9715d31d3ed7c91c51eeeb5cbc663a1d1133299348387517f49
|
@@ -3,7 +3,7 @@ require 'date'
|
|
3
3
|
|
4
4
|
module TimeCop
|
5
5
|
class Accountability
|
6
|
-
attr_reader :report_builder, :client, :date, :hours_per_week
|
6
|
+
attr_reader :report_builder, :client, :date, :today, :hours_per_week
|
7
7
|
|
8
8
|
DAYS_PER_WEEK = 5.0
|
9
9
|
|
@@ -14,9 +14,10 @@ module TimeCop
|
|
14
14
|
q4: [{month: 10, day: 1}, {month: 12, day: 31}]
|
15
15
|
}
|
16
16
|
|
17
|
-
def initialize(username:, password:, subdomain: 'wildland', date: Date.today, report_builder: nil, email: nil, hours_per_week: 32)
|
17
|
+
def initialize(username:, password:, subdomain: 'wildland', date: Date.today, today: Date.today, report_builder: nil, email: nil, hours_per_week: 32)
|
18
18
|
@client = Harvest.client(username: username, password: password, subdomain: subdomain)
|
19
19
|
@date = date
|
20
|
+
@today = today
|
20
21
|
@hours_per_week = hours_per_week
|
21
22
|
@report_builder = report_builder ||
|
22
23
|
ReportBuilder.new(
|
@@ -83,49 +84,12 @@ module TimeCop
|
|
83
84
|
(end_of_quarter_date - start_of_quarter_date).to_i
|
84
85
|
end
|
85
86
|
|
86
|
-
def
|
87
|
-
|
88
|
-
return 0 unless days_between > 0
|
89
|
-
|
90
|
-
# Assuming we need to calculate days from 9th to 25th, 10-23 are covered
|
91
|
-
# by whole weeks, and 24-25 are extra days.
|
92
|
-
#
|
93
|
-
# Su Mo Tu We Th Fr Sa # Su Mo Tu We Th Fr Sa
|
94
|
-
# 1 2 3 4 5 # 1 2 3 4 5
|
95
|
-
# 6 7 8 9 10 11 12 # 6 7 8 9 ww ww ww
|
96
|
-
# 13 14 15 16 17 18 19 # ww ww ww ww ww ww ww
|
97
|
-
# 20 21 22 23 24 25 26 # ww ww ww ww ed ed 26
|
98
|
-
# 27 28 29 30 31 # 27 28 29 30 31
|
99
|
-
whole_weeks, extra_days = days_between.divmod(7)
|
100
|
-
|
101
|
-
unless extra_days.zero?
|
102
|
-
# Extra days start from the week day next to start_day,
|
103
|
-
# and end on end_date's week date. The position of the
|
104
|
-
# start date in a week can be either before (the left calendar)
|
105
|
-
# or after (the right one) the end date.
|
106
|
-
#
|
107
|
-
# Su Mo Tu We Th Fr Sa # Su Mo Tu We Th Fr Sa
|
108
|
-
# 1 2 3 4 5 # 1 2 3 4 5
|
109
|
-
# 6 7 8 9 10 11 12 # 6 7 8 9 10 11 12
|
110
|
-
# ## ## ## ## 17 18 19 # 13 14 15 16 ## ## ##
|
111
|
-
# 20 21 22 23 24 25 26 # ## 21 22 23 24 25 26
|
112
|
-
# 27 28 29 30 31 # 27 28 29 30 31
|
113
|
-
#
|
114
|
-
# If some of the extra_days fall on a weekend, they need to be subtracted.
|
115
|
-
# In the first case only corner days can be days off,
|
116
|
-
# and in the second case there are indeed two such days.
|
117
|
-
extra_days -= if start_date.next_day.wday <= end_date.wday
|
118
|
-
[start_date.next_day.sunday?, end_date.saturday?].count(true)
|
119
|
-
else
|
120
|
-
2
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
(whole_weeks * 5) + extra_days
|
87
|
+
def weekdays_between(start_date, end_date)
|
88
|
+
(start_date..end_date).select{|d| (1..5).include?(d.wday)}.size
|
125
89
|
end
|
126
90
|
|
127
91
|
def total_week_days
|
128
|
-
|
92
|
+
weekdays_between(start_of_quarter_date, end_of_quarter_date)
|
129
93
|
end
|
130
94
|
|
131
95
|
def expected_quarter_hours
|
@@ -133,7 +97,7 @@ module TimeCop
|
|
133
97
|
end
|
134
98
|
|
135
99
|
def expected_quarter_hours_to_today
|
136
|
-
|
100
|
+
weekdays_between(start_of_quarter_date, today < end_of_quarter_date ? Date.today : end_of_quarter_date) * hours_per_day
|
137
101
|
end
|
138
102
|
|
139
103
|
def current_hours_delta
|
@@ -145,13 +109,28 @@ module TimeCop
|
|
145
109
|
end
|
146
110
|
|
147
111
|
def quarterly_hours_per_business_day_needed
|
148
|
-
if
|
112
|
+
if weekdays_between(today, end_of_quarter_date) == 0
|
149
113
|
quarterly_hours_delta
|
150
114
|
else
|
151
|
-
quarterly_hours_delta /
|
115
|
+
quarterly_hours_delta / weekdays_between(today, end_of_quarter_date).to_f
|
152
116
|
end
|
153
117
|
end
|
154
118
|
|
119
|
+
def summary_hash
|
120
|
+
{
|
121
|
+
quarter: {
|
122
|
+
start: start_of_quarter_date,
|
123
|
+
end: end_of_quarter_date,
|
124
|
+
weekdays_in_quarter: weekdays_between(@report_builder.start_date, @report_builder.end_date)
|
125
|
+
},
|
126
|
+
hours_per_week: @hours_per_week,
|
127
|
+
hours: {
|
128
|
+
charged: total_quarter_time_tracked,
|
129
|
+
needed: expected_quarter_hours,
|
130
|
+
}
|
131
|
+
}
|
132
|
+
end
|
133
|
+
|
155
134
|
def print_report
|
156
135
|
puts "Quarter Period: #{start_of_quarter_date} #{end_of_quarter_date}"
|
157
136
|
puts "Hours Per Week: #{@hours_per_week}"
|
data/lib/time_cop/runner.rb
CHANGED
@@ -13,28 +13,73 @@ module TimeCop
|
|
13
13
|
cli = HighLine.new
|
14
14
|
username = cli.ask('Harvest Username: ')
|
15
15
|
password = cli.ask('Harvest Password: ') { |q| q.echo = false }
|
16
|
-
interactive_hash[:hours_per_week] = cli.ask('Hours per week? ') { |q| q.default =
|
16
|
+
interactive_hash[:hours_per_week] = cli.ask('Hours per week? (Full Time 34)') { |q| q.default = 34 }.to_f
|
17
|
+
accountability_options = {
|
18
|
+
username: (username.nil? ? options[:username] : username),
|
19
|
+
password: (password.nil? ? options[:password] : password),
|
20
|
+
email: options[:email]
|
21
|
+
}
|
22
|
+
q_dates = [
|
23
|
+
Date.new(Date.today.year, 1, 1),
|
24
|
+
Date.new(Date.today.year, 4, 1),
|
25
|
+
Date.new(Date.today.year, 7, 1),
|
26
|
+
Date.new(Date.today.year, 10, 1)
|
27
|
+
]
|
28
|
+
|
17
29
|
cli.choose do |menu|
|
18
30
|
menu.prompt = 'Which Quarter? '
|
19
|
-
menu.choice(:Q1)
|
20
|
-
|
21
|
-
|
22
|
-
|
31
|
+
menu.choice(:Q1) do
|
32
|
+
interactive_hash[:date] = q_dates[0]
|
33
|
+
Accountability.new(interactive_hash.merge(accountability_options)).print_report
|
34
|
+
end
|
35
|
+
menu.choice(:Q2) do
|
36
|
+
interactive_hash[:date] = q_dates[1]
|
37
|
+
Accountability.new(interactive_hash.merge(accountability_options)).print_report
|
38
|
+
end
|
39
|
+
menu.choice(:Q3) do
|
40
|
+
interactive_hash[:date] = q_dates[2]
|
41
|
+
Accountability.new(interactive_hash.merge(accountability_options)).print_report
|
42
|
+
end
|
43
|
+
menu.choice(:Q4) do
|
44
|
+
interactive_hash[:date] = q_dates[3]
|
45
|
+
Accountability.new(interactive_hash.merge(accountability_options)).print_report
|
46
|
+
end
|
47
|
+
menu.choice(:Year) do
|
48
|
+
summary = q_dates.map do |d|
|
49
|
+
interactive_hash[:date] = d
|
50
|
+
Accountability.new(interactive_hash.merge(accountability_options)).summary_hash
|
51
|
+
end
|
52
|
+
logged = summary.inject(0){|sum, s| sum + s[:hours][:charged]}
|
53
|
+
needed = summary.inject(0){|sum, s| sum + s[:hours][:needed]}.round(2 )
|
54
|
+
diff = (logged - needed).round(2)
|
55
|
+
weekdays = (Date.today..Date.new(Date.today.year, 12, 31)).select{|d| (1..5).include?(d.wday)}.size
|
56
|
+
weekdays_so_far = (Date.new(Date.today.year, 1, 1)..Date.today).select{|d| (1..5).include?(d.wday)}.size
|
57
|
+
average_needed = (-1 * diff / weekdays).round(2)
|
58
|
+
average_clocked = (logged / weekdays_so_far).round(2)
|
59
|
+
projected_diff = ((logged + (weekdays * average_clocked)) - needed).round(2)
|
60
|
+
|
61
|
+
puts "Business Days Left In Year: #{weekdays}"
|
62
|
+
puts "Current Year End Surplus(+)/Deficit(-): #{diff}"
|
63
|
+
puts "Projected Year End Surplus(+)/Deficit(-): #{projected_diff}"
|
64
|
+
puts ""
|
65
|
+
puts "Total Harvest Hours This Year: #{logged}"
|
66
|
+
puts "Average Harvest Hours Per Business Day: #{average_clocked}"
|
67
|
+
puts ""
|
68
|
+
puts "Total Hours Needed By End Of Year: #{needed}"
|
69
|
+
puts "Average Hours Per Business Day Needed To Reach Goal: #{average_needed}"
|
70
|
+
end
|
23
71
|
end
|
72
|
+
else
|
73
|
+
accountability_options = {
|
74
|
+
username: (options[:username]),
|
75
|
+
password: (options[:password]),
|
76
|
+
email: options[:email]
|
77
|
+
}
|
78
|
+
accountability = Accountability.new(
|
79
|
+
accountability_options
|
80
|
+
)
|
81
|
+
accountability.print_report
|
24
82
|
end
|
25
|
-
|
26
|
-
accountability_options = {
|
27
|
-
username: (username.nil? ? options[:username] : username),
|
28
|
-
password: (password.nil? ? options[:password] : password),
|
29
|
-
email: options[:email]
|
30
|
-
}
|
31
|
-
|
32
|
-
accountability_options = interactive_hash.merge(accountability_options)
|
33
|
-
|
34
|
-
accountability = Accountability.new(
|
35
|
-
accountability_options
|
36
|
-
)
|
37
|
-
accountability.print_report
|
38
83
|
rescue Harvest::AuthenticationFailed
|
39
84
|
puts 'Unable to authenticate to Harvest. Check username/password.'
|
40
85
|
rescue Harvest::HTTPError => e
|
data/lib/time_cop/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: time_cop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam Clopton
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-10-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: harvested
|