gocardless_pro 1.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +13 -4
  3. data/lib/gocardless_pro.rb +1 -0
  4. data/lib/gocardless_pro/api_service.rb +2 -0
  5. data/lib/gocardless_pro/client.rb +4 -3
  6. data/lib/gocardless_pro/error/invalid_state_error.rb +17 -0
  7. data/lib/gocardless_pro/middlewares/raise_gocardless_errors.rb +50 -0
  8. data/lib/gocardless_pro/request.rb +38 -1
  9. data/lib/gocardless_pro/resources/creditor.rb +2 -2
  10. data/lib/gocardless_pro/resources/creditor_bank_account.rb +11 -11
  11. data/lib/gocardless_pro/resources/customer_bank_account.rb +2 -2
  12. data/lib/gocardless_pro/resources/event.rb +2 -2
  13. data/lib/gocardless_pro/resources/mandate.rb +2 -2
  14. data/lib/gocardless_pro/resources/payment.rb +7 -7
  15. data/lib/gocardless_pro/resources/payout.rb +7 -6
  16. data/lib/gocardless_pro/resources/redirect_flow.rb +2 -2
  17. data/lib/gocardless_pro/resources/refund.rb +2 -2
  18. data/lib/gocardless_pro/resources/subscription.rb +2 -2
  19. data/lib/gocardless_pro/response.rb +2 -54
  20. data/lib/gocardless_pro/services/bank_details_lookups_service.rb +3 -0
  21. data/lib/gocardless_pro/services/creditor_bank_accounts_service.rb +31 -2
  22. data/lib/gocardless_pro/services/creditors_service.rb +21 -1
  23. data/lib/gocardless_pro/services/customer_bank_accounts_service.rb +34 -2
  24. data/lib/gocardless_pro/services/customers_service.rb +21 -1
  25. data/lib/gocardless_pro/services/events_service.rb +5 -0
  26. data/lib/gocardless_pro/services/mandate_pdfs_service.rb +3 -0
  27. data/lib/gocardless_pro/services/mandates_service.rb +47 -3
  28. data/lib/gocardless_pro/services/payments_service.rb +47 -3
  29. data/lib/gocardless_pro/services/payouts_service.rb +5 -0
  30. data/lib/gocardless_pro/services/redirect_flows_service.rb +28 -2
  31. data/lib/gocardless_pro/services/refunds_service.rb +21 -1
  32. data/lib/gocardless_pro/services/subscriptions_service.rb +34 -2
  33. data/lib/gocardless_pro/version.rb +1 -1
  34. data/spec/api_service_spec.rb +106 -0
  35. data/spec/middlewares/raise_gocardless_errors_spec.rb +98 -0
  36. data/spec/resources/bank_details_lookup_spec.rb +102 -19
  37. data/spec/resources/creditor_bank_account_spec.rb +416 -40
  38. data/spec/resources/creditor_spec.rb +414 -53
  39. data/spec/resources/customer_bank_account_spec.rb +452 -40
  40. data/spec/resources/customer_spec.rb +457 -45
  41. data/spec/resources/event_spec.rb +171 -72
  42. data/spec/resources/mandate_pdf_spec.rb +100 -17
  43. data/spec/resources/mandate_spec.rb +501 -44
  44. data/spec/resources/payment_spec.rb +531 -48
  45. data/spec/resources/payout_spec.rb +189 -45
  46. data/spec/resources/redirect_flow_spec.rb +277 -43
  47. data/spec/resources/refund_spec.rb +349 -34
  48. data/spec/resources/subscription_spec.rb +531 -53
  49. data/spec/response_spec.rb +12 -79
  50. data/spec/services/bank_details_lookups_service_spec.rb +67 -2
  51. data/spec/services/creditor_bank_accounts_service_spec.rb +309 -31
  52. data/spec/services/creditors_service_spec.rb +343 -33
  53. data/spec/services/customer_bank_accounts_service_spec.rb +335 -32
  54. data/spec/services/customers_service_spec.rb +364 -36
  55. data/spec/services/events_service_spec.rb +185 -24
  56. data/spec/services/mandate_pdfs_service_spec.rb +66 -2
  57. data/spec/services/mandates_service_spec.rb +341 -33
  58. data/spec/services/payments_service_spec.rb +355 -35
  59. data/spec/services/payouts_service_spec.rb +206 -26
  60. data/spec/services/redirect_flows_service_spec.rb +137 -7
  61. data/spec/services/refunds_service_spec.rb +301 -27
  62. data/spec/services/subscriptions_service_spec.rb +377 -38
  63. metadata +6 -3
