gocardless_pro 1.1.0 → 2.0.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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +13 -4
  3. data/lib/gocardless_pro.rb +1 -0
  4. data/lib/gocardless_pro/api_service.rb +2 -0
  5. data/lib/gocardless_pro/client.rb +4 -3
  6. data/lib/gocardless_pro/error/invalid_state_error.rb +17 -0
  7. data/lib/gocardless_pro/middlewares/raise_gocardless_errors.rb +50 -0
  8. data/lib/gocardless_pro/request.rb +38 -1
  9. data/lib/gocardless_pro/resources/creditor.rb +2 -2
  10. data/lib/gocardless_pro/resources/creditor_bank_account.rb +11 -11
  11. data/lib/gocardless_pro/resources/customer_bank_account.rb +2 -2
  12. data/lib/gocardless_pro/resources/event.rb +2 -2
  13. data/lib/gocardless_pro/resources/mandate.rb +2 -2
  14. data/lib/gocardless_pro/resources/payment.rb +7 -7
  15. data/lib/gocardless_pro/resources/payout.rb +7 -6
  16. data/lib/gocardless_pro/resources/redirect_flow.rb +2 -2
  17. data/lib/gocardless_pro/resources/refund.rb +2 -2
  18. data/lib/gocardless_pro/resources/subscription.rb +2 -2
  19. data/lib/gocardless_pro/response.rb +2 -54
  20. data/lib/gocardless_pro/services/bank_details_lookups_service.rb +3 -0
  21. data/lib/gocardless_pro/services/creditor_bank_accounts_service.rb +31 -2
  22. data/lib/gocardless_pro/services/creditors_service.rb +21 -1
  23. data/lib/gocardless_pro/services/customer_bank_accounts_service.rb +34 -2
  24. data/lib/gocardless_pro/services/customers_service.rb +21 -1
  25. data/lib/gocardless_pro/services/events_service.rb +5 -0
  26. data/lib/gocardless_pro/services/mandate_pdfs_service.rb +3 -0
  27. data/lib/gocardless_pro/services/mandates_service.rb +47 -3
  28. data/lib/gocardless_pro/services/payments_service.rb +47 -3
  29. data/lib/gocardless_pro/services/payouts_service.rb +5 -0
  30. data/lib/gocardless_pro/services/redirect_flows_service.rb +28 -2
  31. data/lib/gocardless_pro/services/refunds_service.rb +21 -1
  32. data/lib/gocardless_pro/services/subscriptions_service.rb +34 -2
  33. data/lib/gocardless_pro/version.rb +1 -1
  34. data/spec/api_service_spec.rb +106 -0
  35. data/spec/middlewares/raise_gocardless_errors_spec.rb +98 -0
  36. data/spec/resources/bank_details_lookup_spec.rb +102 -19
  37. data/spec/resources/creditor_bank_account_spec.rb +416 -40
  38. data/spec/resources/creditor_spec.rb +414 -53
  39. data/spec/resources/customer_bank_account_spec.rb +452 -40
  40. data/spec/resources/customer_spec.rb +457 -45
  41. data/spec/resources/event_spec.rb +171 -72
  42. data/spec/resources/mandate_pdf_spec.rb +100 -17
  43. data/spec/resources/mandate_spec.rb +501 -44
  44. data/spec/resources/payment_spec.rb +531 -48
  45. data/spec/resources/payout_spec.rb +189 -45
  46. data/spec/resources/redirect_flow_spec.rb +277 -43
  47. data/spec/resources/refund_spec.rb +349 -34
  48. data/spec/resources/subscription_spec.rb +531 -53
  49. data/spec/response_spec.rb +12 -79
  50. data/spec/services/bank_details_lookups_service_spec.rb +67 -2
  51. data/spec/services/creditor_bank_accounts_service_spec.rb +309 -31
  52. data/spec/services/creditors_service_spec.rb +343 -33
  53. data/spec/services/customer_bank_accounts_service_spec.rb +335 -32
  54. data/spec/services/customers_service_spec.rb +364 -36
  55. data/spec/services/events_service_spec.rb +185 -24
  56. data/spec/services/mandate_pdfs_service_spec.rb +66 -2
  57. data/spec/services/mandates_service_spec.rb +341 -33
  58. data/spec/services/payments_service_spec.rb +355 -35
  59. data/spec/services/payouts_service_spec.rb +206 -26
  60. data/spec/services/redirect_flows_service_spec.rb +137 -7
  61. data/spec/services/refunds_service_spec.rb +301 -27
  62. data/spec/services/subscriptions_service_spec.rb +377 -38
  63. metadata +6 -3
