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,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