@@ -1,79 +1,491 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe GoCardlessPro::Resources::CustomerBankAccount do
4
- describe 'initialising' do
5
- let(:data) do
6
- {
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 '#create' do
13
+ subject(:post_create_response) { client.customer_bank_accounts.create(params: new_resource) }
14
+ context 'with a valid request' do
15
+ let(:new_resource) do
16
+ {
17
+
18
+ 'account_holder_name' => 'account_holder_name-input',
19
+ 'account_number_ending' => 'account_number_ending-input',
20
+ 'bank_name' => 'bank_name-input',
21
+ 'country_code' => 'country_code-input',
22
+ 'created_at' => 'created_at-input',
23
+ 'currency' => 'currency-input',
24
+ 'enabled' => 'enabled-input',
25
+ 'id' => 'id-input',
26
+ 'links' => 'links-input',
27
+ 'metadata' => 'metadata-input'
28
+ }
29
+ end
30
+
31
+ before do
32
+ stub_request(:post, %r{.*api.gocardless.com/customer_bank_accounts})
33
+ .with(
34
+ body: {
35
+ 'customer_bank_accounts' => {
36
+
37
+ 'account_holder_name' => 'account_holder_name-input',
38
+ 'account_number_ending' => 'account_number_ending-input',
39
+ 'bank_name' => 'bank_name-input',
40
+ 'country_code' => 'country_code-input',
41
+ 'created_at' => 'created_at-input',
42
+ 'currency' => 'currency-input',
43
+ 'enabled' => 'enabled-input',
44
+ 'id' => 'id-input',
45
+ 'links' => 'links-input',
46
+ 'metadata' => 'metadata-input'
47
+ }
48
+ }
49
+ )
50
+ .to_return(
51
+ body: {
52
+ 'customer_bank_accounts' =>
53
+
54
+ {
55
+
56
+ 'account_holder_name' => 'account_holder_name-input',
57
+ 'account_number_ending' => 'account_number_ending-input',
58
+ 'bank_name' => 'bank_name-input',
59
+ 'country_code' => 'country_code-input',
60
+ 'created_at' => 'created_at-input',
61
+ 'currency' => 'currency-input',
62
+ 'enabled' => 'enabled-input',
63
+ 'id' => 'id-input',
64
+ 'links' => 'links-input',
65
+ 'metadata' => 'metadata-input'
66
+ }
67
+
68
+ }.to_json,
69
+ headers: response_headers
70
+ )
71
+ end
72
+
73
+ it 'creates and returns the resource' do
74
+ expect(post_create_response).to be_a(GoCardlessPro::Resources::CustomerBankAccount)
75
+ end
76
+ end
77
+
78
+ context 'with a request that returns a validation error' do
79
+ let(:new_resource) { {} }
80
+
81
+ before do
82
+ stub_request(:post, %r{.*api.gocardless.com/customer_bank_accounts}).to_return(
83
+ body: {
84
+ error: {
85
+ type: 'validation_failed',
86
+ code: 422,
87
+ errors: [
88
+ { message: 'test error message', field: 'test_field' }
89
+ ]
90
+ }
91
+ }.to_json,
92
+ headers: response_headers,
93
+ status: 422
94
+ )
95
+ end
96
+
97
+ it 'throws the correct error' do
98
+ expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError)
99
+ end
100
+ end
101
+
102
+ context 'with a request that returns an idempotent creation conflict error' do
103
+ let(:id) { 'ID123' }
104
+
105
+ let(:new_resource) do
106
+ {
107
+
108
+ 'account_holder_name' => 'account_holder_name-input',
109
+ 'account_number_ending' => 'account_number_ending-input',
110
+ 'bank_name' => 'bank_name-input',
111
+ 'country_code' => 'country_code-input',
112
+ 'created_at' => 'created_at-input',
113
+ 'currency' => 'currency-input',
114
+ 'enabled' => 'enabled-input',
115
+ 'id' => 'id-input',
116
+ 'links' => 'links-input',
117
+ 'metadata' => 'metadata-input'
118
+ }
119
+ end
120
+
121
+ let!(:post_stub) do
122
+ stub_request(:post, %r{.*api.gocardless.com/customer_bank_accounts}).to_return(
123
+ body: {
124
+ error: {
125
+ type: 'invalid_state',
126
+ code: 409,
127
+ errors: [
128
+ {
129
+ message: 'A resource has already been created with this idempotency key',
130
+ reason: 'idempotent_creation_conflict',
131
+ links: {
132
+ conflicting_resource_id: id
133
+ }
134
+ }
135
+ ]
136
+ }
137
+ }.to_json,
138
+ headers: response_headers,
139
+ status: 409
140
+ )
141
+ end
142
+
143
+ let!(:get_stub) do
144
+ stub_url = "/customer_bank_accounts/#{id}"
145
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/)
146
+ .to_return(
147
+ body: {
148
+ 'customer_bank_accounts' => {
149
+
150
+ 'account_holder_name' => 'account_holder_name-input',
151
+ 'account_number_ending' => 'account_number_ending-input',
152
+ 'bank_name' => 'bank_name-input',
153
+ 'country_code' => 'country_code-input',
154
+ 'created_at' => 'created_at-input',
155
+ 'currency' => 'currency-input',
156
+ 'enabled' => 'enabled-input',
157
+ 'id' => 'id-input',
158
+ 'links' => 'links-input',
159
+ 'metadata' => 'metadata-input'
160
+ }
161
+ }.to_json,
162
+ headers: response_headers
163
+ )
164
+ end
165
+
166
+ it 'fetches the already-created resource' do
167
+ post_create_response
168
+ expect(post_stub).to have_been_requested
169
+ expect(get_stub).to have_been_requested
170
+ end
171
+ end
172
+ end
173
+
174
+ describe '#list' do
175
+ describe 'with no filters' do
176
+ subject(:get_list_response) { client.customer_bank_accounts.list }
177
+
178
+ before do
179
+ stub_request(:get, %r{.*api.gocardless.com/customer_bank_accounts}).to_return(
180
+ body: {
181
+ 'customer_bank_accounts' => [{
182
+
183
+ 'account_holder_name' => 'account_holder_name-input',
184
+ 'account_number_ending' => 'account_number_ending-input',
185
+ 'bank_name' => 'bank_name-input',
186
+ 'country_code' => 'country_code-input',
187
+ 'created_at' => 'created_at-input',
188
+ 'currency' => 'currency-input',
189
+ 'enabled' => 'enabled-input',
190
+ 'id' => 'id-input',
191
+ 'links' => 'links-input',
192
+ 'metadata' => 'metadata-input'
193
+ }],
194
+ meta: {
195
+ cursors: {
196
+ before: nil,
197
+ after: 'ABC123'
198
+ }
199
+ }
200
+ }.to_json,
201
+ headers: response_headers
202
+ )
203
+ end
204
+
205
+ it 'wraps each item in the resource class' do
206
+ expect(get_list_response.records.map(&:class).uniq.first).to eq(GoCardlessPro::Resources::CustomerBankAccount)
7
207
 