@@ -1,103 +1,202 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe GoCardlessPro::Resources::Event do
4
- describe 'initialising' do
5
- let(:data) do
6
- {
7
-
8
- 'action' => 'action-input',
9
-
10
- 'created_at' => 'created_at-input',
11
-
12
- 'details' => 'details-input',
13
-
14
- 'id' => 'id-input',
15
-
16
- 'links' => {
17
-
18
- 'mandate' => 'mandate-input',
19
-
20
- 'new_customer_bank_account' => 'new_customer_bank_account-input',
21
-
22
- 'new_mandate' => 'new_mandate-input',
23
-
24
- 'organisation' => 'organisation-input',
4
+ let(:client) do
5
+ GoCardlessPro::Client.new(
6
+ access_token: 'SECRET_TOKEN'
7
+ )
8
+ end
25
9
 
26
- 'parent_event' => 'parent_event-input',
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.events.list }
15
+
16
+ before do
17
+ stub_request(:get, %r{.*api.gocardless.com/events}).to_return(
18
+ body: {
19
+ 'events' => [{
20
+
21
+ 'action' => 'action-input',
22
+ 'created_at' => 'created_at-input',
23
+ 'details' => 'details-input',
24
+ 'id' => 'id-input',
25
+ 'links' => 'links-input',
26
+ 'metadata' => 'metadata-input',
27
+ 'resource_type' => 'resource_type-input'
28
+ }],
29
+ meta: {
30
+ cursors: {
31
+ before: nil,
32
+ after: 'ABC123'
33
+ }
34
+ }
35
+ }.to_json,
36
+ headers: response_headers
37
+ )
38
+ end
27
39
 
28
- 'payment' => 'payment-input',
40
+ it 'wraps each item in the resource class' do
41
+ expect(get_list_response.records.map(&:class).uniq.first).to eq(GoCardlessPro::Resources::Event)
29
42
 
30
- 'payout' => 'payout-input',
43
+ expect(get_list_response.records.first.action).to eq('action-input')
31
44
 
32
- 'previous_customer_bank_account' => 'previous_customer_bank_account-input',
45
+ expect(get_list_response.records.first.created_at).to eq('created_at-input')
33
46
 
34
- 'refund' => 'refund-input',
47
+ expect(get_list_response.records.first.details).to eq('details-input')
35
48
 
36
- 'subscription' => 'subscription-input'
49
+ expect(get_list_response.records.first.id).to eq('id-input')
37
50
 
38
- },
51
+ expect(get_list_response.records.first.metadata).to eq('metadata-input')
39
52
 
40
- 'metadata' => 'metadata-input',
53
+ expect(get_list_response.records.first.resource_type).to eq('resource_type-input')
54
+ end
41
55
 
42
- 'resource_type' => 'resource_type-input'
56
+ it 'exposes the cursors for before and after' do
57
+ expect(get_list_response.before).to eq(nil)
58
+ expect(get_list_response.after).to eq('ABC123')
59
+ end
43
60
 
44
- }
61
+ specify { expect(get_list_response.api_response.headers).to eql('content-type' => 'application/json') }
45
62
  end
63
+ end
46
64
 
47
- it 'can be initialized from an unenveloped response' do
48
- resource = described_class.new(data)
49
-
50
- expect(resource.action).to eq('action-input')
51
-
52
- expect(resource.created_at).to eq('created_at-input')
53
-
54
- expect(resource.details).to eq('details-input')
55
-
56
- expect(resource.id).to eq('id-input')
57
-
58
- expect(resource.links.mandate).to eq('mandate-input')
59
-
60
- expect(resource.links.new_customer_bank_account).to eq('new_customer_bank_account-input')
61
-
62
- expect(resource.links.new_mandate).to eq('new_mandate-input')
63
-
64
- expect(resource.links.organisation).to eq('organisation-input')
65
-
66
- expect(resource.links.parent_event).to eq('parent_event-input')
65
+ describe '#all' do
66
+ let!(:first_response_stub) do
67
+ stub_request(:get, %r{.*api.gocardless.com/events$}).to_return(
68
+ body: {
69
+ 'events' => [{
70
+
71
+ 'action' => 'action-input',
72
+ 'created_at' => 'created_at-input',
73
+ 'details' => 'details-input',
74
+ 'id' => 'id-input',
75
+ 'links' => 'links-input',
76
+ 'metadata' => 'metadata-input',
77
+ 'resource_type' => 'resource_type-input'
78
+ }],
79
+ meta: {
80
+ cursors: { after: 'AB345' },
81
+ limit: 1
82
+ }
83
+ }.to_json,
84
+ headers: response_headers
85
+ )
86
+ end
67
87
 
68
- expect(resource.links.payment).to eq('payment-input')
88
+ let!(:second_response_stub) do
89
+ stub_request(:get, %r{.*api.gocardless.com/events\?after=AB345}).to_return(
90
+ body: {
91
+ 'events' => [{
92
+
93
+ 'action' => 'action-input',
94
+ 'created_at' => 'created_at-input',
95
+ 'details' => 'details-input',
96
+ 'id' => 'id-input',
97
+ 'links' => 'links-input',
98
+ 'metadata' => 'metadata-input',
99
+ 'resource_type' => 'resource_type-input'
100
+ }],
101
+ meta: {
102
+ limit: 2,
103
+ cursors: {}
104
+ }
105
+ }.to_json,
106
+ headers: response_headers
107
+ )
108
+ end
69
109
 
