activemerchant 1.42.5 → 1.42.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +8 -8
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CHANGELOG +23 -0
  5. data/CONTRIBUTORS +12 -0
  6. data/README.md +4 -1
  7. data/lib/active_merchant.rb +5 -1
  8. data/lib/active_merchant/billing/gateways/authorize_net.rb +1 -11
  9. data/lib/active_merchant/billing/gateways/balanced.rb +23 -6
  10. data/lib/active_merchant/billing/gateways/cecabank.rb +225 -0
  11. data/lib/active_merchant/billing/gateways/conekta.rb +4 -3
  12. data/lib/active_merchant/billing/gateways/litle.rb +50 -44
  13. data/lib/active_merchant/billing/gateways/maxipago.rb +190 -0
  14. data/lib/active_merchant/billing/gateways/ogone.rb +2 -1
  15. data/lib/active_merchant/billing/gateways/openpay.rb +200 -0
  16. data/lib/active_merchant/billing/gateways/orbital.rb +24 -3
  17. data/lib/active_merchant/billing/gateways/orbital/cvv_result.rb +34 -0
  18. data/lib/active_merchant/billing/gateways/paymill.rb +2 -2
  19. data/lib/active_merchant/billing/gateways/sage_pay.rb +6 -1
  20. data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +2 -1
  21. data/lib/active_merchant/billing/gateways/wirecard.rb +5 -1
  22. data/lib/active_merchant/billing/integrations/alipay.rb +18 -0
  23. data/lib/active_merchant/billing/integrations/alipay/helper.rb +34 -0
  24. data/lib/active_merchant/billing/integrations/alipay/notification.rb +101 -0
  25. data/lib/active_merchant/billing/integrations/paydollar.rb +59 -0
  26. data/lib/active_merchant/billing/integrations/paydollar/helper.rb +41 -0
  27. data/lib/active_merchant/billing/integrations/paydollar/notification.rb +60 -0
  28. data/lib/active_merchant/billing/integrations/paydollar/return.rb +15 -0
  29. data/lib/active_merchant/version.rb +1 -1
  30. metadata +13 -2
  31. metadata.gz.sig +0 -0
@@ -37,7 +37,7 @@ module ActiveMerchant #:nodoc:
37
37
  commit(:post, "charges", post)
38
38
  end
39
39
 
40
- def capture(identifier, money, options = {})
40
+ def capture(money, identifier, options = {})
41
41
  post = {}
42
42
 
43
43
  post[:order_id] = identifier
@@ -46,7 +46,7 @@ module ActiveMerchant #:nodoc:
46
46
  commit(:post, "charges/#{identifier}/capture", post)
47
47
  end
48
48
 
49
- def refund(identifier, money, options)
49
+ def refund(money, identifier, options)
50
50
  post = {}
51
51
 
52
52
  post[:order_id] = identifier
@@ -77,8 +77,9 @@ module ActiveMerchant #:nodoc:
77
77
  private
78
78
 
79
79
  def add_order(post, money, options)
80
- post[:description] = options[:description]
80
+ post[:description] = options[:description] || "Active Merchant Purchase"
81
81
  post[:reference_id] = options[:order_id]
82
+ post[:currency] = (options[:currency] || currency(money)).downcase
82
83
  post[:amount] = amount(money)
83
84
  end
84
85
 
@@ -283,18 +283,19 @@ module ActiveMerchant #:nodoc:
283
283
  exp_date = exp_date_mo + exp_date_yr
284
284
 
285
285
  card_info = {
286
- 'type' => cc_type,
287
- 'number' => creditcard.number,
288
- 'expDate' => exp_date,
289
- 'cardValidationNum' => creditcard.verification_value
286
+ 'type' => cc_type,
287
+ 'number' => creditcard.number,
288
+ 'expDate' => exp_date,
289
+ 'cardValidationNum' => creditcard.verification_value
290
290
  }
291
291
 
292
292
  hash['card'] = card_info
293
293
  hash
294
294
  end
295
295
 
296
- def create_capture_hash(money, authorization, options)
296
+ def create_capture_hash(money, authorization, options={})
297
297
  hash = create_hash(money, options)
