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::CustomersService 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.customers.create(params: new_resource) }
12
14
  context 'with a valid request' do
@@ -82,13 +84,36 @@ describe GoCardlessPro::Services::CustomersService do
82
84
  }
83
85
 
84
86
  }.to_json,
85
- headers: { 'Content-Type' => 'application/json' }
87
+ headers: response_headers
86
88
  )
87
89
  end
88
90
 
89
91
  it 'creates and returns the resource' do
90
92
  expect(post_create_response).to be_a(GoCardlessPro::Resources::Customer)
91
93
  end
94
+
95
+ describe 'retry behaviour' do
96
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
97
+
98
+ it 'retries timeouts' do
99
+ stub = stub_request(:post, %r{.*api.gocardless.com/customers})
100
+ .to_timeout.then.to_return(status: 200, headers: response_headers)
101
+
102
+ post_create_response
103
+ expect(stub).to have_been_requested.twice
104
+ end
105
+
106
+ it 'retries 5XX errors' do
107
+ stub = stub_request(:post, %r{.*api.gocardless.com/customers})
108
+ .to_return(status: 502,
109
+ headers: { 'Content-Type' => 'text/html' },
110
+ body: '<html><body>Response from Cloudflare</body></html>')
111
+ .then.to_return(status: 200, headers: response_headers)
112
+
113
+ post_create_response
114
+ expect(stub).to have_been_requested.twice
115
+ end
116
+ end
92
117
  end
93
118
 
94
119
  context 'with a request that returns a validation error' do
@@ -105,7 +130,7 @@ describe GoCardlessPro::Services::CustomersService do
105
130
  ]
106
131
  }
107
132
  }.to_json,
108
- headers: { 'Content-Type' => 'application/json' },
133
+ headers: response_headers,
109
134
  status: 422
110
135
  )
111
136
  end
@@ -114,42 +139,129 @@ describe GoCardlessPro::Services::CustomersService do
114
139
  expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError)
115
140
  end
116
141
  end
142
+
143
+ context 'with a request that returns an idempotent creation conflict error' do
144
+ let(:id) { 'ID123' }
145
+
146
+ let(:new_resource) do
147
+ {
148
+
149
+ 'address_line1' => 'address_line1-input',
150
+ 'address_line2' => 'address_line2-input',
151
+ 'address_line3' => 'address_line3-input',
152
+ 'city' => 'city-input',
153
+ 'company_name' => 'company_name-input',
154
+ 'country_code' => 'country_code-input',
155
+ 'created_at' => 'created_at-input',
156
+ 'email' => 'email-input',
157
+ 'family_name' => 'family_name-input',
158
+ 'given_name' => 'given_name-input',
159
+ 'id' => 'id-input',
160
+ 'language' => 'language-input',
161
+ 'metadata' => 'metadata-input',
162
+ 'postal_code' => 'postal_code-input',
163
+ 'region' => 'region-input',
164
+ 'swedish_identity_number' => 'swedish_identity_number-input'
165
+ }
166
+ end
167
+
168
+ let!(:post_stub) do
169
+ stub_request(:post, %r{.*api.gocardless.com/customers}).to_return(
170
+ body: {
171
+ error: {
172
+ type: 'invalid_state',
173
+ code: 409,
174
+ errors: [
175
+ {
176
+ message: 'A resource has already been created with this idempotency key',
177
+ reason: 'idempotent_creation_conflict',
178
+ links: {
179
+ conflicting_resource_id: id
180
+ }
181
+ }
182
+ ]
183
+ }
184
+ }.to_json,
185
+ headers: response_headers,
186
+ status: 409
187
+ )
188
+ end
189
+
190
+ let!(:get_stub) do
191
+ stub_url = "/customers/#{id}"
192
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/)
193
+ .to_return(
194
+ body: {
195
+ 'customers' => {
196
+
197
+ 'address_line1' => 'address_line1-input',
198
+ 'address_line2' => 'address_line2-input',
199
+ 'address_line3' => 'address_line3-input',
200
+ 'city' => 'city-input',
201
+ 'company_name' => 'company_name-input',
202
+ 'country_code' => 'country_code-input',
203
+ 'created_at' => 'created_at-input',
204
+ 'email' => 'email-input',
205
+ 'family_name' => 'family_name-input',
206
+ 'given_name' => 'given_name-input',
207
+ 'id' => 'id-input',
208
+ 'language' => 'language-input',
209
+ 'metadata' => 'metadata-input',
210
+ 'postal_code' => 'postal_code-input',
211
+ 'region' => 'region-input',
212
+ 'swedish_identity_number' => 'swedish_identity_number-input'
213
+ }
214
+ }.to_json,
215
+ headers: response_headers
216
+ )
217
+ end
218
+
219
+ it 'fetches the already-created resource' do
220
+ post_create_response
221
+ expect(post_stub).to have_been_requested
222
+ expect(get_stub).to have_been_requested
223
+ end
224
+ end
117
225
  end
