gocardless_pro 2.25.0 → 2.27.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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +3 -3
  3. data/lib/gocardless_pro.rb +18 -0
  4. data/lib/gocardless_pro/client.rb +31 -1
  5. data/lib/gocardless_pro/resources/bank_authorisation.rb +87 -0
  6. data/lib/gocardless_pro/resources/billing_request.rb +86 -0
  7. data/lib/gocardless_pro/resources/billing_request_flow.rb +62 -0
  8. data/lib/gocardless_pro/resources/creditor.rb +2 -3
  9. data/lib/gocardless_pro/resources/institution.rb +45 -0
  10. data/lib/gocardless_pro/resources/payer_authorisation.rb +3 -0
  11. data/lib/gocardless_pro/resources/scenario_simulator.rb +42 -0
  12. data/lib/gocardless_pro/resources/webhook.rb +62 -0
  13. data/lib/gocardless_pro/services/bank_authorisations_service.rb +82 -0
  14. data/lib/gocardless_pro/services/billing_request_flows_service.rb +47 -0
  15. data/lib/gocardless_pro/services/billing_requests_service.rb +325 -0
  16. data/lib/gocardless_pro/services/institutions_service.rb +56 -0
  17. data/lib/gocardless_pro/services/payer_authorisations_service.rb +5 -5
  18. data/lib/gocardless_pro/services/scenario_simulators_service.rb +148 -0
  19. data/lib/gocardless_pro/services/subscriptions_service.rb +8 -3
  20. data/lib/gocardless_pro/services/webhooks_service.rb +113 -0
  21. data/lib/gocardless_pro/version.rb +1 -1
  22. data/spec/resources/bank_authorisation_spec.rb +259 -0
  23. data/spec/resources/billing_request_flow_spec.rb +129 -0
  24. data/spec/resources/billing_request_spec.rb +736 -0
  25. data/spec/resources/institution_spec.rb +103 -0
  26. data/spec/resources/scenario_simulator_spec.rb +63 -0
  27. data/spec/resources/webhook_spec.rb +323 -0
  28. data/spec/services/bank_authorisations_service_spec.rb +366 -0
  29. data/spec/services/billing_request_flows_service_spec.rb +152 -0
  30. data/spec/services/billing_requests_service_spec.rb +1042 -0
  31. data/spec/services/institutions_service_spec.rb +223 -0
  32. data/spec/services/scenario_simulators_service_spec.rb +74 -0
  33. data/spec/services/webhooks_service_spec.rb +545 -0
  34. metadata +39 -3