298
+ hash['partial'] = true if money
298
299
  hash['litleTxnId'] = authorization
299
300
  hash
300
301
  end
@@ -340,58 +341,63 @@ module ActiveMerchant #:nodoc:
340
341
 
341
342
  if options[:billing_address]
342
343
  bill_to_address = {
343
- 'name' => options[:billing_address][:name],
344
- 'companyName' => options[:billing_address][:company],
345
- 'addressLine1' => options[:billing_address][:address1],
346
- 'addressLine2' => options[:billing_address][:address2],
347
- 'city' => options[:billing_address][:city],
348
- 'state' => options[:billing_address][:state],
349
- 'zip' => options[:billing_address][:zip],
350
- 'country' => options[:billing_address][:country],
351
- 'email' => options[:email],
352
- 'phone' => options[:billing_address][:phone]
344
+ 'name' => options[:billing_address][:name],
345
+ 'companyName' => options[:billing_address][:company],
346
+ 'addressLine1' => options[:billing_address][:address1],
347
+ 'addressLine2' => options[:billing_address][:address2],
348
+ 'city' => options[:billing_address][:city],
349
+ 'state' => options[:billing_address][:state],
350
+ 'zip' => options[:billing_address][:zip],
351
+ 'country' => options[:billing_address][:country],
352
+ 'email' => options[:email],
353
+ 'phone' => options[:billing_address][:phone]
353
354
  }
354
355
  end
355
356
  if options[:shipping_address]
356
357
  ship_to_address = {
357
- 'name' => options[:shipping_address][:name],
358
- 'companyName' => options[:shipping_address][:company],
359
- 'addressLine1' => options[:shipping_address][:address1],
360
- 'addressLine2' => options[:shipping_address][:address2],
361
- 'city' => options[:shipping_address][:city],
362
- 'state' => options[:shipping_address][:state],
363
- 'zip' => options[:shipping_address][:zip],
364
- 'country' => options[:shipping_address][:country],
365
- 'email' => options[:email],
366
- 'phone' => options[:shipping_address][:phone]
358
+ 'name' => options[:shipping_address][:name],
359
+ 'companyName' => options[:shipping_address][:company],
360
+ 'addressLine1' => options[:shipping_address][:address1],
361
+ 'addressLine2' => options[:shipping_address][:address2],
362
+ 'city' => options[:shipping_address][:city],
363
+ 'state' => options[:shipping_address][:state],
364
+ 'zip' => options[:shipping_address][:zip],
365
+ 'country' => options[:shipping_address][:country],
366
+ 'email' => options[:email],
367
+ 'phone' => options[:shipping_address][:phone]
367
368
  }
368
369
  end
369
370
 
370
371
  hash = {
371
- 'billToAddress' => bill_to_address,
372
- 'shipToAddress' => ship_to_address,
373
- 'orderId' => (options[:order_id] || @options[:order_id]),
374
- 'customerId' => options[:customer],
375
- 'reportGroup' => (options[:merchant] || @options[:merchant]),
376
- 'merchantId' => (options[:merchant_id] || @options[:merchant_id]),
377
- 'orderSource' => (options[:order_source] || 'ecommerce'),
378
- 'enhancedData' => enhanced_data,
379
- 'fraudCheckType' => fraud_check_type,
380
- 'user' => (options[:user] || @options[:user]),
381
- 'password' => (options[:password] || @options[:password]),
382
- 'version' => (options[:version] || @options[:version]),
383
- 'url' => (options[:url] || url),
384
- 'proxy_addr' => (options[:proxy_addr] || @options[:proxy_addr]),
385
- 'proxy_port' => (options[:proxy_port] || @options[:proxy_port]),
386
- 'id' => (options[:id] || options[:order_id] || @options[:order_id])
372
+ 'billToAddress' => bill_to_address,
373
+ 'shipToAddress' => ship_to_address,
374
+ 'orderId' => truncated_order_id(options),
375
+ 'customerId' => options[:customer],
376
+ 'reportGroup' => (options[:merchant] || @options[:merchant]),
377
+ 'merchantId' => (options[:merchant_id] || @options[:merchant_id]),
378
+ 'orderSource' => (options[:order_source] || 'ecommerce'),
379
+ 'enhancedData' => enhanced_data,
380
+ 'fraudCheckType' => fraud_check_type,
381
+ 'user' => (options[:user] || @options[:user]),
382
+ 'password' => (options[:password] || @options[:password]),
383
+ 'version' => (options[:version] || @options[:version]),
384
+ 'url' => (options[:url] || url),
385
+ 'proxy_addr' => (options[:proxy_addr] || @options[:proxy_addr]),
386
+ 'proxy_port' => (options[:proxy_port] || @options[:proxy_port]),
387
+ 'id' => (options[:id] || options[:order_id] || @options[:order_id])
387
388
  }