8
- 'account_holder_name' => 'account_holder_name-input',
208
+ expect(get_list_response.records.first.account_holder_name).to eq('account_holder_name-input')
9
209
 
10
- 'account_number_ending' => 'account_number_ending-input',
210
+ expect(get_list_response.records.first.account_number_ending).to eq('account_number_ending-input')
11
211
 
12
- 'bank_name' => 'bank_name-input',
212
+ expect(get_list_response.records.first.bank_name).to eq('bank_name-input')
13
213
 
14
- 'country_code' => 'country_code-input',
214
+ expect(get_list_response.records.first.country_code).to eq('country_code-input')
15
215
 
16
- 'created_at' => 'created_at-input',
216
+ expect(get_list_response.records.first.created_at).to eq('created_at-input')
17
217
 
18
- 'currency' => 'currency-input',
218
+ expect(get_list_response.records.first.currency).to eq('currency-input')
19
219
 
20
- 'enabled' => 'enabled-input',
220
+ expect(get_list_response.records.first.enabled).to eq('enabled-input')
21
221
 
22
- 'id' => 'id-input',
222
+ expect(get_list_response.records.first.id).to eq('id-input')
23
223
 
24
- 'links' => {
224
+ expect(get_list_response.records.first.metadata).to eq('metadata-input')
225
+ end
25
226
 
26
- 'customer' => 'customer-input'
227
+ it 'exposes the cursors for before and after' do
228
+ expect(get_list_response.before).to eq(nil)
229
+ expect(get_list_response.after).to eq('ABC123')
230
+ end
27
231
 
28
- },
232
+ specify { expect(get_list_response.api_response.headers).to eql('content-type' => 'application/json') }
233
+ end
234
+ end
29
235
 
