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,67 +1,382 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe GoCardlessPro::Resources::Refund 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.refunds.create(params: new_resource) }
14
+ context 'with a valid request' do
15
+ let(:new_resource) do
16
+ {
17
+
18
+ 'amount' => 'amount-input',
19
+ 'created_at' => 'created_at-input',
20
+ 'currency' => 'currency-input',
21
+ 'id' => 'id-input',
22
+ 'links' => 'links-input',
23
+ 'metadata' => 'metadata-input',
24
+ 'reference' => 'reference-input'
25
+ }
26
+ end
27
+
28
+ before do
29
+ stub_request(:post, %r{.*api.gocardless.com/refunds})
30
+ .with(
31
+ body: {
32
+ 'refunds' => {
33
+
34
+ 'amount' => 'amount-input',
35
+ 'created_at' => 'created_at-input',
36
+ 'currency' => 'currency-input',
37
+ 'id' => 'id-input',
38
+ 'links' => 'links-input',
39
+ 'metadata' => 'metadata-input',
40
+ 'reference' => 'reference-input'
41
+ }
42
+ }
43
+ )
44
+ .to_return(
45
+ body: {
46
+ 'refunds' =>
47
+
48
+ {
49
+
50
+ 'amount' => 'amount-input',
51
+ 'created_at' => 'created_at-input',
52
+ 'currency' => 'currency-input',
53
+ 'id' => 'id-input',
54
+ 'links' => 'links-input',
55
+ 'metadata' => 'metadata-input',
56
+ 'reference' => 'reference-input'
57
+ }
58
+
59
+ }.to_json,
60
+ headers: response_headers
61
+ )
62
+ end
63
+
64
+ it 'creates and returns the resource' do
65
+ expect(post_create_response).to be_a(GoCardlessPro::Resources::Refund)
66
+ end
67
+ end
68
+
69
+ context 'with a request that returns a validation error' do
70
+ let(:new_resource) { {} }
71
+
72
+ before do
73
+ stub_request(:post, %r{.*api.gocardless.com/refunds}).to_return(
74
+ body: {
75
+ error: {
76
+ type: 'validation_failed',
77
+ code: 422,
78
+ errors: [
79
+ { message: 'test error message', field: 'test_field' }
80
+ ]
81
+ }
82
+ }.to_json,
83
+ headers: response_headers,
84
+ status: 422
85
+ )
86
+ end
87
+
88
+ it 'throws the correct error' do
89
+ expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError)
90
+ end
91
+ end
92
+
93
+ context 'with a request that returns an idempotent creation conflict error' do
94
+ let(:id) { 'ID123' }
95
+
96
+ let(:new_resource) do
97
+ {
98
+
99
+ 'amount' => 'amount-input',
100
+ 'created_at' => 'created_at-input',
101
+ 'currency' => 'currency-input',
102
+ 'id' => 'id-input',
103
+ 'links' => 'links-input',
104
+ 'metadata' => 'metadata-input',
105
+ 'reference' => 'reference-input'
106
+ }
107
+ end
108
+
109
+ let!(:post_stub) do
110
+ stub_request(:post, %r{.*api.gocardless.com/refunds}).to_return(
111
+ body: {
112
+ error: {
113
+ type: 'invalid_state',
114
+ code: 409,
115
+ errors: [
116
+ {
117
+ message: 'A resource has already been created with this idempotency key',
118
+ reason: 'idempotent_creation_conflict',
119
+ links: {
120
+ conflicting_resource_id: id
121
+ }
122
+ }
123
+ ]
124
+ }
125
+ }.to_json,
126
+ headers: response_headers,
127
+ status: 409
128
+ )
129
+ end
130
+
131
+ let!(:get_stub) do
132
+ stub_url = "/refunds/#{id}"
133
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/)
134
+ .to_return(
135
+ body: {
136
+ 'refunds' => {
137
+
138
+ 'amount' => 'amount-input',
139
+ 'created_at' => 'created_at-input',
140
+ 'currency' => 'currency-input',
141
+ 'id' => 'id-input',
142
+ 'links' => 'links-input',
143
+ 'metadata' => 'metadata-input',
144
+ 'reference' => 'reference-input'
145
+ }
146
+ }.to_json,
147
+ headers: response_headers
148
+ )
149
+ end
150
+
151
+ it 'fetches the already-created resource' do
152
+ post_create_response
153
+ expect(post_stub).to have_been_requested
154
+ expect(get_stub).to have_been_requested
155
+ end
156
+ end
157
+ end
158
+
159
+ describe '#list' do
160
+ describe 'with no filters' do
161
+ subject(:get_list_response) { client.refunds.list }
162
+
163
+ before do
164
+ stub_request(:get, %r{.*api.gocardless.com/refunds}).to_return(
165
+ body: {
166
+ 'refunds' => [{
167
+
168
+ 'amount' => 'amount-input',
169
+ 'created_at' => 'created_at-input',
170
+ 'currency' => 'currency-input',
171
+ 'id' => 'id-input',
172
+ 'links' => 'links-input',
173
+ 'metadata' => 'metadata-input',
174
+ 'reference' => 'reference-input'
175
+ }],
176
+ meta: {
177
+ cursors: {
178
+ before: nil,
179
+ after: 'ABC123'
180
+ }
181
+ }
182
+ }.to_json,
183
+ headers: response_headers
184
+ )
185
+ end
186
+
187
+ it 'wraps each item in the resource class' do
188
+ expect(get_list_response.records.map(&:class).uniq.first).to eq(GoCardlessPro::Resources::Refund)
7
189
 
