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
@@ -7,6 +7,8 @@ describe GoCardlessPro::Services::CustomerBankAccountsService do
7
7
  )
8
8
  end
9
9
 
10
+ let(:response_headers) { { 'Content-Type' => 'application/json' } }
11
+
10
12
  describe '#create' do
11
13
  subject(:post_create_response) { client.customer_bank_accounts.create(params: new_resource) }
12
14
  context 'with a valid request' do
@@ -64,13 +66,36 @@ describe GoCardlessPro::Services::CustomerBankAccountsService do
64
66
  }
65
67
 
66
68
  }.to_json,
67
- headers: { 'Content-Type' => 'application/json' }
69
+ headers: response_headers
68
70
  )
69
71
  end
70
72
 
71
73
  it 'creates and returns the resource' do
72
74
  expect(post_create_response).to be_a(GoCardlessPro::Resources::CustomerBankAccount)
73
75
  end
76
+
77
+ describe 'retry behaviour' do
78
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
79
+
80
+ it 'retries timeouts' do
81
+ stub = stub_request(:post, %r{.*api.gocardless.com/customer_bank_accounts})
82
+ .to_timeout.then.to_return(status: 200, headers: response_headers)
83
+
84
+ post_create_response
85
+ expect(stub).to have_been_requested.twice
86
+ end
87
+
88
+ it 'retries 5XX errors' do
89
+ stub = stub_request(:post, %r{.*api.gocardless.com/customer_bank_accounts})
90
+ .to_return(status: 502,
91
+ headers: { 'Content-Type' => 'text/html' },
92
+ body: '<html><body>Response from Cloudflare</body></html>')
93
+ .then.to_return(status: 200, headers: response_headers)
94
+
95
+ post_create_response
96
+ expect(stub).to have_been_requested.twice
97
+ end
98
+ end
74
99
  end
75
100
 
76
101
  context 'with a request that returns a validation error' do
@@ -87,7 +112,7 @@ describe GoCardlessPro::Services::CustomerBankAccountsService do
87
112
  ]
88
113
  }
89
114
  }.to_json,
90
- headers: { 'Content-Type' => 'application/json' },
115
+ headers: response_headers,
91
116
  status: 422
92
117
  )
93
118
  end
@@ -96,36 +121,111 @@ describe GoCardlessPro::Services::CustomerBankAccountsService do
96
121
  expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError)
97
122
  end
98
123
  end
124
+
125
+ context 'with a request that returns an idempotent creation conflict error' do
126
+ let(:id) { 'ID123' }
127
+
128
+ let(:new_resource) do
129
+ {
130
+
131
+ 'account_holder_name' => 'account_holder_name-input',
132
+ 'account_number_ending' => 'account_number_ending-input',
133
+ 'bank_name' => 'bank_name-input',
134
+ 'country_code' => 'country_code-input',
135
+ 'created_at' => 'created_at-input',
136
+ 'currency' => 'currency-input',
137
+ 'enabled' => 'enabled-input',
138
+ 'id' => 'id-input',
139
+ 'links' => 'links-input',
140
+ 'metadata' => 'metadata-input'
141
+ }
142
+ end
143
+
144
+ let!(:post_stub) do
145
+ stub_request(:post, %r{.*api.gocardless.com/customer_bank_accounts}).to_return(
146
+ body: {
147
+ error: {
148
+ type: 'invalid_state',
149
+ code: 409,
150
+ errors: [
151
+ {
152
+ message: 'A resource has already been created with this idempotency key',
153
+ reason: 'idempotent_creation_conflict',
154
+ links: {
155
+ conflicting_resource_id: id
156
+ }
157
+ }
158
+ ]
159
+ }
160
+ }.to_json,
161
+ headers: response_headers,
162
+ status: 409
163
+ )
164
+ end
165
+
166
+ let!(:get_stub) do
167
+ stub_url = "/customer_bank_accounts/#{id}"
168
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/)
169
+ .to_return(
170
+ body: {
171
+ 'customer_bank_accounts' => {
172
+
173
+ 'account_holder_name' => 'account_holder_name-input',
174
+ 'account_number_ending' => 'account_number_ending-input',
175
+ 'bank_name' => 'bank_name-input',
176
+ 'country_code' => 'country_code-input',
177
+ 'created_at' => 'created_at-input',
178
+ 'currency' => 'currency-input',
179
+ 'enabled' => 'enabled-input',
180
+ 'id' => 'id-input',
181
+ 'links' => 'links-input',
182
+ 'metadata' => 'metadata-input'
183
+ }
184
+ }.to_json,
185
+ headers: response_headers
186
+ )
187
+ end
188
+
189
+ it 'fetches the already-created resource' do
190
+ post_create_response
191
+ expect(post_stub).to have_been_requested
192
+ expect(get_stub).to have_been_requested
193
+ end
194
+ end
99
195
  end