70
- expect(resource.links.payout).to eq('payout-input')
110
+ it 'automatically makes the extra requests' do
111
+ expect(client.events.all.to_a.length).to eq(2)
112
+ expect(first_response_stub).to have_been_requested
113
+ expect(second_response_stub).to have_been_requested
114
+ end
115
+ end
71
116
 
72
- expect(resource.links.previous_customer_bank_account).to eq('previous_customer_bank_account-input')
117
+ describe '#get' do
118
+ let(:id) { 'ID123' }
119
+
120
+ subject(:get_response) { client.events.get(id) }
121
+
122
+ context 'passing in a custom header' do
123
+ let!(:stub) do
124
+ stub_url = '/events/:identity'.gsub(':identity', id)
125
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/)
126
+ .with(headers: { 'Foo' => 'Bar' })
127
+ .to_return(
128
+ body: {
129
+ 'events' => {
130
+
131
+ 'action' => 'action-input',
132
+ 'created_at' => 'created_at-input',
133
+ 'details' => 'details-input',
134
+ 'id' => 'id-input',
135
+ 'links' => 'links-input',
136
+ 'metadata' => 'metadata-input',
137
+ 'resource_type' => 'resource_type-input'
138
+ }
139
+ }.to_json,
140
+ headers: response_headers
141
+ )
142
+ end
73
143
 
74
- expect(resource.links.refund).to eq('refund-input')
144
+ subject(:get_response) do
145
+ client.events.get(id, headers: {
146
+ 'Foo' => 'Bar'
147
+ })
148
+ end
75
149
 
76
- expect(resource.links.subscription).to eq('subscription-input')
150
+ it 'includes the header' do
151
+ get_response
152
+ expect(stub).to have_been_requested
153
+ end
154
+ end
77
155
 
78
- expect(resource.metadata).to eq('metadata-input')
156
+ context 'when there is a event to return' do
157
+ before do
158
+ stub_url = '/events/:identity'.gsub(':identity', id)
159
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
160
+ body: {
161
+ 'events' => {
162
+
163
+ 'action' => 'action-input',
164
+ 'created_at' => 'created_at-input',
165
+ 'details' => 'details-input',
166
+ 'id' => 'id-input',
167
+ 'links' => 'links-input',
168
+ 'metadata' => 'metadata-input',
169
+ 'resource_type' => 'resource_type-input'
170
+ }
171
+ }.to_json,
172
+ headers: response_headers
173
+ )
174
+ end
79
175
 
80
- expect(resource.resource_type).to eq('resource_type-input')
176
+ it 'wraps the response in a resource' do
177
+ expect(get_response).to be_a(GoCardlessPro::Resources::Event)
178
+ end
81
179
  end
82
180
 
83
- it 'can handle new attributes without erroring' do
84
- data['foo'] = 'bar'
85
- expect { described_class.new(data) }.to_not raise_error
86
- end
181
+ context 'when nothing is returned' do
182
+ before do
183
+ stub_url = '/events/:identity'.gsub(':identity', id)
184
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
185
+ body: '',
186
+ headers: response_headers
187
+ )
188
+ end
87
189
 
88
- it 'can handle new link attributes without erroring' do
89
- data['links']['foo'] = 'bar'
90
- expect { described_class.new(data) }.to_not raise_error
190
+ it 'returns nil' do
191
+ expect(get_response).to be_nil
192
+ end
91
193
  end
92
194
 
93
- it 'can handle a nil links value' do
94
- data['links'] = nil
95
- expect { described_class.new(data).links }.to_not raise_error
96
- end
195
+ context "when an ID is specified which can't be included in a valid URI" do
196
+ let(:id) { '`' }
97
197
 
98
- describe '#to_h' do
99
- it 'returns a hash representing the resource' do
100
- expect(described_class.new(data).to_h).to eq(data)
198
+ it "doesn't raise an error" do
199
+ expect { get_response }.to_not raise_error(/bad URI/)
101
200
  end
102
201
  end
103
202
  end
@@ -1,33 +1,116 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe GoCardlessPro::Resources::MandatePdf do
4
- describe 'initialising' do
5
- let(:data) do
6
- {
4
+ let(:client) do
5
+ GoCardlessPro::Client.new(
6
+ access_token: 'SECRET_TOKEN'
7
+ )
8
+ end
7
9
 
8
- 'expires_at' => 'expires_at-input',
10
+ let(:response_headers) { { 'Content-Type' => 'application/json' } }
9
11
 
10
- 'url' => 'url-input'
12
+ describe '#create' do
13
+ subject(:post_create_response) { client.mandate_pdfs.create(params: new_resource) }
14
+ context 'with a valid request' do
15
+ let(:new_resource) do
16
+ {
11
17
 
12
- }
13
- end
18
+ 'expires_at' => 'expires_at-input',
19
+ 'url' => 'url-input'
20
+ }
21
+ end
22
+
23
+ before do
24
+ stub_request(:post, %r{.*api.gocardless.com/mandate_pdfs})
25
+ .with(
26
+ body: {
27
+ 'mandate_pdfs' => {
28
+
29
+ 'expires_at' => 'expires_at-input',
30
+ 'url' => 'url-input'
31
+ }
32
+ }
33
+ )
34
+ .to_return(
35
+ body: {
36
+ 'mandate_pdfs' =>
14
37
 
15
- it 'can be initialized from an unenveloped response' do
16
- resource = described_class.new(data)
38
+ {
17
39
 
18
- expect(resource.expires_at).to eq('expires_at-input')
40
+ 'expires_at' => 'expires_at-input',
41
+ 'url' => 'url-input'
42
+ }
19
43
 
20
- expect(resource.url).to eq('url-input')
44
+ }.to_json,
45
+ headers: response_headers
46
+ )
47
+ end
48
+
49
+ it 'creates and returns the resource' do
50
+ expect(post_create_response).to be_a(GoCardlessPro::Resources::MandatePdf)
51
+ end
21
52
  end