8
- 'amount' => 'amount-input',
190
+ expect(get_list_response.records.first.amount).to eq('amount-input')
9
191
 
10
- 'created_at' => 'created_at-input',
192
+ expect(get_list_response.records.first.created_at).to eq('created_at-input')
11
193
 
12
- 'currency' => 'currency-input',
194
+ expect(get_list_response.records.first.currency).to eq('currency-input')
13
195
 
14
- 'id' => 'id-input',
196
+ expect(get_list_response.records.first.id).to eq('id-input')
15
197
 
16
- 'links' => {
198
+ expect(get_list_response.records.first.metadata).to eq('metadata-input')
17
199
 
18
- 'payment' => 'payment-input'
200
+ expect(get_list_response.records.first.reference).to eq('reference-input')
201
+ end
19
202
 
20
- },
203
+ it 'exposes the cursors for before and after' do
204
+ expect(get_list_response.before).to eq(nil)
205
+ expect(get_list_response.after).to eq('ABC123')
206
+ end
21
207
 
22
- 'metadata' => 'metadata-input',
208
+ specify { expect(get_list_response.api_response.headers).to eql('content-type' => 'application/json') }
209
+ end
210
+ end
23
211
 
24
- 'reference' => 'reference-input'
212
+ describe '#all' do
213
+ let!(:first_response_stub) do
214
+ stub_request(:get, %r{.*api.gocardless.com/refunds$}).to_return(
215
+ body: {
216
+ 'refunds' => [{
25
217
 
26
- }
218
+ 'amount' => 'amount-input',
219
+ 'created_at' => 'created_at-input',
220
+ 'currency' => 'currency-input',
221
+ 'id' => 'id-input',
222
+ 'links' => 'links-input',
223
+ 'metadata' => 'metadata-input',
224
+ 'reference' => 'reference-input'
225
+ }],
226
+ meta: {
227
+ cursors: { after: 'AB345' },
228
+ limit: 1
229
+ }
230
+ }.to_json,
231
+ headers: response_headers
232
+ )
27
233
  end
28
234
 
29
- it 'can be initialized from an unenveloped response' do
30
- resource = described_class.new(data)
235
+ let!(:second_response_stub) do
236
+ stub_request(:get, %r{.*api.gocardless.com/refunds\?after=AB345}).to_return(
237
+ body: {
238
+ 'refunds' => [{
239
+
240
+ 'amount' => 'amount-input',
241
+ 'created_at' => 'created_at-input',
242
+ 'currency' => 'currency-input',
243
+ 'id' => 'id-input',
244
+ 'links' => 'links-input',
245
+ 'metadata' => 'metadata-input',
246
+ 'reference' => 'reference-input'
247
+ }],
248
+ meta: {
249
+ limit: 2,
250
+ cursors: {}
251
+ }
252
+ }.to_json,
253
+ headers: response_headers
254
+ )
255
+ end
31
256
 
32
- expect(resource.amount).to eq('amount-input')
257
+ it 'automatically makes the extra requests' do
258
+ expect(client.refunds.all.to_a.length).to eq(2)
259
+ expect(first_response_stub).to have_been_requested
260
+ expect(second_response_stub).to have_been_requested
261
+ end
262
+ end
33
263
 
34
- expect(resource.created_at).to eq('created_at-input')
264
+ describe '#get' do
265
+ let(:id) { 'ID123' }
35
266
 
36
- expect(resource.currency).to eq('currency-input')
267
+ subject(:get_response) { client.refunds.get(id) }
37
268
 
38
- expect(resource.id).to eq('id-input')
269
+ context 'passing in a custom header' do
270
+ let!(:stub) do
271
+ stub_url = '/refunds/:identity'.gsub(':identity', id)
272
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/)
273
+ .with(headers: { 'Foo' => 'Bar' })
274
+ .to_return(
275
+ body: {
276
+ 'refunds' => {
39
277
 
40
- expect(resource.links.payment).to eq('payment-input')
278
+ 'amount' => 'amount-input',
279
+ 'created_at' => 'created_at-input',
280
+ 'currency' => 'currency-input',
281
+ 'id' => 'id-input',
282
+ 'links' => 'links-input',
283
+ 'metadata' => 'metadata-input',
284
+ 'reference' => 'reference-input'
285
+ }
286
+ }.to_json,
287
+ headers: response_headers
288
+ )
289
+ end
41
290
 