100
196
 
101
197
  describe '#list' do
102
198
  describe 'with no filters' do
103
199
  subject(:get_list_response) { client.customer_bank_accounts.list }
104
200
 
105
- before do
106
- stub_request(:get, %r{.*api.gocardless.com/customer_bank_accounts}).to_return(
107
- body: {
108
- 'customer_bank_accounts' => [{
201
+ let(:body) do
202
+ {
203
+ 'customer_bank_accounts' => [{
109
204
 
110
- 'account_holder_name' => 'account_holder_name-input',
111
- 'account_number_ending' => 'account_number_ending-input',
112
- 'bank_name' => 'bank_name-input',
113
- 'country_code' => 'country_code-input',
114
- 'created_at' => 'created_at-input',
115
- 'currency' => 'currency-input',
116
- 'enabled' => 'enabled-input',
117
- 'id' => 'id-input',
118
- 'links' => 'links-input',
119
- 'metadata' => 'metadata-input'
120
- }],
121
- meta: {
122
- cursors: {
123
- before: nil,
124
- after: 'ABC123'
125
- }
205
+ 'account_holder_name' => 'account_holder_name-input',
206
+ 'account_number_ending' => 'account_number_ending-input',
207
+ 'bank_name' => 'bank_name-input',
208
+ 'country_code' => 'country_code-input',
209
+ 'created_at' => 'created_at-input',
210
+ 'currency' => 'currency-input',
211
+ 'enabled' => 'enabled-input',
212
+ 'id' => 'id-input',
213
+ 'links' => 'links-input',
214
+ 'metadata' => 'metadata-input'
215
+ }],
216
+ meta: {
217
+ cursors: {
218
+ before: nil,
219
+ after: 'ABC123'
126
220
  }
127
- }.to_json,
128
- headers: { 'Content-Type' => 'application/json' }
221
+ }
222
+ }.to_json
223
+ end
224
+
225
+ before do
226
+ stub_request(:get, %r{.*api.gocardless.com/customer_bank_accounts}).to_return(
227
+ body: body,
228
+ headers: response_headers
129
229
  )
130
230
  end
131
231
 
@@ -157,6 +257,29 @@ describe GoCardlessPro::Services::CustomerBankAccountsService do
157
257
  end
158
258
 
159
259
  specify { expect(get_list_response.api_response.headers).to eql('content-type' => 'application/json') }
260
+
261
+ describe 'retry behaviour' do
262
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
263
+
264
+ it 'retries timeouts' do
265
+ stub = stub_request(:get, %r{.*api.gocardless.com/customer_bank_accounts})
266
+ .to_timeout.then.to_return(status: 200, headers: response_headers, body: body)
267
+
268
+ get_list_response
269
+ expect(stub).to have_been_requested.twice
270
+ end
271
+
272
+ it 'retries 5XX errors' do
273
+ stub = stub_request(:get, %r{.*api.gocardless.com/customer_bank_accounts})
274
+ .to_return(status: 502,
275
+ headers: { 'Content-Type' => 'text/html' },
276
+ body: '<html><body>Response from Cloudflare</body></html>')
277
+ .then.to_return(status: 200, headers: response_headers, body: body)
278
+
279
+ get_list_response
280
+ expect(stub).to have_been_requested.twice
281
+ end
282
+ end
160
283
  end
161
284
  end
162
285
 
@@ -182,7 +305,7 @@ describe GoCardlessPro::Services::CustomerBankAccountsService do
182
305
  limit: 1
183
306
  }
184
307
  }.to_json,
