gocardless_pro 2.23.0 → 2.28.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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +23 -4
  3. data/lib/gocardless_pro.rb +27 -0
  4. data/lib/gocardless_pro/api_service.rb +4 -0
  5. data/lib/gocardless_pro/client.rb +41 -1
  6. data/lib/gocardless_pro/error/authentication_error.rb +4 -0
  7. data/lib/gocardless_pro/error/permission_error.rb +4 -0
  8. data/lib/gocardless_pro/error/rate_limit_error.rb +4 -0
  9. data/lib/gocardless_pro/middlewares/raise_gocardless_errors.rb +12 -1
  10. data/lib/gocardless_pro/resources/bank_authorisation.rb +85 -0
  11. data/lib/gocardless_pro/resources/billing_request.rb +108 -0
  12. data/lib/gocardless_pro/resources/billing_request_flow.rb +72 -0
  13. data/lib/gocardless_pro/resources/billing_request_template.rb +68 -0
  14. data/lib/gocardless_pro/resources/creditor.rb +2 -3
  15. data/lib/gocardless_pro/resources/event.rb +12 -0
  16. data/lib/gocardless_pro/resources/institution.rb +45 -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/scenario_simulator.rb +42 -0
  20. data/lib/gocardless_pro/resources/tax_rate.rb +3 -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/creditor_bank_accounts_service.rb +0 -4
  27. data/lib/gocardless_pro/services/creditors_service.rb +0 -2
  28. data/lib/gocardless_pro/services/customer_bank_accounts_service.rb +0 -4
  29. data/lib/gocardless_pro/services/customers_service.rb +0 -2
  30. data/lib/gocardless_pro/services/instalment_schedules_service.rb +0 -6
  31. data/lib/gocardless_pro/services/institutions_service.rb +56 -0
  32. data/lib/gocardless_pro/services/mandate_imports_service.rb +0 -6
  33. data/lib/gocardless_pro/services/mandates_service.rb +0 -6
  34. data/lib/gocardless_pro/services/payer_authorisations_service.rb +202 -0
  35. data/lib/gocardless_pro/services/payments_service.rb +0 -6
  36. data/lib/gocardless_pro/services/redirect_flows_service.rb +0 -4
  37. data/lib/gocardless_pro/services/refunds_service.rb +0 -2
  38. data/lib/gocardless_pro/services/scenario_simulators_service.rb +170 -0
  39. data/lib/gocardless_pro/services/subscriptions_service.rb +10 -13
  40. data/lib/gocardless_pro/services/webhooks_service.rb +111 -0
  41. data/lib/gocardless_pro/version.rb +1 -1
  42. data/spec/api_service_spec.rb +12 -1
  43. data/spec/middlewares/raise_gocardless_errors_spec.rb +30 -0
  44. data/spec/resources/bank_authorisation_spec.rb +259 -0
  45. data/spec/resources/billing_request_flow_spec.rb +219 -0
  46. data/spec/resources/billing_request_spec.rb +782 -0
  47. data/spec/resources/billing_request_template_spec.rb +502 -0
  48. data/spec/resources/institution_spec.rb +103 -0
  49. data/spec/resources/payer_authorisation_spec.rb +418 -0
  50. data/spec/resources/scenario_simulator_spec.rb +63 -0
  51. data/spec/resources/webhook_spec.rb +323 -0
  52. data/spec/services/bank_authorisations_service_spec.rb +353 -0
  53. data/spec/services/billing_request_flows_service_spec.rb +253 -0
  54. data/spec/services/billing_request_templates_service_spec.rb +789 -0
  55. data/spec/services/billing_requests_service_spec.rb +1082 -0
  56. data/spec/services/creditor_bank_accounts_service_spec.rb +0 -13
  57. data/spec/services/creditors_service_spec.rb +0 -13
  58. data/spec/services/customer_bank_accounts_service_spec.rb +0 -13
  59. data/spec/services/customers_service_spec.rb +0 -13
  60. data/spec/services/instalment_schedules_service_spec.rb +0 -26
  61. data/spec/services/institutions_service_spec.rb +223 -0
  62. data/spec/services/mandate_imports_service_spec.rb +0 -13
  63. data/spec/services/mandates_service_spec.rb +0 -13
  64. data/spec/services/payer_authorisations_service_spec.rb +559 -0
  65. data/spec/services/payments_service_spec.rb +0 -13
  66. data/spec/services/redirect_flows_service_spec.rb +0 -13
  67. data/spec/services/refunds_service_spec.rb +0 -13
  68. data/spec/services/scenario_simulators_service_spec.rb +74 -0
  69. data/spec/services/subscriptions_service_spec.rb +0 -13
  70. data/spec/services/webhooks_service_spec.rb +545 -0
  71. metadata +54 -3