42
- expect(resource.metadata).to eq('metadata-input')
291
+ subject(:get_response) do
292
+ client.refunds.get(id, headers: {
293
+ 'Foo' => 'Bar'
294
+ })
295
+ end
43
296
 
44
- expect(resource.reference).to eq('reference-input')
297
+ it 'includes the header' do
298
+ get_response
299
+ expect(stub).to have_been_requested
300
+ end
45
301
  end
46
302
 
47
- it 'can handle new attributes without erroring' do
48
- data['foo'] = 'bar'
49
- expect { described_class.new(data) }.to_not raise_error
303
+ context 'when there is a refund to return' do
304
+ before do
305
+ stub_url = '/refunds/:identity'.gsub(':identity', id)
306
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
307
+ body: {
308
+ 'refunds' => {
309
+
310
+ 'amount' => 'amount-input',
311
+ 'created_at' => 'created_at-input',
312
+ 'currency' => 'currency-input',
313
+ 'id' => 'id-input',
314
+ 'links' => 'links-input',
315
+ 'metadata' => 'metadata-input',
316
+ 'reference' => 'reference-input'
317
+ }
318
+ }.to_json,
319
+ headers: response_headers
320
+ )
321
+ end
322
+
323
+ it 'wraps the response in a resource' do
324
+ expect(get_response).to be_a(GoCardlessPro::Resources::Refund)
325
+ end
50
326
  end
51
327
 
52
- it 'can handle new link attributes without erroring' do
53
- data['links']['foo'] = 'bar'
54
- expect { described_class.new(data) }.to_not raise_error
328
+ context 'when nothing is returned' do
329
+ before do
330
+ stub_url = '/refunds/:identity'.gsub(':identity', id)
331
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
332
+ body: '',
333
+ headers: response_headers
334
+ )
335
+ end
336
+
337
+ it 'returns nil' do
338
+ expect(get_response).to be_nil
339
+ end
55
340
  end
56
341
 
57
- it 'can handle a nil links value' do
58
- data['links'] = nil
59
- expect { described_class.new(data).links }.to_not raise_error
342
+ context "when an ID is specified which can't be included in a valid URI" do
343
+ let(:id) { '`' }
344
+
345
+ it "doesn't raise an error" do
346
+ expect { get_response }.to_not raise_error(/bad URI/)
347
+ end
60
348
  end
349
+ end
350
+
351
+ describe '#update' do
352
+ subject(:put_update_response) { client.refunds.update(id, params: update_params) }
353
+ let(:id) { 'ABC123' }
354
+
355
+ context 'with a valid request' do
356
+ let(:update_params) { { 'hello' => 'world' } }
357
+
358
+ let!(:stub) do
359
+ stub_url = '/refunds/:identity'.gsub(':identity', id)
360
+ stub_request(:put, /.*api.gocardless.com#{stub_url}/).to_return(
361
+ body: {
362
+ 'refunds' => {
363
+
364
+ 'amount' => 'amount-input',
365
+ 'created_at' => 'created_at-input',
366
+ 'currency' => 'currency-input',
367
+ 'id' => 'id-input',
368
+ 'links' => 'links-input',
369
+ 'metadata' => 'metadata-input',
370
+ 'reference' => 'reference-input'
371
+ }
372
+ }.to_json,
373
+ headers: response_headers
374
+ )
375
+ end
61
376
 
62
- describe '#to_h' do
63
- it 'returns a hash representing the resource' do
64
- expect(described_class.new(data).to_h).to eq(data)
377
+ it 'updates and returns the resource' do
378
+ expect(put_update_response).to be_a(GoCardlessPro::Resources::Refund)
379
+ expect(stub).to have_been_requested
65
380
  end
66
381
  end
67
382
  end
@@ -1,103 +1,581 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe GoCardlessPro::Resources::Subscription 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
7
9
 