118
226
 
119
227
  describe '#list' do
120
228
  describe 'with no filters' do
121
229
  subject(:get_list_response) { client.customers.list }
122
230
 
123
- before do
124
- stub_request(:get, %r{.*api.gocardless.com/customers}).to_return(
125
- body: {
126
- 'customers' => [{
231
+ let(:body) do
232
+ {
233
+ 'customers' => [{
127
234
 
128
- 'address_line1' => 'address_line1-input',
129
- 'address_line2' => 'address_line2-input',
130
- 'address_line3' => 'address_line3-input',
131
- 'city' => 'city-input',
132
- 'company_name' => 'company_name-input',
133
- 'country_code' => 'country_code-input',
134
- 'created_at' => 'created_at-input',
135
- 'email' => 'email-input',
136
- 'family_name' => 'family_name-input',
137
- 'given_name' => 'given_name-input',
138
- 'id' => 'id-input',
139
- 'language' => 'language-input',
140
- 'metadata' => 'metadata-input',
141
- 'postal_code' => 'postal_code-input',
142
- 'region' => 'region-input',
143
- 'swedish_identity_number' => 'swedish_identity_number-input'
144
- }],
145
- meta: {
146
- cursors: {
147
- before: nil,
148
- after: 'ABC123'
149
- }
235
+ 'address_line1' => 'address_line1-input',
236
+ 'address_line2' => 'address_line2-input',
237
+ 'address_line3' => 'address_line3-input',
238
+ 'city' => 'city-input',
239
+ 'company_name' => 'company_name-input',
240
+ 'country_code' => 'country_code-input',
241
+ 'created_at' => 'created_at-input',
242
+ 'email' => 'email-input',
243
+ 'family_name' => 'family_name-input',
244
+ 'given_name' => 'given_name-input',
245
+ 'id' => 'id-input',
246
+ 'language' => 'language-input',
247
+ 'metadata' => 'metadata-input',
248
+ 'postal_code' => 'postal_code-input',
249
+ 'region' => 'region-input',
250
+ 'swedish_identity_number' => 'swedish_identity_number-input'
251
+ }],
252
+ meta: {
253
+ cursors: {
254
+ before: nil,
255
+ after: 'ABC123'
150
256
  }
151
- }.to_json,
152
- headers: { 'Content-Type' => 'application/json' }
257
+ }
258
+ }.to_json
259
+ end
260
+
261
+ before do
262
+ stub_request(:get, %r{.*api.gocardless.com/customers}).to_return(
263
+ body: body,
264
+ headers: response_headers
153
265
  )
154
266
  end
155
267
 
@@ -195,6 +307,29 @@ describe GoCardlessPro::Services::CustomersService do
195
307
  end
196
308
 
197
309
  specify { expect(get_list_response.api_response.headers).to eql('content-type' => 'application/json') }
310
+
311
+ describe 'retry behaviour' do
312
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
313
+
314
+ it 'retries timeouts' do
315
+ stub = stub_request(:get, %r{.*api.gocardless.com/customers})
316
+ .to_timeout.then.to_return(status: 200, headers: response_headers, body: body)
317
+
318
+ get_list_response
319
+ expect(stub).to have_been_requested.twice
320
+ end
321
+
322
+ it 'retries 5XX errors' do
323
+ stub = stub_request(:get, %r{.*api.gocardless.com/customers})
324
+ .to_return(status: 502,
325
+ headers: { 'Content-Type' => 'text/html' },
326
+ body: '<html><body>Response from Cloudflare</body></html>')
327
+ .then.to_return(status: 200, headers: response_headers, body: body)
328
+
329
+ get_list_response
330
+ expect(stub).to have_been_requested.twice
331
+ end
332
+ end
198
333
  end
199
334
  end
200
335
 
@@ -226,7 +361,7 @@ describe GoCardlessPro::Services::CustomersService do
226
361
  limit: 1
227
362
  }
228
363
  }.to_json,
229
- headers: { 'Content-Type' => 'application/json' }
364
+ headers: response_headers
230
365
  )
231
366
  end
232
367
 
@@ -257,7 +392,7 @@ describe GoCardlessPro::Services::CustomersService do
257
392
  cursors: {}
258
393
  }
259
394
  }.to_json,
260
- headers: { 'Content-Type' => 'application/json' }
395
+ headers: response_headers
261
396
  )
262
397
  end
263
398
 
@@ -266,6 +401,147 @@ describe GoCardlessPro::Services::CustomersService do
266
401
  expect(first_response_stub).to have_been_requested
267
402
  expect(second_response_stub).to have_been_requested