@@ -0,0 +1,170 @@
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 ScenarioSimulator endpoints
12
+ class ScenarioSimulatorsService < BaseService
13
+ # Runs the specific scenario simulator against the specific resource
14
+ # Example URL: /scenario_simulators/:identity/actions/run
15
+ #
16
+ # @param identity # The unique identifier of the simulator, used to initiate simulations.
17
+ # One of:
18
+ # <ul>
19
+ # <li>`creditor_verification_status_action_required`: Sets a creditor's
20
+ # `verification status` to `action required`, meaning that the creditor
21
+ # must provide further information to GoCardless in order to verify their
22
+ # account to receive payouts.</li>
23
+ # <li>`creditor_verification_status_in_review`: Sets a creditor's
24
+ # `verification status` to `in review`, meaning that the creditor has
25
+ # provided all of the information requested by GoCardless to verify their
26
+ # account, and is now awaiting review.</li>
27
+ # <li>`creditor_verification_status_successful`: Sets a creditor's
28
+ # `verification status` to `successful`, meaning that the creditor is
29
+ # fully verified and can receive payouts.</li>
30
+ # <li>`payment_confirmed`: Transitions a payment through to `confirmed`.
31
+ # It must start in the `pending_submission` state, and its mandate must be
32
+ # in the `activated` state (unless it is a payment for ACH, BECS, BECS_NZ
33
+ # or SEPA, in which cases the mandate may be `pending_submission`, since
34
+ # their mandates are submitted with their first payment).</li>
35
+ # <li>`payment_paid_out`: Transitions a payment through to `paid_out`,
36
+ # having been collected successfully and paid out to you. It must start in
37
+ # the `pending_submission` state, and its mandate must be in the
38
+ # `activated` state (unless it is a payment for ACH, BECS, BECS_NZ or
39
+ # SEPA, in which cases the mandate may be `pending_submission`, since
40
+ # their mandates are submitted with their first payment).</li>
41
+ # <li>`payment_failed`: Transitions a payment through to `failed`. It must
42
+ # start in the `pending_submission` state, and its mandate must be in the
43
+ # `activated` state (unless it is a payment for ACH, BECS, BECS_NZ or
44
+ # SEPA, in which cases the mandate may be `pending_submission`, since
45
+ # their mandates are submitted with their first payment).</li>
46
+ # <li>`payment_charged_back`: Behaves the same as the `payout_paid_out`
47
+ # simulator, except that the payment is transitioned to `charged_back`
48
+ # after it is paid out, having been charged back by the customer.</li>
49
+ # <li>`payment_chargeback_settled`: Behaves the same as the
50
+ # `payment_charged_back` simulator, except that the charged back payment
51
+ # is additionally included as a debit item in a payout, thereby settling
52
+ # the charged back payment.</li>
53
+ # <li>`payment_late_failure`: Transitions a payment through to
54
+ # `late_failure`, having been apparently collected successfully
55
+ # beforehand. It must start in the `pending_submission` state, and its
56
+ # mandate must be in the `activated` state (unless it is a payment for
57
+ # ACH, BECS, BECS_NZ or SEPA, in which cases the mandate may be
58
+ # `pending_submission`, since their mandates are submitted with their
59
+ # first payment). Not compatible with Autogiro mandates.</li>
60
+ # <li>`payment_late_failure_settled`: Behaves the same as the
61
+ # `payment_late_failure` simulator, except that the late failure is
62
+ # additionally included as a debit item in a payout, thereby settling the
63
+ # late failure.</li>
64
+ # <li>`payment_submitted`: Transitions a payment to `submitted`, without
65
+ # proceeding any further. It must start in the `pending_submission`
66
+ # state.</li>
67
+ # <li>`mandate_activated`: Transitions a mandate through to `activated`,
68
+ # having been submitted to the banks and set up successfully. It must
69
+ # start in the `pending_submission` state. Not compatible with ACH, BECS,
70
+ # BECS_NZ and SEPA mandates, which are submitted and activated with their
71
+ # first payment.</li>
72
+ # <li>`mandate_customer_approval_granted`: Transitions a mandate through
73
+ # to `pending_submission`, as if the customer approved the mandate
74
+ # creation. It must start in the `pending_customer_approval` state.
75
+ # Compatible only with Bacs and SEPA mandates, which support customer
76
+ # signatures on the mandate. All payments associated with the mandate will
77
+ # be transitioned to `pending_submission`. All subscriptions associated
78
+ # with the mandate will become `active`.</li>
79
+ # <li>`mandate_customer_approval_skipped`: Transitions a mandate through
80
+ # to `pending_submission`, as if the customer skipped the mandate approval
81
+ # during the mandate creation process. It must start in the
82
+ # `pending_customer_approval` state. Compatible only with Bacs and SEPA
83
+ # mandates, which support customer signatures on the mandate. All payments
84
+ # associated with the mandate will be transitioned to
85
+ # `pending_submission`. All subscriptions associated with the mandate will
86
+ # become `active`.</li>
87
+ # <li>`mandate_failed`: Transitions a mandate through to `failed`, having
88
+ # been submitted to the banks but found to be invalid (for example due to
89
+ # invalid bank details). It must start in the `pending_submission` or
90
+ # `submitted` states. Not compatible with SEPA mandates, which are
91
+ # submitted with their first payment.</li>
92
+ # <li>`mandate_expired`: Transitions a mandate through to `expired`,
93
+ # having been submitted to the banks, set up successfully and then expired
94
+ # because no collection attempts were made against it for longer than the
95
+ # scheme's dormancy period (13 months for Bacs, 3 years for SEPA, 15
96
+ # months for ACH, Betalingsservice, and BECS). It must start in the
97
+ # `pending_submission` state. Not compatible with Autogiro, BECS NZ, and
98
+ # PAD mandates, which do not expire.</li>
99
+ # <li>`mandate_transferred`: Transitions a mandate through to
100
+ # `transferred`, having been submitted to the banks, set up successfully
101
+ # and then moved to a new bank account due to the customer using the UK's
102
+ # Current Account Switching Service (CASS). It must start in the
103
+ # `pending_submission` state. Only compatible with Bacs mandates.</li>
104
+ # <li>`mandate_transferred_with_resubmission`: Transitions a mandate
105
+ # through `transferred` and resubmits it to the banks, can be caused be
106
+ # the UK's Current Account Switching Service (CASS) or when a customer
107
+ # contacts GoCardless to change their bank details. It must start in the
108
+ # `pending_submission` state. Only compatible with Bacs, SEPA and Autogiro
109
+ # mandates.</li>
110
+ # <li>`refund_paid`: Transitions a refund to `paid`. It must start in
111
+ # either the `pending_submission` or `submitted` state.</li>
112
+ # <li>`refund_settled`: Transitions a refund to `paid`, if it's not
113
+ # already, then generates a payout that includes the refund, thereby
114
+ # settling the funds. It must start in one of `pending_submission`,
115
+ # `submitted` or `paid` states.</li>
116
+ # <li>`refund_bounced`: Transitions a refund to `bounced`. It must start
117
+ # in either the `pending_submission`, `submitted`, or `paid` state.</li>
118
+ # <li>`refund_returned`: Transitions a refund to `refund_returned`. The
119
+ # refund must start in `pending_submission`.</li>
120
+ # <li>`payout_bounced`: Transitions a payout to `bounced`. It must start
121
+ # in the `paid` state.</li>
122
+ # <li>`billing_request_fulfilled`: Authorises the billing request, fulfils
123
+ # it, and moves the associated payment to `failed`. The billing request
124
+ # must be in the `pending` state, with all actions completed except for
125
+ # `bank_authorisation`. Only billing requests with a `payment_request` are
126
+ # supported.</li>
127
+ # <li>`billing_request_fulfilled_and_payment_failed`: Authorises the
128
+ # billing request, fulfils it, and moves the associated payment to
129
+ # `failed`. The billing request must be in the `pending` state, with all
130
+ # actions completed except for `bank_authorisation`. Only billing requests
131
+ # with a `payment_request` are supported.</li>
132
+ # <li>`billing_request_fulfilled_and_payment_paid_out`: Authorises the
133
+ # billing request, fulfils it, and moves the associated payment to
134
+ # `paid_out`. The billing request must be in the `pending` state, with all
135
+ # actions completed except for `bank_authorisation`. Only billing requests
136
+ # with a `payment_request` are supported.</li>
137
+ # </ul>
138
+ # @param options [Hash] parameters as a hash, under a params key.
139
+ def run(identity, options = {})
140
+ path = sub_url('/scenario_simulators/:identity/actions/run', 'identity' => identity)
141
+
142
+ params = options.delete(:params) || {}
143
+ options[:params] = {}
144
+ options[:params]['data'] = params
145
+
146
+ options[:retry_failures] = false
147
+
148
+ response = make_request(:post, path, options)
149
+
150
+ return if response.body.nil?
151
+
152
+ Resources::ScenarioSimulator.new(unenvelope_body(response.body), response)
153
+ end
154
+
155
+ private
156
+
157
+ # Unenvelope the response of the body using the service's `envelope_key`
158
+ #
159
+ # @param body [Hash]
160
+ def unenvelope_body(body)
161
+ body[envelope_key] || body['data']
162
+ end
163
+
164
+ # return the key which API responses will envelope data under
165
+ def envelope_key
166
+ 'scenario_simulators'
167
+ end
168
+ end
169
+ end
170
+ end
@@ -34,8 +34,6 @@ module GoCardlessPro
34
34
  raise IdempotencyConflict, e.error
