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,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
@@ -71,7 +71,7 @@ module GoCardlessPro
71
71
  end
72
72
 
73
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
74
+ # request data. Can be invoked as many times as needed. Only fields present in
75
75
  # the request will be modified. An empty array of incomplete_fields means that
76
76
  # the resource is valid. This endpoint has been designed this way so you do not
77
77
  # need to save any payer data on your servers or the browser while still being
@@ -100,8 +100,8 @@ module GoCardlessPro
100
100
  end
101
101
 
102
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 valid
104
- # and a 422 error response in case of validation errors. After it is
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
105
  # successfully submitted, the Payer Authorisation can no longer be edited.
106
106
  # Example URL: /payer_authorisations/:identity/actions/submit
107
107
  #
@@ -149,8 +149,8 @@ module GoCardlessPro
149
149
  # The main use of the confirm endpoint is to enable integrators to acknowledge
150
150
  # the end of the setup process.
151
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
153
- # mechanism(upcomming feature).
152
+ # through our flow or make them go through the necessary verification mechanism
153
+ # (upcoming feature).
154
154
  # </p>
155
155
  # Example URL: /payer_authorisations/:identity/actions/confirm
156
156
  #
@@ -0,0 +1,148 @@
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_paid_out`: Transitions a payment through to `paid_out`,
31
+ # having been collected successfully and paid out to you. It must start in
32
+ # the `pending_submission` state, and its mandate must be in the
33
+ # `activated` state (unless it is a payment for ACH, BECS, BECS_NZ or
34
+ # SEPA, in which cases the mandate may be `pending_submission`, since
35
+ # their mandates are submitted with their first payment).</li>
36
+ # <li>`payment_failed`: Transitions a payment through to `failed`. It must
37
+ # start in 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_charged_back`: Behaves the same as the `payout_paid_out`
42
+ # simulator, except that the payment is transitioned to `charged_back`
43
+ # after it is paid out, having been charged back by the customer.</li>
44
+ # <li>`payment_chargeback_settled`: Behaves the same as the
45
+ # `payment_charged_back` simulator, except that the charged back payment
46
+ # is additionally included as a debit item in a payout, thereby settling
47
+ # the charged back payment.</li>
48
+ # <li>`payment_late_failure`: Transitions a payment through to
49
+ # `late_failure`, having been apparently collected successfully
50
+ # beforehand. It must start in the `pending_submission` state, and its
51
+ # mandate must be in the `activated` state (unless it is a payment for
52
+ # ACH, BECS, BECS_NZ or SEPA, in which cases the mandate may be
53
+ # `pending_submission`, since their mandates are submitted with their
54
+ # first payment). Not compatible with Autogiro mandates.</li>
55
+ # <li>`payment_late_failure_settled`: Behaves the same as the
56
+ # `payment_late_failure` simulator, except that the late failure is
57
+ # additionally included as a debit item in a payout, thereby settling the
58
+ # late failure.</li>
59
+ # <li>`payment_submitted`: Transitions a payment to `submitted`, without
60
+ # proceeding any further. It must start in the `pending_submission`
61
+ # state.</li>
62
+ # <li>`mandate_activated`: Transitions a mandate through to `activated`,
63
+ # having been submitted to the banks and set up successfully. It must
64
+ # start in the `pending_submission` state. Not compatible with ACH, BECS,
65
+ # BECS_NZ and SEPA mandates, which are submitted and activated with their
66
+ # first payment.</li>
67
+ # <li>`mandate_customer_approval_granted`: Transitions a mandate through
68
+ # to `pending_submission`, as if the customer approved the mandate
69
+ # creation. It must start in the `pending_customer_approval` state.
70
+ # Compatible only with Bacs and SEPA mandates, which support customer
71
+ # signatures on the mandate. All payments associated with the mandate will
72
+ # be transitioned to `pending_submission`. All subscriptions associated
73
+ # with the mandate will become `active`.</li>
74
+ # <li>`mandate_customer_approval_skipped`: Transitions a mandate through
75
+ # to `pending_submission`, as if the customer skipped the mandate approval
76
+ # during the mandate creation process. It must start in the
77
+ # `pending_customer_approval` state. Compatible only with Bacs and SEPA
78
+ # mandates, which support customer signatures on the mandate. All payments
79
+ # associated with the mandate will be transitioned to
80
+ # `pending_submission`. All subscriptions associated with the mandate will
81
+ # become `active`.</li>
82
+ # <li>`mandate_failed`: Transitions a mandate through to `failed`, having
83
+ # been submitted to the banks but found to be invalid (for example due to
84
+ # invalid bank details). It must start in the `pending_submission` or
85
+ # `submitted` states. Not compatible with ACH, BECS, BECS_NZ and SEPA
86
+ # mandates, which are submitted with their first payment.</li>
87
+ # <li>`mandate_expired`: Transitions a mandate through to `expired`,
88
+ # having been submitted to the banks, set up successfully and then expired
89
+ # because no collection attempts were made against it for longer than the
90
+ # scheme's dormancy period (13 months for Bacs, 3 years for SEPA, 15
91
+ # months for ACH, Betalingsservice, and BECS). It must start in the
92
+ # `pending_submission` state. Not compatible with Autogiro, BECS NZ, and
93
+ # PAD mandates, which do not expire.</li>
94
+ # <li>`mandate_transferred`: Transitions a mandate through to
95
+ # `transferred`, having been submitted to the banks, set up successfully
96
+ # and then moved to a new bank account due to the customer using the UK's
97
+ # Current Account Switching Service (CASS). It must start in the
98
+ # `pending_submission` state. Only compatible with Bacs mandates.</li>
99
+ # <li>`mandate_transferred_with_resubmission`: Transitions a mandate
100
+ # through `transferred` and resubmits it to the banks, can be caused be
101
+ # the UK's Current Account Switching Service (CASS) or when a customer
102
+ # contacts GoCardless to change their bank details. It must start in the
103
+ # `pending_submission` state. Only compatible with Bacs, SEPA and Autogiro
104
+ # mandates.</li>
105
+ # <li>`refund_paid`: Transitions a refund to `paid`. It must start in
106
+ # either the `pending_submission` or `submitted` state.</li>
107
+ # <li>`refund_bounced`: Transitions a refund to `bounced`. It must start
108
+ # in either the `pending_submission`, `submitted`, or `paid` state.</li>
109
+ # <li>`payout_bounced`: Transitions a payout to `bounced`. It must start
110
+ # in the `paid` state.</li>
111
+ # <li>`payout_create`: Creates a payout containing payments in
112
+ # `confirmed`, `failed` & `charged_back` states; refunds in `submitted` &
113
+ # `bounced`; and all related fees. Can only be used with a positive total
114
+ # payout balance and when some eligible items exist.</li>
115
+ # </ul>
116
+ # @param options [Hash] parameters as a hash, under a params key.
117
+ def run(identity, options = {})
118
+ path = sub_url('/scenario_simulators/:identity/actions/run', 'identity' => identity)
119
+
120
+ params = options.delete(:params) || {}
121
+ options[:params] = {}
122
+ options[:params]['data'] = params
123
+
124
+ options[:retry_failures] = false
125
+
126
+ response = make_request(:post, path, options)
127
+
128
+ return if response.body.nil?
129
+
130
+ Resources::ScenarioSimulator.new(unenvelope_body(response.body), response)
131
+ end
132
+
133
+ private
134
+
135
+ # Unenvelope the response of the body using the service's `envelope_key`
136
+ #
137
+ # @param body [Hash]
138
+ def unenvelope_body(body)
139
+ body[envelope_key] || body['data']
140
+ end
141
+
142
+ # return the key which API responses will envelope data under
143
+ def envelope_key
144
+ 'scenario_simulators'
145
+ end
146
+ end
147
+ end
148
+ end
@@ -141,8 +141,9 @@ module GoCardlessPro
141
141
  # No payments will be created until it is resumed.
