gocardless_pro 2.41.0 → 2.41.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. checksums.yaml +4 -4
  2. data/lib/gocardless_pro/api_service.rb +4 -5
  3. data/lib/gocardless_pro/client.rb +3 -3
  4. data/lib/gocardless_pro/error/invalid_state_error.rb +1 -0
  5. data/lib/gocardless_pro/error.rb +1 -0
  6. data/lib/gocardless_pro/middlewares/raise_gocardless_errors.rb +7 -9
  7. data/lib/gocardless_pro/request.rb +5 -7
  8. data/lib/gocardless_pro/resources/bank_authorisation.rb +0 -2
  9. data/lib/gocardless_pro/resources/bank_details_lookup.rb +0 -2
  10. data/lib/gocardless_pro/resources/billing_request.rb +0 -2
  11. data/lib/gocardless_pro/resources/billing_request_flow.rb +0 -2
  12. data/lib/gocardless_pro/resources/billing_request_template.rb +0 -2
  13. data/lib/gocardless_pro/resources/block.rb +0 -2
  14. data/lib/gocardless_pro/resources/creditor.rb +0 -2
  15. data/lib/gocardless_pro/resources/creditor_bank_account.rb +0 -2
  16. data/lib/gocardless_pro/resources/currency_exchange_rate.rb +0 -2
  17. data/lib/gocardless_pro/resources/customer.rb +0 -2
  18. data/lib/gocardless_pro/resources/customer_bank_account.rb +0 -2
  19. data/lib/gocardless_pro/resources/customer_notification.rb +0 -2
  20. data/lib/gocardless_pro/resources/event.rb +0 -2
  21. data/lib/gocardless_pro/resources/instalment_schedule.rb +0 -2
  22. data/lib/gocardless_pro/resources/institution.rb +0 -2
  23. data/lib/gocardless_pro/resources/mandate.rb +0 -2
  24. data/lib/gocardless_pro/resources/mandate_import.rb +0 -2
  25. data/lib/gocardless_pro/resources/mandate_import_entry.rb +0 -2
  26. data/lib/gocardless_pro/resources/mandate_pdf.rb +0 -2
  27. data/lib/gocardless_pro/resources/payer_authorisation.rb +0 -2
  28. data/lib/gocardless_pro/resources/payment.rb +0 -2
  29. data/lib/gocardless_pro/resources/payout.rb +0 -2
  30. data/lib/gocardless_pro/resources/payout_item.rb +0 -2
  31. data/lib/gocardless_pro/resources/redirect_flow.rb +0 -2
  32. data/lib/gocardless_pro/resources/refund.rb +0 -2
  33. data/lib/gocardless_pro/resources/scenario_simulator.rb +0 -2
  34. data/lib/gocardless_pro/resources/scheme_identifier.rb +0 -2
  35. data/lib/gocardless_pro/resources/subscription.rb +0 -2
  36. data/lib/gocardless_pro/resources/tax_rate.rb +0 -2
  37. data/lib/gocardless_pro/resources/verification_detail.rb +0 -2
  38. data/lib/gocardless_pro/resources/webhook.rb +0 -2
  39. data/lib/gocardless_pro/services/bank_authorisations_service.rb +3 -1
  40. data/lib/gocardless_pro/services/billing_request_flows_service.rb +3 -1
  41. data/lib/gocardless_pro/services/billing_request_templates_service.rb +6 -2
  42. data/lib/gocardless_pro/services/billing_requests_service.rb +27 -9
  43. data/lib/gocardless_pro/services/blocks_service.rb +9 -3
  44. data/lib/gocardless_pro/services/creditor_bank_accounts_service.rb +6 -2
  45. data/lib/gocardless_pro/services/creditors_service.rb +9 -3
  46. data/lib/gocardless_pro/services/customer_bank_accounts_service.rb +9 -3
  47. data/lib/gocardless_pro/services/customer_notifications_service.rb +3 -1
  48. data/lib/gocardless_pro/services/customers_service.rb +9 -3
  49. data/lib/gocardless_pro/services/events_service.rb +3 -1
  50. data/lib/gocardless_pro/services/instalment_schedules_service.rb +9 -3
  51. data/lib/gocardless_pro/services/mandate_imports_service.rb +9 -3
  52. data/lib/gocardless_pro/services/mandates_service.rb +12 -4
  53. data/lib/gocardless_pro/services/payer_authorisations_service.rb +12 -4
  54. data/lib/gocardless_pro/services/payments_service.rb +12 -4
  55. data/lib/gocardless_pro/services/payouts_service.rb +6 -2
  56. data/lib/gocardless_pro/services/redirect_flows_service.rb +6 -2
  57. data/lib/gocardless_pro/services/refunds_service.rb +6 -2
  58. data/lib/gocardless_pro/services/scenario_simulators_service.rb +3 -1
  59. data/lib/gocardless_pro/services/scheme_identifiers_service.rb +3 -1
  60. data/lib/gocardless_pro/services/subscriptions_service.rb +15 -5
  61. data/lib/gocardless_pro/services/tax_rates_service.rb +3 -1
  62. data/lib/gocardless_pro/services/webhooks_service.rb +6 -2
  63. data/lib/gocardless_pro/version.rb +1 -2
  64. data/lib/gocardless_pro/webhook.rb +5 -4
  65. data/lib/gocardless_pro.rb +2 -4
  66. metadata +5 -195
  67. data/.github/workflows/tests.yml +0 -40
  68. data/.gitignore +0 -1
  69. data/.rspec +0 -2
  70. data/.rubocop.yml +0 -5
  71. data/.travis.yml +0 -10
  72. data/Gemfile +0 -10
  73. data/demo.rb +0 -9
  74. data/gocardless_pro.gemspec +0 -39
  75. data/spec/api_response_spec.rb +0 -28
  76. data/spec/api_service_spec.rb +0 -188
  77. data/spec/client_spec.rb +0 -19
  78. data/spec/error_spec.rb +0 -53
  79. data/spec/middlewares/raise_gocardless_errors_spec.rb +0 -127
  80. data/spec/resources/bank_authorisation_spec.rb +0 -259
  81. data/spec/resources/bank_details_lookup_spec.rb +0 -121
  82. data/spec/resources/billing_request_flow_spec.rb +0 -257
  83. data/spec/resources/billing_request_spec.rb +0 -962
  84. data/spec/resources/billing_request_template_spec.rb +0 -515
  85. data/spec/resources/block_spec.rb +0 -577
  86. data/spec/resources/creditor_bank_account_spec.rb +0 -472
  87. data/spec/resources/creditor_spec.rb +0 -659
  88. data/spec/resources/currency_exchange_rate_spec.rb +0 -103
  89. data/spec/resources/customer_bank_account_spec.rb +0 -509
  90. data/spec/resources/customer_notification_spec.rb +0 -75
  91. data/spec/resources/customer_spec.rb +0 -616
  92. data/spec/resources/event_spec.rb +0 -210
  93. data/spec/resources/instalment_schedule_spec.rb +0 -636
  94. data/spec/resources/institution_spec.rb +0 -113
  95. data/spec/resources/mandate_import_entry_spec.rb +0 -206
  96. data/spec/resources/mandate_import_spec.rb +0 -344
  97. data/spec/resources/mandate_pdf_spec.rb +0 -117
  98. data/spec/resources/mandate_spec.rb +0 -600
  99. data/spec/resources/payer_authorisation_spec.rb +0 -422
  100. data/spec/resources/payment_spec.rb +0 -617
  101. data/spec/resources/payout_item_spec.rb +0 -101
  102. data/spec/resources/payout_spec.rb +0 -284
  103. data/spec/resources/redirect_flow_spec.rb +0 -347
  104. data/spec/resources/refund_spec.rb +0 -409
  105. data/spec/resources/scenario_simulator_spec.rb +0 -65
  106. data/spec/resources/scheme_identifier_spec.rb +0 -484
  107. data/spec/resources/subscription_spec.rb +0 -828
  108. data/spec/resources/tax_rate_spec.rb +0 -198
  109. data/spec/resources/verification_detail_spec.rb +0 -145
  110. data/spec/resources/webhook_spec.rb +0 -325
  111. data/spec/response_spec.rb +0 -34
  112. data/spec/services/bank_authorisations_service_spec.rb +0 -353
  113. data/spec/services/bank_details_lookups_service_spec.rb +0 -144
  114. data/spec/services/billing_request_flows_service_spec.rb +0 -291
  115. data/spec/services/billing_request_templates_service_spec.rb +0 -806
  116. data/spec/services/billing_requests_service_spec.rb +0 -1288
  117. data/spec/services/blocks_service_spec.rb +0 -840
  118. data/spec/services/creditor_bank_accounts_service_spec.rb +0 -725
  119. data/spec/services/creditors_service_spec.rb +0 -977
  120. data/spec/services/currency_exchange_rates_service_spec.rb +0 -223
  121. data/spec/services/customer_bank_accounts_service_spec.rb +0 -787
  122. data/spec/services/customer_notifications_service_spec.rb +0 -86
  123. data/spec/services/customers_service_spec.rb +0 -922
  124. data/spec/services/events_service_spec.rb +0 -401
  125. data/spec/services/instalment_schedules_service_spec.rb +0 -945
  126. data/spec/services/institutions_service_spec.rb +0 -241
  127. data/spec/services/mandate_import_entries_service_spec.rb +0 -345
  128. data/spec/services/mandate_imports_service_spec.rb +0 -460
  129. data/spec/services/mandate_pdfs_service_spec.rb +0 -140
  130. data/spec/services/mandates_service_spec.rb +0 -893
  131. data/spec/services/payer_authorisations_service_spec.rb +0 -563
  132. data/spec/services/payments_service_spec.rb +0 -914
  133. data/spec/services/payout_items_service_spec.rb +0 -221
  134. data/spec/services/payouts_service_spec.rb +0 -520
  135. data/spec/services/redirect_flows_service_spec.rb +0 -452
  136. data/spec/services/refunds_service_spec.rb +0 -668
  137. data/spec/services/scenario_simulators_service_spec.rb +0 -76
  138. data/spec/services/scheme_identifiers_service_spec.rb +0 -754
  139. data/spec/services/subscriptions_service_spec.rb +0 -1164
  140. data/spec/services/tax_rates_service_spec.rb +0 -381
  141. data/spec/services/verification_details_service_spec.rb +0 -168
  142. data/spec/services/webhooks_service_spec.rb +0 -547
  143. data/spec/spec_helper.rb +0 -90
  144. data/spec/webhook_spec.rb +0 -122