8
- 'amount' => 'amount-input',
10
+ let(:response_headers) { { 'Content-Type' => 'application/json' } }
11
+
12
+ describe '#create' do
13
+ subject(:post_create_response) { client.subscriptions.create(params: new_resource) }
14
+ context 'with a valid request' do
15
+ let(:new_resource) do
16
+ {
17
+
18
+ 'amount' => 'amount-input',
19
+ 'created_at' => 'created_at-input',
20
+ 'currency' => 'currency-input',
21
+ 'day_of_month' => 'day_of_month-input',
22
+ 'end_date' => 'end_date-input',
23
+ 'id' => 'id-input',
24
+ 'interval' => 'interval-input',
25
+ 'interval_unit' => 'interval_unit-input',
26
+ 'links' => 'links-input',
27
+ 'metadata' => 'metadata-input',
28
+ 'month' => 'month-input',
29
+ 'name' => 'name-input',
30
+ 'payment_reference' => 'payment_reference-input',
31
+ 'start_date' => 'start_date-input',
32
+ 'status' => 'status-input',
33
+ 'upcoming_payments' => 'upcoming_payments-input'
34
+ }
35
+ end
9
36
 
10
- 'created_at' => 'created_at-input',
37
+ before do
38
+ stub_request(:post, %r{.*api.gocardless.com/subscriptions})
39
+ .with(
40
+ body: {
41
+ 'subscriptions' => {
42
+
43
+ 'amount' => 'amount-input',
44
+ 'created_at' => 'created_at-input',
45
+ 'currency' => 'currency-input',
46
+ 'day_of_month' => 'day_of_month-input',
47
+ 'end_date' => 'end_date-input',
48
+ 'id' => 'id-input',
49
+ 'interval' => 'interval-input',
50
+ 'interval_unit' => 'interval_unit-input',
51
+ 'links' => 'links-input',
52
+ 'metadata' => 'metadata-input',
53
+ 'month' => 'month-input',
54
+ 'name' => 'name-input',
55
+ 'payment_reference' => 'payment_reference-input',
56
+ 'start_date' => 'start_date-input',
57
+ 'status' => 'status-input',
58
+ 'upcoming_payments' => 'upcoming_payments-input'
59
+ }
60
+ }
61
+ )
62
+ .to_return(
63
+ body: {
64
+ 'subscriptions' =>
65
+
66
+ {
67
+
68
+ 'amount' => 'amount-input',
69
+ 'created_at' => 'created_at-input',
70
+ 'currency' => 'currency-input',
71
+ 'day_of_month' => 'day_of_month-input',
72
+ 'end_date' => 'end_date-input',
73
+ 'id' => 'id-input',
74
+ 'interval' => 'interval-input',
75
+ 'interval_unit' => 'interval_unit-input',
76
+ 'links' => 'links-input',
77
+ 'metadata' => 'metadata-input',
78
+ 'month' => 'month-input',
79
+ 'name' => 'name-input',
80
+ 'payment_reference' => 'payment_reference-input',
81
+ 'start_date' => 'start_date-input',
82
+ 'status' => 'status-input',
83
+ 'upcoming_payments' => 'upcoming_payments-input'
84
+ }
85
+
86
+ }.to_json,
87
+ headers: response_headers
88
+ )
89
+ end
11
90
 
12
- 'currency' => 'currency-input',
91
+ it 'creates and returns the resource' do
92
+ expect(post_create_response).to be_a(GoCardlessPro::Resources::Subscription)
93
+ end
94
+ end
13
95
 
14
- 'day_of_month' => 'day_of_month-input',
96
+ context 'with a request that returns a validation error' do
97
+ let(:new_resource) { {} }
98
+
99
+ before do
100
+ stub_request(:post, %r{.*api.gocardless.com/subscriptions}).to_return(
101
+ body: {
102
+ error: {
103
+ type: 'validation_failed',
104
+ code: 422,
105
+ errors: [
106
+ { message: 'test error message', field: 'test_field' }
107
+ ]
108
+ }
109
+ }.to_json,
110
+ headers: response_headers,
111
+ status: 422
112
+ )
113
+ end
15
114
 
16
- 'end_date' => 'end_date-input',
115
+ it 'throws the correct error' do
116
+ expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError)
117
+ end
118
+ end
17
119
 
18
- 'id' => 'id-input',
120
+ context 'with a request that returns an idempotent creation conflict error' do
121
+ let(:id) { 'ID123' }
122
+
123
+ let(:new_resource) do
124
+ {
125
+
126
+ 'amount' => 'amount-input',
127
+ 'created_at' => 'created_at-input',
128
+ 'currency' => 'currency-input',
129
+ 'day_of_month' => 'day_of_month-input',
130
+ 'end_date' => 'end_date-input',
131
+ 'id' => 'id-input',
132
+ 'interval' => 'interval-input',
133
+ 'interval_unit' => 'interval_unit-input',
134
+ 'links' => 'links-input',
135
+ 'metadata' => 'metadata-input',
136
+ 'month' => 'month-input',
137
+ 'name' => 'name-input',
138
+ 'payment_reference' => 'payment_reference-input',
139
+ 'start_date' => 'start_date-input',
140
+ 'status' => 'status-input',
141
+ 'upcoming_payments' => 'upcoming_payments-input'
142
+ }
143
+ end
19
144
 
