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
@@ -76,7 +76,7 @@ module GoCardlessPro
76
76
 
77
77
  # Return the links that the resource has
78
78
  def links
79
- @links_links ||= Links.new(@links)
79
+ @redirect_flow_links ||= Links.new(@links)
80
80
  end
81
81
 
82
82
  # Provides the redirect_flow resource as a hash of all its readable attributes
@@ -86,7 +86,7 @@ module GoCardlessPro
86
86
 
87
87
  class Links
88
88
  def initialize(links)
89
- @links = links
89
+ @links = links || {}
90
90
  end
91
91
 
92
92
  def creditor
@@ -47,7 +47,7 @@ module GoCardlessPro
47
47
 
48
48
  # Return the links that the resource has
49
49
  def links
50
- @links_links ||= Links.new(@links)
50
+ @refund_links ||= Links.new(@links)
51
51
  end
52
52
 
53
53
  # Provides the refund resource as a hash of all its readable attributes
@@ -57,7 +57,7 @@ module GoCardlessPro
57
57
 
58
58
  class Links
59
59
  def initialize(links)
60
- @links = links
60
+ @links = links || {}
61
61
  end
62
62
 
63
63
  def payment
@@ -128,7 +128,7 @@ module GoCardlessPro
128
128
 
129
129
  # Return the links that the resource has
130
130
  def links
131
- @links_links ||= Links.new(@links)
131
+ @subscription_links ||= Links.new(@links)
132
132
  end
133
133
 
134
134
  # Provides the subscription resource as a hash of all its readable attributes
@@ -138,7 +138,7 @@ module GoCardlessPro
138
138
 
139
139
  class Links
140
140
  def initialize(links)
141
- @links = links
141
+ @links = links || {}
142
142
  end
143
143
 
144
144
  def mandate
@@ -12,27 +12,13 @@ module GoCardlessPro
12
12
  @response = response
13
13
  end
14
14
 
15
- # Return the body of the API response
15
+ # Return the body of parsed JSON body of the API response
16
16
  def body
17
- json? ? handle_json : handle_raw
18
- end
19
-
20
- # Returns true if the response is JSON
21
- def json?
22
- content_type = @response.headers['Content-Type'] ||
23
- @response.headers['content-type'] || ''
24
- content_type.include?('application/json')
25
- end
26
-
27
- # Returns true if the response is an error
28
- def error?
29
- @response.status >= 400
17
+ JSON.parse(@response.body) unless @response.body.empty?
30
18
  end
31
19
 
32
20
  # Returns the meta hash of the response
33
21
  def meta
34
- fail ResponseError, 'Cannot fetch meta for non JSON response' unless json?
35
-
36
22
  json_body.fetch('meta', {})
37
23
  end
38
24
 
@@ -40,43 +26,5 @@ module GoCardlessPro
40
26
  def limit
41
27
  meta.fetch('limit', nil)
42
28
  end
43
-
44
- private
45
-
46
- def json_body
47
- @json_body ||= JSON.parse(@response.body) unless @response.body.empty?
48
- end
49
-
50
- def raw_body
51
- @response.body
52
- end
53
-
54
- def handle_json
55
- if error?
56
- type = json_body['error']['type']
57
- fail(error_class_for_type(type), json_body['error'])
58
- else
59
- json_body
60
- end
61
- end
62
-
63
- def error_class_for_type(type)
64
- {
65
- validation_failed: GoCardlessPro::ValidationError,
66
- gocardless: GoCardlessPro::GoCardlessError,
67
- invalid_api_usage: GoCardlessPro::InvalidApiUsageError,
68
- invalid_state: GoCardlessPro::InvalidStateError
69
- }.fetch(type.to_sym)
70
- end
71
-
72
- def handle_raw
73
- default_raw_message = {
74
- 'message' => "Something went wrong with this raw request\n" \
75
- "status: #{@response.status}\n" \
76
- "headers: #{@response.headers}\n" \
77
- "body: #{@response.body}"
78
- }
79
- error? ? fail(ApiError, default_raw_message) : raw_body
80
- end
81
29
  end
82
30
  end
@@ -32,6 +32,9 @@ module GoCardlessPro
32
32
  params = options.delete(:params) || {}
33
33
  options[:params] = {}
