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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 461fe4226d6a5980fa168c7c918b01b35fb27aebef3110ff25d6d295709c6551
4
- data.tar.gz: 830f66bef87e5925b117e32a2e82647736997381a07efe12a8e8151123e7d9cd
3
+ metadata.gz: 35406dddfbbe1e74c061171bea36962f3d5632a6cedc75e846a66e53fc2fbd9e
4
+ data.tar.gz: deab85ae87457cab458141d8a4987ca592a07d0860405d2ecea1190a316e2b9e
5
5
  SHA512:
6
- metadata.gz: 6b99531029582021e5eff7c47a1483e24ad6ceb86b0865c2abd7b6af0496225b9e0f222c958538f073553e6ce5b4e4fe36d8e9ec10d3d2ab9b7ed8e1b83523f7
7
- data.tar.gz: 358e04d3c9f16416d451d192ed5ad2a94545ef135250ecb3836ce75d5f551b3295e65b1d44b3a36f9b71ab95386acd466e866e2c27457e61c8ed4b853d311ad5
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
@@ -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 default_location
89
- result = []
90
- config_file = "#{ENV['HOME']}/.time-sheet.conf"
91
- if File.exist?(config_file)
92
- File.read(config_file).split("\n").each do |line|
93
- if m = line.match(/^([a-z_]+):(.*)$/)
94
- result << m[2].strip if m[1] == 'location'
95
- end
96
- end
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
- result << "#{ENV['HOME']}/time-sheet" if result.empty?
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: default_location
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
- @data['activity'] ||= self.prev.activity
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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module TimeSheet
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.0"
3
3
  end
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.0.0
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-02-07 00:00:00.000000000 Z
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.16
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