22
53
 
23
- it 'can handle new attributes without erroring' do
24
- data['foo'] = 'bar'
25
- expect { described_class.new(data) }.to_not raise_error
54
+ context 'with a request that returns a validation error' do
55
+ let(:new_resource) { {} }
56
+
57
+ before do
58
+ stub_request(:post, %r{.*api.gocardless.com/mandate_pdfs}).to_return(
59
+ body: {
60
+ error: {
61
+ type: 'validation_failed',
62
+ code: 422,
63
+ errors: [
64
+ { message: 'test error message', field: 'test_field' }
65
+ ]
66
+ }
67
+ }.to_json,
68
+ headers: response_headers,
69
+ status: 422
70
+ )
71
+ end
72
+
73
+ it 'throws the correct error' do
74
+ expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError)
75
+ end
26
76
  end
27
77
 
28
- describe '#to_h' do
29
- it 'returns a hash representing the resource' do
30
- expect(described_class.new(data).to_h).to eq(data)
78
+ context 'with a request that returns an idempotent creation conflict error' do
79
+ let(:id) { 'ID123' }
80
+
81
+ let(:new_resource) do
82
+ {
83
+
84
+ 'expires_at' => 'expires_at-input',
85
+ 'url' => 'url-input'
86
+ }
87
+ end
88
+
89
+ let!(:post_stub) do
90
+ stub_request(:post, %r{.*api.gocardless.com/mandate_pdfs}).to_return(
91
+ body: {
92
+ error: {
93
+ type: 'invalid_state',
94
+ code: 409,
95
+ errors: [
96
+ {
97
+ message: 'A resource has already been created with this idempotency key',
98
+ reason: 'idempotent_creation_conflict',
99
+ links: {
100
+ conflicting_resource_id: id
101
+ }
102
+ }
103
+ ]
104
+ }
105
+ }.to_json,
106
+ headers: response_headers,
107
+ status: 409
108
+ )
109
+ end
110
+
111
+ it 'raises an InvalidStateError' do
112
+ expect { post_create_response }.to raise_error(GoCardlessPro::InvalidStateError)
113
+ expect(post_stub).to have_been_requested
31
114
  end
32
115
  end
33
116
  end
