gocardless_pro 1.1.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,99 +1,460 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe GoCardlessPro::Resources::Creditor do
4
- describe 'initialising' do
5
- let(:data) do
6
- {
7
-
8
- 'address_line1' => 'address_line1-input',
4
+ let(:client) do
5
+ GoCardlessPro::Client.new(
6
+ access_token: 'SECRET_TOKEN'
7
+ )
8
+ end
9
9
 
10
- 'address_line2' => 'address_line2-input',
10
+ let(:response_headers) { { 'Content-Type' => 'application/json' } }
11
+
12
+ describe '#create' do
13
+ subject(:post_create_response) { client.creditors.create(params: new_resource) }
14
+ context 'with a valid request' do
15
+ let(:new_resource) do
16
+ {
17
+
18
+ 'address_line1' => 'address_line1-input',
19
+ 'address_line2' => 'address_line2-input',
20
+ 'address_line3' => 'address_line3-input',
21
+ 'city' => 'city-input',
22
+ 'country_code' => 'country_code-input',
23
+ 'created_at' => 'created_at-input',
24
+ 'id' => 'id-input',
25
+ 'links' => 'links-input',
26
+ 'logo_url' => 'logo_url-input',
27
+ 'name' => 'name-input',
28
+ 'postal_code' => 'postal_code-input',
29
+ 'region' => 'region-input',
30
+ 'scheme_identifiers' => 'scheme_identifiers-input'
31
+ }
32
+ end
11
33
 
12
- 'address_line3' => 'address_line3-input',
34
+ before do
35
+ stub_request(:post, %r{.*api.gocardless.com/creditors})
36
+ .with(
37
+ body: {
38
+ 'creditors' => {
39
+
40
+ 'address_line1' => 'address_line1-input',
41
+ 'address_line2' => 'address_line2-input',
42
+ 'address_line3' => 'address_line3-input',
43
+ 'city' => 'city-input',
44
+ 'country_code' => 'country_code-input',
45
+ 'created_at' => 'created_at-input',
46
+ 'id' => 'id-input',
47
+ 'links' => 'links-input',
48
+ 'logo_url' => 'logo_url-input',
49
+ 'name' => 'name-input',
50
+ 'postal_code' => 'postal_code-input',
51
+ 'region' => 'region-input',
52
+ 'scheme_identifiers' => 'scheme_identifiers-input'
53
+ }
54
+ }
55
+ )
56
+ .to_return(
57
+ body: {
58
+ 'creditors' =>
59
+
60
+ {
61
+
62
+ 'address_line1' => 'address_line1-input',
63
+ 'address_line2' => 'address_line2-input',
64
+ 'address_line3' => 'address_line3-input',
65
+ 'city' => 'city-input',
66
+ 'country_code' => 'country_code-input',
67
+ 'created_at' => 'created_at-input',
68
+ 'id' => 'id-input',
69
+ 'links' => 'links-input',
70
+ 'logo_url' => 'logo_url-input',
71
+ 'name' => 'name-input',
72
+ 'postal_code' => 'postal_code-input',
73
+ 'region' => 'region-input',
74
+ 'scheme_identifiers' => 'scheme_identifiers-input'
75
+ }
76
+
77
+ }.to_json,
78
+ headers: response_headers
79
+ )
80
+ end
13
81
 
14
- 'city' => 'city-input',
82
+ it 'creates and returns the resource' do
83
+ expect(post_create_response).to be_a(GoCardlessPro::Resources::Creditor)
84
+ end
85
+ end
15
86
 
16
- 'country_code' => 'country_code-input',
87
+ context 'with a request that returns a validation error' do
88
+ let(:new_resource) { {} }
89
+
90
+ before do
91
+ stub_request(:post, %r{.*api.gocardless.com/creditors}).to_return(
92
+ body: {
93
+ error: {
94
+ type: 'validation_failed',
95
+ code: 422,
96
+ errors: [
97
+ { message: 'test error message', field: 'test_field' }
98
+ ]
99
+ }
100
+ }.to_json,
101
+ headers: response_headers,
102
+ status: 422
103
+ )
104
+ end
17
105
 
18
- 'created_at' => 'created_at-input',
106
+ it 'throws the correct error' do
107
+ expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError)
108
+ end
109
+ end
19
110
 