30
- 'metadata' => 'metadata-input'
236
+ describe '#all' do
237
+ let!(:first_response_stub) do
238
+ stub_request(:get, %r{.*api.gocardless.com/customer_bank_accounts$}).to_return(
239
+ body: {
240
+ 'customer_bank_accounts' => [{
31
241
 
32
- }
242
+ 'account_holder_name' => 'account_holder_name-input',
243
+ 'account_number_ending' => 'account_number_ending-input',
244
+ 'bank_name' => 'bank_name-input',
245
+ 'country_code' => 'country_code-input',
246
+ 'created_at' => 'created_at-input',
247
+ 'currency' => 'currency-input',
248
+ 'enabled' => 'enabled-input',
249
+ 'id' => 'id-input',
250
+ 'links' => 'links-input',
251
+ 'metadata' => 'metadata-input'
252
+ }],
253
+ meta: {
254
+ cursors: { after: 'AB345' },
255
+ limit: 1
256
+ }
257
+ }.to_json,
258
+ headers: response_headers
259
+ )
33
260
  end
34
261
 
35
- it 'can be initialized from an unenveloped response' do
36
- resource = described_class.new(data)
262
+ let!(:second_response_stub) do
263
+ stub_request(:get, %r{.*api.gocardless.com/customer_bank_accounts\?after=AB345}).to_return(
264
+ body: {
265
+ 'customer_bank_accounts' => [{
266
+
267
+ 'account_holder_name' => 'account_holder_name-input',
268
+ 'account_number_ending' => 'account_number_ending-input',
269
+ 'bank_name' => 'bank_name-input',
270
+ 'country_code' => 'country_code-input',
271
+ 'created_at' => 'created_at-input',
272
+ 'currency' => 'currency-input',
273
+ 'enabled' => 'enabled-input',
274
+ 'id' => 'id-input',
275
+ 'links' => 'links-input',
276
+ 'metadata' => 'metadata-input'
277
+ }],
278
+ meta: {
279
+ limit: 2,
280
+ cursors: {}
281
+ }
282
+ }.to_json,
283
+ headers: response_headers
284
+ )
285
+ end
37
286
 
38
- expect(resource.account_holder_name).to eq('account_holder_name-input')
287
+ it 'automatically makes the extra requests' do
288
+ expect(client.customer_bank_accounts.all.to_a.length).to eq(2)
289
+ expect(first_response_stub).to have_been_requested
290
+ expect(second_response_stub).to have_been_requested
291
+ end
292
+ end
39
293
 
40
- expect(resource.account_number_ending).to eq('account_number_ending-input')
294
+ describe '#get' do
295
+ let(:id) { 'ID123' }
41
296
 
42
- expect(resource.bank_name).to eq('bank_name-input')
297
+ subject(:get_response) { client.customer_bank_accounts.get(id) }
43
298
 