@@ -1,87 +1,544 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe GoCardlessPro::Resources::Mandate do
4
- describe 'initialising' do
5
- let(:data) do
6
- {
4
+ let(:client) do
5
+ GoCardlessPro::Client.new(
6
+ access_token: 'SECRET_TOKEN'
7
+ )
8
+ end
7
9
 
8
- 'created_at' => 'created_at-input',
10
+ let(:response_headers) { { 'Content-Type' => 'application/json' } }
11
+
12
+ describe '#create' do
13
+ subject(:post_create_response) { client.mandates.create(params: new_resource) }
14
+ context 'with a valid request' do
15
+ let(:new_resource) do
16
+ {
17
+
18
+ 'created_at' => 'created_at-input',
19
+ 'id' => 'id-input',
20
+ 'links' => 'links-input',
21
+ 'metadata' => 'metadata-input',
22
+ 'next_possible_charge_date' => 'next_possible_charge_date-input',
23
+ 'payments_require_approval' => 'payments_require_approval-input',
24
+ 'reference' => 'reference-input',
25
+ 'scheme' => 'scheme-input',
26
+ 'status' => 'status-input'
27
+ }
28
+ end
9
29
 
10
- 'id' => 'id-input',
30
+ before do
31
+ stub_request(:post, %r{.*api.gocardless.com/mandates})
32
+ .with(
33
+ body: {
34
+ 'mandates' => {
35
+
36
+ 'created_at' => 'created_at-input',
37
+ 'id' => 'id-input',
38
+ 'links' => 'links-input',
39
+ 'metadata' => 'metadata-input',
40
+ 'next_possible_charge_date' => 'next_possible_charge_date-input',
41
+ 'payments_require_approval' => 'payments_require_approval-input',
42
+ 'reference' => 'reference-input',
43
+ 'scheme' => 'scheme-input',
44
+ 'status' => 'status-input'
45
+ }
46
+ }
47
+ )
48
+ .to_return(
49
+ body: {
50
+ 'mandates' =>
51
+
52
+ {
53
+
54
+ 'created_at' => 'created_at-input',
55
+ 'id' => 'id-input',
56
+ 'links' => 'links-input',
57
+ 'metadata' => 'metadata-input',
58
+ 'next_possible_charge_date' => 'next_possible_charge_date-input',
59
+ 'payments_require_approval' => 'payments_require_approval-input',
60
+ 'reference' => 'reference-input',
61
+ 'scheme' => 'scheme-input',
62
+ 'status' => 'status-input'
63
+ }
64
+
65
+ }.to_json,
66
+ headers: response_headers
67
+ )
68
+ end
11
69
 
12
- 'links' => {
70
+ it 'creates and returns the resource' do
71
+ expect(post_create_response).to be_a(GoCardlessPro::Resources::Mandate)
72
+ end
73
+ end
13
74
 
14
- 'creditor' => 'creditor-input',
75
+ context 'with a request that returns a validation error' do
76
+ let(:new_resource) { {} }
77
+
78
+ before do
79
+ stub_request(:post, %r{.*api.gocardless.com/mandates}).to_return(
80
+ body: {
81
+ error: {
82
+ type: 'validation_failed',
83
+ code: 422,
84
+ errors: [
85
+ { message: 'test error message', field: 'test_field' }
86
+ ]
87
+ }
88
+ }.to_json,
89
+ headers: response_headers,
90
+ status: 422
91
+ )
92
+ end
15
93
 
16
- 'customer' => 'customer-input',
94
+ it 'throws the correct error' do
95
+ expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError)
96
+ end
97
+ end
17
98
 
18
- 'customer_bank_account' => 'customer_bank_account-input',
99
+ context 'with a request that returns an idempotent creation conflict error' do
100
+ let(:id) { 'ID123' }
101
+
102
+ let(:new_resource) do
103
+ {
104
+
105
+ 'created_at' => 'created_at-input',
106
+ 'id' => 'id-input',
107
+ 'links' => 'links-input',
108
+ 'metadata' => 'metadata-input',
109
+ 'next_possible_charge_date' => 'next_possible_charge_date-input',
110
+ 'payments_require_approval' => 'payments_require_approval-input',
111
+ 'reference' => 'reference-input',
112
+ 'scheme' => 'scheme-input',
113
+ 'status' => 'status-input'
114
+ }
115
+ end
19
116
 
20
- 'new_mandate' => 'new_mandate-input'
117
+ let!(:post_stub) do
118
+ stub_request(:post, %r{.*api.gocardless.com/mandates}).to_return(
119
+ body: {
120
+ error: {
121
+ type: 'invalid_state',
122
+ code: 409,
123
+ errors: [
124
+ {
125
+ message: 'A resource has already been created with this idempotency key',
126
+ reason: 'idempotent_creation_conflict',
127
+ links: {
128
+ conflicting_resource_id: id
129
+ }
130
+ }
131
+ ]
132
+ }
133
+ }.to_json,
134
+ headers: response_headers,
135
+ status: 409
136
+ )
137
+ end
21
138
 
22
- },
139
+ let!(:get_stub) do
140
+ stub_url = "/mandates/#{id}"
141
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/)
142
+ .to_return(
143
+ body: {
144
+ 'mandates' => {
145
+
146
+ 'created_at' => 'created_at-input',
147
+ 'id' => 'id-input',
148
+ 'links' => 'links-input',
149
+ 'metadata' => 'metadata-input',
150
+ 'next_possible_charge_date' => 'next_possible_charge_date-input',
151
+ 'payments_require_approval' => 'payments_require_approval-input',
152
+ 'reference' => 'reference-input',
153
+ 'scheme' => 'scheme-input',
154
+ 'status' => 'status-input'
155
+ }
156
+ }.to_json,
157
+ headers: response_headers
158
+ )
159
+ end
23
160
 
24
- 'metadata' => 'metadata-input',
161
+ it 'fetches the already-created resource' do
162
+ post_create_response
163
+ expect(post_stub).to have_been_requested
164
+ expect(get_stub).to have_been_requested
165
+ end
166
+ end
167
+ end
25
168
 
26
- 'next_possible_charge_date' => 'next_possible_charge_date-input',
169
+ describe '#list' do
170
+ describe 'with no filters' do
171
+ subject(:get_list_response) { client.mandates.list }
172
+
173
+ before do
174
+ stub_request(:get, %r{.*api.gocardless.com/mandates}).to_return(
175
+ body: {
176
+ 'mandates' => [{
177
+
178
+ 'created_at' => 'created_at-input',
179
+ 'id' => 'id-input',
180
+ 'links' => 'links-input',
181
+ 'metadata' => 'metadata-input',
182
+ 'next_possible_charge_date' => 'next_possible_charge_date-input',
183
+ 'payments_require_approval' => 'payments_require_approval-input',
184
+ 'reference' => 'reference-input',
185
+ 'scheme' => 'scheme-input',
186
+ 'status' => 'status-input'
187
+ }],
188
+ meta: {
189
+ cursors: {
190
+ before: nil,
191
+ after: 'ABC123'
192
+ }
193
+ }
194
+ }.to_json,
195
+ headers: response_headers
196
+ )
197
+ end
198
+
199
+ it 'wraps each item in the resource class' do
200
+ expect(get_list_response.records.map(&:class).uniq.first).to eq(GoCardlessPro::Resources::Mandate)
201
+
202
+ expect(get_list_response.records.first.created_at).to eq('created_at-input')
203
+
204
+ expect(get_list_response.records.first.id).to eq('id-input')
27
205
 
