gocardless_pro 2.22.1 → 2.27.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +3 -3
  3. data/lib/gocardless_pro.rb +24 -0
  4. data/lib/gocardless_pro/client.rb +41 -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/event.rb +12 -0
  10. data/lib/gocardless_pro/resources/institution.rb +45 -0
  11. data/lib/gocardless_pro/resources/payer_authorisation.rb +122 -0
  12. data/lib/gocardless_pro/resources/payout.rb +2 -0
  13. data/lib/gocardless_pro/resources/payout_item.rb +6 -0
  14. data/lib/gocardless_pro/resources/scenario_simulator.rb +42 -0
  15. data/lib/gocardless_pro/resources/tax_rate.rb +51 -0
  16. data/lib/gocardless_pro/resources/webhook.rb +62 -0
  17. data/lib/gocardless_pro/services/bank_authorisations_service.rb +82 -0
  18. data/lib/gocardless_pro/services/billing_request_flows_service.rb +47 -0
  19. data/lib/gocardless_pro/services/billing_requests_service.rb +325 -0
  20. data/lib/gocardless_pro/services/institutions_service.rb +56 -0
  21. data/lib/gocardless_pro/services/payer_authorisations_service.rb +208 -0
  22. data/lib/gocardless_pro/services/scenario_simulators_service.rb +148 -0
  23. data/lib/gocardless_pro/services/subscriptions_service.rb +9 -4
  24. data/lib/gocardless_pro/services/tax_rates_service.rb +74 -0
  25. data/lib/gocardless_pro/services/webhooks_service.rb +113 -0
  26. data/lib/gocardless_pro/version.rb +1 -1
  27. data/spec/resources/bank_authorisation_spec.rb +259 -0
  28. data/spec/resources/billing_request_flow_spec.rb +129 -0
  29. data/spec/resources/billing_request_spec.rb +736 -0
  30. data/spec/resources/institution_spec.rb +103 -0
  31. data/spec/resources/payer_authorisation_spec.rb +418 -0
  32. data/spec/resources/payout_item_spec.rb +5 -0
  33. data/spec/resources/payout_spec.rb +8 -0
  34. data/spec/resources/scenario_simulator_spec.rb +63 -0
  35. data/spec/resources/tax_rate_spec.rb +198 -0
  36. data/spec/resources/webhook_spec.rb +323 -0
  37. data/spec/services/bank_authorisations_service_spec.rb +366 -0
  38. data/spec/services/billing_request_flows_service_spec.rb +152 -0
  39. data/spec/services/billing_requests_service_spec.rb +1042 -0
  40. data/spec/services/institutions_service_spec.rb +223 -0
  41. data/spec/services/payer_authorisations_service_spec.rb +572 -0
  42. data/spec/services/payout_items_service_spec.rb +9 -0
  43. data/spec/services/payouts_service_spec.rb +12 -0
  44. data/spec/services/scenario_simulators_service_spec.rb +74 -0
  45. data/spec/services/tax_rates_service_spec.rb +381 -0
  46. data/spec/services/webhooks_service_spec.rb +545 -0
  47. metadata +51 -3
