activemerchant 1.42.5 → 1.42.6

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 (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
+