142
142
  #
143
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`)
144
+ # payments (created using `count`),
145
+ # when they continue forever (created without `count` or `end_date`) or
146
+ # the subscription is paused for a number of cycles.
146
147
  #
147
148
  # When `pause_cycles` is omitted the subscription is paused until the [resume
148
149
  # endpoint](#subscriptions-resume-a-subscription) is called.
@@ -166,7 +167,11 @@ module GoCardlessPro
166
167
  # - `validation_failed` if invalid data is provided when attempting to pause a
167
168
  # subscription.
168
169
  #
169
- # - `subscription_not_active` if the subscription is no longer active.
170
+ # - `subscription_paused_cannot_update_cycles` if the subscription is already
171
+ # paused for a number of cycles and the request provides a value for
172
+ # `pause_cycle`.
173
+ #
174
+ # - `subscription_cannot_be_paused` if the subscription cannot be paused.
170
175
  #
171
176
  # - `subscription_already_ended` if the subscription has taken all payments.
172
177
  #
@@ -0,0 +1,113 @@
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
+ else
86
+ raise ArgumentError, 'Unknown mode for :on_idempotency_conflict'
87
+ end
88
+ end
89
+
90
+ raise e
91
+ end
92
+
93
+ return if response.body.nil?
94
+
95
+ Resources::Webhook.new(unenvelope_body(response.body), response)
96
+ end
97
+
98
+ private
99
+
100
+ # Unenvelope the response of the body using the service's `envelope_key`
101
+ #
102
+ # @param body [Hash]
103
+ def unenvelope_body(body)
104
+ body[envelope_key] || body['data']
105
+ end
106
+
107
+ # return the key which API responses will envelope data under
108
+ def envelope_key
109
+ 'webhooks'
110
+ end
111
+ end
112
+ end
113
+ end
@@ -4,5 +4,5 @@ end
4
4
 
5
5
  module GoCardlessPro
6
6
  # Current version of the GC gem
7
- VERSION = '2.25.0'.freeze
7
+ VERSION = '2.27.0'.freeze
8
8
  end
@@ -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
+ '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
+ 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
+ 'created_at' => 'created_at-input',
111
+ 'expires_at' => 'expires_at-input',
112
+ 'id' => 'id-input',
113
+ 'last_visited_at' => 'last_visited_at-input',
114
+ 'links' => 'links-input',
115
+ 'redirect_uri' => 'redirect_uri-input',
116
+ 'short_url' => 'short_url-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
+ 'created_at' => 'created_at-input',
129
+ 'expires_at' => 'expires_at-input',
130
+ 'id' => 'id-input',
131
+ 'last_visited_at' => 'last_visited_at-input',
132
+ 'links' => 'links-input',
133
+ 'redirect_uri' => 'redirect_uri-input',
134
+ 'short_url' => 'short_url-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
+ 'created_at' => 'created_at-input',
147
+ 'expires_at' => 'expires_at-input',
148
+ 'id' => 'id-input',
149
+ 'last_visited_at' => 'last_visited_at-input',
150
+ 'links' => 'links-input',
151
+ 'redirect_uri' => 'redirect_uri-input',
152
+ 'short_url' => 'short_url-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
+ 'created_at' => 'created_at-input',
198
+ 'expires_at' => 'expires_at-input',
199
+ 'id' => 'id-input',
200
+ 'last_visited_at' => 'last_visited_at-input',
201
+ 'links' => 'links-input',
202
+ 'redirect_uri' => 'redirect_uri-input',
203
+ 'short_url' => 'short_url-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
+ 'created_at' => 'created_at-input',
239
+ 'expires_at' => 'expires_at-input',
240
+ 'id' => 'id-input',
241
+ 'last_visited_at' => 'last_visited_at-input',
242
+ 'links' => 'links-input',
243
+ 'redirect_uri' => 'redirect_uri-input',
244
+ 'short_url' => 'short_url-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