mangopay4-ruby-sdk 3.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/workflows/ruby_cd.yml +34 -0
- data/.github/workflows/ruby_ci.yml +30 -0
- data/.gitignore +30 -0
- data/.rspec +3 -0
- data/CHANGELOG.md +640 -0
- data/Gemfile +2 -0
- data/LICENSE +20 -0
- data/README.md +162 -0
- data/Rakefile +5 -0
- data/bin/mangopay +9 -0
- data/lib/generators/mangopay/install_generator.rb +60 -0
- data/lib/generators/templates/mangopay.rb.erb +5 -0
- data/lib/mangopay/acquiring.rb +56 -0
- data/lib/mangopay/authorization_token.rb +89 -0
- data/lib/mangopay/bank_account.rb +49 -0
- data/lib/mangopay/bankingaliases.rb +29 -0
- data/lib/mangopay/bankingaliases_iban.rb +16 -0
- data/lib/mangopay/card.rb +54 -0
- data/lib/mangopay/card_registration.rb +9 -0
- data/lib/mangopay/client.rb +94 -0
- data/lib/mangopay/conversion.rb +49 -0
- data/lib/mangopay/deposit.rb +36 -0
- data/lib/mangopay/dispute.rb +152 -0
- data/lib/mangopay/errors.rb +66 -0
- data/lib/mangopay/event.rb +18 -0
- data/lib/mangopay/filter_parameters.rb +56 -0
- data/lib/mangopay/hook.rb +9 -0
- data/lib/mangopay/http_calls.rb +88 -0
- data/lib/mangopay/identity_verification.rb +16 -0
- data/lib/mangopay/json.rb +14 -0
- data/lib/mangopay/kyc_document.rb +83 -0
- data/lib/mangopay/legal_user.rb +21 -0
- data/lib/mangopay/legal_user_sca.rb +25 -0
- data/lib/mangopay/mandate.rb +42 -0
- data/lib/mangopay/natural_user.rb +20 -0
- data/lib/mangopay/natural_user_sca.rb +25 -0
- data/lib/mangopay/pay_in.rb +415 -0
- data/lib/mangopay/pay_out.rb +41 -0
- data/lib/mangopay/payment_method_metadata.rb +13 -0
- data/lib/mangopay/pre_authorization.rb +17 -0
- data/lib/mangopay/recipient.rb +35 -0
- data/lib/mangopay/refund.rb +19 -0
- data/lib/mangopay/regulatory.rb +22 -0
- data/lib/mangopay/report.rb +24 -0
- data/lib/mangopay/report_v2.rb +21 -0
- data/lib/mangopay/resource.rb +21 -0
- data/lib/mangopay/settlement.rb +21 -0
- data/lib/mangopay/transaction.rb +24 -0
- data/lib/mangopay/transfer.rb +20 -0
- data/lib/mangopay/ubo.rb +26 -0
- data/lib/mangopay/ubo_declaration.rb +32 -0
- data/lib/mangopay/user.rb +100 -0
- data/lib/mangopay/version.rb +3 -0
- data/lib/mangopay/virtual_account.rb +44 -0
- data/lib/mangopay/wallet.rb +17 -0
- data/lib/mangopay.rb +456 -0
- data/mangopay.gemspec +30 -0
- data/spec/mangopay/acquiring_spec.rb +176 -0
- data/spec/mangopay/authorization_token_spec.rb +70 -0
- data/spec/mangopay/bank_account_spec.rb +105 -0
- data/spec/mangopay/bankingaliases_spec.rb +29 -0
- data/spec/mangopay/card_registration_spec.rb +123 -0
- data/spec/mangopay/client_spec.png +0 -0
- data/spec/mangopay/client_spec.rb +213 -0
- data/spec/mangopay/configuration_spec.rb +249 -0
- data/spec/mangopay/conversion_spec.rb +96 -0
- data/spec/mangopay/deposit_spec.rb +107 -0
- data/spec/mangopay/dispute_spec.png +0 -0
- data/spec/mangopay/dispute_spec.rb +294 -0
- data/spec/mangopay/event_spec.rb +33 -0
- data/spec/mangopay/fetch_filters_spec.rb +63 -0
- data/spec/mangopay/hook_spec.rb +37 -0
- data/spec/mangopay/idempotency_spec.rb +41 -0
- data/spec/mangopay/identity_verification_spec.rb +47 -0
- data/spec/mangopay/kyc_document_spec.png +0 -0
- data/spec/mangopay/kyc_document_spec.rb +118 -0
- data/spec/mangopay/log_requests_filter_spec.rb +26 -0
- data/spec/mangopay/mandate_spec.rb +99 -0
- data/spec/mangopay/payin_applepay_direct_spec.rb +21 -0
- data/spec/mangopay/payin_bancontact_web_spec.rb +30 -0
- data/spec/mangopay/payin_bankwire_direct_spec.rb +74 -0
- data/spec/mangopay/payin_bankwire_external_instruction_spec.rb +104 -0
- data/spec/mangopay/payin_bizum_web_spec.rb +54 -0
- data/spec/mangopay/payin_blik_web_spec.rb +41 -0
- data/spec/mangopay/payin_card_direct_spec.rb +69 -0
- data/spec/mangopay/payin_card_web_spec.rb +64 -0
- data/spec/mangopay/payin_directdebit_direct_spec.rb +37 -0
- data/spec/mangopay/payin_directdebit_web_spec.rb +38 -0
- data/spec/mangopay/payin_giropay_web_spec.rb +30 -0
- data/spec/mangopay/payin_googlepay_direct_spec.rb +21 -0
- data/spec/mangopay/payin_ideal_web_spec.rb +30 -0
- data/spec/mangopay/payin_intent_spec.rb +151 -0
- data/spec/mangopay/payin_klarna_web_spec.rb +32 -0
- data/spec/mangopay/payin_mbway_web_spec.rb +32 -0
- data/spec/mangopay/payin_multibanco_web_spec.rb +31 -0
- data/spec/mangopay/payin_paybybank_web_spec.rb +56 -0
- data/spec/mangopay/payin_payconiq_web_spec.rb +31 -0
- data/spec/mangopay/payin_paypal_web_spec.rb +113 -0
- data/spec/mangopay/payin_preauthorized_direct_spec.rb +118 -0
- data/spec/mangopay/payin_satispay_web_spec.rb +32 -0
- data/spec/mangopay/payin_swish_web_spec.rb +30 -0
- data/spec/mangopay/payin_twint_web_spec.rb +30 -0
- data/spec/mangopay/payment_method_metadata_spec.rb +15 -0
- data/spec/mangopay/payout_bankwire_spec.rb +93 -0
- data/spec/mangopay/preauthorization_spec.rb +51 -0
- data/spec/mangopay/recipient_spec.rb +134 -0
- data/spec/mangopay/recurring_payin_spec.rb +222 -0
- data/spec/mangopay/refund_spec.rb +34 -0
- data/spec/mangopay/regulatory_spec.rb +26 -0
- data/spec/mangopay/report_spec.rb +40 -0
- data/spec/mangopay/report_v2_spec.rb +117 -0
- data/spec/mangopay/report_wallets_spec.rb +40 -0
- data/spec/mangopay/settlement_sample.csv +8 -0
- data/spec/mangopay/settlement_spec.rb +38 -0
- data/spec/mangopay/shared_resources.rb +1380 -0
- data/spec/mangopay/transaction_spec.rb +59 -0
- data/spec/mangopay/transfer_spec.rb +77 -0
- data/spec/mangopay/ubo_declaration_spec.rb +44 -0
- data/spec/mangopay/ubo_spec.rb +39 -0
- data/spec/mangopay/user_spec.rb +444 -0
- data/spec/mangopay/virtual_account_spec.rb +52 -0
- data/spec/mangopay/wallet_spec.rb +100 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/tmp/.keep +0 -0
- metadata +280 -0
data/lib/mangopay.rb
ADDED
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
require 'net/http'
|
|
2
|
+
require 'cgi/util'
|
|
3
|
+
require 'digest/md5'
|
|
4
|
+
require 'multi_json'
|
|
5
|
+
require 'benchmark'
|
|
6
|
+
require 'logger'
|
|
7
|
+
require 'time'
|
|
8
|
+
require 'securerandom'
|
|
9
|
+
|
|
10
|
+
# helpers
|
|
11
|
+
require 'mangopay/version'
|
|
12
|
+
require 'mangopay/errors'
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
module MangoPay
|
|
16
|
+
|
|
17
|
+
autoload :HTTPCalls, 'mangopay/http_calls'
|
|
18
|
+
autoload :Resource, 'mangopay/resource'
|
|
19
|
+
autoload :Client, 'mangopay/client'
|
|
20
|
+
autoload :User, 'mangopay/user'
|
|
21
|
+
autoload :NaturalUser, 'mangopay/natural_user'
|
|
22
|
+
autoload :NaturalUserSca, 'mangopay/natural_user_sca'
|
|
23
|
+
autoload :LegalUserSca, 'mangopay/legal_user_sca'
|
|
24
|
+
autoload :LegalUser, 'mangopay/legal_user'
|
|
25
|
+
autoload :PayIn, 'mangopay/pay_in'
|
|
26
|
+
autoload :PayOut, 'mangopay/pay_out'
|
|
27
|
+
autoload :Transfer, 'mangopay/transfer'
|
|
28
|
+
autoload :Transaction, 'mangopay/transaction'
|
|
29
|
+
autoload :Wallet, 'mangopay/wallet'
|
|
30
|
+
autoload :BankAccount, 'mangopay/bank_account'
|
|
31
|
+
autoload :CardRegistration, 'mangopay/card_registration'
|
|
32
|
+
autoload :PreAuthorization, 'mangopay/pre_authorization'
|
|
33
|
+
autoload :Card, 'mangopay/card'
|
|
34
|
+
autoload :Event, 'mangopay/event'
|
|
35
|
+
autoload :KycDocument, 'mangopay/kyc_document'
|
|
36
|
+
autoload :Hook, 'mangopay/hook'
|
|
37
|
+
autoload :Refund, 'mangopay/refund'
|
|
38
|
+
autoload :Dispute, 'mangopay/dispute'
|
|
39
|
+
autoload :Mandate, 'mangopay/mandate'
|
|
40
|
+
autoload :Report, 'mangopay/report'
|
|
41
|
+
autoload :ReportV2, 'mangopay/report_v2'
|
|
42
|
+
autoload :JSON, 'mangopay/json'
|
|
43
|
+
autoload :AuthorizationToken, 'mangopay/authorization_token'
|
|
44
|
+
autoload :FilterParameters, 'mangopay/filter_parameters'
|
|
45
|
+
autoload :BankingAliases, 'mangopay/bankingaliases'
|
|
46
|
+
autoload :BankingAliasesIBAN, 'mangopay/bankingaliases_iban'
|
|
47
|
+
autoload :UboDeclaration, 'mangopay/ubo_declaration'
|
|
48
|
+
autoload :Ubo, 'mangopay/ubo'
|
|
49
|
+
autoload :Regulatory, 'mangopay/regulatory'
|
|
50
|
+
autoload :Deposit, 'mangopay/deposit'
|
|
51
|
+
autoload :Conversion, 'mangopay/conversion'
|
|
52
|
+
autoload :PaymentMethodMetadata, 'mangopay/payment_method_metadata'
|
|
53
|
+
autoload :VirtualAccount, 'mangopay/virtual_account'
|
|
54
|
+
autoload :IdentityVerification, 'mangopay/identity_verification'
|
|
55
|
+
autoload :Recipient, 'mangopay/recipient'
|
|
56
|
+
autoload :Settlement, 'mangopay/settlement'
|
|
57
|
+
autoload :Acquiring, 'mangopay/acquiring'
|
|
58
|
+
|
|
59
|
+
# temporary
|
|
60
|
+
autoload :Temp, 'mangopay/temp'
|
|
61
|
+
|
|
62
|
+
@configurations = {}
|
|
63
|
+
|
|
64
|
+
class Configuration
|
|
65
|
+
attr_accessor :preproduction, :root_url,
|
|
66
|
+
:client_id, :client_apiKey,
|
|
67
|
+
:temp_dir, :log_file, :log_trace_headers, :http_timeout,
|
|
68
|
+
:http_max_retries, :http_open_timeout,
|
|
69
|
+
:logger, :use_ssl, :uk_header_flag,
|
|
70
|
+
:after_request_proc
|
|
71
|
+
|
|
72
|
+
def apply_configuration
|
|
73
|
+
MangoPay.configure do |config|
|
|
74
|
+
config.preproduction = @preproduction
|
|
75
|
+
config.client_id = @client_id
|
|
76
|
+
config.client_apiKey = @client_apiKey
|
|
77
|
+
config.log_file = @log_file
|
|
78
|
+
config.log_trace_headers = @log_trace_headers
|
|
79
|
+
config.http_timeout = @http_timeout
|
|
80
|
+
config.http_max_retries = @http_max_retries
|
|
81
|
+
config.http_open_timeout = @http_open_timeout
|
|
82
|
+
config.use_ssl = @use_ssl
|
|
83
|
+
config.logger = @logger
|
|
84
|
+
config.uk_header_flag = @uk_header_flag
|
|
85
|
+
config.after_request_proc = @after_request_proc
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def preproduction
|
|
90
|
+
@preproduction || false
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def root_url
|
|
94
|
+
@root_url || (@preproduction == true ? "https://api.sandbox.mangopay.com" : "https://api.mangopay.com")
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def http_timeout
|
|
98
|
+
@http_timeout || 30
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def http_max_retries
|
|
102
|
+
@http_max_retries || 1
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def http_open_timeout
|
|
106
|
+
@http_open_timeout || 30
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def use_ssl?
|
|
110
|
+
return true unless preproduction == true
|
|
111
|
+
return true unless defined?(@use_ssl)
|
|
112
|
+
return false if @use_ssl == false
|
|
113
|
+
|
|
114
|
+
true
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def log_trace_headers
|
|
118
|
+
@log_trace_headers || false
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def uk_header_flag
|
|
122
|
+
@uk_header_flag || false
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
class << self
|
|
127
|
+
def version_code
|
|
128
|
+
"v2.01"
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def version_code_v3
|
|
132
|
+
"V3.0"
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def api_path
|
|
136
|
+
"/#{version_code}/#{MangoPay.configuration.client_id}"
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def api_path_no_client
|
|
140
|
+
"/#{version_code}"
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def api_path_v3
|
|
144
|
+
"/#{version_code_v3}/#{MangoPay.configuration.client_id}"
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def api_uri(url='')
|
|
148
|
+
URI(configuration.root_url + url)
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def configuration=(value)
|
|
152
|
+
Thread.current[:mangopay_configuration] = value
|
|
153
|
+
@last_configuration_set = value
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def configuration
|
|
157
|
+
config = Thread.current[:mangopay_configuration]
|
|
158
|
+
|
|
159
|
+
config ||
|
|
160
|
+
( @last_configuration_set &&
|
|
161
|
+
(self.configuration = @last_configuration_set.dup)) ||
|
|
162
|
+
(self.configuration = MangoPay::Configuration.new)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def configure
|
|
166
|
+
config = self.configuration
|
|
167
|
+
yield config
|
|
168
|
+
self.configuration = config
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def with_configuration(config)
|
|
172
|
+
original_config = MangoPay.configuration
|
|
173
|
+
MangoPay.configuration = config
|
|
174
|
+
yield
|
|
175
|
+
ensure
|
|
176
|
+
MangoPay.configuration = original_config
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def ratelimit
|
|
180
|
+
@ratelimit
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def ratelimit=(obj)
|
|
184
|
+
@ratelimit = obj
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
# Add MangoPay.Configuration to the list of configs
|
|
188
|
+
def add_config(name, config)
|
|
189
|
+
@configurations[name] = config
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
# Fetch a MangoPay configuration from the list of configs. Throw error if not found
|
|
193
|
+
def get_config(name)
|
|
194
|
+
config = @configurations[name]
|
|
195
|
+
raise "Could not find any configuration with name '#{name}'" unless config
|
|
196
|
+
config
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def remove_config(name)
|
|
200
|
+
raise "Could not find any configuration with name '#{name}'" unless @configurations[name]
|
|
201
|
+
@configurations[name] = nil
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
#
|
|
205
|
+
# - +method+: HTTP method; lowercase symbol, e.g. :get, :post etc.
|
|
206
|
+
# - +url+: the part after Configuration#root_url
|
|
207
|
+
# - +params+: hash; entity data for creation, update etc.; will dump it by JSON and assign to Net::HTTPRequest#body
|
|
208
|
+
# - +filters+: hash; pagination params etc.; will encode it by URI and assign to URI#query
|
|
209
|
+
# - +headers_or_idempotency_key+: hash of headers; or replaced by request_headers if nil; or added to request_headers as idempotency key otherwise (see https://docs.mangopay.com/api-references/idempotency-support/)
|
|
210
|
+
# - +before_request_proc+: optional proc; will call it passing the Net::HTTPRequest instance just before Net::HTTPRequest#request
|
|
211
|
+
#
|
|
212
|
+
# Raises MangoPay::ResponseError if response code != 200.
|
|
213
|
+
#
|
|
214
|
+
def request(method, url, params={}, filters={}, headers_or_idempotency_key = nil, before_request_proc = nil)
|
|
215
|
+
uri = api_uri(url)
|
|
216
|
+
uri.query = URI.encode_www_form(filters) unless filters.empty?
|
|
217
|
+
|
|
218
|
+
if headers_or_idempotency_key.is_a?(Hash)
|
|
219
|
+
headers = headers_or_idempotency_key
|
|
220
|
+
else
|
|
221
|
+
headers = request_headers
|
|
222
|
+
headers['Idempotency-Key'] = headers_or_idempotency_key if headers_or_idempotency_key != nil
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
if configuration.uk_header_flag
|
|
226
|
+
headers['x-tenant-id'] = 'uk'
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
res = Net::HTTP.start(uri.host, uri.port, :use_ssl => configuration.use_ssl?, :read_timeout => configuration.http_timeout,
|
|
230
|
+
:max_retries => configuration.http_max_retries,
|
|
231
|
+
:open_timeout => configuration.http_open_timeout, ssl_version: :TLSv1_2) do |http|
|
|
232
|
+
req = Net::HTTP::const_get(method.capitalize).new(uri.request_uri, headers)
|
|
233
|
+
req.body = JSON.dump(params)
|
|
234
|
+
before_request_proc.call(req) if before_request_proc
|
|
235
|
+
do_request(http, req, uri)
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
raise MangoPay::ResponseError.new(uri, '408', {'Message' => 'Request Timeout'}) if res.nil?
|
|
239
|
+
|
|
240
|
+
# decode json data
|
|
241
|
+
begin
|
|
242
|
+
data = res.body.to_s.empty? ? {} : JSON.load(res.body.to_s)
|
|
243
|
+
rescue MultiJson::ParseError
|
|
244
|
+
details = {}
|
|
245
|
+
details['Message'] = res.body
|
|
246
|
+
raise MangoPay::ResponseError.new(uri, res.code, details)
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
unless res.is_a?(Net::HTTPOK) or res.is_a?(Net::HTTPCreated) or res.is_a?(Net::HTTPNoContent)
|
|
250
|
+
if res.is_a?(Net::HTTPUnauthorized) and res['www-authenticate'] != nil
|
|
251
|
+
redirect_url = res['www-authenticate'][/RedirectUrl=(.+)/, 1]
|
|
252
|
+
data['RedirectUrl'] = redirect_url
|
|
253
|
+
data['message'] = 'SCA required to perform this action.'
|
|
254
|
+
raise MangoPay::ResponseError.new(uri, res.code, data)
|
|
255
|
+
end
|
|
256
|
+
raise MangoPay::ResponseError.new(uri, res.code, data)
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
# copy pagination info if any
|
|
260
|
+
['x-number-of-pages', 'x-number-of-items'].each { |k|
|
|
261
|
+
filters[k.gsub('x-number-of-', 'total_')] = res[k].to_i if res[k]
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if res['x-ratelimit']
|
|
265
|
+
self.ratelimit = {
|
|
266
|
+
limit: res['x-ratelimit'].split(", "),
|
|
267
|
+
remaining: res['x-ratelimit-remaining'].split(", "),
|
|
268
|
+
reset: res['x-ratelimit-reset'].split(", ")
|
|
269
|
+
}
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
configuration.after_request_proc&.call(data)
|
|
273
|
+
|
|
274
|
+
data
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def request_multipart(method, url, file, file_name, idempotency_key = nil)
|
|
278
|
+
uri = api_uri(url)
|
|
279
|
+
|
|
280
|
+
# Set headers
|
|
281
|
+
headers = request_headers
|
|
282
|
+
headers['Idempotency-Key'] = idempotency_key if idempotency_key
|
|
283
|
+
headers['x-tenant-id'] = 'uk' if configuration.uk_header_flag
|
|
284
|
+
|
|
285
|
+
boundary = "#{SecureRandom.hex}"
|
|
286
|
+
headers['Content-Type'] = "multipart/form-data; boundary=#{boundary}"
|
|
287
|
+
|
|
288
|
+
multipart_body = []
|
|
289
|
+
multipart_body << "--#{boundary}"
|
|
290
|
+
multipart_body << "Content-Disposition: form-data; name=\"file\"; filename=\"#{file_name}\""
|
|
291
|
+
multipart_body << ""
|
|
292
|
+
multipart_body << file
|
|
293
|
+
multipart_body << "--#{boundary}--"
|
|
294
|
+
multipart_body << ""
|
|
295
|
+
|
|
296
|
+
# Join string parts and ensure binary content is preserved
|
|
297
|
+
body = multipart_body.map { |part| part.is_a?(String) ? part.force_encoding("ASCII-8BIT") : part }.join("\r\n")
|
|
298
|
+
|
|
299
|
+
res = Net::HTTP.start(uri.host, uri.port,
|
|
300
|
+
use_ssl: configuration.use_ssl?,
|
|
301
|
+
read_timeout: configuration.http_timeout,
|
|
302
|
+
open_timeout: configuration.http_open_timeout,
|
|
303
|
+
max_retries: configuration.http_max_retries,
|
|
304
|
+
ssl_version: :TLSv1_2) do |http|
|
|
305
|
+
req_class = Net::HTTP.const_get(method.capitalize)
|
|
306
|
+
req = req_class.new(uri.request_uri, headers)
|
|
307
|
+
req.body = body
|
|
308
|
+
do_request(http, req, uri)
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
raise MangoPay::ResponseError.new(uri, '408', { 'Message' => 'Request Timeout' }) if res.nil?
|
|
312
|
+
|
|
313
|
+
begin
|
|
314
|
+
data = res.body.to_s.empty? ? {} : JSON.load(res.body.to_s)
|
|
315
|
+
rescue MultiJson::ParseError
|
|
316
|
+
raise MangoPay::ResponseError.new(uri, res.code, { 'Message' => res.body })
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
unless res.is_a?(Net::HTTPOK) || res.is_a?(Net::HTTPCreated) || res.is_a?(Net::HTTPNoContent)
|
|
320
|
+
if res.is_a?(Net::HTTPUnauthorized) && res['www-authenticate']
|
|
321
|
+
redirect_url = res['www-authenticate'][/RedirectUrl=(.+)/, 1]
|
|
322
|
+
data['RedirectUrl'] = redirect_url
|
|
323
|
+
data['message'] = 'SCA required to perform this action.'
|
|
324
|
+
end
|
|
325
|
+
raise MangoPay::ResponseError.new(uri, res.code, data)
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
if res['x-ratelimit']
|
|
329
|
+
self.ratelimit = {
|
|
330
|
+
limit: res['x-ratelimit'].split(", "),
|
|
331
|
+
remaining: res['x-ratelimit-remaining'].split(", "),
|
|
332
|
+
reset: res['x-ratelimit-reset'].split(", ")
|
|
333
|
+
}
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
configuration.after_request_proc&.call(data)
|
|
337
|
+
|
|
338
|
+
data
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
# Retrieve a previous response by idempotency_key
|
|
342
|
+
# See https://docs.mangopay.com/api-references/idempotency-support/
|
|
343
|
+
def fetch_response(idempotency_key)
|
|
344
|
+
url = "#{api_path}/responses/#{idempotency_key}"
|
|
345
|
+
request(:get, url)
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
private
|
|
349
|
+
|
|
350
|
+
def user_agent
|
|
351
|
+
{
|
|
352
|
+
bindings_version: VERSION,
|
|
353
|
+
lang: 'ruby',
|
|
354
|
+
lang_version: "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})",
|
|
355
|
+
platform: RUBY_PLATFORM,
|
|
356
|
+
uname: get_uname
|
|
357
|
+
}
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
def get_uname
|
|
361
|
+
`uname -a 2>/dev/null`.strip if RUBY_PLATFORM =~ /linux|darwin/i
|
|
362
|
+
rescue Errno::ENOMEM
|
|
363
|
+
'uname lookup failed'
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def request_headers
|
|
367
|
+
auth_token = AuthorizationToken::Manager.get_token
|
|
368
|
+
headers = {
|
|
369
|
+
'User-Agent' => "Mangopay-SDK/#{VERSION} (Ruby/#{RUBY_VERSION})",
|
|
370
|
+
'Authorization' => "#{auth_token['token_type']} #{auth_token['access_token']}",
|
|
371
|
+
'Content-Type' => 'application/json'
|
|
372
|
+
}
|
|
373
|
+
if configuration.log_trace_headers
|
|
374
|
+
headers.update('x_mangopay_trace-id' => SecureRandom.uuid)
|
|
375
|
+
end
|
|
376
|
+
begin
|
|
377
|
+
headers.update('x_mangopay_client_user_agent' => JSON.dump(user_agent))
|
|
378
|
+
rescue => e
|
|
379
|
+
headers.update('x_mangopay_client_raw_user_agent' => user_agent.inspect, error: "#{e} (#{e.class})")
|
|
380
|
+
end
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
def do_request(http, req, uri)
|
|
384
|
+
if logs_required?
|
|
385
|
+
do_request_with_log(http, req, uri)
|
|
386
|
+
else
|
|
387
|
+
do_request_without_log(http, req)
|
|
388
|
+
end
|
|
389
|
+
end
|
|
390
|
+
|
|
391
|
+
def do_request_with_log(http, req, uri)
|
|
392
|
+
res, time = nil, nil
|
|
393
|
+
params = FilterParameters.request(req.body)
|
|
394
|
+
if configuration.log_trace_headers
|
|
395
|
+
trace_headers = JSON.dump({ 'Idempotency-Key' => req['Idempotency-Key'] , 'x_mangopay_trace-id' => req['x_mangopay_trace-id'] })
|
|
396
|
+
line = "[#{Time.now.iso8601}] #{req.method.upcase} \"#{uri.to_s}\" #{params} #{trace_headers}"
|
|
397
|
+
else
|
|
398
|
+
line = "[#{Time.now.iso8601}] #{req.method.upcase} \"#{uri.to_s}\" #{params}"
|
|
399
|
+
end
|
|
400
|
+
begin
|
|
401
|
+
time = Benchmark.realtime {
|
|
402
|
+
begin
|
|
403
|
+
res = do_request_without_log(http, req)
|
|
404
|
+
rescue Net::ReadTimeout
|
|
405
|
+
res = nil
|
|
406
|
+
end
|
|
407
|
+
}
|
|
408
|
+
res
|
|
409
|
+
ensure
|
|
410
|
+
line = "#{log_severity(res)} #{line}"
|
|
411
|
+
if time.nil?
|
|
412
|
+
time_log = "[Unknown ms]"
|
|
413
|
+
else
|
|
414
|
+
time_log = "[#{(time * 1000).round(1)}ms]"
|
|
415
|
+
end
|
|
416
|
+
if res.nil?
|
|
417
|
+
params = ''
|
|
418
|
+
line += "\n #{time_log} 408 Request Timeout #{params}\n"
|
|
419
|
+
else
|
|
420
|
+
params = FilterParameters.response(res.body)
|
|
421
|
+
line += "\n #{time_log} #{res.code} #{params}\n"
|
|
422
|
+
end
|
|
423
|
+
logger.info { line }
|
|
424
|
+
end
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
def do_request_without_log(http, req)
|
|
428
|
+
http.request(req)
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
def log_severity(res)
|
|
432
|
+
errors = [Net::HTTPClientError, Net::HTTPServerError, Net::HTTPUnknownResponse]
|
|
433
|
+
errors.any? { |klass| res.is_a?(klass) } ? 'E' : 'I'
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
def logger
|
|
437
|
+
raise NotImplementedError unless logs_required?
|
|
438
|
+
return @logger if @logger
|
|
439
|
+
|
|
440
|
+
if !configuration.logger.nil?
|
|
441
|
+
@logger = configuration.logger
|
|
442
|
+
elsif !configuration.log_file.nil?
|
|
443
|
+
@logger = Logger.new(configuration.log_file)
|
|
444
|
+
@logger.formatter = proc do |_, _, _, msg|
|
|
445
|
+
"#{msg}\n"
|
|
446
|
+
end
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
@logger
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
def logs_required?
|
|
453
|
+
!configuration.log_file.nil? || !configuration.logger.nil?
|
|
454
|
+
end
|
|
455
|
+
end
|
|
456
|
+
end
|
data/mangopay.gemspec
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), 'lib'))
|
|
2
|
+
|
|
3
|
+
require 'mangopay/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = 'mangopay4-ruby-sdk'
|
|
7
|
+
s.version = MangoPay::VERSION
|
|
8
|
+
s.summary = "Ruby bindings for the version 2 of the MANGOPAY API"
|
|
9
|
+
s.description = <<-EOF
|
|
10
|
+
The mangopay Gem makes interacting with MANGOPAY Services much easier.
|
|
11
|
+
For any questions regarding the use of MANGOPAY's Services feel free to contact us at http://www.mangopay.com/get-started-2/
|
|
12
|
+
You can find more documentation about MANGOPAY Services at http://docs.mangopay.com/
|
|
13
|
+
EOF
|
|
14
|
+
s.authors = ['Geoffroy Lorieux', 'Sergiusz Woznicki']
|
|
15
|
+
s.email = 'support@mangopay.com'
|
|
16
|
+
s.homepage = 'http://docs.mangopay.com/'
|
|
17
|
+
s.license = 'MIT'
|
|
18
|
+
|
|
19
|
+
s.required_ruby_version = '>= 1.9.2'
|
|
20
|
+
|
|
21
|
+
s.add_dependency('multi_json', '>= 1.15.0')
|
|
22
|
+
|
|
23
|
+
s.add_development_dependency('rake', '>= 13.2.1')
|
|
24
|
+
s.add_development_dependency('rspec', '>= 3.13.0')
|
|
25
|
+
|
|
26
|
+
s.files = `git ls-files`.split("\n")
|
|
27
|
+
s.test_files = `git ls-files -- spec/*`.split("\n")
|
|
28
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
29
|
+
s.require_paths = ['lib']
|
|
30
|
+
end
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
xdescribe MangoPay::Hook do
|
|
2
|
+
include_context 'wallets'
|
|
3
|
+
include_context 'payins'
|
|
4
|
+
|
|
5
|
+
let(:card_id) { 'placeholder' }
|
|
6
|
+
|
|
7
|
+
describe 'PAY_IN CARD DIRECT' do
|
|
8
|
+
it 'creates a Card Direct PayIn' do
|
|
9
|
+
created = create_new_pay_in_card_direct
|
|
10
|
+
|
|
11
|
+
assert_common_pay_in_properties(created)
|
|
12
|
+
expect(created['PaymentType']).to eq('CARD')
|
|
13
|
+
expect(created['ExecutionType']).to eq('DIRECT')
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe 'REFUND' do
|
|
18
|
+
it 'creates a Refund for a PayIn' do
|
|
19
|
+
pay_in = create_new_pay_in_card_direct
|
|
20
|
+
refund = MangoPay::Acquiring::Refund.create(pay_in['Id'], { DebitedFunds: { Currency: 'EUR', Amount: 10 } })
|
|
21
|
+
|
|
22
|
+
expect(refund['Id']).not_to be_nil
|
|
23
|
+
expect(refund['Status']).to eq('SUCCEEDED')
|
|
24
|
+
expect(refund['Type']).to eq('PAYOUT')
|
|
25
|
+
expect(refund['Nature']).to eq('REFUND')
|
|
26
|
+
expect(refund['InitialTransactionType']).to eq('PAYIN')
|
|
27
|
+
expect(refund['InitialTransactionId']).to eq(pay_in['Id'])
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
describe 'PAY_IN APPLE_PAY' do
|
|
32
|
+
it 'creates an ApplePay direct PayIn' do
|
|
33
|
+
created = MangoPay::Acquiring::PayIn::ApplePay::Direct.create(
|
|
34
|
+
DebitedFunds: { Currency: 'EUR', Amount: 100 },
|
|
35
|
+
PaymentData: {
|
|
36
|
+
transactionId: "97e64d87f13a89ff6443cdcc205d5ccf7e15368b0d64126a8a2e0888a3a5c2a0",
|
|
37
|
+
network: "MasterCard",
|
|
38
|
+
tokenDataø: "{\"data\":\"2TihgKbmyPje02.........wAAAAAAAA==\",\"header\":{\"publicKeyHash\":\"xUyeFb75d359bfPEiq2JJMQj694UAxtTuBsaTWMOJxQ=\",\"ephemeralPublicKey\":\"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEkeuICjZ7x15b7hPEBEBT5Zp43l95wCmJCU3QNxBvOCusG9w9sJMULuXlT4K8LOlPgaZzAcyWlfNwnLivVdOPfg==\",\"transactionId\":\"97e64d87f13a89ff6443cdcc205d5ccf7e15368b0d64126a8a2e0888a3a5c2a0\"},\"version\":\"EC_v1\"}"
|
|
39
|
+
}
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
assert_common_pay_in_properties(created)
|
|
43
|
+
expect(created['PaymentType']).to eq('APPLEPAY')
|
|
44
|
+
expect(created['ExecutionType']).to eq('DIRECT')
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe 'PAY_IN GOOGLE_PAY' do
|
|
49
|
+
it 'creates a GooglePay direct PayIn' do
|
|
50
|
+
created = MangoPay::Acquiring::PayIn::GooglePay::Direct.create(
|
|
51
|
+
DebitedFunds: { Currency: 'EUR', Amount: 199 },
|
|
52
|
+
IpAddress: "2001:0620:0000:0000:0211:24FF:FE80:C12C",
|
|
53
|
+
SecureModeReturnURL: 'http://test.com',
|
|
54
|
+
BrowserInfo: {
|
|
55
|
+
AcceptHeader: "text/html, application/xhtml+xml, application/xml;q=0.9, /;q=0.8",
|
|
56
|
+
JavaEnabled: true,
|
|
57
|
+
Language: "fr-FR",
|
|
58
|
+
ColorDepth: 4,
|
|
59
|
+
ScreenHeight: 1800,
|
|
60
|
+
ScreenWidth: 400,
|
|
61
|
+
JavascriptEnabled: true,
|
|
62
|
+
TimeZoneOffset: "+60",
|
|
63
|
+
UserAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 13_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148"
|
|
64
|
+
},
|
|
65
|
+
PaymentData: "{\"signature\":\"MEUCIQDc49/Bw1lTk8ok2fUe4UT......................\\u003d\\\"}\"}"
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
assert_common_pay_in_properties(created)
|
|
69
|
+
expect(created['PaymentType']).to eq('GOOGLEPAY')
|
|
70
|
+
expect(created['ExecutionType']).to eq('DIRECT')
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
describe 'PAY_IN IDEAL WEB' do
|
|
75
|
+
it 'creates an Ideal Web PayIn' do
|
|
76
|
+
created = MangoPay::Acquiring::PayIn::Ideal::Web.create(
|
|
77
|
+
DebitedFunds: { Currency: 'EUR', Amount: 100 },
|
|
78
|
+
ReturnURL: 'http://www.my-site.com/returnURL'
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
assert_common_pay_in_properties(created)
|
|
82
|
+
expect(created['PaymentType']).to eq('IDEAL')
|
|
83
|
+
expect(created['ExecutionType']).to eq('WEB')
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
describe 'PAY_IN PAYPAL' do
|
|
88
|
+
it 'creates a PayPal Web PayIn' do
|
|
89
|
+
created = MangoPay::Acquiring::PayIn::PayPal::Web.create(
|
|
90
|
+
DebitedFunds: { Currency: 'EUR', Amount: 400 },
|
|
91
|
+
ReturnUrl: "http://example.com",
|
|
92
|
+
LineItems: [
|
|
93
|
+
{
|
|
94
|
+
Name: "running shoes",
|
|
95
|
+
Quantity: 1,
|
|
96
|
+
UnitAmount: 200,
|
|
97
|
+
TaxAmount: 0,
|
|
98
|
+
Description: "seller1 ID"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
Name: "running shoes",
|
|
102
|
+
Quantity: 1,
|
|
103
|
+
UnitAmount: 200,
|
|
104
|
+
TaxAmount: 0,
|
|
105
|
+
Description: "seller2 ID"
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
assert_common_pay_in_properties(created)
|
|
111
|
+
expect(created['PaymentType']).to eq('PAYPAL')
|
|
112
|
+
expect(created['ExecutionType']).to eq('WEB')
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it 'creates PayPal DataCollection' do
|
|
116
|
+
data_collection = MangoPay::Acquiring::PayIn::PayPal::Web.create_data_collection(
|
|
117
|
+
{
|
|
118
|
+
"sender_account_id": "A12345N343",
|
|
119
|
+
"sender_first_name": "Jane",
|
|
120
|
+
"sender_last_name": "Doe",
|
|
121
|
+
"sender_email": "jane.doe@sample.com",
|
|
122
|
+
"sender_phone": "(042)11234567",
|
|
123
|
+
"sender_address_zip": "75009",
|
|
124
|
+
"sender_country_code": "FR",
|
|
125
|
+
"sender_create_date": "2012-12-09T19:14:55.277-0:00",
|
|
126
|
+
"sender_signup_ip": "10.220.90.20",
|
|
127
|
+
"sender_popularity_score": "high",
|
|
128
|
+
"receiver_account_id": "A12345N344",
|
|
129
|
+
"receiver_create_date": "2012-12-09T19:14:55.277-0:00",
|
|
130
|
+
"receiver_email": "jane@sample.com",
|
|
131
|
+
"receiver_address_country_code": "FR",
|
|
132
|
+
"business_name": "Jane Ltd",
|
|
133
|
+
"recipient_popularity_score": "high",
|
|
134
|
+
"first_interaction_date": "2012-12-09T19:14:55.277-0:00",
|
|
135
|
+
"txn_count_total": "34",
|
|
136
|
+
"vertical": "Household goods",
|
|
137
|
+
"transaction_is_tangible": "0"
|
|
138
|
+
}
|
|
139
|
+
)
|
|
140
|
+
expect(data_collection['dataCollectionId']).not_to be_nil
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def create_new_pay_in_card_direct
|
|
145
|
+
MangoPay::Acquiring::PayIn::Card::Direct.create(
|
|
146
|
+
DebitedFunds: { Currency: 'EUR', Amount: 100 },
|
|
147
|
+
CardType: 'CB_VISA_MASTERCARD',
|
|
148
|
+
CardId: card_id,
|
|
149
|
+
SecureMode: 'DEFAULT',
|
|
150
|
+
SecureModeReturnURL: 'http://test.com',
|
|
151
|
+
Tag: 'Acquiring Test PayIn/Card/Direct',
|
|
152
|
+
BrowserInfo: {
|
|
153
|
+
AcceptHeader: "text/html, application/xhtml+xml, application/xml;q=0.9, /;q=0.8",
|
|
154
|
+
JavaEnabled: true,
|
|
155
|
+
Language: "FR-FR",
|
|
156
|
+
ColorDepth: 4,
|
|
157
|
+
ScreenHeight: 1800,
|
|
158
|
+
ScreenWidth: 400,
|
|
159
|
+
JavascriptEnabled: true,
|
|
160
|
+
TimeZoneOffset: "+60",
|
|
161
|
+
UserAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 13_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148"
|
|
162
|
+
},
|
|
163
|
+
IpAddress: "2001:0620:0000:0000:0211:24FF:FE80:C12C"
|
|
164
|
+
)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def assert_common_pay_in_properties(pay_in)
|
|
168
|
+
expect(pay_in['Id']).not_to be_nil
|
|
169
|
+
expect(pay_in['Type']).to eq('PAYIN')
|
|
170
|
+
expect(pay_in['Nature']).to eq('REGULAR')
|
|
171
|
+
expect(pay_in['Status']).to eq('SUCCEEDED')
|
|
172
|
+
expect(pay_in['ResultCode']).to eq('000000')
|
|
173
|
+
expect(pay_in['ResultMessage']).to eq('Success')
|
|
174
|
+
expect(pay_in['ExecutionDate']).to be > 0
|
|
175
|
+
end
|
|
176
|
+
end
|