185
- headers: { 'Content-Type' => 'application/json' }
308
+ headers: response_headers
186
309
  )
187
310
  end
188
311
 
@@ -207,7 +330,7 @@ describe GoCardlessPro::Services::CustomerBankAccountsService do
207
330
  cursors: {}
208
331
  }
209
332
  }.to_json,
210
- headers: { 'Content-Type' => 'application/json' }
333
+ headers: response_headers
211
334
  )
212
335
  end
213
336
 
@@ -216,6 +339,123 @@ describe GoCardlessPro::Services::CustomerBankAccountsService do
216
339
  expect(first_response_stub).to have_been_requested
217
340
  expect(second_response_stub).to have_been_requested
218
341
  end
342
+
343
+ describe 'retry behaviour' do
344
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
345
+
346
+ it 'retries timeouts' do
347
+ first_response_stub = stub_request(:get, %r{.*api.gocardless.com/customer_bank_accounts$}).to_return(
348
+ body: {
349
+ 'customer_bank_accounts' => [{
350
+
351
+ 'account_holder_name' => 'account_holder_name-input',
352
+ 'account_number_ending' => 'account_number_ending-input',
353
+ 'bank_name' => 'bank_name-input',
354
+ 'country_code' => 'country_code-input',
355
+ 'created_at' => 'created_at-input',
356
+ 'currency' => 'currency-input',
357
+ 'enabled' => 'enabled-input',
358
+ 'id' => 'id-input',
359
+ 'links' => 'links-input',
360
+ 'metadata' => 'metadata-input'
361
+ }],
362
+ meta: {
363
+ cursors: { after: 'AB345' },
364
+ limit: 1
365
+ }
366
+ }.to_json,
367
+ headers: response_headers
368
+ )
369
+
370
+ second_response_stub = stub_request(:get, %r{.*api.gocardless.com/customer_bank_accounts\?after=AB345})
371
+ .to_timeout.then
372
+ .to_return(
373
+ body: {
374
+ 'customer_bank_accounts' => [{
375
+
376
+ 'account_holder_name' => 'account_holder_name-input',
377
+ 'account_number_ending' => 'account_number_ending-input',
378
+ 'bank_name' => 'bank_name-input',
379
+ 'country_code' => 'country_code-input',
380
+ 'created_at' => 'created_at-input',
381
+ 'currency' => 'currency-input',
382
+ 'enabled' => 'enabled-input',
383
+ 'id' => 'id-input',
384
+ 'links' => 'links-input',
385
+ 'metadata' => 'metadata-input'
386
+ }],
387
+ meta: {
388
+ limit: 2,
389
+ cursors: {}
390
+ }
391
+ }.to_json,
392
+ headers: response_headers
393
+ )
394
+
395
+ client.customer_bank_accounts.all.to_a
396
+
397
+ expect(first_response_stub).to have_been_requested
398
+ expect(second_response_stub).to have_been_requested.twice
399
+ end
400
+
401
+ it 'retries 5XX errors' do
402
+ first_response_stub = stub_request(:get, %r{.*api.gocardless.com/customer_bank_accounts$}).to_return(
403
+ body: {
404
+ 'customer_bank_accounts' => [{
405
+
406
+ 'account_holder_name' => 'account_holder_name-input',
407
+ 'account_number_ending' => 'account_number_ending-input',
408
+ 'bank_name' => 'bank_name-input',
409
+ 'country_code' => 'country_code-input',
410
+ 'created_at' => 'created_at-input',
411
+ 'currency' => 'currency-input',
412
+ 'enabled' => 'enabled-input',
413
+ 'id' => 'id-input',
414
+ 'links' => 'links-input',
415
+ 'metadata' => 'metadata-input'
416
+ }],
417
+ meta: {
418
+ cursors: { after: 'AB345' },
419
+ limit: 1
420
+ }
421
+ }.to_json,
422
+ headers: response_headers
423
+ )
424
+
425
+ second_response_stub = stub_request(:get, %r{.*api.gocardless.com/customer_bank_accounts\?after=AB345})
426
+ .to_return(
427
+ status: 502,
428
+ body: '<html><body>Response from Cloudflare</body></html>',
429
+ headers: { 'Content-Type' => 'text/html' }
430
+ ).then.to_return(
431
+ body: {
432
+ 'customer_bank_accounts' => [{
433
+
434
+ 'account_holder_name' => 'account_holder_name-input',
435
+ 'account_number_ending' => 'account_number_ending-input',
436
+ 'bank_name' => 'bank_name-input',
437
+ 'country_code' => 'country_code-input',
438
+ 'created_at' => 'created_at-input',
439
+ 'currency' => 'currency-input',
440
+ 'enabled' => 'enabled-input',
441
+ 'id' => 'id-input',
442
+ 'links' => 'links-input',
443
+ 'metadata' => 'metadata-input'
444
+ }],
445
+ meta: {
446
+ limit: 2,
447
+ cursors: {}
448
+ }
449
+ }.to_json,
450
+ headers: response_headers
451
+ )
452
+
453
+ client.customer_bank_accounts.all.to_a
454
+
455
+ expect(first_response_stub).to have_been_requested
456
+ expect(second_response_stub).to have_been_requested.twice
457
+ end
458
+ end
219
459
  end