388
389
 
389
- if (!money.nil? && money.to_s.length > 0)
390
- hash.merge!({ 'amount' => money })
391
- end
390
+ hash.merge!('amount' => money) if(money && (money != ""))
391
+
392
392
  hash
393
393
  end
394
394
 
395
+ def truncated_order_id(options)
396
+ order_id = options[:order_id] || @options[:order_id]
397
+ return unless order_id
398
+ order_id[0..24]
399
+ end
400
+
395
401
  def fraud_result(authorization_response)
396
402
  if result = authorization_response['fraudResult']
397
403
  if result.key?('cardValidationResult')
@@ -0,0 +1,190 @@
1
+ require 'nokogiri'
2
+
3
+ module ActiveMerchant #:nodoc:
4
+ module Billing #:nodoc:
5
+ class MaxipagoGateway < Gateway
6
+ API_VERSION = '3.1.1.15'
7
+
8
+ self.live_url = 'https://api.maxipago.net/UniversalAPI/postXML'
9
+ self.test_url = 'https://testapi.maxipago.net/UniversalAPI/postXML'
10
+
11
+ self.supported_countries = ['BR']
12
+ self.default_currency = 'BRL'
13
+ self.money_format = :dollars
14
+ self.supported_cardtypes = [:visa, :master, :discover, :american_express, :diners_club]
15
+ self.homepage_url = 'http://www.maxipago.com/'
16
+ self.display_name = 'maxiPago!'
17
+
18
+ def initialize(options = {})
19
+ requires!(options, :login, :password)
20
+ super
21
+ end
22
+
23
+ def purchase(money, creditcard, options = {})
24
+ post = {}
25
+ add_aux_data(post, options)
26
+ add_amount(post, money)
27
+ add_creditcard(post, creditcard)
28
+ add_name(post, creditcard)
29
+ add_address(post, options)
30
+
31
+ commit(build_sale_request(post))
32
+ end
33
+
34
+ def authorize(money, creditcard, options = {})
35
+ post = {}
36
+ add_aux_data(post, options)
37
+ add_amount(post, money)
38
+ add_creditcard(post, creditcard)
39
+ add_name(post, creditcard)
40
+ add_address(post, options)
41
+
42
+ commit(build_sale_request(post, "auth"))
43
+ end
44
+
45
+ def capture(money, authorization, options = {})
46
+ post = {}
47
+ add_amount(post, money)
48
+ add_aux_data(post, options)
49
+ commit(build_capture_request(authorization, post))
50
+ end
51
+
52
+ private
53
+
54
+ def commit(request)
55
+ url = (test? ? self.test_url : self.live_url)
56
+ response = parse(ssl_post(url, request, 'Content-Type' => 'text/xml'))
57
+ Response.new(
58
+ success?(response),
59
+ message_from(response),
60
+ response,
61
+ test: test?,
62
+ authorization: response[:order_id]
63
+ )
64
+ end
65
+
66
+ def success?(response)
67
+ (response[:response_code] == '0')
68
+ end
69
+
70
+ def message_from(response)
71
+ return response[:error_message] if response[:error_message].present?
72
+ return response[:processor_message] if response[:processor_message].present?
73
+ return response[:response_message] if response[:response_message].present?
74
+ return (success?(response) ? 'success' : 'error')
75
+ end
76
+
77
+ def add_aux_data(post, options)
78
+ post[:processorID] = (test? ? 1 : 4) # test: 1, redecard: 2, cielo: 4
79
+ post[:referenceNum] = options[:order_id]
80
+ end
81
+
82
+ def add_amount(post, money)
83
+ post[:amount] = amount(money)
84
+ end
85
+
86
+ def add_creditcard(post, creditcard)
87
+ post[:card_number] = creditcard.number
88
+ post[:card_exp_month] = creditcard.month
89
+ post[:card_exp_year] = creditcard.year
90
+ post[:card_cvv] = creditcard.verification_value
91
+ end
92
+
93
+ def add_name(post, creditcard)
94
+ post[:billing_name] = creditcard.name
95
+ end
96
+
97
+ def add_address(post, options)
98
+ if(address = (options[:address] || options[:billing_address]))
99
+ post[:billing_address] = address[:address1]
100
+ post[:billing_address2] = address[:address2]
101
+ post[:billing_city] = address[:city]
102
+ post[:billing_state] = address[:state]
103
+ post[:billing_postalcode] = address[:zip]
104
+ post[:billing_country] = address[:country]
105
+ post[:billing_phone] = address[:phone]
106
+ end
107
+ end
108
+
109
+ def build_capture_request(authorization, params)
110
+ build_request(params) do |xml|
111
+ xml.capture! {
112
+ xml.orderID authorization
113
+ xml.referenceNum params[:referenceNum]
114
+ xml.payment {
115
+ xml.chargeTotal params[:amount]
116
+ }
117
+ }
118
+ end
119
+ end
120
+
121
+ def build_sale_request(params, action="sale")
122
+ build_request(params) do |xml|
123
+ xml.send(action) {
124
+ xml.processorID params[:processorID]
125
+ xml.fraudCheck 'N'
126
+ xml.referenceNum params[:referenceNum] # spree_order
127
+ xml.transactionDetail {
128
+ xml.payType {
129
+ xml.creditCard {
130
+ xml.number params[:card_number]
131
+ xml.expMonth params[:card_exp_month]
132
+ xml.expYear params[:card_exp_year]
133
+ xml.cvvNumber params[:card_cvv]
134
+ }
135
+ }
136
+ }
137
+ xml.payment {
138
+ xml.chargeTotal params[:amount]
139
+ }
140
+ xml.billing {
141
+ xml.name params[:billing_name]
142
+ xml.address params[:billing_address] if params[:billing_address].present?
143
+ xml.address2 params[:billing_address2] if params[:billing_address2].present?
144
+ xml.city params[:billing_city] if params[:billing_city].present?
145
+ xml.state params[:billing_state] if params[:billing_state].present?
146
+ xml.postalcode params[:billing_postalcode] if params[:billing_postalcode].present?
147
+ xml.country params[:billing_country] if params[:billing_country].present?
148
+ xml.phone params[:billing_phone] if params[:billing_phone].present?
149
+ }
150
+ }
151
+ end
152
+ end
153
+
154
+ def build_request(params)
155
+ builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
156
+ xml.send("transaction-request") {
157
+ xml.version API_VERSION
158
+ xml.verification {
159
+ xml.merchantId @options[:login]
160
+ xml.merchantKey @options[:password]
161
+ }
162
+ xml.order {
163
+ yield(xml)
164
+ }
165
+ }
166
+ end
167
+ builder.to_xml(indent: 2)
168
+ end
169
+
170
+ def parse(body)
171
+ xml = REXML::Document.new(body)
172
+
173
+ response = {}
174
+ xml.root.elements.to_a.each do |node|
175
+ parse_element(response, node)
176
+ end
177
+ response
178
+ end
179
+
180
+ def parse_element(response, node)
181
+ if node.has_elements?
182
+ node.elements.each{|element| parse_element(response, element) }
183
+ else
184
+ response[node.name.underscore.to_sym] = node.text
185
+ end
186
+ end
187
+ end
188
+ end
189
+ end
190
+
@@ -244,6 +244,8 @@ module ActiveMerchant #:nodoc:
244
244
  end