28
- 'payments_require_approval' => 'payments_require_approval-input',
206
+ expect(get_list_response.records.first.metadata).to eq('metadata-input')
29
207
 
30
- 'reference' => 'reference-input',
208
+ expect(get_list_response.records.first.next_possible_charge_date).to eq('next_possible_charge_date-input')
31
209
 
32
- 'scheme' => 'scheme-input',
210
+ expect(get_list_response.records.first.payments_require_approval).to eq('payments_require_approval-input')
33
211
 
34
- 'status' => 'status-input'
212
+ expect(get_list_response.records.first.reference).to eq('reference-input')
213
+
214
+ expect(get_list_response.records.first.scheme).to eq('scheme-input')
215
+
216
+ expect(get_list_response.records.first.status).to eq('status-input')
217
+ end
35
218
 
36
- }
219
+ it 'exposes the cursors for before and after' do
220
+ expect(get_list_response.before).to eq(nil)
221
+ expect(get_list_response.after).to eq('ABC123')
222
+ end
223
+
224
+ specify { expect(get_list_response.api_response.headers).to eql('content-type' => 'application/json') }
37
225
  end
226
+ end
38
227
 
39
- it 'can be initialized from an unenveloped response' do
40
- resource = described_class.new(data)
228
+ describe '#all' do
229
+ let!(:first_response_stub) do
230
+ stub_request(:get, %r{.*api.gocardless.com/mandates$}).to_return(
231
+ body: {
232
+ 'mandates' => [{
233
+
234
+ 'created_at' => 'created_at-input',
235
+ 'id' => 'id-input',
236
+ 'links' => 'links-input',
237
+ 'metadata' => 'metadata-input',
238
+ 'next_possible_charge_date' => 'next_possible_charge_date-input',
239
+ 'payments_require_approval' => 'payments_require_approval-input',
240
+ 'reference' => 'reference-input',
241
+ 'scheme' => 'scheme-input',
242
+ 'status' => 'status-input'
243
+ }],
244
+ meta: {
245
+ cursors: { after: 'AB345' },
246
+ limit: 1
247
+ }
248
+ }.to_json,
249
+ headers: response_headers
250
+ )
251
+ end
41
252
 
42
- expect(resource.created_at).to eq('created_at-input')
253
+ let!(:second_response_stub) do
254
+ stub_request(:get, %r{.*api.gocardless.com/mandates\?after=AB345}).to_return(
255
+ body: {
256
+ 'mandates' => [{
257
+
258
+ 'created_at' => 'created_at-input',
259
+ 'id' => 'id-input',
260
+ 'links' => 'links-input',
261
+ 'metadata' => 'metadata-input',
262
+ 'next_possible_charge_date' => 'next_possible_charge_date-input',
263
+ 'payments_require_approval' => 'payments_require_approval-input',
264
+ 'reference' => 'reference-input',
265
+ 'scheme' => 'scheme-input',
266
+ 'status' => 'status-input'
267
+ }],
268
+ meta: {
269
+ limit: 2,
270
+ cursors: {}
271
+ }
272
+ }.to_json,
273
+ headers: response_headers
274
+ )
275
+ end
43
276
 
44
- expect(resource.id).to eq('id-input')
277
+ it 'automatically makes the extra requests' do
278
+ expect(client.mandates.all.to_a.length).to eq(2)
279
+ expect(first_response_stub).to have_been_requested
280
+ expect(second_response_stub).to have_been_requested
281
+ end
282
+ end
283
+
284
+ describe '#get' do
285
+ let(:id) { 'ID123' }
286
+
287
+ subject(:get_response) { client.mandates.get(id) }
288
+
289
+ context 'passing in a custom header' do
290
+ let!(:stub) do
291
+ stub_url = '/mandates/:identity'.gsub(':identity', id)
292
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/)
293
+ .with(headers: { 'Foo' => 'Bar' })
294
+ .to_return(
295
+ body: {
296
+ 'mandates' => {
297
+
298
+ 'created_at' => 'created_at-input',
299
+ 'id' => 'id-input',
300
+ 'links' => 'links-input',
301
+ 'metadata' => 'metadata-input',
302
+ 'next_possible_charge_date' => 'next_possible_charge_date-input',
303
+ 'payments_require_approval' => 'payments_require_approval-input',
304
+ 'reference' => 'reference-input',
305
+ 'scheme' => 'scheme-input',
306
+ 'status' => 'status-input'
307
+ }
308
+ }.to_json,
309
+ headers: response_headers
310
+ )
311
+ end
45
312
 