220
460
 
221
461
  describe '#get' do
@@ -244,7 +484,7 @@ describe GoCardlessPro::Services::CustomerBankAccountsService do
244
484
  'metadata' => 'metadata-input'
245
485
  }
246
486
  }.to_json,
247
- headers: { 'Content-Type' => 'application/json' }
487
+ headers: response_headers
248
488
  )
249
489
  end
250
490
 
@@ -279,7 +519,7 @@ describe GoCardlessPro::Services::CustomerBankAccountsService do
279
519
  'metadata' => 'metadata-input'
280
520
  }
281
521
  }.to_json,
282
- headers: { 'Content-Type' => 'application/json' }
522
+ headers: response_headers
283
523
  )
284
524
  end
285
525
 
@@ -293,7 +533,7 @@ describe GoCardlessPro::Services::CustomerBankAccountsService do
293
533
  stub_url = '/customer_bank_accounts/:identity'.gsub(':identity', id)
294
534
  stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
295
535
  body: '',
296
- headers: { 'Content-Type' => 'application/json' }
536
+ headers: response_headers
297
537
  )
298
538
  end
299
539
 
@@ -309,6 +549,33 @@ describe GoCardlessPro::Services::CustomerBankAccountsService do
309
549
  expect { get_response }.to_not raise_error(/bad URI/)
310
550
  end
311
551
  end
