activemerchant 1.29.3 → 1.30.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.
- data.tar.gz.sig +0 -0
- data/CHANGELOG +39 -0
- data/CONTRIBUTORS +19 -0
- data/README.md +43 -41
- data/lib/active_merchant/billing/check.rb +15 -11
- data/lib/active_merchant/billing/credit_card.rb +5 -1
- data/lib/active_merchant/billing/credit_card_formatting.rb +8 -8
- data/lib/active_merchant/billing/gateway.rb +1 -1
- data/lib/active_merchant/billing/gateways/authorize_net.rb +9 -1
- data/lib/active_merchant/billing/gateways/authorize_net_cim.rb +15 -4
- data/lib/active_merchant/billing/gateways/balanced.rb +9 -3
- data/lib/active_merchant/billing/gateways/banwire.rb +15 -1
- data/lib/active_merchant/billing/gateways/beanstream.rb +26 -24
- data/lib/active_merchant/billing/gateways/beanstream/beanstream_core.rb +6 -2
- data/lib/active_merchant/billing/gateways/braintree_blue.rb +5 -2
- data/lib/active_merchant/billing/gateways/cyber_source.rb +55 -22
- data/lib/active_merchant/billing/gateways/eway.rb +114 -171
- data/lib/active_merchant/billing/gateways/eway_managed.rb +52 -22
- data/lib/active_merchant/billing/gateways/firstdata_e4.rb +222 -0
- data/lib/active_merchant/billing/gateways/ideal_rabobank.rb +13 -2
- data/lib/active_merchant/billing/gateways/litle.rb +50 -19
- data/lib/active_merchant/billing/gateways/merchant_ware.rb +44 -9
- data/lib/active_merchant/billing/gateways/merchant_warrior.rb +190 -0
- data/lib/active_merchant/billing/gateways/moneris.rb +2 -4
- data/lib/active_merchant/billing/gateways/nab_transact.rb +20 -3
- data/lib/active_merchant/billing/gateways/netbilling.rb +1 -0
- data/lib/active_merchant/billing/gateways/netpay.rb +223 -0
- data/lib/active_merchant/billing/gateways/optimal_payment.rb +18 -3
- data/lib/active_merchant/billing/gateways/orbital.rb +9 -5
- data/lib/active_merchant/billing/gateways/payment_express.rb +62 -1
- data/lib/active_merchant/billing/gateways/paypal/paypal_common_api.rb +1 -1
- data/lib/active_merchant/billing/gateways/paypal_express.rb +2 -0
- data/lib/active_merchant/billing/gateways/pin.rb +157 -0
- data/lib/active_merchant/billing/gateways/qbms.rb +3 -2
- data/lib/active_merchant/billing/gateways/quickpay.rb +66 -28
- data/lib/active_merchant/billing/gateways/sage_pay.rb +6 -0
- data/lib/active_merchant/billing/gateways/smart_ps.rb +1 -1
- data/lib/active_merchant/billing/gateways/spreedly_core.rb +235 -0
- data/lib/active_merchant/billing/gateways/stripe.rb +1 -0
- data/lib/active_merchant/billing/gateways/wirecard.rb +15 -9
- data/lib/active_merchant/billing/integrations/payflow_link/helper.rb +4 -1
- data/lib/active_merchant/billing/integrations/paypal/notification.rb +39 -31
- data/lib/active_merchant/billing/integrations/quickpay/helper.rb +13 -10
- data/lib/active_merchant/billing/integrations/quickpay/notification.rb +14 -14
- data/lib/active_merchant/version.rb +1 -1
- metadata +109 -49
- metadata.gz.sig +0 -0
@@ -1,7 +1,10 @@
|
|
1
1
|
module ActiveMerchant #:nodoc:
|
2
2
|
module Billing #:nodoc:
|
3
3
|
class MerchantWareGateway < Gateway
|
4
|
+
class_attribute :v4_live_url
|
5
|
+
|
4
6
|
self.live_url = self.test_url = 'https://ps1.merchantware.net/MerchantWARE/ws/RetailTransaction/TXRetail.asmx'
|
7
|
+
self.v4_live_url = 'https://ps1.merchantware.net/Merchantware/ws/RetailTransaction/v4/Credit.asmx'
|
5
8
|
|
6
9
|
self.supported_countries = ['US']
|
7
10
|
self.supported_cardtypes = [:visa, :master, :american_express, :discover]
|
@@ -12,13 +15,19 @@ module ActiveMerchant #:nodoc:
|
|
12
15
|
"xmlns:xsd" => "http://www.w3.org/2001/XMLSchema",
|
13
16
|
"xmlns:env" => "http://schemas.xmlsoap.org/soap/envelope/"
|
14
17
|
}
|
18
|
+
ENV_NAMESPACES_V4 = { "xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance",
|
19
|
+
"xmlns:xsd" => "http://www.w3.org/2001/XMLSchema",
|
20
|
+
"xmlns:soap" => "http://schemas.xmlsoap.org/soap/envelope/"
|
21
|
+
}
|
22
|
+
|
15
23
|
TX_NAMESPACE = "http://merchantwarehouse.com/MerchantWARE/Client/TransactionRetail"
|
24
|
+
TX_NAMESPACE_V4 = "http://schemas.merchantwarehouse.com/merchantware/40/Credit/"
|
16
25
|
|
17
26
|
ACTIONS = {
|
18
27
|
:purchase => "IssueKeyedSale",
|
19
28
|
:authorize => "IssueKeyedPreAuth",
|
20
29
|
:capture => "IssuePostAuth",
|
21
|
-
:void => "
|
30
|
+
:void => "VoidPreAuthorization",
|
22
31
|
:credit => "IssueKeyedRefund",
|
23
32
|
:reference_credit => "IssueRefundByReference"
|
24
33
|
}
|
@@ -80,11 +89,10 @@ module ActiveMerchant #:nodoc:
|
|
80
89
|
# * <tt>authorization</tt> - The authorization string returned from the initial authorization or purchase.
|
81
90
|
def void(authorization, options = {})
|
82
91
|
reference, options[:order_id] = split_reference(authorization)
|
83
|
-
|
84
|
-
|
85
|
-
add_reference(xml, reference)
|
92
|
+
request = v4_soap_request(:void) do |xml|
|
93
|
+
add_reference_token(xml, reference)
|
86
94
|
end
|
87
|
-
commit(:void, request)
|
95
|
+
commit(:void, request, true)
|
88
96
|
end
|
89
97
|
|
90
98
|
# Refund an amount back a cardholder
|
@@ -108,7 +116,6 @@ module ActiveMerchant #:nodoc:
|
|
108
116
|
perform_reference_credit(money, reference, options)
|
109
117
|
end
|
110
118
|
|
111
|
-
|
112
119
|
private
|
113
120
|
|
114
121
|
def soap_request(action)
|
@@ -125,6 +132,22 @@ module ActiveMerchant #:nodoc:
|
|
125
132
|
xml.target!
|
126
133
|
end
|
127
134
|
|
135
|
+
def v4_soap_request(action)
|
136
|
+
xml = Builder::XmlMarkup.new :indent => 2
|
137
|
+
xml.instruct!
|
138
|
+
xml.tag! "soap:Envelope", ENV_NAMESPACES_V4 do
|
139
|
+
xml.tag! "soap:Body" do
|
140
|
+
xml.tag! ACTIONS[:void], "xmlns" => TX_NAMESPACE_V4 do
|
141
|
+
xml.tag! "merchantName", @options[:name]
|
142
|
+
xml.tag! "merchantSiteId", @options[:login]
|
143
|
+
xml.tag! "merchantKey", @options[:password]
|
144
|
+
yield xml
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
xml.target!
|
149
|
+
end
|
150
|
+
|
128
151
|
def build_purchase_request(action, money, credit_card, options)
|
129
152
|
requires!(options, :order_id)
|
130
153
|
|
@@ -195,6 +218,10 @@ module ActiveMerchant #:nodoc:
|
|
195
218
|
xml.tag! "strReferenceCode", reference
|
196
219
|
end
|
197
220
|
|
221
|
+
def add_reference_token(xml, reference)
|
222
|
+
xml.tag! "token", reference
|
223
|
+
end
|
224
|
+
|
198
225
|
def add_address(xml, options)
|
199
226
|
if address = options[:billing_address] || options[:address]
|
200
227
|
xml.tag! "strAVSStreetAddress", address[:address1]
|
@@ -258,11 +285,19 @@ module ActiveMerchant #:nodoc:
|
|
258
285
|
response
|
259
286
|
end
|
260
287
|
|
261
|
-
def
|
288
|
+
def soap_action(action, v4 = false)
|
289
|
+
v4 ? "#{TX_NAMESPACE_V4}#{ACTIONS[action]}" : "#{TX_NAMESPACE}/#{ACTIONS[action]}"
|
290
|
+
end
|
291
|
+
|
292
|
+
def url(v4 = false)
|
293
|
+
v4 ? v4_live_url : live_url
|
294
|
+
end
|
295
|
+
|
296
|
+
def commit(action, request, v4 = false)
|
262
297
|
begin
|
263
|
-
data = ssl_post(
|
298
|
+
data = ssl_post(url(v4), request,
|
264
299
|
"Content-Type" => 'text/xml; charset=utf-8',
|
265
|
-
"SOAPAction" =>
|
300
|
+
"SOAPAction" => soap_action(action, v4)
|
266
301
|
)
|
267
302
|
response = parse(action, data)
|
268
303
|
rescue ActiveMerchant::ResponseError => e
|
@@ -0,0 +1,190 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
require 'rexml/document'
|
3
|
+
|
4
|
+
module ActiveMerchant #:nodoc:
|
5
|
+
module Billing #:nodoc:
|
6
|
+
class MerchantWarriorGateway < Gateway
|
7
|
+
TOKEN_TEST_URL = 'https://base.merchantwarrior.com/token/'
|
8
|
+
TOKEN_LIVE_URL = 'https://api.merchantwarrior.com/token/'
|
9
|
+
|
10
|
+
POST_TEST_URL = 'https://base.merchantwarrior.com/post/'
|
11
|
+
POST_LIVE_URL = 'https://api.merchantwarrior.com/post/'
|
12
|
+
|
13
|
+
self.supported_countries = ['AU']
|
14
|
+
self.supported_cardtypes = [:visa, :master, :american_express,
|
15
|
+
:diners_club, :discover]
|
16
|
+
self.homepage_url = 'http://www.merchantwarrior.com/'
|
17
|
+
self.display_name = 'MerchantWarrior'
|
18
|
+
|
19
|
+
self.money_format = :dollars
|
20
|
+
self.default_currency = 'AUD'
|
21
|
+
|
22
|
+
def initialize(options = {})
|
23
|
+
requires!(options, :merchant_uuid, :api_key, :api_passphrase)
|
24
|
+
super
|
25
|
+
end
|
26
|
+
|
27
|
+
def authorize(money, payment_method, options = {})
|
28
|
+
post = {}
|
29
|
+
add_amount(post, money, options)
|
30
|
+
add_product(post, options)
|
31
|
+
add_address(post, options)
|
32
|
+
add_payment_method(post, payment_method)
|
33
|
+
commit('processAuth', post)
|
34
|
+
end
|
35
|
+
|
36
|
+
def purchase(money, payment_method, options = {})
|
37
|
+
post = {}
|
38
|
+
add_amount(post, money, options)
|
39
|
+
add_product(post, options)
|
40
|
+
add_address(post, options)
|
41
|
+
add_payment_method(post, payment_method)
|
42
|
+
commit('processCard', post)
|
43
|
+
end
|
44
|
+
|
45
|
+
def capture(money, identification)
|
46
|
+
post = {}
|
47
|
+
add_amount(post, money, options)
|
48
|
+
add_transaction(post, identification)
|
49
|
+
post.merge!('captureAmount' => money.to_s)
|
50
|
+
commit('processCapture', post)
|
51
|
+
end
|
52
|
+
|
53
|
+
def refund(money, identification)
|
54
|
+
post = {}
|
55
|
+
add_amount(post, money, options)
|
56
|
+
add_transaction(post, identification)
|
57
|
+
post['refundAmount'] = money
|
58
|
+
commit('refundCard', post)
|
59
|
+
end
|
60
|
+
|
61
|
+
def store(creditcard, options = {})
|
62
|
+
post = {
|
63
|
+
'cardName' => creditcard.name,
|
64
|
+
'cardNumber' => creditcard.number,
|
65
|
+
'cardExpiryMonth' => sprintf('%02d', creditcard.month),
|
66
|
+
'cardExpiryYear' => sprintf('%02d', creditcard.year)
|
67
|
+
}
|
68
|
+
commit('addCard', post)
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def add_transaction(post, identification)
|
74
|
+
post['transactionID'] = identification
|
75
|
+
end
|
76
|
+
|
77
|
+
def add_address(post, options)
|
78
|
+
return unless(address = options[:address])
|
79
|
+
|
80
|
+
post['customerName'] = address[:name]
|
81
|
+
post['customerCountry'] = address[:country]
|
82
|
+
post['customerState'] = address[:state]
|
83
|
+
post['customerCity'] = address[:city]
|
84
|
+
post['customerAddress'] = address[:address1]
|
85
|
+
post['customerPostCode'] = address[:zip]
|
86
|
+
end
|
87
|
+
|
88
|
+
def add_product(post, options)
|
89
|
+
post['transactionProduct'] = options[:transaction_product]
|
90
|
+
end
|
91
|
+
|
92
|
+
def add_payment_method(post, payment_method)
|
93
|
+
if payment_method.respond_to?(:number)
|
94
|
+
add_creditcard(post, payment_method)
|
95
|
+
else
|
96
|
+
add_token(post, payment_method)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def add_token(post, token)
|
101
|
+
post['cardID'] = token
|
102
|
+
end
|
103
|
+
|
104
|
+
def add_creditcard(post, creditcard)
|
105
|
+
post['paymentCardNumber'] = creditcard.number
|
106
|
+
post['paymentCardName'] = creditcard.name
|
107
|
+
post['paymentCardExpiry'] = creditcard.expiry_date.expiration.strftime("%m%y")
|
108
|
+
end
|
109
|
+
|
110
|
+
def add_amount(post, money, options)
|
111
|
+
currency = (options[:currency] || currency(money))
|
112
|
+
|
113
|
+
post['transactionAmount'] = money.to_s
|
114
|
+
post['transactionCurrency'] = currency
|
115
|
+
post['hash'] = verification_hash(money, currency)
|
116
|
+
end
|
117
|
+
|
118
|
+
def verification_hash(money, currency)
|
119
|
+
Digest::MD5.hexdigest(
|
120
|
+
(
|
121
|
+
@options[:api_passphrase].to_s +
|
122
|
+
@options[:merchant_uuid].to_s +
|
123
|
+
money.to_s +
|
124
|
+
currency
|
125
|
+
).downcase
|
126
|
+
)
|
127
|
+
end
|
128
|
+
|
129
|
+
def parse(body)
|
130
|
+
xml = REXML::Document.new(body)
|
131
|
+
|
132
|
+
response = {}
|
133
|
+
xml.root.elements.to_a.each do |node|
|
134
|
+
parse_element(response, node)
|
135
|
+
end
|
136
|
+
response
|
137
|
+
end
|
138
|
+
|
139
|
+
def parse_element(response, node)
|
140
|
+
if node.has_elements?
|
141
|
+
node.elements.each{|element| parse_element(response, element)}
|
142
|
+
else
|
143
|
+
response[node.name.underscore.to_sym] = node.text
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
def commit(action, post)
|
148
|
+
add_auth(action, post)
|
149
|
+
|
150
|
+
response = parse(ssl_post(url_for(action, post), post_data(post)))
|
151
|
+
|
152
|
+
Response.new(
|
153
|
+
success?(response),
|
154
|
+
response[:response_message],
|
155
|
+
response,
|
156
|
+
:test => test?,
|
157
|
+
:authorization => (response[:card_id] || response[:transaction_id])
|
158
|
+
)
|
159
|
+
end
|
160
|
+
|
161
|
+
def add_auth(action, post)
|
162
|
+
post['merchantUUID'] = @options[:merchant_uuid]
|
163
|
+
post['apiKey'] = @options[:api_key]
|
164
|
+
unless token?(post)
|
165
|
+
post['method'] = action
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def url_for(action, post)
|
170
|
+
if token?(post)
|
171
|
+
[(test? ? TOKEN_TEST_URL : TOKEN_LIVE_URL), action].join("/")
|
172
|
+
else
|
173
|
+
(test? ? POST_TEST_URL : POST_LIVE_URL)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def token?(post)
|
178
|
+
(post["cardID"] || post["cardName"])
|
179
|
+
end
|
180
|
+
|
181
|
+
def success?(response)
|
182
|
+
(response[:response_code] == '0')
|
183
|
+
end
|
184
|
+
|
185
|
+
def post_data(post)
|
186
|
+
post.collect{|k,v| "#{k}=#{CGI.escape(v.to_s)}" }.join("&")
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
@@ -70,15 +70,13 @@ module ActiveMerchant #:nodoc:
|
|
70
70
|
commit 'completion', crediting_params(authorization, :comp_amount => amount(money))
|
71
71
|
end
|
72
72
|
|
73
|
-
# Voiding
|
74
|
-
# transaction. Closed transactions must be refunded. Note that the only
|
75
|
-
# methods which may be voided are +capture+ and +purchase+.
|
73
|
+
# Voiding cancels an open authorization.
|
76
74
|
#
|
77
75
|
# Concatenate your transaction number and order_id by using a semicolon
|
78
76
|
# (';'). This is to keep the Moneris interface consistent with other
|
79
77
|
# gateways. (See +capture+ for details.)
|
80
78
|
def void(authorization, options = {})
|
81
|
-
|
79
|
+
capture(0, authorization, options)
|
82
80
|
end
|
83
81
|
|
84
82
|
# Performs a refund. This method requires that the original transaction
|
@@ -34,7 +34,7 @@ module ActiveMerchant #:nodoc:
|
|
34
34
|
#Transactions currently accepted by NAB Transact XML API
|
35
35
|
TRANSACTIONS = {
|
36
36
|
:purchase => 0, #Standard Payment
|
37
|
-
:
|
37
|
+
:refund => 4, #Refund
|
38
38
|
:void => 6, #Client Reversal (Void)
|
39
39
|
:authorization => 10, #Preauthorise
|
40
40
|
:capture => 11 #Preauthorise Complete (Advice)
|
@@ -66,6 +66,10 @@ module ActiveMerchant #:nodoc:
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
+
def refund(money, authorization, options = {})
|
70
|
+
commit :refund, build_reference_request(money, authorization)
|
71
|
+
end
|
72
|
+
|
69
73
|
def store(creditcard, options = {})
|
70
74
|
requires!(options, :billing_id, :amount)
|
71
75
|
commit_periodic(build_periodic_item(:addcrn, options[:amount], creditcard, options))
|
@@ -104,10 +108,23 @@ module ActiveMerchant #:nodoc:
|
|
104
108
|
xml.target!
|
105
109
|
end
|
106
110
|
|
111
|
+
def build_reference_request(money, reference)
|
112
|
+
xml = Builder::XmlMarkup.new
|
113
|
+
|
114
|
+
transaction_id, order_id, preauth_id, original_amount = reference.split('*')
|
115
|
+
|
116
|
+
xml.tag! 'amount', (money ? amount(money) : original_amount)
|
117
|
+
xml.tag! 'currency', options[:currency] || currency(money)
|
118
|
+
xml.tag! 'txnID', transaction_id
|
119
|
+
xml.tag! 'purchaseOrderNo', order_id
|
120
|
+
xml.tag! 'preauthID', preauth_id
|
121
|
+
|
122
|
+
xml.target!
|
123
|
+
end
|
124
|
+
|
107
125
|
#Generate payment request XML
|
108
126
|
# - API is set to allow multiple Txn's but currentlu only allows one
|
109
127
|
# - txnSource = 23 - (XML)
|
110
|
-
|
111
128
|
def build_request(action, body)
|
112
129
|
xml = Builder::XmlMarkup.new
|
113
130
|
xml.instruct!
|
@@ -210,7 +227,7 @@ module ActiveMerchant #:nodoc:
|
|
210
227
|
end
|
211
228
|
|
212
229
|
def authorization_from(response)
|
213
|
-
response[:txn_id]
|
230
|
+
[response[:txn_id], response[:purchase_order_no], response[:preauth_id], response[:amount]].join('*')
|
214
231
|
end
|
215
232
|
|
216
233
|
def message_from(response)
|
@@ -177,6 +177,7 @@ module ActiveMerchant #:nodoc:
|
|
177
177
|
|
178
178
|
def post_data(action, parameters = {})
|
179
179
|
parameters[:account_id] = @options[:login]
|
180
|
+
parameters[:site_tag] = @options[:site_tag] if @options[:site_tag].present?
|
180
181
|
parameters[:pay_type] = 'C'
|
181
182
|
parameters[:tran_type] = TRANSACTIONS[action]
|
182
183
|
|
@@ -0,0 +1,223 @@
|
|
1
|
+
module ActiveMerchant #:nodoc:
|
2
|
+
module Billing #:nodoc:
|
3
|
+
#
|
4
|
+
# NETPAY Gateway
|
5
|
+
#
|
6
|
+
# Support for NETPAY's HTTP Connector payment gateway in Mexico.
|
7
|
+
#
|
8
|
+
# The gateway sends requests as HTTP POST and receives the response details
|
9
|
+
# in the HTTP header, making the process really rather simple.
|
10
|
+
#
|
11
|
+
# Support for calls to the authorize and capture methods have been included
|
12
|
+
# as per the Netpay manuals, however, your millage may vary with these
|
13
|
+
# methods. At the time of writing (January 2013) they were not fully
|
14
|
+
# supported by the production or test gateways. This situation is
|
15
|
+
# expected to change within a few weeks/months.
|
16
|
+
#
|
17
|
+
# Purchases can be cancelled (`#void`) only within 24 hours of the
|
18
|
+
# transaction. After this, a refund should be performed instead.
|
19
|
+
#
|
20
|
+
# In addition to the regular ActiveMerchant transaction options, NETPAY
|
21
|
+
# also supports a `:mode` parameter. This allows testing to be peformed
|
22
|
+
# in production and force specific results.
|
23
|
+
#
|
24
|
+
# * 'P' - Production
|
25
|
+
# * 'A' - Approved
|
26
|
+
# * 'D' - Declined
|
27
|
+
# * 'R' - Random (Approved or Declined)
|
28
|
+
# * 'T' - Test
|
29
|
+
#
|
30
|
+
# For example:
|
31
|
+
#
|
32
|
+
# response = @gateway.purchase(1000, card, :mode => 'D')
|
33
|
+
# response.success # false
|
34
|
+
#
|
35
|
+
class NetpayGateway < Gateway
|
36
|
+
self.test_url = 'http://200.57.87.243:8855'
|
37
|
+
self.live_url = 'https://suite.netpay.com.mx/acquirerprd'
|
38
|
+
|
39
|
+
# The countries the gateway supports merchants from as 2 digit ISO country codes
|
40
|
+
self.supported_countries = ['MX']
|
41
|
+
|
42
|
+
self.default_currency = 'MXN'
|
43
|
+
|
44
|
+
# The card types supported by the payment gateway
|
45
|
+
self.supported_cardtypes = [:visa, :master, :american_express, :diners_club]
|
46
|
+
|
47
|
+
# The homepage URL of the gateway
|
48
|
+
self.homepage_url = 'http://www.netpay.com.mx'
|
49
|
+
|
50
|
+
# The name of the gateway
|
51
|
+
self.display_name = 'NETPAY Gateway'
|
52
|
+
|
53
|
+
CURRENCY_CODES = {
|
54
|
+
"MXN" => '484'
|
55
|
+
}
|
56
|
+
|
57
|
+
# The header keys that we will provide in the response params hash
|
58
|
+
RESPONSE_KEYS = ['ResponseMsg', 'ResponseText', 'ResponseCode', 'TimeIn', 'TimeOut', 'AuthCode', 'OrderId', 'CardTypeName', 'MerchantId', 'IssuerAuthDate']
|
59
|
+
|
60
|
+
def initialize(options = {})
|
61
|
+
requires!(options, :store_id, :login, :password)
|
62
|
+
super
|
63
|
+
end
|
64
|
+
|
65
|
+
# Send an authorization request
|
66
|
+
def authorize(money, creditcard, options = {})
|
67
|
+
post = {}
|
68
|
+
add_invoice(post, options)
|
69
|
+
add_creditcard(post, creditcard)
|
70
|
+
add_customer_data(post, options)
|
71
|
+
add_amount(post, money, options)
|
72
|
+
|
73
|
+
commit('PreAuth', post, options)
|
74
|
+
end
|
75
|
+
|
76
|
+
# Capture an authorization
|
77
|
+
def capture(money, authorization, options = {})
|
78
|
+
post = {}
|
79
|
+
add_order_id(post, order_id_from(authorization))
|
80
|
+
add_amount(post, money, options)
|
81
|
+
|
82
|
+
commit('PostAuth', post, options)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Cancel an auth/purchase within first 24 hours
|
86
|
+
def void(authorization, options = {})
|
87
|
+
post = {}
|
88
|
+
order_id, amount, currency = split_authorization(authorization)
|
89
|
+
add_order_id(post, order_id)
|
90
|
+
post['Total'] = (options[:amount] || amount)
|
91
|
+
post['CurrencyCode'] = currency
|
92
|
+
|
93
|
+
commit('Refund', post, options)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Make a purchase.
|
97
|
+
def purchase(money, creditcard, options = {})
|
98
|
+
post = {}
|
99
|
+
add_invoice(post, options)
|
100
|
+
add_creditcard(post, creditcard)
|
101
|
+
add_customer_data(post, options)
|
102
|
+
add_amount(post, money, options)
|
103
|
+
|
104
|
+
commit('Auth', post, options)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Perform a Credit transaction.
|
108
|
+
def refund(money, authorization, options = {})
|
109
|
+
post = {}
|
110
|
+
add_order_id(post, order_id_from(authorization))
|
111
|
+
add_amount(post, money, options)
|
112
|
+
|
113
|
+
#commit('Refund', post, options)
|
114
|
+
commit('Credit', post, options)
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def add_login_data(post)
|
120
|
+
post['StoreId'] = @options[:store_id]
|
121
|
+
post['UserName'] = @options[:login]
|
122
|
+
post['Password'] = @options[:password]
|
123
|
+
end
|
124
|
+
|
125
|
+
def add_action(post, action, options)
|
126
|
+
post['ResourceName'] = action
|
127
|
+
post['ContentType'] = 'Transaction'
|
128
|
+
post['Mode'] = options[:mode] || 'P'
|
129
|
+
end
|
130
|
+
|
131
|
+
def add_order_id(post, order_id)
|
132
|
+
post['OrderId'] = order_id
|
133
|
+
end
|
134
|
+
|
135
|
+
def add_amount(post, money, options)
|
136
|
+
post['Total'] = amount(money)
|
137
|
+
post['CurrencyCode'] = currency_code(options[:currency] || currency(money))
|
138
|
+
end
|
139
|
+
|
140
|
+
def add_customer_data(post, options)
|
141
|
+
post['IPAddress'] = options[:ip] unless options[:ip].blank?
|
142
|
+
end
|
143
|
+
|
144
|
+
def add_invoice(post, options)
|
145
|
+
post['Comments'] = options[:description] if options[:description]
|
146
|
+
end
|
147
|
+
|
148
|
+
def add_creditcard(post, creditcard)
|
149
|
+
post['CardNumber'] = creditcard.number
|
150
|
+
post['ExpDate'] = expdate(creditcard)
|
151
|
+
post['CustomerName'] = creditcard.name
|
152
|
+
post['CVV2'] = creditcard.verification_value unless creditcard.verification_value.nil?
|
153
|
+
end
|
154
|
+
|
155
|
+
def build_authorization(request_params, response_params)
|
156
|
+
[response_params['OrderId'], request_params['Total'], request_params['CurrencyCode']].join('|')
|
157
|
+
end
|
158
|
+
|
159
|
+
def split_authorization(authorization)
|
160
|
+
order_id, amount, currency = authorization.split("|")
|
161
|
+
[order_id, amount, currency]
|
162
|
+
end
|
163
|
+
|
164
|
+
def order_id_from(authorization)
|
165
|
+
split_authorization(authorization).first
|
166
|
+
end
|
167
|
+
|
168
|
+
def expdate(credit_card)
|
169
|
+
year = sprintf("%.4i", credit_card.year)
|
170
|
+
month = sprintf("%.2i", credit_card.month)
|
171
|
+
|
172
|
+
"#{month}/#{year[-2..-1]}"
|
173
|
+
end
|
174
|
+
|
175
|
+
def url
|
176
|
+
test? ? test_url : live_url
|
177
|
+
end
|
178
|
+
|
179
|
+
def parse(response, request_params)
|
180
|
+
response_params = params_from_response(response)
|
181
|
+
|
182
|
+
success = (response_params['ResponseCode'] == '00')
|
183
|
+
message = response_params['ResponseText'] || response_params['ResponseMsg']
|
184
|
+
options = @options.merge(:test => test?,
|
185
|
+
:authorization => build_authorization(request_params, response_params))
|
186
|
+
|
187
|
+
Response.new(success, message, response_params, options)
|
188
|
+
end
|
189
|
+
|
190
|
+
def commit(action, parameters, options)
|
191
|
+
add_login_data(parameters)
|
192
|
+
add_action(parameters, action, options)
|
193
|
+
|
194
|
+
post = parameters.collect{|key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
|
195
|
+
parse(ssl_post(url, post), parameters)
|
196
|
+
end
|
197
|
+
|
198
|
+
# Override the regular handle response so we can access the headers
|
199
|
+
def handle_response(response)
|
200
|
+
case response.code.to_i
|
201
|
+
when 200...300
|
202
|
+
response
|
203
|
+
else
|
204
|
+
raise ResponseError.new(response)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
# Return a hash containing all the useful, or informative values from netpay
|
209
|
+
def params_from_response(response)
|
210
|
+
params = {}
|
211
|
+
RESPONSE_KEYS.each do |k|
|
212
|
+
params[k] = response[k] unless response[k].to_s.empty?
|
213
|
+
end
|
214
|
+
params
|
215
|
+
end
|
216
|
+
|
217
|
+
def currency_code(currency)
|
218
|
+
return currency if currency =~ /^\d+$/
|
219
|
+
CURRENCY_CODES[currency]
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|