44
- expect(resource.country_code).to eq('country_code-input')
299
+ context 'passing in a custom header' do
300
+ let!(:stub) do
301
+ stub_url = '/customer_bank_accounts/:identity'.gsub(':identity', id)
302
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/)
303
+ .with(headers: { 'Foo' => 'Bar' })
304
+ .to_return(
305
+ body: {
306
+ 'customer_bank_accounts' => {
45
307
 
46
- expect(resource.created_at).to eq('created_at-input')
308
+ 'account_holder_name' => 'account_holder_name-input',
309
+ 'account_number_ending' => 'account_number_ending-input',
310
+ 'bank_name' => 'bank_name-input',
311
+ 'country_code' => 'country_code-input',
312
+ 'created_at' => 'created_at-input',
313
+ 'currency' => 'currency-input',
314
+ 'enabled' => 'enabled-input',
315
+ 'id' => 'id-input',
316
+ 'links' => 'links-input',
317
+ 'metadata' => 'metadata-input'
318
+ }
319
+ }.to_json,
320
+ headers: response_headers
321
+ )
322
+ end
47
323
 
48
- expect(resource.currency).to eq('currency-input')
324
+ subject(:get_response) do
325
+ client.customer_bank_accounts.get(id, headers: {
326
+ 'Foo' => 'Bar'
327
+ })
328
+ end
329
+
330
+ it 'includes the header' do
331
+ get_response
332
+ expect(stub).to have_been_requested
333
+ end
334
+ end
335
+
336
+ context 'when there is a customer_bank_account to return' do
337
+ before do
338
+ stub_url = '/customer_bank_accounts/:identity'.gsub(':identity', id)
339
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
340
+ body: {
341
+ 'customer_bank_accounts' => {
342
+
343
+ 'account_holder_name' => 'account_holder_name-input',
344
+ 'account_number_ending' => 'account_number_ending-input',
345
+ 'bank_name' => 'bank_name-input',
346
+ 'country_code' => 'country_code-input',
347
+ 'created_at' => 'created_at-input',
348
+ 'currency' => 'currency-input',
349
+ 'enabled' => 'enabled-input',
350
+ 'id' => 'id-input',
351
+ 'links' => 'links-input',
352
+ 'metadata' => 'metadata-input'
353
+ }
354
+ }.to_json,
355
+ headers: response_headers
356
+ )
357
+ end
358
+
359
+ it 'wraps the response in a resource' do
360
+ expect(get_response).to be_a(GoCardlessPro::Resources::CustomerBankAccount)
361
+ end
362
+ end
49
363
 
50
- expect(resource.enabled).to eq('enabled-input')
364
+ context 'when nothing is returned' do
365
+ before do
366
+ stub_url = '/customer_bank_accounts/:identity'.gsub(':identity', id)
367
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
368
+ body: '',
369
+ headers: response_headers
370
+ )
371
+ end
51
372
 
52
- expect(resource.id).to eq('id-input')
373
+ it 'returns nil' do
374
+ expect(get_response).to be_nil
375
+ end
376
+ end
53
377
 
54
- expect(resource.links.customer).to eq('customer-input')
378
+ context "when an ID is specified which can't be included in a valid URI" do
379
+ let(:id) { '`' }
55
380
 
56
- expect(resource.metadata).to eq('metadata-input')
381
+ it "doesn't raise an error" do
382
+ expect { get_response }.to_not raise_error(/bad URI/)
383
+ end
57
384
  end
385
+ end
386
+
387
+ describe '#update' do
388
+ subject(:put_update_response) { client.customer_bank_accounts.update(id, params: update_params) }
389
+ let(:id) { 'ABC123' }
390
+
391
+ context 'with a valid request' do
392
+ let(:update_params) { { 'hello' => 'world' } }
393
+
394
+ let!(:stub) do
395
+ stub_url = '/customer_bank_accounts/:identity'.gsub(':identity', id)
396
+ stub_request(:put, /.*api.gocardless.com#{stub_url}/).to_return(
397
+ body: {
398
+ 'customer_bank_accounts' => {
399
+
400
+ 'account_holder_name' => 'account_holder_name-input',
401
+ 'account_number_ending' => 'account_number_ending-input',
402
+ 'bank_name' => 'bank_name-input',
403
+ 'country_code' => 'country_code-input',
404
+ 'created_at' => 'created_at-input',
405
+ 'currency' => 'currency-input',
406
+ 'enabled' => 'enabled-input',
407
+ 'id' => 'id-input',
408
+ 'links' => 'links-input',
409
+ 'metadata' => 'metadata-input'
410
+ }
411
+ }.to_json,
412
+ headers: response_headers
413
+ )
414
+ end
58
415
 