20
- 'interval' => 'interval-input',
145
+ let!(:post_stub) do
146
+ stub_request(:post, %r{.*api.gocardless.com/subscriptions}).to_return(
147
+ body: {
148
+ error: {
149
+ type: 'invalid_state',
150
+ code: 409,
151
+ errors: [
152
+ {
153
+ message: 'A resource has already been created with this idempotency key',
154
+ reason: 'idempotent_creation_conflict',
155
+ links: {
156
+ conflicting_resource_id: id
157
+ }
158
+ }
159
+ ]
160
+ }
161
+ }.to_json,
162
+ headers: response_headers,
163
+ status: 409
164
+ )
165
+ end
21
166
 
22
- 'interval_unit' => 'interval_unit-input',
167
+ let!(:get_stub) do
168
+ stub_url = "/subscriptions/#{id}"
169
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/)
170
+ .to_return(
171
+ body: {
172
+ 'subscriptions' => {
173
+
174
+ 'amount' => 'amount-input',
175
+ 'created_at' => 'created_at-input',
176
+ 'currency' => 'currency-input',
177
+ 'day_of_month' => 'day_of_month-input',
178
+ 'end_date' => 'end_date-input',
179
+ 'id' => 'id-input',
180
+ 'interval' => 'interval-input',
181
+ 'interval_unit' => 'interval_unit-input',
182
+ 'links' => 'links-input',
183
+ 'metadata' => 'metadata-input',
184
+ 'month' => 'month-input',
185
+ 'name' => 'name-input',
186
+ 'payment_reference' => 'payment_reference-input',
187
+ 'start_date' => 'start_date-input',
188
+ 'status' => 'status-input',
189
+ 'upcoming_payments' => 'upcoming_payments-input'
190
+ }
191
+ }.to_json,
192
+ headers: response_headers
193
+ )
194
+ end
23
195
 
24
- 'links' => {
196
+ it 'fetches the already-created resource' do
197
+ post_create_response
198
+ expect(post_stub).to have_been_requested
199
+ expect(get_stub).to have_been_requested
200
+ end
201
+ end
202
+ end
25
203
 
26
- 'mandate' => 'mandate-input'
204
+ describe '#list' do
205
+ describe 'with no filters' do
206
+ subject(:get_list_response) { client.subscriptions.list }
207
+
208
+ before do
209
+ stub_request(:get, %r{.*api.gocardless.com/subscriptions}).to_return(
210
+ body: {
211
+ 'subscriptions' => [{
212
+
213
+ 'amount' => 'amount-input',
214
+ 'created_at' => 'created_at-input',
215
+ 'currency' => 'currency-input',
216
+ 'day_of_month' => 'day_of_month-input',
217
+ 'end_date' => 'end_date-input',
218
+ 'id' => 'id-input',
219
+ 'interval' => 'interval-input',
220
+ 'interval_unit' => 'interval_unit-input',
221
+ 'links' => 'links-input',
222
+ 'metadata' => 'metadata-input',
223
+ 'month' => 'month-input',
224
+ 'name' => 'name-input',
225
+ 'payment_reference' => 'payment_reference-input',
226
+ 'start_date' => 'start_date-input',
227
+ 'status' => 'status-input',
228
+ 'upcoming_payments' => 'upcoming_payments-input'
229
+ }],
230
+ meta: {
231
+ cursors: {
232
+ before: nil,
233
+ after: 'ABC123'
234
+ }
235
+ }
236
+ }.to_json,
237
+ headers: response_headers
238
+ )
239
+ end
27
240
 
28
- },
241
+ it 'wraps each item in the resource class' do
242
+ expect(get_list_response.records.map(&:class).uniq.first).to eq(GoCardlessPro::Resources::Subscription)
29
243
 
30
- 'metadata' => 'metadata-input',
244
+ expect(get_list_response.records.first.amount).to eq('amount-input')
31
245
 
32
- 'month' => 'month-input',
246
+ expect(get_list_response.records.first.created_at).to eq('created_at-input')
33
247
 
34
- 'name' => 'name-input',
248
+ expect(get_list_response.records.first.currency).to eq('currency-input')
35
249
 
36
- 'payment_reference' => 'payment_reference-input',
250
+ expect(get_list_response.records.first.day_of_month).to eq('day_of_month-input')
37
251
 
38
- 'start_date' => 'start_date-input',
252
+ expect(get_list_response.records.first.end_date).to eq('end_date-input')
39
253
 
40
- 'status' => 'status-input',
254
+ expect(get_list_response.records.first.id).to eq('id-input')
41
255
 
42
- 'upcoming_payments' => 'upcoming_payments-input'
256
+ expect(get_list_response.records.first.interval).to eq('interval-input')
43
257
 
44
- }
45
- end
258
+ expect(get_list_response.records.first.interval_unit).to eq('interval_unit-input')
46
259
 
