gocardless_pro 1.1.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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