toggl_billable 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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,9 @@
1
+ class Fixnum
2
+ DEFAULT_ROUNDING = 0.25
3
+
4
+ def to_hours(round=nil)
5
+ round ||= DEFAULT_ROUNDING
6
+
7
+ ((self / 3600000.0) / round).round * 0.25
8
+ end
9
+ end
@@ -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: