gocardless_pro 2.17.1 → 2.18.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cb41d5906c1d6d6a9fc78abc852058cf63715020e3c957c7a0a8bcc8e907d74e
4
- data.tar.gz: c85a921b9ea881ed5acc7d56c20b4f75f5c51e1c5e305d4de8c7d0079798adbf
3
+ metadata.gz: 250fed25fc74cb084ad988286e20f8dd2c679fcb62e0de5a1fc3bfca71b67c43
4
+ data.tar.gz: af02087f4d85aafa9337d51219c467bc195c6c9eff6d03b2f9c5dbf209956680
5
5
  SHA512:
6
- metadata.gz: 54114ab5751f18ea4c0b010ca600db89523de93353f309cd0e247dbc13a7339f1cf14d7869f44db7d7b0a7571233a54bd9bc0130c9c4eb796bf186bda5e659eb
7
- data.tar.gz: a2c5a5cdc5321d2e8a00f82adaba6b56540f3aa86d55cf950862f92fbc1cd971e5bad955b4701d69c4babb2fa5ac83a01a53f5da3427117ec7c11d652c47730e
6
+ metadata.gz: a3bd1149c2936dfd1ba6d8b60e7183c279d105046c4c02ab497e2d11da3c3f93c363a56ce5a2c1133138ad9acd421bbfb4c479c1da3970afb4c6b650a0197965
7
+ data.tar.gz: '07951005f59ae4328b34342bb24c9b06bfb9f0221a87630751d21b9755354fb3daaf7f0b34bb51d98811f2e1199479be08745afdb66c888953bfad50fc8bc099'
Binary file
@@ -47,6 +47,9 @@ require_relative 'gocardless_pro/services/creditors_service'
47
47
  require_relative 'gocardless_pro/resources/creditor_bank_account'
48
48
  require_relative 'gocardless_pro/services/creditor_bank_accounts_service'
49
49
 
50
+ require_relative 'gocardless_pro/resources/currency_exchange_rate'
51
+ require_relative 'gocardless_pro/services/currency_exchange_rates_service'
52
+
50
53
  require_relative 'gocardless_pro/resources/customer'
51
54
  require_relative 'gocardless_pro/services/customers_service'
52
55
 
@@ -18,6 +18,11 @@ module GoCardlessPro
18
18
  @creditor_bank_accounts ||= Services::CreditorBankAccountsService.new(@api_service)
19
19
  end
20
20
 
21
+ # Access to the service for currency_exchange_rate to make API calls
22
+ def currency_exchange_rates
23
+ @currency_exchange_rates ||= Services::CurrencyExchangeRatesService.new(@api_service)
24
+ end
25
+
21
26
  # Access to the service for customer to make API calls
22
27
  def customers
23
28
  @customers ||= Services::CustomersService.new(@api_service)
@@ -143,7 +148,7 @@ module GoCardlessPro
143
148
  'User-Agent' => user_agent.to_s,
144
149
  'Content-Type' => 'application/json',
145
150
  'GoCardless-Client-Library' => 'gocardless-pro-ruby',
146
- 'GoCardless-Client-Version' => '2.17.1',
151
+ 'GoCardless-Client-Version' => '2.18.0',
147
152
  },
148
153
  }
149
154
  end
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+
3
+ #
4
+ # This client is automatically generated from a template and JSON schema definition.
5
+ # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing.
6
+ #
7
+
8
+ require 'uri'
9
+
10
+ module GoCardlessPro
11
+ # A module containing classes for each of the resources in the GC Api
12
+ module Resources
13
+ # Represents an instance of a currency_exchange_rate resource returned from the API
14
+
15
+ # Currency exchange rates from our foreign exchange provider.
16
+ class CurrencyExchangeRate
17
+ attr_reader :rate
18
+ attr_reader :source
19
+ attr_reader :target
20
+ attr_reader :time
21
+
22
+ # Initialize a currency_exchange_rate resource instance
23
+ # @param object [Hash] an object returned from the API
24
+ def initialize(object, response = nil)
25
+ @object = object
26
+
27
+ @rate = object['rate']
28
+ @source = object['source']
29
+ @target = object['target']
30
+ @time = object['time']
31
+ @response = response
32
+ end
33
+
34
+ def api_response
35
+ ApiResponse.new(@response)
36
+ end
37
+
38
+ # Provides the currency_exchange_rate resource as a hash of all its readable attributes
39
+ def to_h
40
+ @object
41
+ end
42
+ end
43
+ end
44
+ end
@@ -69,6 +69,7 @@ module GoCardlessPro
69
69
  class Subscription
70
70
  attr_reader :amount
71
71
  attr_reader :app_fee
72
+ attr_reader :count
72
73
  attr_reader :created_at
73
74
  attr_reader :currency
74
75
  attr_reader :day_of_month
@@ -92,6 +93,7 @@ module GoCardlessPro
92
93
 
93
94
  @amount = object['amount']
94
95
  @app_fee = object['app_fee']
96
+ @count = object['count']
95
97
  @created_at = object['created_at']
96
98
  @currency = object['currency']
97
99
  @day_of_month = object['day_of_month']
@@ -0,0 +1,67 @@
1
+ require_relative './base_service'
2
+ require 'uri'
3
+
4
+ # encoding: utf-8
5
+ #
6
+ # This client is automatically generated from a template and JSON schema definition.
7
+ # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing.
8
+ #
9
+
10
+ module GoCardlessPro
11
+ module Services
12
+ # Service for making requests to the CurrencyExchangeRate endpoints
13
+ class CurrencyExchangeRatesService < BaseService
14
+ # Returns a [cursor-paginated](#api-usage-cursor-pagination) list of all
15
+ # exchange rates.
16
+ # Example URL: /currency_exchange_rates
17
+ # @param options [Hash] parameters as a hash, under a params key.
18
+ def list(options = {})
19
+ path = '/currency_exchange_rates'
20
+
21
+ options[:retry_failures] = true
22
+
23
+ response = make_request(:get, path, options)
24
+
25
+ ListResponse.new(
26
+ response: response,
27
+ unenveloped_body: unenvelope_body(response.body),
28
+ resource_class: Resources::CurrencyExchangeRate
29
+ )
30
+ end
31
+
32
+ # Get a lazily enumerated list of all the items returned. This is simmilar to the `list` method but will paginate for you automatically.
33
+ #
34
+ # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
35
+ # Otherwise they will be the body of the request.
36
+ def all(options = {})
37
+ Paginator.new(
38
+ service: self,
39
+ options: options
40
+ ).enumerator
41
+ end
42
+
43
+ private
44
+
45
+ # Unenvelope the response of the body using the service's `envelope_key`
46
+ #
47
+ # @param body [Hash]
48
+ def unenvelope_body(body)
49
+ body[envelope_key] || body['data']
50
+ end
51
+
52
+ # return the key which API responses will envelope data under
53
+ def envelope_key
54
+ 'currency_exchange_rates'
55
+ end
56
+
57
+ # take a URL with placeholder params and substitute them out for the actual value
58
+ # @param url [String] the URL with placeholders in
59
+ # @param param_map [Hash] a hash of placeholders and their actual values (which will be escaped)
60
+ def sub_url(url, param_map)
61
+ param_map.reduce(url) do |new_url, (param, value)|
62
+ new_url.gsub(":#{param}", URI.escape(value))
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -12,11 +12,66 @@ module GoCardlessPro
12
12
  # Service for making requests to the InstalmentSchedule endpoints
13
13
  class InstalmentSchedulesService < BaseService
14
14
  # Creates a new instalment schedule object, along with the associated payments.
15
+ # This
16
+ # API is recommended if you know the specific dates you wish to charge.
17
+ # Otherwise,
18
+ # please check out the [scheduling
19
+ # version](#instalment-schedules-create-with-schedule).
15
20
  #
16
- # The `instalments` property can either be an array of payment properties
17
- # (`amount`
18
- # and `charge_date`) or a schedule object with `interval`, `interval_unit` and
19
- # `amounts`.
21
+ # The `instalments` property is an array of payment properties (`amount` and
22
+ # `charge_date`).
23
+ #
24
+ # It can take quite a while to create the associated payments, so the API will
25
+ # return
26
+ # the status as `pending` initially. When processing has completed, a subsequent
27
+ # GET
28
+ # request for the instalment schedule will either have the status `success` and
29
+ # link
30
+ # to the created payments, or the status `error` and detailed information about
31
+ # the
32
+ # failures.
33
+ # Example URL: /instalment_schedules
34
+ # @param options [Hash] parameters as a hash, under a params key.
35
+ def create_with_dates(options = {})
36
+ path = '/instalment_schedules'
37
+
38
+ params = options.delete(:params) || {}
39
+ options[:params] = {}
40
+ options[:params][envelope_key] = params
41
+
42
+ options[:retry_failures] = true
43
+
44
+ begin
45
+ response = make_request(:post, path, options)
46
+
47
+ # Response doesn't raise any errors until #body is called
48
+ response.tap(&:body)
49
+ rescue InvalidStateError => e
50
+ if e.idempotent_creation_conflict?
51
+ case @api_service.on_idempotency_conflict
52
+ when :raise
53
+ raise IdempotencyConflict, e.error
54
+ when :fetch
55
+ return get(e.conflicting_resource_id)
56
+ else
57
+ raise ArgumentError, 'Unknown mode for :on_idempotency_conflict'
58
+ end
59
+ end
60
+
61
+ raise e
62
+ end
63
+
64
+ return if response.body.nil?
65
+
66
+ Resources::InstalmentSchedule.new(unenvelope_body(response.body), response)
67
+ end
68
+
69
+ # Creates a new instalment schedule object, along with the associated payments.
70
+ # This
71
+ # API is recommended if you wish to use the GoCardless scheduling logic. For
72
+ # finer
73
+ # control over the individual dates, please check out the [alternative
74
+ # version](#instalment-schedules-create-with-dates).
20
75
  #
21
76
  # It can take quite a while to create the associated payments, so the API will
22
77
  # return
@@ -27,7 +82,7 @@ module GoCardlessPro
27
82
  # failures.
28
83
  # Example URL: /instalment_schedules
29
84
  # @param options [Hash] parameters as a hash, under a params key.
30
- def create(options = {})
85
+ def create_with_schedule(options = {})
31
86
  path = '/instalment_schedules'
32
87
 
33
88
  params = options.delete(:params) || {}
@@ -4,5 +4,5 @@ end
4
4
 
5
5
  module GoCardlessPro
6
6
  # Current version of the GC gem
7
- VERSION = '2.17.1'.freeze
7
+ VERSION = '2.18.0'.freeze
8
8
  end
@@ -0,0 +1,103 @@
1
+ require 'spec_helper'
2
+
3
+ describe GoCardlessPro::Resources::CurrencyExchangeRate do
4
+ let(:client) do
5
+ GoCardlessPro::Client.new(
6
+ access_token: 'SECRET_TOKEN'
7
+ )
8
+ end
9
+
10
+ let(:response_headers) { { 'Content-Type' => 'application/json' } }
11
+
12
+ describe '#list' do
13
+ describe 'with no filters' do
14
+ subject(:get_list_response) { client.currency_exchange_rates.list }
15
+
16
+ before do
17
+ stub_request(:get, %r{.*api.gocardless.com/currency_exchange_rates}).to_return(
18
+ body: {
19
+ 'currency_exchange_rates' => [{
20
+
21
+ 'rate' => 'rate-input',
22
+ 'source' => 'source-input',
23
+ 'target' => 'target-input',
24
+ 'time' => 'time-input',
25
+ }],
26
+ meta: {
27
+ cursors: {
28
+ before: nil,
29
+ after: 'ABC123',
30
+ },
31
+ },
32
+ }.to_json,
33
+ headers: response_headers
34
+ )
35
+ end
36
+
37
+ it 'wraps each item in the resource class' do
38
+ expect(get_list_response.records.map(&:class).uniq.first).to eq(GoCardlessPro::Resources::CurrencyExchangeRate)
39
+
40
+ expect(get_list_response.records.first.rate).to eq('rate-input')
41
+
42
+ expect(get_list_response.records.first.source).to eq('source-input')
43
+
44
+ expect(get_list_response.records.first.target).to eq('target-input')
45
+
46
+ expect(get_list_response.records.first.time).to eq('time-input')
47
+ end
48
+
49
+ it 'exposes the cursors for before and after' do
50
+ expect(get_list_response.before).to eq(nil)
51
+ expect(get_list_response.after).to eq('ABC123')
52
+ end
53
+
54
+ specify { expect(get_list_response.api_response.headers).to eql('content-type' => 'application/json') }
55
+ end
56
+ end
57
+
58
+ describe '#all' do
59
+ let!(:first_response_stub) do
60
+ stub_request(:get, %r{.*api.gocardless.com/currency_exchange_rates$}).to_return(
61
+ body: {
62
+ 'currency_exchange_rates' => [{
63
+
64
+ 'rate' => 'rate-input',
65
+ 'source' => 'source-input',
66
+ 'target' => 'target-input',
67
+ 'time' => 'time-input',
68
+ }],
69
+ meta: {
70
+ cursors: { after: 'AB345' },
71
+ limit: 1,
72
+ },
73
+ }.to_json,
74
+ headers: response_headers
75
+ )
76
+ end
77
+
78
+ let!(:second_response_stub) do
79
+ stub_request(:get, %r{.*api.gocardless.com/currency_exchange_rates\?after=AB345}).to_return(
80
+ body: {
81
+ 'currency_exchange_rates' => [{
82
+
83
+ 'rate' => 'rate-input',
84
+ 'source' => 'source-input',
85
+ 'target' => 'target-input',
86
+ 'time' => 'time-input',
87
+ }],
88
+ meta: {
89
+ limit: 2,
90
+ cursors: {},
91
+ },
92
+ }.to_json,
93
+ headers: response_headers
94
+ )
95
+ end
96
+
97
+ it 'automatically makes the extra requests' do
98
+ expect(client.currency_exchange_rates.all.to_a.length).to eq(2)
99
+ expect(first_response_stub).to have_been_requested
100
+ expect(second_response_stub).to have_been_requested
101
+ end
102
+ end
103
+ end
@@ -10,7 +10,164 @@ describe GoCardlessPro::Resources::InstalmentSchedule do
10
10
  let(:response_headers) { { 'Content-Type' => 'application/json' } }
11
11
 
12
12
  describe '#create' do
13
- subject(:post_create_response) { client.instalment_schedules.create(params: new_resource) }
13
+ subject(:post_create_response) { client.instalment_schedules.create_with_dates(params: new_resource) }
14
+ context 'with a valid request' do
15
+ let(:new_resource) do
16
+ {
17
+
18
+ 'created_at' => 'created_at-input',
19
+ 'currency' => 'currency-input',
20
+ 'id' => 'id-input',
21
+ 'links' => 'links-input',
22
+ 'metadata' => 'metadata-input',
23
+ 'name' => 'name-input',
24
+ 'payment_errors' => 'payment_errors-input',
25
+ 'status' => 'status-input',
26
+ 'total_amount' => 'total_amount-input',
27
+ }
28
+ end
29
+
30
+ before do
31
+ stub_request(:post, %r{.*api.gocardless.com/instalment_schedules}).
32
+ with(
33
+ body: {
34
+ 'instalment_schedules' => {
35
+
36
+ 'created_at' => 'created_at-input',
37
+ 'currency' => 'currency-input',
38
+ 'id' => 'id-input',
39
+ 'links' => 'links-input',
40
+ 'metadata' => 'metadata-input',
41
+ 'name' => 'name-input',
42
+ 'payment_errors' => 'payment_errors-input',
43
+ 'status' => 'status-input',
44
+ 'total_amount' => 'total_amount-input',
45
+ },
46
+ }
47
+ ).
48
+ to_return(
49
+ body: {
50
+ 'instalment_schedules' =>
51
+
52
+ {
53
+
54
+ 'created_at' => 'created_at-input',
55
+ 'currency' => 'currency-input',
56
+ 'id' => 'id-input',
57
+ 'links' => 'links-input',
58
+ 'metadata' => 'metadata-input',
59
+ 'name' => 'name-input',
60
+ 'payment_errors' => 'payment_errors-input',
61
+ 'status' => 'status-input',
62
+ 'total_amount' => 'total_amount-input',
63
+ },
64
+
65
+ }.to_json,
66
+ headers: response_headers
67
+ )
68
+ end
69
+
70
+ it 'creates and returns the resource' do
71
+ expect(post_create_response).to be_a(GoCardlessPro::Resources::InstalmentSchedule)
72
+ end
73
+ end
74
+
75
+ context 'with a request that returns a validation error' do
76
+ let(:new_resource) { {} }
77
+
78
+ before do
79
+ stub_request(:post, %r{.*api.gocardless.com/instalment_schedules}).to_return(
80
+ body: {
81
+ error: {
82
+ type: 'validation_failed',
83
+ code: 422,
84
+ errors: [
85
+ { message: 'test error message', field: 'test_field' },
86
+ ],
87
+ },
88
+ }.to_json,
89
+ headers: response_headers,
90
+ status: 422
91
+ )
92
+ end
93
+
94
+ it 'throws the correct error' do
95
+ expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError)
96
+ end
97
+ end
98
+
99
+ context 'with a request that returns an idempotent creation conflict error' do
100
+ let(:id) { 'ID123' }
101
+
102
+ let(:new_resource) do
103
+ {
104
+
105
+ 'created_at' => 'created_at-input',
106
+ 'currency' => 'currency-input',
107
+ 'id' => 'id-input',
108
+ 'links' => 'links-input',
109
+ 'metadata' => 'metadata-input',
110
+ 'name' => 'name-input',
111
+ 'payment_errors' => 'payment_errors-input',
112
+ 'status' => 'status-input',
113
+ 'total_amount' => 'total_amount-input',
114
+ }
115
+ end
116
+
117
+ let!(:post_stub) do
118
+ stub_request(:post, %r{.*api.gocardless.com/instalment_schedules}).to_return(
119
+ body: {
120
+ error: {
121
+ type: 'invalid_state',
122
+ code: 409,
123
+ errors: [
124
+ {
125
+ message: 'A resource has already been created with this idempotency key',
126
+ reason: 'idempotent_creation_conflict',
127
+ links: {
128
+ conflicting_resource_id: id,
129
+ },
130
+ },
131
+ ],
132
+ },
133
+ }.to_json,
134
+ headers: response_headers,
135
+ status: 409
136
+ )
137
+ end
138
+
139
+ let!(:get_stub) do
140
+ stub_url = "/instalment_schedules/#{id}"
141
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).
142
+ to_return(
143
+ body: {
144
+ 'instalment_schedules' => {
145
+
146
+ 'created_at' => 'created_at-input',
147
+ 'currency' => 'currency-input',
148
+ 'id' => 'id-input',
149
+ 'links' => 'links-input',
150
+ 'metadata' => 'metadata-input',
151
+ 'name' => 'name-input',
152
+ 'payment_errors' => 'payment_errors-input',
153
+ 'status' => 'status-input',
154
+ 'total_amount' => 'total_amount-input',
155
+ },
156
+ }.to_json,
157
+ headers: response_headers
158
+ )
159
+ end
160
+
161
+ it 'fetches the already-created resource' do
162
+ post_create_response
163
+ expect(post_stub).to have_been_requested
164
+ expect(get_stub).to have_been_requested
165
+ end
166
+ end
167
+ end
168
+
169
+ describe '#create' do
170
+ subject(:post_create_response) { client.instalment_schedules.create_with_schedule(params: new_resource) }
14
171
  context 'with a valid request' do
15
172
  let(:new_resource) do
16
173
  {
@@ -17,6 +17,7 @@ describe GoCardlessPro::Resources::Subscription do
17
17
 
18
18
  'amount' => 'amount-input',
19
19
  'app_fee' => 'app_fee-input',
20
+ 'count' => 'count-input',
20
21
  'created_at' => 'created_at-input',
21
22
  'currency' => 'currency-input',
22
23
  'day_of_month' => 'day_of_month-input',
@@ -44,6 +45,7 @@ describe GoCardlessPro::Resources::Subscription do
44
45
 
45
46
  'amount' => 'amount-input',
46
47
  'app_fee' => 'app_fee-input',
48
+ 'count' => 'count-input',
47
49
  'created_at' => 'created_at-input',
48
50
  'currency' => 'currency-input',
49
51
  'day_of_month' => 'day_of_month-input',
@@ -71,6 +73,7 @@ describe GoCardlessPro::Resources::Subscription do
71
73
 
72
74
  'amount' => 'amount-input',
73
75
  'app_fee' => 'app_fee-input',
76
+ 'count' => 'count-input',
74
77
  'created_at' => 'created_at-input',
75
78
  'currency' => 'currency-input',
76
79
  'day_of_month' => 'day_of_month-input',
@@ -131,6 +134,7 @@ describe GoCardlessPro::Resources::Subscription do
131
134
 
132
135
  'amount' => 'amount-input',
133
136
  'app_fee' => 'app_fee-input',
137
+ 'count' => 'count-input',
134
138
  'created_at' => 'created_at-input',
135
139
  'currency' => 'currency-input',
136
140
  'day_of_month' => 'day_of_month-input',
@@ -181,6 +185,7 @@ describe GoCardlessPro::Resources::Subscription do
181
185
 
182
186
  'amount' => 'amount-input',
183
187
  'app_fee' => 'app_fee-input',
188
+ 'count' => 'count-input',
184
189
  'created_at' => 'created_at-input',
185
190
  'currency' => 'currency-input',
186
191
  'day_of_month' => 'day_of_month-input',
@@ -222,6 +227,7 @@ describe GoCardlessPro::Resources::Subscription do
222
227
 
223
228
  'amount' => 'amount-input',
224
229
  'app_fee' => 'app_fee-input',
230
+ 'count' => 'count-input',
225
231
  'created_at' => 'created_at-input',
226
232
  'currency' => 'currency-input',
227
233
  'day_of_month' => 'day_of_month-input',
@@ -257,6 +263,8 @@ describe GoCardlessPro::Resources::Subscription do
257
263
 
258
264
  expect(get_list_response.records.first.app_fee).to eq('app_fee-input')
259
265
 
266
+ expect(get_list_response.records.first.count).to eq('count-input')
267
+
260
268
  expect(get_list_response.records.first.created_at).to eq('created_at-input')
261
269
 
262
270
  expect(get_list_response.records.first.currency).to eq('currency-input')
@@ -305,6 +313,7 @@ describe GoCardlessPro::Resources::Subscription do
305
313
 
306
314
  'amount' => 'amount-input',
307
315
  'app_fee' => 'app_fee-input',
316
+ 'count' => 'count-input',
308
317
  'created_at' => 'created_at-input',
309
318
  'currency' => 'currency-input',
310
319
  'day_of_month' => 'day_of_month-input',
@@ -338,6 +347,7 @@ describe GoCardlessPro::Resources::Subscription do
338
347
 
339
348
  'amount' => 'amount-input',
340
349
  'app_fee' => 'app_fee-input',
350
+ 'count' => 'count-input',
341
351
  'created_at' => 'created_at-input',
342
352
  'currency' => 'currency-input',
343
353
  'day_of_month' => 'day_of_month-input',
@@ -387,6 +397,7 @@ describe GoCardlessPro::Resources::Subscription do
387
397
 
388
398
  'amount' => 'amount-input',
389
399
  'app_fee' => 'app_fee-input',
400
+ 'count' => 'count-input',
390
401
  'created_at' => 'created_at-input',
391
402
  'currency' => 'currency-input',
392
403
  'day_of_month' => 'day_of_month-input',
@@ -430,6 +441,7 @@ describe GoCardlessPro::Resources::Subscription do
430
441
 
431
442
  'amount' => 'amount-input',
432
443
  'app_fee' => 'app_fee-input',
444
+ 'count' => 'count-input',
433
445
  'created_at' => 'created_at-input',
434
446
  'currency' => 'currency-input',
435
447
  'day_of_month' => 'day_of_month-input',
@@ -495,6 +507,7 @@ describe GoCardlessPro::Resources::Subscription do
495
507
 
496
508
  'amount' => 'amount-input',
497
509
  'app_fee' => 'app_fee-input',
510
+ 'count' => 'count-input',
498
511
  'created_at' => 'created_at-input',
499
512
  'currency' => 'currency-input',
500
513
  'day_of_month' => 'day_of_month-input',
@@ -538,6 +551,7 @@ describe GoCardlessPro::Resources::Subscription do
538
551
 
539
552
  'amount' => 'amount-input',
540
553
  'app_fee' => 'app_fee-input',
554
+ 'count' => 'count-input',
541
555
  'created_at' => 'created_at-input',
542
556
  'currency' => 'currency-input',
543
557
  'day_of_month' => 'day_of_month-input',
@@ -586,6 +600,7 @@ describe GoCardlessPro::Resources::Subscription do
586
600
 
587
601
  'amount' => 'amount-input',
588
602
  'app_fee' => 'app_fee-input',
603
+ 'count' => 'count-input',
589
604
  'created_at' => 'created_at-input',
590
605
  'currency' => 'currency-input',
591
606
  'day_of_month' => 'day_of_month-input',
@@ -0,0 +1,223 @@
1
+ require 'spec_helper'
2
+
3
+ describe GoCardlessPro::Services::CurrencyExchangeRatesService do
4
+ let(:client) do
5
+ GoCardlessPro::Client.new(
6
+ access_token: 'SECRET_TOKEN'
7
+ )
8
+ end
9
+
10
+ let(:response_headers) { { 'Content-Type' => 'application/json' } }
11
+
12
+ describe '#list' do
13
+ describe 'with no filters' do
14
+ subject(:get_list_response) { client.currency_exchange_rates.list }
15
+
16
+ let(:body) do
17
+ {
18
+ 'currency_exchange_rates' => [{
19
+
20
+ 'rate' => 'rate-input',
21
+ 'source' => 'source-input',
22
+ 'target' => 'target-input',
23
+ 'time' => 'time-input',
24
+ }],
25
+ meta: {
26
+ cursors: {
27
+ before: nil,
28
+ after: 'ABC123',
29
+ },
30
+ },
31
+ }.to_json
32
+ end
33
+
34
+ before do
35
+ stub_request(:get, %r{.*api.gocardless.com/currency_exchange_rates}).to_return(
36
+ body: body,
37
+ headers: response_headers
38
+ )
39
+ end
40
+
41
+ it 'wraps each item in the resource class' do
42
+ expect(get_list_response.records.map(&:class).uniq.first).to eq(GoCardlessPro::Resources::CurrencyExchangeRate)
43
+
44
+ expect(get_list_response.records.first.rate).to eq('rate-input')
45
+
46
+ expect(get_list_response.records.first.source).to eq('source-input')
47
+
48
+ expect(get_list_response.records.first.target).to eq('target-input')
49
+
50
+ expect(get_list_response.records.first.time).to eq('time-input')
51
+ end
52
+
53
+ it 'exposes the cursors for before and after' do
54
+ expect(get_list_response.before).to eq(nil)
55
+ expect(get_list_response.after).to eq('ABC123')
56
+ end
57
+
58
+ specify { expect(get_list_response.api_response.headers).to eql('content-type' => 'application/json') }
59
+
60
+ describe 'retry behaviour' do
61
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
62
+
63
+ it 'retries timeouts' do
64
+ stub = stub_request(:get, %r{.*api.gocardless.com/currency_exchange_rates}).
65
+ to_timeout.then.to_return(status: 200, headers: response_headers, body: body)
66
+
67
+ get_list_response
68
+ expect(stub).to have_been_requested.twice
69
+ end
70
+
71
+ it 'retries 5XX errors' do
72
+ stub = stub_request(:get, %r{.*api.gocardless.com/currency_exchange_rates}).
73
+ to_return(status: 502,
74
+ headers: { 'Content-Type' => 'text/html' },
75
+ body: '<html><body>Response from Cloudflare</body></html>').
76
+ then.to_return(status: 200, headers: response_headers, body: body)
77
+
78
+ get_list_response
79
+ expect(stub).to have_been_requested.twice
80
+ end
81
+ end
82
+ end
83
+ end
84
+
85
+ describe '#all' do
86
+ let!(:first_response_stub) do
87
+ stub_request(:get, %r{.*api.gocardless.com/currency_exchange_rates$}).to_return(
88
+ body: {
89
+ 'currency_exchange_rates' => [{
90
+
91
+ 'rate' => 'rate-input',
92
+ 'source' => 'source-input',
93
+ 'target' => 'target-input',
94
+ 'time' => 'time-input',
95
+ }],
96
+ meta: {
97
+ cursors: { after: 'AB345' },
98
+ limit: 1,
99
+ },
100
+ }.to_json,
101
+ headers: response_headers
102
+ )
103
+ end
104
+
105
+ let!(:second_response_stub) do
106
+ stub_request(:get, %r{.*api.gocardless.com/currency_exchange_rates\?after=AB345}).to_return(
107
+ body: {
108
+ 'currency_exchange_rates' => [{
109
+
110
+ 'rate' => 'rate-input',
111
+ 'source' => 'source-input',
112
+ 'target' => 'target-input',
113
+ 'time' => 'time-input',
114
+ }],
115
+ meta: {
116
+ limit: 2,
117
+ cursors: {},
118
+ },
119
+ }.to_json,
120
+ headers: response_headers
121
+ )
122
+ end
123
+
124
+ it 'automatically makes the extra requests' do
125
+ expect(client.currency_exchange_rates.all.to_a.length).to eq(2)
126
+ expect(first_response_stub).to have_been_requested
127
+ expect(second_response_stub).to have_been_requested
128
+ end
129
+
130
+ describe 'retry behaviour' do
131
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
132
+
133
+ it 'retries timeouts' do
134
+ first_response_stub = stub_request(:get, %r{.*api.gocardless.com/currency_exchange_rates$}).to_return(
135
+ body: {
136
+ 'currency_exchange_rates' => [{
137
+
138
+ 'rate' => 'rate-input',
139
+ 'source' => 'source-input',
140
+ 'target' => 'target-input',
141
+ 'time' => 'time-input',
142
+ }],
143
+ meta: {
144
+ cursors: { after: 'AB345' },
145
+ limit: 1,
146
+ },
147
+ }.to_json,
148
+ headers: response_headers
149
+ )
150
+
151
+ second_response_stub = stub_request(:get, %r{.*api.gocardless.com/currency_exchange_rates\?after=AB345}).
152
+ to_timeout.then.
153
+ to_return(
154
+ body: {
155
+ 'currency_exchange_rates' => [{
156
+
157
+ 'rate' => 'rate-input',
158
+ 'source' => 'source-input',
159
+ 'target' => 'target-input',
160
+ 'time' => 'time-input',
161
+ }],
162
+ meta: {
163
+ limit: 2,
164
+ cursors: {},
165
+ },
166
+ }.to_json,
167
+ headers: response_headers
168
+ )
169
+
170
+ client.currency_exchange_rates.all.to_a
171
+
172
+ expect(first_response_stub).to have_been_requested
173
+ expect(second_response_stub).to have_been_requested.twice
174
+ end
175
+
176
+ it 'retries 5XX errors' do
177
+ first_response_stub = stub_request(:get, %r{.*api.gocardless.com/currency_exchange_rates$}).to_return(
178
+ body: {
179
+ 'currency_exchange_rates' => [{
180
+
181
+ 'rate' => 'rate-input',
182
+ 'source' => 'source-input',
183
+ 'target' => 'target-input',
184
+ 'time' => 'time-input',
185
+ }],
186
+ meta: {
187
+ cursors: { after: 'AB345' },
188
+ limit: 1,
189
+ },
190
+ }.to_json,
191
+ headers: response_headers
192
+ )
193
+
194
+ second_response_stub = stub_request(:get, %r{.*api.gocardless.com/currency_exchange_rates\?after=AB345}).
195
+ to_return(
196
+ status: 502,
197
+ body: '<html><body>Response from Cloudflare</body></html>',
198
+ headers: { 'Content-Type' => 'text/html' }
199
+ ).then.to_return(
200
+ body: {
201
+ 'currency_exchange_rates' => [{
202
+
203
+ 'rate' => 'rate-input',
204
+ 'source' => 'source-input',
205
+ 'target' => 'target-input',
206
+ 'time' => 'time-input',
207
+ }],
208
+ meta: {
209
+ limit: 2,
210
+ cursors: {},
211
+ },
212
+ }.to_json,
213
+ headers: response_headers
214
+ )
215
+
216
+ client.currency_exchange_rates.all.to_a
217
+
218
+ expect(first_response_stub).to have_been_requested
219
+ expect(second_response_stub).to have_been_requested.twice
220
+ end
221
+ end
222
+ end
223
+ end
@@ -10,7 +10,216 @@ describe GoCardlessPro::Services::InstalmentSchedulesService do
10
10
  let(:response_headers) { { 'Content-Type' => 'application/json' } }
11
11
 
12
12
  describe '#create' do
13
- subject(:post_create_response) { client.instalment_schedules.create(params: new_resource) }
13
+ subject(:post_create_response) { client.instalment_schedules.create_with_dates(params: new_resource) }
14
+ context 'with a valid request' do
15
+ let(:new_resource) do
16
+ {
17
+
18
+ 'created_at' => 'created_at-input',
19
+ 'currency' => 'currency-input',
20
+ 'id' => 'id-input',
21
+ 'links' => 'links-input',
22
+ 'metadata' => 'metadata-input',
23
+ 'name' => 'name-input',
24
+ 'payment_errors' => 'payment_errors-input',
25
+ 'status' => 'status-input',
26
+ 'total_amount' => 'total_amount-input',
27
+ }
28
+ end
29
+
30
+ before do
31
+ stub_request(:post, %r{.*api.gocardless.com/instalment_schedules}).
32
+ with(
33
+ body: {
34
+ 'instalment_schedules' => {
35
+
36
+ 'created_at' => 'created_at-input',
37
+ 'currency' => 'currency-input',
38
+ 'id' => 'id-input',
39
+ 'links' => 'links-input',
40
+ 'metadata' => 'metadata-input',
41
+ 'name' => 'name-input',
42
+ 'payment_errors' => 'payment_errors-input',
43
+ 'status' => 'status-input',
44
+ 'total_amount' => 'total_amount-input',
45
+ },
46
+ }
47
+ ).
48
+ to_return(
49
+ body: {
50
+ 'instalment_schedules' =>
51
+
52
+ {
53
+
54
+ 'created_at' => 'created_at-input',
55
+ 'currency' => 'currency-input',
56
+ 'id' => 'id-input',
57
+ 'links' => 'links-input',
58
+ 'metadata' => 'metadata-input',
59
+ 'name' => 'name-input',
60
+ 'payment_errors' => 'payment_errors-input',
61
+ 'status' => 'status-input',
62
+ 'total_amount' => 'total_amount-input',
63
+ },
64
+
65
+ }.to_json,
66
+ headers: response_headers
67
+ )
68
+ end
69
+
70
+ it 'creates and returns the resource' do
71
+ expect(post_create_response).to be_a(GoCardlessPro::Resources::InstalmentSchedule)
72
+ end
73
+
74
+ describe 'retry behaviour' do
75
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
76
+
77
+ it 'retries timeouts' do
78
+ stub = stub_request(:post, %r{.*api.gocardless.com/instalment_schedules}).
79
+ to_timeout.then.to_return(status: 200, headers: response_headers)
80
+
81
+ post_create_response
82
+ expect(stub).to have_been_requested.twice
83
+ end
84
+
85
+ it 'retries 5XX errors' do
86
+ stub = stub_request(:post, %r{.*api.gocardless.com/instalment_schedules}).
87
+ to_return(status: 502,
88
+ headers: { 'Content-Type' => 'text/html' },
89
+ body: '<html><body>Response from Cloudflare</body></html>').
90
+ then.to_return(status: 200, headers: response_headers)
91
+
92
+ post_create_response
93
+ expect(stub).to have_been_requested.twice
94
+ end
95
+ end
96
+ end
97
+
98
+ context 'with a request that returns a validation error' do
99
+ let(:new_resource) { {} }
100
+
101
+ before do
102
+ stub_request(:post, %r{.*api.gocardless.com/instalment_schedules}).to_return(
103
+ body: {
104
+ error: {
105
+ type: 'validation_failed',
106
+ code: 422,
107
+ errors: [
108
+ { message: 'test error message', field: 'test_field' },
109
+ ],
110
+ },
111
+ }.to_json,
112
+ headers: response_headers,
113
+ status: 422
114
+ )
115
+ end
116
+
117
+ it 'throws the correct error' do
118
+ expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError)
119
+ end
120
+ end
121
+
122
+ context 'with a request that returns an idempotent creation conflict error' do
123
+ let(:id) { 'ID123' }
124
+
125
+ let(:new_resource) do
126
+ {
127
+
128
+ 'created_at' => 'created_at-input',
129
+ 'currency' => 'currency-input',
130
+ 'id' => 'id-input',
131
+ 'links' => 'links-input',
132
+ 'metadata' => 'metadata-input',
133
+ 'name' => 'name-input',
134
+ 'payment_errors' => 'payment_errors-input',
135
+ 'status' => 'status-input',
136
+ 'total_amount' => 'total_amount-input',
137
+ }
138
+ end
139
+
140
+ let!(:post_stub) do
141
+ stub_request(:post, %r{.*api.gocardless.com/instalment_schedules}).to_return(
142
+ body: {
143
+ error: {
144
+ type: 'invalid_state',
145
+ code: 409,
146
+ errors: [
147
+ {
148
+ message: 'A resource has already been created with this idempotency key',
149
+ reason: 'idempotent_creation_conflict',
150
+ links: {
151
+ conflicting_resource_id: id,
152
+ },
153
+ },
154
+ ],
155
+ },
156
+ }.to_json,
157
+ headers: response_headers,
158
+ status: 409
159
+ )
160
+ end
161
+
162
+ let!(:get_stub) do
163
+ stub_url = "/instalment_schedules/#{id}"
164
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).
165
+ to_return(
166
+ body: {
167
+ 'instalment_schedules' => {
168
+
169
+ 'created_at' => 'created_at-input',
170
+ 'currency' => 'currency-input',
171
+ 'id' => 'id-input',
172
+ 'links' => 'links-input',
173
+ 'metadata' => 'metadata-input',
174
+ 'name' => 'name-input',
175
+ 'payment_errors' => 'payment_errors-input',
176
+ 'status' => 'status-input',
177
+ 'total_amount' => 'total_amount-input',
178
+ },
179
+ }.to_json,
180
+ headers: response_headers
181
+ )
182
+ end
183
+
184
+ context 'with default behaviour' do
185
+ it 'fetches the already-created resource' do
186
+ post_create_response
187
+ expect(post_stub).to have_been_requested
188
+ expect(get_stub).to have_been_requested
189
+ end
190
+ end
191
+
192
+ context 'with on_idempotency_conflict: :raise' do
193
+ let(:client) do
194
+ GoCardlessPro::Client.new(
195
+ access_token: 'SECRET_TOKEN',
196
+ on_idempotency_conflict: :raise
197
+ )
198
+ end
199
+
200
+ it 'raises an IdempotencyConflict error' do
201
+ expect { post_create_response }.
202
+ to raise_error(GoCardlessPro::IdempotencyConflict)
203
+ end
204
+ end
205
+
206
+ context 'with on_idempotency_conflict: :unknown' do
207
+ let(:client) do
208
+ GoCardlessPro::Client.new(
209
+ access_token: 'SECRET_TOKEN',
210
+ on_idempotency_conflict: :unknown
211
+ )
212
+ end
213
+
214
+ it 'raises an ArgumentError' do
215
+ expect { post_create_response }.to raise_error(ArgumentError)
216
+ end
217
+ end
218
+ end
219
+ end
220
+
221
+ describe '#create' do
222
+ subject(:post_create_response) { client.instalment_schedules.create_with_schedule(params: new_resource) }
14
223
  context 'with a valid request' do