47
- it 'can be initialized from an unenveloped response' do
48
- resource = described_class.new(data)
260
+ expect(get_list_response.records.first.metadata).to eq('metadata-input')
49
261
 
50
- expect(resource.amount).to eq('amount-input')
262
+ expect(get_list_response.records.first.month).to eq('month-input')
51
263
 
52
- expect(resource.created_at).to eq('created_at-input')
264
+ expect(get_list_response.records.first.name).to eq('name-input')
53
265
 
54
- expect(resource.currency).to eq('currency-input')
266
+ expect(get_list_response.records.first.payment_reference).to eq('payment_reference-input')
55
267
 
56
- expect(resource.day_of_month).to eq('day_of_month-input')
268
+ expect(get_list_response.records.first.start_date).to eq('start_date-input')
57
269
 
58
- expect(resource.end_date).to eq('end_date-input')
270
+ expect(get_list_response.records.first.status).to eq('status-input')
59
271
 
60
- expect(resource.id).to eq('id-input')
272
+ expect(get_list_response.records.first.upcoming_payments).to eq('upcoming_payments-input')
273
+ end
61
274
 
62
- expect(resource.interval).to eq('interval-input')
275
+ it 'exposes the cursors for before and after' do
276
+ expect(get_list_response.before).to eq(nil)
277
+ expect(get_list_response.after).to eq('ABC123')
278
+ end
63
279
 
64
- expect(resource.interval_unit).to eq('interval_unit-input')
280
+ specify { expect(get_list_response.api_response.headers).to eql('content-type' => 'application/json') }
281
+ end
282
+ end
65
283
 
66
- expect(resource.links.mandate).to eq('mandate-input')
284
+ describe '#all' do
285
+ let!(:first_response_stub) do
286
+ stub_request(:get, %r{.*api.gocardless.com/subscriptions$}).to_return(
287
+ body: {
288
+ 'subscriptions' => [{
289
+
290
+ 'amount' => 'amount-input',
291
+ 'created_at' => 'created_at-input',
292
+ 'currency' => 'currency-input',
293
+ 'day_of_month' => 'day_of_month-input',
294
+ 'end_date' => 'end_date-input',
295
+ 'id' => 'id-input',
296
+ 'interval' => 'interval-input',
297
+ 'interval_unit' => 'interval_unit-input',
298
+ 'links' => 'links-input',
299
+ 'metadata' => 'metadata-input',
300
+ 'month' => 'month-input',
301
+ 'name' => 'name-input',
302
+ 'payment_reference' => 'payment_reference-input',
303
+ 'start_date' => 'start_date-input',
304
+ 'status' => 'status-input',
305
+ 'upcoming_payments' => 'upcoming_payments-input'
306
+ }],
307
+ meta: {
308
+ cursors: { after: 'AB345' },
309
+ limit: 1
310
+ }
311
+ }.to_json,
312
+ headers: response_headers
313
+ )
314
+ end
67
315
 
68
- expect(resource.metadata).to eq('metadata-input')
316
+ let!(:second_response_stub) do
317
+ stub_request(:get, %r{.*api.gocardless.com/subscriptions\?after=AB345}).to_return(
318
+ body: {
319
+ 'subscriptions' => [{
320
+
321
+ 'amount' => 'amount-input',
322
+ 'created_at' => 'created_at-input',
323
+ 'currency' => 'currency-input',
324
+ 'day_of_month' => 'day_of_month-input',
325
+ 'end_date' => 'end_date-input',
326
+ 'id' => 'id-input',
327
+ 'interval' => 'interval-input',
328
+ 'interval_unit' => 'interval_unit-input',
329
+ 'links' => 'links-input',
330
+ 'metadata' => 'metadata-input',
331
+ 'month' => 'month-input',
332
+ 'name' => 'name-input',
333
+ 'payment_reference' => 'payment_reference-input',
334
+ 'start_date' => 'start_date-input',
335
+ 'status' => 'status-input',
336
+ 'upcoming_payments' => 'upcoming_payments-input'
337
+ }],
338
+ meta: {
339
+ limit: 2,
340
+ cursors: {}
341
+ }
342
+ }.to_json,
343
+ headers: response_headers
344
+ )
345
+ end
69
346
 