35
35
  when :fetch
36
36
  return get(e.conflicting_resource_id)
37
- else
38
- raise ArgumentError, 'Unknown mode for :on_idempotency_conflict'
39
37
  end
40
38
  end
41
39
 
@@ -140,14 +138,15 @@ module GoCardlessPro
140
138
  # Pause a subscription object.
141
139
  # No payments will be created until it is resumed.
142
140
  #
143
- # This can only be used when a subscription collecting a fixed number of
144
- # payments (created using `count`)
145
- # or when they continue forever (created without `count` or `end_date`)
141
+ # This can only be used when a subscription is collecting a fixed number of
142
+ # payments (created using `count`),
143
+ # when they continue forever (created without `count` or `end_date`) or
144
+ # the subscription is already paused for a number of cycles.
146
145
  #
147
146
  # When `pause_cycles` is omitted the subscription is paused until the [resume
148
147
  # endpoint](#subscriptions-resume-a-subscription) is called.
149
148
  # If the subscription is collecting a fixed number of payments, `end_date` will
150
- # be set to `nil`.
149
+ # be set to `null`.
151
150
  # When paused indefinitely, `upcoming_payments` will be empty.
152
151
  #
153
152
  # When `pause_cycles` is provided the subscription will be paused for the number
@@ -166,7 +165,11 @@ module GoCardlessPro
166
165
  # - `validation_failed` if invalid data is provided when attempting to pause a