46
- expect(resource.links.creditor).to eq('creditor-input')
313
+ subject(:get_response) do
314
+ client.mandates.get(id, headers: {
315
+ 'Foo' => 'Bar'
316
+ })
317
+ end
318
+
319
+ it 'includes the header' do
320
+ get_response
321
+ expect(stub).to have_been_requested
322
+ end
323
+ end
47
324
 
48
- expect(resource.links.customer).to eq('customer-input')
325
+ context 'when there is a mandate to return' do
326
+ before do
327
+ stub_url = '/mandates/:identity'.gsub(':identity', id)
328
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
329
+ body: {
330
+ 'mandates' => {
331
+
332
+ 'created_at' => 'created_at-input',
333
+ 'id' => 'id-input',
334
+ 'links' => 'links-input',
335
+ 'metadata' => 'metadata-input',
336
+ 'next_possible_charge_date' => 'next_possible_charge_date-input',
337
+ 'payments_require_approval' => 'payments_require_approval-input',
338
+ 'reference' => 'reference-input',
339
+ 'scheme' => 'scheme-input',
340
+ 'status' => 'status-input'
341
+ }
342
+ }.to_json,
343
+ headers: response_headers
344
+ )
345
+ end
346
+
347
+ it 'wraps the response in a resource' do
348
+ expect(get_response).to be_a(GoCardlessPro::Resources::Mandate)
349
+ end
350
+ end
351
+
352
+ context 'when nothing is returned' do
353
+ before do
354
+ stub_url = '/mandates/:identity'.gsub(':identity', id)
355
+ stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
356
+ body: '',
357
+ headers: response_headers
358
+ )
359
+ end
49
360
 
50
- expect(resource.links.customer_bank_account).to eq('customer_bank_account-input')
361
+ it 'returns nil' do
362
+ expect(get_response).to be_nil
363
+ end
364
+ end
51
365
 
52
- expect(resource.links.new_mandate).to eq('new_mandate-input')
366
+ context "when an ID is specified which can't be included in a valid URI" do
367
+ let(:id) { '`' }
53
368
 
54
- expect(resource.metadata).to eq('metadata-input')
369
+ it "doesn't raise an error" do
370
+ expect { get_response }.to_not raise_error(/bad URI/)
371
+ end
372
+ end
373
+ end
55
374
 
56
- expect(resource.next_possible_charge_date).to eq('next_possible_charge_date-input')
375
+ describe '#update' do
376
+ subject(:put_update_response) { client.mandates.update(id, params: update_params) }
377
+ let(:id) { 'ABC123' }
378
+
379
+ context 'with a valid request' do
380
+ let(:update_params) { { 'hello' => 'world' } }
381
+
382
+ let!(:stub) do
383
+ stub_url = '/mandates/:identity'.gsub(':identity', id)
384
+ stub_request(:put, /.*api.gocardless.com#{stub_url}/).to_return(
385
+ body: {
386
+ 'mandates' => {
387
+
388
+ 'created_at' => 'created_at-input',
389
+ 'id' => 'id-input',
390
+ 'links' => 'links-input',
391
+ 'metadata' => 'metadata-input',
392
+ 'next_possible_charge_date' => 'next_possible_charge_date-input',
393
+ 'payments_require_approval' => 'payments_require_approval-input',
394
+ 'reference' => 'reference-input',
395
+ 'scheme' => 'scheme-input',
396
+ 'status' => 'status-input'
397
+ }
398
+ }.to_json,
399
+ headers: response_headers
400
+ )
401
+ end
57
402
 
58
- expect(resource.payments_require_approval).to eq('payments_require_approval-input')
403
+ it 'updates and returns the resource' do
404
+ expect(put_update_response).to be_a(GoCardlessPro::Resources::Mandate)
405
+ expect(stub).to have_been_requested
406
+ end
407
+ end
408
+ end
59
409
 
60
- expect(resource.reference).to eq('reference-input')
410
+ describe '#cancel' do
411
+ subject(:post_response) { client.mandates.cancel(resource_id) }
412
+
413
+ let(:resource_id) { 'ABC123' }
414
+
415
+ let!(:stub) do
416
+ # /mandates/%v/actions/cancel
417
+ stub_url = '/mandates/:identity/actions/cancel'.gsub(':identity', resource_id)
418
+ stub_request(:post, /.*api.gocardless.com#{stub_url}/).to_return(
419
+ body: {
420
+ 'mandates' => {
421
+
422
+ 'created_at' => 'created_at-input',
423
+ 'id' => 'id-input',
424
+ 'links' => 'links-input',
425
+ 'metadata' => 'metadata-input',
426
+ 'next_possible_charge_date' => 'next_possible_charge_date-input',
427
+ 'payments_require_approval' => 'payments_require_approval-input',
428
+ 'reference' => 'reference-input',
429
+ 'scheme' => 'scheme-input',
430
+ 'status' => 'status-input'
431
+ }
432
+ }.to_json,
433
+ headers: response_headers
434
+ )
435
+ end
61
436
 
