activemerchant 1.54.0 → 1.55.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +51 -0
- data/CONTRIBUTORS +24 -0
- data/README.md +8 -2
- data/lib/active_merchant/billing/base.rb +11 -22
- data/lib/active_merchant/billing/credit_card.rb +24 -1
- data/lib/active_merchant/billing/gateway.rb +18 -8
- data/lib/active_merchant/billing/gateways/allied_wallet.rb +1 -1
- data/lib/active_merchant/billing/gateways/authorize_net.rb +12 -14
- data/lib/active_merchant/billing/gateways/blue_pay.rb +3 -2
- data/lib/active_merchant/billing/gateways/bogus.rb +63 -17
- data/lib/active_merchant/billing/gateways/braintree/braintree_common.rb +1 -1
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +19 -10
- data/lib/active_merchant/billing/gateways/cams.rb +230 -0
- data/lib/active_merchant/billing/gateways/card_stream.rb +1 -1
- data/lib/active_merchant/billing/gateways/clearhaus.rb +238 -0
- data/lib/active_merchant/billing/gateways/creditcall.rb +1 -1
- data/lib/active_merchant/billing/gateways/cyber_source.rb +1 -0
- data/lib/active_merchant/billing/gateways/elavon.rb +21 -18
- data/lib/active_merchant/billing/gateways/eway_rapid.rb +7 -7
- data/lib/active_merchant/billing/gateways/ezic.rb +2 -12
- data/lib/active_merchant/billing/gateways/firstdata_e4.rb +15 -9
- data/lib/active_merchant/billing/gateways/forte.rb +32 -21
- data/lib/active_merchant/billing/gateways/inspire.rb +1 -1
- data/lib/active_merchant/billing/gateways/jetpay.rb +141 -38
- data/lib/active_merchant/billing/gateways/komoju.rb +115 -0
- data/lib/active_merchant/billing/gateways/litle.rb +7 -3
- data/lib/active_merchant/billing/gateways/merchant_ware_version_four.rb +1 -1
- data/lib/active_merchant/billing/gateways/micropayment.rb +18 -14
- data/lib/active_merchant/billing/gateways/modern_payments_cim.rb +1 -3
- data/lib/active_merchant/billing/gateways/monei.rb +1 -1
- data/lib/active_merchant/billing/gateways/netbilling.rb +10 -11
- data/lib/active_merchant/billing/gateways/omise.rb +2 -2
- data/lib/active_merchant/billing/gateways/optimal_payment.rb +3 -2
- data/lib/active_merchant/billing/gateways/orbital.rb +1 -0
- data/lib/active_merchant/billing/gateways/pay_gate_xml.rb +1 -1
- data/lib/active_merchant/billing/gateways/paybox_direct.rb +2 -1
- data/lib/active_merchant/billing/gateways/payeezy.rb +238 -0
- data/lib/active_merchant/billing/gateways/payflow.rb +16 -3
- data/lib/active_merchant/billing/gateways/paymill.rb +101 -44
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +2 -2
- data/lib/active_merchant/billing/gateways/paypal_express.rb +8 -0
- data/lib/active_merchant/billing/gateways/quickpay/quickpay_v10.rb +1 -1
- data/lib/active_merchant/billing/gateways/sage_pay.rb +6 -14
- data/lib/active_merchant/billing/gateways/secure_net.rb +3 -4
- data/lib/active_merchant/billing/gateways/securion_pay.rb +238 -0
- data/lib/active_merchant/billing/gateways/stripe.rb +9 -7
- data/lib/active_merchant/billing/gateways/swipe_checkout.rb +1 -2
- data/lib/active_merchant/billing/gateways/tns.rb +2 -8
- data/lib/active_merchant/billing/gateways/transact_pro.rb +224 -0
- data/lib/active_merchant/billing/gateways/trust_commerce.rb +2 -2
- data/lib/active_merchant/billing/gateways/usa_epay_advanced.rb +5 -7
- data/lib/active_merchant/billing/gateways/usa_epay_transaction.rb +12 -11
- data/lib/active_merchant/billing/gateways/vanco.rb +8 -3
- data/lib/active_merchant/billing/gateways/viaklix.rb +1 -9
- data/lib/active_merchant/billing/gateways/worldpay_online_payments.rb +22 -8
- data/lib/active_merchant/posts_data.rb +2 -2
- data/lib/active_merchant/version.rb +1 -1
- metadata +8 -2
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module ActiveMerchant #:nodoc:
|
4
|
+
module Billing #:nodoc:
|
5
|
+
class KomojuGateway < Gateway
|
6
|
+
self.test_url = "https://sandbox.komoju.com/api/v1"
|
7
|
+
self.live_url = "https://komoju.com/api/v1"
|
8
|
+
self.supported_countries = ['JP']
|
9
|
+
self.default_currency = 'JPY'
|
10
|
+
self.money_format = :cents
|
11
|
+
self.homepage_url = 'https://www.komoju.com/'
|
12
|
+
self.display_name = 'Komoju'
|
13
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :jcb]
|
14
|
+
|
15
|
+
STANDARD_ERROR_CODE_MAPPING = {
|
16
|
+
"bad_verification_value" => "incorrect_cvc",
|
17
|
+
"card_expired" => "expired_card",
|
18
|
+
"card_declined" => "card_declined",
|
19
|
+
"invalid_number" => "invalid_number"
|
20
|
+
}
|
21
|
+
|
22
|
+
def initialize(options = {})
|
23
|
+
requires!(options, :login)
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
def purchase(money, payment, options = {})
|
28
|
+
post = {}
|
29
|
+
post[:amount] = amount(money)
|
30
|
+
post[:description] = options[:description]
|
31
|
+
add_payment_details(post, payment, options)
|
32
|
+
post[:currency] = options[:currency] || default_currency
|
33
|
+
post[:external_order_num] = options[:order_id] if options[:order_id]
|
34
|
+
post[:tax] = options[:tax] if options[:tax]
|
35
|
+
add_fraud_details(post, options)
|
36
|
+
|
37
|
+
commit("/payments", post)
|
38
|
+
end
|
39
|
+
|
40
|
+
def refund(money, identification, options = {})
|
41
|
+
commit("/payments/#{identification}/refund", {})
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def add_payment_details(post, payment, options)
|
47
|
+
details = {}
|
48
|
+
|
49
|
+
details[:type] = 'credit_card'
|
50
|
+
details[:number] = payment.number
|
51
|
+
details[:month] = payment.month
|
52
|
+
details[:year] = payment.year
|
53
|
+
details[:verification_value] = payment.verification_value
|
54
|
+
details[:given_name] = payment.first_name
|
55
|
+
details[:family_name] = payment.last_name
|
56
|
+
details[:email] = options[:email] if options[:email]
|
57
|
+
|
58
|
+
post[:payment_details] = details
|
59
|
+
end
|
60
|
+
|
61
|
+
def add_fraud_details(post, options)
|
62
|
+
details = {}
|
63
|
+
|
64
|
+
details[:customer_ip] = options[:ip] if options[:ip]
|
65
|
+
details[:customer_email] = options[:email] if options[:email]
|
66
|
+
details[:browser_language] = options[:browser_language] if options[:browser_language]
|
67
|
+
details[:browser_user_agent] = options[:browser_user_agent] if options[:browser_user_agent]
|
68
|
+
|
69
|
+
post[:fraud_details] = details unless details.empty?
|
70
|
+
end
|
71
|
+
|
72
|
+
def api_request(path, data)
|
73
|
+
raw_response = nil
|
74
|
+
begin
|
75
|
+
raw_response = ssl_post("#{url}#{path}", data, headers)
|
76
|
+
rescue ResponseError => e
|
77
|
+
raw_response = e.response.body
|
78
|
+
end
|
79
|
+
|
80
|
+
JSON.parse(raw_response)
|
81
|
+
end
|
82
|
+
|
83
|
+
def commit(path, params)
|
84
|
+
response = api_request(path, params.to_json)
|
85
|
+
success = !response.key?("error")
|
86
|
+
message = (success ? "Transaction succeeded" : response["error"]["message"])
|
87
|
+
Response.new(
|
88
|
+
success,
|
89
|
+
message,
|
90
|
+
response,
|
91
|
+
test: test?,
|
92
|
+
error_code: (success ? nil : error_code(response["error"]["code"])),
|
93
|
+
authorization: (success ? response["id"] : nil)
|
94
|
+
)
|
95
|
+
end
|
96
|
+
|
97
|
+
def error_code(code)
|
98
|
+
STANDARD_ERROR_CODE_MAPPING[code] || code
|
99
|
+
end
|
100
|
+
|
101
|
+
def url
|
102
|
+
test? ? self.test_url : self.live_url
|
103
|
+
end
|
104
|
+
|
105
|
+
def headers
|
106
|
+
{
|
107
|
+
"Authorization" => "Basic " + Base64.encode64(@options[:login].to_s + ":").strip,
|
108
|
+
"Accept" => "application/json",
|
109
|
+
"Content-Type" => "application/json",
|
110
|
+
"User-Agent" => "Komoju/v1 ActiveMerchantBindings/#{ActiveMerchant::VERSION}"
|
111
|
+
}
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -103,13 +103,17 @@ module ActiveMerchant #:nodoc:
|
|
103
103
|
commit(void_type(kind), request)
|
104
104
|
end
|
105
105
|
|
106
|
-
def store(
|
106
|
+
def store(payment_method, options = {})
|
107
107
|
request = build_xml_request do |doc|
|
108
108
|
add_authentication(doc)
|
109
109
|
doc.registerTokenRequest(transaction_attributes(options)) do
|
110
110
|
doc.orderId(truncate(options[:order_id], 24))
|
111
|
-
|
112
|
-
|
111
|
+
if payment_method.is_a?(String)
|
112
|
+
doc.paypageRegistrationId(payment_method)
|
113
|
+
else
|
114
|
+
doc.accountNumber(payment_method.number)
|
115
|
+
doc.cardValidationNum(payment_method.verification_value) if payment_method.verification_value
|
116
|
+
end
|
113
117
|
end
|
114
118
|
end
|
115
119
|
|
@@ -5,13 +5,14 @@ module ActiveMerchant #:nodoc:
|
|
5
5
|
self.display_name = "micropayment"
|
6
6
|
self.homepage_url = "https://www.micropayment.de/"
|
7
7
|
|
8
|
-
self.test_url = self.live_url = "https://sipg.micropayment.de/public/
|
8
|
+
self.test_url = self.live_url = "https://sipg.micropayment.de/public/creditcardpsp/v1/nvp/"
|
9
9
|
|
10
10
|
self.supported_countries = %w(DE)
|
11
11
|
self.default_currency = "EUR"
|
12
12
|
self.money_format = :cents
|
13
13
|
self.supported_cardtypes = [:visa, :master, :american_express]
|
14
14
|
|
15
|
+
|
15
16
|
def initialize(options={})
|
16
17
|
requires!(options, :access_key)
|
17
18
|
super
|
@@ -20,40 +21,41 @@ module ActiveMerchant #:nodoc:
|
|
20
21
|
def purchase(amount, payment_method, options={})
|
21
22
|
post = {}
|
22
23
|
add_invoice(post, amount, options)
|
23
|
-
add_payment_method(post, payment_method)
|
24
|
+
add_payment_method(post, payment_method, options)
|
24
25
|
add_customer_data(post, options)
|
25
|
-
commit("
|
26
|
+
commit("purchase", post)
|
26
27
|
end
|
27
28
|
|
28
29
|
def authorize(amount, payment_method, options={})
|
29
30
|
post = {}
|
30
31
|
add_invoice(post, amount, options)
|
31
|
-
add_payment_method(post, payment_method)
|
32
|
+
add_payment_method(post, payment_method, options)
|
32
33
|
add_customer_data(post, options)
|
33
|
-
commit("
|
34
|
+
commit("authorize", post)
|
34
35
|
end
|
35
36
|
|
36
37
|
def capture(amount, authorization, options={})
|
37
38
|
post = {}
|
38
39
|
add_reference(post, authorization)
|
39
40
|
add_invoice(post, amount, options)
|
40
|
-
commit("
|
41
|
+
commit("capture", post)
|
41
42
|
end
|
42
43
|
|
43
44
|
def void(authorization, options={})
|
44
45
|
post = {}
|
45
46
|
add_reference(post, authorization)
|
46
|
-
commit("
|
47
|
+
commit("void", post)
|
47
48
|
end
|
48
49
|
|
49
50
|
def refund(amount, authorization, options={})
|
50
51
|
post = {}
|
51
52
|
add_reference(post, authorization)
|
52
53
|
add_invoice(post, amount, options)
|
53
|
-
commit("
|
54
|
+
commit("refund", post)
|
54
55
|
end
|
55
56
|
|
56
57
|
def verify(credit_card, options={})
|
58
|
+
|
57
59
|
MultiResponse.run(:use_first_response) do |r|
|
58
60
|
r.process { authorize(250, credit_card, options) }
|
59
61
|
r.process(:ignore_result) { void(r.authorization, options) }
|
@@ -78,13 +80,14 @@ module ActiveMerchant #:nodoc:
|
|
78
80
|
post[:amount] = amount(money)
|
79
81
|
post[:currency] = options[:currency] || currency(money)
|
80
82
|
end
|
81
|
-
post[:project] = options[:project]
|
83
|
+
post[:project] = options[:project] if options[:project]
|
82
84
|
end
|
83
85
|
|
84
|
-
def add_payment_method(post, payment_method)
|
86
|
+
def add_payment_method(post, payment_method, options={})
|
85
87
|
post[:firstname] = payment_method.first_name
|
86
88
|
post[:surname] = payment_method.last_name
|
87
89
|
post[:number] = payment_method.number
|
90
|
+
post[:recurring] = 1 if options[:recurring] == true
|
88
91
|
post[:cvc2] = payment_method.verification_value
|
89
92
|
post[:expiryYear] = format(payment_method.year, :four_digits)
|
90
93
|
post[:expiryMonth] = format(payment_method.month, :two_digits)
|
@@ -103,9 +106,9 @@ module ActiveMerchant #:nodoc:
|
|
103
106
|
end
|
104
107
|
|
105
108
|
def commit(action, params)
|
106
|
-
|
107
109
|
params[:testMode] = 1 if test?
|
108
110
|
params[:accessKey] = @options[:access_key]
|
111
|
+
params[:apiKey] = @options[:api_key] || "af1fd841af792f4c50131414ff76e004"
|
109
112
|
|
110
113
|
response = parse(ssl_post(url(action), post_data(action, params), headers))
|
111
114
|
|
@@ -113,7 +116,7 @@ module ActiveMerchant #:nodoc:
|
|
113
116
|
succeeded = success_from(response),
|
114
117
|
message_from(succeeded, response),
|
115
118
|
response,
|
116
|
-
authorization: authorization_from(response),
|
119
|
+
authorization: authorization_from(response, params),
|
117
120
|
avs_result: AVSResult.new(code: response["some_avs_result_key"]),
|
118
121
|
cvv_result: CVVResult.new(response["some_cvv_result_key"]),
|
119
122
|
test: test?
|
@@ -159,8 +162,9 @@ module ActiveMerchant #:nodoc:
|
|
159
162
|
authorization.split("|")
|
160
163
|
end
|
161
164
|
|
162
|
-
def authorization_from(response)
|
163
|
-
|
165
|
+
def authorization_from(response, request_params)
|
166
|
+
session_id = response["sessionId"] ? response["sessionId"] : request_params[:sessionId]
|
167
|
+
"#{session_id}|#{response["transactionId"]}"
|
164
168
|
end
|
165
169
|
end
|
166
170
|
end
|
@@ -87,9 +87,7 @@ module ActiveMerchant #:nodoc:
|
|
87
87
|
address = options[:billing_address] || options[:address] || {}
|
88
88
|
|
89
89
|
if name = address[:name]
|
90
|
-
|
91
|
-
post[:lastName] = segments.pop
|
92
|
-
post[:firstName] = segments.join(' ')
|
90
|
+
post[:firstName], post[:lastName] = split_names(name)
|
93
91
|
else
|
94
92
|
post[:firstName] = address[:first_name]
|
95
93
|
post[:lastName] = address[:last_name]
|
@@ -138,7 +138,7 @@ module ActiveMerchant #:nodoc:
|
|
138
138
|
commit(request)
|
139
139
|
end
|
140
140
|
|
141
|
-
# Private: Execute operation that depends on
|
141
|
+
# Private: Execute operation that depends on authorization code from previous purchase or authorize operation
|
142
142
|
def execute_dependant(action, money, authorization, options)
|
143
143
|
request = build_request do |xml|
|
144
144
|
add_identification_authorization(xml, authorization, options)
|
@@ -46,6 +46,7 @@ module ActiveMerchant #:nodoc:
|
|
46
46
|
add_payment_source(post, payment_source)
|
47
47
|
add_address(post, payment_source, options)
|
48
48
|
add_customer_data(post, options)
|
49
|
+
add_user_data(post, options)
|
49
50
|
|
50
51
|
commit(:authorization, post)
|
51
52
|
end
|
@@ -57,6 +58,7 @@ module ActiveMerchant #:nodoc:
|
|
57
58
|
add_payment_source(post, payment_source)
|
58
59
|
add_address(post, payment_source, options)
|
59
60
|
add_customer_data(post, options)
|
61
|
+
add_user_data(post, options)
|
60
62
|
|
61
63
|
commit(:purchase, post)
|
62
64
|
end
|
@@ -81,6 +83,7 @@ module ActiveMerchant #:nodoc:
|
|
81
83
|
add_credit_card(post, credit_card)
|
82
84
|
add_address(post, credit_card, options)
|
83
85
|
add_customer_data(post, options)
|
86
|
+
add_user_data(post, options)
|
84
87
|
|
85
88
|
commit(:credit, post)
|
86
89
|
end
|
@@ -142,10 +145,7 @@ module ActiveMerchant #:nodoc:
|
|
142
145
|
end
|
143
146
|
|
144
147
|
if shipping_address = options[:shipping_address]
|
145
|
-
|
146
|
-
|
147
|
-
post[:ship_name1] = first_name
|
148
|
-
post[:ship_name2] = last_name
|
148
|
+
post[:ship_name1], post[:ship_name2] = split_names(shipping_address[:name])
|
149
149
|
post[:ship_street] = shipping_address[:address1]
|
150
150
|
post[:ship_zip] = shipping_address[:zip]
|
151
151
|
post[:ship_city] = shipping_address[:city]
|
@@ -166,6 +166,12 @@ module ActiveMerchant #:nodoc:
|
|
166
166
|
end
|
167
167
|
end
|
168
168
|
|
169
|
+
def add_user_data(post, options)
|
170
|
+
if options[:order_id]
|
171
|
+
post[:user_data] = "order_id:#{options[:order_id]}"
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
169
175
|
def add_transaction_id(post, transaction_id)
|
170
176
|
post[:card_number] = 'CS:' + transaction_id
|
171
177
|
end
|
@@ -222,13 +228,6 @@ module ActiveMerchant #:nodoc:
|
|
222
228
|
parameters.reject{|k,v| v.blank?}.collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
|
223
229
|
end
|
224
230
|
|
225
|
-
def parse_first_and_last_name(value)
|
226
|
-
name = value.to_s.split(' ')
|
227
|
-
|
228
|
-
last_name = name.pop || ''
|
229
|
-
first_name = name.join(' ')
|
230
|
-
[ first_name, last_name ]
|
231
|
-
end
|
232
231
|
end
|
233
232
|
end
|
234
233
|
end
|
@@ -15,7 +15,7 @@ module ActiveMerchant #:nodoc:
|
|
15
15
|
self.live_url = self.test_url = API_URL
|
16
16
|
|
17
17
|
# Currency supported by Omise
|
18
|
-
# * Thai Baht with Satang,
|
18
|
+
# * Thai Baht with Satang, i.e. 9000 => 90 THB
|
19
19
|
self.default_currency = 'THB'
|
20
20
|
self.money_format = :cents
|
21
21
|
|
@@ -145,7 +145,7 @@ module ActiveMerchant #:nodoc:
|
|
145
145
|
commit(:delete, "customers/#{CGI.escape(customer_id)}")
|
146
146
|
end
|
147
147
|
|
148
|
-
# Enable
|
148
|
+
# Enable scrubbing sensitive information
|
149
149
|
def supports_scrubbing?
|
150
150
|
true
|
151
151
|
end
|
@@ -283,8 +283,9 @@ module ActiveMerchant #:nodoc:
|
|
283
283
|
|
284
284
|
def build_address(xml, addr)
|
285
285
|
if addr[:name]
|
286
|
-
|
287
|
-
xml.tag! '
|
286
|
+
first_name, last_name = split_names(addr[:name])
|
287
|
+
xml.tag! 'firstName', first_name
|
288
|
+
xml.tag! 'lastName' , last_name
|
288
289
|
end
|
289
290
|
xml.tag! 'street' , addr[:address1] if addr[:address1].present?
|
290
291
|
xml.tag! 'street2', addr[:address2] if addr[:address2].present?
|
@@ -668,6 +668,7 @@ module ActiveMerchant #:nodoc:
|
|
668
668
|
end
|
669
669
|
|
670
670
|
def build_customer_request_xml(creditcard, options = {})
|
671
|
+
ActiveMerchant.deprecated "Customer Profile support in Orbital is non-conformant to the ActiveMerchant API and will be removed in its current form in a future version. Please contact the ActiveMerchant maintainers if you have an interest in modifying it to conform to the store/unstore/update API."
|
671
672
|
xml = xml_envelope
|
672
673
|
xml.tag! :Request do
|
673
674
|
xml.tag! :Profile do
|
@@ -52,7 +52,7 @@ module ActiveMerchant #:nodoc:
|
|
52
52
|
#
|
53
53
|
# PayGateXML Field ActiveMerchant Use
|
54
54
|
#
|
55
|
-
# pgid use :login value to gateway
|
55
|
+
# pgid use :login value to gateway instantiation
|
56
56
|
# pwd use :password value to gateway instantiation
|
57
57
|
#
|
58
58
|
# cname credit_card.name
|
@@ -113,6 +113,7 @@ module ActiveMerchant #:nodoc:
|
|
113
113
|
post = {}
|
114
114
|
add_invoice(post, options)
|
115
115
|
add_reference(post, identification)
|
116
|
+
add_amount(post, money, options)
|
116
117
|
commit('refund', money, post)
|
117
118
|
end
|
118
119
|
|
@@ -180,7 +181,7 @@ module ActiveMerchant #:nodoc:
|
|
180
181
|
:dateq => Time.now.strftime('%d%m%Y%H%M%S'),
|
181
182
|
:numquestion => unique_id(parameters[:order_id]),
|
182
183
|
:site => @options[:login].to_s[0,7],
|
183
|
-
:rang => @options[:login].to_s[7..-1],
|
184
|
+
:rang => @options[:rang] || @options[:login].to_s[7..-1],
|
184
185
|
:cle => @options[:password],
|
185
186
|
:pays => '',
|
186
187
|
:archivage => parameters[:order_id]
|
@@ -0,0 +1,238 @@
|
|
1
|
+
module ActiveMerchant
|
2
|
+
module Billing
|
3
|
+
class PayeezyGateway < Gateway
|
4
|
+
class_attribute :integration_url
|
5
|
+
|
6
|
+
self.test_url = 'https://api-cert.payeezy.com/v1/transactions'
|
7
|
+
self.integration_url = 'https://api-cat.payeezy.com/v1/transactions'
|
8
|
+
self.live_url = 'https://api.payeezy.com/v1/transactions'
|
9
|
+
|
10
|
+
self.default_currency = 'USD'
|
11
|
+
self.money_format = :cents
|
12
|
+
self.supported_countries = %w(US CA)
|
13
|
+
|
14
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :jcb, :diners_club]
|
15
|
+
|
16
|
+
self.homepage_url = 'https://developer.payeezy.com/'
|
17
|
+
self.display_name = 'Payeezy'
|
18
|
+
|
19
|
+
CREDIT_CARD_BRAND = {
|
20
|
+
'visa' => 'Visa',
|
21
|
+
'master' => 'Mastercard',
|
22
|
+
'american_express' => 'American Express',
|
23
|
+
'discover' => 'Discover',
|
24
|
+
'jcb' => 'JCB',
|
25
|
+
'diners_club' => 'Diners Club'
|
26
|
+
}
|
27
|
+
|
28
|
+
def initialize(options = {})
|
29
|
+
requires!(options, :apikey, :apisecret, :token)
|
30
|
+
super
|
31
|
+
end
|
32
|
+
|
33
|
+
def purchase(amount, creditcard, options = {})
|
34
|
+
params = {transaction_type: 'purchase'}
|
35
|
+
|
36
|
+
add_invoice(params, options)
|
37
|
+
add_creditcard(params, creditcard)
|
38
|
+
add_address(params, options)
|
39
|
+
add_amount(params, amount, options)
|
40
|
+
|
41
|
+
commit(params, options)
|
42
|
+
end
|
43
|
+
|
44
|
+
def authorize(amount, creditcard, options = {})
|
45
|
+
params = {transaction_type: 'authorize'}
|
46
|
+
|
47
|
+
add_invoice(params, options)
|
48
|
+
add_creditcard(params, creditcard)
|
49
|
+
add_address(params, options)
|
50
|
+
add_amount(params, amount, options)
|
51
|
+
|
52
|
+
commit(params, options)
|
53
|
+
end
|
54
|
+
|
55
|
+
def capture(amount, authorization, options = {})
|
56
|
+
params = {transaction_type: 'capture'}
|
57
|
+
|
58
|
+
add_authorization_info(params, authorization)
|
59
|
+
add_amount(params, amount, options)
|
60
|
+
|
61
|
+
commit(params, options)
|
62
|
+
end
|
63
|
+
|
64
|
+
def refund(amount, authorization, options = {})
|
65
|
+
params = {transaction_type: 'refund'}
|
66
|
+
|
67
|
+
add_authorization_info(params, authorization)
|
68
|
+
add_amount(params, (amount || amount_from_authorization(authorization)), options)
|
69
|
+
|
70
|
+
commit(params, options)
|
71
|
+
end
|
72
|
+
|
73
|
+
def void(authorization, options = {})
|
74
|
+
params = {transaction_type: 'refund'}
|
75
|
+
|
76
|
+
add_authorization_info(params, authorization)
|
77
|
+
add_amount(params, amount_from_authorization(authorization), options)
|
78
|
+
|
79
|
+
commit(params, options)
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def add_invoice(params, options)
|
85
|
+
params[:merchant_ref] = options[:order_id]
|
86
|
+
end
|
87
|
+
|
88
|
+
def amount_from_authorization(authorization)
|
89
|
+
authorization.split('|').last.to_i
|
90
|
+
end
|
91
|
+
|
92
|
+
def add_authorization_info(params, authorization)
|
93
|
+
transaction_id, transaction_tag, method, _ = authorization.split('|')
|
94
|
+
params[:transaction_id] = transaction_id
|
95
|
+
params[:transaction_tag] = transaction_tag
|
96
|
+
params[:method] = method
|
97
|
+
end
|
98
|
+
|
99
|
+
def add_creditcard(params, creditcard)
|
100
|
+
credit_card = {}
|
101
|
+
|
102
|
+
credit_card[:type] = CREDIT_CARD_BRAND[creditcard.brand]
|
103
|
+
credit_card[:cardholder_name] = creditcard.name
|
104
|
+
credit_card[:card_number] = creditcard.number
|
105
|
+
credit_card[:exp_date] = "#{format(creditcard.month, :two_digits)}#{format(creditcard.year, :two_digits)}"
|
106
|
+
credit_card[:cvv] = creditcard.verification_value if creditcard.verification_value?
|
107
|
+
|
108
|
+
params[:method] = 'credit_card'
|
109
|
+
params[:credit_card] = credit_card
|
110
|
+
end
|
111
|
+
|
112
|
+
def add_address(params, options)
|
113
|
+
address = options[:billing_address]
|
114
|
+
return unless address
|
115
|
+
|
116
|
+
billing_address = {}
|
117
|
+
billing_address[:street] = address[:address1] if address[:address1]
|
118
|
+
billing_address[:city] = address[:city] if address[:city]
|
119
|
+
billing_address[:state_province] = address[:state] if address[:state]
|
120
|
+
billing_address[:zip_postal_code] = address[:zip] if address[:zip]
|
121
|
+
billing_address[:country] = address[:country] if address[:country]
|
122
|
+
|
123
|
+
params[:billing_address] = billing_address
|
124
|
+
end
|
125
|
+
|
126
|
+
def add_amount(params, money, options)
|
127
|
+
params[:currency_code] = (options[:currency] || default_currency).upcase
|
128
|
+
params[:amount] = amount(money)
|
129
|
+
end
|
130
|
+
|
131
|
+
def commit(params, options)
|
132
|
+
url = if options[:integration]
|
133
|
+
integration_url
|
134
|
+
elsif test?
|
135
|
+
test_url
|
136
|
+
else
|
137
|
+
live_url
|
138
|
+
end
|
139
|
+
|
140
|
+
if transaction_id = params.delete(:transaction_id)
|
141
|
+
url = "#{url}/#{transaction_id}"
|
142
|
+
end
|
143
|
+
|
144
|
+
success = false
|
145
|
+
begin
|
146
|
+
body = params.to_json
|
147
|
+
raw_response = ssl_post(url, body, headers(body))
|
148
|
+
response = parse(raw_response)
|
149
|
+
success = (response['transaction_status'] == 'approved')
|
150
|
+
rescue ResponseError => e
|
151
|
+
response = response_error(e.response.body)
|
152
|
+
rescue JSON::ParserError
|
153
|
+
response = json_error(raw_response)
|
154
|
+
end
|
155
|
+
|
156
|
+
Response.new(
|
157
|
+
success,
|
158
|
+
handle_message(response, success),
|
159
|
+
response,
|
160
|
+
test: test?,
|
161
|
+
authorization: authorization_from(params, response),
|
162
|
+
avs_result: {code: response['avs']},
|
163
|
+
cvv_result: response['cvv2'],
|
164
|
+
error_code: error_code(response, success)
|
165
|
+
)
|
166
|
+
end
|
167
|
+
|
168
|
+
def authorization_from(params, response)
|
169
|
+
[
|
170
|
+
response['transaction_id'],
|
171
|
+
response['transaction_tag'],
|
172
|
+
params[:method],
|
173
|
+
(response['amount'] && response['amount'].to_i)
|
174
|
+
].join('|')
|
175
|
+
end
|
176
|
+
|
177
|
+
def generate_hmac(nonce, current_timestamp, payload)
|
178
|
+
message = [
|
179
|
+
@options[:apikey],
|
180
|
+
nonce.to_s,
|
181
|
+
current_timestamp.to_s,
|
182
|
+
@options[:token],
|
183
|
+
payload
|
184
|
+
].join("")
|
185
|
+
hash = Base64.strict_encode64(OpenSSL::HMAC.hexdigest('sha256', @options[:apisecret], message))
|
186
|
+
hash
|
187
|
+
end
|
188
|
+
|
189
|
+
def headers(payload)
|
190
|
+
nonce = (SecureRandom.random_number * 10_000_000_000)
|
191
|
+
current_timestamp = (Time.now.to_f * 1000).to_i
|
192
|
+
{
|
193
|
+
'Content-Type' => 'application/json',
|
194
|
+
'apikey' => options[:apikey],
|
195
|
+
'token' => options[:token],
|
196
|
+
'nonce' => nonce.to_s,
|
197
|
+
'timestamp' => current_timestamp.to_s,
|
198
|
+
'Authorization' => generate_hmac(nonce, current_timestamp, payload)
|
199
|
+
}
|
200
|
+
end
|
201
|
+
|
202
|
+
def error_code(response, success)
|
203
|
+
return if success
|
204
|
+
response['Error'].to_h['messages'].to_a.map { |e| e['code'] }.join(', ')
|
205
|
+
end
|
206
|
+
|
207
|
+
def handle_message(response, success)
|
208
|
+
if success
|
209
|
+
"#{response['gateway_message']} - #{response['bank_message']}"
|
210
|
+
elsif %w(401 403).include?(response['code'])
|
211
|
+
response['message']
|
212
|
+
elsif response.key?('Error')
|
213
|
+
response['Error']['messages'].first['description']
|
214
|
+
elsif response.key?('error')
|
215
|
+
response['error']
|
216
|
+
elsif response.key?('fault')
|
217
|
+
response['fault'].to_h['faultstring']
|
218
|
+
else
|
219
|
+
response['bank_message']
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def parse(body)
|
224
|
+
JSON.parse(body)
|
225
|
+
end
|
226
|
+
|
227
|
+
def response_error(raw_response)
|
228
|
+
parse(raw_response)
|
229
|
+
rescue JSON::ParserError
|
230
|
+
json_error(raw_response)
|
231
|
+
end
|
232
|
+
|
233
|
+
def json_error(raw_response)
|
234
|
+
{"error" => "Unable to parse response: #{raw_response.inspect}"}
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|