167
166
  # subscription.
168
167
  #
169
- # - `subscription_not_active` if the subscription is no longer active.
168
+ # - `subscription_paused_cannot_update_cycles` if the subscription is already
169
+ # paused for a number of cycles and the request provides a value for
170
+ # `pause_cycle`.
171
+ #
172
+ # - `subscription_cannot_be_paused` if the subscription cannot be paused.
170
173
  #
171
174
  # - `subscription_already_ended` if the subscription has taken all payments.
172
175
  #
@@ -198,8 +201,6 @@ module GoCardlessPro
198
201
  raise IdempotencyConflict, e.error
199
202
  when :fetch
200
203
  return get(e.conflicting_resource_id)
201
- else
202
- raise ArgumentError, 'Unknown mode for :on_idempotency_conflict'
203
204
  end
204
205
  end
205
206
 
@@ -253,8 +254,6 @@ module GoCardlessPro
253
254
  raise IdempotencyConflict, e.error
254
255
  when :fetch
255
256
  return get(e.conflicting_resource_id)
256
- else
257
- raise ArgumentError, 'Unknown mode for :on_idempotency_conflict'
258
257
  end
259
258
  end
260
259
 
@@ -297,8 +296,6 @@ module GoCardlessPro
297
296
  raise IdempotencyConflict, e.error