34
34
  options[:params][envelope_key] = params
35
+
36
+ options[:retry_failures] = true
37
+
35
38
  response = make_request(:post, path, options)
36
39
 
37
40
  return if response.body.nil?
@@ -20,7 +20,19 @@ module GoCardlessPro
20
20
  params = options.delete(:params) || {}
21
21
  options[:params] = {}
22
22
  options[:params][envelope_key] = params
23
- response = make_request(:post, path, options)
23
+
24
+ options[:retry_failures] = true
25
+
26
+ begin
27
+ response = make_request(:post, path, options)
28
+
29
+ # Response doesn't raise any errors until #body is called
30
+ response.tap(&:body)
31
+ rescue InvalidStateError => e
32
+ return get(e.conflicting_resource_id) if e.idempotent_creation_conflict?
33
+
34
+ raise e
35
+ end
24
36
 
25
37
  return if response.body.nil?
26
38
 
@@ -34,7 +46,10 @@ module GoCardlessPro
34
46
  def list(options = {})
35
47
  path = '/creditor_bank_accounts'
36
48
 
49
+ options[:retry_failures] = true
50
+
37
51
  response = make_request(:get, path, options)
52
+
38
53
  ListResponse.new(
39
54
  response: response,
40
55
  unenveloped_body: unenvelope_body(response.body),
@@ -61,6 +76,8 @@ module GoCardlessPro
61
76
  def get(identity, options = {})
62
77
  path = sub_url('/creditor_bank_accounts/:identity', 'identity' => identity)
63
78
 
79
+ options[:retry_failures] = true
80
+
64
81
  response = make_request(:get, path, options)
65
82
 
66
83
  return if response.body.nil?
@@ -86,7 +103,19 @@ module GoCardlessPro
86
103
  params = options.delete(:params) || {}
87
104
  options[:params] = {}
88
105
  options[:params]['data'] = params
89
- response = make_request(:post, path, options)
106
+
107
+ options[:retry_failures] = false
108
+
109
+ begin
110
+ response = make_request(:post, path, options)
111
+
112
+ # Response doesn't raise any errors until #body is called
113
+ response.tap(&:body)
114
+ rescue InvalidStateError => e
115
+ return get(e.conflicting_resource_id) if e.idempotent_creation_conflict?
116
+
117
+ raise e
118
+ end
90
119
 
91
120
  return if response.body.nil?
92
121
 
@@ -20,7 +20,19 @@ module GoCardlessPro
20
20
  params = options.delete(:params) || {}
21
21
  options[:params] = {}
22
22
  options[:params][envelope_key] = params
23
- response = make_request(:post, path, options)
23
+
24
+ options[:retry_failures] = true
25
+
26
+ begin
27
+ response = make_request(:post, path, options)
28
+
29
+ # Response doesn't raise any errors until #body is called
30
+ response.tap(&:body)
31
+ rescue InvalidStateError => e
32
+ return get(e.conflicting_resource_id) if e.idempotent_creation_conflict?
33
+
34
+ raise e
35
+ end
24
36
 
25
37
  return if response.body.nil?
26
38
 
@@ -34,7 +46,10 @@ module GoCardlessPro
34
46
  def list(options = {})
35
47
  path = '/creditors'
36
48
 
49
+ options[:retry_failures] = true
50
+
37
51
  response = make_request(:get, path, options)
52
+
38
53
  ListResponse.new(
39
54
  response: response,
40
55
  unenveloped_body: unenvelope_body(response.body),
@@ -61,6 +76,8 @@ module GoCardlessPro
61
76
  def get(identity, options = {})
62
77
  path = sub_url('/creditors/:identity', 'identity' => identity)
63
78
 
79
+ options[:retry_failures] = true
80
+
64
81
  response = make_request(:get, path, options)
65
82
 
66
83
  return if response.body.nil?
@@ -80,6 +97,9 @@ module GoCardlessPro
80
97
  params = options.delete(:params) || {}
81
98
  options[:params] = {}
82
99
  options[:params][envelope_key] = params
100
+
101
+ options[:retry_failures] = true
102
+
83
103
  response = make_request(:put, path, options)
84
104
 
85
105
  return if response.body.nil?
@@ -35,7 +35,19 @@ module GoCardlessPro
35
35
  params = options.delete(:params) || {}
36
36
  options[:params] = {}
37
37
  options[:params][envelope_key] = params
38
- response = make_request(:post, path, options)
38
+
39
+ options[:retry_failures] = true
40
+
41
+ begin
42
+ response = make_request(:post, path, options)
43
+
44
+ # Response doesn't raise any errors until #body is called
45
+ response.tap(&:body)
46
+ rescue InvalidStateError => e
47
+ return get(e.conflicting_resource_id) if e.idempotent_creation_conflict?
48
+
49
+ raise e
50
+ end
39
51
 
40
52
  return if response.body.nil?
41
53
 
@@ -49,7 +61,10 @@ module GoCardlessPro
49
61
  def list(options = {})
50
62
  path = '/customer_bank_accounts'
51
63
 
64
+ options[:retry_failures] = true
65
+
52
66
  response = make_request(:get, path, options)
67
+
53
68
  ListResponse.new(
54
69
  response: response,
55
70
  unenveloped_body: unenvelope_body(response.body),
@@ -76,6 +91,8 @@ module GoCardlessPro
76
91
  def get(identity, options = {})
77
92
  path = sub_url('/customer_bank_accounts/:identity', 'identity' => identity)
78
93
 
94
+ options[:retry_failures] = true
95
+
79
96
  response = make_request(:get, path, options)
80
97
 
81
98
  return if response.body.nil?
@@ -95,6 +112,9 @@ module GoCardlessPro
95
112
  params = options.delete(:params) || {}
96
113
  options[:params] = {}
97
114
  options[:params][envelope_key] = params
115
+
116
+ options[:retry_failures] = true
117
+
98
118
  response = make_request(:put, path, options)
99
119
 
100
120
  return if response.body.nil?
@@ -120,7 +140,19 @@ module GoCardlessPro
120
140
  params = options.delete(:params) || {}
121
141
  options[:params] = {}
122
142
  options[:params]['data'] = params
123
- response = make_request(:post, path, options)
143
+
144
+ options[:retry_failures] = false
145
+
146
+ begin
147
+ response = make_request(:post, path, options)
148
+
149
+ # Response doesn't raise any errors until #body is called
150
+ response.tap(&:body)
151
+ rescue InvalidStateError => e
152
+ return get(e.conflicting_resource_id) if e.idempotent_creation_conflict?
153
+
154
+ raise e
155
+ end
124
156
 
125
157
  return if response.body.nil?
126
158
 
@@ -20,7 +20,19 @@ module GoCardlessPro
20
20
  params = options.delete(:params) || {}
21
21
  options[:params] = {}
22
22
  options[:params][envelope_key] = params
23
- response = make_request(:post, path, options)
23
+
24
+ options[:retry_failures] = true
25
+
26
+ begin
27
+ response = make_request(:post, path, options)
28
+
29
+ # Response doesn't raise any errors until #body is called
30
+ response.tap(&:body)
31
+ rescue InvalidStateError => e
32
+ return get(e.conflicting_resource_id) if e.idempotent_creation_conflict?
33
+
34
+ raise e
35
+ end
24
36
 
25
37
  return if response.body.nil?
26
38
 
@@ -34,7 +46,10 @@ module GoCardlessPro
34
46
  def list(options = {})
35
47
  path = '/customers'
36
48
 
49
+ options[:retry_failures] = true
50
+
37
51
  response = make_request(:get, path, options)
52
+
38
53
  ListResponse.new(
39
54
  response: response,
40
55
  unenveloped_body: unenvelope_body(response.body),
@@ -61,6 +76,8 @@ module GoCardlessPro
61
76
  def get(identity, options = {})
62
77
  path = sub_url('/customers/:identity', 'identity' => identity)
63
78
 
79
+ options[:retry_failures] = true
80
+
64
81
  response = make_request(:get, path, options)
65
82
 
66
83
  return if response.body.nil?
@@ -80,6 +97,9 @@ module GoCardlessPro
80
97
  params = options.delete(:params) || {}
81
98
  options[:params] = {}
82
99
  options[:params][envelope_key] = params
100
+
101
+ options[:retry_failures] = true
102
+
83
103
  response = make_request(:put, path, options)
84
104
 
85
105
  return if response.body.nil?
@@ -18,7 +18,10 @@ module GoCardlessPro
18
18
  def list(options = {})
19
19
  path = '/events'
20
20
 
21
+ options[:retry_failures] = true
22
+
21
23
  response = make_request(:get, path, options)
24
+
22
25
  ListResponse.new(
23
26
  response: response,
24
27
  unenveloped_body: unenvelope_body(response.body),
@@ -45,6 +48,8 @@ module GoCardlessPro
45
48
  def get(identity, options = {})
46
49
  path = sub_url('/events/:identity', 'identity' => identity)
47
50
 
51
+ options[:retry_failures] = true
52
+
48
53
  response = make_request(:get, path, options)
49
54
 
50
55
  return if response.body.nil?
@@ -31,6 +31,9 @@ module GoCardlessPro
31
31
  params = options.delete(:params) || {}
32
32
  options[:params] = {}
33
33
  options[:params][envelope_key] = params
34
+
35
+ options[:retry_failures] = true
36
+
34
37
  response = make_request(:post, path, options)
35
38
 
36
39
  return if response.body.nil?
@@ -20,7 +20,19 @@ module GoCardlessPro
20
20
  params = options.delete(:params) || {}
21
21
  options[:params] = {}
22
22
  options[:params][envelope_key] = params
23
- response = make_request(:post, path, options)
23
+
24
+ options[:retry_failures] = true
25
+
26
+ begin
27
+ response = make_request(:post, path, options)
28
+
29
+ # Response doesn't raise any errors until #body is called
30
+ response.tap(&:body)
31
+ rescue InvalidStateError => e
32
+ return get(e.conflicting_resource_id) if e.idempotent_creation_conflict?
33
+
34
+ raise e
35
+ end
24
36
 
25
37
  return if response.body.nil?
26
38
 
@@ -34,7 +46,10 @@ module GoCardlessPro
34
46
  def list(options = {})
35
47
  path = '/mandates'
36
48
 
49
+ options[:retry_failures] = true
50
+
37
51
  response = make_request(:get, path, options)
52
+
38
53
  ListResponse.new(
39
54
  response: response,
40
55
  unenveloped_body: unenvelope_body(response.body),
@@ -61,6 +76,8 @@ module GoCardlessPro
61
76
  def get(identity, options = {})
62
77
  path = sub_url('/mandates/:identity', 'identity' => identity)
63
78
 
79
+ options[:retry_failures] = true
80
+
64
81
  response = make_request(:get, path, options)
65
82
 
66
83
  return if response.body.nil?
@@ -79,6 +96,9 @@ module GoCardlessPro
79
96
  params = options.delete(:params) || {}
80
97
  options[:params] = {}
81
98
  options[:params][envelope_key] = params
99
+
100
+ options[:retry_failures] = true
101
+
82
102
  response = make_request(:put, path, options)
83
103
 
84
104
  return if response.body.nil?
@@ -102,7 +122,19 @@ module GoCardlessPro
102
122
  params = options.delete(:params) || {}
103
123
  options[:params] = {}
104
124
  options[:params]['data'] = params
105
- response = make_request(:post, path, options)
125
+
126
+ options[:retry_failures] = false
127
+
128
+ begin
129
+ response = make_request(:post, path, options)
130
+
131
+ # Response doesn't raise any errors until #body is called
132
+ response.tap(&:body)
133
+ rescue InvalidStateError => e
134
+ return get(e.conflicting_resource_id) if e.idempotent_creation_conflict?
135
+
136
+ raise e
137
+ end
106
138
 
107
139
  return if response.body.nil?
108
140
 
@@ -131,7 +163,19 @@ module GoCardlessPro
131
163
  params = options.delete(:params) || {}
132
164
  options[:params] = {}
133
165
  options[:params]['data'] = params
134
- response = make_request(:post, path, options)
166
+
167
+ options[:retry_failures] = false
168
+
169
+ begin
170
+ response = make_request(:post, path, options)
171
+
172
+ # Response doesn't raise any errors until #body is called
173
+ response.tap(&:body)
174
+ rescue InvalidStateError => e
175
+ return get(e.conflicting_resource_id) if e.idempotent_creation_conflict?
176
+
177
+ raise e
178
+ end
135
179
 
136
180
  return if response.body.nil?
137
181