15
224
  let(:new_resource) do
16
225
  {
@@ -17,6 +17,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
17
17
 
18
18
  'amount' => 'amount-input',
19
19
  'app_fee' => 'app_fee-input',
20
+ 'count' => 'count-input',
20
21
  'created_at' => 'created_at-input',
21
22
  'currency' => 'currency-input',
22
23
  'day_of_month' => 'day_of_month-input',
@@ -44,6 +45,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
44
45
 
45
46
  'amount' => 'amount-input',
46
47
  'app_fee' => 'app_fee-input',
48
+ 'count' => 'count-input',
47
49
  'created_at' => 'created_at-input',
48
50
  'currency' => 'currency-input',
49
51
  'day_of_month' => 'day_of_month-input',
@@ -71,6 +73,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
71
73
 
72
74
  'amount' => 'amount-input',
73
75
  'app_fee' => 'app_fee-input',
76
+ 'count' => 'count-input',
74
77
  'created_at' => 'created_at-input',
75
78
  'currency' => 'currency-input',
76
79
  'day_of_month' => 'day_of_month-input',
@@ -154,6 +157,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
154
157
 
155
158
  'amount' => 'amount-input',
156
159
  'app_fee' => 'app_fee-input',
160
+ 'count' => 'count-input',
157
161
  'created_at' => 'created_at-input',
158
162
  'currency' => 'currency-input',
159
163
  'day_of_month' => 'day_of_month-input',
@@ -204,6 +208,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
204
208
 
205
209
  'amount' => 'amount-input',
206
210
  'app_fee' => 'app_fee-input',
211
+ 'count' => 'count-input',
207
212
  'created_at' => 'created_at-input',
208
213
  'currency' => 'currency-input',
209
214
  'day_of_month' => 'day_of_month-input',
@@ -273,6 +278,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
273
278
 
274
279
  'amount' => 'amount-input',
275
280
  'app_fee' => 'app_fee-input',
281
+ 'count' => 'count-input',
276
282
  'created_at' => 'created_at-input',
277
283
  'currency' => 'currency-input',
278
284
  'day_of_month' => 'day_of_month-input',
@@ -313,6 +319,8 @@ describe GoCardlessPro::Services::SubscriptionsService do
313
319
 
314
320
  expect(get_list_response.records.first.app_fee).to eq('app_fee-input')
315
321
 
322
+ expect(get_list_response.records.first.count).to eq('count-input')
323
+
316
324
  expect(get_list_response.records.first.created_at).to eq('created_at-input')
317
325
 
318
326
  expect(get_list_response.records.first.currency).to eq('currency-input')
@@ -384,6 +392,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
384
392
 
385
393
  'amount' => 'amount-input',
386
394
  'app_fee' => 'app_fee-input',
395
+ 'count' => 'count-input',
387
396
  'created_at' => 'created_at-input',
388
397
  'currency' => 'currency-input',
389
398
  'day_of_month' => 'day_of_month-input',
@@ -417,6 +426,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
417
426
 
418
427
  'amount' => 'amount-input',
419
428
  'app_fee' => 'app_fee-input',
429
+ 'count' => 'count-input',
420
430
  'created_at' => 'created_at-input',
421
431
  'currency' => 'currency-input',
422
432
  'day_of_month' => 'day_of_month-input',
@@ -459,6 +469,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
459
469
 
460
470
  'amount' => 'amount-input',
461
471
  'app_fee' => 'app_fee-input',
472
+ 'count' => 'count-input',
462
473
  'created_at' => 'created_at-input',
463
474
  'currency' => 'currency-input',
464
475
  'day_of_month' => 'day_of_month-input',
@@ -492,6 +503,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
492
503
 
493
504
  'amount' => 'amount-input',
494
505
  'app_fee' => 'app_fee-input',
506
+ 'count' => 'count-input',
495
507
  'created_at' => 'created_at-input',
496
508
  'currency' => 'currency-input',
497
509
  'day_of_month' => 'day_of_month-input',
@@ -530,6 +542,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
530
542
 
531
543
  'amount' => 'amount-input',
532
544
  'app_fee' => 'app_fee-input',
545
+ 'count' => 'count-input',
533
546
  'created_at' => 'created_at-input',
534
547
  'currency' => 'currency-input',
535
548
  'day_of_month' => 'day_of_month-input',
@@ -566,6 +579,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
566
579
 
567
580
  'amount' => 'amount-input',
568
581
  'app_fee' => 'app_fee-input',
582
+ 'count' => 'count-input',
569
583
  'created_at' => 'created_at-input',
570
584
  'currency' => 'currency-input',
571
585
  'day_of_month' => 'day_of_month-input',
@@ -615,6 +629,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
615
629
 
616
630
  'amount' => 'amount-input',
617
631
  'app_fee' => 'app_fee-input',
632
+ 'count' => 'count-input',
618
633
  'created_at' => 'created_at-input',
619
634
  'currency' => 'currency-input',
620
635
  'day_of_month' => 'day_of_month-input',
@@ -658,6 +673,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
658
673
 
659
674
  'amount' => 'amount-input',
660
675
  'app_fee' => 'app_fee-input',
676
+ 'count' => 'count-input',
661
677
  'created_at' => 'created_at-input',
662
678
  'currency' => 'currency-input',
663
679
  'day_of_month' => 'day_of_month-input',
@@ -778,6 +794,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
778
794
 
779
795
  'amount' => 'amount-input',
780
796
  'app_fee' => 'app_fee-input',
797
+ 'count' => 'count-input',
781
798
  'created_at' => 'created_at-input',
782
799
  'currency' => 'currency-input',
783
800
  'day_of_month' => 'day_of_month-input',
@@ -846,6 +863,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
846
863
 
847
864
  'amount' => 'amount-input',
848
865
  'app_fee' => 'app_fee-input',
866
+ 'count' => 'count-input',
849
867
  'created_at' => 'created_at-input',
850
868
  'currency' => 'currency-input',
851
869
  'day_of_month' => 'day_of_month-input',
@@ -905,6 +923,7 @@ describe GoCardlessPro::Services::SubscriptionsService do
905
923
 
906
924
  'amount' => 'amount-input',
907
925
  'app_fee' => 'app_fee-input',
926
+ 'count' => 'count-input',
908
927
  'created_at' => 'created_at-input',
909
928
  'currency' => 'currency-input',
910
929
  'day_of_month' => 'day_of_month-input',
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gocardless_pro
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.17.1
4
+ version: 2.18.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GoCardless
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-24 00:00:00.000000000 Z
11
+ date: 2020-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -144,6 +144,7 @@ files:
144
144
  - LICENSE.txt
145
145
  - README.md
146
146
  - demo.rb
147
+ - gocardless_pro-2.17.1.gem
147
148
  - gocardless_pro.gemspec
148
149
  - lib/gocardless_pro.rb
149
150
  - lib/gocardless_pro/api_response.rb
@@ -162,6 +163,7 @@ files:
162
163
  - lib/gocardless_pro/resources/bank_details_lookup.rb
163
164
  - lib/gocardless_pro/resources/creditor.rb
164
165
  - lib/gocardless_pro/resources/creditor_bank_account.rb
166
+ - lib/gocardless_pro/resources/currency_exchange_rate.rb
165
167
  - lib/gocardless_pro/resources/customer.rb
166
168
  - lib/gocardless_pro/resources/customer_bank_account.rb
167
169
  - lib/gocardless_pro/resources/customer_notification.rb
@@ -182,6 +184,7 @@ files:
182
184
  - lib/gocardless_pro/services/base_service.rb
183
185
  - lib/gocardless_pro/services/creditor_bank_accounts_service.rb
184
186
  - lib/gocardless_pro/services/creditors_service.rb
187
+ - lib/gocardless_pro/services/currency_exchange_rates_service.rb
185
188
  - lib/gocardless_pro/services/customer_bank_accounts_service.rb
186
189
  - lib/gocardless_pro/services/customer_notifications_service.rb
187
190
  - lib/gocardless_pro/services/customers_service.rb
@@ -207,6 +210,7 @@ files:
207
210
  - spec/resources/bank_details_lookup_spec.rb
208
211
  - spec/resources/creditor_bank_account_spec.rb
209
212
  - spec/resources/creditor_spec.rb
213
+ - spec/resources/currency_exchange_rate_spec.rb
210
214
  - spec/resources/customer_bank_account_spec.rb
211
215
  - spec/resources/customer_notification_spec.rb
212
216
  - spec/resources/customer_spec.rb
@@ -226,6 +230,7 @@ files:
226
230
  - spec/services/bank_details_lookups_service_spec.rb
227
231
  - spec/services/creditor_bank_accounts_service_spec.rb
228
232
  - spec/services/creditors_service_spec.rb
233
+ - spec/services/currency_exchange_rates_service_spec.rb
229
234
  - spec/services/customer_bank_accounts_service_spec.rb
230
235
  - spec/services/customer_notifications_service_spec.rb
231
236
  - spec/services/customers_service_spec.rb
@@ -275,6 +280,7 @@ test_files:
275
280
  - spec/resources/bank_details_lookup_spec.rb
276
281
  - spec/resources/creditor_bank_account_spec.rb
277
282
  - spec/resources/creditor_spec.rb
283
+ - spec/resources/currency_exchange_rate_spec.rb
278
284
  - spec/resources/customer_bank_account_spec.rb
279
285
  - spec/resources/customer_notification_spec.rb
280
286
  - spec/resources/customer_spec.rb
@@ -294,6 +300,7 @@ test_files:
294
300
  - spec/services/bank_details_lookups_service_spec.rb
295
301
  - spec/services/creditor_bank_accounts_service_spec.rb
296
302
  - spec/services/creditors_service_spec.rb
303
+ - spec/services/currency_exchange_rates_service_spec.rb
297
304
  - spec/services/customer_bank_accounts_service_spec.rb
298
305
  - spec/services/customer_notifications_service_spec.rb
299
306
  - spec/services/customers_service_spec.rb