552
+
553
+ describe 'retry behaviour' do
554
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
555
+
556
+ it 'retries timeouts' do
557
+ stub_url = '/customer_bank_accounts/:identity'.gsub(':identity', id)
558
+
559
+ stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/)
560
+ .to_timeout.then.to_return(status: 200, headers: response_headers)
561
+
562
+ get_response
563
+ expect(stub).to have_been_requested.twice
564
+ end
565
+
566
+ it 'retries 5XX errors' do
567
+ stub_url = '/customer_bank_accounts/:identity'.gsub(':identity', id)
568
+
569
+ stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/)
570
+ .to_return(status: 502,
571
+ headers: { 'Content-Type' => 'text/html' },
572
+ body: '<html><body>Response from Cloudflare</body></html>')
573
+ .then.to_return(status: 200, headers: response_headers)
574
+
575
+ get_response
576
+ expect(stub).to have_been_requested.twice
577
+ end
578
+ end
312
579
  end
313
580
 
314
581
  describe '#update' do
@@ -336,7 +603,7 @@ describe GoCardlessPro::Services::CustomerBankAccountsService do
336
603
  'metadata' => 'metadata-input'
337
604
  }
338
605
  }.to_json,
339
- headers: { 'Content-Type' => 'application/json' }
606
+ headers: response_headers
340
607
  )
341
608
  end
342
609
 
@@ -344,6 +611,31 @@ describe GoCardlessPro::Services::CustomerBankAccountsService do
344
611
  expect(put_update_response).to be_a(GoCardlessPro::Resources::CustomerBankAccount)
345
612
  expect(stub).to have_been_requested
346
613
  end
614
+
615
+ describe 'retry behaviour' do
616
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
617
+
618
+ it 'retries timeouts' do
619
+ stub_url = '/customer_bank_accounts/:identity'.gsub(':identity', id)
620
+ stub = stub_request(:put, /.*api.gocardless.com#{stub_url}/)
621
+ .to_timeout.then.to_return(status: 200, headers: response_headers)
622
+
623
+ put_update_response
624
+ expect(stub).to have_been_requested.twice
625
+ end
626
+
627
+ it 'retries 5XX errors' do
628
+ stub_url = '/customer_bank_accounts/:identity'.gsub(':identity', id)
629
+ stub = stub_request(:put, /.*api.gocardless.com#{stub_url}/)
630
+ .to_return(status: 502,
631
+ headers: { 'Content-Type' => 'text/html' },
632
+ body: '<html><body>Response from Cloudflare</body></html>')
633
+ .then.to_return(status: 200, headers: response_headers)
634
+
635
+ put_update_response
636
+ expect(stub).to have_been_requested.twice
637
+ end
638
+ end
347
639
  end
348
640
  end
349
641
 
@@ -371,7 +663,7 @@ describe GoCardlessPro::Services::CustomerBankAccountsService do
371
663
  'metadata' => 'metadata-input'
372
664
  }
373
665
  }.to_json,
374
- headers: { 'Content-Type' => 'application/json' }
666
+ headers: response_headers
375
667
  )
376
668
  end
377
669
 
@@ -381,6 +673,17 @@ describe GoCardlessPro::Services::CustomerBankAccountsService do
381
673
  expect(stub).to have_been_requested
382
674
  end
383
675
 
676
+ describe 'retry behaviour' do
677
+ it "doesn't retry errors" do
678
+ stub_url = '/customer_bank_accounts/:identity/actions/disable'.gsub(':identity', resource_id)
679
+ stub = stub_request(:post, /.*api.gocardless.com#{stub_url}/)
680
+ .to_timeout
681
+
682
+ expect { post_response }.to raise_error(Faraday::TimeoutError)
683
+ expect(stub).to have_been_requested
684
+ end
685
+ end
686
+
384
687
  context 'when the request needs a body and custom header' do
385
688
  let(:body) { { foo: 'bar' } }
386
689
  let(:headers) { { 'Foo' => 'Bar' } }
@@ -411,7 +714,7 @@ describe GoCardlessPro::Services::CustomerBankAccountsService do
411
714
  'metadata' => 'metadata-input'
412
715
  }
413
716
  }.to_json,
414
- headers: { 'Content-Type' => 'application/json' }
717
+ headers: response_headers
415
718
  )
416
719
  end
417
720
  end