20
- 'id' => 'id-input',
111
+ context 'with a request that returns an idempotent creation conflict error' do
112
+ let(:id) { 'ID123' }
113
+
114
+ let(:new_resource) do
115
+ {
116
+
117
+ 'address_line1' => 'address_line1-input',
118
+ 'address_line2' => 'address_line2-input',
119
+ 'address_line3' => 'address_line3-input',
120
+ 'city' => 'city-input',
121
+ 'country_code' => 'country_code-input',
122
+ 'created_at' => 'created_at-input',
123
+ 'id' => 'id-input',
124
+ 'links' => 'links-input',
125
+ 'logo_url' => 'logo_url-input',
126
+ 'name' => 'name-input',
127
+ 'postal_code' => 'postal_code-input',
128
+ 'region' => 'region-input',
129
+ 'scheme_identifiers' => 'scheme_identifiers-input'
130
+ }
131
+ end
21
132
 
22
- 'links' => {
133
+ let!(:post_stub) do
134
+ stub_request(:post, %r{.*api.gocardless.com/creditors}).to_return(
135
+ body: {
136
+ error: {
137
+ type: 'invalid_state',
138
+ code: 409,
139
+ errors: [
140
+ {
141
+ message: 'A resource has already been created with this idempotency key',
142
+ reason: 'idempotent_creation_conflict',
143
+ links: {
144
+ conflicting_resource_id: id
145
+ }
146
+ }
147
+ ]
148
+ }
149
+ }.to_json,
150
+ headers: response_headers,
151
+ status: 409
152
+ )
153
+ end
23
154
 
24
- 'default_eur_payout_account' => 'default_eur_payout_account-input',
155
+ let!(:get_stub) do
156
+ stub_url = "/creditors/#{id}"
157
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/)
158
+ .to_return(
159
+ body: {
160
+ 'creditors' => {
161
+
162
+ 'address_line1' => 'address_line1-input',
163
+ 'address_line2' => 'address_line2-input',
164
+ 'address_line3' => 'address_line3-input',
165
+ 'city' => 'city-input',
166
+ 'country_code' => 'country_code-input',
167
+ 'created_at' => 'created_at-input',
168
+ 'id' => 'id-input',
169
+ 'links' => 'links-input',
170
+ 'logo_url' => 'logo_url-input',
171
+ 'name' => 'name-input',
172
+ 'postal_code' => 'postal_code-input',
173
+ 'region' => 'region-input',
174
+ 'scheme_identifiers' => 'scheme_identifiers-input'
175
+ }
176
+ }.to_json,
177
+ headers: response_headers
178
+ )
179
+ end
25
180
 
26
- 'default_gbp_payout_account' => 'default_gbp_payout_account-input',
181
+ it 'fetches the already-created resource' do
182
+ post_create_response
183
+ expect(post_stub).to have_been_requested
184
+ expect(get_stub).to have_been_requested
185
+ end
186
+ end
187
+ end
27
188
 
28
- 'default_sek_payout_account' => 'default_sek_payout_account-input'
189
+ describe '#list' do
190
+ describe 'with no filters' do
191
+ subject(:get_list_response) { client.creditors.list }
192
+
193
+ before do
194
+ stub_request(:get, %r{.*api.gocardless.com/creditors}).to_return(
195
+ body: {
196
+ 'creditors' => [{
197
+
198
+ 'address_line1' => 'address_line1-input',
199
+ 'address_line2' => 'address_line2-input',
200
+ 'address_line3' => 'address_line3-input',
201
+ 'city' => 'city-input',
202
+ 'country_code' => 'country_code-input',
203
+ 'created_at' => 'created_at-input',
204
+ 'id' => 'id-input',
205
+ 'links' => 'links-input',
206
+ 'logo_url' => 'logo_url-input',
207
+ 'name' => 'name-input',
208
+ 'postal_code' => 'postal_code-input',
209
+ 'region' => 'region-input',
210
+ 'scheme_identifiers' => 'scheme_identifiers-input'
211
+ }],
212
+ meta: {
213
+ cursors: {
214
+ before: nil,
215
+ after: 'ABC123'
216
+ }
217
+ }
218
+ }.to_json,
219
+ headers: response_headers
220
+ )
221
+ end
29
222
 