@@ -0,0 +1,366 @@
1
+ require 'spec_helper'
2
+
3
+ describe GoCardlessPro::Services::BankAuthorisationsService do
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 '#get' do
13
+ let(:id) { 'ID123' }
14
+
15
+ subject(:get_response) { client.bank_authorisations.get(id) }
16
+
17
+ context 'passing in a custom header' do
18
+ let!(:stub) do
19
+ stub_url = '/bank_authorisations/:identity'.gsub(':identity', id)
20
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).
21
+ with(headers: { 'Foo' => 'Bar' }).
22
+ to_return(
23
+ body: {
24
+ 'bank_authorisations' => {
25
+
26
+ 'authorisation_type' => 'authorisation_type-input',
27
+ 'created_at' => 'created_at-input',
28
+ 'expires_at' => 'expires_at-input',
29
+ 'id' => 'id-input',
30
+ 'last_visited_at' => 'last_visited_at-input',
31
+ 'links' => 'links-input',
32
+ 'redirect_uri' => 'redirect_uri-input',
33
+ 'short_url' => 'short_url-input',
34
+ 'url' => 'url-input',
35
+ },
36
+ }.to_json,
37
+ headers: response_headers
38
+ )
39
+ end
40
+
41
+ subject(:get_response) do
42
+ client.bank_authorisations.get(id, headers: {
43
+ 'Foo' => 'Bar',
44
+ })
45
+ end
46
+
47
+ it 'includes the header' do
48
+ get_response
49
+ expect(stub).to have_been_requested
50
+ end
51
+ end
52
+
53
+ context 'when there is a bank_authorisation to return' do
54
+ before do
55
+ stub_url = '/bank_authorisations/:identity'.gsub(':identity', id)
56
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
57
+ body: {
58
+ 'bank_authorisations' => {
59
+
60
+ 'authorisation_type' => 'authorisation_type-input',
61
+ 'created_at' => 'created_at-input',
62
+ 'expires_at' => 'expires_at-input',
63
+ 'id' => 'id-input',
64
+ 'last_visited_at' => 'last_visited_at-input',
65
+ 'links' => 'links-input',
66
+ 'redirect_uri' => 'redirect_uri-input',
67
+ 'short_url' => 'short_url-input',
68
+ 'url' => 'url-input',
69
+ },
70
+ }.to_json,
71
+ headers: response_headers
72
+ )
73
+ end
74
+
75
+ it 'wraps the response in a resource' do
76
+ expect(get_response).to be_a(GoCardlessPro::Resources::BankAuthorisation)
77
+ end
78
+ end
79
+
80
+ context 'when nothing is returned' do
81
+ before do
82
+ stub_url = '/bank_authorisations/:identity'.gsub(':identity', id)
83
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
84
+ body: '',
85
+ headers: response_headers
86
+ )
87
+ end
88
+
89
+ it 'returns nil' do
90
+ expect(get_response).to be_nil
91
+ end
92
+ end
93
+
94
+ context "when an ID is specified which can't be included in a valid URI" do
95
+ let(:id) { '`' }
96
+
97
+ it "doesn't raise an error" do
98
+ expect { get_response }.to_not raise_error(/bad URI/)
99
+ end
100
+ end
101
+
102
+ describe 'retry behaviour' do
103
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
104
+
105
+ it 'retries timeouts' do
106
+ stub_url = '/bank_authorisations/:identity'.gsub(':identity', id)
107
+
108
+ stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/).
109
+ to_timeout.then.to_return(status: 200, headers: response_headers)
110
+
111
+ get_response
112
+ expect(stub).to have_been_requested.twice
113
+ end
114
+
115
+ it 'retries 5XX errors, other than 500s' do
116
+ stub_url = '/bank_authorisations/:identity'.gsub(':identity', id)
117
+
118
+ stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/).
119
+ to_return(status: 502,
120
+ headers: { 'Content-Type' => 'text/html' },
121
+ body: '<html><body>Response from Cloudflare</body></html>').
122
+ then.to_return(status: 200, headers: response_headers)
123
+
124
+ get_response
125
+ expect(stub).to have_been_requested.twice
126
+ end
127
+
128
+ it 'retries 500 errors returned by the API' do
129
+ stub_url = '/bank_authorisations/:identity'.gsub(':identity', id)
130
+
131
+ gocardless_error = {
132
+ 'error' => {
133
+ 'message' => 'Internal server error',
134
+ 'documentation_url' => 'https://developer.gocardless.com/#gocardless',
135
+ 'errors' => [{
136
+ 'message' => 'Internal server error',
137
+ 'reason' => 'internal_server_error',
138
+ }],
139
+ 'type' => 'gocardless',
140
+ 'code' => 500,
141
+ 'request_id' => 'dummy_request_id',
142
+ 'id' => 'dummy_exception_id',
143
+ },
144
+ }
145
+
146
+ stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/).
147
+ to_return(status: 500,
148
+ headers: response_headers,
149
+ body: gocardless_error.to_json).
150
+ then.to_return(status: 200, headers: response_headers)
151
+
152
+ get_response
153
+ expect(stub).to have_been_requested.twice
154
+ end
155
+ end
156
+ end
157
+
158
+ describe '#create' do
159
+ subject(:post_create_response) { client.bank_authorisations.create(params: new_resource) }
160
+ context 'with a valid request' do
161
+ let(:new_resource) do
162
+ {
163
+
164
+ 'authorisation_type' => 'authorisation_type-input',
165
+ 'created_at' => 'created_at-input',
166
+ 'expires_at' => 'expires_at-input',
167
+ 'id' => 'id-input',
168
+ 'last_visited_at' => 'last_visited_at-input',
169
+ 'links' => 'links-input',
170
+ 'redirect_uri' => 'redirect_uri-input',
171
+ 'short_url' => 'short_url-input',
172
+ 'url' => 'url-input',
173
+ }
174
+ end
175
+
176
+ before do
177
+ stub_request(:post, %r{.*api.gocardless.com/bank_authorisations}).
178
+ with(
179
+ body: {
180
+ 'bank_authorisations' => {
181
+
182
+ 'authorisation_type' => 'authorisation_type-input',
183
+ 'created_at' => 'created_at-input',
184
+ 'expires_at' => 'expires_at-input',
185
+ 'id' => 'id-input',
186
+ 'last_visited_at' => 'last_visited_at-input',
187
+ 'links' => 'links-input',
188
+ 'redirect_uri' => 'redirect_uri-input',
189
+ 'short_url' => 'short_url-input',
190
+ 'url' => 'url-input',
191
+ },
192
+ }
193
+ ).
194
+ to_return(
195
+ body: {
196
+ 'bank_authorisations' =>
197
+
198
+ {
199
+
200
+ 'authorisation_type' => 'authorisation_type-input',
201
+ 'created_at' => 'created_at-input',
202
+ 'expires_at' => 'expires_at-input',
203
+ 'id' => 'id-input',
204
+ 'last_visited_at' => 'last_visited_at-input',
205
+ 'links' => 'links-input',
206
+ 'redirect_uri' => 'redirect_uri-input',
207
+ 'short_url' => 'short_url-input',
208
+ 'url' => 'url-input',
209
+ },
210
+
211
+ }.to_json,
212
+ headers: response_headers
213
+ )
214
+ end
215
+
216
+ it 'creates and returns the resource' do
217
+ expect(post_create_response).to be_a(GoCardlessPro::Resources::BankAuthorisation)
218
+ end
219
+
220
+ describe 'retry behaviour' do
221
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
222
+
223
+ it 'retries timeouts' do
224
+ stub = stub_request(:post, %r{.*api.gocardless.com/bank_authorisations}).
225
+ to_timeout.then.to_return(status: 200, headers: response_headers)
226
+
227
+ post_create_response
228
+ expect(stub).to have_been_requested.twice
229
+ end
230
+
231
+ it 'retries 5XX errors' do
232
+ stub = stub_request(:post, %r{.*api.gocardless.com/bank_authorisations}).
233
+ to_return(status: 502,
234
+ headers: { 'Content-Type' => 'text/html' },
235
+ body: '<html><body>Response from Cloudflare</body></html>').
236
+ then.to_return(status: 200, headers: response_headers)
237
+
238
+ post_create_response
239
+ expect(stub).to have_been_requested.twice
240
+ end
241
+ end
242
+ end
243
+
244
+ context 'with a request that returns a validation error' do
245
+ let(:new_resource) { {} }
246
+
247
+ before do
248
+ stub_request(:post, %r{.*api.gocardless.com/bank_authorisations}).to_return(
249
+ body: {
250
+ error: {
251
+ type: 'validation_failed',
252
+ code: 422,
253
+ errors: [
254
+ { message: 'test error message', field: 'test_field' },
255
+ ],
256
+ },
257
+ }.to_json,
258
+ headers: response_headers,
259
+ status: 422
260
+ )
261
+ end
262
+
263
+ it 'throws the correct error' do
264
+ expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError)
265
+ end
266
+ end
267
+
268
+ context 'with a request that returns an idempotent creation conflict error' do
269
+ let(:id) { 'ID123' }
270
+
271
+ let(:new_resource) do
272
+ {
273
+
274
+ 'authorisation_type' => 'authorisation_type-input',
275
+ 'created_at' => 'created_at-input',
276
+ 'expires_at' => 'expires_at-input',
277
+ 'id' => 'id-input',
278
+ 'last_visited_at' => 'last_visited_at-input',
279
+ 'links' => 'links-input',
280
+ 'redirect_uri' => 'redirect_uri-input',
281
+ 'short_url' => 'short_url-input',
282
+ 'url' => 'url-input',
283
+ }
284
+ end
285
+
286
+ let!(:post_stub) do
287
+ stub_request(:post, %r{.*api.gocardless.com/bank_authorisations}).to_return(
288
+ body: {
289
+ error: {
290
+ type: 'invalid_state',
291
+ code: 409,
292
+ errors: [
293
+ {
294
+ message: 'A resource has already been created with this idempotency key',
295
+ reason: 'idempotent_creation_conflict',
296
+ links: {
297
+ conflicting_resource_id: id,
298
+ },
299
+ },
300
+ ],
301
+ },
302
+ }.to_json,
303
+ headers: response_headers,
304
+ status: 409
305
+ )
306
+ end
307
+
308
+ let!(:get_stub) do
309
+ stub_url = "/bank_authorisations/#{id}"
310
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).
311
+ to_return(
312
+ body: {
313
+ 'bank_authorisations' => {
314
+
315
+ 'authorisation_type' => 'authorisation_type-input',
316
+ 'created_at' => 'created_at-input',
317
+ 'expires_at' => 'expires_at-input',
318
+ 'id' => 'id-input',
319
+ 'last_visited_at' => 'last_visited_at-input',
320
+ 'links' => 'links-input',
321
+ 'redirect_uri' => 'redirect_uri-input',
322
+ 'short_url' => 'short_url-input',
323
+ 'url' => 'url-input',
324
+ },
325
+ }.to_json,
326
+ headers: response_headers
327
+ )
328
+ end
329
+
330
+ context 'with default behaviour' do
331
+ it 'fetches the already-created resource' do
332
+ post_create_response
333
+ expect(post_stub).to have_been_requested
334
+ expect(get_stub).to have_been_requested
335
+ end
336
+ end
337
+
338
+ context 'with on_idempotency_conflict: :raise' do
339
+ let(:client) do
340
+ GoCardlessPro::Client.new(
341
+ access_token: 'SECRET_TOKEN',
342
+ on_idempotency_conflict: :raise
343
+ )
344
+ end
345
+
346
+ it 'raises an IdempotencyConflict error' do
347
+ expect { post_create_response }.
348
+ to raise_error(GoCardlessPro::IdempotencyConflict)
349
+ end
350
+ end
351
+
352
+ context 'with on_idempotency_conflict: :unknown' do
353
+ let(:client) do
354
+ GoCardlessPro::Client.new(
355
+ access_token: 'SECRET_TOKEN',
356
+ on_idempotency_conflict: :unknown
357
+ )
358
+ end
359
+
360
+ it 'raises an ArgumentError' do
361
+ expect { post_create_response }.to raise_error(ArgumentError)
362
+ end
363
+ end
364
+ end
365
+ end
366
+ end
@@ -0,0 +1,152 @@
1
+ require 'spec_helper'
2
+
3
+ describe GoCardlessPro::Services::BillingRequestFlowsService do
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.billing_request_flows.create(params: new_resource) }
14
+ context 'with a valid request' do
15
+ let(:new_resource) do
16
+ {
17
+
18
+ 'authorisation_url' => 'authorisation_url-input',
19
+ 'created_at' => 'created_at-input',
20
+ 'expires_at' => 'expires_at-input',
21
+ 'links' => 'links-input',
22
+ 'redirect_uri' => 'redirect_uri-input',
23
+ }
24
+ end
25
+
26
+ before do
27
+ stub_request(:post, %r{.*api.gocardless.com/billing_request_flows}).
28
+ with(
29
+ body: {
30
+ 'billing_request_flows' => {
31
+
32
+ 'authorisation_url' => 'authorisation_url-input',
33
+ 'created_at' => 'created_at-input',
34
+ 'expires_at' => 'expires_at-input',
35
+ 'links' => 'links-input',
36
+ 'redirect_uri' => 'redirect_uri-input',
37
+ },
38
+ }
39
+ ).
40
+ to_return(
41
+ body: {
42
+ 'billing_request_flows' =>
43
+
44
+ {
45
+
46
+ 'authorisation_url' => 'authorisation_url-input',
47
+ 'created_at' => 'created_at-input',
48
+ 'expires_at' => 'expires_at-input',
49
+ 'links' => 'links-input',
50
+ 'redirect_uri' => 'redirect_uri-input',
51
+ },
52
+
53
+ }.to_json,
54
+ headers: response_headers
55
+ )
56
+ end
57
+
58
+ it 'creates and returns the resource' do
59
+ expect(post_create_response).to be_a(GoCardlessPro::Resources::BillingRequestFlow)
60
+ end
61
+
62
+ describe 'retry behaviour' do
63
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
64
+
65
+ it 'retries timeouts' do
66
+ stub = stub_request(:post, %r{.*api.gocardless.com/billing_request_flows}).
67
+ to_timeout.then.to_return(status: 200, headers: response_headers)
68
+
69
+ post_create_response
70
+ expect(stub).to have_been_requested.twice
71
+ end
72
+
73
+ it 'retries 5XX errors' do
74
+ stub = stub_request(:post, %r{.*api.gocardless.com/billing_request_flows}).
75
+ to_return(status: 502,
76
+ headers: { 'Content-Type' => 'text/html' },
77
+ body: '<html><body>Response from Cloudflare</body></html>').
78
+ then.to_return(status: 200, headers: response_headers)
79
+
80
+ post_create_response
81
+ expect(stub).to have_been_requested.twice
82
+ end
83
+ end
84
+ end
85
+
86
+ context 'with a request that returns a validation error' do
87
+ let(:new_resource) { {} }
88
+
89
+ before do
90
+ stub_request(:post, %r{.*api.gocardless.com/billing_request_flows}).to_return(
91
+ body: {
92
+ error: {
93
+ type: 'validation_failed',
94
+ code: 422,
95
+ errors: [
96
+ { message: 'test error message', field: 'test_field' },
97
+ ],
98
+ },
99
+ }.to_json,
100
+ headers: response_headers,
101
+ status: 422
102
+ )
103
+ end
104
+
105
+ it 'throws the correct error' do
106
+ expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError)
107
+ end
108
+ end
109
+
110
+ context 'with a request that returns an idempotent creation conflict error' do
111
+ let(:id) { 'ID123' }
112
+
113
+ let(:new_resource) do
114
+ {
115
+
116
+ 'authorisation_url' => 'authorisation_url-input',
117
+ 'created_at' => 'created_at-input',
118
+ 'expires_at' => 'expires_at-input',
119
+ 'links' => 'links-input',
120
+ 'redirect_uri' => 'redirect_uri-input',
121
+ }
122
+ end
123
+
124
+ let!(:post_stub) do
125
+ stub_request(:post, %r{.*api.gocardless.com/billing_request_flows}).to_return(
126
+ body: {
127
+ error: {
128
+ type: 'invalid_state',
129
+ code: 409,
130
+ errors: [
131
+ {
132
+ message: 'A resource has already been created with this idempotency key',
133
+ reason: 'idempotent_creation_conflict',
134
+ links: {
135
+ conflicting_resource_id: id,
136
+ },
137
+ },
138
+ ],
139
+ },
140
+ }.to_json,
141
+ headers: response_headers,
142
+ status: 409
143
+ )
144
+ end
145
+
146
+ it 'raises an InvalidStateError' do
147
+ expect { post_create_response }.to raise_error(GoCardlessPro::InvalidStateError)
148
+ expect(post_stub).to have_been_requested
149
+ end
150
+ end
151
+ end
152
+ end