toggl_billable 0.1.1
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 +7 -0
- data/lib/core_ext/fixnum.rb +9 -0
- data/lib/toggl_billable/client.rb +32 -0
- data/lib/toggl_billable/config.rb +16 -0
- data/lib/toggl_billable/formatter/base.rb +16 -0
- data/lib/toggl_billable/formatter/details.rb +63 -0
- data/lib/toggl_billable/formatter/summary.rb +37 -0
- data/lib/toggl_billable/reports/base.rb +41 -0
- data/lib/toggl_billable/reports/details.rb +35 -0
- data/lib/toggl_billable/reports/summary.rb +15 -0
- data/lib/toggl_billable/user.rb +15 -0
- data/lib/toggl_billable.rb +16 -0
- metadata +154 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 56d473d435fed4f3fd59cddbdd11489a927291ab
|
4
|
+
data.tar.gz: 91050fe583c99dcbf27ec7ac60a969d0bc572d07
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 626c0f172d331391784ceef8487bd34e399f01a5c884c5aa15fe8945ed5418633feb8656ac0d37374d7263b2ace0bd7fdb74b8b349d946b6930c36660e7826d9
|
7
|
+
data.tar.gz: 7f0bd923e82af581d440b37388b5e13431fa07cabc4a0ec415166a984801ce1ee254ad624e0fad2cb8f96bbf65a0e8095a81f230843972dd424d7f1880f3c7bb
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module TogglBillable
|
2
|
+
class Client
|
3
|
+
def self.start(api_token)
|
4
|
+
@connection = Faraday.new(url: 'https://www.toggle.com') do |faraday|
|
5
|
+
faraday.use Faraday::Request::BasicAuthentication, api_token, 'api_token'
|
6
|
+
faraday.request :url_encoded
|
7
|
+
faraday.adapter Faraday.default_adapter
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.api_base
|
12
|
+
'https://www.toggl.com/api/v8'
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.reports_base
|
16
|
+
'https://toggl.com/reports/api/v2'
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.connection
|
20
|
+
@connection
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.api_get(end_point)
|
24
|
+
connection.get("#{api_base}/#{end_point}")
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.report_get(end_point)
|
28
|
+
connection.get("#{reports_base}/#{end_point}")
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module TogglBillable
|
2
|
+
class Config
|
3
|
+
@format_daterange_start = '%b %-d'
|
4
|
+
@format_daterange_end = '%-d'
|
5
|
+
@format_day = '%b %-d'
|
6
|
+
@format_month = '%b'
|
7
|
+
|
8
|
+
class << self
|
9
|
+
attr_accessor :format_daterange_start
|
10
|
+
attr_accessor :format_daterange_end
|
11
|
+
attr_accessor :format_day
|
12
|
+
attr_accessor :format_month
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module TogglBillable
|
2
|
+
module Formatter
|
3
|
+
class Base
|
4
|
+
attr_accessor :data, :billable
|
5
|
+
|
6
|
+
NO_CLIENT_KEY = 'NO_CLIENT'
|
7
|
+
|
8
|
+
def initialize(report, options = {})
|
9
|
+
@data = report['data']
|
10
|
+
@billable = {}
|
11
|
+
@no_client_key = options[:default_client] || NO_CLIENT_KEY
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module TogglBillable
|
2
|
+
module Formatter
|
3
|
+
class Details < Base
|
4
|
+
SKIP_GROUP_DATES = []
|
5
|
+
SHORT_DATES = [nil]
|
6
|
+
|
7
|
+
# TODO: make this working also for different grouping than default
|
8
|
+
def billable_items(with_dates = true)
|
9
|
+
group = data.group_by { |d| d['client'] }
|
10
|
+
|
11
|
+
group.each do |group_name, group_items|
|
12
|
+
key = group_name || @no_client_key
|
13
|
+
billable[key] = [] unless billable[key]
|
14
|
+
subgroup = group_items.group_by { |d| d['project'] }
|
15
|
+
|
16
|
+
subgroup.each do |subgroup_name, subgroup_items|
|
17
|
+
subgroup_items.group_by { |d| d['description'] }.each do |item, data|
|
18
|
+
if with_dates && !SKIP_GROUP_DATES.include?(subgroup_name)
|
19
|
+
task = "#{dates(data, SHORT_DATES.include?(subgroup_name))}: "
|
20
|
+
else
|
21
|
+
task = ''
|
22
|
+
end
|
23
|
+
|
24
|
+
if item && subgroup_name
|
25
|
+
task += "#{subgroup_name}: #{item}"
|
26
|
+
elsif item
|
27
|
+
task += "#{item}"
|
28
|
+
elsif subgroup_name
|
29
|
+
task += "#{subgroup_name}"
|
30
|
+
end
|
31
|
+
|
32
|
+
billable[key] << {
|
33
|
+
task: task,
|
34
|
+
amount: data.map {|i| i['dur']}.reduce(0, :+).to_hours,
|
35
|
+
unit: :hours
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
billable
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def dates(items, short)
|
47
|
+
start_date = Date.parse(items.sort_by { |i| i['start'] }.first['start'])
|
48
|
+
end_date = Date.parse(items.sort_by { |i| i['end'] }.reverse.first['end'])
|
49
|
+
|
50
|
+
return start_date.strftime(TogglBillable::Config.format_month).to_s if short
|
51
|
+
|
52
|
+
if start_date.strftime('%-d') == end_date.strftime('%-d')
|
53
|
+
start_date.strftime(TogglBillable::Config.format_day)
|
54
|
+
else
|
55
|
+
start_date = start_date.strftime(TogglBillable::Config.format_daterange_start)
|
56
|
+
end_date = end_date.strftime(TogglBillable::Config.format_daterange_end)
|
57
|
+
|
58
|
+
"#{start_date}-#{end_date}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module TogglBillable
|
2
|
+
module Formatter
|
3
|
+
class Summary < Base
|
4
|
+
|
5
|
+
# TODO: make this working also for different grouping than default
|
6
|
+
# TODO: rounding parameter
|
7
|
+
# TODO: implement custom formatting
|
8
|
+
# TODO: projects without names
|
9
|
+
def billable_items
|
10
|
+
data.group_by { |d| d['title']['client'] }.each do |group_name, group_data|
|
11
|
+
key = group_name || @no_client_key
|
12
|
+
billable[key] = [] unless billable[key]
|
13
|
+
group_data.group_by { |d| d['title']['project'] }.each do |subgroup_name, subgroup_data|
|
14
|
+
process_project(subgroup_data.first)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
billable
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def process_project(project_data)
|
24
|
+
project = project_data['title']['project']
|
25
|
+
client = project_data['title']['client'] || @no_client_key
|
26
|
+
|
27
|
+
project_data['items'].each do |item|
|
28
|
+
billable[client] << {
|
29
|
+
task: "#{project}: #{item['title']['time_entry']}",
|
30
|
+
amount: item['time'].to_hours,
|
31
|
+
unit: :hours
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module TogglBillable
|
2
|
+
module Reports
|
3
|
+
class Base
|
4
|
+
attr_accessor :params, :report, :options
|
5
|
+
|
6
|
+
def initialize(options = {})
|
7
|
+
@params = {
|
8
|
+
workspace_id: options[:workspace_id] || User.new.default_workspace_id,
|
9
|
+
user_agent: options[:user_agent] || 'toggl_client'
|
10
|
+
}
|
11
|
+
@options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
def last_month_billable
|
15
|
+
start = DateTime.now.prev_month
|
16
|
+
|
17
|
+
start_date = start.strftime('%Y-%m-01')
|
18
|
+
end_date = DateTime.civil(start.year, start.month, -1).strftime(('%Y-%m-%d'))
|
19
|
+
|
20
|
+
@report ||= get_report(start_date: start_date, end_date: end_date)
|
21
|
+
billable_items
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def billable_items
|
27
|
+
params = {}
|
28
|
+
params[:default_client] = options[:default_client] if options[:default_client]
|
29
|
+
|
30
|
+
klass = Object.const_get("TogglBillable::Formatter::#{self.class.to_s.gsub(/^.*::/, '')}")
|
31
|
+
klass.new(report, options).billable_items
|
32
|
+
end
|
33
|
+
|
34
|
+
def hash_to_params
|
35
|
+
return '' unless params
|
36
|
+
|
37
|
+
params.map{ |k, v| "#{k}=#{v}" }.join('&')
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module TogglBillable
|
2
|
+
module Reports
|
3
|
+
class Details < Base
|
4
|
+
def get_report(options = {})
|
5
|
+
params[:since] = options[:start_date]
|
6
|
+
params[:until] = options[:end_date]
|
7
|
+
params[:grouping] = options[:grouping] if options[:grouping]
|
8
|
+
params[:subgrouping] = options[:subgrouping] if options[:grouping]
|
9
|
+
params[:page] = options[:page] || 1
|
10
|
+
params[:order_field] = options[:oder_field] || 'date'
|
11
|
+
count = 0
|
12
|
+
|
13
|
+
result = {}
|
14
|
+
|
15
|
+
loop do
|
16
|
+
request = "details?user_agent=reports&#{hash_to_params}"
|
17
|
+
response = JSON.parse(Client.report_get(request).body)
|
18
|
+
|
19
|
+
if result.size == 0
|
20
|
+
result = response
|
21
|
+
else
|
22
|
+
result['data'] += response['data']
|
23
|
+
end
|
24
|
+
|
25
|
+
count += response['data'].count
|
26
|
+
break if count >= response['total_count']
|
27
|
+
|
28
|
+
params[:page] += 1
|
29
|
+
end
|
30
|
+
|
31
|
+
result
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module TogglBillable
|
2
|
+
module Reports
|
3
|
+
class Summary < Base
|
4
|
+
def get_report(options)
|
5
|
+
params[:since] = options[:start_date]
|
6
|
+
params[:until] = options[:end_date]
|
7
|
+
params[:grouping] = options[:grouping] if options[:grouping]
|
8
|
+
params[:subgrouping] = options[:subgrouping] if options[:grouping]
|
9
|
+
|
10
|
+
request = "summary?#{hash_to_params}"
|
11
|
+
@report = JSON.parse(Client.report_get(request).body)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module TogglBillable
|
2
|
+
class User
|
3
|
+
|
4
|
+
def workspaces
|
5
|
+
response = Client.api_get('workspaces')
|
6
|
+
JSON.parse(response.body)
|
7
|
+
end
|
8
|
+
|
9
|
+
def default_workspace_id
|
10
|
+
response = Client.api_get('me')
|
11
|
+
JSON.parse(response.body)['data']['default_wid']
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'pry'
|
2
|
+
require 'faraday'
|
3
|
+
require 'json'
|
4
|
+
require 'date'
|
5
|
+
|
6
|
+
require_relative 'core_ext/fixnum.rb'
|
7
|
+
|
8
|
+
require_relative 'toggl_billable/client.rb'
|
9
|
+
require_relative 'toggl_billable/config.rb'
|
10
|
+
require_relative 'toggl_billable/user.rb'
|
11
|
+
require_relative 'toggl_billable/reports/base.rb'
|
12
|
+
require_relative 'toggl_billable/reports/summary.rb'
|
13
|
+
require_relative 'toggl_billable/reports/details.rb'
|
14
|
+
require_relative 'toggl_billable/formatter/base.rb'
|
15
|
+
require_relative 'toggl_billable/formatter/details.rb'
|
16
|
+
require_relative 'toggl_billable/formatter/summary.rb'
|
metadata
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: toggl_billable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jaroslava Kadlecova
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-03-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: faraday
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.8'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.8'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: json
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.6'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.6'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: vcr
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.5'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.5'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: webmock
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.5'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.5'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.5'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.5'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: pry
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: timecop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.6'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0.6'
|
111
|
+
description: A simple gem that enables to communicate with toggl API. Main Purpose
|
112
|
+
is to receive items for invoicing.
|
113
|
+
email: kadlecovaj@gmail.com
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- lib/core_ext/fixnum.rb
|
119
|
+
- lib/toggl_billable.rb
|
120
|
+
- lib/toggl_billable/client.rb
|
121
|
+
- lib/toggl_billable/config.rb
|
122
|
+
- lib/toggl_billable/formatter/base.rb
|
123
|
+
- lib/toggl_billable/formatter/details.rb
|
124
|
+
- lib/toggl_billable/formatter/summary.rb
|
125
|
+
- lib/toggl_billable/reports/base.rb
|
126
|
+
- lib/toggl_billable/reports/details.rb
|
127
|
+
- lib/toggl_billable/reports/summary.rb
|
128
|
+
- lib/toggl_billable/user.rb
|
129
|
+
homepage: http://github.com/jarkadlec/toggl_billable
|
130
|
+
licenses:
|
131
|
+
- MIT
|
132
|
+
metadata: {}
|
133
|
+
post_install_message:
|
134
|
+
rdoc_options: []
|
135
|
+
require_paths:
|
136
|
+
- lib
|
137
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
138
|
+
requirements:
|
139
|
+
- - ">="
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '2.0'
|
142
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - ">="
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0'
|
147
|
+
requirements: []
|
148
|
+
rubyforge_project:
|
149
|
+
rubygems_version: 2.4.6
|
150
|
+
signing_key:
|
151
|
+
specification_version: 4
|
152
|
+
summary: Basic operations with toggl API
|
153
|
+
test_files: []
|
154
|
+
has_rdoc:
|