298
297
  when :fetch
299
298
  return get(e.conflicting_resource_id)
300
- else
301
- raise ArgumentError, 'Unknown mode for :on_idempotency_conflict'
302
299
  end
303
300
  end
304
301
 
@@ -0,0 +1,111 @@
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 Webhook endpoints
12
+ class WebhooksService < BaseService
13
+ # Returns a [cursor-paginated](#api-usage-cursor-pagination) list of your
14
+ # webhooks.
15
+ # Example URL: /webhooks
16
+ # @param options [Hash] parameters as a hash, under a params key.
17
+ def list(options = {})
18
+ path = '/webhooks'
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::Webhook
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
+ # Retrieves the details of an existing webhook.
43
+ # Example URL: /webhooks/:identity
44
+ #
45
+ # @param identity # Unique identifier, beginning with "WB".
46
+ # @param options [Hash] parameters as a hash, under a params key.
47
+ def get(identity, options = {})
48
+ path = sub_url('/webhooks/:identity', 'identity' => identity)
49
+
50
+ options[:retry_failures] = true
51
+
52
+ response = make_request(:get, path, options)
53
+
54
+ return if response.body.nil?
55
+
56
+ Resources::Webhook.new(unenvelope_body(response.body), response)
57
+ end
58
+
59
+ # Requests for a previous webhook to be sent again
60
+ # Example URL: /webhooks/:identity/actions/retry
61
+ #
62
+ # @param identity # Unique identifier, beginning with "WB".
63
+ # @param options [Hash] parameters as a hash, under a params key.
64
+ def retry(identity, options = {})
65
+ path = sub_url('/webhooks/:identity/actions/retry', 'identity' => identity)
66
+
67
+ params = options.delete(:params) || {}
68
+ options[:params] = {}
69
+ options[:params]['data'] = params
70
+
71
+ options[:retry_failures] = false
72
+
73
+ begin
74
+ response = make_request(:post, path, options)
75
+
76
+ # Response doesn't raise any errors until #body is called
77
+ response.tap(&:body)
78
+ rescue InvalidStateError => e
79
+ if e.idempotent_creation_conflict?
80
+ case @api_service.on_idempotency_conflict
81
+ when :raise
82
+ raise IdempotencyConflict, e.error
83
+ when :fetch
84
+ return get(e.conflicting_resource_id)
85
+ end
86
+ end
87
+
88
+ raise e
89
+ end
90
+
91
+ return if response.body.nil?
92
+
93
+ Resources::Webhook.new(unenvelope_body(response.body), response)
94
+ end
95
+
96
+ private
97
+
98
+ # Unenvelope the response of the body using the service's `envelope_key`
99
+ #
100
+ # @param body [Hash]
101
+ def unenvelope_body(body)
102
+ body[envelope_key] || body['data']
103
+ end
104
+
105
+ # return the key which API responses will envelope data under
106
+ def envelope_key
107
+ 'webhooks'
108
+ end
109
+ end
110
+ end
111
+ end
@@ -4,5 +4,5 @@ end
4
4
 
5
5
  module GoCardlessPro
6
6
  # Current version of the GC gem
7
- VERSION = '2.23.0'.freeze
7
+ VERSION = '2.28.0'.freeze
8
8
  end
@@ -1,8 +1,11 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe GoCardlessPro::ApiService do
4
- subject(:service) { described_class.new('https://api.example.com', 'secret_token') }
4
+ subject(:service) do
5
+ described_class.new('https://api.example.com', 'secret_token', options)
6
+ end
5
7
 
8
+ let(:options) { {} }
6
9
  let(:default_response) do