30
- },
223
+ it 'wraps each item in the resource class' do
224
+ expect(get_list_response.records.map(&:class).uniq.first).to eq(GoCardlessPro::Resources::Creditor)
31
225
 
32
- 'logo_url' => 'logo_url-input',
226
+ expect(get_list_response.records.first.address_line1).to eq('address_line1-input')
33
227
 
34
- 'name' => 'name-input',
228
+ expect(get_list_response.records.first.address_line2).to eq('address_line2-input')
35
229
 
36
- 'postal_code' => 'postal_code-input',
230
+ expect(get_list_response.records.first.address_line3).to eq('address_line3-input')
37
231
 
38
- 'region' => 'region-input',
232
+ expect(get_list_response.records.first.city).to eq('city-input')
39
233
 
40
- 'scheme_identifiers' => 'scheme_identifiers-input'
234
+ expect(get_list_response.records.first.country_code).to eq('country_code-input')
41
235
 
42
- }
43
- end
236
+ expect(get_list_response.records.first.created_at).to eq('created_at-input')
44
237
 
45
- it 'can be initialized from an unenveloped response' do
46
- resource = described_class.new(data)
238
+ expect(get_list_response.records.first.id).to eq('id-input')
47
239
 
48
- expect(resource.address_line1).to eq('address_line1-input')
240
+ expect(get_list_response.records.first.logo_url).to eq('logo_url-input')
49
241
 
50
- expect(resource.address_line2).to eq('address_line2-input')
242
+ expect(get_list_response.records.first.name).to eq('name-input')
51
243
 
52
- expect(resource.address_line3).to eq('address_line3-input')
244
+ expect(get_list_response.records.first.postal_code).to eq('postal_code-input')
53
245
 
54
- expect(resource.city).to eq('city-input')
246
+ expect(get_list_response.records.first.region).to eq('region-input')
55
247
 
56
- expect(resource.country_code).to eq('country_code-input')
248
+ expect(get_list_response.records.first.scheme_identifiers).to eq('scheme_identifiers-input')
249
+ end
57
250
 
58
- expect(resource.created_at).to eq('created_at-input')
251
+ it 'exposes the cursors for before and after' do
252
+ expect(get_list_response.before).to eq(nil)
253
+ expect(get_list_response.after).to eq('ABC123')
254
+ end
59
255
 
60
- expect(resource.id).to eq('id-input')
256
+ specify { expect(get_list_response.api_response.headers).to eql('content-type' => 'application/json') }
257
+ end
258
+ end
61
259
 
62
- expect(resource.links.default_eur_payout_account).to eq('default_eur_payout_account-input')
260
+ describe '#all' do
261
+ let!(:first_response_stub) do
262
+ stub_request(:get, %r{.*api.gocardless.com/creditors$}).to_return(
263
+ body: {
264
+ 'creditors' => [{
265
+
266
+ 'address_line1' => 'address_line1-input',
267
+ 'address_line2' => 'address_line2-input',
268
+ 'address_line3' => 'address_line3-input',
269
+ 'city' => 'city-input',
270
+ 'country_code' => 'country_code-input',
271
+ 'created_at' => 'created_at-input',
272
+ 'id' => 'id-input',
273
+ 'links' => 'links-input',
274
+ 'logo_url' => 'logo_url-input',
275
+ 'name' => 'name-input',
276
+ 'postal_code' => 'postal_code-input',
277
+ 'region' => 'region-input',
278
+ 'scheme_identifiers' => 'scheme_identifiers-input'
279
+ }],
280
+ meta: {
281
+ cursors: { after: 'AB345' },
282
+ limit: 1
283
+ }
284
+ }.to_json,
285
+ headers: response_headers
286
+ )
287
+ end
63
288
 