70
- expect(resource.month).to eq('month-input')
347
+ it 'automatically makes the extra requests' do
348
+ expect(client.subscriptions.all.to_a.length).to eq(2)
349
+ expect(first_response_stub).to have_been_requested
350
+ expect(second_response_stub).to have_been_requested
351
+ end
352
+ end
353
+
354
+ describe '#get' do
355
+ let(:id) { 'ID123' }
356
+
357
+ subject(:get_response) { client.subscriptions.get(id) }
358
+
359
+ context 'passing in a custom header' do
360
+ let!(:stub) do
361
+ stub_url = '/subscriptions/:identity'.gsub(':identity', id)
362
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/)
363
+ .with(headers: { 'Foo' => 'Bar' })
364
+ .to_return(
365
+ body: {
366
+ 'subscriptions' => {
367
+
368
+ 'amount' => 'amount-input',
369
+ 'created_at' => 'created_at-input',
370
+ 'currency' => 'currency-input',
371
+ 'day_of_month' => 'day_of_month-input',
372
+ 'end_date' => 'end_date-input',
373
+ 'id' => 'id-input',
374
+ 'interval' => 'interval-input',
375
+ 'interval_unit' => 'interval_unit-input',
376
+ 'links' => 'links-input',
377
+ 'metadata' => 'metadata-input',
378
+ 'month' => 'month-input',
379
+ 'name' => 'name-input',
380
+ 'payment_reference' => 'payment_reference-input',
381
+ 'start_date' => 'start_date-input',
382
+ 'status' => 'status-input',
383
+ 'upcoming_payments' => 'upcoming_payments-input'
384
+ }
385
+ }.to_json,
386
+ headers: response_headers
387
+ )
388
+ end
71
389
 
72
- expect(resource.name).to eq('name-input')
390
+ subject(:get_response) do
391
+ client.subscriptions.get(id, headers: {
392
+ 'Foo' => 'Bar'
393
+ })
394
+ end
395
+
396
+ it 'includes the header' do
397
+ get_response
398
+ expect(stub).to have_been_requested
399
+ end
400
+ end
401
+
402
+ context 'when there is a subscription to return' do
403
+ before do
404
+ stub_url = '/subscriptions/:identity'.gsub(':identity', id)
405
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
406
+ body: {
407
+ 'subscriptions' => {
408
+
409
+ 'amount' => 'amount-input',
410
+ 'created_at' => 'created_at-input',
411
+ 'currency' => 'currency-input',
412
+ 'day_of_month' => 'day_of_month-input',
413
+ 'end_date' => 'end_date-input',
414
+ 'id' => 'id-input',
415
+ 'interval' => 'interval-input',
416
+ 'interval_unit' => 'interval_unit-input',
417
+ 'links' => 'links-input',
418
+ 'metadata' => 'metadata-input',
419
+ 'month' => 'month-input',
420
+ 'name' => 'name-input',
421
+ 'payment_reference' => 'payment_reference-input',
422
+ 'start_date' => 'start_date-input',
423
+ 'status' => 'status-input',
424
+ 'upcoming_payments' => 'upcoming_payments-input'
425
+ }
426
+ }.to_json,
427
+ headers: response_headers
428
+ )
429
+ end
430
+
431
+ it 'wraps the response in a resource' do
432
+ expect(get_response).to be_a(GoCardlessPro::Resources::Subscription)
433
+ end
434
+ end
73
435
 
74
- expect(resource.payment_reference).to eq('payment_reference-input')
436
+ context 'when nothing is returned' do
437
+ before do
438
+ stub_url = '/subscriptions/:identity'.gsub(':identity', id)
439
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
440
+ body: '',
441
+ headers: response_headers
442
+ )
443
+ end
75
444
 
76
- expect(resource.start_date).to eq('start_date-input')
445
+ it 'returns nil' do
446
+ expect(get_response).to be_nil
447
+ end
448
+ end
77
449
 
78
- expect(resource.status).to eq('status-input')
450
+ context "when an ID is specified which can't be included in a valid URI" do
451
+ let(:id) { '`' }
79
452
 
80
- expect(resource.upcoming_payments).to eq('upcoming_payments-input')
453
+ it "doesn't raise an error" do
454
+ expect { get_response }.to_not raise_error(/bad URI/)
455
+ end
81
456
  end
457
+ end
82
458
 
83
- it 'can handle new attributes without erroring' do
84
- data['foo'] = 'bar'
85
- expect { described_class.new(data) }.to_not raise_error
459
+ describe '#update' do
460
+ subject(:put_update_response) { client.subscriptions.update(id, params: update_params) }
461
+ let(:id) { 'ABC123' }
462
+
463
+ context 'with a valid request' do
464
+ let(:update_params) { { 'hello' => 'world' } }
465
+
466
+ let!(:stub) do
467
+ stub_url = '/subscriptions/:identity'.gsub(':identity', id)
468
+ stub_request(:put, /.*api.gocardless.com#{stub_url}/).to_return(
469
+ body: {
470
+ 'subscriptions' => {
471
+
472
+ 'amount' => 'amount-input',
473
+ 'created_at' => 'created_at-input',
474
+ 'currency' => 'currency-input',
475
+ 'day_of_month' => 'day_of_month-input',
476
+ 'end_date' => 'end_date-input',
477
+ 'id' => 'id-input',
478
+ 'interval' => 'interval-input',
479
+ 'interval_unit' => 'interval_unit-input',
480
+ 'links' => 'links-input',
481
+ 'metadata' => 'metadata-input',
482
+ 'month' => 'month-input',
483
+ 'name' => 'name-input',
484
+ 'payment_reference' => 'payment_reference-input',
485
+ 'start_date' => 'start_date-input',
486
+ 'status' => 'status-input',
487
+ 'upcoming_payments' => 'upcoming_payments-input'
488
+ }
489
+ }.to_json,
490
+ headers: response_headers
491
+ )
492
+ end
493
+
494
+ it 'updates and returns the resource' do
495
+ expect(put_update_response).to be_a(GoCardlessPro::Resources::Subscription)
496
+ expect(stub).to have_been_requested
497
+ end
86
498
  end
