gocardless_pro 2.24.0 → 2.29.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +23 -4
  3. data/lib/gocardless_pro/api_service.rb +4 -0
  4. data/lib/gocardless_pro/client.rb +46 -1
  5. data/lib/gocardless_pro/error/authentication_error.rb +4 -0
  6. data/lib/gocardless_pro/error/permission_error.rb +4 -0
  7. data/lib/gocardless_pro/error/rate_limit_error.rb +4 -0
  8. data/lib/gocardless_pro/middlewares/raise_gocardless_errors.rb +12 -1
  9. data/lib/gocardless_pro/resources/bank_authorisation.rb +81 -0
  10. data/lib/gocardless_pro/resources/billing_request.rb +108 -0
  11. data/lib/gocardless_pro/resources/billing_request_flow.rb +72 -0
  12. data/lib/gocardless_pro/resources/billing_request_template.rb +68 -0
  13. data/lib/gocardless_pro/resources/block.rb +66 -0
  14. data/lib/gocardless_pro/resources/creditor.rb +2 -3
  15. data/lib/gocardless_pro/resources/event.rb +20 -0
  16. data/lib/gocardless_pro/resources/institution.rb +47 -0
  17. data/lib/gocardless_pro/resources/payer_authorisation.rb +131 -0
  18. data/lib/gocardless_pro/resources/payout_item.rb +4 -0
  19. data/lib/gocardless_pro/resources/redirect_flow.rb +2 -0
  20. data/lib/gocardless_pro/resources/scenario_simulator.rb +42 -0
  21. data/lib/gocardless_pro/resources/webhook.rb +62 -0
  22. data/lib/gocardless_pro/services/bank_authorisations_service.rb +80 -0
  23. data/lib/gocardless_pro/services/billing_request_flows_service.rb +70 -0
  24. data/lib/gocardless_pro/services/billing_request_templates_service.rb +131 -0
  25. data/lib/gocardless_pro/services/billing_requests_service.rb +352 -0
  26. data/lib/gocardless_pro/services/blocks_service.rb +223 -0
  27. data/lib/gocardless_pro/services/creditor_bank_accounts_service.rb +1 -5
  28. data/lib/gocardless_pro/services/creditors_service.rb +1 -3
  29. data/lib/gocardless_pro/services/currency_exchange_rates_service.rb +1 -1
  30. data/lib/gocardless_pro/services/customer_bank_accounts_service.rb +1 -5
  31. data/lib/gocardless_pro/services/customers_service.rb +1 -3
  32. data/lib/gocardless_pro/services/events_service.rb +1 -1
  33. data/lib/gocardless_pro/services/instalment_schedules_service.rb +1 -7
  34. data/lib/gocardless_pro/services/institutions_service.rb +56 -0
  35. data/lib/gocardless_pro/services/mandate_import_entries_service.rb +1 -1
  36. data/lib/gocardless_pro/services/mandate_imports_service.rb +0 -6
  37. data/lib/gocardless_pro/services/mandates_service.rb +1 -7
  38. data/lib/gocardless_pro/services/payer_authorisations_service.rb +202 -0
  39. data/lib/gocardless_pro/services/payments_service.rb +1 -7
  40. data/lib/gocardless_pro/services/payout_items_service.rb +1 -1
  41. data/lib/gocardless_pro/services/payouts_service.rb +1 -1
  42. data/lib/gocardless_pro/services/redirect_flows_service.rb +0 -4
  43. data/lib/gocardless_pro/services/refunds_service.rb +1 -3
  44. data/lib/gocardless_pro/services/scenario_simulators_service.rb +170 -0
  45. data/lib/gocardless_pro/services/subscriptions_service.rb +10 -13
  46. data/lib/gocardless_pro/services/tax_rates_service.rb +1 -1
  47. data/lib/gocardless_pro/services/webhooks_service.rb +111 -0
  48. data/lib/gocardless_pro/version.rb +1 -1
  49. data/lib/gocardless_pro.rb +30 -0
  50. data/spec/api_service_spec.rb +12 -1
  51. data/spec/middlewares/raise_gocardless_errors_spec.rb +30 -0
  52. data/spec/resources/bank_authorisation_spec.rb +259 -0
  53. data/spec/resources/billing_request_flow_spec.rb +219 -0
  54. data/spec/resources/billing_request_spec.rb +782 -0
  55. data/spec/resources/billing_request_template_spec.rb +502 -0
  56. data/spec/resources/block_spec.rb +560 -0
  57. data/spec/resources/institution_spec.rb +108 -0
  58. data/spec/resources/payer_authorisation_spec.rb +418 -0
  59. data/spec/resources/redirect_flow_spec.rb +9 -0
  60. data/spec/resources/scenario_simulator_spec.rb +63 -0
  61. data/spec/resources/webhook_spec.rb +323 -0
  62. data/spec/services/bank_authorisations_service_spec.rb +353 -0
  63. data/spec/services/billing_request_flows_service_spec.rb +253 -0
  64. data/spec/services/billing_request_templates_service_spec.rb +789 -0
  65. data/spec/services/billing_requests_service_spec.rb +1082 -0
  66. data/spec/services/blocks_service_spec.rb +823 -0
  67. data/spec/services/creditor_bank_accounts_service_spec.rb +0 -13
  68. data/spec/services/creditors_service_spec.rb +0 -13
  69. data/spec/services/customer_bank_accounts_service_spec.rb +0 -13
  70. data/spec/services/customers_service_spec.rb +0 -13
  71. data/spec/services/instalment_schedules_service_spec.rb +0 -26
  72. data/spec/services/institutions_service_spec.rb +232 -0
  73. data/spec/services/mandate_imports_service_spec.rb +0 -13
  74. data/spec/services/mandates_service_spec.rb +0 -13
  75. data/spec/services/payer_authorisations_service_spec.rb +559 -0
  76. data/spec/services/payments_service_spec.rb +0 -13
  77. data/spec/services/redirect_flows_service_spec.rb +9 -13
  78. data/spec/services/refunds_service_spec.rb +0 -13
  79. data/spec/services/scenario_simulators_service_spec.rb +74 -0
  80. data/spec/services/subscriptions_service_spec.rb +0 -13
  81. data/spec/services/webhooks_service_spec.rb +545 -0
  82. metadata +64 -7