64
- expect(resource.links.default_gbp_payout_account).to eq('default_gbp_payout_account-input')
289
+ let!(:second_response_stub) do
290
+ stub_request(:get, %r{.*api.gocardless.com/creditors\?after=AB345}).to_return(
291
+ body: {
292
+ 'creditors' => [{
293
+
294
+ 'address_line1' => 'address_line1-input',
295
+ 'address_line2' => 'address_line2-input',
296
+ 'address_line3' => 'address_line3-input',
297
+ 'city' => 'city-input',
298
+ 'country_code' => 'country_code-input',
299
+ 'created_at' => 'created_at-input',
300
+ 'id' => 'id-input',
301
+ 'links' => 'links-input',
302
+ 'logo_url' => 'logo_url-input',
303
+ 'name' => 'name-input',
304
+ 'postal_code' => 'postal_code-input',
305
+ 'region' => 'region-input',
306
+ 'scheme_identifiers' => 'scheme_identifiers-input'
307
+ }],
308
+ meta: {
309
+ limit: 2,
310
+ cursors: {}
311
+ }
312
+ }.to_json,
313
+ headers: response_headers
314
+ )
315
+ end
65
316
 
66
- expect(resource.links.default_sek_payout_account).to eq('default_sek_payout_account-input')
317
+ it 'automatically makes the extra requests' do
318
+ expect(client.creditors.all.to_a.length).to eq(2)
319
+ expect(first_response_stub).to have_been_requested
320
+ expect(second_response_stub).to have_been_requested
321
+ end
322
+ end
67
323
 
68
- expect(resource.logo_url).to eq('logo_url-input')
324
+ describe '#get' do
325
+ let(:id) { 'ID123' }
326
+
327
+ subject(:get_response) { client.creditors.get(id) }
328
+
329
+ context 'passing in a custom header' do
330
+ let!(:stub) do
331
+ stub_url = '/creditors/:identity'.gsub(':identity', id)
332
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/)
333
+ .with(headers: { 'Foo' => 'Bar' })
334
+ .to_return(
335
+ body: {
336
+ 'creditors' => {
337
+
338
+ 'address_line1' => 'address_line1-input',
339
+ 'address_line2' => 'address_line2-input',
340
+ 'address_line3' => 'address_line3-input',
341
+ 'city' => 'city-input',
342
+ 'country_code' => 'country_code-input',
343
+ 'created_at' => 'created_at-input',
344
+ 'id' => 'id-input',
345
+ 'links' => 'links-input',
346
+ 'logo_url' => 'logo_url-input',
347
+ 'name' => 'name-input',
348
+ 'postal_code' => 'postal_code-input',
349
+ 'region' => 'region-input',
350
+ 'scheme_identifiers' => 'scheme_identifiers-input'
351
+ }
352
+ }.to_json,
353
+ headers: response_headers
354
+ )
355
+ end
69
356
 
70
- expect(resource.name).to eq('name-input')
357
+ subject(:get_response) do
358
+ client.creditors.get(id, headers: {
359
+ 'Foo' => 'Bar'
360
+ })
361
+ end
71
362
 
72
- expect(resource.postal_code).to eq('postal_code-input')
363
+ it 'includes the header' do
364
+ get_response
365
+ expect(stub).to have_been_requested
366
+ end
367
+ end
73
368
 