268
403
  end
404
+
405
+ describe 'retry behaviour' do
406
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
407
+
408
+ it 'retries timeouts' do
409
+ first_response_stub = stub_request(:get, %r{.*api.gocardless.com/customers$}).to_return(
410
+ body: {
411
+ 'customers' => [{
412
+
413
+ 'address_line1' => 'address_line1-input',
414
+ 'address_line2' => 'address_line2-input',
415
+ 'address_line3' => 'address_line3-input',
416
+ 'city' => 'city-input',
417
+ 'company_name' => 'company_name-input',
418
+ 'country_code' => 'country_code-input',
419
+ 'created_at' => 'created_at-input',
420
+ 'email' => 'email-input',
421
+ 'family_name' => 'family_name-input',
422
+ 'given_name' => 'given_name-input',
423
+ 'id' => 'id-input',
424
+ 'language' => 'language-input',
425
+ 'metadata' => 'metadata-input',
426
+ 'postal_code' => 'postal_code-input',
427
+ 'region' => 'region-input',
428
+ 'swedish_identity_number' => 'swedish_identity_number-input'
429
+ }],
430
+ meta: {
431
+ cursors: { after: 'AB345' },
432
+ limit: 1
433
+ }
434
+ }.to_json,
435
+ headers: response_headers
436
+ )
437
+
438
+ second_response_stub = stub_request(:get, %r{.*api.gocardless.com/customers\?after=AB345})
439
+ .to_timeout.then
440
+ .to_return(
441
+ body: {
442
+ 'customers' => [{
443
+
444
+ 'address_line1' => 'address_line1-input',
445
+ 'address_line2' => 'address_line2-input',
446
+ 'address_line3' => 'address_line3-input',
447
+ 'city' => 'city-input',
448
+ 'company_name' => 'company_name-input',
449
+ 'country_code' => 'country_code-input',
450
+ 'created_at' => 'created_at-input',
451
+ 'email' => 'email-input',
452
+ 'family_name' => 'family_name-input',
453
+ 'given_name' => 'given_name-input',
454
+ 'id' => 'id-input',
455
+ 'language' => 'language-input',
456
+ 'metadata' => 'metadata-input',
457
+ 'postal_code' => 'postal_code-input',
458
+ 'region' => 'region-input',
459
+ 'swedish_identity_number' => 'swedish_identity_number-input'
460
+ }],
461
+ meta: {
462
+ limit: 2,
463
+ cursors: {}
464
+ }
465
+ }.to_json,
466
+ headers: response_headers
467
+ )
468
+
469
+ client.customers.all.to_a
470
+
471
+ expect(first_response_stub).to have_been_requested
472
+ expect(second_response_stub).to have_been_requested.twice
473
+ end
474
+
475
+ it 'retries 5XX errors' do
476
+ first_response_stub = stub_request(:get, %r{.*api.gocardless.com/customers$}).to_return(
477
+ body: {
478
+ 'customers' => [{
479
+
480
+ 'address_line1' => 'address_line1-input',
481
+ 'address_line2' => 'address_line2-input',
482
+ 'address_line3' => 'address_line3-input',
483
+ 'city' => 'city-input',
484
+ 'company_name' => 'company_name-input',
485
+ 'country_code' => 'country_code-input',
486
+ 'created_at' => 'created_at-input',
487
+ 'email' => 'email-input',
488
+ 'family_name' => 'family_name-input',
489
+ 'given_name' => 'given_name-input',
490
+ 'id' => 'id-input',
491
+ 'language' => 'language-input',
492
+ 'metadata' => 'metadata-input',
493
+ 'postal_code' => 'postal_code-input',
494
+ 'region' => 'region-input',
495
+ 'swedish_identity_number' => 'swedish_identity_number-input'
496
+ }],
497
+ meta: {
498
+ cursors: { after: 'AB345' },
499
+ limit: 1
500
+ }
501
+ }.to_json,
502
+ headers: response_headers
503
+ )
504
+
505
+ second_response_stub = stub_request(:get, %r{.*api.gocardless.com/customers\?after=AB345})
506
+ .to_return(
507
+ status: 502,
508
+ body: '<html><body>Response from Cloudflare</body></html>',
509
+ headers: { 'Content-Type' => 'text/html' }
510
+ ).then.to_return(
511
+ body: {
512
+ 'customers' => [{
513
+
514
+ 'address_line1' => 'address_line1-input',
515
+ 'address_line2' => 'address_line2-input',
516
+ 'address_line3' => 'address_line3-input',
517
+ 'city' => 'city-input',
518
+ 'company_name' => 'company_name-input',
519
+ 'country_code' => 'country_code-input',
520
+ 'created_at' => 'created_at-input',
521
+ 'email' => 'email-input',
522
+ 'family_name' => 'family_name-input',
523
+ 'given_name' => 'given_name-input',
524
+ 'id' => 'id-input',
525
+ 'language' => 'language-input',
526
+ 'metadata' => 'metadata-input',
527
+ 'postal_code' => 'postal_code-input',
528
+ 'region' => 'region-input',
529
+ 'swedish_identity_number' => 'swedish_identity_number-input'
530
+ }],
531
+ meta: {
532
+ limit: 2,
533
+ cursors: {}
534
+ }
535
+ }.to_json,
536
+ headers: response_headers
537
+ )
538
+
539
+ client.customers.all.to_a
540
+
541
+ expect(first_response_stub).to have_been_requested
542
+ expect(second_response_stub).to have_been_requested.twice
543
+ end
544
+ end
269
545
  end
