activemerchant 1.55.0 → 1.56.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG +22 -0
- data/CONTRIBUTORS +4 -0
- data/README.md +1 -0
- data/lib/active_merchant.rb +0 -1
- data/lib/active_merchant/billing/credit_card_methods.rb +5 -0
- data/lib/active_merchant/billing/gateways/bridge_pay.rb +56 -29
- data/lib/active_merchant/billing/gateways/card_stream.rb +2 -1
- data/lib/active_merchant/billing/gateways/cardknox.rb +328 -0
- data/lib/active_merchant/billing/gateways/cashnet.rb +4 -0
- data/lib/active_merchant/billing/gateways/creditcall.rb +3 -1
- data/lib/active_merchant/billing/gateways/elavon.rb +6 -0
- data/lib/active_merchant/billing/gateways/firstdata_e4.rb +1 -1
- data/lib/active_merchant/billing/gateways/garanti.rb +4 -2
- data/lib/active_merchant/billing/gateways/jetpay.rb +3 -2
- data/lib/active_merchant/billing/gateways/mercury.rb +10 -1
- data/lib/active_merchant/billing/gateways/micropayment.rb +20 -6
- data/lib/active_merchant/billing/gateways/omise.rb +5 -4
- data/lib/active_merchant/billing/gateways/redsys.rb +107 -21
- data/lib/active_merchant/billing/gateways/stripe.rb +17 -3
- data/lib/active_merchant/billing/gateways/trans_first.rb +107 -18
- data/lib/active_merchant/version.rb +1 -1
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8a7fa5a42dbb05e1c335a93e8cefc85781e7cbae
|
4
|
+
data.tar.gz: 928d0561eab8bc6a0fcac4245ccc2342d4e8fa6a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bf1511639e9a72d13e6be69a301e0f0553cd4b52e65205a0e9f777c951e355124c16440182716a622beb5cd56037d98aea1659e1bdf49541b20d0438d2bf3802
|
7
|
+
data.tar.gz: 83dd4208bb147e5dce68f4751ff27e7298f03fffa0ef8c32f0f335fbf8fa79b1c4177d4839b236510fc7d9f66bedf98a4237085fbb2dcc94a9509d57f3004feb
|
data/CHANGELOG
CHANGED
@@ -1,5 +1,26 @@
|
|
1
1
|
= ActiveMerchant CHANGELOG
|
2
2
|
|
3
|
+
== Version 1.56.0 (December 1, 2015)
|
4
|
+
* Add Cardknox gateway [dlehren]
|
5
|
+
* Mercury: Add support for card present track 2 [ryanbalsdon]
|
6
|
+
* Cardstream: Improve default currency handling [duff]
|
7
|
+
* Mercury: Strip start and end sentinels on track 2 [ryanbalsdon]
|
8
|
+
* Redsys: Support new SHA256 authentication method [davidsantoso]
|
9
|
+
* Cashnet: Allow custcode override [duff]
|
10
|
+
* Add Rails 5 support [rafaelfranca]
|
11
|
+
* Set required Ruby version for install to 2 or greater [rafaelfranca]
|
12
|
+
* JetPay: Pass ud_fields in capture too [duff]
|
13
|
+
* Stripe: Correctly detect test mode refunds [aprofeit]
|
14
|
+
* Fix variables in remote gateways test template [sdball]
|
15
|
+
* Micropayment: Update fieldnames for new API [duff]
|
16
|
+
* Fix CreditCard#valid_number? erroring on non-digit characters [PatrickTulskie]
|
17
|
+
* Stripe: Correctly detect test mode voids [methodmissing]
|
18
|
+
* Garanti: Add test mode URL and update remote test credentials [cbilgili]
|
19
|
+
* Cashnet: Allow custcode override on refund [duff]
|
20
|
+
* Omise: Add a new optional api_version config [zdk]
|
21
|
+
* Elavon: Include IP address in purchase and authorize requests [aprofeit]
|
22
|
+
* TransFirst: Add support for ACH and more operations [davidsantoso]
|
23
|
+
* FirstData_e4: Fix void for even dollar transactions [duff]
|
3
24
|
|
4
25
|
== Version 1.55.0 (November 9, 2015)
|
5
26
|
* CyberSource: send customer IP address when provided [fastjames]
|
@@ -51,6 +72,7 @@
|
|
51
72
|
* PayBox Direct: Refunds and working test credentials [ivanfer]
|
52
73
|
* Vanco: Handle case of no billing_address [duff]
|
53
74
|
* BluePay: Add support for CUSTOM_ID2 field [ajporterfield]
|
75
|
+
* Creditcall: Handle no verification_value [duff]
|
54
76
|
|
55
77
|
== Version 1.54.0 (October 2, 2015)
|
56
78
|
* Beanstream: Add Network Tokenization support [girasquid]
|
data/CONTRIBUTORS
CHANGED
data/README.md
CHANGED
@@ -97,6 +97,7 @@ The [ActiveMerchant Wiki](http://github.com/activemerchant/active_merchant/wikis
|
|
97
97
|
* [Borgun](https://www.borgun.is/) - IS
|
98
98
|
* [Braintree](http://www.braintreepaymentsolutions.com) - US, CA, AU, AD, AT, BE, BG, CY, CZ, DK, EE, FI, FR, GI, DE, GR, HU, IS, IM, IE, IT, LV, LI, LT, LU, MT, MC, NL, NO, PL, PT, RO, SM, SK, SI, ES, SE, CH, TR, GB
|
99
99
|
* [BridgePay](http://www.bridgepaynetwork.com/) - CA, US
|
100
|
+
* [Cardknox](https://www.cardknox.com/) - US, CA, GB
|
100
101
|
* [CardSave](http://www.cardsave.net/) - GB
|
101
102
|
* [CardStream](http://www.cardstream.com/) - GB
|
102
103
|
* [Cashnet](http://www.higherone.com/) - US
|
data/lib/active_merchant.rb
CHANGED
@@ -33,7 +33,6 @@ if(!defined?(ActiveSupport::VERSION) || (ActiveSupport::VERSION::STRING < "4.1")
|
|
33
33
|
require 'active_support/core_ext/class/attribute_accessors'
|
34
34
|
end
|
35
35
|
|
36
|
-
require 'active_support/core_ext/class/delegating_attributes'
|
37
36
|
require 'active_support/core_ext/module/attribute_accessors'
|
38
37
|
|
39
38
|
require 'base64'
|
@@ -68,6 +68,7 @@ module ActiveMerchant #:nodoc:
|
|
68
68
|
def valid_number?(number)
|
69
69
|
valid_test_mode_card_number?(number) ||
|
70
70
|
valid_card_number_length?(number) &&
|
71
|
+
valid_card_number_characters?(number) &&
|
71
72
|
valid_checksum?(number)
|
72
73
|
end
|
73
74
|
|
@@ -138,6 +139,10 @@ module ActiveMerchant #:nodoc:
|
|
138
139
|
number.to_s.length >= 12
|
139
140
|
end
|
140
141
|
|
142
|
+
def valid_card_number_characters?(number) #:nodoc:
|
143
|
+
!number.to_s.match(/\D/)
|
144
|
+
end
|
145
|
+
|
141
146
|
def valid_test_mode_card_number?(number) #:nodoc:
|
142
147
|
ActiveMerchant::Billing::Base.test? &&
|
143
148
|
%w[1 2 3 success failure error].include?(number.to_s)
|
@@ -6,8 +6,8 @@ module ActiveMerchant #:nodoc:
|
|
6
6
|
self.display_name = "BridgePay"
|
7
7
|
self.homepage_url = "http://www.bridgepaynetwork.com/"
|
8
8
|
|
9
|
-
self.test_url = "https://gatewaystage.itstgate.com/SmartPayments/transact.asmx
|
10
|
-
self.live_url = "https://gateway.itstgate.com/SmartPayments/transact.asmx
|
9
|
+
self.test_url = "https://gatewaystage.itstgate.com/SmartPayments/transact.asmx"
|
10
|
+
self.live_url = "https://gateway.itstgate.com/SmartPayments/transact.asmx"
|
11
11
|
|
12
12
|
self.supported_countries = ["CA", "US"]
|
13
13
|
self.default_currency = "USD"
|
@@ -19,30 +19,30 @@ module ActiveMerchant #:nodoc:
|
|
19
19
|
super
|
20
20
|
end
|
21
21
|
|
22
|
-
def purchase(amount,
|
23
|
-
post =
|
22
|
+
def purchase(amount, payment_method, options={})
|
23
|
+
post = initialize_required_fields("Sale")
|
24
24
|
|
25
25
|
# Allow the same amount in multiple transactions.
|
26
26
|
post[:ExtData] = "<Force>T</Force>"
|
27
27
|
add_invoice(post, amount, options)
|
28
|
-
|
28
|
+
add_payment_method(post, payment_method)
|
29
29
|
add_customer_data(post, options)
|
30
30
|
|
31
31
|
commit(post)
|
32
32
|
end
|
33
33
|
|
34
|
-
def authorize(amount,
|
35
|
-
post =
|
34
|
+
def authorize(amount, payment_method, options={})
|
35
|
+
post = initialize_required_fields("Auth")
|
36
36
|
|
37
37
|
add_invoice(post, amount, options)
|
38
|
-
|
38
|
+
add_payment_method(post, payment_method)
|
39
39
|
add_customer_data(post, options)
|
40
40
|
|
41
41
|
commit(post)
|
42
42
|
end
|
43
43
|
|
44
44
|
def capture(amount, authorization, options={})
|
45
|
-
post =
|
45
|
+
post = initialize_required_fields("Force")
|
46
46
|
|
47
47
|
add_invoice(post, amount, options)
|
48
48
|
add_reference(post, authorization)
|
@@ -52,7 +52,7 @@ module ActiveMerchant #:nodoc:
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def refund(amount, authorization, options={})
|
55
|
-
post =
|
55
|
+
post = initialize_required_fields("Return")
|
56
56
|
|
57
57
|
add_invoice(post, amount, options)
|
58
58
|
add_reference(post, authorization)
|
@@ -61,7 +61,7 @@ module ActiveMerchant #:nodoc:
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def void(authorization, options={})
|
64
|
-
post =
|
64
|
+
post = initialize_required_fields("Void")
|
65
65
|
|
66
66
|
add_reference(post, authorization)
|
67
67
|
|
@@ -75,9 +75,37 @@ module ActiveMerchant #:nodoc:
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
+
def supports_scrubbing?
|
79
|
+
true
|
80
|
+
end
|
81
|
+
|
82
|
+
def scrub(transcript)
|
83
|
+
transcript.
|
84
|
+
gsub(%r((&?CardNum=)[^&]*)i, '\1[FILTERED]').
|
85
|
+
gsub(%r((&?CVNum=)[^&]*)i, '\1[FILTERED]').
|
86
|
+
gsub(%r((&?Password=)[^&]*)i, '\1[FILTERED]').
|
87
|
+
gsub(%r((&?TransitNum=)[^&]*)i, '\1[FILTERED]').
|
88
|
+
gsub(%r((&?AccountNum=)[^&]*)i, '\1[FILTERED]')
|
89
|
+
end
|
90
|
+
|
78
91
|
private
|
79
92
|
|
80
|
-
def
|
93
|
+
def add_payment_method(post, payment_method)
|
94
|
+
if payment_method.respond_to? :brand
|
95
|
+
post[:NameOnCard] = payment_method.name if payment_method.name
|
96
|
+
post[:ExpDate] = expdate(payment_method)
|
97
|
+
post[:CardNum] = payment_method.number
|
98
|
+
post[:CVNum] = payment_method.verification_value
|
99
|
+
else
|
100
|
+
post[:CheckNum] = payment_method.number
|
101
|
+
post[:TransitNum] = payment_method.routing_number
|
102
|
+
post[:AccountNum] = payment_method.account_number
|
103
|
+
post[:NameOnCheck] = payment_method.name
|
104
|
+
post[:ExtData] = "<AccountType>#{payment_method.account_type.capitalize}</AccountType>"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def initialize_required_fields(transaction_type)
|
81
109
|
post = {}
|
82
110
|
post[:TransType] = transaction_type
|
83
111
|
post[:Amount] = ""
|
@@ -92,6 +120,12 @@ module ActiveMerchant #:nodoc:
|
|
92
120
|
post[:CVNum] = ""
|
93
121
|
post[:MagData] = ""
|
94
122
|
post[:ExtData] = ""
|
123
|
+
post[:MICR] = ""
|
124
|
+
post[:DL] = ""
|
125
|
+
post[:SS] = ""
|
126
|
+
post[:DOB] = ""
|
127
|
+
post[:StateCode] = ""
|
128
|
+
post[:CheckType] = ""
|
95
129
|
post
|
96
130
|
end
|
97
131
|
|
@@ -107,13 +141,6 @@ module ActiveMerchant #:nodoc:
|
|
107
141
|
post[:InvNum] = options[:order_id]
|
108
142
|
end
|
109
143
|
|
110
|
-
def add_creditcard(post, creditcard)
|
111
|
-
post[:NameOnCard] = creditcard.name if creditcard.name
|
112
|
-
post[:ExpDate] = expdate(creditcard)
|
113
|
-
post[:CardNum] = creditcard.number
|
114
|
-
post[:CVNum] = creditcard.verification_value
|
115
|
-
end
|
116
|
-
|
117
144
|
def expdate(creditcard)
|
118
145
|
"#{format(creditcard.month, :two_digits)}#{format(creditcard.year, :two_digits)}"
|
119
146
|
end
|
@@ -137,12 +164,12 @@ module ActiveMerchant #:nodoc:
|
|
137
164
|
end
|
138
165
|
|
139
166
|
def commit(parameters)
|
140
|
-
url = (
|
167
|
+
url = url(parameters[:TransitNum] ? 'ProcessCheck' : 'ProcessCreditCard')
|
141
168
|
data = post_data(parameters)
|
142
169
|
raw = parse(ssl_post(url, data))
|
143
170
|
|
144
171
|
Response.new(
|
145
|
-
success_from(raw
|
172
|
+
success_from(raw),
|
146
173
|
message_from(raw),
|
147
174
|
raw,
|
148
175
|
authorization: authorization_from(raw),
|
@@ -150,17 +177,17 @@ module ActiveMerchant #:nodoc:
|
|
150
177
|
)
|
151
178
|
end
|
152
179
|
|
153
|
-
def
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
180
|
+
def url(action)
|
181
|
+
base = test? ? test_url : live_url
|
182
|
+
"#{base}/#{action}"
|
183
|
+
end
|
184
|
+
|
185
|
+
def success_from(response)
|
186
|
+
response[:result] == "0"
|
160
187
|
end
|
161
188
|
|
162
189
|
def message_from(response)
|
163
|
-
response[:respmsg]
|
190
|
+
response[:respmsg] || response[:message]
|
164
191
|
end
|
165
192
|
|
166
193
|
def authorization_from(response)
|
@@ -14,6 +14,7 @@ module ActiveMerchant #:nodoc:
|
|
14
14
|
|
15
15
|
CURRENCY_CODES = {
|
16
16
|
"AUD" => '036',
|
17
|
+
"BRL" => '986',
|
17
18
|
"CAD" => '124',
|
18
19
|
"CZK" => '203',
|
19
20
|
"DKK" => '208',
|
@@ -132,7 +133,7 @@ module ActiveMerchant #:nodoc:
|
|
132
133
|
|
133
134
|
def add_amount(post, money, options)
|
134
135
|
add_pair(post, :amount, amount(money), :required => true)
|
135
|
-
add_pair(post, :currencyCode, currency_code(options[:currency] || currency(money))
|
136
|
+
add_pair(post, :currencyCode, currency_code(options[:currency] || currency(money)))
|
136
137
|
end
|
137
138
|
|
138
139
|
def add_customer_data(post, options)
|
@@ -0,0 +1,328 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
class CardknoxGateway < Gateway
|
4
|
+
self.live_url = 'https://x1.cardknox.com/gateway'
|
5
|
+
|
6
|
+
self.supported_countries = ['US','CA','GB']
|
7
|
+
self.default_currency = 'USD'
|
8
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :discover, :diners_club, :jcb]
|
9
|
+
|
10
|
+
self.homepage_url = 'https://www.cardknox.com/'
|
11
|
+
self.display_name = 'Cardknox'
|
12
|
+
|
13
|
+
COMMANDS = {
|
14
|
+
credit_card: {
|
15
|
+
purchase: 'cc:sale',
|
16
|
+
authorization: 'cc:authonly',
|
17
|
+
capture: 'cc:capture',
|
18
|
+
refund: 'cc:refund',
|
19
|
+
void: 'cc:void',
|
20
|
+
save: 'cc:save'
|
21
|
+
},
|
22
|
+
check: {
|
23
|
+
purchase: 'check:sale',
|
24
|
+
refund: 'check:refund',
|
25
|
+
void: 'check:void',
|
26
|
+
save: 'check:save'
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
def initialize(options={})
|
31
|
+
requires!(options, :api_key)
|
32
|
+
super
|
33
|
+
end
|
34
|
+
|
35
|
+
# There are three sources for doing a purchase transation:
|
36
|
+
# - credit card
|
37
|
+
# - check
|
38
|
+
# - cardknox token, which is returned in the the authorization string "ref_num;token;command"
|
39
|
+
|
40
|
+
def purchase(amount, source, options={})
|
41
|
+
post = {}
|
42
|
+
add_amount(post, amount, options)
|
43
|
+
add_invoice(post, options)
|
44
|
+
add_source(post, source)
|
45
|
+
add_address(post, source, options)
|
46
|
+
add_customer_data(post, options)
|
47
|
+
add_custom_fields(post, options)
|
48
|
+
commit(:purchase, source_type(source), post)
|
49
|
+
end
|
50
|
+
|
51
|
+
def authorize(amount, source, options={})
|
52
|
+
post = {}
|
53
|
+
add_amount(post, amount)
|
54
|
+
add_invoice(post, options)
|
55
|
+
add_source(post, source)
|
56
|
+
add_address(post, source, options)
|
57
|
+
add_customer_data(post, options)
|
58
|
+
add_custom_fields(post, options)
|
59
|
+
commit(:authorization, source_type(source), post)
|
60
|
+
end
|
61
|
+
|
62
|
+
def capture(amount, authorization, options = {})
|
63
|
+
post = {}
|
64
|
+
add_reference(post, authorization)
|
65
|
+
add_amount(post, amount)
|
66
|
+
commit(:capture, source_type(authorization), post)
|
67
|
+
end
|
68
|
+
|
69
|
+
def refund(amount, authorization, options={})
|
70
|
+
post = {}
|
71
|
+
add_reference(post, authorization)
|
72
|
+
add_amount(post, amount)
|
73
|
+
commit(:refund, source_type(authorization), post)
|
74
|
+
end
|
75
|
+
|
76
|
+
def void(authorization, options = {})
|
77
|
+
post = {}
|
78
|
+
add_reference(post, authorization)
|
79
|
+
commit(:void, source_type(authorization), post)
|
80
|
+
end
|
81
|
+
|
82
|
+
def verify(credit_card, options={})
|
83
|
+
MultiResponse.run(:use_first_response) do |r|
|
84
|
+
r.process { authorize(100, credit_card, options) }
|
85
|
+
r.process(:ignore_result) { void(r.authorization, options) }
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def store(source, options = {})
|
90
|
+
post = {}
|
91
|
+
add_source(post, source)
|
92
|
+
add_address(post, source, options)
|
93
|
+
add_invoice(post, options)
|
94
|
+
add_customer_data(post, options)
|
95
|
+
add_custom_fields(post, options)
|
96
|
+
commit(:save, source_type(source), post)
|
97
|
+
end
|
98
|
+
|
99
|
+
def supports_scrubbing?
|
100
|
+
true
|
101
|
+
end
|
102
|
+
|
103
|
+
def scrub(transcript)
|
104
|
+
transcript.
|
105
|
+
gsub(%r((xCardNum=)\d+), '\1[FILTERED]').
|
106
|
+
gsub(%r((xCVV=)\d+), '\1[FILTERED]').
|
107
|
+
gsub(%r((xAccount=)\d+), '\1[FILTERED]').
|
108
|
+
gsub(%r((xRouting=)\d+), '\1[FILTERED]').
|
109
|
+
gsub(%r((xKey=)\w+), '\1[FILTERED]')
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def split_authorization(authorization)
|
115
|
+
authorization.split(";")
|
116
|
+
end
|
117
|
+
|
118
|
+
def add_reference(post, reference)
|
119
|
+
reference, _, _ = split_authorization(reference)
|
120
|
+
post[:Refnum] = reference
|
121
|
+
end
|
122
|
+
|
123
|
+
def source_type(source)
|
124
|
+
if source.respond_to?(:brand)
|
125
|
+
:credit_card
|
126
|
+
elsif source.respond_to?(:routing_number)
|
127
|
+
:check
|
128
|
+
elsif source.kind_of?(String)
|
129
|
+
source_type_from(source)
|
130
|
+
else
|
131
|
+
raise ArgumentError, "Unknown source #{source.inspect}"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def source_type_from(authorization)
|
136
|
+
_, _, source_type = split_authorization(authorization)
|
137
|
+
(source_type || "credit_card").to_sym
|
138
|
+
end
|
139
|
+
|
140
|
+
def add_source(post, source)
|
141
|
+
if source.respond_to?(:brand)
|
142
|
+
add_credit_card(post, source)
|
143
|
+
elsif source.respond_to?(:routing_number)
|
144
|
+
add_check(post, source)
|
145
|
+
elsif source.kind_of?(String)
|
146
|
+
add_cardknox_token(post, source)
|
147
|
+
else
|
148
|
+
raise ArgumentError, "Invalid payment source #{source.inspect}"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Subtotal + Tax + Tip = Amount.
|
153
|
+
|
154
|
+
def add_amount(post, money, options = {})
|
155
|
+
post[:Tip] = amount(options[:tip])
|
156
|
+
post[:Amount] = amount(money)
|
157
|
+
end
|
158
|
+
|
159
|
+
def expdate(credit_card)
|
160
|
+
year = format(credit_card.year, :two_digits)
|
161
|
+
month = format(credit_card.month, :two_digits)
|
162
|
+
"#{month}#{year}"
|
163
|
+
end
|
164
|
+
|
165
|
+
def add_customer_data(post, options)
|
166
|
+
address = options[:billing_address] || {}
|
167
|
+
post[:Street] = address[:address1]
|
168
|
+
post[:Zip] = address[:zip]
|
169
|
+
post[:PONum] = options[:po_number]
|
170
|
+
post[:Fax] = options[:fax]
|
171
|
+
post[:Email] = options[:email]
|
172
|
+
post[:IP] = options[:ip]
|
173
|
+
end
|
174
|
+
|
175
|
+
def add_address(post, source, options)
|
176
|
+
add_address_for_type(:billing, post, source, options[:billing_address]) if options[:billing_address]
|
177
|
+
add_address_for_type(:shipping, post, source, options[:shipping_address]) if options[:shipping_address]
|
178
|
+
end
|
179
|
+
|
180
|
+
def add_address_for_type(type, post, source, address)
|
181
|
+
prefix = address_key_prefix(type)
|
182
|
+
if source.respond_to?(:first_name)
|
183
|
+
post[address_key(prefix, 'FirstName')] = source.first_name
|
184
|
+
post[address_key(prefix, 'LastName')] = source.last_name
|
185
|
+
else
|
186
|
+
post[address_key(prefix, 'FirstName')] = address[:first_name]
|
187
|
+
post[address_key(prefix, 'LastName')] = address[:last_name]
|
188
|
+
end
|
189
|
+
post[address_key(prefix, 'MiddleName')] = address[:middle_name]
|
190
|
+
|
191
|
+
post[address_key(prefix, 'Company')] = address[:company]
|
192
|
+
post[address_key(prefix, 'Street')] = address[:address1]
|
193
|
+
post[address_key(prefix, 'Street2')] = address[:address2]
|
194
|
+
post[address_key(prefix, 'City')] = address[:city]
|
195
|
+
post[address_key(prefix, 'State')] = address[:state]
|
196
|
+
post[address_key(prefix, 'Zip')] = address[:zip]
|
197
|
+
post[address_key(prefix, 'Country')] = address[:country]
|
198
|
+
post[address_key(prefix, 'Phone')] = address[:phone]
|
199
|
+
post[address_key(prefix, 'Mobile')] = address[:mobile]
|
200
|
+
end
|
201
|
+
|
202
|
+
def address_key_prefix(type)
|
203
|
+
case type
|
204
|
+
when :shipping then 'Ship'
|
205
|
+
when :billing then 'Bill'
|
206
|
+
else
|
207
|
+
raise ArgumentError, "Unknown address key prefix: #{type}"
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def address_key(prefix, key)
|
212
|
+
"#{prefix}#{key}".to_sym
|
213
|
+
end
|
214
|
+
|
215
|
+
def add_invoice(post, options)
|
216
|
+
post[:Invoice] = options[:invoice]
|
217
|
+
post[:OrderID] = options[:order_id]
|
218
|
+
post[:Comments] = options[:comments]
|
219
|
+
post[:Description] = options[:description]
|
220
|
+
post[:Tax] = amount(options[:tax])
|
221
|
+
end
|
222
|
+
|
223
|
+
def add_custom_fields(post, options)
|
224
|
+
options.keys.grep(/^custom(?:[01]\d|20)$/) do |key|
|
225
|
+
post[key.to_s.capitalize] = options[key]
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
def add_credit_card(post, credit_card)
|
230
|
+
if credit_card.track_data.present?
|
231
|
+
post[:Magstripe] = credit_card.track_data
|
232
|
+
post[:Cardpresent] = true
|
233
|
+
else
|
234
|
+
post[:CardNum] = credit_card.number
|
235
|
+
post[:CVV] = credit_card.verification_value
|
236
|
+
post[:Exp] = expdate(credit_card)
|
237
|
+
post[:Name] = credit_card.name
|
238
|
+
post[:CardPresent] = true if credit_card.manual_entry
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def add_check(post, check)
|
243
|
+
post[:Routing] = check.routing_number
|
244
|
+
post[:Account] = check.account_number
|
245
|
+
post[:Name] = check.name
|
246
|
+
post[:CheckNum] = check.number
|
247
|
+
end
|
248
|
+
|
249
|
+
def add_cardknox_token(post, authorization)
|
250
|
+
_, token, _ = split_authorization(authorization)
|
251
|
+
|
252
|
+
post[:Token] = token
|
253
|
+
end
|
254
|
+
|
255
|
+
def parse(body)
|
256
|
+
fields = {}
|
257
|
+
for line in body.split('&')
|
258
|
+
key, value = *line.scan( %r{^(\w+)\=(.*)$} ).flatten
|
259
|
+
fields[key] = CGI.unescape(value.to_s)
|
260
|
+
end
|
261
|
+
|
262
|
+
{
|
263
|
+
result: fields['xResult'],
|
264
|
+
status: fields['xStatus'],
|
265
|
+
error: fields['xError'],
|
266
|
+
auth_code: fields['xAuthCode'],
|
267
|
+
ref_num: fields['xRefNum'],
|
268
|
+
current_ref_num: fields['xRefNumCurrent'],
|
269
|
+
token: fields['xToken'],
|
270
|
+
batch: fields['xBatch'],
|
271
|
+
avs_result: fields['xAvsResult'],
|
272
|
+
avs_result_code: fields['xAvsResultCode'],
|
273
|
+
cvv_result: fields['xCvvResult'],
|
274
|
+
cvv_result_code: fields['xCvvResultCode'],
|
275
|
+
remaining_balance: fields['xRemainingBalance'],
|
276
|
+
amount: fields['xAuthAmount'],
|
277
|
+
masked_card_num: fields['xMaskedCardNumber'],
|
278
|
+
masked_account_number: fields['MaskedAccountNumber']
|
279
|
+
}.delete_if{|k, v| v.nil?}
|
280
|
+
end
|
281
|
+
|
282
|
+
|
283
|
+
def commit(action, source_type, parameters)
|
284
|
+
response = parse(ssl_post(live_url, post_data(COMMANDS[source_type][action], parameters)))
|
285
|
+
|
286
|
+
Response.new(
|
287
|
+
(response[:status] == 'Approved'),
|
288
|
+
message_from(response),
|
289
|
+
response,
|
290
|
+
authorization: authorization_from(response, source_type),
|
291
|
+
avs_result: { code: response[:avs_result_code] },
|
292
|
+
cvv_result: response[:cvv_result_code]
|
293
|
+
)
|
294
|
+
end
|
295
|
+
|
296
|
+
def message_from(response)
|
297
|
+
if response[:status] == "Approved"
|
298
|
+
"Success"
|
299
|
+
elsif response[:error].blank?
|
300
|
+
"Unspecified error"
|
301
|
+
else
|
302
|
+
response[:error]
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
def authorization_from(response, source_type)
|
307
|
+
"#{response[:ref_num]};#{response[:token]};#{source_type}"
|
308
|
+
end
|
309
|
+
|
310
|
+
def post_data(command, parameters = {})
|
311
|
+
initial_parameters = {
|
312
|
+
Key: @options[:api_key],
|
313
|
+
Version: "4.5.4",
|
314
|
+
SoftwareName: 'Active Merchant',
|
315
|
+
SoftwareVersion: "#{ActiveMerchant::VERSION}",
|
316
|
+
Command: command,
|
317
|
+
}
|
318
|
+
|
319
|
+
seed = SecureRandom.hex(32).upcase
|
320
|
+
hash = Digest::SHA1.hexdigest("#{initial_parameters[:command]}:#{@options[:pin]}:#{parameters[:amount]}:#{parameters[:invoice]}:#{seed}")
|
321
|
+
initial_parameters[:Hash] = "s/#{seed}/#{hash}/n" unless @options[:pin].blank?
|
322
|
+
parameters = initial_parameters.merge(parameters)
|
323
|
+
|
324
|
+
parameters.reject{|k, v| v.blank?}.collect{ |key, value| "x#{key}=#{CGI.escape(value.to_s)}" }.join("&")
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|