time-sheet 1.0.0 → 1.1.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/README.md +5 -0
- data/lib/time_sheet/time/cmd.rb +28 -15
- data/lib/time_sheet/time/entry.rb +15 -2
- data/lib/time_sheet/time.rb +7 -3
- data/lib/time_sheet/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 35406dddfbbe1e74c061171bea36962f3d5632a6cedc75e846a66e53fc2fbd9e
|
4
|
+
data.tar.gz: deab85ae87457cab458141d8a4987ca592a07d0860405d2ecea1190a316e2b9e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e262b17d41fbc239710af28d16d6fa00334d5cb691489e0b017f8864db76ce7b4b5ac7ba7fec53d39b821cda78522bd7fc234680ece63c184adf7b9275dcddee
|
7
|
+
data.tar.gz: 03eb5990ebcae8f95d4931a1dcaa7b5469e54f6eac61fcfe20a752c8e0c75146028b066153fed8bb8d46afeff5fa417235418db7ea82120694f224626c9ccbcc
|
data/README.md
CHANGED
@@ -5,6 +5,11 @@ generate various statistics suitable for invoices and project effort estimates.
|
|
5
5
|
|
6
6
|
## Changelog
|
7
7
|
|
8
|
+
v1.0.0
|
9
|
+
|
10
|
+
* input files need to be .xlsx files now because we needed to replace the
|
11
|
+
spreadsheet parser, see [#1](https://github.com/moritzschepp/time-sheet/issues/1)
|
12
|
+
|
8
13
|
v0.9.0
|
9
14
|
|
10
15
|
* introduced employee data column: To use it, add a column "employee" to the
|
data/lib/time_sheet/time/cmd.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
1
3
|
require 'slop'
|
2
4
|
require 'time'
|
3
5
|
|
4
6
|
class TimeSheet::Time::Cmd
|
5
7
|
def run
|
6
|
-
TimeSheet.options = options
|
7
|
-
|
8
8
|
if d = options[:from]
|
9
9
|
if d.match(/^\d\d?-\d\d?$/)
|
10
10
|
d = "#{TimeSheet::Time::Util.now.year}-#{d}"
|
@@ -85,17 +85,22 @@ class TimeSheet::Time::Cmd
|
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
88
|
-
def
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
88
|
+
def config
|
89
|
+
defaults = {
|
90
|
+
'location' => "#{ENV['HOME']}/time",
|
91
|
+
'carry_over_activity' => 'previous'
|
92
|
+
}
|
93
|
+
|
94
|
+
file = "#{ENV['HOME']}/.time-sheet.conf"
|
95
|
+
return defaults unless File.exist?(file)
|
96
|
+
|
97
|
+
result = YAML.load_file(file)
|
98
|
+
result = defaults.merge(result)
|
99
|
+
|
100
|
+
unless result['location'].is_a?(Array)
|
101
|
+
result['location'] = [result['location']]
|
97
102
|
end
|
98
|
-
|
103
|
+
|
99
104
|
result
|
100
105
|
end
|
101
106
|
|
@@ -114,7 +119,7 @@ class TimeSheet::Time::Cmd
|
|
114
119
|
o.boolean '-h', '--help', 'show help'
|
115
120
|
o.boolean '--version', 'show the version'
|
116
121
|
o.array('-l', '--location', 'a location to gather data from (file, directory or google docs share-url)',
|
117
|
-
default:
|
122
|
+
default: config['location']
|
118
123
|
)
|
119
124
|
o.string '-f', '--from', 'ignore entries older than the date given'
|
120
125
|
o.string '-t', '--to', 'ignore entries more recent than the date given'
|
@@ -123,6 +128,12 @@ class TimeSheet::Time::Cmd
|
|
123
128
|
o.string '--tags', 'filter by tag (comma separated, not case sensitive, prefix tag with ! to exclude)'
|
124
129
|
o.string '-d', '--description', 'consider only entries matching this description'
|
125
130
|
o.string '-e', '--employee', 'consider only entries for this employee'
|
131
|
+
o.string(
|
132
|
+
'--carry-over-activity',
|
133
|
+
'mode for carrying over activity (previous|same-description)',
|
134
|
+
default: config['carry_over_activity']
|
135
|
+
)
|
136
|
+
o.string '--default-activity', 'default activity', default: config['default_activity']
|
126
137
|
o.float '-r', '--rate', 'use an alternative hourly rate (default: 80.0)', default: 80.00
|
127
138
|
o.boolean '-s', '--summary', 'when reporting, add summary section'
|
128
139
|
o.boolean '--trim', 'compact the output for processing as CSV', default: false
|
@@ -148,6 +159,8 @@ class TimeSheet::Time::Cmd
|
|
148
159
|
end
|
149
160
|
|
150
161
|
def verify
|
162
|
+
TimeSheet.options = options
|
163
|
+
|
151
164
|
convert_to_time
|
152
165
|
|
153
166
|
entries = TimeSheet::Time::Parser.new(options[:location]).entries
|
@@ -222,7 +235,7 @@ class TimeSheet::Time::Cmd
|
|
222
235
|
TimeSheet::Time::Util.hours(pdata['total']),
|
223
236
|
TimeSheet::Time::Util.price(pdata['total'], options[:rate])
|
224
237
|
]
|
225
|
-
|
238
|
+
|
226
239
|
pdata['activities'].sort_by{|k, v| v}.reverse.to_h.each do |aname, atotal|
|
227
240
|
tdata << [
|
228
241
|
'',
|
@@ -250,4 +263,4 @@ class TimeSheet::Time::Cmd
|
|
250
263
|
end
|
251
264
|
end
|
252
265
|
|
253
|
-
end
|
266
|
+
end
|
@@ -14,7 +14,20 @@ class TimeSheet::Time::Entry
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def activity
|
17
|
-
|
17
|
+
if !@data['activity']
|
18
|
+
carry_mode = TimeSheet.options[:carry_over_activity]
|
19
|
+
use_prev = (
|
20
|
+
carry_mode == 'previous' ||
|
21
|
+
(carry_mode == 'same-description' && self.prev.description == description)
|
22
|
+
)
|
23
|
+
if use_prev
|
24
|
+
@data['activity'] = self.prev.activity
|
25
|
+
end
|
26
|
+
|
27
|
+
@data['activity'] ||= TimeSheet.options[:default_activity] || ''
|
28
|
+
end
|
29
|
+
|
30
|
+
@data['activity']
|
18
31
|
end
|
19
32
|
|
20
33
|
def description
|
@@ -215,4 +228,4 @@ class TimeSheet::Time::Entry
|
|
215
228
|
(string || '').to_s.downcase.split(/\s*,\s*/).map{|t| t.strip}
|
216
229
|
end
|
217
230
|
|
218
|
-
end
|
231
|
+
end
|
data/lib/time_sheet/time.rb
CHANGED
@@ -8,6 +8,8 @@ module TimeSheet::Time
|
|
8
8
|
autoload :Util, 'time_sheet/time/util'
|
9
9
|
|
10
10
|
def self.report(options)
|
11
|
+
TimeSheet.options = options
|
12
|
+
|
11
13
|
results = {
|
12
14
|
'entries' => [],
|
13
15
|
'total' => 0.0,
|
@@ -40,7 +42,7 @@ module TimeSheet::Time
|
|
40
42
|
|
41
43
|
unless results['entries'].empty?
|
42
44
|
time = (
|
43
|
-
(options[:to] || Util.day_end) -
|
45
|
+
(options[:to] || Util.day_end) -
|
44
46
|
(options[:from] || results['entries'].first[1].to_time)
|
45
47
|
).to_i
|
46
48
|
days = (time.to_f / 60 / 60 / 24).round
|
@@ -65,6 +67,8 @@ module TimeSheet::Time
|
|
65
67
|
end
|
66
68
|
|
67
69
|
def self.invoice(options)
|
70
|
+
TimeSheet.options = options
|
71
|
+
|
68
72
|
grouped = {}
|
69
73
|
Parser.new(options[:location]).entries.each do |e|
|
70
74
|
if e.matches?(options)
|
@@ -102,7 +106,7 @@ module TimeSheet::Time
|
|
102
106
|
next
|
103
107
|
end
|
104
108
|
end
|
105
|
-
|
109
|
+
|
106
110
|
packages.last << row
|
107
111
|
ptotal += row[1]
|
108
112
|
end
|
@@ -131,4 +135,4 @@ module TimeSheet::Time
|
|
131
135
|
packages
|
132
136
|
end
|
133
137
|
|
134
|
-
end
|
138
|
+
end
|
data/lib/time_sheet/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: time-sheet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Moritz Schepp
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-
|
11
|
+
date: 2025-09-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: roo
|
@@ -141,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
141
141
|
- !ruby/object:Gem::Version
|
142
142
|
version: '0'
|
143
143
|
requirements: []
|
144
|
-
rubygems_version: 3.5.
|
144
|
+
rubygems_version: 3.5.22
|
145
145
|
signing_key:
|
146
146
|
specification_version: 4
|
147
147
|
summary: a time tracking solution based on spreadsheets
|