@@ -0,0 +1,789 @@
1
+ require 'spec_helper'
2
+
3
+ describe GoCardlessPro::Services::BillingRequestTemplatesService 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 '#list' do
13
+ describe 'with no filters' do
14
+ subject(:get_list_response) { client.billing_request_templates.list }
15
+
16
+ let(:body) do
17
+ {
18
+ 'billing_request_templates' => [{
19
+
20
+ 'authorisation_url' => 'authorisation_url-input',
21
+ 'created_at' => 'created_at-input',
22
+ 'id' => 'id-input',
23
+ 'mandate_request_currency' => 'mandate_request_currency-input',
24
+ 'mandate_request_metadata' => 'mandate_request_metadata-input',
25
+ 'mandate_request_scheme' => 'mandate_request_scheme-input',
26
+ 'mandate_request_verify' => 'mandate_request_verify-input',
27
+ 'metadata' => 'metadata-input',
28
+ 'name' => 'name-input',
29
+ 'payment_request_amount' => 'payment_request_amount-input',
30
+ 'payment_request_currency' => 'payment_request_currency-input',
31
+ 'payment_request_description' => 'payment_request_description-input',
32
+ 'payment_request_metadata' => 'payment_request_metadata-input',
33
+ 'payment_request_scheme' => 'payment_request_scheme-input',
34
+ 'redirect_uri' => 'redirect_uri-input',
35
+ 'updated_at' => 'updated_at-input',
36
+ }],
37
+ meta: {
38
+ cursors: {
39
+ before: nil,
40
+ after: 'ABC123',
41
+ },
42
+ },
43
+ }.to_json
44
+ end
45
+
46
+ before do
47
+ stub_request(:get, %r{.*api.gocardless.com/billing_request_templates}).to_return(
48
+ body: body,
49
+ headers: response_headers
50
+ )
51
+ end
52
+
53
+ it 'wraps each item in the resource class' do
54
+ expect(get_list_response.records.map(&:class).uniq.first).to eq(GoCardlessPro::Resources::BillingRequestTemplate)
55
+
56
+ expect(get_list_response.records.first.authorisation_url).to eq('authorisation_url-input')
57
+
58
+ expect(get_list_response.records.first.created_at).to eq('created_at-input')
59
+
60
+ expect(get_list_response.records.first.id).to eq('id-input')
61
+
62
+ expect(get_list_response.records.first.mandate_request_currency).to eq('mandate_request_currency-input')
63
+
64
+ expect(get_list_response.records.first.mandate_request_metadata).to eq('mandate_request_metadata-input')
65
+
66
+ expect(get_list_response.records.first.mandate_request_scheme).to eq('mandate_request_scheme-input')
67
+
68
+ expect(get_list_response.records.first.mandate_request_verify).to eq('mandate_request_verify-input')
69
+
70
+ expect(get_list_response.records.first.metadata).to eq('metadata-input')
71
+
72
+ expect(get_list_response.records.first.name).to eq('name-input')
73
+
74
+ expect(get_list_response.records.first.payment_request_amount).to eq('payment_request_amount-input')
75
+
76
+ expect(get_list_response.records.first.payment_request_currency).to eq('payment_request_currency-input')
77
+
78
+ expect(get_list_response.records.first.payment_request_description).to eq('payment_request_description-input')
79
+
80
+ expect(get_list_response.records.first.payment_request_metadata).to eq('payment_request_metadata-input')
81
+
82
+ expect(get_list_response.records.first.payment_request_scheme).to eq('payment_request_scheme-input')
83
+
84
+ expect(get_list_response.records.first.redirect_uri).to eq('redirect_uri-input')
85
+
86
+ expect(get_list_response.records.first.updated_at).to eq('updated_at-input')
87
+ end
88
+
89
+ it 'exposes the cursors for before and after' do
90
+ expect(get_list_response.before).to eq(nil)
91
+ expect(get_list_response.after).to eq('ABC123')
92
+ end
93
+
94
+ specify { expect(get_list_response.api_response.headers).to eql('content-type' => 'application/json') }
95
+
96
+ describe 'retry behaviour' do
97
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
98
+
99
+ it 'retries timeouts' do
100
+ stub = stub_request(:get, %r{.*api.gocardless.com/billing_request_templates}).
101
+ to_timeout.then.to_return(status: 200, headers: response_headers, body: body)
102
+
103
+ get_list_response
104
+ expect(stub).to have_been_requested.twice
105
+ end
106
+
107
+ it 'retries 5XX errors' do
108
+ stub = stub_request(:get, %r{.*api.gocardless.com/billing_request_templates}).
109
+ to_return(status: 502,
110
+ headers: { 'Content-Type' => 'text/html' },
111
+ body: '<html><body>Response from Cloudflare</body></html>').
112
+ then.to_return(status: 200, headers: response_headers, body: body)
113
+
114
+ get_list_response
115
+ expect(stub).to have_been_requested.twice
116
+ end
117
+ end
118
+ end
119
+ end
120
+
121
+ describe '#all' do
122
+ let!(:first_response_stub) do
123
+ stub_request(:get, %r{.*api.gocardless.com/billing_request_templates$}).to_return(
124
+ body: {
125
+ 'billing_request_templates' => [{
126
+
127
+ 'authorisation_url' => 'authorisation_url-input',
128
+ 'created_at' => 'created_at-input',
129
+ 'id' => 'id-input',
130
+ 'mandate_request_currency' => 'mandate_request_currency-input',
131
+ 'mandate_request_metadata' => 'mandate_request_metadata-input',
132
+ 'mandate_request_scheme' => 'mandate_request_scheme-input',
133
+ 'mandate_request_verify' => 'mandate_request_verify-input',
134
+ 'metadata' => 'metadata-input',
135
+ 'name' => 'name-input',
136
+ 'payment_request_amount' => 'payment_request_amount-input',
137
+ 'payment_request_currency' => 'payment_request_currency-input',
138
+ 'payment_request_description' => 'payment_request_description-input',
139
+ 'payment_request_metadata' => 'payment_request_metadata-input',
140
+ 'payment_request_scheme' => 'payment_request_scheme-input',
141
+ 'redirect_uri' => 'redirect_uri-input',
142
+ 'updated_at' => 'updated_at-input',
143
+ }],
144
+ meta: {
145
+ cursors: { after: 'AB345' },
146
+ limit: 1,
147
+ },
148
+ }.to_json,
149
+ headers: response_headers
150
+ )
151
+ end
152
+
153
+ let!(:second_response_stub) do
154
+ stub_request(:get, %r{.*api.gocardless.com/billing_request_templates\?after=AB345}).to_return(
155
+ body: {
156
+ 'billing_request_templates' => [{
157
+
158
+ 'authorisation_url' => 'authorisation_url-input',
159
+ 'created_at' => 'created_at-input',
160
+ 'id' => 'id-input',
161
+ 'mandate_request_currency' => 'mandate_request_currency-input',
162
+ 'mandate_request_metadata' => 'mandate_request_metadata-input',
163
+ 'mandate_request_scheme' => 'mandate_request_scheme-input',
164
+ 'mandate_request_verify' => 'mandate_request_verify-input',
165
+ 'metadata' => 'metadata-input',
166
+ 'name' => 'name-input',
167
+ 'payment_request_amount' => 'payment_request_amount-input',
168
+ 'payment_request_currency' => 'payment_request_currency-input',
169
+ 'payment_request_description' => 'payment_request_description-input',
170
+ 'payment_request_metadata' => 'payment_request_metadata-input',
171
+ 'payment_request_scheme' => 'payment_request_scheme-input',
172
+ 'redirect_uri' => 'redirect_uri-input',
173
+ 'updated_at' => 'updated_at-input',
174
+ }],
175
+ meta: {
176
+ limit: 2,
177
+ cursors: {},
178
+ },
179
+ }.to_json,
180
+ headers: response_headers
181
+ )
182
+ end
183
+
184
+ it 'automatically makes the extra requests' do
185
+ expect(client.billing_request_templates.all.to_a.length).to eq(2)
186
+ expect(first_response_stub).to have_been_requested
187
+ expect(second_response_stub).to have_been_requested
188
+ end
189
+
190
+ describe 'retry behaviour' do
191
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
192
+
193
+ it 'retries timeouts' do
194
+ first_response_stub = stub_request(:get, %r{.*api.gocardless.com/billing_request_templates$}).to_return(
195
+ body: {
196
+ 'billing_request_templates' => [{
197
+
198
+ 'authorisation_url' => 'authorisation_url-input',
199
+ 'created_at' => 'created_at-input',
200
+ 'id' => 'id-input',
201
+ 'mandate_request_currency' => 'mandate_request_currency-input',
202
+ 'mandate_request_metadata' => 'mandate_request_metadata-input',
203
+ 'mandate_request_scheme' => 'mandate_request_scheme-input',
204
+ 'mandate_request_verify' => 'mandate_request_verify-input',
205
+ 'metadata' => 'metadata-input',
206
+ 'name' => 'name-input',
207
+ 'payment_request_amount' => 'payment_request_amount-input',
208
+ 'payment_request_currency' => 'payment_request_currency-input',
209
+ 'payment_request_description' => 'payment_request_description-input',
210
+ 'payment_request_metadata' => 'payment_request_metadata-input',
211
+ 'payment_request_scheme' => 'payment_request_scheme-input',
212
+ 'redirect_uri' => 'redirect_uri-input',
213
+ 'updated_at' => 'updated_at-input',
214
+ }],
215
+ meta: {
216
+ cursors: { after: 'AB345' },
217
+ limit: 1,
218
+ },
219
+ }.to_json,
220
+ headers: response_headers
221
+ )
222
+
223
+ second_response_stub = stub_request(:get, %r{.*api.gocardless.com/billing_request_templates\?after=AB345}).
224
+ to_timeout.then.
225
+ to_return(
226
+ body: {
227
+ 'billing_request_templates' => [{
228
+
229
+ 'authorisation_url' => 'authorisation_url-input',
230
+ 'created_at' => 'created_at-input',
231
+ 'id' => 'id-input',
232
+ 'mandate_request_currency' => 'mandate_request_currency-input',
233
+ 'mandate_request_metadata' => 'mandate_request_metadata-input',
234
+ 'mandate_request_scheme' => 'mandate_request_scheme-input',
235
+ 'mandate_request_verify' => 'mandate_request_verify-input',
236
+ 'metadata' => 'metadata-input',
237
+ 'name' => 'name-input',
238
+ 'payment_request_amount' => 'payment_request_amount-input',
239
+ 'payment_request_currency' => 'payment_request_currency-input',
240
+ 'payment_request_description' => 'payment_request_description-input',
241
+ 'payment_request_metadata' => 'payment_request_metadata-input',
242
+ 'payment_request_scheme' => 'payment_request_scheme-input',
243
+ 'redirect_uri' => 'redirect_uri-input',
244
+ 'updated_at' => 'updated_at-input',
245
+ }],
246
+ meta: {
247
+ limit: 2,
248
+ cursors: {},
249
+ },
250
+ }.to_json,
251
+ headers: response_headers
252
+ )
253
+
254
+ client.billing_request_templates.all.to_a
255
+
256
+ expect(first_response_stub).to have_been_requested
257
+ expect(second_response_stub).to have_been_requested.twice
258
+ end
259
+
260
+ it 'retries 5XX errors' do
261
+ first_response_stub = stub_request(:get, %r{.*api.gocardless.com/billing_request_templates$}).to_return(
262
+ body: {
263
+ 'billing_request_templates' => [{
264
+
265
+ 'authorisation_url' => 'authorisation_url-input',
266
+ 'created_at' => 'created_at-input',
267
+ 'id' => 'id-input',
268
+ 'mandate_request_currency' => 'mandate_request_currency-input',
269
+ 'mandate_request_metadata' => 'mandate_request_metadata-input',
270
+ 'mandate_request_scheme' => 'mandate_request_scheme-input',
271
+ 'mandate_request_verify' => 'mandate_request_verify-input',
272
+ 'metadata' => 'metadata-input',
273
+ 'name' => 'name-input',
274
+ 'payment_request_amount' => 'payment_request_amount-input',
275
+ 'payment_request_currency' => 'payment_request_currency-input',
276
+ 'payment_request_description' => 'payment_request_description-input',
277
+ 'payment_request_metadata' => 'payment_request_metadata-input',
278
+ 'payment_request_scheme' => 'payment_request_scheme-input',
279
+ 'redirect_uri' => 'redirect_uri-input',
280
+ 'updated_at' => 'updated_at-input',
281
+ }],
282
+ meta: {
283
+ cursors: { after: 'AB345' },
284
+ limit: 1,
285
+ },
286
+ }.to_json,
287
+ headers: response_headers
288
+ )
289
+
290
+ second_response_stub = stub_request(:get, %r{.*api.gocardless.com/billing_request_templates\?after=AB345}).
291
+ to_return(
292
+ status: 502,
293
+ body: '<html><body>Response from Cloudflare</body></html>',
294
+ headers: { 'Content-Type' => 'text/html' }
295
+ ).then.to_return(
296
+ body: {
297
+ 'billing_request_templates' => [{
298
+
299
+ 'authorisation_url' => 'authorisation_url-input',
300
+ 'created_at' => 'created_at-input',
301
+ 'id' => 'id-input',
302
+ 'mandate_request_currency' => 'mandate_request_currency-input',
303
+ 'mandate_request_metadata' => 'mandate_request_metadata-input',
304
+ 'mandate_request_scheme' => 'mandate_request_scheme-input',
305
+ 'mandate_request_verify' => 'mandate_request_verify-input',
306
+ 'metadata' => 'metadata-input',
307
+ 'name' => 'name-input',
308
+ 'payment_request_amount' => 'payment_request_amount-input',
309
+ 'payment_request_currency' => 'payment_request_currency-input',
310
+ 'payment_request_description' => 'payment_request_description-input',
311
+ 'payment_request_metadata' => 'payment_request_metadata-input',
312
+ 'payment_request_scheme' => 'payment_request_scheme-input',
313
+ 'redirect_uri' => 'redirect_uri-input',
314
+ 'updated_at' => 'updated_at-input',
315
+ }],
316
+ meta: {
317
+ limit: 2,
318
+ cursors: {},
319
+ },
320
+ }.to_json,
321
+ headers: response_headers
322
+ )
323
+
324
+ client.billing_request_templates.all.to_a
325
+
326
+ expect(first_response_stub).to have_been_requested
327
+ expect(second_response_stub).to have_been_requested.twice
328
+ end
329
+ end
330
+ end
331
+
332
+ describe '#get' do
333
+ let(:id) { 'ID123' }
334
+
335
+ subject(:get_response) { client.billing_request_templates.get(id) }
336
+
337
+ context 'passing in a custom header' do
338
+ let!(:stub) do
339
+ stub_url = '/billing_request_templates/:identity'.gsub(':identity', id)
340
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).
341
+ with(headers: { 'Foo' => 'Bar' }).
342
+ to_return(
343
+ body: {
344
+ 'billing_request_templates' => {
345
+
346
+ 'authorisation_url' => 'authorisation_url-input',
347
+ 'created_at' => 'created_at-input',
348
+ 'id' => 'id-input',
349
+ 'mandate_request_currency' => 'mandate_request_currency-input',
350
+ 'mandate_request_metadata' => 'mandate_request_metadata-input',
351
+ 'mandate_request_scheme' => 'mandate_request_scheme-input',
352
+ 'mandate_request_verify' => 'mandate_request_verify-input',
353
+ 'metadata' => 'metadata-input',
354
+ 'name' => 'name-input',
355
+ 'payment_request_amount' => 'payment_request_amount-input',
356
+ 'payment_request_currency' => 'payment_request_currency-input',
357
+ 'payment_request_description' => 'payment_request_description-input',
358
+ 'payment_request_metadata' => 'payment_request_metadata-input',
359
+ 'payment_request_scheme' => 'payment_request_scheme-input',
360
+ 'redirect_uri' => 'redirect_uri-input',
361
+ 'updated_at' => 'updated_at-input',
362
+ },
363
+ }.to_json,
364
+ headers: response_headers
365
+ )
366
+ end
367
+
368
+ subject(:get_response) do
369
+ client.billing_request_templates.get(id, headers: {
370
+ 'Foo' => 'Bar',
371
+ })
372
+ end
373
+
374
+ it 'includes the header' do
375
+ get_response
376
+ expect(stub).to have_been_requested
377
+ end
378
+ end
379
+
380
+ context 'when there is a billing_request_template to return' do
381
+ before do
382
+ stub_url = '/billing_request_templates/:identity'.gsub(':identity', id)
383
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
384
+ body: {
385
+ 'billing_request_templates' => {
386
+
387
+ 'authorisation_url' => 'authorisation_url-input',
388
+ 'created_at' => 'created_at-input',
389
+ 'id' => 'id-input',
390
+ 'mandate_request_currency' => 'mandate_request_currency-input',
391
+ 'mandate_request_metadata' => 'mandate_request_metadata-input',
392
+ 'mandate_request_scheme' => 'mandate_request_scheme-input',
393
+ 'mandate_request_verify' => 'mandate_request_verify-input',
394
+ 'metadata' => 'metadata-input',
395
+ 'name' => 'name-input',
396
+ 'payment_request_amount' => 'payment_request_amount-input',
397
+ 'payment_request_currency' => 'payment_request_currency-input',
398
+ 'payment_request_description' => 'payment_request_description-input',
399
+ 'payment_request_metadata' => 'payment_request_metadata-input',
400
+ 'payment_request_scheme' => 'payment_request_scheme-input',
401
+ 'redirect_uri' => 'redirect_uri-input',
402
+ 'updated_at' => 'updated_at-input',
403
+ },
404
+ }.to_json,
405
+ headers: response_headers
406
+ )
407
+ end
408
+
409
+ it 'wraps the response in a resource' do
410
+ expect(get_response).to be_a(GoCardlessPro::Resources::BillingRequestTemplate)
411
+ end
412
+ end
413
+
414
+ context 'when nothing is returned' do
415
+ before do
416
+ stub_url = '/billing_request_templates/:identity'.gsub(':identity', id)
417
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
418
+ body: '',
419
+ headers: response_headers
420
+ )
421
+ end
422
+
423
+ it 'returns nil' do
424
+ expect(get_response).to be_nil
425
+ end
426
+ end
427
+
428
+ context "when an ID is specified which can't be included in a valid URI" do
429
+ let(:id) { '`' }
430
+
431
+ it "doesn't raise an error" do
432
+ expect { get_response }.to_not raise_error(/bad URI/)
433
+ end
434
+ end
435
+
436
+ describe 'retry behaviour' do
437
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
438
+
439
+ it 'retries timeouts' do
440
+ stub_url = '/billing_request_templates/:identity'.gsub(':identity', id)
441
+
442
+ stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/).
443
+ to_timeout.then.to_return(status: 200, headers: response_headers)
444
+
445
+ get_response
446
+ expect(stub).to have_been_requested.twice
447
+ end
448
+
449
+ it 'retries 5XX errors, other than 500s' do
450
+ stub_url = '/billing_request_templates/:identity'.gsub(':identity', id)
451
+
452
+ stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/).
453
+ to_return(status: 502,
454
+ headers: { 'Content-Type' => 'text/html' },
455
+ body: '<html><body>Response from Cloudflare</body></html>').
456
+ then.to_return(status: 200, headers: response_headers)
457
+
458
+ get_response
459
+ expect(stub).to have_been_requested.twice
460
+ end
461
+
462
+ it 'retries 500 errors returned by the API' do
463
+ stub_url = '/billing_request_templates/:identity'.gsub(':identity', id)
464
+
465
+ gocardless_error = {
466
+ 'error' => {
467
+ 'message' => 'Internal server error',
468
+ 'documentation_url' => 'https://developer.gocardless.com/#gocardless',
469
+ 'errors' => [{
470
+ 'message' => 'Internal server error',
471
+ 'reason' => 'internal_server_error',
472
+ }],
473
+ 'type' => 'gocardless',
474
+ 'code' => 500,
475
+ 'request_id' => 'dummy_request_id',
476
+ 'id' => 'dummy_exception_id',
477
+ },
478
+ }
479
+
480
+ stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/).
481
+ to_return(status: 500,
482
+ headers: response_headers,
483
+ body: gocardless_error.to_json).
484
+ then.to_return(status: 200, headers: response_headers)
485
+
486
+ get_response
487
+ expect(stub).to have_been_requested.twice
488
+ end
489
+ end
490
+ end
491
+
492
+ describe '#create' do
493
+ subject(:post_create_response) { client.billing_request_templates.create(params: new_resource) }
494
+ context 'with a valid request' do
495
+ let(:new_resource) do
496
+ {
497
+
498
+ 'authorisation_url' => 'authorisation_url-input',
499
+ 'created_at' => 'created_at-input',
500
+ 'id' => 'id-input',
501
+ 'mandate_request_currency' => 'mandate_request_currency-input',
502
+ 'mandate_request_metadata' => 'mandate_request_metadata-input',
503
+ 'mandate_request_scheme' => 'mandate_request_scheme-input',
504
+ 'mandate_request_verify' => 'mandate_request_verify-input',
505
+ 'metadata' => 'metadata-input',
506
+ 'name' => 'name-input',
507
+ 'payment_request_amount' => 'payment_request_amount-input',
508
+ 'payment_request_currency' => 'payment_request_currency-input',
509
+ 'payment_request_description' => 'payment_request_description-input',
510
+ 'payment_request_metadata' => 'payment_request_metadata-input',
511
+ 'payment_request_scheme' => 'payment_request_scheme-input',
512
+ 'redirect_uri' => 'redirect_uri-input',
513
+ 'updated_at' => 'updated_at-input',
514
+ }
515
+ end
516
+
517
+ before do
518
+ stub_request(:post, %r{.*api.gocardless.com/billing_request_templates}).
519
+ with(
520
+ body: {
521
+ 'billing_request_templates' => {
522
+
523
+ 'authorisation_url' => 'authorisation_url-input',
524
+ 'created_at' => 'created_at-input',
525
+ 'id' => 'id-input',
526
+ 'mandate_request_currency' => 'mandate_request_currency-input',
527
+ 'mandate_request_metadata' => 'mandate_request_metadata-input',
528
+ 'mandate_request_scheme' => 'mandate_request_scheme-input',
529
+ 'mandate_request_verify' => 'mandate_request_verify-input',
530
+ 'metadata' => 'metadata-input',
531
+ 'name' => 'name-input',
532
+ 'payment_request_amount' => 'payment_request_amount-input',
533
+ 'payment_request_currency' => 'payment_request_currency-input',
534
+ 'payment_request_description' => 'payment_request_description-input',
535
+ 'payment_request_metadata' => 'payment_request_metadata-input',
536
+ 'payment_request_scheme' => 'payment_request_scheme-input',
537
+ 'redirect_uri' => 'redirect_uri-input',
538
+ 'updated_at' => 'updated_at-input',
539
+ },
540
+ }
541
+ ).
542
+ to_return(
543
+ body: {
544
+ 'billing_request_templates' =>
545
+
546
+ {
547
+
548
+ 'authorisation_url' => 'authorisation_url-input',
549
+ 'created_at' => 'created_at-input',
550
+ 'id' => 'id-input',
551
+ 'mandate_request_currency' => 'mandate_request_currency-input',
552
+ 'mandate_request_metadata' => 'mandate_request_metadata-input',
553
+ 'mandate_request_scheme' => 'mandate_request_scheme-input',
554
+ 'mandate_request_verify' => 'mandate_request_verify-input',
555
+ 'metadata' => 'metadata-input',
556
+ 'name' => 'name-input',
557
+ 'payment_request_amount' => 'payment_request_amount-input',
558
+ 'payment_request_currency' => 'payment_request_currency-input',
559
+ 'payment_request_description' => 'payment_request_description-input',
560
+ 'payment_request_metadata' => 'payment_request_metadata-input',
561
+ 'payment_request_scheme' => 'payment_request_scheme-input',
562
+ 'redirect_uri' => 'redirect_uri-input',
563
+ 'updated_at' => 'updated_at-input',
564
+ },
565
+
566
+ }.to_json,
567
+ headers: response_headers
568
+ )
569
+ end
570
+
571
+ it 'creates and returns the resource' do
572
+ expect(post_create_response).to be_a(GoCardlessPro::Resources::BillingRequestTemplate)
573
+ end
574
+
575
+ describe 'retry behaviour' do
576
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
577
+
578
+ it 'retries timeouts' do
579
+ stub = stub_request(:post, %r{.*api.gocardless.com/billing_request_templates}).
580
+ to_timeout.then.to_return(status: 200, headers: response_headers)
581
+
582
+ post_create_response
583
+ expect(stub).to have_been_requested.twice
584
+ end
585
+
586
+ it 'retries 5XX errors' do
587
+ stub = stub_request(:post, %r{.*api.gocardless.com/billing_request_templates}).
588
+ to_return(status: 502,
589
+ headers: { 'Content-Type' => 'text/html' },
590
+ body: '<html><body>Response from Cloudflare</body></html>').
591
+ then.to_return(status: 200, headers: response_headers)
592
+
593
+ post_create_response
594
+ expect(stub).to have_been_requested.twice
595
+ end
596
+ end
597
+ end
598
+
599
+ context 'with a request that returns a validation error' do
600
+ let(:new_resource) { {} }
601
+
602
+ before do
603
+ stub_request(:post, %r{.*api.gocardless.com/billing_request_templates}).to_return(
604
+ body: {
605
+ error: {
606
+ type: 'validation_failed',
607
+ code: 422,
608
+ errors: [
609
+ { message: 'test error message', field: 'test_field' },
610
+ ],
611
+ },
612
+ }.to_json,
613
+ headers: response_headers,
614
+ status: 422
615
+ )
616
+ end
617
+
618
+ it 'throws the correct error' do
619
+ expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError)
620
+ end
621
+ end
622
+
623
+ context 'with a request that returns an idempotent creation conflict error' do
624
+ let(:id) { 'ID123' }
625
+
626
+ let(:new_resource) do
627
+ {
628
+
629
+ 'authorisation_url' => 'authorisation_url-input',
630
+ 'created_at' => 'created_at-input',
631
+ 'id' => 'id-input',
632
+ 'mandate_request_currency' => 'mandate_request_currency-input',
633
+ 'mandate_request_metadata' => 'mandate_request_metadata-input',
634
+ 'mandate_request_scheme' => 'mandate_request_scheme-input',
635
+ 'mandate_request_verify' => 'mandate_request_verify-input',
636
+ 'metadata' => 'metadata-input',
637
+ 'name' => 'name-input',
638
+ 'payment_request_amount' => 'payment_request_amount-input',
639
+ 'payment_request_currency' => 'payment_request_currency-input',
640
+ 'payment_request_description' => 'payment_request_description-input',
641
+ 'payment_request_metadata' => 'payment_request_metadata-input',
642
+ 'payment_request_scheme' => 'payment_request_scheme-input',
643
+ 'redirect_uri' => 'redirect_uri-input',
644
+ 'updated_at' => 'updated_at-input',
645
+ }
646
+ end
647
+
648
+ let!(:post_stub) do
649
+ stub_request(:post, %r{.*api.gocardless.com/billing_request_templates}).to_return(
650
+ body: {
651
+ error: {
652
+ type: 'invalid_state',
653
+ code: 409,
654
+ errors: [
655
+ {
656
+ message: 'A resource has already been created with this idempotency key',
657
+ reason: 'idempotent_creation_conflict',
658
+ links: {
659
+ conflicting_resource_id: id,
660
+ },
661
+ },
662
+ ],
663
+ },
664
+ }.to_json,
665
+ headers: response_headers,
666
+ status: 409
667
+ )
668
+ end
669
+
670
+ let!(:get_stub) do
671
+ stub_url = "/billing_request_templates/#{id}"
672
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).
673
+ to_return(
674
+ body: {
675
+ 'billing_request_templates' => {
676
+
677
+ 'authorisation_url' => 'authorisation_url-input',
678
+ 'created_at' => 'created_at-input',
679
+ 'id' => 'id-input',
680
+ 'mandate_request_currency' => 'mandate_request_currency-input',
681
+ 'mandate_request_metadata' => 'mandate_request_metadata-input',
682
+ 'mandate_request_scheme' => 'mandate_request_scheme-input',
683
+ 'mandate_request_verify' => 'mandate_request_verify-input',
684
+ 'metadata' => 'metadata-input',
685
+ 'name' => 'name-input',
686
+ 'payment_request_amount' => 'payment_request_amount-input',
687
+ 'payment_request_currency' => 'payment_request_currency-input',
688
+ 'payment_request_description' => 'payment_request_description-input',
689
+ 'payment_request_metadata' => 'payment_request_metadata-input',
690
+ 'payment_request_scheme' => 'payment_request_scheme-input',
691
+ 'redirect_uri' => 'redirect_uri-input',
692
+ 'updated_at' => 'updated_at-input',
693
+ },
694
+ }.to_json,
695
+ headers: response_headers
696
+ )
697
+ end
698
+
699
+ context 'with default behaviour' do
700
+ it 'fetches the already-created resource' do
701
+ post_create_response
702
+ expect(post_stub).to have_been_requested
703
+ expect(get_stub).to have_been_requested
704
+ end
705
+ end
706
+
707
+ context 'with on_idempotency_conflict: :raise' do
708
+ let(:client) do
709
+ GoCardlessPro::Client.new(
710
+ access_token: 'SECRET_TOKEN',
711
+ on_idempotency_conflict: :raise
712
+ )
713
+ end
714
+
715
+ it 'raises an IdempotencyConflict error' do
716
+ expect { post_create_response }.
717
+ to raise_error(GoCardlessPro::IdempotencyConflict)
718
+ end
719
+ end
720
+ end
721
+ end
722
+
723
+ describe '#update' do
724
+ subject(:put_update_response) { client.billing_request_templates.update(id, params: update_params) }
725
+ let(:id) { 'ABC123' }
726
+
727
+ context 'with a valid request' do
728
+ let(:update_params) { { 'hello' => 'world' } }
729
+
730
+ let!(:stub) do
731
+ stub_url = '/billing_request_templates/:identity'.gsub(':identity', id)
732
+ stub_request(:put, /.*api.gocardless.com#{stub_url}/).to_return(
733
+ body: {
734
+ 'billing_request_templates' => {
735
+
736
+ 'authorisation_url' => 'authorisation_url-input',
737
+ 'created_at' => 'created_at-input',
738
+ 'id' => 'id-input',
739
+ 'mandate_request_currency' => 'mandate_request_currency-input',
740
+ 'mandate_request_metadata' => 'mandate_request_metadata-input',
741
+ 'mandate_request_scheme' => 'mandate_request_scheme-input',
742
+ 'mandate_request_verify' => 'mandate_request_verify-input',
743
+ 'metadata' => 'metadata-input',
744
+ 'name' => 'name-input',
745
+ 'payment_request_amount' => 'payment_request_amount-input',
746
+ 'payment_request_currency' => 'payment_request_currency-input',
747
+ 'payment_request_description' => 'payment_request_description-input',
748
+ 'payment_request_metadata' => 'payment_request_metadata-input',
749
+ 'payment_request_scheme' => 'payment_request_scheme-input',
750
+ 'redirect_uri' => 'redirect_uri-input',
751
+ 'updated_at' => 'updated_at-input',
752
+ },
753
+ }.to_json,
754
+ headers: response_headers
755
+ )
756
+ end
757
+
758
+ it 'updates and returns the resource' do
759
+ expect(put_update_response).to be_a(GoCardlessPro::Resources::BillingRequestTemplate)
760
+ expect(stub).to have_been_requested
761
+ end
762
+
763
+ describe 'retry behaviour' do
764
+ before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
765
+
766
+ it 'retries timeouts' do
767
+ stub_url = '/billing_request_templates/:identity'.gsub(':identity', id)
768
+ stub = stub_request(:put, /.*api.gocardless.com#{stub_url}/).
769
+ to_timeout.then.to_return(status: 200, headers: response_headers)
770
+
771
+ put_update_response
772
+ expect(stub).to have_been_requested.twice
773
+ end
774
+
775
+ it 'retries 5XX errors' do
776
+ stub_url = '/billing_request_templates/:identity'.gsub(':identity', id)
777
+ stub = stub_request(:put, /.*api.gocardless.com#{stub_url}/).
778
+ to_return(status: 502,
779
+ headers: { 'Content-Type' => 'text/html' },
780
+ body: '<html><body>Response from Cloudflare</body></html>').
781
+ then.to_return(status: 200, headers: response_headers)
782
+
783
+ put_update_response
784
+ expect(stub).to have_been_requested.twice
785
+ end
786
+ end
787
+ end
788
+ end
789
+ end