currency_cloud 0.5 → 0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +151 -8
- data/currency_cloud.gemspec +1 -0
- data/lib/currency_cloud.rb +14 -0
- data/lib/currency_cloud/actions/delete.rb +7 -1
- data/lib/currency_cloud/actions/save.rb +14 -0
- data/lib/currency_cloud/errors/api_error.rb +38 -2
- data/lib/currency_cloud/errors/error_utils.rb +14 -0
- data/lib/currency_cloud/errors/general_error.rb +5 -0
- data/lib/currency_cloud/errors/unexpected_error.rb +23 -1
- data/lib/currency_cloud/request_handler.rb +27 -20
- data/lib/currency_cloud/resource.rb +7 -1
- data/lib/currency_cloud/resources/balance.rb +3 -1
- data/lib/currency_cloud/resources/beneficiary.rb +2 -3
- data/lib/currency_cloud/resources/payment.rb +0 -2
- data/lib/currency_cloud/resources/settlement.rb +30 -9
- data/lib/currency_cloud/response_handler.rb +14 -15
- data/lib/currency_cloud/session.rb +4 -4
- data/lib/currency_cloud/version.rb +1 -1
- data/spec/currency_cloud/request_handler_spec.rb +32 -0
- data/spec/currency_cloud/resource_spec.rb +37 -0
- data/spec/currency_cloud_spec.rb +49 -5
- data/spec/integration/actions_spec.rb +28 -0
- data/spec/integration/errors_spec.rb +47 -0
- data/spec/integration/rates_spec.rb +1 -1
- data/spec/integration/settlements_spec.rb +67 -0
- data/spec/spec_helper.rb +3 -2
- data/spec/support/vcr_cassettes/Actions/can_first.yml +0 -36
- data/spec/support/vcr_cassettes/Actions/can_use_currency_to_retrieve_balance.yml +36 -0
- data/spec/support/vcr_cassettes/Actions/can_validate_beneficiaries.yml +38 -0
- data/spec/support/vcr_cassettes/Error/contains_full_details_for_api_error.yml +35 -0
- data/spec/support/vcr_cassettes/Error/is_raised_on_an_internal_server_error.yml +0 -34
- data/spec/support/vcr_cassettes/Rates/can_find.yml +3 -3
- data/spec/support/vcr_cassettes/Rates/can_provided_detailed_rate.yml +3 -3
- data/spec/support/vcr_cassettes/Reference/can_retrieve_beneficiary_required_details.yml +3 -3
- data/spec/support/vcr_cassettes/Reference/can_retrieve_conversion_dates.yml +3 -3
- data/spec/support/vcr_cassettes/Reference/can_retrieve_settlement_accounts.yml +3 -3
- data/spec/support/vcr_cassettes/Settlements/can_add_conversion.yml +102 -0
- data/spec/support/vcr_cassettes/Settlements/can_release.yml +69 -0
- data/spec/support/vcr_cassettes/Settlements/can_remove_conversion.yml +69 -0
- data/spec/support/vcr_cassettes/Settlements/can_unrelease.yml +69 -0
- metadata +26 -5
- data/Gemfile.lock +0 -99
- data/lib/currency_cloud/errors/config_error.rb +0 -5
@@ -11,13 +11,19 @@ module CurrencyCloud
|
|
11
11
|
def self.actions(*actions)
|
12
12
|
@actions ||= actions
|
13
13
|
@actions.each do |action|
|
14
|
-
self.class_eval do
|
14
|
+
self.class_eval do
|
15
15
|
action_module = CurrencyCloud::Actions.const_get(action.to_s.capitalize)
|
16
16
|
self.extend(action_module)
|
17
17
|
end
|
18
|
+
|
19
|
+
|
20
|
+
self.send(:include, CurrencyCloud::Actions::Save) if action == :update
|
21
|
+
self.send(:include, CurrencyCloud::Actions::InstanceDelete) if action == :delete
|
18
22
|
end
|
19
23
|
end
|
20
24
|
|
25
|
+
attr_reader :changed_attributes
|
26
|
+
|
21
27
|
def initialize(object)
|
22
28
|
@object = object
|
23
29
|
@changed_attributes = Set.new
|
@@ -5,26 +5,47 @@ module CurrencyCloud
|
|
5
5
|
resource :settlements
|
6
6
|
|
7
7
|
actions :create, :retrieve, :find, :delete
|
8
|
-
|
8
|
+
|
9
9
|
def add_conversion(conversion_id)
|
10
|
-
|
11
|
-
new(request.post("#{self.resource}/#{self.id}/add_conversion", conversion_id: conversion_id))
|
10
|
+
update_attributes(Settlement.add_conversion(id, conversion_id))
|
12
11
|
end
|
13
12
|
|
14
13
|
def remove_conversion(conversion_id)
|
15
|
-
|
16
|
-
new(request.post("#{self.resource}/#{self.id}/remove_conversion", conversion_id: conversion_id))
|
14
|
+
update_attributes(Settlement.remove_conversion(id, conversion_id))
|
17
15
|
end
|
18
16
|
|
19
17
|
def release
|
20
|
-
|
21
|
-
new(request.post("#{self.resource}/#{self.id}/release"))
|
18
|
+
update_attributes(Settlement.release(id))
|
22
19
|
end
|
23
20
|
|
24
21
|
def unrelease
|
25
|
-
|
26
|
-
|
22
|
+
update_attributes(Settlement.unrelease(id))
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.add_conversion(settlement_id, conversion_id)
|
26
|
+
post("#{settlement_id}/add_conversion", conversion_id: conversion_id)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.remove_conversion(settlement_id, conversion_id)
|
30
|
+
post("#{settlement_id}/remove_conversion", conversion_id: conversion_id)
|
27
31
|
end
|
28
32
|
|
33
|
+
def self.release(settlement_id)
|
34
|
+
post("#{settlement_id}/release")
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.unrelease(settlement_id)
|
38
|
+
post("#{settlement_id}/unrelease")
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
def update_attributes(settlement)
|
43
|
+
self.conversion_ids = settlement.conversion_ids
|
44
|
+
self.status = settlement.status
|
45
|
+
self.entries = settlement.entries
|
46
|
+
self.updated_at = settlement.updated_at
|
47
|
+
self.released_at = settlement.released_at
|
48
|
+
self
|
49
|
+
end
|
29
50
|
end
|
30
51
|
end
|
@@ -2,17 +2,16 @@ module CurrencyCloud
|
|
2
2
|
|
3
3
|
class ResponseHandler
|
4
4
|
|
5
|
-
attr_reader :response
|
5
|
+
attr_reader :verb, :route, :params, :response
|
6
6
|
|
7
|
-
def
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
def initialize(response)
|
7
|
+
def initialize(verb, route, params, response)
|
8
|
+
@verb = verb
|
9
|
+
@route = route
|
10
|
+
@params = params
|
12
11
|
@response = response
|
13
12
|
end
|
14
13
|
|
15
|
-
def
|
14
|
+
def process
|
16
15
|
if success?
|
17
16
|
return parsed_response
|
18
17
|
else
|
@@ -28,15 +27,15 @@ module CurrencyCloud
|
|
28
27
|
|
29
28
|
def handle_failure
|
30
29
|
error_class = case response.code
|
31
|
-
when 400 then
|
32
|
-
when 401 then
|
33
|
-
when 403 then
|
34
|
-
when 404 then
|
35
|
-
when 429 then
|
36
|
-
when 500 then
|
37
|
-
else CurrencyCloud::UnexpectedError
|
30
|
+
when 400 then BadRequestError
|
31
|
+
when 401 then AuthenticationError
|
32
|
+
when 403 then ForbiddenError
|
33
|
+
when 404 then NotFoundError
|
34
|
+
when 429 then TooManyRequestsError
|
35
|
+
when 500 then InternalApplicationError
|
38
36
|
end
|
39
|
-
raise error_class.new(response)
|
37
|
+
raise error_class.new(verb, route, params, response) if error_class
|
38
|
+
raise UnexpectedError.new(verb, route, params, response)
|
40
39
|
end
|
41
40
|
|
42
41
|
def parsed_response
|
@@ -7,11 +7,11 @@ module CurrencyCloud
|
|
7
7
|
:uat => 'https://api-uat1.ccycloud.com'}
|
8
8
|
|
9
9
|
attr_reader :environment, :login_id, :api_key
|
10
|
-
attr_accessor :token
|
10
|
+
attr_accessor :token, :on_behalf_of
|
11
11
|
|
12
12
|
def self.validate_environment(environment)
|
13
13
|
unless Environments.keys.include?(environment)
|
14
|
-
raise CurrencyCloud::
|
14
|
+
raise CurrencyCloud::GeneralError, "'#{environment}' is not a valid environment, must be one of: #{Environments.keys.join(", ")}"
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
@@ -51,8 +51,8 @@ module CurrencyCloud
|
|
51
51
|
private
|
52
52
|
def validate
|
53
53
|
self.class.validate_environment(environment)
|
54
|
-
raise CurrencyCloud::
|
55
|
-
raise CurrencyCloud::
|
54
|
+
raise CurrencyCloud::GeneralError, "login_id must be set using CurrencyCloud.login_id=" unless login_id
|
55
|
+
raise CurrencyCloud::GeneralError, "api_key must be set using CurrencyCloud.api_key=" unless api_key
|
56
56
|
end
|
57
57
|
|
58
58
|
def request
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'RequestHandler' do
|
4
|
+
let(:session) { CurrencyCloud::Session.new(:demonstration, nil, nil, '4df5b3e5882a412f148dcd08fa4e5b73')}
|
5
|
+
let(:response) { double('Response', code: 200, body: '{}') }
|
6
|
+
|
7
|
+
subject { CurrencyCloud::RequestHandler.new(session) }
|
8
|
+
|
9
|
+
describe 'with on_behalf_of parameter' do
|
10
|
+
it "adds it to parameters in HTTP call" do
|
11
|
+
session.on_behalf_of = "d1f7f5c2-4187-41da-88fc-b3ae40fa958f"
|
12
|
+
|
13
|
+
allow(HTTParty).to receive(:post) do |_, params|
|
14
|
+
expect(params).to include(:body)
|
15
|
+
expect(params[:body]).to include(on_behalf_of: "d1f7f5c2-4187-41da-88fc-b3ae40fa958f")
|
16
|
+
end.and_return(response)
|
17
|
+
|
18
|
+
subject.post('accounts/create', account_name: "Test Account")
|
19
|
+
end
|
20
|
+
|
21
|
+
it "ignores it if it's not a uuid" do
|
22
|
+
session.on_behalf_of = "nonsense variable"
|
23
|
+
|
24
|
+
allow(HTTParty).to receive(:post) do |_, params|
|
25
|
+
expect(params).to include(:body)
|
26
|
+
expect(params[:body]).to eq(account_name: "Test Account")
|
27
|
+
end.and_return(response)
|
28
|
+
|
29
|
+
subject.post('accounts/create', account_name: "Test Account")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Resource' do
|
4
|
+
before(:all) do
|
5
|
+
class Person < CurrencyCloud::Resource
|
6
|
+
resource :people
|
7
|
+
actions :update, :delete
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#save" do
|
12
|
+
it "only updates changed records" do
|
13
|
+
person = Person.new(id: 1, name: 'Richard', surname: 'Nienaber')
|
14
|
+
allow(person).to receive(:post).with(1, name: 'John')
|
15
|
+
person.name = 'John'
|
16
|
+
|
17
|
+
expect(person.save).to eq(person)
|
18
|
+
expect(person.changed_attributes).to eq(Set.new)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "does nothing if nothing has changed" do
|
22
|
+
person = Person.new(id: 1, name: 'Richard', surname: 'Nienaber')
|
23
|
+
|
24
|
+
expect(person.save).to eq(person)
|
25
|
+
expect(person.changed_attributes).to eq(Set.new)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#delete" do
|
30
|
+
it 'removes resource' do
|
31
|
+
person = Person.new(id: 1, name: 'Richard', surname: 'Nienaber')
|
32
|
+
allow(Person).to receive(:post).with('1/delete')
|
33
|
+
|
34
|
+
expect(person.delete).to eq(person)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/spec/currency_cloud_spec.rb
CHANGED
@@ -2,7 +2,7 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe CurrencyCloud do
|
4
4
|
|
5
|
-
before
|
5
|
+
before do
|
6
6
|
CurrencyCloud.environment = nil
|
7
7
|
CurrencyCloud.login_id = nil
|
8
8
|
CurrencyCloud.api_key = nil
|
@@ -53,26 +53,70 @@ describe CurrencyCloud do
|
|
53
53
|
it "raises an error if the environment is not set" do
|
54
54
|
CurrencyCloud.environment = nil
|
55
55
|
expect { CurrencyCloud.session }
|
56
|
-
.to raise_error(CurrencyCloud::
|
56
|
+
.to raise_error(CurrencyCloud::GeneralError, "'' is not a valid environment, must be one of: production, demonstration, uat")
|
57
57
|
end
|
58
58
|
|
59
59
|
it "raises an error if the environment is invalid" do
|
60
60
|
CurrencyCloud.environment = :invalid
|
61
61
|
expect { CurrencyCloud.session }
|
62
|
-
.to raise_error(CurrencyCloud::
|
62
|
+
.to raise_error(CurrencyCloud::GeneralError, "'invalid' is not a valid environment, must be one of: production, demonstration, uat")
|
63
63
|
end
|
64
64
|
|
65
65
|
it "raises an error if the login_id is not set" do
|
66
66
|
CurrencyCloud.environment = :demonstration
|
67
67
|
expect { CurrencyCloud.session }
|
68
|
-
.to raise_error(CurrencyCloud::
|
68
|
+
.to raise_error(CurrencyCloud::GeneralError, "login_id must be set using CurrencyCloud.login_id=")
|
69
69
|
end
|
70
70
|
|
71
71
|
it "raises an error if the api_key is not set" do
|
72
72
|
CurrencyCloud.environment = :demonstration
|
73
73
|
CurrencyCloud.login_id = 'test@example.com'
|
74
74
|
expect { CurrencyCloud.session }
|
75
|
-
.to raise_error(CurrencyCloud::
|
75
|
+
.to raise_error(CurrencyCloud::GeneralError, "api_key must be set using CurrencyCloud.api_key=")
|
76
76
|
end
|
77
77
|
end
|
78
|
+
|
79
|
+
describe "#on_behalf_of" do
|
80
|
+
before do
|
81
|
+
CurrencyCloud.environment = :demonstration
|
82
|
+
CurrencyCloud.token = '4df5b3e5882a412f148dcd08fa4e5b73'
|
83
|
+
CurrencyCloud.session.on_behalf_of = nil
|
84
|
+
end
|
85
|
+
|
86
|
+
it "sets the value on the session, and removes it when done" do
|
87
|
+
CurrencyCloud.on_behalf_of('c6ece846-6df1-461d-acaa-b42a6aa74045') do
|
88
|
+
expect(CurrencyCloud.session.on_behalf_of).to eq('c6ece846-6df1-461d-acaa-b42a6aa74045')
|
89
|
+
end
|
90
|
+
expect(CurrencyCloud.session.on_behalf_of).to be_nil
|
91
|
+
end
|
92
|
+
|
93
|
+
it "still removes the value from the session on error" do
|
94
|
+
expect do
|
95
|
+
CurrencyCloud.on_behalf_of('c6ece846-6df1-461d-acaa-b42a6aa74045') do
|
96
|
+
expect(CurrencyCloud.session.on_behalf_of).to eq('c6ece846-6df1-461d-acaa-b42a6aa74045')
|
97
|
+
raise 'Completed Expected error'
|
98
|
+
end
|
99
|
+
end.to raise_error('Completed Expected error')
|
100
|
+
|
101
|
+
expect(CurrencyCloud.session.on_behalf_of).to be_nil
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'prevents reentrant usage' do
|
105
|
+
expect do
|
106
|
+
CurrencyCloud.on_behalf_of('c6ece846-6df1-461d-acaa-b42a6aa74045') do
|
107
|
+
CurrencyCloud.on_behalf_of('f57b2d33-652c-4589-a8ff-7762add2706d') do
|
108
|
+
raise "Should raise exception"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end.to raise_error(CurrencyCloud::GeneralError, "#on_behalf_of has already been set")
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'prevents reentrant usage' do
|
115
|
+
expect do
|
116
|
+
CurrencyCloud.on_behalf_of('Richard Nienaber') do
|
117
|
+
raise "Should raise exception"
|
118
|
+
end
|
119
|
+
end.to raise_error(CurrencyCloud::GeneralError, "contact id for on behalf of is not a UUID")
|
120
|
+
end
|
121
|
+
end
|
78
122
|
end
|
@@ -98,4 +98,32 @@ describe 'Actions', :vcr => true do
|
|
98
98
|
expect(account.created_at).to eq('2015-04-24T15:57:55+00:00')
|
99
99
|
expect(account.updated_at).to eq('2015-04-24T15:57:55+00:00')
|
100
100
|
end
|
101
|
+
|
102
|
+
it "can #validate beneficiaries" do
|
103
|
+
params = {
|
104
|
+
:bank_country => 'GB',
|
105
|
+
:currency => 'GBP',
|
106
|
+
:account_number => '12345678',
|
107
|
+
:routing_code_type_1 => 'sort_code',
|
108
|
+
:routing_code_value_1 => '123456',
|
109
|
+
:payment_types => ['regular']
|
110
|
+
}
|
111
|
+
|
112
|
+
beneficiary = CurrencyCloud::Beneficiary.validate(params)
|
113
|
+
expect(beneficiary).to be_a_kind_of(CurrencyCloud::Beneficiary)
|
114
|
+
|
115
|
+
expect(beneficiary.account_number).to include('12345678')
|
116
|
+
expect(beneficiary.payment_types).to include('regular')
|
117
|
+
end
|
118
|
+
|
119
|
+
it "can use #currency to retrieve balance" do
|
120
|
+
balance = CurrencyCloud::Balance.currency('GBP')
|
121
|
+
|
122
|
+
expect(balance).to be_a_kind_of(CurrencyCloud::Balance)
|
123
|
+
|
124
|
+
expect(balance.id).to eq("5a998e06-3eb7-46d6-ba58-f749864159ce")
|
125
|
+
expect(balance.amount).to eq('999866.78')
|
126
|
+
expect(balance.created_at).to eq('2014-12-04T09:50:35+00:00')
|
127
|
+
expect(balance.updated_at).to eq('2015-03-23T14:33:37+00:00')
|
128
|
+
end
|
101
129
|
end
|
@@ -10,6 +10,40 @@ describe 'Error', :vcr => true do
|
|
10
10
|
CurrencyCloud.token = nil
|
11
11
|
end
|
12
12
|
|
13
|
+
it 'contains full details for api error' do
|
14
|
+
CurrencyCloud.login_id = 'non-existent-login-id'
|
15
|
+
CurrencyCloud.api_key = 'ef0fd50fca1fb14c1fab3a8436b9ecb57528f0'
|
16
|
+
|
17
|
+
error = nil
|
18
|
+
begin
|
19
|
+
CurrencyCloud.session
|
20
|
+
raise 'Should have failed'
|
21
|
+
rescue CurrencyCloud::BadRequestError => error
|
22
|
+
end
|
23
|
+
|
24
|
+
expected_error = %Q{CurrencyCloud::BadRequestError
|
25
|
+
---
|
26
|
+
platform: #{error.platform}
|
27
|
+
request:
|
28
|
+
parameters:
|
29
|
+
login_id: non-existent-login-id
|
30
|
+
api_key: ef0fd50fca1fb14c1fab3a8436b9ecb57528f0
|
31
|
+
verb: post
|
32
|
+
url: https://devapi.thecurrencycloud.com/v2/authenticate/api
|
33
|
+
response:
|
34
|
+
status_code: 400
|
35
|
+
date: Wed, 29 Apr 2015 22:46:53 GMT
|
36
|
+
request_id: 2775253392756800903
|
37
|
+
errors:
|
38
|
+
- field: api_key
|
39
|
+
code: api_key_length_is_invalid
|
40
|
+
message: api_key should be 64 character(s) long
|
41
|
+
params:
|
42
|
+
length: 64
|
43
|
+
}
|
44
|
+
expect(error.to_s).to eq(expected_error)
|
45
|
+
end
|
46
|
+
|
13
47
|
it 'is raised on a bad request' do
|
14
48
|
CurrencyCloud.login_id = 'non-existent-login-id'
|
15
49
|
CurrencyCloud.api_key = 'ef0fd50fca1fb14c1fab3a8436b9ecb57528f0'
|
@@ -66,6 +100,19 @@ describe 'Error', :vcr => true do
|
|
66
100
|
rescue CurrencyCloud::UnexpectedError => error
|
67
101
|
end
|
68
102
|
|
103
|
+
expected_error = %Q{CurrencyCloud::UnexpectedError
|
104
|
+
---
|
105
|
+
platform: #{error.platform}
|
106
|
+
request:
|
107
|
+
parameters:
|
108
|
+
login_id: rjnienaber@gmail.com
|
109
|
+
api_key: ef0fd50fca1fb14c1fab3a8436b9ecb65f02f129fd87eafa45ded8ae257528f0
|
110
|
+
verb: post
|
111
|
+
url: https://devapi.thecurrencycloud.com/v2/authenticate/api
|
112
|
+
inner_error: Timeout::Error
|
113
|
+
}
|
114
|
+
|
115
|
+
expect(error.to_s).to eq(expected_error)
|
69
116
|
expect(error.inner_error).to_not be_nil
|
70
117
|
expect(error.inner_error.class).to eq(Timeout::Error)
|
71
118
|
end
|
@@ -4,7 +4,7 @@ describe 'Rates', :vcr => true do
|
|
4
4
|
before do
|
5
5
|
CurrencyCloud.reset_session
|
6
6
|
CurrencyCloud.environment = :demonstration
|
7
|
-
CurrencyCloud.token = '
|
7
|
+
CurrencyCloud.token = 'bbdd421bdda373ea69670c9101fa9197'
|
8
8
|
end
|
9
9
|
|
10
10
|
it 'can #find' do
|