74
- expect(resource.region).to eq('region-input')
369
+ context 'when there is a creditor to return' do
370
+ before do
371
+ stub_url = '/creditors/:identity'.gsub(':identity', id)
372
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
373
+ body: {
374
+ 'creditors' => {
375
+
376
+ 'address_line1' => 'address_line1-input',
377
+ 'address_line2' => 'address_line2-input',
378
+ 'address_line3' => 'address_line3-input',
379
+ 'city' => 'city-input',
380
+ 'country_code' => 'country_code-input',
381
+ 'created_at' => 'created_at-input',
382
+ 'id' => 'id-input',
383
+ 'links' => 'links-input',
384
+ 'logo_url' => 'logo_url-input',
385
+ 'name' => 'name-input',
386
+ 'postal_code' => 'postal_code-input',
387
+ 'region' => 'region-input',
388
+ 'scheme_identifiers' => 'scheme_identifiers-input'
389
+ }
390
+ }.to_json,
391
+ headers: response_headers
392
+ )
393
+ end
75
394
 
76
- expect(resource.scheme_identifiers).to eq('scheme_identifiers-input')
395
+ it 'wraps the response in a resource' do
396
+ expect(get_response).to be_a(GoCardlessPro::Resources::Creditor)
397
+ end
77
398
  end
78
399
 
79
- it 'can handle new attributes without erroring' do
80
- data['foo'] = 'bar'
81
- expect { described_class.new(data) }.to_not raise_error
82
- end
400
+ context 'when nothing is returned' do
401
+ before do
402
+ stub_url = '/creditors/:identity'.gsub(':identity', id)
403
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
404
+ body: '',
405
+ headers: response_headers
406
+ )
407
+ end
83
408
 
84
- it 'can handle new link attributes without erroring' do
85
- data['links']['foo'] = 'bar'
86
- expect { described_class.new(data) }.to_not raise_error
409
+ it 'returns nil' do
410
+ expect(get_response).to be_nil
411
+ end
87
412
  end
88
413
 
89
- it 'can handle a nil links value' do
90
- data['links'] = nil
91
- expect { described_class.new(data).links }.to_not raise_error
414
+ context "when an ID is specified which can't be included in a valid URI" do
415
+ let(:id) { '`' }
416
+
417
+ it "doesn't raise an error" do
418
+ expect { get_response }.to_not raise_error(/bad URI/)
419
+ end
92
420
  end
421
+ end
422
+
423
+ describe '#update' do
424
+ subject(:put_update_response) { client.creditors.update(id, params: update_params) }
425
+ let(:id) { 'ABC123' }
426
+
427
+ context 'with a valid request' do
428
+ let(:update_params) { { 'hello' => 'world' } }
429
+
430
+ let!(:stub) do
431
+ stub_url = '/creditors/:identity'.gsub(':identity', id)
432
+ stub_request(:put, /.*api.gocardless.com#{stub_url}/).to_return(
433
+ body: {
434
+ 'creditors' => {
435
+
436
+ 'address_line1' => 'address_line1-input',
437
+ 'address_line2' => 'address_line2-input',
438
+ 'address_line3' => 'address_line3-input',
439
+ 'city' => 'city-input',
440
+ 'country_code' => 'country_code-input',
441
+ 'created_at' => 'created_at-input',
442
+ 'id' => 'id-input',
443
+ 'links' => 'links-input',
444
+ 'logo_url' => 'logo_url-input',
445
+ 'name' => 'name-input',
446
+ 'postal_code' => 'postal_code-input',
447
+ 'region' => 'region-input',
448
+ 'scheme_identifiers' => 'scheme_identifiers-input'
449
+ }
450
+ }.to_json,
451
+ headers: response_headers
452
+ )
453
+ end
93
454
 
94
- describe '#to_h' do
95
- it 'returns a hash representing the resource' do
96
- expect(described_class.new(data).to_h).to eq(data)
455
+ it 'updates and returns the resource' do
456
+ expect(put_update_response).to be_a(GoCardlessPro::Resources::Creditor)
457
+ expect(stub).to have_been_requested
97
458
  end
98
459
  end
99
460
  end