@@ -1,977 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe GoCardlessPro::Services::CreditorsService 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 '#create' do
13
- subject(:post_create_response) { client.creditors.create(params: new_resource) }
14
- context 'with a valid request' do
15
- let(:new_resource) do
16
- {
17
-
18
- 'activated' => 'activated-input',
19
- 'address_line1' => 'address_line1-input',
20
- 'address_line2' => 'address_line2-input',
21
- 'address_line3' => 'address_line3-input',
22
- 'can_create_refunds' => 'can_create_refunds-input',
23
- 'city' => 'city-input',
24
- 'country_code' => 'country_code-input',
25
- 'created_at' => 'created_at-input',
26
- 'creditor_type' => 'creditor_type-input',
27
- 'custom_payment_pages_enabled' => 'custom_payment_pages_enabled-input',
28
- 'fx_payout_currency' => 'fx_payout_currency-input',
29
- 'id' => 'id-input',
30
- 'links' => 'links-input',
31
- 'logo_url' => 'logo_url-input',
32
- 'mandate_imports_enabled' => 'mandate_imports_enabled-input',
33
- 'merchant_responsible_for_notifications' => 'merchant_responsible_for_notifications-input',
34
- 'name' => 'name-input',
35
- 'postal_code' => 'postal_code-input',
36
- 'region' => 'region-input',
37
- 'scheme_identifiers' => 'scheme_identifiers-input',
38
- 'verification_status' => 'verification_status-input',
39
- }
40
- end
41
-
42
- before do
43
- stub_request(:post, %r{.*api.gocardless.com/creditors}).
44
- with(
45
- body: {
46
- 'creditors' => {
47
-
48
- 'activated' => 'activated-input',
49
- 'address_line1' => 'address_line1-input',
50
- 'address_line2' => 'address_line2-input',
51
- 'address_line3' => 'address_line3-input',
52
- 'can_create_refunds' => 'can_create_refunds-input',
53
- 'city' => 'city-input',
54
- 'country_code' => 'country_code-input',
55
- 'created_at' => 'created_at-input',
56
- 'creditor_type' => 'creditor_type-input',
57
- 'custom_payment_pages_enabled' => 'custom_payment_pages_enabled-input',
58
- 'fx_payout_currency' => 'fx_payout_currency-input',
59
- 'id' => 'id-input',
60
- 'links' => 'links-input',
61
- 'logo_url' => 'logo_url-input',
62
- 'mandate_imports_enabled' => 'mandate_imports_enabled-input',
63
- 'merchant_responsible_for_notifications' => 'merchant_responsible_for_notifications-input',
64
- 'name' => 'name-input',
65
- 'postal_code' => 'postal_code-input',
66
- 'region' => 'region-input',
67
- 'scheme_identifiers' => 'scheme_identifiers-input',
68
- 'verification_status' => 'verification_status-input',
69
- },
70
- }
71
- ).
72
- to_return(
73
- body: {
74
- 'creditors' =>
75
-
76
- {
77
-
78
- 'activated' => 'activated-input',
79
- 'address_line1' => 'address_line1-input',
80
- 'address_line2' => 'address_line2-input',
81
- 'address_line3' => 'address_line3-input',
82
- 'can_create_refunds' => 'can_create_refunds-input',
83
- 'city' => 'city-input',
84
- 'country_code' => 'country_code-input',
85
- 'created_at' => 'created_at-input',
86
- 'creditor_type' => 'creditor_type-input',
87
- 'custom_payment_pages_enabled' => 'custom_payment_pages_enabled-input',
88
- 'fx_payout_currency' => 'fx_payout_currency-input',
89
- 'id' => 'id-input',
90
- 'links' => 'links-input',
91
- 'logo_url' => 'logo_url-input',
92
- 'mandate_imports_enabled' => 'mandate_imports_enabled-input',
93
- 'merchant_responsible_for_notifications' => 'merchant_responsible_for_notifications-input',
94
- 'name' => 'name-input',
95
- 'postal_code' => 'postal_code-input',
96
- 'region' => 'region-input',
97
- 'scheme_identifiers' => 'scheme_identifiers-input',
98
- 'verification_status' => 'verification_status-input',
99
- },
100
-
101
- }.to_json,
102
- headers: response_headers
103
- )
104
- end
105
-
106
- it 'creates and returns the resource' do
107
- expect(post_create_response).to be_a(GoCardlessPro::Resources::Creditor)
108
- end
109
-
110
- describe 'retry behaviour' do
111
- before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
112
-
113
- it 'retries timeouts' do
114
- stub = stub_request(:post, %r{.*api.gocardless.com/creditors}).
115
- to_timeout.then.to_return(status: 200, headers: response_headers)
116
-
117
- post_create_response
118
- expect(stub).to have_been_requested.twice
119
- end
120
-
121
- it 'retries 5XX errors' do
122
- stub = stub_request(:post, %r{.*api.gocardless.com/creditors}).
123
- to_return(status: 502,
124
- headers: { 'Content-Type' => 'text/html' },
125
- body: '<html><body>Response from Cloudflare</body></html>').
126
- then.to_return(status: 200, headers: response_headers)
127
-
128
- post_create_response
129
- expect(stub).to have_been_requested.twice
130
- end
131
- end
132
- end
133
-
134
- context 'with a request that returns a validation error' do
135
- let(:new_resource) { {} }
136
-
137
- before do
138
- stub_request(:post, %r{.*api.gocardless.com/creditors}).to_return(
139
- body: {
140
- error: {
141
- type: 'validation_failed',
142
- code: 422,
143
- errors: [
144
- { message: 'test error message', field: 'test_field' },
145
- ],
146
- },
147
- }.to_json,
148
- headers: response_headers,
149
- status: 422
150
- )
151
- end
152
-
153
- it 'throws the correct error' do
154
- expect { post_create_response }.to raise_error(GoCardlessPro::ValidationError)
155
- end
156
- end
157
-
158
- context 'with a request that returns an idempotent creation conflict error' do
159
- let(:id) { 'ID123' }
160
-
161
- let(:new_resource) do
162
- {
163
-
164
- 'activated' => 'activated-input',
165
- 'address_line1' => 'address_line1-input',
166
- 'address_line2' => 'address_line2-input',
167
- 'address_line3' => 'address_line3-input',
168
- 'can_create_refunds' => 'can_create_refunds-input',
169
- 'city' => 'city-input',
170
- 'country_code' => 'country_code-input',
171
- 'created_at' => 'created_at-input',
172
- 'creditor_type' => 'creditor_type-input',
173
- 'custom_payment_pages_enabled' => 'custom_payment_pages_enabled-input',
174
- 'fx_payout_currency' => 'fx_payout_currency-input',
175
- 'id' => 'id-input',
176
- 'links' => 'links-input',
177
- 'logo_url' => 'logo_url-input',
178
- 'mandate_imports_enabled' => 'mandate_imports_enabled-input',
179
- 'merchant_responsible_for_notifications' => 'merchant_responsible_for_notifications-input',
180
- 'name' => 'name-input',
181
- 'postal_code' => 'postal_code-input',
182
- 'region' => 'region-input',
183
- 'scheme_identifiers' => 'scheme_identifiers-input',
184
- 'verification_status' => 'verification_status-input',
185
- }
186
- end
187
-
188
- let!(:post_stub) do
189
- stub_request(:post, %r{.*api.gocardless.com/creditors}).to_return(
190
- body: {
191
- error: {
192
- type: 'invalid_state',
193
- code: 409,
194
- errors: [
195
- {
196
- message: 'A resource has already been created with this idempotency key',
197
- reason: 'idempotent_creation_conflict',
198
- links: {
199
- conflicting_resource_id: id,
200
- },
201
- },
202
- ],
203
- },
204
- }.to_json,
205
- headers: response_headers,
206
- status: 409
207
- )
208
- end
209
-
210
- let!(:get_stub) do
211
- stub_url = "/creditors/#{id}"
212
- stub_request(:get, /.*api.gocardless.com#{stub_url}/).
213
- to_return(
214
- body: {
215
- 'creditors' => {
216
-
217
- 'activated' => 'activated-input',
218
- 'address_line1' => 'address_line1-input',
219
- 'address_line2' => 'address_line2-input',
220
- 'address_line3' => 'address_line3-input',
221
- 'can_create_refunds' => 'can_create_refunds-input',
222
- 'city' => 'city-input',
223
- 'country_code' => 'country_code-input',
224
- 'created_at' => 'created_at-input',
225
- 'creditor_type' => 'creditor_type-input',
226
- 'custom_payment_pages_enabled' => 'custom_payment_pages_enabled-input',
227
- 'fx_payout_currency' => 'fx_payout_currency-input',
228
- 'id' => 'id-input',
229
- 'links' => 'links-input',
230
- 'logo_url' => 'logo_url-input',
231
- 'mandate_imports_enabled' => 'mandate_imports_enabled-input',
232
- 'merchant_responsible_for_notifications' => 'merchant_responsible_for_notifications-input',
233
- 'name' => 'name-input',
234
- 'postal_code' => 'postal_code-input',
235
- 'region' => 'region-input',
236
- 'scheme_identifiers' => 'scheme_identifiers-input',
237
- 'verification_status' => 'verification_status-input',
238
- },
239
- }.to_json,
240
- headers: response_headers
241
- )
242
- end
243
-
244
- context 'with default behaviour' do
245
- it 'fetches the already-created resource' do
246
- post_create_response
247
- expect(post_stub).to have_been_requested
248
- expect(get_stub).to have_been_requested
249
- end
250
- end
251
-
252
- context 'with on_idempotency_conflict: :raise' do
253
- let(:client) do
254
- GoCardlessPro::Client.new(
255
- access_token: 'SECRET_TOKEN',
256
- on_idempotency_conflict: :raise
257
- )
258
- end
259
-
260
- it 'raises an IdempotencyConflict error' do
261
- expect { post_create_response }.
262
- to raise_error(GoCardlessPro::IdempotencyConflict)
263
- end
264
- end
265
- end
266
- end
267
-
268
- describe '#list' do
269
- describe 'with no filters' do
270
- subject(:get_list_response) { client.creditors.list }
271
-
272
- let(:body) do
273
- {
274
- 'creditors' => [{
275
-
276
- 'activated' => 'activated-input',
277
- 'address_line1' => 'address_line1-input',
278
- 'address_line2' => 'address_line2-input',
279
- 'address_line3' => 'address_line3-input',
280
- 'can_create_refunds' => 'can_create_refunds-input',
281
- 'city' => 'city-input',
282
- 'country_code' => 'country_code-input',
283
- 'created_at' => 'created_at-input',
284
- 'creditor_type' => 'creditor_type-input',
285
- 'custom_payment_pages_enabled' => 'custom_payment_pages_enabled-input',
286
- 'fx_payout_currency' => 'fx_payout_currency-input',
287
- 'id' => 'id-input',
288
- 'links' => 'links-input',
289
- 'logo_url' => 'logo_url-input',
290
- 'mandate_imports_enabled' => 'mandate_imports_enabled-input',
291
- 'merchant_responsible_for_notifications' => 'merchant_responsible_for_notifications-input',
292
- 'name' => 'name-input',
293
- 'postal_code' => 'postal_code-input',
294
- 'region' => 'region-input',
295
- 'scheme_identifiers' => 'scheme_identifiers-input',
296
- 'verification_status' => 'verification_status-input',
297
- }],
298
- meta: {
299
- cursors: {
300
- before: nil,
301
- after: 'ABC123',
302
- },
303
- },
304
- }.to_json
305
- end
306
-
307
- before do
308
- stub_request(:get, %r{.*api.gocardless.com/creditors}).to_return(
309
- body: body,
310
- headers: response_headers
311
- )
312
- end
313
-
314
- it 'wraps each item in the resource class' do
315
- expect(get_list_response.records.map(&:class).uniq.first).to eq(GoCardlessPro::Resources::Creditor)
316
-
317
- expect(get_list_response.records.first.activated).to eq('activated-input')
318
-
319
- expect(get_list_response.records.first.address_line1).to eq('address_line1-input')
320
-
321
- expect(get_list_response.records.first.address_line2).to eq('address_line2-input')
322
-
323
- expect(get_list_response.records.first.address_line3).to eq('address_line3-input')
324
-
325
- expect(get_list_response.records.first.can_create_refunds).to eq('can_create_refunds-input')
326
-
327
- expect(get_list_response.records.first.city).to eq('city-input')
328
-
329
- expect(get_list_response.records.first.country_code).to eq('country_code-input')
330
-
331
- expect(get_list_response.records.first.created_at).to eq('created_at-input')
332
-
333
- expect(get_list_response.records.first.creditor_type).to eq('creditor_type-input')
334
-
335
- expect(get_list_response.records.first.custom_payment_pages_enabled).to eq('custom_payment_pages_enabled-input')
336
-
337
- expect(get_list_response.records.first.fx_payout_currency).to eq('fx_payout_currency-input')
338
-
339
- expect(get_list_response.records.first.id).to eq('id-input')
340
-
341
- expect(get_list_response.records.first.logo_url).to eq('logo_url-input')
342
-
343
- expect(get_list_response.records.first.mandate_imports_enabled).to eq('mandate_imports_enabled-input')
344
-
345
- expect(get_list_response.records.first.merchant_responsible_for_notifications).to eq('merchant_responsible_for_notifications-input')
346
-
347
- expect(get_list_response.records.first.name).to eq('name-input')
348
-
349
- expect(get_list_response.records.first.postal_code).to eq('postal_code-input')
350
-
351
- expect(get_list_response.records.first.region).to eq('region-input')
352
-
353
- expect(get_list_response.records.first.scheme_identifiers).to eq('scheme_identifiers-input')
354
-
355
- expect(get_list_response.records.first.verification_status).to eq('verification_status-input')
356
- end
357
-
358
- it 'exposes the cursors for before and after' do
359
- expect(get_list_response.before).to eq(nil)
360
- expect(get_list_response.after).to eq('ABC123')
361
- end
362
-
363
- specify { expect(get_list_response.api_response.headers).to eql('content-type' => 'application/json') }
364
-
365
- describe 'retry behaviour' do
366
- before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
367
-
368
- it 'retries timeouts' do
369
- stub = stub_request(:get, %r{.*api.gocardless.com/creditors}).
370
- to_timeout.then.to_return(status: 200, headers: response_headers, body: body)
371
-
372
- get_list_response
373
- expect(stub).to have_been_requested.twice
374
- end
375
-
376
- it 'retries 5XX errors' do
377
- stub = stub_request(:get, %r{.*api.gocardless.com/creditors}).
378
- to_return(status: 502,
379
- headers: { 'Content-Type' => 'text/html' },
380
- body: '<html><body>Response from Cloudflare</body></html>').
381
- then.to_return(status: 200, headers: response_headers, body: body)
382
-
383
- get_list_response
384
- expect(stub).to have_been_requested.twice
385
- end
386
- end
387
- end
388
- end
389
-
390
- describe '#all' do
391
- let!(:first_response_stub) do
392
- stub_request(:get, %r{.*api.gocardless.com/creditors$}).to_return(
393
- body: {
394
- 'creditors' => [{
395
-
396
- 'activated' => 'activated-input',
397
- 'address_line1' => 'address_line1-input',
398
- 'address_line2' => 'address_line2-input',
399
- 'address_line3' => 'address_line3-input',
400
- 'can_create_refunds' => 'can_create_refunds-input',
401
- 'city' => 'city-input',
402
- 'country_code' => 'country_code-input',
403
- 'created_at' => 'created_at-input',
404
- 'creditor_type' => 'creditor_type-input',
405
- 'custom_payment_pages_enabled' => 'custom_payment_pages_enabled-input',
406
- 'fx_payout_currency' => 'fx_payout_currency-input',
407
- 'id' => 'id-input',
408
- 'links' => 'links-input',
409
- 'logo_url' => 'logo_url-input',
410
- 'mandate_imports_enabled' => 'mandate_imports_enabled-input',
411
- 'merchant_responsible_for_notifications' => 'merchant_responsible_for_notifications-input',
412
- 'name' => 'name-input',
413
- 'postal_code' => 'postal_code-input',
414
- 'region' => 'region-input',
415
- 'scheme_identifiers' => 'scheme_identifiers-input',
416
- 'verification_status' => 'verification_status-input',
417
- }],
418
- meta: {
419
- cursors: { after: 'AB345' },
420
- limit: 1,
421
- },
422
- }.to_json,
423
- headers: response_headers
424
- )
425
- end
426
-
427
- let!(:second_response_stub) do
428
- stub_request(:get, %r{.*api.gocardless.com/creditors\?after=AB345}).to_return(
429
- body: {
430
- 'creditors' => [{
431
-
432
- 'activated' => 'activated-input',
433
- 'address_line1' => 'address_line1-input',
434
- 'address_line2' => 'address_line2-input',
435
- 'address_line3' => 'address_line3-input',
436
- 'can_create_refunds' => 'can_create_refunds-input',
437
- 'city' => 'city-input',
438
- 'country_code' => 'country_code-input',
439
- 'created_at' => 'created_at-input',
440
- 'creditor_type' => 'creditor_type-input',
441
- 'custom_payment_pages_enabled' => 'custom_payment_pages_enabled-input',
442
- 'fx_payout_currency' => 'fx_payout_currency-input',
443
- 'id' => 'id-input',
444
- 'links' => 'links-input',
445
- 'logo_url' => 'logo_url-input',
446
- 'mandate_imports_enabled' => 'mandate_imports_enabled-input',
447
- 'merchant_responsible_for_notifications' => 'merchant_responsible_for_notifications-input',
448
- 'name' => 'name-input',
449
- 'postal_code' => 'postal_code-input',
450
- 'region' => 'region-input',
451
- 'scheme_identifiers' => 'scheme_identifiers-input',
452
- 'verification_status' => 'verification_status-input',
453
- }],
454
- meta: {
455
- limit: 2,
456
- cursors: {},
457
- },
458
- }.to_json,
459
- headers: response_headers
460
- )
461
- end
462
-
463
- it 'automatically makes the extra requests' do
464
- expect(client.creditors.all.to_a.length).to eq(2)
465
- expect(first_response_stub).to have_been_requested
466
- expect(second_response_stub).to have_been_requested
467
- end
468
-
469
- describe 'retry behaviour' do
470
- before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
471
-
472
- it 'retries timeouts' do
473
- first_response_stub = stub_request(:get, %r{.*api.gocardless.com/creditors$}).to_return(
474
- body: {
475
- 'creditors' => [{
476
-
477
- 'activated' => 'activated-input',
478
- 'address_line1' => 'address_line1-input',
479
- 'address_line2' => 'address_line2-input',
480
- 'address_line3' => 'address_line3-input',
481
- 'can_create_refunds' => 'can_create_refunds-input',
482
- 'city' => 'city-input',
483
- 'country_code' => 'country_code-input',
484
- 'created_at' => 'created_at-input',
485
- 'creditor_type' => 'creditor_type-input',
486
- 'custom_payment_pages_enabled' => 'custom_payment_pages_enabled-input',
487
- 'fx_payout_currency' => 'fx_payout_currency-input',
488
- 'id' => 'id-input',
489
- 'links' => 'links-input',
490
- 'logo_url' => 'logo_url-input',
491
- 'mandate_imports_enabled' => 'mandate_imports_enabled-input',
492
- 'merchant_responsible_for_notifications' => 'merchant_responsible_for_notifications-input',
493
- 'name' => 'name-input',
494
- 'postal_code' => 'postal_code-input',
495
- 'region' => 'region-input',
496
- 'scheme_identifiers' => 'scheme_identifiers-input',
497
- 'verification_status' => 'verification_status-input',
498
- }],
499
- meta: {
500
- cursors: { after: 'AB345' },
501
- limit: 1,
502
- },
503
- }.to_json,
504
- headers: response_headers
505
- )
506
-
507
- second_response_stub = stub_request(:get, %r{.*api.gocardless.com/creditors\?after=AB345}).
508
- to_timeout.then.
509
- to_return(
510
- body: {
511
- 'creditors' => [{
512
-
513
- 'activated' => 'activated-input',
514
- 'address_line1' => 'address_line1-input',
515
- 'address_line2' => 'address_line2-input',
516
- 'address_line3' => 'address_line3-input',
517
- 'can_create_refunds' => 'can_create_refunds-input',
518
- 'city' => 'city-input',
519
- 'country_code' => 'country_code-input',
520
- 'created_at' => 'created_at-input',
521
- 'creditor_type' => 'creditor_type-input',
522
- 'custom_payment_pages_enabled' => 'custom_payment_pages_enabled-input',
523
- 'fx_payout_currency' => 'fx_payout_currency-input',
524
- 'id' => 'id-input',
525
- 'links' => 'links-input',
526
- 'logo_url' => 'logo_url-input',
527
- 'mandate_imports_enabled' => 'mandate_imports_enabled-input',
528
- 'merchant_responsible_for_notifications' => 'merchant_responsible_for_notifications-input',
529
- 'name' => 'name-input',
530
- 'postal_code' => 'postal_code-input',
531
- 'region' => 'region-input',
532
- 'scheme_identifiers' => 'scheme_identifiers-input',
533
- 'verification_status' => 'verification_status-input',
534
- }],
535
- meta: {
536
- limit: 2,
537
- cursors: {},
538
- },
539
- }.to_json,
540
- headers: response_headers
541
- )
542
-
543
- client.creditors.all.to_a
544
-
545
- expect(first_response_stub).to have_been_requested
546
- expect(second_response_stub).to have_been_requested.twice
547
- end
548
-
549
- it 'retries 5XX errors' do
550
- first_response_stub = stub_request(:get, %r{.*api.gocardless.com/creditors$}).to_return(
551
- body: {
552
- 'creditors' => [{
553
-
554
- 'activated' => 'activated-input',
555
- 'address_line1' => 'address_line1-input',
556
- 'address_line2' => 'address_line2-input',
557
- 'address_line3' => 'address_line3-input',
558
- 'can_create_refunds' => 'can_create_refunds-input',
559
- 'city' => 'city-input',
560
- 'country_code' => 'country_code-input',
561
- 'created_at' => 'created_at-input',
562
- 'creditor_type' => 'creditor_type-input',
563
- 'custom_payment_pages_enabled' => 'custom_payment_pages_enabled-input',
564
- 'fx_payout_currency' => 'fx_payout_currency-input',
565
- 'id' => 'id-input',
566
- 'links' => 'links-input',
567
- 'logo_url' => 'logo_url-input',
568
- 'mandate_imports_enabled' => 'mandate_imports_enabled-input',
569
- 'merchant_responsible_for_notifications' => 'merchant_responsible_for_notifications-input',
570
- 'name' => 'name-input',
571
- 'postal_code' => 'postal_code-input',
572
- 'region' => 'region-input',
573
- 'scheme_identifiers' => 'scheme_identifiers-input',
574
- 'verification_status' => 'verification_status-input',
575
- }],
576
- meta: {
577
- cursors: { after: 'AB345' },
578
- limit: 1,
579
- },
580
- }.to_json,
581
- headers: response_headers
582
- )
583
-
584
- second_response_stub = stub_request(:get, %r{.*api.gocardless.com/creditors\?after=AB345}).
585
- to_return(
586
- status: 502,
587
- body: '<html><body>Response from Cloudflare</body></html>',
588
- headers: { 'Content-Type' => 'text/html' }
589
- ).then.to_return(
590
- body: {
591
- 'creditors' => [{
592
-
593
- 'activated' => 'activated-input',
594
- 'address_line1' => 'address_line1-input',
595
- 'address_line2' => 'address_line2-input',
596
- 'address_line3' => 'address_line3-input',
597
- 'can_create_refunds' => 'can_create_refunds-input',
598
- 'city' => 'city-input',
599
- 'country_code' => 'country_code-input',
600
- 'created_at' => 'created_at-input',
601
- 'creditor_type' => 'creditor_type-input',
602
- 'custom_payment_pages_enabled' => 'custom_payment_pages_enabled-input',
603
- 'fx_payout_currency' => 'fx_payout_currency-input',
604
- 'id' => 'id-input',
605
- 'links' => 'links-input',
606
- 'logo_url' => 'logo_url-input',
607
- 'mandate_imports_enabled' => 'mandate_imports_enabled-input',
608
- 'merchant_responsible_for_notifications' => 'merchant_responsible_for_notifications-input',
609
- 'name' => 'name-input',
610
- 'postal_code' => 'postal_code-input',
611
- 'region' => 'region-input',
612
- 'scheme_identifiers' => 'scheme_identifiers-input',
613
- 'verification_status' => 'verification_status-input',
614
- }],
615
- meta: {
616
- limit: 2,
617
- cursors: {},
618
- },
619
- }.to_json,
620
- headers: response_headers
621
- )
622
-
623
- client.creditors.all.to_a
624
-
625
- expect(first_response_stub).to have_been_requested
626
- expect(second_response_stub).to have_been_requested.twice
627
- end
628
- end
629
- end
630
-
631
- describe '#get' do
632
- let(:id) { 'ID123' }
633
-
634
- subject(:get_response) { client.creditors.get(id) }
635
-
636
- context 'passing in a custom header' do
637
- let!(:stub) do
638
- stub_url = '/creditors/:identity'.gsub(':identity', id)
639
- stub_request(:get, /.*api.gocardless.com#{stub_url}/).
640
- with(headers: { 'Foo' => 'Bar' }).
641
- to_return(
642
- body: {
643
- 'creditors' => {
644
-
645
- 'activated' => 'activated-input',
646
- 'address_line1' => 'address_line1-input',
647
- 'address_line2' => 'address_line2-input',
648
- 'address_line3' => 'address_line3-input',
649
- 'can_create_refunds' => 'can_create_refunds-input',
650
- 'city' => 'city-input',
651
- 'country_code' => 'country_code-input',
652
- 'created_at' => 'created_at-input',
653
- 'creditor_type' => 'creditor_type-input',
654
- 'custom_payment_pages_enabled' => 'custom_payment_pages_enabled-input',
655
- 'fx_payout_currency' => 'fx_payout_currency-input',
656
- 'id' => 'id-input',
657
- 'links' => 'links-input',
658
- 'logo_url' => 'logo_url-input',
659
- 'mandate_imports_enabled' => 'mandate_imports_enabled-input',
660
- 'merchant_responsible_for_notifications' => 'merchant_responsible_for_notifications-input',
661
- 'name' => 'name-input',
662
- 'postal_code' => 'postal_code-input',
663
- 'region' => 'region-input',
664
- 'scheme_identifiers' => 'scheme_identifiers-input',
665
- 'verification_status' => 'verification_status-input',
666
- },
667
- }.to_json,
668
- headers: response_headers
669
- )
670
- end
671
-
672
- subject(:get_response) do
673
- client.creditors.get(id, headers: {
674
- 'Foo' => 'Bar',
675
- })
676
- end
677
-
678
- it 'includes the header' do
679
- get_response
680
- expect(stub).to have_been_requested
681
- end
682
- end
683
-
684
- context 'when there is a creditor to return' do
685
- before do
686
- stub_url = '/creditors/:identity'.gsub(':identity', id)
687
- stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
688
- body: {
689
- 'creditors' => {
690
-
691
- 'activated' => 'activated-input',
692
- 'address_line1' => 'address_line1-input',
693
- 'address_line2' => 'address_line2-input',
694
- 'address_line3' => 'address_line3-input',
695
- 'can_create_refunds' => 'can_create_refunds-input',
696
- 'city' => 'city-input',
697
- 'country_code' => 'country_code-input',
698
- 'created_at' => 'created_at-input',
699
- 'creditor_type' => 'creditor_type-input',
700
- 'custom_payment_pages_enabled' => 'custom_payment_pages_enabled-input',
701
- 'fx_payout_currency' => 'fx_payout_currency-input',
702
- 'id' => 'id-input',
703
- 'links' => 'links-input',
704
- 'logo_url' => 'logo_url-input',
705
- 'mandate_imports_enabled' => 'mandate_imports_enabled-input',
706
- 'merchant_responsible_for_notifications' => 'merchant_responsible_for_notifications-input',
707
- 'name' => 'name-input',
708
- 'postal_code' => 'postal_code-input',
709
- 'region' => 'region-input',
710
- 'scheme_identifiers' => 'scheme_identifiers-input',
711
- 'verification_status' => 'verification_status-input',
712
- },
713
- }.to_json,
714
- headers: response_headers
715
- )
716
- end
717
-
718
- it 'wraps the response in a resource' do
719
- expect(get_response).to be_a(GoCardlessPro::Resources::Creditor)
720
- end
721
- end
722
-
723
- context 'when nothing is returned' do
724
- before do
725
- stub_url = '/creditors/:identity'.gsub(':identity', id)
726
- stub_request(:get, /.*api.gocardless.com#{stub_url}/).to_return(
727
- body: '',
728
- headers: response_headers
729
- )
730
- end
731
-
732
- it 'returns nil' do
733
- expect(get_response).to be_nil
734
- end
735
- end
736
-
737
- context "when an ID is specified which can't be included in a valid URI" do
738
- let(:id) { '`' }
739
-
740
- it "doesn't raise an error" do
741
- expect { get_response }.to_not raise_error(/bad URI/)
742
- end
743
- end
744
-
745
- describe 'retry behaviour' do
746
- before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
747
-
748
- it 'retries timeouts' do
749
- stub_url = '/creditors/:identity'.gsub(':identity', id)
750
-
751
- stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/).
752
- to_timeout.then.to_return(status: 200, headers: response_headers)
753
-
754
- get_response
755
- expect(stub).to have_been_requested.twice
756
- end
757
-
758
- it 'retries 5XX errors, other than 500s' do
759
- stub_url = '/creditors/:identity'.gsub(':identity', id)
760
-
761
- stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/).
762
- to_return(status: 502,
763
- headers: { 'Content-Type' => 'text/html' },
764
- body: '<html><body>Response from Cloudflare</body></html>').
765
- then.to_return(status: 200, headers: response_headers)
766
-
767
- get_response
768
- expect(stub).to have_been_requested.twice
769
- end
770
-
771
- it 'retries 500 errors returned by the API' do
772
- stub_url = '/creditors/:identity'.gsub(':identity', id)
773
-
774
- gocardless_error = {
775
- 'error' => {
776
- 'message' => 'Internal server error',
777
- 'documentation_url' => 'https://developer.gocardless.com/#gocardless',
778
- 'errors' => [{
779
- 'message' => 'Internal server error',
780
- 'reason' => 'internal_server_error',
781
- }],
782
- 'type' => 'gocardless',
783
- 'code' => 500,
784
- 'request_id' => 'dummy_request_id',
785
- 'id' => 'dummy_exception_id',
786
- },
787
- }
788
-
789
- stub = stub_request(:get, /.*api.gocardless.com#{stub_url}/).
790
- to_return(status: 500,
791
- headers: response_headers,
792
- body: gocardless_error.to_json).
793
- then.to_return(status: 200, headers: response_headers)
794
-
795
- get_response
796
- expect(stub).to have_been_requested.twice
797
- end
798
- end
799
- end
800
-
801
- describe '#update' do
802
- subject(:put_update_response) { client.creditors.update(id, params: update_params) }
803
- let(:id) { 'ABC123' }
804
-
805
- context 'with a valid request' do
806
- let(:update_params) { { 'hello' => 'world' } }
807
-
808
- let!(:stub) do
809
- stub_url = '/creditors/:identity'.gsub(':identity', id)
810
- stub_request(:put, /.*api.gocardless.com#{stub_url}/).to_return(
811
- body: {
812
- 'creditors' => {
813
-
814
- 'activated' => 'activated-input',
815
- 'address_line1' => 'address_line1-input',
816
- 'address_line2' => 'address_line2-input',
817
- 'address_line3' => 'address_line3-input',
818
- 'can_create_refunds' => 'can_create_refunds-input',
819
- 'city' => 'city-input',
820
- 'country_code' => 'country_code-input',
821
- 'created_at' => 'created_at-input',
822
- 'creditor_type' => 'creditor_type-input',
823
- 'custom_payment_pages_enabled' => 'custom_payment_pages_enabled-input',
824
- 'fx_payout_currency' => 'fx_payout_currency-input',
825
- 'id' => 'id-input',
826
- 'links' => 'links-input',
827
- 'logo_url' => 'logo_url-input',
828
- 'mandate_imports_enabled' => 'mandate_imports_enabled-input',
829
- 'merchant_responsible_for_notifications' => 'merchant_responsible_for_notifications-input',
830
- 'name' => 'name-input',
831
- 'postal_code' => 'postal_code-input',
832
- 'region' => 'region-input',
833
- 'scheme_identifiers' => 'scheme_identifiers-input',
834
- 'verification_status' => 'verification_status-input',
835
- },
836
- }.to_json,
837
- headers: response_headers
838
- )
839
- end
840
-
841
- it 'updates and returns the resource' do
842
- expect(put_update_response).to be_a(GoCardlessPro::Resources::Creditor)
843
- expect(stub).to have_been_requested
844
- end
845
-
846
- describe 'retry behaviour' do
847
- before { allow_any_instance_of(GoCardlessPro::Request).to receive(:sleep) }
848
-
849
- it 'retries timeouts' do
850
- stub_url = '/creditors/:identity'.gsub(':identity', id)
851
- stub = stub_request(:put, /.*api.gocardless.com#{stub_url}/).
852
- to_timeout.then.to_return(status: 200, headers: response_headers)
853
-
854
- put_update_response
855
- expect(stub).to have_been_requested.twice
856
- end
857
-
858
- it 'retries 5XX errors' do
859
- stub_url = '/creditors/:identity'.gsub(':identity', id)
860
- stub = stub_request(:put, /.*api.gocardless.com#{stub_url}/).
861
- to_return(status: 502,
862
- headers: { 'Content-Type' => 'text/html' },
863
- body: '<html><body>Response from Cloudflare</body></html>').
864
- then.to_return(status: 200, headers: response_headers)
865
-
866
- put_update_response
867
- expect(stub).to have_been_requested.twice
868
- end
869
- end
870
- end
871
- end
872
-
873
- describe '#apply_scheme_identifier' do
874
- subject(:post_response) { client.creditors.apply_scheme_identifier(resource_id) }
875
-
876
- let(:resource_id) { 'ABC123' }
877
-
878
- let!(:stub) do
879
- # /creditors/%v/actions/apply_scheme_identifier
880
- stub_url = '/creditors/:identity/actions/apply_scheme_identifier'.gsub(':identity', resource_id)
881
- stub_request(:post, /.*api.gocardless.com#{stub_url}/).to_return(
882
-
883
- body: {
884
- 'creditors' => {
885
-
886
- 'activated' => 'activated-input',
887
- 'address_line1' => 'address_line1-input',
888
- 'address_line2' => 'address_line2-input',
889
- 'address_line3' => 'address_line3-input',
890
- 'can_create_refunds' => 'can_create_refunds-input',
891
- 'city' => 'city-input',
892
- 'country_code' => 'country_code-input',
893
- 'created_at' => 'created_at-input',
894
- 'creditor_type' => 'creditor_type-input',
895
- 'custom_payment_pages_enabled' => 'custom_payment_pages_enabled-input',
896
- 'fx_payout_currency' => 'fx_payout_currency-input',
897
- 'id' => 'id-input',
898
- 'links' => 'links-input',
899
- 'logo_url' => 'logo_url-input',
900
- 'mandate_imports_enabled' => 'mandate_imports_enabled-input',
901
- 'merchant_responsible_for_notifications' => 'merchant_responsible_for_notifications-input',
902
- 'name' => 'name-input',
903
- 'postal_code' => 'postal_code-input',
904
- 'region' => 'region-input',
905
- 'scheme_identifiers' => 'scheme_identifiers-input',
906
- 'verification_status' => 'verification_status-input',
907
- },
908
- }.to_json,
909
-
910
- headers: response_headers
911
- )
912
- end
913
-
914
- it 'wraps the response and calls the right endpoint' do
915
- expect(post_response).to be_a(GoCardlessPro::Resources::Creditor)
916
-
917
- expect(stub).to have_been_requested
918
- end
919
-
920
- describe 'retry behaviour' do
921
- it "doesn't retry errors" do
922
- stub_url = '/creditors/:identity/actions/apply_scheme_identifier'.gsub(':identity', resource_id)
923
- stub = stub_request(:post, /.*api.gocardless.com#{stub_url}/).
924
- to_timeout
925
-
926
- expect { post_response }.to raise_error(Faraday::ConnectionFailed)
927
- expect(stub).to have_been_requested
928
- end
929
- end
930
-
931
- context 'when the request needs a body and custom header' do
932
- let(:body) { { foo: 'bar' } }
933
- let(:headers) { { 'Foo' => 'Bar' } }
934
- subject(:post_response) { client.creditors.apply_scheme_identifier(resource_id, body, headers) }
935
-
936
- let(:resource_id) { 'ABC123' }
937
-
938
- let!(:stub) do
939
- # /creditors/%v/actions/apply_scheme_identifier
940
- stub_url = '/creditors/:identity/actions/apply_scheme_identifier'.gsub(':identity', resource_id)
941
- stub_request(:post, /.*api.gocardless.com#{stub_url}/).
942
- with(
943
- body: { foo: 'bar' },
944
- headers: { 'Foo' => 'Bar' }
945
- ).to_return(
946
- body: {
947
- 'creditors' => {
948
-
949
- 'activated' => 'activated-input',
950
- 'address_line1' => 'address_line1-input',
951
- 'address_line2' => 'address_line2-input',
952
- 'address_line3' => 'address_line3-input',
953
- 'can_create_refunds' => 'can_create_refunds-input',
954
- 'city' => 'city-input',
955
- 'country_code' => 'country_code-input',
956
- 'created_at' => 'created_at-input',
957
- 'creditor_type' => 'creditor_type-input',
958
- 'custom_payment_pages_enabled' => 'custom_payment_pages_enabled-input',
959
- 'fx_payout_currency' => 'fx_payout_currency-input',
960
- 'id' => 'id-input',
961
- 'links' => 'links-input',
962
- 'logo_url' => 'logo_url-input',
963
- 'mandate_imports_enabled' => 'mandate_imports_enabled-input',
964
- 'merchant_responsible_for_notifications' => 'merchant_responsible_for_notifications-input',
965
- 'name' => 'name-input',
966
- 'postal_code' => 'postal_code-input',
967
- 'region' => 'region-input',
968
- 'scheme_identifiers' => 'scheme_identifiers-input',
969
- 'verification_status' => 'verification_status-input',
970
- },
971
- }.to_json,
972
- headers: response_headers
973
- )
974
- end
975
- end
976
- end
977
- end