62
- expect(resource.scheme).to eq('scheme-input')
437
+ it 'wraps the response and calls the right endpoint' do
438
+ expect(post_response).to be_a(GoCardlessPro::Resources::Mandate)
63
439
 
64
- expect(resource.status).to eq('status-input')
440
+ expect(stub).to have_been_requested
65
441
  end
66
442
 
67
- it 'can handle new attributes without erroring' do
68
- data['foo'] = 'bar'
69
- expect { described_class.new(data) }.to_not raise_error
443
+ context 'when the request needs a body and custom header' do
444
+ let(:body) { { foo: 'bar' } }
445
+ let(:headers) { { 'Foo' => 'Bar' } }
446
+ subject(:post_response) { client.mandates.cancel(resource_id, body, headers) }
447
+
448
+ let(:resource_id) { 'ABC123' }
449
+
450
+ let!(:stub) do
451
+ # /mandates/%v/actions/cancel
452
+ stub_url = '/mandates/:identity/actions/cancel'.gsub(':identity', resource_id)
453
+ stub_request(:post, /.*api.gocardless.com#{stub_url}/)
454
+ .with(
455
+ body: { foo: 'bar' },
456
+ headers: { 'Foo' => 'Bar' }
457
+ ).to_return(
458
+ body: {
459
+ 'mandates' => {
460
+
461
+ 'created_at' => 'created_at-input',
462
+ 'id' => 'id-input',
463
+ 'links' => 'links-input',
464
+ 'metadata' => 'metadata-input',
465
+ 'next_possible_charge_date' => 'next_possible_charge_date-input',
466
+ 'payments_require_approval' => 'payments_require_approval-input',
467
+ 'reference' => 'reference-input',
468
+ 'scheme' => 'scheme-input',
469
+ 'status' => 'status-input'
470
+ }
471
+ }.to_json,
472
+ headers: response_headers
473
+ )
474
+ end
70
475
  end
476
+ end
71
477
 
72
- it 'can handle new link attributes without erroring' do
73
- data['links']['foo'] = 'bar'
74
- expect { described_class.new(data) }.to_not raise_error
478
+ describe '#reinstate' do
479
+ subject(:post_response) { client.mandates.reinstate(resource_id) }
480
+
481
+ let(:resource_id) { 'ABC123' }
482
+
483
+ let!(:stub) do
484
+ # /mandates/%v/actions/reinstate
485
+ stub_url = '/mandates/:identity/actions/reinstate'.gsub(':identity', resource_id)
486
+ stub_request(:post, /.*api.gocardless.com#{stub_url}/).to_return(
487
+ body: {
488
+ 'mandates' => {
489
+
490
+ 'created_at' => 'created_at-input',
491
+ 'id' => 'id-input',
492
+ 'links' => 'links-input',
493
+ 'metadata' => 'metadata-input',
494
+ 'next_possible_charge_date' => 'next_possible_charge_date-input',
495
+ 'payments_require_approval' => 'payments_require_approval-input',
496
+ 'reference' => 'reference-input',
497
+ 'scheme' => 'scheme-input',
498
+ 'status' => 'status-input'
499
+ }
500
+ }.to_json,
501
+ headers: response_headers
502
+ )
75
503
  end
76
504
 
77
- it 'can handle a nil links value' do
78
- data['links'] = nil
79
- expect { described_class.new(data).links }.to_not raise_error
505
+ it 'wraps the response and calls the right endpoint' do
506
+ expect(post_response).to be_a(GoCardlessPro::Resources::Mandate)
507
+
508
+ expect(stub).to have_been_requested
80
509
  end
81
510
 
82
- describe '#to_h' do
83
- it 'returns a hash representing the resource' do
84
- expect(described_class.new(data).to_h).to eq(data)
511
+ context 'when the request needs a body and custom header' do
512
+ let(:body) { { foo: 'bar' } }
513
+ let(:headers) { { 'Foo' => 'Bar' } }
514
+ subject(:post_response) { client.mandates.reinstate(resource_id, body, headers) }
515
+
516
+ let(:resource_id) { 'ABC123' }
517
+
518
+ let!(:stub) do
519
+ # /mandates/%v/actions/reinstate
520
+ stub_url = '/mandates/:identity/actions/reinstate'.gsub(':identity', resource_id)
521
+ stub_request(:post, /.*api.gocardless.com#{stub_url}/)
522
+ .with(
523
+ body: { foo: 'bar' },
524
+ headers: { 'Foo' => 'Bar' }
525
+ ).to_return(
526
+ body: {
527
+ 'mandates' => {
528
+
529
+ 'created_at' => 'created_at-input',
530
+ 'id' => 'id-input',
531
+ 'links' => 'links-input',
532
+ 'metadata' => 'metadata-input',
533
+ 'next_possible_charge_date' => 'next_possible_charge_date-input',
534
+ 'payments_require_approval' => 'payments_require_approval-input',
535
+ 'reference' => 'reference-input',
536
+ 'scheme' => 'scheme-input',
537
+ 'status' => 'status-input'
538
+ }
539
+ }.to_json,
540
+ headers: response_headers
541
+ )
85
542
  end
86
543
  end
87
544
  end