@@ -0,0 +1,47 @@
1
+ require_relative './base_service'
2
+
3
+ # encoding: utf-8
4
+ #
5
+ # This client is automatically generated from a template and JSON schema definition.
6
+ # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing.
7
+ #
8
+
9
+ module GoCardlessPro
10
+ module Services
11
+ # Service for making requests to the BillingRequestFlow endpoints
12
+ class BillingRequestFlowsService < BaseService
13
+ # Creates a new billing request flow.
14
+ # Example URL: /billing_request_flows
15
+ # @param options [Hash] parameters as a hash, under a params key.
16
+ def create(options = {})
17
+ path = '/billing_request_flows'
18
+
19
+ params = options.delete(:params) || {}
20
+ options[:params] = {}
21
+ options[:params][envelope_key] = params
22
+
23
+ options[:retry_failures] = true
24
+
25
+ response = make_request(:post, path, options)
26
+
27
+ return if response.body.nil?
28
+
29
+ Resources::BillingRequestFlow.new(unenvelope_body(response.body), response)
30
+ end
31
+
32
+ private
33
+
34
+ # Unenvelope the response of the body using the service's `envelope_key`
35
+ #
36
+ # @param body [Hash]
37
+ def unenvelope_body(body)
38
+ body[envelope_key] || body['data']
39
+ end
40
+
41
+ # return the key which API responses will envelope data under
42
+ def envelope_key
43
+ 'billing_request_flows'
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,325 @@
1
+ require_relative './base_service'
2
+
3
+ # encoding: utf-8
4
+ #
5
+ # This client is automatically generated from a template and JSON schema definition.
6
+ # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing.
7
+ #
8
+
9
+ module GoCardlessPro
10
+ module Services
11
+ # Service for making requests to the BillingRequest endpoints
12
+ class BillingRequestsService < BaseService
13
+ # Returns a [cursor-paginated](#api-usage-cursor-pagination) list of your
14
+ # billing_requests.
15
+ # Example URL: /billing_requests
16
+ # @param options [Hash] parameters as a hash, under a params key.
17
+ def list(options = {})
18
+ path = '/billing_requests'
19
+
20
+ options[:retry_failures] = true
21
+
22
+ response = make_request(:get, path, options)
23
+
24
+ ListResponse.new(
25
+ response: response,
26
+ unenveloped_body: unenvelope_body(response.body),
27
+ resource_class: Resources::BillingRequest
28
+ )
29
+ end
30
+
31
+ # Get a lazily enumerated list of all the items returned. This is simmilar to the `list` method but will paginate for you automatically.
32
+ #
33
+ # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
34
+ # Otherwise they will be the body of the request.
35
+ def all(options = {})
36
+ Paginator.new(
37
+ service: self,
38
+ options: options
39
+ ).enumerator
40
+ end
41
+
42
+ #
43
+ # Example URL: /billing_requests
44
+ # @param options [Hash] parameters as a hash, under a params key.
45
+ def create(options = {})
46
+ path = '/billing_requests'
47
+
48
+ params = options.delete(:params) || {}
49
+ options[:params] = {}
50
+ options[:params][envelope_key] = params
51
+
52
+ options[:retry_failures] = true
53
+
54
+ begin
55
+ response = make_request(:post, path, options)
56
+
57
+ # Response doesn't raise any errors until #body is called
58
+ response.tap(&:body)
59
+ rescue InvalidStateError => e
60
+ if e.idempotent_creation_conflict?
61
+ case @api_service.on_idempotency_conflict
62
+ when :raise
63
+ raise IdempotencyConflict, e.error
64
+ when :fetch
65
+ return get(e.conflicting_resource_id)
66
+ else
67
+ raise ArgumentError, 'Unknown mode for :on_idempotency_conflict'
68
+ end
69
+ end
70
+
71
+ raise e
72
+ end
73
+
74
+ return if response.body.nil?
75
+
76
+ Resources::BillingRequest.new(unenvelope_body(response.body), response)
77
+ end
78
+
79
+ # Fetches a billing request
80
+ # Example URL: /billing_requests/:identity
81
+ #
82
+ # @param identity # Unique identifier, beginning with "PY".
83
+ # @param options [Hash] parameters as a hash, under a params key.
84
+ def get(identity, options = {})
85
+ path = sub_url('/billing_requests/:identity', 'identity' => identity)
86
+
87
+ options[:retry_failures] = true
88
+
89
+ response = make_request(:get, path, options)
90
+
91
+ return if response.body.nil?
92
+
93
+ Resources::BillingRequest.new(unenvelope_body(response.body), response)
94
+ end
95
+
96
+ # If the billing request has a pending <code>collect_customer_details</code>
97
+ # action, this endpoint can be used to collect the details in order to
98
+ # complete it.
99
+ #
100
+ # The endpoint takes the same payload as Customers, but checks that the
101
+ # customer fields are populated correctly for the billing request scheme.
102
+ #
103
+ # Whatever is provided to this endpoint is used to update the referenced
104
+ # customer, and will take effect immediately after the request is
105
+ # successful.
106
+ # Example URL: /billing_requests/:identity/actions/collect_customer_details
107
+ #
108
+ # @param identity # Unique identifier, beginning with "PY".
109
+ # @param options [Hash] parameters as a hash, under a params key.
110
+ def collect_customer_details(identity, options = {})
111
+ path = sub_url('/billing_requests/:identity/actions/collect_customer_details', 'identity' => identity)
112
+
113
+ params = options.delete(:params) || {}
114
+ options[:params] = {}
115
+ options[:params]['data'] = params
116
+
117
+ options[:retry_failures] = false
118
+
119
+ begin
120
+ response = make_request(:post, path, options)
121
+
122
+ # Response doesn't raise any errors until #body is called
123
+ response.tap(&:body)
124
+ rescue InvalidStateError => e
125
+ if e.idempotent_creation_conflict?
126
+ case @api_service.on_idempotency_conflict
127
+ when :raise
128
+ raise IdempotencyConflict, e.error
129
+ when :fetch
130
+ return get(e.conflicting_resource_id)
131
+ else
132
+ raise ArgumentError, 'Unknown mode for :on_idempotency_conflict'
133
+ end
134
+ end
135
+
136
+ raise e
137
+ end
138
+
139
+ return if response.body.nil?
140
+
141
+ Resources::BillingRequest.new(unenvelope_body(response.body), response)
142
+ end
143
+
144
+ # If the billing request has a pending
145
+ # <code>collect_bank_account_details</code> action, this endpoint can be
146
+ # used to collect the details in order to complete it.
147
+ #
148
+ # The endpoint takes the same payload as Customer Bank Accounts, but check
149
+ # the bank account is valid for the billing request scheme before creating
150
+ # and attaching it.
151
+ # Example URL: /billing_requests/:identity/actions/collect_bank_account_details
152
+ #
153
+ # @param identity # Unique identifier, beginning with "PY".
154
+ # @param options [Hash] parameters as a hash, under a params key.
155
+ def collect_bank_account_details(identity, options = {})
156
+ path = sub_url('/billing_requests/:identity/actions/collect_bank_account_details', 'identity' => identity)
157
+
158
+ params = options.delete(:params) || {}
159
+ options[:params] = {}
160
+ options[:params]['data'] = params
161
+
162
+ options[:retry_failures] = false
163
+
164
+ begin
165
+ response = make_request(:post, path, options)
166
+
167
+ # Response doesn't raise any errors until #body is called
168
+ response.tap(&:body)
169
+ rescue InvalidStateError => e
170
+ if e.idempotent_creation_conflict?
171
+ case @api_service.on_idempotency_conflict
172
+ when :raise
173
+ raise IdempotencyConflict, e.error
174
+ when :fetch
175
+ return get(e.conflicting_resource_id)
176
+ else
177
+ raise ArgumentError, 'Unknown mode for :on_idempotency_conflict'
178
+ end
179
+ end
180
+
181
+ raise e
182
+ end
183
+
184
+ return if response.body.nil?
185
+
186
+ Resources::BillingRequest.new(unenvelope_body(response.body), response)
187
+ end
188
+
189
+ # If a billing request is ready to be fulfilled, call this endpoint to cause
190
+ # it to fulfil, executing the payment.
191
+ # Example URL: /billing_requests/:identity/actions/fulfil
192
+ #
193
+ # @param identity # Unique identifier, beginning with "PY".
194
+ # @param options [Hash] parameters as a hash, under a params key.
195
+ def fulfil(identity, options = {})
196
+ path = sub_url('/billing_requests/:identity/actions/fulfil', 'identity' => identity)
197
+
198
+ params = options.delete(:params) || {}
199
+ options[:params] = {}
200
+ options[:params]['data'] = params
201
+
202
+ options[:retry_failures] = false
203
+
204
+ begin
205
+ response = make_request(:post, path, options)
206
+
207
+ # Response doesn't raise any errors until #body is called
208
+ response.tap(&:body)
209
+ rescue InvalidStateError => e
210
+ if e.idempotent_creation_conflict?
211
+ case @api_service.on_idempotency_conflict
212
+ when :raise
213
+ raise IdempotencyConflict, e.error
214
+ when :fetch
215
+ return get(e.conflicting_resource_id)
216
+ else
217
+ raise ArgumentError, 'Unknown mode for :on_idempotency_conflict'
218
+ end
219
+ end
220
+
221
+ raise e
222
+ end
223
+
224
+ return if response.body.nil?
225
+
226
+ Resources::BillingRequest.new(unenvelope_body(response.body), response)
227
+ end
228
+
229
+ # Immediately cancels a billing request, causing all billing request flows
230
+ # to expire.
231
+ # Example URL: /billing_requests/:identity/actions/cancel
232
+ #
233
+ # @param identity # Unique identifier, beginning with "PY".
234
+ # @param options [Hash] parameters as a hash, under a params key.
235
+ def cancel(identity, options = {})
236
+ path = sub_url('/billing_requests/:identity/actions/cancel', 'identity' => identity)
237
+
238
+ params = options.delete(:params) || {}
239
+ options[:params] = {}
240
+ options[:params]['data'] = params
241
+
242
+ options[:retry_failures] = false
243
+
244
+ begin
245
+ response = make_request(:post, path, options)
246
+
247
+ # Response doesn't raise any errors until #body is called
248
+ response.tap(&:body)
249
+ rescue InvalidStateError => e
250
+ if e.idempotent_creation_conflict?
251
+ case @api_service.on_idempotency_conflict
252
+ when :raise
253
+ raise IdempotencyConflict, e.error
254
+ when :fetch
255
+ return get(e.conflicting_resource_id)
256
+ else
257
+ raise ArgumentError, 'Unknown mode for :on_idempotency_conflict'
258
+ end
259
+ end
260
+
261
+ raise e
262
+ end
263
+
264
+ return if response.body.nil?
265
+
266
+ Resources::BillingRequest.new(unenvelope_body(response.body), response)
267
+ end
268
+
269
+ # Notifies the customer linked to the billing request, asking them to authorise
270
+ # it.
271
+ # Currently, the customer can only be notified by email.
272
+ # Example URL: /billing_requests/:identity/actions/notify
273
+ #
274
+ # @param identity # Unique identifier, beginning with "PY".
275
+ # @param options [Hash] parameters as a hash, under a params key.
276
+ def notify(identity, options = {})
277
+ path = sub_url('/billing_requests/:identity/actions/notify', 'identity' => identity)
278
+
279
+ params = options.delete(:params) || {}
280
+ options[:params] = {}
281
+ options[:params]['data'] = params
282
+
283
+ options[:retry_failures] = false
284
+
285
+ begin
286
+ response = make_request(:post, path, options)
287
+
288
+ # Response doesn't raise any errors until #body is called
289
+ response.tap(&:body)
290
+ rescue InvalidStateError => e
291
+ if e.idempotent_creation_conflict?
292
+ case @api_service.on_idempotency_conflict
293
+ when :raise
294
+ raise IdempotencyConflict, e.error
295
+ when :fetch
296
+ return get(e.conflicting_resource_id)
297
+ else
298
+ raise ArgumentError, 'Unknown mode for :on_idempotency_conflict'
299
+ end
300
+ end
301
+
302
+ raise e
303
+ end
304
+
305
+ return if response.body.nil?
306
+
307
+ Resources::BillingRequest.new(unenvelope_body(response.body), response)
308
+ end
309
+
310
+ private
311
+
312
+ # Unenvelope the response of the body using the service's `envelope_key`
313
+ #
314
+ # @param body [Hash]
315
+ def unenvelope_body(body)
316
+ body[envelope_key] || body['data']
317
+ end
318
+
319
+ # return the key which API responses will envelope data under
320
+ def envelope_key
321
+ 'billing_requests'
322
+ end
323
+ end
324
+ end
325
+ end
@@ -0,0 +1,56 @@
1
+ require_relative './base_service'
2
+
3
+ # encoding: utf-8
4
+ #
5
+ # This client is automatically generated from a template and JSON schema definition.
6
+ # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing.
7
+ #
8
+
9
+ module GoCardlessPro
10
+ module Services
11
+ # Service for making requests to the Institution endpoints
12
+ class InstitutionsService < BaseService
13
+ # Returns a list of all supported institutions.
14
+ # Example URL: /institutions
15
+ # @param options [Hash] parameters as a hash, under a params key.
16
+ def list(options = {})
17
+ path = '/institutions'
18
+
19
+ options[:retry_failures] = true
20
+
21
+ response = make_request(:get, path, options)
22
+
23
+ ListResponse.new(
24
+ response: response,
25
+ unenveloped_body: unenvelope_body(response.body),
26
+ resource_class: Resources::Institution
27
+ )
28
+ end
29
+
30
+ # Get a lazily enumerated list of all the items returned. This is simmilar to the `list` method but will paginate for you automatically.
31
+ #
32
+ # @param options [Hash] parameters as a hash. If the request is a GET, these will be converted to query parameters.
33
+ # Otherwise they will be the body of the request.
34
+ def all(options = {})
35
+ Paginator.new(
36
+ service: self,
37
+ options: options
38
+ ).enumerator
39
+ end
40
+
41
+ private
42
+
43
+ # Unenvelope the response of the body using the service's `envelope_key`
44
+ #
45
+ # @param body [Hash]
46
+ def unenvelope_body(body)
47
+ body[envelope_key] || body['data']
48
+ end
49
+
50
+ # return the key which API responses will envelope data under
51
+ def envelope_key
52
+ 'institutions'
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,208 @@
1
+ require_relative './base_service'
2
+
3
+ # encoding: utf-8
4
+ #
5
+ # This client is automatically generated from a template and JSON schema definition.
6
+ # See https://github.com/gocardless/gocardless-pro-ruby#contributing before editing.
7
+ #
8
+
9
+ module GoCardlessPro
10
+ module Services
11
+ # Service for making requests to the PayerAuthorisation endpoints
12
+ class PayerAuthorisationsService < BaseService
13
+ # Retrieves the details of a single existing Payer Authorisation. It can be used
14
+ # for polling the status of a Payer Authorisation.
15
+ # Example URL: /payer_authorisations/:identity
16
+ #
17
+ # @param identity # Unique identifier, beginning with "PA".
18
+ # @param options [Hash] parameters as a hash, under a params key.
19
+ def get(identity, options = {})
20
+ path = sub_url('/payer_authorisations/:identity', 'identity' => identity)
21
+
22
+ options[:retry_failures] = true
23
+
24
+ response = make_request(:get, path, options)
25
+
26
+ return if response.body.nil?
27
+
28
+ Resources::PayerAuthorisation.new(unenvelope_body(response.body), response)
29
+ end
30
+
31
+ # Creates a Payer Authorisation. The resource is saved to the database even if
32
+ # incomplete. An empty array of incomplete_fields means that the resource is
33
+ # valid. The ID of the resource is used for the other actions. This endpoint has
34
+ # been designed this way so you do not need to save any payer data on your
35
+ # servers or the browser while still being able to implement a progressive
36
+ # solution, such as a multi-step form.
37
+ # Example URL: /payer_authorisations
38
+ # @param options [Hash] parameters as a hash, under a params key.
39
+ def create(options = {})
40
+ path = '/payer_authorisations'
41
+
42
+ params = options.delete(:params) || {}
43
+ options[:params] = {}
44
+ options[:params][envelope_key] = params
45
+
46
+ options[:retry_failures] = true
47
+
48
+ begin
49
+ response = make_request(:post, path, options)
50
+
51
+ # Response doesn't raise any errors until #body is called
52
+ response.tap(&:body)
53
+ rescue InvalidStateError => e
54
+ if e.idempotent_creation_conflict?
55
+ case @api_service.on_idempotency_conflict
56
+ when :raise
57
+ raise IdempotencyConflict, e.error
58
+ when :fetch
59
+ return get(e.conflicting_resource_id)
60
+ else
61
+ raise ArgumentError, 'Unknown mode for :on_idempotency_conflict'
62
+ end
63
+ end
64
+
65
+ raise e
66
+ end
67
+
68
+ return if response.body.nil?
69
+
70
+ Resources::PayerAuthorisation.new(unenvelope_body(response.body), response)
71
+ end
72
+
73
+ # Updates a Payer Authorisation. Updates the Payer Authorisation with the
74
+ # request data. Can be invoked as many times as needed. Only fields present in
75
+ # the request will be modified. An empty array of incomplete_fields means that
76
+ # the resource is valid. This endpoint has been designed this way so you do not
77
+ # need to save any payer data on your servers or the browser while still being
78
+ # able to implement a progressive solution, such a multi-step form. <p
79
+ # class="notice"> Note that in order to update the `metadata` attribute values
80
+ # it must be sent completely as it overrides the previously existing values.
81
+ # </p>
82
+ # Example URL: /payer_authorisations/:identity
83
+ #
84
+ # @param identity # Unique identifier, beginning with "PA".
85
+ # @param options [Hash] parameters as a hash, under a params key.
86
+ def update(identity, options = {})
87
+ path = sub_url('/payer_authorisations/:identity', 'identity' => identity)
88
+
89
+ params = options.delete(:params) || {}
90
+ options[:params] = {}
91
+ options[:params][envelope_key] = params
92
+
93
+ options[:retry_failures] = true
94
+
95
+ response = make_request(:put, path, options)
96
+
97
+ return if response.body.nil?
98
+
99
+ Resources::PayerAuthorisation.new(unenvelope_body(response.body), response)
100
+ end
101
+
102
+ # Submits all the data previously pushed to this PayerAuthorisation for
103
+ # verification. This time, a 200 HTTP status is returned if the resource is
104
+ # valid and a 422 error response in case of validation errors. After it is
105
+ # successfully submitted, the Payer Authorisation can no longer be edited.
106
+ # Example URL: /payer_authorisations/:identity/actions/submit
107
+ #
108
+ # @param identity # Unique identifier, beginning with "PA".
109
+ # @param options [Hash] parameters as a hash, under a params key.
110
+ def submit(identity, options = {})
111
+ path = sub_url('/payer_authorisations/:identity/actions/submit', 'identity' => identity)
112
+
113
+ params = options.delete(:params) || {}
114
+ options[:params] = {}
115
+ options[:params]['data'] = params
116
+
117
+ options[:retry_failures] = false
118
+
119
+ begin
120
+ response = make_request(:post, path, options)
121
+
122
+ # Response doesn't raise any errors until #body is called
123
+ response.tap(&:body)
124
+ rescue InvalidStateError => e
125
+ if e.idempotent_creation_conflict?
126
+ case @api_service.on_idempotency_conflict
127
+ when :raise
128
+ raise IdempotencyConflict, e.error
129
+ when :fetch
130
+ return get(e.conflicting_resource_id)
131
+ else
132
+ raise ArgumentError, 'Unknown mode for :on_idempotency_conflict'
133
+ end
134
+ end
135
+
136
+ raise e
137
+ end
138
+
139
+ return if response.body.nil?
140
+
141
+ Resources::PayerAuthorisation.new(unenvelope_body(response.body), response)
142
+ end
143
+
144
+ # Confirms the Payer Authorisation, indicating that the resources are ready to
145
+ # be created.
146
+ # A Payer Authorisation cannot be confirmed if it hasn't been submitted yet.
147
+ #
148
+ # <p class="notice">
149
+ # The main use of the confirm endpoint is to enable integrators to acknowledge
150
+ # the end of the setup process.
151
+ # They might want to make the payers go through some other steps after they go
152
+ # through our flow or make them go through the necessary verification mechanism
153
+ # (upcoming feature).
154
+ # </p>
155
+ # Example URL: /payer_authorisations/:identity/actions/confirm
156
+ #
157
+ # @param identity # Unique identifier, beginning with "PA".
158
+ # @param options [Hash] parameters as a hash, under a params key.
159
+ def confirm(identity, options = {})
160
+ path = sub_url('/payer_authorisations/:identity/actions/confirm', 'identity' => identity)
161
+
162
+ params = options.delete(:params) || {}
163
+ options[:params] = {}
164
+ options[:params]['data'] = params
165
+
166
+ options[:retry_failures] = false
167
+
168
+ begin
169
+ response = make_request(:post, path, options)
170
+
171
+ # Response doesn't raise any errors until #body is called
172
+ response.tap(&:body)
173
+ rescue InvalidStateError => e
174
+ if e.idempotent_creation_conflict?
175
+ case @api_service.on_idempotency_conflict
176
+ when :raise
177
+ raise IdempotencyConflict, e.error
178
+ when :fetch
179
+ return get(e.conflicting_resource_id)
180
+ else
181
+ raise ArgumentError, 'Unknown mode for :on_idempotency_conflict'
182
+ end
183
+ end
184
+
185
+ raise e
186
+ end
187
+
188
+ return if response.body.nil?
189
+
190
+ Resources::PayerAuthorisation.new(unenvelope_body(response.body), response)
191
+ end
192
+
193
+ private
194
+
195
+ # Unenvelope the response of the body using the service's `envelope_key`
196
+ #
197
+ # @param body [Hash]
198
+ def unenvelope_body(body)
199
+ body[envelope_key] || body['data']
200
+ end
201
+
202
+ # return the key which API responses will envelope data under
203
+ def envelope_key
204
+ 'payer_authorisations'
205
+ end
206
+ end
207
+ end
208
+ end