270
546
 
271
547
  describe '#get' do
@@ -300,7 +576,7 @@ describe GoCardlessPro::Services::CustomersService do
300
576
  'swedish_identity_number' => 'swedish_identity_number-input'
301
577
  }
302
578
  }.to_json,
303
- headers: { 'Content-Type' => 'application/json' }
579
+ headers: response_headers
304
580
  )
305
581
  end
306
582
 
@@ -341,7 +617,7 @@ describe GoCardlessPro::Services::CustomersService do
341
617
  'swedish_identity_number' => 'swedish_identity_number-input'
342
618
  }
343
619
  }.to_json,
344
- headers: { 'Content-Type' => 'application/json' }
620
+ headers: response_headers
345
621
  )
346
622
  end
347
623
 
@@ -355,7 +631,7 @@ describe GoCardlessPro::Services::CustomersService do
355
631
  stub_url = '/customers/:identity'.gsub(':identity', id)
356
632
  stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
357
633
  body: '',
358
- headers: { 'Content-Type' => 'application/json' }
634
+ headers: response_headers
359
635
  )
360
636
  end
361
637
 
@@ -371,6 +647,33 @@ describe GoCardlessPro::Services::CustomersService do
371
647
  expect { get_response }.to_not raise_error(/bad URI/)
372
648
  end
373
649
  end
650
+
651
+ describe 'retry behaviour' do
652
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
653
+
654
+ it 'retries timeouts' do
655
+ stub_url = '/customers/:identity'.gsub(':identity', id)
656
+
657
+ stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/)
658
+ .to_timeout.then.to_return(status: 200, headers: response_headers)
659
+
660
+ get_response
661
+ expect(stub).to have_been_requested.twice
662
+ end
663
+
664
+ it 'retries 5XX errors' do
665
+ stub_url = '/customers/:identity'.gsub(':identity', id)
666
+
667
+ stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/)
668
+ .to_return(status: 502,
669
+ headers: { 'Content-Type' => 'text/html' },
670
+ body: '<html><body>Response from Cloudflare</body></html>')
671
+ .then.to_return(status: 200, headers: response_headers)
672
+
673
+ get_response
674
+ expect(stub).to have_been_requested.twice
675
+ end
676
+ end
374
677
  end
375
678
 
376
679
  describe '#update' do
@@ -404,7 +707,7 @@ describe GoCardlessPro::Services::CustomersService do
404
707
  'swedish_identity_number' => 'swedish_identity_number-input'
405
708
  }
406
709
  }.to_json,
407
- headers: { 'Content-Type' => 'application/json' }
710
+ headers: response_headers
408
711
  )
409
712
  end
410
713
 
@@ -412,6 +715,31 @@ describe GoCardlessPro::Services::CustomersService do
412
715
  expect(put_update_response).to be_a(GoCardlessPro::Resources::Customer)
413
716
  expect(stub).to have_been_requested
414
717
  end
718
+
719
+ describe 'retry behaviour' do
720
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
721
+
722
+ it 'retries timeouts' do
723
+ stub_url = '/customers/:identity'.gsub(':identity', id)
724
+ stub = stub_request(:put, /.*api.gocardless.com#{stub_url}/)
725
+ .to_timeout.then.to_return(status: 200, headers: response_headers)
726
+
727
+ put_update_response
728
+ expect(stub).to have_been_requested.twice
729
+ end
730
+
731
+ it 'retries 5XX errors' do
732
+ stub_url = '/customers/:identity'.gsub(':identity', id)
733
+ stub = stub_request(:put, /.*api.gocardless.com#{stub_url}/)
734
+ .to_return(status: 502,
735
+ headers: { 'Content-Type' => 'text/html' },
736
+ body: '<html><body>Response from Cloudflare</body></html>')
737
+ .then.to_return(status: 200, headers: response_headers)
738
+
739
+ put_update_response
740
+ expect(stub).to have_been_requested.twice
741
+ end
742
+ end
415
743
  end
416
744
  end
417
745
  end