245
245
 
246
246
  def add_payment_source(post, payment_source, options)
247
+ add_d3d(post, options) if options[:d3d]
248
+
247
249
  if payment_source.is_a?(String)
248
250
  add_alias(post, payment_source, options[:alias_operation])
249
251
  add_eci(post, options[:eci] || '9')
@@ -254,7 +256,6 @@ module ActiveMerchant #:nodoc:
254
256
  end
255
257
  add_alias(post, options[:billing_id], options[:alias_operation])
256
258
  add_eci(post, options[:eci] || '7')
257
- add_d3d(post, options) if options[:d3d]
258
259
  add_creditcard(post, payment_source)
259
260
  end
260
261
  end
@@ -0,0 +1,200 @@
1
+ module ActiveMerchant #:nodoc:
2
+ module Billing #:nodoc:
3
+ class OpenpayGateway < Gateway
4
+ self.live_url = 'https://api.openpay.mx/v1/'
5
+ self.test_url = 'https://sandbox-api.openpay.mx/v1/'
6
+
7
+ self.supported_countries = ['MX']
8
+ self.supported_cardtypes = [:visa, :master, :american_express]
9
+ self.homepage_url = 'http://www.openpay.mx/'
10
+ self.display_name = 'Openpay'
11
+ self.default_currency = 'MXN'
12
+
13
+ # Instantiate a instance of OpenpayGateway by passing through your
14
+ # merchant id and private api key.
15
+ #
16
+ # === To obtain your own credentials
17
+ # 1. Visit http://openpay.mx
18
+ # 2. Sign up
19
+ # 3. Activate your account clicking on the email confirmation
20
+ def initialize(options = {})
21
+ requires!(options, :key, :merchant_id)
22
+ @api_key = options[:key]
23
+ @merchant_id = options[:merchant_id]
24
+ super
25
+ end
26
+
27
+ def purchase(money, creditcard, options = {})
28
+ post = create_post_for_auth_or_purchase(money, creditcard, options)
29
+ commit(:post, 'charges', post, options)
30
+ end
31
+
32
+ def authorize(money, creditcard, options = {})
33
+ post = create_post_for_auth_or_purchase(money, creditcard, options)
34
+ post[:capture] = false
35
+ commit(:post, 'charges', post, options)
36
+ end
37
+
38
+ def capture(money, authorization, options = {})
39
+ post = {}
40
+ post[:amount] = amount(money) if money
41
+ commit(:post, "charges/#{CGI.escape(authorization)}/capture", post, options)
42
+ end
43
+
44
+ def void(identification, options = {})
45
+ commit(:post, "charges/#{CGI.escape(identification)}/refund", nil, options)
46
+ end
47
+
48
+ def refund(money, identification, options = {})
49
+ post = {}
50
+ post[:description] = options[:description]
51
+ post[:amount] = amount(money)
52
+ commit(:post, "charges/#{CGI.escape(identification)}/refund", post, options)
53
+ end
54
+
55
+ def store(creditcard, options = {})
56
+ card_params = {}
57
+ add_creditcard(card_params, creditcard, options)
58
+ card = card_params[:card]
59
+
60
+ if options[:customer].present?
61
+ commit(:post, "customers/#{CGI.escape(options[:customer])}/cards", card, options)
62
+ else
63
+ requires!(options, :email, :name)
64
+ post = {}
65
+ post[:name] = options[:name]
66
+ post[:email] = options[:email]
67
+ MultiResponse.run(:first) do |r|
68
+ r.process { commit(:post, 'customers', post, options) }
69
+
70
+ if(r.success? && !r.params['id'].blank?)
71
+ customer_id = r.params['id']
72
+ r.process { commit(:post, "customers/#{customer_id}/cards", card, options) }
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ def unstore(customer_id, card_id = nil, options = {})
79
+ if card_id.nil?
80
+ commit(:delete, "customers/#{CGI.escape(customer_id)}", nil, options)
81
+ else
82
+ commit(:delete, "customers/#{CGI.escape(customer_id)}/cards/#{CGI.escape(card_id)}", nil, options)
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ def create_post_for_auth_or_purchase(money, creditcard, options)
89
+ post = {}
90
+ post[:amount] = amount(money)
91
+ post[:method] = 'card'
92
+ post[:description] = options[:description]
93
+ post[:order_id] = options[:order_id]
94
+ add_creditcard(post, creditcard, options)
95
+ post
96
+ end
97
+
98
+ def add_creditcard(post, creditcard, options)
99
+ if creditcard.kind_of?(String)
100
+ post[:source_id] = creditcard
101
+ elsif creditcard.respond_to?(:number)
102
+ card = {
103
+ card_number: creditcard.number,
104
+ expiration_month: "#{sprintf("%02d", creditcard.month)}",
105
+ expiration_year: "#{"#{creditcard.year}"[-2, 2]}",
106
+ cvv2: creditcard.verification_value,
107
+ holder_name: creditcard.name
108
+ }
109
+ add_address(card, options)
110
+ post[:card] = card
111
+ end
112
+ end
113
+
114
+ def add_address(card, options)
115
+ return unless card.kind_of?(Hash)
116
+ if address = (options[:billing_address] || options[:address])
117
+ card[:address] = {
118
+ line1: address[:address1],
119
+ line2: address[:address2],
120
+ line3: address[:company],
121
+ city: address[:city],
122
+ postal_code: address[:zip],
123
+ state: address[:state],
124
+ country_code: address[:country]
125
+ }
126
+ end
127
+ end
128
+
129
+ def headers(options = {})
130
+ @@ua ||= JSON.dump(
131
+ :bindings_version => ActiveMerchant::VERSION,
132
+ :lang => 'ruby',
133
+ :lang_version => "#{RUBY_VERSION} p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE})",
134
+ :platform => RUBY_PLATFORM,
135
+ :publisher => 'active_merchant'
136
+ )
137
+ {
138
+ "Content-Type" => "application/json",
139
+ "Authorization" => "Basic " + Base64.encode64(@api_key.to_s + ":").strip,
140
+ "User-Agent" => "Openpay/v1 ActiveMerchantBindings/#{ActiveMerchant::VERSION}",
141
+ "X-Openpay-Client-User-Agent" => @@ua
142
+ }
143
+ end
144
+
145
+ def parse(body)
146
+ return {} unless body
147
+ JSON.parse(body)
148
+ end
149
+
150
+ def commit(method, resource, parameters, options = {})
151
+ response = http_request(method, resource, parameters, options)
152
+ success = !error?(response)
153
+
154
+ Response.new(success,
155
+ (success ? response['error_code'] : response['description']),
156
+ response,
157
+ :test => test?,
158
+ :authorization => response['id']
159
+ )
160
+ end
161
+
162
+ def http_request(method, resource, parameters={}, options={})
163
+ url = (test? ? self.test_url : self.live_url) + @merchant_id + '/' + resource
164
+ raw_response = nil
165
+ begin
166
+ raw_response = ssl_request(method, url, (parameters ? parameters.to_json : nil), headers(options))
167
+ parse(raw_response)
168
+ rescue ResponseError => e
169
+ raw_response = e.response.body
170
+ response_error(raw_response)
171
+ rescue JSON::ParserError
172
+ json_error(raw_response)
173
+ end
174
+ end
175
+
176
+ def error?(response)
177
+ response.key?('error_code')
178
+ end
179
+
180
+ def response_error(raw_response)
181
+ begin
182
+ parse(raw_response)
183
+ rescue JSON::ParserError
184
+ json_error(raw_response)
185
+ end
186
+ end
187
+
188
+ def json_error(raw_response)
189
+ msg = 'Invalid response received from the Openpay API. Please contact soporte@openpay.mx if you continue to receive this message.'
190
+ msg += " (The raw response returned by the API was #{raw_response.inspect})"
191
+ {
192
+ 'category' => 'request',
193
+ 'error_code' => '9999',
194
+ 'description' => msg
195
+ }
196
+ end
197
+ end
198
+ end
199
+ end
200
+