59
- it 'can handle new attributes without erroring' do
60
- data['foo'] = 'bar'
61
- expect { described_class.new(data) }.to_not raise_error
416
+ it 'updates and returns the resource' do
417
+ expect(put_update_response).to be_a(GoCardlessPro::Resources::CustomerBankAccount)
418
+ expect(stub).to have_been_requested
419
+ end
62
420
  end
421
+ end
422
+
423
+ describe '#disable' do
424
+ subject(:post_response) { client.customer_bank_accounts.disable(resource_id) }
425
+
426
+ let(:resource_id) { 'ABC123' }
427
+
428
+ let!(:stub) do
429
+ # /customer_bank_accounts/%v/actions/disable
430
+ stub_url = '/customer_bank_accounts/:identity/actions/disable'.gsub(':identity', resource_id)
431
+ stub_request(:post, /.*api.gocardless.com#{stub_url}/).to_return(
432
+ body: {
433
+ 'customer_bank_accounts' => {
63
434
 
64
- it 'can handle new link attributes without erroring' do
65
- data['links']['foo'] = 'bar'
66
- expect { described_class.new(data) }.to_not raise_error
435
+ 'account_holder_name' => 'account_holder_name-input',
436
+ 'account_number_ending' => 'account_number_ending-input',
437
+ 'bank_name' => 'bank_name-input',
438
+ 'country_code' => 'country_code-input',
439
+ 'created_at' => 'created_at-input',
440
+ 'currency' => 'currency-input',
441
+ 'enabled' => 'enabled-input',
442
+ 'id' => 'id-input',
443
+ 'links' => 'links-input',
444
+ 'metadata' => 'metadata-input'
445
+ }
446
+ }.to_json,
447
+ headers: response_headers
448
+ )
67
449
  end
68
450
 
69
- it 'can handle a nil links value' do
70
- data['links'] = nil
71
- expect { described_class.new(data).links }.to_not raise_error
451
+ it 'wraps the response and calls the right endpoint' do
452
+ expect(post_response).to be_a(GoCardlessPro::Resources::CustomerBankAccount)
453
+
454
+ expect(stub).to have_been_requested
72
455
  end
73
456
 
74
- describe '#to_h' do
75
- it 'returns a hash representing the resource' do
76
- expect(described_class.new(data).to_h).to eq(data)
457
+ context 'when the request needs a body and custom header' do
458
+ let(:body) { { foo: 'bar' } }
459
+ let(:headers) { { 'Foo' => 'Bar' } }
460
+ subject(:post_response) { client.customer_bank_accounts.disable(resource_id, body, headers) }
461
+
462
+ let(:resource_id) { 'ABC123' }
463
+
464
+ let!(:stub) do
465
+ # /customer_bank_accounts/%v/actions/disable
466
+ stub_url = '/customer_bank_accounts/:identity/actions/disable'.gsub(':identity', resource_id)
467
+ stub_request(:post, /.*api.gocardless.com#{stub_url}/)
468
+ .with(
469
+ body: { foo: 'bar' },
470
+ headers: { 'Foo' => 'Bar' }
471
+ ).to_return(
472
+ body: {
473
+ 'customer_bank_accounts' => {
474
+
475
+ 'account_holder_name' => 'account_holder_name-input',
476
+ 'account_number_ending' => 'account_number_ending-input',
477
+ 'bank_name' => 'bank_name-input',
478
+ 'country_code' => 'country_code-input',
479
+ 'created_at' => 'created_at-input',
480
+ 'currency' => 'currency-input',
481
+ 'enabled' => 'enabled-input',
482
+ 'id' => 'id-input',
483
+ 'links' => 'links-input',
484
+ 'metadata' => 'metadata-input'
485
+ }
486
+ }.to_json,
487
+ headers: response_headers
488
+ )
77
489
  end
78
490
  end
79
491
  end