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.
Files changed (126) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ruby_cd.yml +34 -0
  3. data/.github/workflows/ruby_ci.yml +30 -0
  4. data/.gitignore +30 -0
  5. data/.rspec +3 -0
  6. data/CHANGELOG.md +640 -0
  7. data/Gemfile +2 -0
  8. data/LICENSE +20 -0
  9. data/README.md +162 -0
  10. data/Rakefile +5 -0
  11. data/bin/mangopay +9 -0
  12. data/lib/generators/mangopay/install_generator.rb +60 -0
  13. data/lib/generators/templates/mangopay.rb.erb +5 -0
  14. data/lib/mangopay/acquiring.rb +56 -0
  15. data/lib/mangopay/authorization_token.rb +89 -0
  16. data/lib/mangopay/bank_account.rb +49 -0
  17. data/lib/mangopay/bankingaliases.rb +29 -0
  18. data/lib/mangopay/bankingaliases_iban.rb +16 -0
  19. data/lib/mangopay/card.rb +54 -0
  20. data/lib/mangopay/card_registration.rb +9 -0
  21. data/lib/mangopay/client.rb +94 -0
  22. data/lib/mangopay/conversion.rb +49 -0
  23. data/lib/mangopay/deposit.rb +36 -0
  24. data/lib/mangopay/dispute.rb +152 -0
  25. data/lib/mangopay/errors.rb +66 -0
  26. data/lib/mangopay/event.rb +18 -0
  27. data/lib/mangopay/filter_parameters.rb +56 -0
  28. data/lib/mangopay/hook.rb +9 -0
  29. data/lib/mangopay/http_calls.rb +88 -0
  30. data/lib/mangopay/identity_verification.rb +16 -0
  31. data/lib/mangopay/json.rb +14 -0
  32. data/lib/mangopay/kyc_document.rb +83 -0
  33. data/lib/mangopay/legal_user.rb +21 -0
  34. data/lib/mangopay/legal_user_sca.rb +25 -0
  35. data/lib/mangopay/mandate.rb +42 -0
  36. data/lib/mangopay/natural_user.rb +20 -0
  37. data/lib/mangopay/natural_user_sca.rb +25 -0
  38. data/lib/mangopay/pay_in.rb +415 -0
  39. data/lib/mangopay/pay_out.rb +41 -0
  40. data/lib/mangopay/payment_method_metadata.rb +13 -0
  41. data/lib/mangopay/pre_authorization.rb +17 -0
  42. data/lib/mangopay/recipient.rb +35 -0
  43. data/lib/mangopay/refund.rb +19 -0
  44. data/lib/mangopay/regulatory.rb +22 -0
  45. data/lib/mangopay/report.rb +24 -0
  46. data/lib/mangopay/report_v2.rb +21 -0
  47. data/lib/mangopay/resource.rb +21 -0
  48. data/lib/mangopay/settlement.rb +21 -0
  49. data/lib/mangopay/transaction.rb +24 -0
  50. data/lib/mangopay/transfer.rb +20 -0
  51. data/lib/mangopay/ubo.rb +26 -0
  52. data/lib/mangopay/ubo_declaration.rb +32 -0
  53. data/lib/mangopay/user.rb +100 -0
  54. data/lib/mangopay/version.rb +3 -0
  55. data/lib/mangopay/virtual_account.rb +44 -0
  56. data/lib/mangopay/wallet.rb +17 -0
  57. data/lib/mangopay.rb +456 -0
  58. data/mangopay.gemspec +30 -0
  59. data/spec/mangopay/acquiring_spec.rb +176 -0
  60. data/spec/mangopay/authorization_token_spec.rb +70 -0
  61. data/spec/mangopay/bank_account_spec.rb +105 -0
  62. data/spec/mangopay/bankingaliases_spec.rb +29 -0
  63. data/spec/mangopay/card_registration_spec.rb +123 -0
  64. data/spec/mangopay/client_spec.png +0 -0
  65. data/spec/mangopay/client_spec.rb +213 -0
  66. data/spec/mangopay/configuration_spec.rb +249 -0
  67. data/spec/mangopay/conversion_spec.rb +96 -0
  68. data/spec/mangopay/deposit_spec.rb +107 -0
  69. data/spec/mangopay/dispute_spec.png +0 -0
  70. data/spec/mangopay/dispute_spec.rb +294 -0
  71. data/spec/mangopay/event_spec.rb +33 -0
  72. data/spec/mangopay/fetch_filters_spec.rb +63 -0
  73. data/spec/mangopay/hook_spec.rb +37 -0
  74. data/spec/mangopay/idempotency_spec.rb +41 -0
  75. data/spec/mangopay/identity_verification_spec.rb +47 -0
  76. data/spec/mangopay/kyc_document_spec.png +0 -0
  77. data/spec/mangopay/kyc_document_spec.rb +118 -0
  78. data/spec/mangopay/log_requests_filter_spec.rb +26 -0
  79. data/spec/mangopay/mandate_spec.rb +99 -0
  80. data/spec/mangopay/payin_applepay_direct_spec.rb +21 -0
  81. data/spec/mangopay/payin_bancontact_web_spec.rb +30 -0
  82. data/spec/mangopay/payin_bankwire_direct_spec.rb +74 -0
  83. data/spec/mangopay/payin_bankwire_external_instruction_spec.rb +104 -0
  84. data/spec/mangopay/payin_bizum_web_spec.rb +54 -0
  85. data/spec/mangopay/payin_blik_web_spec.rb +41 -0
  86. data/spec/mangopay/payin_card_direct_spec.rb +69 -0
  87. data/spec/mangopay/payin_card_web_spec.rb +64 -0
  88. data/spec/mangopay/payin_directdebit_direct_spec.rb +37 -0
  89. data/spec/mangopay/payin_directdebit_web_spec.rb +38 -0
  90. data/spec/mangopay/payin_giropay_web_spec.rb +30 -0
  91. data/spec/mangopay/payin_googlepay_direct_spec.rb +21 -0
  92. data/spec/mangopay/payin_ideal_web_spec.rb +30 -0
  93. data/spec/mangopay/payin_intent_spec.rb +151 -0
  94. data/spec/mangopay/payin_klarna_web_spec.rb +32 -0
  95. data/spec/mangopay/payin_mbway_web_spec.rb +32 -0
  96. data/spec/mangopay/payin_multibanco_web_spec.rb +31 -0
  97. data/spec/mangopay/payin_paybybank_web_spec.rb +56 -0
  98. data/spec/mangopay/payin_payconiq_web_spec.rb +31 -0
  99. data/spec/mangopay/payin_paypal_web_spec.rb +113 -0
  100. data/spec/mangopay/payin_preauthorized_direct_spec.rb +118 -0
  101. data/spec/mangopay/payin_satispay_web_spec.rb +32 -0
  102. data/spec/mangopay/payin_swish_web_spec.rb +30 -0
  103. data/spec/mangopay/payin_twint_web_spec.rb +30 -0
  104. data/spec/mangopay/payment_method_metadata_spec.rb +15 -0
  105. data/spec/mangopay/payout_bankwire_spec.rb +93 -0
  106. data/spec/mangopay/preauthorization_spec.rb +51 -0
  107. data/spec/mangopay/recipient_spec.rb +134 -0
  108. data/spec/mangopay/recurring_payin_spec.rb +222 -0
  109. data/spec/mangopay/refund_spec.rb +34 -0
  110. data/spec/mangopay/regulatory_spec.rb +26 -0
  111. data/spec/mangopay/report_spec.rb +40 -0
  112. data/spec/mangopay/report_v2_spec.rb +117 -0
  113. data/spec/mangopay/report_wallets_spec.rb +40 -0
  114. data/spec/mangopay/settlement_sample.csv +8 -0
  115. data/spec/mangopay/settlement_spec.rb +38 -0
  116. data/spec/mangopay/shared_resources.rb +1380 -0
  117. data/spec/mangopay/transaction_spec.rb +59 -0
  118. data/spec/mangopay/transfer_spec.rb +77 -0
  119. data/spec/mangopay/ubo_declaration_spec.rb +44 -0
  120. data/spec/mangopay/ubo_spec.rb +39 -0
  121. data/spec/mangopay/user_spec.rb +444 -0
  122. data/spec/mangopay/virtual_account_spec.rb +52 -0
  123. data/spec/mangopay/wallet_spec.rb +100 -0
  124. data/spec/spec_helper.rb +31 -0
  125. data/spec/tmp/.keep +0 -0
  126. 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