currency_cloud 0.5 → 0.7
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 +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
|