7
10
  {
8
11
  status: 200,
@@ -174,4 +177,12 @@ describe GoCardlessPro::ApiService do
174
177
  expect(stub).to have_been_requested
175
178
  end
176
179
  end
180
+
181
+ describe 'when passing an invalid :on_idempotency_conflict' do
182
+ let(:options) { { on_idempotency_conflict: :junk } }
183
+
184
+ it 'raises an error' do
185
+ expect { service }.to raise_error(ArgumentError)
186
+ end
187
+ end
177
188
  end
@@ -74,6 +74,36 @@ describe GoCardlessPro::Middlewares::RaiseGoCardlessErrors do
74
74
  end
75
75
  end
76
76
 
77
+ context 'for a Permission error' do
78
+ let(:status) { 403 }
79
+ let(:body) { { error: { type: 'invalid_api_usage' } }.to_json }
80
+
81
+ it 'raises a GoCardlessError' do
82
+ expect { connection.post('https://api.gocardless.com/widgets') }.
83
+ to raise_error(GoCardlessPro::PermissionError)
84
+ end
85
+ end
86
+
87
+ context 'for a RateLimit error' do
88
+ let(:status) { 429 }
89
+ let(:body) { { error: { type: 'invalid_api_usage' } }.to_json }
90
+
91
+ it 'raises a GoCardlessError' do
92
+ expect { connection.post('https://api.gocardless.com/widgets') }.
93
+ to raise_error(GoCardlessPro::RateLimitError)
94
+ end
95
+ end
96
+
97
+ context 'for a Authentication error' do
98
+ let(:status) { 401 }
99
+ let(:body) { { error: { type: 'invalid_api_usage' } }.to_json }
100
+
101
+ it 'raises a GoCardlessError' do
102
+ expect { connection.post('https://api.gocardless.com/widgets') }.
103
+ to raise_error(GoCardlessPro::AuthenticationError)
104
+ end
105
+ end
106
+
77
107
  context 'for an invalid API usage error' do
78
108
  let(:status) { 400 }
79
109
  let(:body) { { error: { type: 'invalid_api_usage' } }.to_json }
@@ -0,0 +1,259 @@
1
+ require 'spec_helper'
2
+
3
+ describe GoCardlessPro::Resources::BankAuthorisation 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
+ 'authorised_at' => 'authorised_at-input',
28
+ 'created_at' => 'created_at-input',
29
+ 'expires_at' => 'expires_at-input',
30
+ 'id' => 'id-input',
31
+ 'last_visited_at' => 'last_visited_at-input',
32
+ 'links' => 'links-input',
33
+ 'redirect_uri' => 'redirect_uri-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
+ 'authorised_at' => 'authorised_at-input',
62
+ 'created_at' => 'created_at-input',
63
+ 'expires_at' => 'expires_at-input',
64
+ 'id' => 'id-input',
65
+ 'last_visited_at' => 'last_visited_at-input',
66
+ 'links' => 'links-input',
67
+ 'redirect_uri' => 'redirect_uri-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
+ end
102
+
103
+ describe '#create' do
104
+ subject(:post_create_response) { client.bank_authorisations.create(params: new_resource) }
105
+ context 'with a valid request' do
106
+ let(:new_resource) do
107
+ {
108
+
109
+ 'authorisation_type' => 'authorisation_type-input',
110
+ 'authorised_at' => 'authorised_at-input',
111
+ 'created_at' => 'created_at-input',
112
+ 'expires_at' => 'expires_at-input',
113
+ 'id' => 'id-input',
114
+ 'last_visited_at' => 'last_visited_at-input',
115
+ 'links' => 'links-input',
116
+ 'redirect_uri' => 'redirect_uri-input',
117
+ 'url' => 'url-input',
118
+ }
119
+ end
120
+
121
+ before do
122
+ stub_request(:post, %r{.*api.gocardless.com/bank_authorisations}).
123
+ with(
124
+ body: {
125
+ 'bank_authorisations' => {
126
+
127
+ 'authorisation_type' => 'authorisation_type-input',
128
+ 'authorised_at' => 'authorised_at-input',
129
+ 'created_at' => 'created_at-input',
130
+ 'expires_at' => 'expires_at-input',
131
+ 'id' => 'id-input',
132
+ 'last_visited_at' => 'last_visited_at-input',
133
+ 'links' => 'links-input',
134
+ 'redirect_uri' => 'redirect_uri-input',
135
+ 'url' => 'url-input',
136
+ },
137
+ }
138
+ ).
139
+ to_return(
140
+ body: {
141
+ 'bank_authorisations' =>
142
+
143
+ {
144
+
145
+ 'authorisation_type' => 'authorisation_type-input',
146
+ 'authorised_at' => 'authorised_at-input',
147
+ 'created_at' => 'created_at-input',
148
+ 'expires_at' => 'expires_at-input',
149
+ 'id' => 'id-input',
150
+ 'last_visited_at' => 'last_visited_at-input',
151
+ 'links' => 'links-input',
152
+ 'redirect_uri' => 'redirect_uri-input',
153
+ 'url' => 'url-input',
154
+ },
155
+
156
+ }.to_json,
157
+ headers: response_headers
158
+ )
159
+ end
160
+
161
+ it 'creates and returns the resource' do
162
+ expect(post_create_response).to be_a(GoCardlessPro::Resources::BankAuthorisation)
163
+ end
164
+ end
165
+
166
+ context 'with a request that returns a validation error' do
167
+ let(:new_resource) { {} }
168
+
169
+ before do
170
+ stub_request(:post, %r{.*api.gocardless.com/bank_authorisations}).to_return(
171
+ body: {
172
+ error: {
173
+ type: 'validation_failed',
174
+ code: 422,
175
+ errors: [
176
+ { message: 'test error message', field: 'test_field' },
177
+ ],
178
+ },
179
+ }.to_json,
180
+ headers: response_headers,
181
+ status: 422
182
+ )
183
+ end
184
+
185
+ it 'throws the correct error' do
186
+ expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError)
187
+ end
188
+ end
189
+
190
+ context 'with a request that returns an idempotent creation conflict error' do
191
+ let(:id) { 'ID123' }
192
+
193
+ let(:new_resource) do
194
+ {
195
+
196
+ 'authorisation_type' => 'authorisation_type-input',
197
+ 'authorised_at' => 'authorised_at-input',
198
+ 'created_at' => 'created_at-input',
199
+ 'expires_at' => 'expires_at-input',
200
+ 'id' => 'id-input',
201
+ 'last_visited_at' => 'last_visited_at-input',
202
+ 'links' => 'links-input',
203
+ 'redirect_uri' => 'redirect_uri-input',
204
+ 'url' => 'url-input',
205
+ }
206
+ end
207
+
208
+ let!(:post_stub) do
209
+ stub_request(:post, %r{.*api.gocardless.com/bank_authorisations}).to_return(
210
+ body: {
211
+ error: {
212
+ type: 'invalid_state',
213
+ code: 409,
214
+ errors: [
215
+ {
216
+ message: 'A resource has already been created with this idempotency key',
217
+ reason: 'idempotent_creation_conflict',
218
+ links: {
219
+ conflicting_resource_id: id,
220
+ },
221
+ },
222
+ ],
223
+ },
224
+ }.to_json,
225
+ headers: response_headers,
226
+ status: 409
227
+ )
228
+ end
229
+
230
+ let!(:get_stub) do
231
+ stub_url = "/bank_authorisations/#{id}"
232
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).
233
+ to_return(
234
+ body: {
235
+ 'bank_authorisations' => {
236
+
237
+ 'authorisation_type' => 'authorisation_type-input',
238
+ 'authorised_at' => 'authorised_at-input',
239
+ 'created_at' => 'created_at-input',
240
+ 'expires_at' => 'expires_at-input',
241
+ 'id' => 'id-input',
242
+ 'last_visited_at' => 'last_visited_at-input',
243
+ 'links' => 'links-input',
244
+ 'redirect_uri' => 'redirect_uri-input',
245
+ 'url' => 'url-input',
246
+ },
247
+ }.to_json,
248
+ headers: response_headers
249
+ )
250
+ end
251
+
252
+ it 'fetches the already-created resource' do
253
+ post_create_response
254
+ expect(post_stub).to have_been_requested
255
+ expect(get_stub).to have_been_requested
256
+ end
257
+ end
258
+ end
259
+ end