sox 0.0.1 → 0.0.2
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.
- data/Gemfile.lock +1 -1
- data/README.md +6 -6
- data/lib/sox/client.rb +4 -0
- data/lib/sox/request_options.rb +1 -2
- data/lib/sox/restful_operation.rb +11 -1
- data/lib/sox/version.rb +1 -1
- data/spec/fixtures/all_clients_successful_response.xml +1 -0
- data/spec/fixtures/all_projects_successful_response.xml +1 -0
- data/spec/fixtures/all_time_entries_successful_response.xml +17 -0
- data/spec/fixtures/new_client_successful_response.xml +4 -0
- data/spec/fixtures/new_project_successful_response.xml +4 -0
- data/spec/fixtures/new_time_entry_successful_response.xml +4 -0
- data/spec/lib/sox/client_spec.rb +6 -0
- data/spec/lib/sox/clients_operations_spec.rb +31 -0
- data/spec/lib/sox/projects_operations_spec.rb +32 -0
- data/spec/lib/sox/request_options_spec.rb +5 -0
- data/spec/lib/sox/time_entries_operations_spec.rb +48 -0
- metadata +13 -3
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -31,7 +31,7 @@ Currenly Sox only supports basic authentication using your Freshbooks API token
|
|
|
31
31
|
You can retrieve your Freshbooks API token from the 'My Account' page on Freshbooks.
|
|
32
32
|
|
|
33
33
|
```ruby
|
|
34
|
-
@client = Sox::Client 'your-freshbooks-subdomain', 'api-token'
|
|
34
|
+
@client = Sox::Client.new 'your-freshbooks-subdomain', 'api-token'
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
You can then use your client object to perform the CRUD operations on Freshbooks.
|
|
@@ -54,8 +54,8 @@ This is a very early release. All the base classes and supporting classes should
|
|
|
54
54
|
* Add integration tests for real API data
|
|
55
55
|
* Support for OAuth authentication
|
|
56
56
|
|
|
57
|
-
* Clients (
|
|
58
|
-
* Projects (
|
|
57
|
+
* Clients (update, get, delete)
|
|
58
|
+
* Projects (update, get, delete)
|
|
59
59
|
* Categories (create, update, get, delete, list)
|
|
60
60
|
* Estimates (create, update, get, delete, list, sendByEmail)
|
|
61
61
|
* Categories (create, update, get, delete, list)
|
|
@@ -70,9 +70,9 @@ This is a very early release. All the base classes and supporting classes should
|
|
|
70
70
|
* Recurring (create, update, get, delete, list)
|
|
71
71
|
* Recurring Items (add, delete, update)
|
|
72
72
|
* Staff (current, get, list)
|
|
73
|
-
* Tasks (create, update, get, delete)
|
|
74
|
-
* Taxes (create, update, get, delete)
|
|
75
|
-
* Time entries (
|
|
73
|
+
* Tasks (create, update, get, delete, list)
|
|
74
|
+
* Taxes (create, update, get, delete, list)
|
|
75
|
+
* Time entries (update, get, delete)
|
|
76
76
|
|
|
77
77
|
## Contributing
|
|
78
78
|
|
data/lib/sox/client.rb
CHANGED
data/lib/sox/request_options.rb
CHANGED
|
@@ -28,12 +28,11 @@ module Sox
|
|
|
28
28
|
parent = NSXMLElement.alloc.initWithName(key)
|
|
29
29
|
value.each do |k, v|
|
|
30
30
|
el = generate_xml_node parent, k, v
|
|
31
|
-
element.addChild el
|
|
32
31
|
end
|
|
33
32
|
else
|
|
34
33
|
el = NSXMLElement.alloc.initWithName(key, stringValue: value.to_s)
|
|
35
|
-
element.addChild el
|
|
36
34
|
end
|
|
35
|
+
element.addChild el
|
|
37
36
|
element
|
|
38
37
|
end
|
|
39
38
|
end
|
|
@@ -9,7 +9,17 @@ module Sox
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def all(options={}, &block)
|
|
12
|
-
|
|
12
|
+
post("#{@prefix}.list", options, &block)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create(options={}, &block)
|
|
16
|
+
post("#{@prefix}.create", options, &block)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def post(path, options, &block)
|
|
22
|
+
payload = RequestOptions.new(path, options).request
|
|
13
23
|
opts = { credentials: @auth }
|
|
14
24
|
opts.merge!({ payload: payload })
|
|
15
25
|
BW::HTTP.post(@base_url, opts) do |response|
|
data/lib/sox/version.rb
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<response xmlns="http://www.freshbooks.com/api/" status="ok">
|
|
3
|
+
<time_entries page="1" per_page="15" pages="10" total="2">
|
|
4
|
+
<time_entry>
|
|
5
|
+
<time_entry_id>211</time_entry_id>
|
|
6
|
+
<staff_id>1</staff_id>
|
|
7
|
+
<project_id>1</project_id>
|
|
8
|
+
<task_id>1</task_id>
|
|
9
|
+
<hours>2</hours>
|
|
10
|
+
<date>2009-03-13</date>
|
|
11
|
+
<notes>Sample Notes</notes>
|
|
12
|
+
<billed>0</billed> <!-- 1 or 0 (Read Only) -->
|
|
13
|
+
</time_entry>
|
|
14
|
+
<time_entry>
|
|
15
|
+
</time_entry>
|
|
16
|
+
</time_entries>
|
|
17
|
+
</response>
|
data/spec/lib/sox/client_spec.rb
CHANGED
|
@@ -29,6 +29,12 @@ describe Sox::Client do
|
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
+
describe '#time_entries' do
|
|
33
|
+
it 'returns a proxy object' do
|
|
34
|
+
@client.time_entries.prefix.should == :time_entry
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
32
38
|
it 'can have multiple proxies' do
|
|
33
39
|
@client.clients.prefix.should == :client
|
|
34
40
|
@client.projects.prefix.should == :project
|
|
@@ -25,4 +25,35 @@ describe 'Freshbooks API clients operations' do
|
|
|
25
25
|
response[:clients][:client][1][:first_name][:data].should == 'John'
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
|
+
|
|
29
|
+
it 'can create a new client' do
|
|
30
|
+
body = load_fixture('new_client_successful_response.xml')
|
|
31
|
+
stub_request(:post, @client.base_url).to_return body: body, content_type: 'application/xml'
|
|
32
|
+
|
|
33
|
+
request = { client: {
|
|
34
|
+
first_name: 'Jane',
|
|
35
|
+
last_name: 'Doe',
|
|
36
|
+
organization: 'ABC Corp',
|
|
37
|
+
username: 'janedoe',
|
|
38
|
+
contacts: {
|
|
39
|
+
contact: {
|
|
40
|
+
username: 'alex',
|
|
41
|
+
first_name: '',
|
|
42
|
+
last_name: '',
|
|
43
|
+
email: 'test@freshbooks.com'
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
} }
|
|
47
|
+
|
|
48
|
+
@client.clients.create(request) do |r|
|
|
49
|
+
@response = r
|
|
50
|
+
resume
|
|
51
|
+
end
|
|
52
|
+
wait_max 1.0 do
|
|
53
|
+
response = @response[:response]
|
|
54
|
+
response[:status].should == 'ok'
|
|
55
|
+
response[:client_id][:data].should == '13'
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
28
59
|
end
|
|
@@ -24,4 +24,36 @@ describe 'Freshbooks API projects operations' do
|
|
|
24
24
|
response[:projects][:project][0][:client_id][:data].should == '119'
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
|
+
|
|
28
|
+
it 'can create a new project' do
|
|
29
|
+
body = load_fixture('new_project_successful_response.xml')
|
|
30
|
+
stub_request(:post, @client.base_url).to_return body: body, content_type: 'application/xml'
|
|
31
|
+
|
|
32
|
+
request = { project: {
|
|
33
|
+
name: 'Website Redesign',
|
|
34
|
+
bill_method: 'project-rate',
|
|
35
|
+
client_id: 21,
|
|
36
|
+
rate: 45.00,
|
|
37
|
+
description: 'A new website for ABC Corp',
|
|
38
|
+
tasks: {
|
|
39
|
+
task: {
|
|
40
|
+
task_id: 5
|
|
41
|
+
},
|
|
42
|
+
task: {
|
|
43
|
+
task_id: 3
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
} }
|
|
47
|
+
|
|
48
|
+
@client.projects.create(request) do |r|
|
|
49
|
+
@response = r
|
|
50
|
+
resume
|
|
51
|
+
end
|
|
52
|
+
wait_max 1.0 do
|
|
53
|
+
response = @response[:response]
|
|
54
|
+
response[:status].should == 'ok'
|
|
55
|
+
response[:project_id][:data].should == '15'
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
27
59
|
end
|
|
@@ -18,4 +18,9 @@ describe Sox::RequestOptions do
|
|
|
18
18
|
request = Sox::RequestOptions.new('client.list', { client: { address: { street: '123 Main St.' } } }).request
|
|
19
19
|
request.should == '<request method="client.list"><client><address><street>123 Main St.</street></address></client></request>'
|
|
20
20
|
end
|
|
21
|
+
|
|
22
|
+
it 'converts a converts a child list to xml' do
|
|
23
|
+
request = Sox::RequestOptions.new('client.list', { client: { attribute_one: 1, attribute_two: 2 } }).request
|
|
24
|
+
request.should == '<request method="client.list"><client><attribute_one>1</attribute_one><attribute_two>2</attribute_two></client></request>'
|
|
25
|
+
end
|
|
21
26
|
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
describe 'Freshbooks API time entries operations' do
|
|
2
|
+
extend WebStub::SpecHelpers
|
|
3
|
+
extend SpecHelper
|
|
4
|
+
|
|
5
|
+
before do
|
|
6
|
+
disable_network_access!
|
|
7
|
+
@client = Sox::Client.new 'fake', '12345'
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it 'can fetch all of the time entries' do
|
|
11
|
+
body = load_fixture('all_time_entries_successful_response.xml')
|
|
12
|
+
stub_request(:post, @client.base_url).to_return body: body, content_type: 'application/xml'
|
|
13
|
+
|
|
14
|
+
@client.time_entries.all do |r|
|
|
15
|
+
@response = r
|
|
16
|
+
resume
|
|
17
|
+
end
|
|
18
|
+
wait_max 1.0 do
|
|
19
|
+
response = @response[:response]
|
|
20
|
+
response[:status].should == 'ok'
|
|
21
|
+
response[:time_entries][:total].should == '2'
|
|
22
|
+
response[:time_entries][:time_entry][0][:project_id][:data].should == '1'
|
|
23
|
+
response[:time_entries][:time_entry][0][:hours][:data].should == '2'
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it 'can create a new time entry' do
|
|
28
|
+
body = load_fixture('new_time_entry_successful_response.xml')
|
|
29
|
+
stub_request(:post, @client.base_url).to_return body: body, content_type: 'application/xml'
|
|
30
|
+
|
|
31
|
+
request = { time_entry: {
|
|
32
|
+
project_id: 1,
|
|
33
|
+
task_id: 1,
|
|
34
|
+
hours: 4.5,
|
|
35
|
+
notes: 'Phone consultation'
|
|
36
|
+
} }
|
|
37
|
+
|
|
38
|
+
@client.time_entries.create(request) do |r|
|
|
39
|
+
@response = r
|
|
40
|
+
resume
|
|
41
|
+
end
|
|
42
|
+
wait_max 1.0 do
|
|
43
|
+
response = @response[:response]
|
|
44
|
+
response[:status].should == 'ok'
|
|
45
|
+
response[:time_entry_id][:data].should == '211'
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sox
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.2
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -101,10 +101,15 @@ files:
|
|
|
101
101
|
- spec/_spec_helper.rb
|
|
102
102
|
- spec/fixtures/all_clients_successful_response.xml
|
|
103
103
|
- spec/fixtures/all_projects_successful_response.xml
|
|
104
|
+
- spec/fixtures/all_time_entries_successful_response.xml
|
|
105
|
+
- spec/fixtures/new_client_successful_response.xml
|
|
106
|
+
- spec/fixtures/new_project_successful_response.xml
|
|
107
|
+
- spec/fixtures/new_time_entry_successful_response.xml
|
|
104
108
|
- spec/lib/sox/client_spec.rb
|
|
105
109
|
- spec/lib/sox/clients_operations_spec.rb
|
|
106
110
|
- spec/lib/sox/projects_operations_spec.rb
|
|
107
111
|
- spec/lib/sox/request_options_spec.rb
|
|
112
|
+
- spec/lib/sox/time_entries_operations_spec.rb
|
|
108
113
|
- spec/lib/sox/xml_parser_spec.rb
|
|
109
114
|
homepage:
|
|
110
115
|
licenses: []
|
|
@@ -120,7 +125,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
120
125
|
version: '0'
|
|
121
126
|
segments:
|
|
122
127
|
- 0
|
|
123
|
-
hash:
|
|
128
|
+
hash: 3723447028891806663
|
|
124
129
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
125
130
|
none: false
|
|
126
131
|
requirements:
|
|
@@ -129,7 +134,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
129
134
|
version: '0'
|
|
130
135
|
segments:
|
|
131
136
|
- 0
|
|
132
|
-
hash:
|
|
137
|
+
hash: 3723447028891806663
|
|
133
138
|
requirements: []
|
|
134
139
|
rubyforge_project:
|
|
135
140
|
rubygems_version: 1.8.23
|
|
@@ -140,8 +145,13 @@ test_files:
|
|
|
140
145
|
- spec/_spec_helper.rb
|
|
141
146
|
- spec/fixtures/all_clients_successful_response.xml
|
|
142
147
|
- spec/fixtures/all_projects_successful_response.xml
|
|
148
|
+
- spec/fixtures/all_time_entries_successful_response.xml
|
|
149
|
+
- spec/fixtures/new_client_successful_response.xml
|
|
150
|
+
- spec/fixtures/new_project_successful_response.xml
|
|
151
|
+
- spec/fixtures/new_time_entry_successful_response.xml
|
|
143
152
|
- spec/lib/sox/client_spec.rb
|
|
144
153
|
- spec/lib/sox/clients_operations_spec.rb
|
|
145
154
|
- spec/lib/sox/projects_operations_spec.rb
|
|
146
155
|
- spec/lib/sox/request_options_spec.rb
|
|
156
|
+
- spec/lib/sox/time_entries_operations_spec.rb
|
|
147
157
|
- spec/lib/sox/xml_parser_spec.rb
|