sage_one 0.0.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.
- data/.gitignore +14 -0
- data/.travis.yml +11 -0
- data/.yardopts +4 -0
- data/Gemfile +8 -0
- data/LICENSE +19 -0
- data/README.md +141 -0
- data/Rakefile +4 -0
- data/bin/autospec +16 -0
- data/bin/htmldiff +16 -0
- data/bin/ldiff +16 -0
- data/bin/rake +16 -0
- data/bin/rspec +16 -0
- data/bin/yard +16 -0
- data/bin/yardoc +16 -0
- data/bin/yri +16 -0
- data/lib/faraday/request/oauth2.rb +25 -0
- data/lib/faraday/response/convert_sdata_to_headers.rb +70 -0
- data/lib/faraday/response/raise_sage_one_exception.rb +42 -0
- data/lib/sage_one/client/contacts.rb +14 -0
- data/lib/sage_one/client/sales_invoices.rb +77 -0
- data/lib/sage_one/client.rb +33 -0
- data/lib/sage_one/configuration.rb +81 -0
- data/lib/sage_one/connection.rb +44 -0
- data/lib/sage_one/error.rb +39 -0
- data/lib/sage_one/oauth.rb +49 -0
- data/lib/sage_one/request.rb +72 -0
- data/lib/sage_one/version.rb +3 -0
- data/lib/sage_one.rb +31 -0
- data/sage_one.gemspec +32 -0
- data/spec/faraday/request/oauth2_spec.rb +44 -0
- data/spec/faraday/response/convert_sdata_to_headers_spec.rb +113 -0
- data/spec/faraday/response/raise_sage_one_exception_spec.rb +45 -0
- data/spec/fixtures/contact.json +28 -0
- data/spec/fixtures/invalid_sales_invoice.json +28 -0
- data/spec/fixtures/oauth/invalid_client.json +1 -0
- data/spec/fixtures/oauth/invalid_grant.json +1 -0
- data/spec/fixtures/oauth/oauth_token.json +4 -0
- data/spec/fixtures/sales_invoice.json +43 -0
- data/spec/fixtures/sales_invoices.json +90 -0
- data/spec/sage_one/client/contacts_spec.rb +19 -0
- data/spec/sage_one/client/sales_invoices_spec.rb +53 -0
- data/spec/sage_one/client_spec.rb +41 -0
- data/spec/sage_one/configuration_spec.rb +88 -0
- data/spec/sage_one/connection_spec.rb +36 -0
- data/spec/sage_one/oauth_spec.rb +44 -0
- data/spec/sage_one/request_spec.rb +113 -0
- data/spec/sage_one/version_spec.rb +7 -0
- data/spec/sage_one_spec.rb +38 -0
- data/spec/spec_helper.rb +76 -0
- metadata +301 -0
@@ -0,0 +1,90 @@
|
|
1
|
+
{ "$totalResults":2,
|
2
|
+
"$startIndex":0,
|
3
|
+
"$itemsPerPage":20,
|
4
|
+
|
5
|
+
"$resources":[
|
6
|
+
{ "id":954380,
|
7
|
+
"invoice_number":"SI-4",
|
8
|
+
"status":{"id":1, "$key":1},
|
9
|
+
"due_date":"19/04/2013",
|
10
|
+
"date":"20/03/2013",
|
11
|
+
"void_reason":null,
|
12
|
+
"outstanding_amount":"17.0",
|
13
|
+
"total_net_amount":"14.17",
|
14
|
+
"total_tax_amount":"2.83",
|
15
|
+
"tax_scheme_period_id":30394,
|
16
|
+
"carriage":"0.0",
|
17
|
+
"carriage_tax_code":{"id":1, "$key":1},
|
18
|
+
"carriage_tax_rate_percentage":"20.0",
|
19
|
+
"contact":{"id":568085, "$key":568085},
|
20
|
+
"contact_name":"Luke corp (Luke Brown)",
|
21
|
+
"main_address":"Killer Bees",
|
22
|
+
"delivery_address":"",
|
23
|
+
"delivery_address_same_as_main":false,
|
24
|
+
"reference":"",
|
25
|
+
"notes":"future date. did email it.",
|
26
|
+
"terms_and_conditions":"",
|
27
|
+
"lock_version":0,
|
28
|
+
"line_items":[{
|
29
|
+
"id":1570294,
|
30
|
+
"description":"Some fish - herring",
|
31
|
+
"quantity":"1.0",
|
32
|
+
"unit_price":"17.0",
|
33
|
+
"net_amount":"14.17",
|
34
|
+
"tax_amount":"2.83",
|
35
|
+
"tax_code":{"id":1, "$key":1},
|
36
|
+
"tax_rate_percentage":"20.0",
|
37
|
+
"unit_price_includes_tax":true,
|
38
|
+
"ledger_account":{"id":1898509,
|
39
|
+
"$key":1898509},
|
40
|
+
"product_code":"HERRING",
|
41
|
+
"product":{"id":68656, "$key":68656},
|
42
|
+
"service":{"$key":null},
|
43
|
+
"lock_version":0,
|
44
|
+
"$key":1570294
|
45
|
+
}
|
46
|
+
],
|
47
|
+
"$key":954380},
|
48
|
+
{"id":954368,
|
49
|
+
"invoice_number":"SI-3",
|
50
|
+
"status":{"id":1, "$key":1},
|
51
|
+
"due_date":"07/12/2012",
|
52
|
+
"date":"07/11/2012",
|
53
|
+
"void_reason":null,
|
54
|
+
"outstanding_amount":"19.4",
|
55
|
+
"total_net_amount":"16.17",
|
56
|
+
"total_tax_amount":"3.23",
|
57
|
+
"tax_scheme_period_id":30394,
|
58
|
+
"carriage":"2.0",
|
59
|
+
"carriage_tax_code":{"id":1, "$key":1},
|
60
|
+
"carriage_tax_rate_percentage":"20.0",
|
61
|
+
"contact":{"id":568085, "$key":568085},
|
62
|
+
"contact_name":"Luke corp (Luke Brown)",
|
63
|
+
"main_address":"here man.",
|
64
|
+
"delivery_address":"",
|
65
|
+
"delivery_address_same_as_main":false,
|
66
|
+
"reference":"",
|
67
|
+
"notes":"this one neither emailed nor printed.",
|
68
|
+
"terms_and_conditions":"",
|
69
|
+
"lock_version":0,
|
70
|
+
"line_items":[{
|
71
|
+
"id":1570277,
|
72
|
+
"description":"Some fish - herring",
|
73
|
+
"quantity":"1.0",
|
74
|
+
"unit_price":"17.0",
|
75
|
+
"net_amount":"14.17",
|
76
|
+
"tax_amount":"2.83",
|
77
|
+
"tax_code":{"id":1, "$key":1},
|
78
|
+
"tax_rate_percentage":"20.0",
|
79
|
+
"unit_price_includes_tax":true,
|
80
|
+
"ledger_account":{"id":1898509, "$key":1898509},
|
81
|
+
"product_code":"HERRING",
|
82
|
+
"product":{"id":68656, "$key":68656},
|
83
|
+
"service":{"$key":null},
|
84
|
+
"lock_version":0,
|
85
|
+
"$key":1570277
|
86
|
+
}
|
87
|
+
],
|
88
|
+
"$key":954368}
|
89
|
+
]
|
90
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SageOne::Client::Contacts do
|
4
|
+
|
5
|
+
let(:client) { SageOne.new }
|
6
|
+
|
7
|
+
describe '.contact' do
|
8
|
+
context 'when the contact exists' do
|
9
|
+
it 'returns a Hashie::Mash of the contact' do
|
10
|
+
stub_get('contacts/1').to_return(body: fixture('contact.json'))
|
11
|
+
contact = client.contact(1)
|
12
|
+
expect(contact).to be_a(Hashie::Mash)
|
13
|
+
expect(contact.name).to eq('Luke Brown')
|
14
|
+
expect(contact.email).to eq('luke.brown@example.com')
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SageOne::Client::SalesInvoices do
|
4
|
+
|
5
|
+
let(:client) { SageOne.new }
|
6
|
+
|
7
|
+
describe 'sales_invoices' do
|
8
|
+
it 'returns an array of Hashie::Mashes, representing the available invoices' do
|
9
|
+
stub_get('sales_invoices').to_return(body: fixture('sales_invoices.json'))
|
10
|
+
inv = client.sales_invoices.first
|
11
|
+
expect(inv.outstanding_amount).to eq '17.0'
|
12
|
+
expect(inv.outstanding_amount).to eq '17.0'
|
13
|
+
expect(inv.notes).to eq 'future date. did email it.'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'create_sales_invoice' do
|
18
|
+
it 'posts to the correct endpoint and returns the new invoice' do
|
19
|
+
stub_post('sales_invoices').to_return(body: fixture('sales_invoice.json'))
|
20
|
+
invoice = client.create_sales_invoice(foo: 'bar')
|
21
|
+
a_post('sales_invoices').with(body: { sales_invoice: { foo: 'bar' } }).should have_been_made.once
|
22
|
+
expect(invoice.invoice_number).to eq 'SI-4'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'sales_invoice' do
|
27
|
+
it 'gets the requested sales invoice' do
|
28
|
+
stub_get('sales_invoices/333').to_return(body: fixture('sales_invoice.json'))
|
29
|
+
invoice = client.sales_invoice(333)
|
30
|
+
a_get('sales_invoices/333').should have_been_made.once
|
31
|
+
expect(invoice.invoice_number).to eq 'SI-4'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe 'update_sales_invoice' do
|
36
|
+
it "makes a put and returns the new invoice" do
|
37
|
+
stub_put('sales_invoices/333').to_return(body: fixture('sales_invoice.json'))
|
38
|
+
invoice = client.update_sales_invoice(333, foo: 'bar')
|
39
|
+
a_put('sales_invoices/333').with(body: { sales_invoice: { foo: 'bar' } }).should have_been_made.once
|
40
|
+
expect(invoice.invoice_number).to eq 'SI-4'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe 'delete_sales_invoice!' do
|
45
|
+
it "makes a delete and returns the deleted invoice" do
|
46
|
+
stub_delete('sales_invoices/444').to_return(body: fixture('sales_invoice.json'))
|
47
|
+
invoice = client.delete_sales_invoice!(444)
|
48
|
+
a_delete('sales_invoices/444').should have_been_made.once
|
49
|
+
expect(invoice.invoice_number).to eq 'SI-4'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SageOne::Client do
|
4
|
+
|
5
|
+
it 'creates accessors for all the keys in the SageOne::Configuration::VALID_OPTIONS_KEYS constant' do
|
6
|
+
client = SageOne::Client.new
|
7
|
+
SageOne::Configuration::VALID_OPTIONS_KEYS.each_with_index do |method, i|
|
8
|
+
value = "Setting attribute #{i}"
|
9
|
+
client.send("#{method}=", value)
|
10
|
+
expect(client.send(method)).to eq(value)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'initialize' do
|
15
|
+
it 'copies the SageOne.options to the new client' do
|
16
|
+
client = SageOne::Client.new
|
17
|
+
SageOne::Configuration::VALID_OPTIONS_KEYS.each do |method|
|
18
|
+
expect(client.send(method)).to eq(SageOne.options[method])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
it 'allows you to override any config options' do
|
22
|
+
better_options = {
|
23
|
+
adapter: 'BestAdaptor',
|
24
|
+
faraday_config_block: 'blocky block',
|
25
|
+
api_endpoint: 'https://www.example.com/',
|
26
|
+
proxy: 'proxy.example.com',
|
27
|
+
access_token: 'let_me_in',
|
28
|
+
client_id: 'client123',
|
29
|
+
client_secret: 'secret',
|
30
|
+
user_agent: 'Gem Awesome',
|
31
|
+
request_host: 'example.com',
|
32
|
+
auto_traversal: true,
|
33
|
+
raw_response: true
|
34
|
+
}
|
35
|
+
client = SageOne::Client.new(better_options)
|
36
|
+
SageOne::Configuration::VALID_OPTIONS_KEYS.each do |method|
|
37
|
+
expect(client.send(method)).to eq(better_options[method])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SageOne::Configuration do
|
4
|
+
|
5
|
+
subject do
|
6
|
+
module TestConfigModule
|
7
|
+
extend SageOne::Configuration
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'has some default constants setup' do
|
12
|
+
expect(SageOne::Configuration::DEFAULT_ADAPTER).to eq(Faraday.default_adapter)
|
13
|
+
expect(SageOne::Configuration::DEFAULT_API_ENDPOINT).to eq('https://app.sageone.com/api/v1/')
|
14
|
+
expect(SageOne::Configuration::DEFAULT_USER_AGENT).to eq("SageOne Ruby Gem #{SageOne::VERSION}")
|
15
|
+
expect(SageOne::Configuration::DEFAULT_AUTO_TRAVERSAL).to be_false
|
16
|
+
expect(SageOne::Configuration::DEFAULT_RAW_RESPONSE).to be_false
|
17
|
+
expect(SageOne::Configuration::VALID_OPTIONS_KEYS).to be_a(Array)
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'attr_accessors' do
|
21
|
+
it 'creates accessors for all the keys in the VALID_OPTIONS_KEYS constant' do
|
22
|
+
SageOne::Configuration::VALID_OPTIONS_KEYS.reject { |k| [:api_endpoint].include?(k) }.each_with_index do |method, i|
|
23
|
+
value = "Setting attribute #{i}"
|
24
|
+
subject.send("#{method}=", value)
|
25
|
+
expect(subject.send(method)).to eq(value)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
it 'uses an overridden method for setting the api_endpoint which ensures a trailing forward slash is present' do
|
29
|
+
subject.api_endpoint = 'http://www.example.com'
|
30
|
+
expect(subject.api_endpoint).to eq('http://www.example.com/')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "faraday_config" do
|
35
|
+
it 'assigns the given block to faraday_config_block' do
|
36
|
+
p = lambda { 'hi' }
|
37
|
+
subject.faraday_config(&p)
|
38
|
+
expect(subject.faraday_config_block.call).to eq('hi')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe 'configure' do
|
43
|
+
it 'yields the given block passing in self - allowing you to config attributes' do
|
44
|
+
value = "my new client id"
|
45
|
+
|
46
|
+
subject.configure do |config|
|
47
|
+
config.client_id = value
|
48
|
+
end
|
49
|
+
|
50
|
+
expect(subject.client_id).to eq(value)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe 'options' do
|
55
|
+
it 'returns a new hash of all the config options' do
|
56
|
+
expect(subject.options).to be_a(Hash)
|
57
|
+
expect(subject.options.keys).to eq(SageOne::Configuration::VALID_OPTIONS_KEYS)
|
58
|
+
expect(subject.options[:adapter]).to eq(SageOne::Configuration::DEFAULT_ADAPTER)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe 'extended' do
|
63
|
+
it 'calls reset on module extending it' do
|
64
|
+
module NewMod; end
|
65
|
+
NewMod.should_receive(:reset).once
|
66
|
+
NewMod.extend(SageOne::Configuration)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe 'reset' do
|
71
|
+
it 'resets all the config options to the default values' do
|
72
|
+
# Change them first
|
73
|
+
SageOne::Configuration::VALID_OPTIONS_KEYS.each { |method| subject.send("#{method}=", 'something') }
|
74
|
+
subject.reset
|
75
|
+
expect(subject.adapter).to eq(SageOne::Configuration::DEFAULT_ADAPTER)
|
76
|
+
expect(subject.api_endpoint).to eq(SageOne::Configuration::DEFAULT_API_ENDPOINT)
|
77
|
+
expect(subject.proxy).to be_nil
|
78
|
+
expect(subject.access_token).to be_nil
|
79
|
+
expect(subject.client_id).to be_nil
|
80
|
+
expect(subject.client_secret).to be_nil
|
81
|
+
expect(subject.request_host).to be_nil
|
82
|
+
expect(subject.user_agent).to eq(SageOne::Configuration::DEFAULT_USER_AGENT)
|
83
|
+
expect(subject.auto_traversal).to be_false
|
84
|
+
expect(subject.raw_response).to be_false
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SageOne::Connection do
|
4
|
+
|
5
|
+
let(:client) { SageOne.new }
|
6
|
+
let(:basic_middleware) { %w(FaradayMiddleware::EncodeJson FaradayMiddleware::OAuth2 FaradayMiddleware::RaiseSageOneException) }
|
7
|
+
let(:non_raw_middleware) { %w(FaradayMiddleware::Mashify FaradayMiddleware::ParseJson) }
|
8
|
+
|
9
|
+
it "returns a Faraday" do
|
10
|
+
expect(client.send(:connection)).to be_a(Faraday::Connection)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "sets up mandatory headers" do
|
14
|
+
headers = client.send(:connection).headers
|
15
|
+
|
16
|
+
{ "Accept" => /application\/json/,
|
17
|
+
"User-Agent" => /SageOne Ruby Gem/,
|
18
|
+
"Content-Type" => /application\/json/ }.each do |header, value|
|
19
|
+
expect(headers[header]).to match(value)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it "has the correct middleware stack" do
|
24
|
+
stack = client.send(:connection).builder.handlers.map(&:name)
|
25
|
+
(basic_middleware + non_raw_middleware).each { |mw| expect(stack).to include(mw) }
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'raw connection requested' do
|
29
|
+
it 'does not include mashify or parse_json' do
|
30
|
+
client.raw_response = true
|
31
|
+
stack = client.send(:connection).builder.handlers.map(&:name)
|
32
|
+
(non_raw_middleware).each { |mw| expect(stack).to_not include(mw) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SageOne::OAuth do
|
4
|
+
|
5
|
+
let(:client) { SageOne.new(client_id: "CLIENT_ID", client_secret: "CLIENT_SECRET") }
|
6
|
+
|
7
|
+
describe 'authorize_url' do
|
8
|
+
it 'returns a correctly formatted url' do
|
9
|
+
expect(client.authorize_url('http://www.example.com/endpoint')).to eq("https://app.sageone.com/oauth/authorize/?client_id=CLIENT_ID&redirect_uri=http%3A%2F%2Fwww.example.com%2Fendpoint&response_type=code")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe 'get_access_token' do
|
14
|
+
it 'returns an object containing an access_token' do
|
15
|
+
|
16
|
+
stub_post("https://app.sageone.com/oauth/token/").
|
17
|
+
with(:body => "{\"client_id\":\"CLIENT_ID\",\"client_secret\":\"CLIENT_SECRET\",\"grant_type\":\"authorization_code\",\"code\":\"uuddlrlr\",\"redirect_uri\":\"http://www.example.com/endpoint\"}",
|
18
|
+
:headers => {'Accept'=>'application/json; charset=utf-8', 'Content-Type'=>'application/json', 'User-Agent'=>'SageOne Ruby Gem 0.0.1'}).
|
19
|
+
to_return(:body => fixture("oauth/oauth_token.json"))
|
20
|
+
|
21
|
+
expect(client.get_access_token('uuddlrlr', 'http://www.example.com/endpoint').access_token).to eq('IguLPAK5VPvDSw3z4SjrkhHTyRXgnnqAPzt1mLUk')
|
22
|
+
end
|
23
|
+
|
24
|
+
describe 'failure cases' do
|
25
|
+
context 'invalid client' do
|
26
|
+
before do
|
27
|
+
client.client_secret = "SALMON"
|
28
|
+
stub_post("https://app.sageone.com/oauth/token/").to_return(status: 401, body: fixture('oauth/invalid_client.json'))
|
29
|
+
end
|
30
|
+
it { expect { client.get_access_token('uuddlrlr', 'http://www.example.com/endpoint') }.to raise_error(SageOne::Unauthorized, /invalid_client/) }
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'wrong code' do
|
34
|
+
before { stub_post("https://app.sageone.com/oauth/token/").to_return(status: 400, body: fixture('oauth/invalid_grant.json')) }
|
35
|
+
it { expect { client.get_access_token('', 'http://www.example.com/endpoint') } .to raise_error(SageOne::BadRequest, /invalid_grant/) }
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'wrong callback' do
|
39
|
+
before { stub_post("https://app.sageone.com/oauth/token/").to_return(status: 401, body: '') }
|
40
|
+
it { expect { client.get_access_token('uuddlrlr', 'http://www.example.com/notendpoint') }.to raise_error(SageOne::Unauthorized, %q{{"method":"post","url":"https://app.sageone.com/oauth/token/","status":401,"body":""}}) }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SageOne::Request do
|
4
|
+
|
5
|
+
let(:client) { SageOne.new }
|
6
|
+
|
7
|
+
describe 'helper methods' do
|
8
|
+
before { client.stub(:request) }
|
9
|
+
|
10
|
+
[:get, :delete, :post, :put].each do |meth|
|
11
|
+
it "#{meth} exists and delegates to request" do
|
12
|
+
client.should_receive(:request).with(meth, 'foo', {})
|
13
|
+
client.send(meth, 'foo')
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'request' do
|
19
|
+
context 'get/delete' do
|
20
|
+
it "makes a get request" do
|
21
|
+
stub_get('sales_invoices')
|
22
|
+
client.get('sales_invoices')
|
23
|
+
a_get('sales_invoices').should have_been_made.once
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'with options' do
|
27
|
+
it 'passes the options to the get request' do
|
28
|
+
stub_get('sales_invoices?start_date=2011-12-13')
|
29
|
+
client.get('sales_invoices', { start_date: '2011-12-13' })
|
30
|
+
a_get('sales_invoices?start_date=2011-12-13').should have_been_made.once
|
31
|
+
end
|
32
|
+
it 'special-cases start_index' do
|
33
|
+
stub_delete('sales_invoices?start_date=2011-12-13&%24startIndex=10')
|
34
|
+
client.delete('sales_invoices', { start_date: '2011-12-13', start_index: 10 })
|
35
|
+
a_delete('sales_invoices?start_date=2011-12-13&%24startIndex=10').should have_been_made.once
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
context 'put/post' do
|
40
|
+
it "sets the request path" do
|
41
|
+
stub_post('sales_invoices')
|
42
|
+
client.post('sales_invoices')
|
43
|
+
a_post('sales_invoices').should have_been_made.once
|
44
|
+
end
|
45
|
+
it "stores the options in the body" do
|
46
|
+
stub_put('sales_invoices')
|
47
|
+
client.put('sales_invoices', { "void_reason" => nil, "outstanding_amount" => "17.0", "total_net_amount" => "14.17"})
|
48
|
+
a_put('sales_invoices').with(body: '{"void_reason":null,"outstanding_amount":"17.0","total_net_amount":"14.17"}').should have_been_made.once
|
49
|
+
end
|
50
|
+
describe 'auto-conversion of Date-y objects' do
|
51
|
+
it "converts any options which are passed which resemble a date into a correctly-formatted date" do
|
52
|
+
stub_put('sales_invoices/222')
|
53
|
+
client.put('sales_invoices/222', { start_date: Time.new(2012, 10, 20), contents: { another_date: Time.new(2011, 8, 31) }})
|
54
|
+
a_put('sales_invoices/222').with(body: '{"start_date":"20/10/2012","contents":{"another_date":"31/08/2011"}}').should have_been_made.once
|
55
|
+
end
|
56
|
+
it "converts for any type of request, not just puts (regression test)" do
|
57
|
+
stub_get('sales_invoices?contents%5Banother_date%5D=31/08/2011&start_date=20/10/2012')
|
58
|
+
client.get('sales_invoices', { start_date: Time.new(2012, 10, 20), contents: { another_date: Time.new(2011, 8, 31) }})
|
59
|
+
a_get('sales_invoices?contents%5Banother_date%5D=31/08/2011&start_date=20/10/2012').should have_been_made.once
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'Sets a request host if one is specified' do
|
65
|
+
client.request_host = "CustomerHost"
|
66
|
+
stub_get('sales_invoices')
|
67
|
+
client.get('sales_invoices')
|
68
|
+
a_get('sales_invoices').with(headers: { "Host" => 'CustomerHost' }).should have_been_made.once
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "response body" do
|
72
|
+
context 'raw requested' do
|
73
|
+
it "returns a faraday response" do
|
74
|
+
stub_get('sales_invoices')
|
75
|
+
client.raw_response = true
|
76
|
+
expect(client.get('sales_invoices', {})).to be_a(Faraday::Response)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
context 'not raw' do
|
80
|
+
it "returns an array of Hashie::Mash-es" do
|
81
|
+
stub_get('sales_invoices').to_return(body: fixture('sales_invoices.json'))
|
82
|
+
expect(client.get('sales_invoices')).to be_a(Array)
|
83
|
+
expect(client.get('sales_invoices').first).to be_a(Hashie::Mash)
|
84
|
+
expect(client.get('sales_invoices').first.outstanding_amount).to eq("17.0")
|
85
|
+
expect(client.get('sales_invoices').last).to be_a(Hashie::Mash)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'with auto_traversal turned on' do
|
91
|
+
before { client.auto_traversal = true }
|
92
|
+
it "recursively calls itself to build a complete result set" do
|
93
|
+
|
94
|
+
stub_get("sales_invoices").to_return(:status => 200, :body => sdata_fixture('sales_invoices.json', 30, 0, 10))
|
95
|
+
stub_get("sales_invoices?$startIndex=10").to_return(:status => 200, :body => sdata_fixture('sales_invoices.json', 30, 10, 10))
|
96
|
+
stub_get("sales_invoices?$startIndex=20").to_return(:status => 200, :body => sdata_fixture('sales_invoices.json', 30, 20, 10))
|
97
|
+
|
98
|
+
result = client.get("sales_invoices")
|
99
|
+
|
100
|
+
a_get('sales_invoices').should have_been_made.once
|
101
|
+
a_get('sales_invoices?$startIndex=10').should have_been_made.once
|
102
|
+
a_get('sales_invoices?$startIndex=20').should have_been_made.once
|
103
|
+
|
104
|
+
# The response should be three copies of the fixture file concatenated, so result[0] == result[2], etc
|
105
|
+
expect(result.size).to eq(6)
|
106
|
+
expect(result).to be_an(Array)
|
107
|
+
expect(result[0]).to be_a(Hashie::Mash)
|
108
|
+
expect(result[5]).to be_a(Hashie::Mash)
|
109
|
+
expect(result[0]).to eq(result[2])
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SageOne do
|
4
|
+
|
5
|
+
describe '.new' do
|
6
|
+
it { SageOne.new.should be_a(SageOne::Client) }
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '.respond_to?' do
|
10
|
+
it 'returns true when the method exists' do
|
11
|
+
expect(SageOne.respond_to?(:new, true)).to be_true
|
12
|
+
end
|
13
|
+
it 'returns true when a client responds to the method' do
|
14
|
+
expect(SageOne.respond_to?(:sales_invoices)).to be_true
|
15
|
+
end
|
16
|
+
it 'returns false when the method does not exist' do
|
17
|
+
expect(SageOne.respond_to?(:noway, true)).to be_false
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '.method_missing' do
|
22
|
+
context "when the client does not respond to the method either" do
|
23
|
+
it 'raises a NoMethodError' do
|
24
|
+
expect(lambda{ SageOne.noway }).to raise_error(NoMethodError)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
context "when the client does respond to the method" do
|
28
|
+
it 'delegates the call to the client, passing any args and block' do
|
29
|
+
block = Proc.new { puts "hi" }
|
30
|
+
mock_client = mock('SageOne::Client', :my_method => 'called')
|
31
|
+
SageOne.should_receive(:new).twice.and_return(mock_client)
|
32
|
+
mock_client.should_receive(:my_method).with('abc', block)
|
33
|
+
SageOne.my_method('abc', block)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
unless ENV['CI']
|
2
|
+
require 'simplecov'
|
3
|
+
SimpleCov.start do
|
4
|
+
add_filter "/spec"
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'sage_one'
|
9
|
+
require 'rspec'
|
10
|
+
require 'webmock/rspec'
|
11
|
+
|
12
|
+
RSpec.configure do |config|
|
13
|
+
config.color_enabled = true
|
14
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
15
|
+
config.filter_run :focus => true
|
16
|
+
config.run_all_when_everything_filtered = true
|
17
|
+
end
|
18
|
+
|
19
|
+
def a_delete(url)
|
20
|
+
a_request(:delete, sage_url(url))
|
21
|
+
end
|
22
|
+
|
23
|
+
def a_get(url)
|
24
|
+
a_request(:get, sage_url(url))
|
25
|
+
end
|
26
|
+
|
27
|
+
def a_patch(url)
|
28
|
+
a_request(:patch, sage_url(url))
|
29
|
+
end
|
30
|
+
|
31
|
+
def a_post(url)
|
32
|
+
a_request(:post, sage_url(url))
|
33
|
+
end
|
34
|
+
|
35
|
+
def a_put(url)
|
36
|
+
a_request(:put, sage_url(url))
|
37
|
+
end
|
38
|
+
|
39
|
+
def stub_delete(url)
|
40
|
+
stub_request(:delete, sage_url(url))
|
41
|
+
end
|
42
|
+
|
43
|
+
def stub_get(url)
|
44
|
+
stub_request(:get, sage_url(url))
|
45
|
+
end
|
46
|
+
|
47
|
+
def stub_post(url)
|
48
|
+
stub_request(:post, sage_url(url))
|
49
|
+
end
|
50
|
+
|
51
|
+
def stub_put(url)
|
52
|
+
stub_request(:put, sage_url(url))
|
53
|
+
end
|
54
|
+
|
55
|
+
def sage_url(url)
|
56
|
+
if url =~ /^http/
|
57
|
+
url
|
58
|
+
else
|
59
|
+
"https://app.sageone.com/api/v1/#{url}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def fixture_path
|
64
|
+
File.expand_path("../fixtures", __FILE__)
|
65
|
+
end
|
66
|
+
|
67
|
+
def fixture(file)
|
68
|
+
File.new(fixture_path + '/' + file)
|
69
|
+
end
|
70
|
+
|
71
|
+
def sdata_fixture(fixture, total_results, start_index, items_per_page)
|
72
|
+
raw = fixture(fixture).read
|
73
|
+
raw.sub!(/"\$totalResults":(\d+)/, %Q("$totalResults":#{total_results}))
|
74
|
+
raw.sub!(/"\$startIndex":(\d+)/, %Q("$startIndex":#{start_index}))
|
75
|
+
raw.sub!(/"\$itemsPerPage":(\d+)/, %Q("$itemsPerPage":#{items_per_page}))
|
76
|
+
end
|