499
+ end
87
500
 
88
- it 'can handle new link attributes without erroring' do
89
- data['links']['foo'] = 'bar'
90
- expect { described_class.new(data) }.to_not raise_error
501
+ describe '#cancel' do
502
+ subject(:post_response) { client.subscriptions.cancel(resource_id) }
503
+
504
+ let(:resource_id) { 'ABC123' }
505
+
506
+ let!(:stub) do
507
+ # /subscriptions/%v/actions/cancel
508
+ stub_url = '/subscriptions/:identity/actions/cancel'.gsub(':identity', resource_id)
509
+ stub_request(:post, /.*api.gocardless.com#{stub_url}/).to_return(
510
+ body: {
511
+ 'subscriptions' => {
512
+
513
+ 'amount' => 'amount-input',
514
+ 'created_at' => 'created_at-input',
515
+ 'currency' => 'currency-input',
516
+ 'day_of_month' => 'day_of_month-input',
517
+ 'end_date' => 'end_date-input',
518
+ 'id' => 'id-input',
519
+ 'interval' => 'interval-input',
520
+ 'interval_unit' => 'interval_unit-input',
521
+ 'links' => 'links-input',
522
+ 'metadata' => 'metadata-input',
523
+ 'month' => 'month-input',
524
+ 'name' => 'name-input',
525
+ 'payment_reference' => 'payment_reference-input',
526
+ 'start_date' => 'start_date-input',
527
+ 'status' => 'status-input',
528
+ 'upcoming_payments' => 'upcoming_payments-input'
529
+ }
530
+ }.to_json,
531
+ headers: response_headers
532
+ )
91
533
  end
92
534
 
93
- it 'can handle a nil links value' do
94
- data['links'] = nil
95
- expect { described_class.new(data).links }.to_not raise_error
535
+ it 'wraps the response and calls the right endpoint' do
536
+ expect(post_response).to be_a(GoCardlessPro::Resources::Subscription)
537
+
538
+ expect(stub).to have_been_requested
96
539
  end
97
540
 
98
- describe '#to_h' do
99
- it 'returns a hash representing the resource' do
100
- expect(described_class.new(data).to_h).to eq(data)
541
+ context 'when the request needs a body and custom header' do
542
+ let(:body) { { foo: 'bar' } }
543
+ let(:headers) { { 'Foo' => 'Bar' } }
544
+ subject(:post_response) { client.subscriptions.cancel(resource_id, body, headers) }
545
+
546
+ let(:resource_id) { 'ABC123' }
547
+
548
+ let!(:stub) do
549
+ # /subscriptions/%v/actions/cancel
550
+ stub_url = '/subscriptions/:identity/actions/cancel'.gsub(':identity', resource_id)
551
+ stub_request(:post, /.*api.gocardless.com#{stub_url}/)
552
+ .with(
553
+ body: { foo: 'bar' },
554
+ headers: { 'Foo' => 'Bar' }
555
+ ).to_return(
556
+ body: {
557
+ 'subscriptions' => {
558
+
559
+ 'amount' => 'amount-input',
560
+ 'created_at' => 'created_at-input',
561
+ 'currency' => 'currency-input',
562
+ 'day_of_month' => 'day_of_month-input',
563
+ 'end_date' => 'end_date-input',
564
+ 'id' => 'id-input',
565
+ 'interval' => 'interval-input',
566
+ 'interval_unit' => 'interval_unit-input',
567
+ 'links' => 'links-input',
568
+ 'metadata' => 'metadata-input',
569
+ 'month' => 'month-input',
570
+ 'name' => 'name-input',
571
+ 'payment_reference' => 'payment_reference-input',
572
+ 'start_date' => 'start_date-input',
573
+ 'status' => 'status-input',
574
+ 'upcoming_payments' => 'upcoming_payments-input'
575
+ }
576
+ }.to_json,
577
+ headers: response_headers
578
+ )
101
579
  end
102
580
  end
103
581
  end